Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MicroObjects - Seattle Code Camp 2018

Quinn
September 15, 2018
67

MicroObjects - Seattle Code Camp 2018

Writing highly maintainable code is hard. Without being able to maintain the code it rots and eventually must be replaced. Some very simple constraints can produce highly maintainable code. Highly maintainable code allows quicker delivery of new features. Let's explore the practices that allow quick deliver of highly maintainable software.

Quinn

September 15, 2018
Tweet

Transcript

  1. Feature Parity in
    25% of the Dev Hours
    With MicroObjects
    @TheQuinnGil https://QuinnGil.com

    View Slide

  2. MicroObjects
    Object Oriented Practices to the Extreme

    View Slide

  3. Quinn Gil
    Blog -- QuinnGil.com
    Twitter -- TheQuinnGil
    Github -- Fyzxs

    View Slide

  4. Primary Philosophy

    View Slide

  5. Primary Philosophy
    Single Responsibility

    View Slide

  6. Single Responsibility
    What’s its job?

    View Slide

  7. Single Responsibility
    Single Behavior

    View Slide

  8. Technical Practices…
    ● No Getters / No Setters
    ● Always Immutable
    ● No ‘new’ Inline
    ● No Primitive Obsession
    ● Encapsulate Relationships
    ● ‘if’ Only as Guard Clause
    ● ‘switch’ & ‘else’ Always Evil
    ● Composition Over Inheritance
    ● Interface Everything
    ● Isolate Their Code
    ● No Statics
    ● No nulls

    View Slide

  9. Technical Practices… Drive Single Responsibility
    ● No Getters / No Setters
    ● Always Immutable
    ● No ‘new’ Inline
    ● No Primitive Obsession
    ● Encapsulate Relationships
    ● ‘if’ Only as Guard Clause
    ● ‘switch’ & ‘else’ Always Evil
    ● Composition Over Inheritance
    ● Interface Everything
    ● No Statics
    ● No nulls
    ● Isolate Their Code

    View Slide

  10. Driving Single Responsibility
    No Getters / No Setters
    ‘if’s Only as a Guard Clause
    Isolate Their Code

    View Slide

  11. Driving Single Responsibility
    No Getters / No Setters

    View Slide

  12. No Getters / No Setters
    My Definition

    View Slide

  13. No Getters / No Setters
    class FizzBuzzBag{
    public int Input{ get; set; }
    public string Result{ get; set; }
    }
    class FizzBuzzBag:
    def __init__(self):
    self._result = None
    self._input = None
    @property
    def result(self):
    return self._result
    @result.setter
    def result(self, value):
    self._result = value
    @property
    def input(self):
    return self._input
    @input.setter
    def input(self, value):
    self._input = value
    class FizzBuzzBag{
    private int input;
    private String result;
    public String getResult(){
    return result;
    }
    public void setResult(String value){
    result = value;
    }
    public int getInput(){
    return input;
    }
    public void setInput(int value){
    input = value;
    }
    }
    class FizzBuzzBag
    attr_accessor :input
    attr_accessor :result
    end

    View Slide

  14. No Getters / No Setters
    No Way

    View Slide

  15. No Getters / No Setters

    View Slide

  16. No Getters
    Why?

    View Slide

  17. No Getters
    Behavior

    View Slide

  18. No Getters / No Setters

    View Slide

  19. No Getters / No Setters

    View Slide

  20. No Setters
    Why?

    View Slide

  21. No Setters
    Behavior

    View Slide

  22. No Setters
    Clear Usage

    View Slide

  23. No Getters / No Setters

    View Slide

  24. No Getters / No Setters

    View Slide

  25. No Getters / No Setters
    class FizzBuzzBag{
    public int Input{ get; set; }
    public string Result{ get; set; }
    }
    private void CalcFizzBuzzResult(FizzBuzzBag fb){
    var sb = new StringBuilder();
    if(ShouldIncludeFizz(fb.Input)){
    sb.Append("Fizz");
    }
    if(ShouldIncludeBuzz(fb.Input)){
    sb.Append("Buzz");
    }
    fb.Result = sb.Length != 0 ? sb.ToString() : fb.Input.ToString();
    }

    View Slide

  26. No Getters / No Setters - Encapsulated Behavior
    class FizzBuzz{
    private readonly int input;
    public FizzBuzz(int input){
    this.input = input;
    }
    public string Result(){
    var sb = new StringBuilder();
    if(ShouldIncludeFizz(input)){
    sb.Append("Fizz");
    }
    if(ShouldIncludeBuzz(input)){
    sb.Append("Buzz");
    }
    return sb.Length != 0 ? sb.ToString() : input.ToString();
    }
    }

    View Slide

  27. Driving Single Responsibility
    No Getters / No Setters
    ‘if’s Only as a Guard Clause
    Isolate Their Code

    View Slide

  28. ‘if’s Only as a Guard Clause
    Driving Single Responsibility

    View Slide

  29. ‘if’s Only as a Guard Clause
    No Way

    View Slide

  30. ‘if’s Only as a Guard Clause
    Cascading Effect

    View Slide

  31. ‘if’s Only as a Guard Clause
    Success Path

    View Slide

  32. ‘if’s Only as a Guard Clause - Success Path
    class FizzBuzz{
    private readonly int input;
    public FizzBuzz(int input){
    this.input = input;
    }
    public string Result(){
    var sb = new StringBuilder();
    if(ShouldIncludeFizz(input)){
    sb.Append("Fizz");
    }
    if(ShouldIncludeBuzz(input)){
    sb.Append("Buzz");
    }
    return sb.Length != 0
    ? sb.ToString()
    : input.ToString();
    }
    }

    View Slide

  33. ‘if’s Only as a Guard Clause - Success Path
    class FizzBuzz{
    private readonly int input;
    public FizzBuzz(int input){
    this.input = input;
    }
    public string Result(){
    var sb = new StringBuilder();
    if(ShouldIncludeFizz(input)){
    sb.Append("Fizz");
    }
    if(ShouldIncludeBuzz(input)){
    sb.Append("Buzz");
    }
    return sb.Length != 0
    ? sb.ToString()
    : input.ToString();
    }
    }
    class FizzBuzz{
    private readonly int input;
    public FizzBuzz(int input){
    this.input = input;
    }
    public string Result(){
    if(ShouldBeFizzBuzz(input)) return "FizzBuzz";
    if(ShouldBeFizz(input)) return "Fizz";
    if(ShouldBeBuzz(input)) return "Buzz";
    return input.ToString();
    }
    }

    View Slide

  34. FizzBuzz?

    View Slide

  35. Driving Single Responsibility
    No Getters / No Setters
    ‘if’s Only as a Guard Clause
    Isolate Their Code

    View Slide

  36. Driving Single Responsibility
    Isolate Their Code

    View Slide

  37. Isolate Their Code
    OOP Practices

    View Slide

  38. Isolate Their Code - OOP Practices
    class FizzBuzz{
    private readonly string json;
    public string Result(){
    JObject jObject = JObject.Parse(json);
    int input = jObject.Value("input");
    if(ShouldBeFizzBuzz(input)) return "FizzBuzz";
    if(ShouldBeFizz(input)) return "Fizz";
    if(ShouldBeBuzz(input)) return "Buzz";
    return input.ToString();
    }
    }

    View Slide

  39. Isolate Their Code
    Coupling

    View Slide

  40. Isolate Their Code
    Commonality

    View Slide

  41. Isolate Their Code
    Single Behavior

    View Slide

  42. Isolate Their Code - Single Behavior
    class FizzBuzz{
    private readonly string json;
    private readonly IParser parser;
    public string Result(){
    IParsedObject pObject = parser.Parse(json);
    int input = pObject.IntValue("input");
    if(ShouldBeFizzBuzz(input)) return "FizzBuzz";
    if(ShouldBeFizz(input)) return "Fizz";
    if(ShouldBeBuzz(input)) return "Buzz";
    return input.ToString();
    }
    }

    View Slide

  43. Isolate Their Code - Single Behavior
    class FizzBuzz{
    private readonly IFizzBuzzInput input;
    public FizzBuzz(IFizzBuzzInput input){
    this.input = input;
    }
    public string Result(){
    if(ShouldBeFizzBuzz(input)) return "FizzBuzz";
    if(ShouldBeFizz(input)) return "Fizz";
    if(ShouldBeBuzz(input)) return "Buzz";
    return input.AsString();
    }
    }
    class FizzBuzz{
    private readonly string json;
    private readonly IParser parser;
    public string Result(){
    IParsedObject pObject = parser.Parse(json);
    int input = pObject.IntValue("input");
    if(ShouldBeFizzBuzz(input)) return "FizzBuzz";
    if(ShouldBeFizz(input)) return "Fizz";
    if(ShouldBeBuzz(input)) return "Buzz";
    return input.ToString();
    }
    }

    View Slide

  44. Asymmetric Marriage

    View Slide

  45. Driving Single Responsibility
    No Getters / No Setters
    ‘if’s Only as a Guard Clause
    Isolate Their Code

    View Slide

  46. 25% of the Dev Hours

    View Slide

  47. ● No Getters / No Setters
    ● Always Immutable
    ● No ‘new’ Inline
    ● No Enum
    ● No Primitive Obsession
    ● Encapsulate Relationships
    ● ‘if’ Only as Guard Clause
    ● ‘switch’ & ‘else’ Always Evil
    ● Composition Over Inheritance
    ● Interface Everything
    ● No Public Statics
    ● No nulls
    ● Isolate Their Code

    View Slide

  48. View Slide

  49. MicroObjects
    Single Responsibility to the Extreme
    @TheQuinnGil https://QuinnGil.com

    View Slide