MicroObjects - Seattle Code Camp 2018

5b92c5ea42bc2c2ab28d973d5da63cd6?s=47 Quinn
September 15, 2018
34

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.

5b92c5ea42bc2c2ab28d973d5da63cd6?s=128

Quinn

September 15, 2018
Tweet

Transcript

  1. Feature Parity in 25% of the Dev Hours With MicroObjects

    @TheQuinnGil https://QuinnGil.com
  2. MicroObjects Object Oriented Practices to the Extreme

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

    Fyzxs
  4. Primary Philosophy

  5. Primary Philosophy Single Responsibility

  6. Single Responsibility What’s its job?

  7. Single Responsibility Single Behavior

  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
  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
  10. Driving Single Responsibility No Getters / No Setters ‘if’s Only

    as a Guard Clause Isolate Their Code
  11. Driving Single Responsibility No Getters / No Setters

  12. No Getters / No Setters My Definition

  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
  14. No Getters / No Setters No Way

  15. No Getters / No Setters

  16. No Getters Why?

  17. No Getters Behavior

  18. No Getters / No Setters

  19. No Getters / No Setters

  20. No Setters Why?

  21. No Setters Behavior

  22. No Setters Clear Usage

  23. No Getters / No Setters

  24. No Getters / No Setters

  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(); }
  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(); } }
  27. Driving Single Responsibility No Getters / No Setters ‘if’s Only

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

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

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

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

  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(); } }
  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(); } }
  34. FizzBuzz?

  35. Driving Single Responsibility No Getters / No Setters ‘if’s Only

    as a Guard Clause Isolate Their Code
  36. Driving Single Responsibility Isolate Their Code

  37. Isolate Their Code OOP Practices

  38. Isolate Their Code - OOP Practices class FizzBuzz{ private readonly

    string json; public string Result(){ JObject jObject = JObject.Parse(json); int input = jObject.Value<int>("input"); if(ShouldBeFizzBuzz(input)) return "FizzBuzz"; if(ShouldBeFizz(input)) return "Fizz"; if(ShouldBeBuzz(input)) return "Buzz"; return input.ToString(); } }
  39. Isolate Their Code Coupling

  40. Isolate Their Code Commonality

  41. Isolate Their Code Single Behavior

  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(); } }
  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(); } }
  44. Asymmetric Marriage

  45. Driving Single Responsibility No Getters / No Setters ‘if’s Only

    as a Guard Clause Isolate Their Code
  46. 25% of the Dev Hours

  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
  48. None
  49. MicroObjects Single Responsibility to the Extreme @TheQuinnGil https://QuinnGil.com