Slide 1

Slide 1 text

Feature Parity in 25% of the Dev Hours with Technical Practices for Sustainable Code @TheQuinnGil QuinnGil.com

Slide 2

Slide 2 text

Feature Parity in 25% of the Dev Hours @TheQuinnGil QuinnGil.com

Slide 3

Slide 3 text

@TheQuinnGil QuinnGil.com Technical Practices for Sustainable Code

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

This is for you.

Slide 6

Slide 6 text

Sustainable Code through Technical Practices @TheQuinnGil QuinnGil.com

Slide 7

Slide 7 text

Sustainable Code through Technical Practices @TheQuinnGil QuinnGil.com

Slide 8

Slide 8 text

Sustainable Code through Technical Practices @TheQuinnGil QuinnGil.com

Slide 9

Slide 9 text

Tests

Slide 10

Slide 10 text

Sustainable Code through Technical Practices ● No Getters / No Setters ● `if` Only As Guard Clause ● Isolate Their Code ● Never `null` ● No `new` inline ● Composition, Not Inheritance ● ● Be Immutable ● No Primitives ● Extract Cohesion ● No Public Statics ● Never Reflection @TheQuinnGil QuinnGil.com

Slide 11

Slide 11 text

Sustainable Code through Technical Practices ● No Getters / No Setters ● `if` Only As Guard Clause ● Isolate Their Code ● Never `null` ● No `new` inline ● Composition, Not Inheritance ● ● Be Immutable ● No Primitives ● Extract Cohesion ● No Public Statics ● Never Reflection No Getters / No Setters @TheQuinnGil QuinnGil.com

Slide 12

Slide 12 text

Technical Practices - 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

Slide 13

Slide 13 text

Technical Practices - No Getters / No Setters No Way

Slide 14

Slide 14 text

No Getters / No Setters Technical Practices

Slide 15

Slide 15 text

Technical Practices - No Getters Why No Getters?

Slide 16

Slide 16 text

Technical Practices - No Setters Why No Setters?

Slide 17

Slide 17 text

Technical Practices - No Getters / No Setters How?

Slide 18

Slide 18 text

No Getters / No Setters - How? The Class Does It

Slide 19

Slide 19 text

Technical Practices - No Getters / No Setters public class FizzBuzz{ public int Input { get; set; } public string Result { get; set; } } public static class FizzBuzzUtils{ public static void Calculate(FizzBuzz fb){ if (fb.Input % 3 == 0){ fb.Result = "Fizz"; } if (fb.Input % 5 == 0){ if (fb.Result == null){ fb.Result = "Buzz"; } else { fb.Result += "Buzz"; } } if (string.IsNullOrEmpty(fb.Result)){ fb.Result = fb.Input.ToString(); } } }

Slide 20

Slide 20 text

Technical Practices - No Getters / No Setters public class FizzBuzz{ private readonly int _input; public FizzBuzz(int input) => _input = input; public string Result(){ string result = null; if (_input % 3 == 0) result = "Fizz"; if (_input % 5 == 0){ if (result == null) result = "Buzz"; else result += "Buzz"; } if (string.IsNullOrEmpty(result)){ result = _input.ToString(); } return result; } } public class FizzBuzz{ public int Input { get; set; } public string Result { get; set; } } public static class FizzBuzzUtils{ public static void Calculate(FizzBuzz fb){ if (fb.Input % 3 == 0){ fb.Result = "Fizz"; } if (fb.Input % 5 == 0){ if (fb.Result == null){ fb.Result = "Buzz"; } else { fb.Result += "Buzz"; } } if (string.IsNullOrEmpty(fb.Result)){ fb.Result = fb.Input.ToString(); } } }

Slide 21

Slide 21 text

Technical Practices - No Getters / No Setters Benefits

Slide 22

Slide 22 text

Sustainable Code through Technical Practices No Getters / No Setters @TheQuinnGil QuinnGil.com ● No Getters / No Setters ● `if` Only As Guard Clause ● Isolate Their Code ● Never `null` ● No `new` inline ● Composition, Not Inheritance ● ● Be Immutable ● No Primitives ● Extract Cohesion ● No Public Statics ● Never Reflection

Slide 23

Slide 23 text

Sustainable Code through Technical Practices ● No Getters / No Setters ● `if` Only As Guard Clause ● Isolate Their Code ● Never `null` ● No `new` inline ● Composition, Not Inheritance ● ● Be Immutable ● No Primitives ● Extract Cohesion ● No Public Statics ● Never Reflection `if` Only As Guard Clause @TheQuinnGil QuinnGil.com

Slide 24

Slide 24 text

Technical Practices - `if` Only As Guard Clause No Way

Slide 25

Slide 25 text

Technical Practices - `if` Only As Guard Clause Default Path

Slide 26

Slide 26 text

`if` Only As Guard Clause - Default Path public class FizzBuzz{ private readonly int _input; public FizzBuzz(int input) => _input = input; public string Result(){ string result = null; if (_input % 3 == 0) result = "Fizz"; if (_input % 5 == 0){ if (result == null) result = "Buzz"; else result += "Buzz"; } if (string.IsNullOrEmpty(result)){ result = _input.ToString(); } return result; } }

Slide 27

Slide 27 text

public class FizzBuzz{ private readonly int _input; public FizzBuzz(int input) => _input = input; public string Result(){ string result = null; if (_input % 3 == 0) result = "Fizz"; if (_input % 5 == 0){ if (result == null) result = "Buzz"; else result += "Buzz"; } if (string.IsNullOrEmpty(result)){ result = _input.ToString(); } return result; } } `if` Only As Guard Clause - Default Path public class FizzBuzz{ private int _input; public FizzBuzz(int input) => _input = input; public string Result(){ if (_input % 15 == 0) return "FizzBuzz"; if (_input % 3 == 0) return "Fizz"; if (_input % 5 == 0) return "Buzz"; return _input.ToString(); } }

Slide 28

Slide 28 text

Technical Practices - `if` Only As Guard Clause Cascading Changes

Slide 29

Slide 29 text

Technical Practices - `if` Only As Guard Clause Cascading Changes switch and else - always evil

Slide 30

Slide 30 text

Technical Practices - `if` Only As Guard Clause How?

Slide 31

Slide 31 text

`if` Only As Guard Clause - Default Path public class FizzBuzz{ private int _input; public FizzBuzz(int input) => _input = input; public string Result(){ if (_input % 15 == 0) return "FizzBuzz"; if (_input % 3 == 0) return "Fizz"; if (_input % 5 == 0) return "Buzz"; return _input.ToString(); } } public class FizzBuzz{ private readonly int _input; public FizzBuzz(int input) => _input = input; public string Result(){ string result = null; if (_input % 3 == 0) result = "Fizz"; if (_input % 5 == 0){ if (result == null) result = "Buzz"; else result += "Buzz"; } if (string.IsNullOrEmpty(result)){ result = _input.ToString(); } return result; } }

Slide 32

Slide 32 text

Sustainable Code through Technical Practices `if` Only As Guard Clause @TheQuinnGil QuinnGil.com ● No Getters / No Setters ● `if` Only As Guard Clause ● Isolate Their Code ● Never `null` ● No `new` inline ● Composition, Not Inheritance ● ● Be Immutable ● No Primitives ● Extract Cohesion ● No Public Statics ● Never Reflection

Slide 33

Slide 33 text

Sustainable Code through Technical Practices ● No Getters / No Setters ● `if` Only As Guard Clause ● Isolate Their Code ● Never `null` ● No `new` inline ● Composition, Not Inheritance ● ● Be Immutable ● No Primitives ● Extract Cohesion ● No Public Statics ● Never Reflection Isolate Their Code @TheQuinnGil QuinnGil.com

Slide 34

Slide 34 text

Technical Practices - Isolate Their Code - 3rd Party public class FizzBuzz{ private readonly string _input; public FizzBuzz(string input) => _input = input; public string Result(){ JObject jObject = JObject.Parse(_input); int input = jObject.Value("number"); if (IsFizzBuzz(input)) return "FizzBuzz"; if (IsFizz(input)) return "Fizz"; if (IsBuzz(input)) return "Buzz"; return input.ToString(); } }

Slide 35

Slide 35 text

Technical Practices - Isolate Their Code - 3rd Party public class FizzBuzz{ private readonly string _input; private readonly IParser _parser; public string Result(){ IParsedObject pObject = _parser.Parse(_input); int input = pObject.IntValue("input"); if (IsFizzBuzz(input)) return "FizzBuzz"; if (IsFizz(input)) return "Fizz"; if (IsBuzz(input)) return "Buzz"; return input.ToString(); } }

Slide 36

Slide 36 text

What Else? Technical Practices - Isolate Their Code

Slide 37

Slide 37 text

Operating System Technical Practices - Isolate Their Code

Slide 38

Slide 38 text

How? Technical Practices - Isolate Their Code

Slide 39

Slide 39 text

Technical Practices - Isolate Their Code - How? internal class HttpClientBookEnd : IHttpClientBookEnd { private static HttpClient _testClient; #if DEBUG public static void SetTestClient(HttpClient testClient) => _testClient = testClient; #endif private readonly HttpClient _httpClient; public HttpClientBookEnd() : this(new HttpClient()) { } private HttpClientBookEnd(HttpClient httpClient) => _httpClient = httpClient; public void SendRequestAsync(HttpRequestMessage msg) => HttpClient().SendAsync(msg); private HttpClient HttpClient() => _testClient ?? _httpClient; }

Slide 40

Slide 40 text

User Interface Technical Practices - Isolate Their Code

Slide 41

Slide 41 text

Sustainable Code through Technical Practices Isolate Their Code @TheQuinnGil QuinnGil.com ● No Getters / No Setters ● `if` Only As Guard Clause ● Isolate Their Code ● Never `null` ● No `new` inline ● Composition, Not Inheritance ● ● Be Immutable ● No Primitives ● Extract Cohesion ● No Public Statics ● Never Reflection

Slide 42

Slide 42 text

Sustainable Code through Technical Practices ● No Getters / No Setters ● `if` Only As Guard Clause ● Isolate Their Code ● Never `null` ● No `new` inline ● Composition, Not Inheritance ● ● Be Immutable ● No Primitives ● Extract Cohesion ● No Public Statics ● Never Reflection Never `null` @TheQuinnGil QuinnGil.com

Slide 43

Slide 43 text

Why? Technical Practices - Never `null`

Slide 44

Slide 44 text

How? Technical Practices - Never `null`

Slide 45

Slide 45 text

Technical Practices - Never `null` public string CalculateThing(ICanBeNull canBeNull) { if (canBeNull == null) return "Default"; IAlsoNull alsoNull = canBeNull.Example(); if (alsoNull == null) return "Default"; string sample = alsoNull.Sample(); if (sample == null) return "Default"; return sample; }

Slide 46

Slide 46 text

Technical Practices - Never `null` public string CalculateThing(ICanBeNull canBeNull) { if (canBeNull == null) return "Default"; IAlsoNull alsoNull = canBeNull.Example(); if (alsoNull == null) return "Default"; string sample = alsoNull.Sample(); if (sample == null) return "Default"; return sample; } public string CalculateThing(ICanBeNull canBeNull) { return canBeNull?.Example()?.Sample() ?? "Default"; }

Slide 47

Slide 47 text

Technical Practices - Never `null` public string CalculateThing(ICanBeNull canBeNull) { if (canBeNull == null) return "Default"; IAlsoNull alsoNull = canBeNull.Example(); if (alsoNull == null) return "Default"; string sample = alsoNull.Sample(); if (sample == null) return "Default"; return sample; } public string CalculateThing(ICanBeNull canBeNull) { return canBeNull?.Example()?.Sample() ?? "Default"; } public string CalculateThing(ICanNotBeNull canNotBeNull) { return canNotBeNull.Example().Sample(); }

Slide 48

Slide 48 text

Technical Practices - Never `null` public string CalculateThing(ICanBeNull canBeNull) { if (canBeNull == null) return "Default"; IAlsoNull alsoNull = canBeNull.Example(); if (alsoNull == null) return "Default"; string sample = alsoNull.Sample(); if (sample == null) return "Default"; return sample; } public string CalculateThing(ICanBeNull canBeNull) { return canBeNull?.Example()?.Sample() ?? "Default"; } public string CalculateThing(ICanNotBeNull canNotBeNull) { return canNotBeNull.Example().Sample(); } public void Foo() { string thing = _bar.CalculateThing(_canBeNull); //... }

Slide 49

Slide 49 text

Technical Practices - Never `null` public string CalculateThing(ICanBeNull canBeNull) { if (canBeNull == null) return "Default"; IAlsoNull alsoNull = canBeNull.Example(); if (alsoNull == null) return "Default"; string sample = alsoNull.Sample(); if (sample == null) return "Default"; return sample; } public string CalculateThing(ICanBeNull canBeNull) { return canBeNull?.Example()?.Sample() ?? "Default"; } public string CalculateThing(ICanNotBeNull canNotBeNull) { return canNotBeNull.Example().Sample(); } public void Foo() { string thing = _bar.CalculateThing(_canBeNull); //... } public void Foo() { string thing = _canNotBeNull.Example().Sample(); //... }

Slide 50

Slide 50 text

Technical Practices - Never `null` public class NullObject : ICanNotBeNull { public IAlsoNotNull Example() => new NullObjectAlso(); } public class NullObjectAlso : IAlsoNotNull { public string Sample() => "Default"; } public string CalculateThing(ICanBeNull canBeNull) { if (canBeNull == null) return "Default"; IAlsoNull alsoNull = canBeNull.Example(); if (alsoNull == null) return "Default"; string sample = alsoNull.Sample(); if (sample == null) return "Default"; return sample; } public void Foo() { string thing = _canNotBeNull.Example().Sample(); //... }

Slide 51

Slide 51 text

Languages and Null

Slide 52

Slide 52 text

Sustainable Code through Technical Practices Never `null` @TheQuinnGil QuinnGil.com ● No Getters / No Setters ● `if` Only As Guard Clause ● Isolate Their Code ● Never `null` ● No `new` inline ● Composition, Not Inheritance ● ● Be Immutable ● No Primitives ● Extract Cohesion ● No Public Statics ● Never Reflection

Slide 53

Slide 53 text

Sustainable Code through Technical Practices ● No Getters / No Setters ● `if` Only As Guard Clause ● Isolate Their Code ● Never `null` ● No `new` inline ● Composition, Not Inheritance ● ● Be Immutable ● No Primitives ● Extract Cohesion ● No Public Statics ● Never Reflection No `new` inline @TheQuinnGil QuinnGil.com

Slide 54

Slide 54 text

Technical Practices - No `new` inline public class FizzBuzz{ private readonly int _input; public FizzBuzz(int input) => _input = input; public string Result(){ if (new Mod15(_input).Remainder() == 0) return "FizzBuzz"; if (new Mod3(_input).Remainder() == 0) return "Fizz"; if (new Mod5(_input).Remainder() == 0) return "Buzz"; return _input.ToString(); } }

Slide 55

Slide 55 text

Technical Practices - No `new` inline public class FizzBuzz{ private readonly int _input; public FizzBuzz(int input) => _input = input; public string Result(){ if (Mod15().Remainder() == 0) return "FizzBuzz"; if (Mod3().Remainder() == 0) return "Fizz"; if (Mod5().Remainder() == 0) return "Buzz"; return _input.ToString(); } private IRemainder Mod15() => new Mod15(_input); private IRemainder Mod3() => new Mod3(_input); private IRemainder Mod5() => new Mod5(_input); }

Slide 56

Slide 56 text

Technical Practices - No `new` inline public class FizzBuzz{ private readonly int _input; private readonly ModFactory factory; public FizzBuzz(int input) => _input = input; public string Result(){ if (factory.Mod15(_input).Remainder() == 0) return "FizzBuzz"; if (factory.Mod3(_input).Remainder() == 0) return "Fizz"; if (factory.Mod5(_input).Remainder() == 0) return "Buzz"; return _input.ToString(); } } public class ModFactory{ public IRemainder Mod15(int input) => new Mod15(input); public IRemainder Mod3(int input) => new Mod3(input); public IRemainder Mod5(int input) => new Mod5(input); }

Slide 57

Slide 57 text

Where DO we Create? Technical Practices

Slide 58

Slide 58 text

No `new` inline - Where DO We Create? public class FizzBuzz{ public string Result(){ IFizzBuzzInput input = new FizzBuzzInput(); if (input.EvenlyDivisibleBy(15)) return "FizzBuzz"; if (input.EvenlyDivisibleBy(3)) return "Fizz"; if (input.EvenlyDivisibleBy(5)) return "Buzz"; return input.ToString(); } }

Slide 59

Slide 59 text

No `new` inline - Where DO We Create? public class FizzBuzz{ private readonly IFizzBuzzInput _input; public FizzBuzz() : this(new FizzBuzzInput()) { } private FizzBuzz(IFizzBuzzInput fizzBuzzInput) => _input = fizzBuzzInput; public string Result(){ if (_input.EvenlyDivisibleBy(15)) return "FizzBuzz"; if (_input.EvenlyDivisibleBy(3)) return "Fizz"; if (_input.EvenlyDivisibleBy(5)) return "Buzz"; return _input.ToString(); } } public class FizzBuzz{ public string Result(){ IFizzBuzzInput input = new FizzBuzzInput(); if (input.EvenlyDivisibleBy(15)) return "FizzBuzz"; if (input.EvenlyDivisibleBy(3)) return "Fizz"; if (input.EvenlyDivisibleBy(5)) return "Buzz"; return input.ToString(); } }

Slide 60

Slide 60 text

No `new` inline - Where DO We Create? public class FizzBuzz{ private readonly IFizzBuzzService _service; public FizzBuzz() : this(new FizzBuzzService()) { } private FizzBuzz(IFizzBuzzService fizzBuzzService) => _service = fizzBuzzService; public string Result(){ IFizzBuzzInput input = _service.FizzBuzzInput(); if (input.EvenlyDivisibleBy(15)) return "FizzBuzz"; if (input.EvenlyDivisibleBy(3)) return "Fizz"; if (input.EvenlyDivisibleBy(5)) return "Buzz"; return input.ToString(); } } public class FizzBuzzService : IFizzBuzzService { public IFizzBuzzInput FizzBuzzInput() { return new FizzBuzzInputFromNetwork(_foo); } }

Slide 61

Slide 61 text

Just Two Places No `new` inline

Slide 62

Slide 62 text

Why? No `new` inline

Slide 63

Slide 63 text

Testability No `new` inline - Why?

Slide 64

Slide 64 text

No `new` inline - Why? - Testability public class FizzBuzz{ private readonly IFizzBuzzInput _input; public FizzBuzz() : this(new FizzBuzzInput()) { } private FizzBuzz(IFizzBuzzInput fizzBuzzInput) => _input = fizzBuzzInput; public string Result(){ if (_input.EvenlyDivisibleBy(15)) return "FizzBuzz"; if (_input.EvenlyDivisibleBy(3)) return "Fizz"; if (_input.EvenlyDivisibleBy(5)) return "Buzz"; return _input.ToString(); } }

Slide 65

Slide 65 text

No `new` inline - Why? - Testability public class FizzBuzz{ private readonly IFizzBuzzInput _input; public FizzBuzz() : this(new FizzBuzzInput()) { } private FizzBuzz(IFizzBuzzInput fizzBuzzInput) => _input = fizzBuzzInput; public string Result(){ if (_input.EvenlyDivisibleBy(15)) return "FizzBuzz"; if (_input.EvenlyDivisibleBy(3)) return "Fizz"; if (_input.EvenlyDivisibleBy(5)) return "Buzz"; return _input.ToString(); } } public class FizzBuzz{ private readonly IFizzBuzzService _service; public FizzBuzz() : this(new FizzBuzzService()) { } private FizzBuzz(IFizzBuzzService fizzBuzzService) => _service = fizzBuzzService; public string Result(){ IFizzBuzzInput input = _service.FizzBuzzInput(); if (input.EvenlyDivisibleBy(15)) return "FizzBuzz"; if (input.EvenlyDivisibleBy(3)) return "Fizz"; if (input.EvenlyDivisibleBy(5)) return "Buzz"; return input.ToString(); } }

Slide 66

Slide 66 text

Expose Existing Cohesion No `new` inline - Why?

Slide 67

Slide 67 text

No `new` inline - Why? - Expose Existing Cohesion public class FizzBuzz{ private readonly int _input; public FizzBuzz(int input) => _input = input; public string Result(){ if (new Mod15(_input).IsMultipleOf()) return "FizzBuzz"; if (new Mod3(_input).IsMultipleOf()) return "Fizz"; if (new Mod5(_input).IsMultipleOf()) return "Buzz"; return _input.ToString(); } }

Slide 68

Slide 68 text

No `new` inline - Why? - Expose Existing Cohesion public class FizzBuzz{ public FizzBuzz(int input):this(input, new Mod15(input), new Mod3(input), new Mod5(input)) public string Result(){ if (_mod15.IsMultipleOf()) return "FizzBuzz"; if (_mod3.IsMultipleOf()) return "Fizz"; if (_mod5.IsMultipleOf()) return "Buzz"; return _input.ToString(); } }

Slide 69

Slide 69 text

No `new` inline - Why? - Expose Existing Cohesion public class FizzBuzz{ public FizzBuzz(int input):this(new IntToString(input), new Mod15(input), new Mod3(input), new Mod5(input)) public string Result(){ if (_mod15.IsMultipleOf()) return "FizzBuzz"; if (_mod3.IsMultipleOf()) return "Fizz"; if (_mod5.IsMultipleOf()) return "Buzz"; return _toString.Value(); } }

Slide 70

Slide 70 text

No `new` inline - Why? - Expose Existing Cohesion public class FizzBuzz{ public FizzBuzz(int input):this(new IntToString(input), new Mod15(input), new Mod3(input), new Mod5(input)) public string Result(){ if (_mod15.IsMultipleOf()) return _mod15.Value(); if (_mod3.IsMultipleOf()) return _mod3.Value(); if (_mod5.IsMultipleOf()) return _mod5.Value(); return _toString.Value(); } }

Slide 71

Slide 71 text

No `new` inline - Why? - Expose Existing Cohesion public class FizzBuzz{ public FizzBuzz(int input):this(new ToStringResult(input), new FizzBuzzResult(input), new FizzResult(input), new BuzzResult(input)) public string Result(){ if (_fizzBuzz.ShouldReturn()) return _fizzBuzz.Value(); if (_buzz.ShouldReturn()) return _buzz.Value(); if (_fizz.ShouldReturn()) return _fizz.Value(); return _toString.Value(); } }

Slide 72

Slide 72 text

Sustainable Code through Technical Practices ● No Getters / No Setters ● `if` Only As Guard Clause ● Isolate Their Code ● Never `null` ● No `new` inline ● Composition, Not Inheritance ● ● Be Immutable ● No Primitives ● Extract Cohesion ● No Public Statics ● Never Reflection No `new` inline @TheQuinnGil QuinnGil.com

Slide 73

Slide 73 text

Sustainable Code through Technical Practices ● No Getters / No Setters ● `if` Only As Guard Clause ● Isolate Their Code ● Never `null` ● No `new` inline ● Composition, Not Inheritance ● ● Be Immutable ● No Primitives ● Extract Cohesion ● No Public Statics ● Never Reflection @TheQuinnGil QuinnGil.com

Slide 74

Slide 74 text

Feature Parity in 25% of the Dev Hours @TheQuinnGil QuinnGil.com

Slide 75

Slide 75 text

THANK YOU! @TheQuinnGil QuinnGil.com

Slide 76

Slide 76 text

Sustainable Code through Technical Practices ● No Getters / No Setters ● `if` Only As Guard Clause ● Isolate Their Code ● Never `null` ● No `new` inline ● Composition, Not Inheritance ● ● Be Immutable ● No Primitives ● Extract Cohesion ● No Public Statics ● Never Reflection @TheQuinnGil QuinnGil.com