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

Trust Your Code - Don't Be Defensive 2019-09-14

Quinn
September 14, 2019

Trust Your Code - Don't Be Defensive 2019-09-14

Trust Your Code - Don't defend it.

We are trained to code defensively.
We have to defend our method against getting a bad result as a return argument.
We have to defend their method from being called when it shouldn't.
We have to defend ourselves against being passed unusable parameter.

We are so focused on defending and trying to know how everything our method uses works that we become numb to the damage we're inflicting on the source code itself.

Let's trust our code.
Let's trust the return value is something we can use.
Let's trust the method knows if it should execute or not.
Let's trust that the parameter we're given is usable.

Trusting our code simplifies our code.

This trust isn't free.
This trust takes discipline and rigor.
This trust takes practices that allow us to have this trust.

This talk is about the practices that enable us to trust our code and not be so defensive about it.

Quinn

September 14, 2019
Tweet

More Decks by Quinn

Other Decks in Programming

Transcript

  1. Trust Your Code
    @TheQuinnGil QuinnGil.com
    Seattle Code Camp 2019

    View Slide

  2. Quinn Gil
    Software Development Coach
    International Speaker on Software Development
    Past 15 years focused on High Quality code
    Blog at QuinnGil.com
    @TheQuinnGil QuinnGil.com

    View Slide

  3. This is for you.
    @TheQuinnGil QuinnGil.com

    View Slide

  4. Trust Your Code
    @TheQuinnGil QuinnGil.com

    View Slide

  5. “Untrusted Code”?
    @TheQuinnGil QuinnGil.com

    View Slide

  6. Untrusted Code - Defensive Code
    ● Defend the Method Perspective
    ○ PreConditions
    ○ Nulls
    ○ Assertions
    @TheQuinnGil QuinnGil.com

    View Slide

  7. Untrusted Code - Defenses
    ● Defend the Method Perspective
    ○ PreConditions
    ○ Nulls
    ○ Assertions
    ● Defend the Caller Perspective
    ○ State Verification
    ○ Exception Handling
    ○ OK to call
    @TheQuinnGil QuinnGil.com

    View Slide

  8. Untrusted Code - Defenses
    ● Defend the Method Perspective
    ○ PreConditions
    ○ Nulls
    ○ Assertions
    ● Defend the Caller Perspective
    ○ State Verification
    ○ Exception Handling
    ○ OK to call
    ● Defend the Using Perspective
    ○ Null
    ○ Ready
    ○ Valid
    @TheQuinnGil QuinnGil.com

    View Slide

  9. Is “Defensive Code”
    really that bad?
    @TheQuinnGil QuinnGil.com

    View Slide

  10. Why not “Defensive Code”?
    ● A defense somewhere is a defense everywhere
    @TheQuinnGil QuinnGil.com

    View Slide

  11. Why not “Defensive Code”?
    ● A defense somewhere is a defense everywhere
    ● Complicates the code
    @TheQuinnGil QuinnGil.com

    View Slide

  12. Why not “Defensive Code”?
    ● A defense somewhere is a defense everywhere
    ● Complicates the code
    ● Higher Cognitive Load
    @TheQuinnGil QuinnGil.com

    View Slide

  13. Why not “Defensive Code”?
    ● A defense somewhere is a defense everywhere
    ● Complicates the code
    ● Higher Cognitive Load
    ● Write more code
    @TheQuinnGil QuinnGil.com

    View Slide

  14. Why not “Defensive Code”?
    ● A defense somewhere is a defense everywhere
    ● Complicates the code
    ● Higher Cognitive Load
    ● Write more code
    ● Maintain more code
    @TheQuinnGil QuinnGil.com

    View Slide

  15. Why not “Defensive Code”?
    ● A defense somewhere is a defense everywhere
    ● Complicates the code
    ● Higher Cognitive Load
    ● Write more code
    ● Maintain more code
    ● Dead Code? Undetectable?
    @TheQuinnGil QuinnGil.com

    View Slide

  16. How do we protect the code?
    @TheQuinnGil QuinnGil.com

    View Slide

  17. How do we protect the code?
    @TheQuinnGil QuinnGil.com
    I don’t

    View Slide

  18. How do we protect the code?
    @TheQuinnGil QuinnGil.com
    I don’t... directly.

    View Slide

  19. Trust Your Code
    with
    Technical Practices
    @TheQuinnGil QuinnGil.com

    View Slide

  20. Trusting Your Code
    is
    Sustainable Code
    @TheQuinnGil QuinnGil.com

    View Slide

  21. Sustainable Code
    through
    Technical Practices
    @TheQuinnGil QuinnGil.com

    View Slide

  22. Sustainable Code
    through
    Technical Practices
    @TheQuinnGil QuinnGil.com

    View Slide

  23. Sustainable Code
    through
    Technical Practices
    @TheQuinnGil QuinnGil.com

    View Slide

  24. Tests
    @TheQuinnGil QuinnGil.com

    View Slide

  25. 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

    View Slide

  26. 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

    View Slide

  27. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    HttpClient httpClient = new HttpClient();
    HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(r);
    string readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync();
    JObject jsonContent = JObject.Parse(readAsStringAsync);
    string value = jsonContent.Value("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  28. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    //COUPLING
    HttpClient httpClient = new HttpClient();
    HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(r);
    string readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync();
    JObject jsonContent = JObject.Parse(readAsStringAsync);
    string value = jsonContent.Value("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  29. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    //COUPLING
    HttpClient httpClient = new HttpClient();
    //EXCEPTION
    HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(r);
    string readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync();
    JObject jsonContent = JObject.Parse(readAsStringAsync);
    string value = jsonContent.Value("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  30. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    //COUPLING
    HttpClient httpClient = new HttpClient();
    //EXCEPTION
    HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(r);
    string readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync();
    //EXCEPTION, COUPLING
    JObject jsonContent = JObject.Parse(readAsStringAsync);
    string value = jsonContent.Value("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  31. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    //COUPLING
    HttpClient httpClient = new HttpClient();
    //EXCEPTION
    HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(r);
    string readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync();
    //EXCEPTION, COUPLING
    JObject jsonContent = JObject.Parse(readAsStringAsync);
    //IMPERATIVE
    string value = jsonContent.Value("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  32. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    //COUPLING
    HttpClient httpClient = new HttpClient();
    //EXCEPTION
    HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(r);
    string readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync();
    //EXCEPTION, COUPLING
    JObject jsonContent = JObject.Parse(readAsStringAsync);
    //IMPERATIVE
    string value = jsonContent.Value("some_key");
    //EXCEPTION
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  33. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    HttpClient httpClient = new HttpClient();
    HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(r);
    string readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync();
    JObject jsonContent = JObject.Parse(readAsStringAsync);
    string value = jsonContent.Value("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  34. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    IHttpClientBookEnd httpClient = new HttpClientFacade();
    HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(r);
    string readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync();
    JObject jsonContent = JObject.Parse(readAsStringAsync);
    string value = jsonContent.Value("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  35. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    IHttpClientBookEnd httpClient = new HttpClientFacade();
    IHttpResponseMessageBookEnd httpResponseMessage = await httpClient.SendAsync(r);
    string readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync();
    JObject jsonContent = JObject.Parse(readAsStringAsync);
    string value = jsonContent.Value("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  36. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    IHttpClientBookEnd httpClient = new HttpClientFacade();
    IHttpResponseMessageBookEnd httpResponseMessage = await httpClient.SendAsync(r);
    string readAsStringAsync = await httpResponseMessage.ContentAsStringAsync();
    JObject jsonContent = JObject.Parse(readAsStringAsync);
    string value = jsonContent.Value("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  37. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    IHttpResponseMessageBookEnd httpResponseMessage = await _httpClient.SendAsync(r);
    string readAsStringAsync = await httpResponseMessage.ContentAsStringAsync();
    JObject jsonContent = JObject.Parse(readAsStringAsync);
    string value = jsonContent.Value("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  38. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    IHttpResponseMessageBookEnd httpResponseMessage = await _httpClient.SendAsync(r);
    string readAsStringAsync = await httpResponseMessage.ContentAsStringAsync();
    IParsedObject parsedObject = _parser.Parse(readAsStringAsync);
    string value = parsedObject.StringValue("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  39. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    IHttpResponseMessageBookEnd httpResponseMessage = await _httpClient.SendAsync(r);
    IParsedObject parsedObject = await httpResponseMessage.ParsedContent(_parser);
    string value = parsedObject.StringValue("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  40. Technical Practices - Isolate Their Code - 3rd Party
    public async Task NetworkCall(HttpRequestMessage r)
    {
    HttpClient httpClient = new HttpClient();
    HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(r);
    string readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync();
    JObject jsonContent = JObject.Parse(readAsStringAsync);
    string value = jsonContent.Value("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    public async Task NetworkCall(HttpRequestMessage r)
    {
    IHttpResponseMessageBookEnd httpResponseMessage = await _httpClient.SendAsync(r);
    IParsedObject parsedObject = await httpResponseMessage.ParsedContent(_parser);
    string value = parsedObject.StringValue("some_key");
    return value.Contains("expected_Value") ? "Success" : "Failure";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  41. What Else?
    Technical Practices - Isolate Their Code
    @TheQuinnGil QuinnGil.com

    View Slide

  42. Operating System
    Technical Practices - Isolate Their Code
    @TheQuinnGil QuinnGil.com

    View Slide

  43. How?
    Technical Practices - Isolate Their Code
    @TheQuinnGil QuinnGil.com

    View Slide

  44. Technical Practices - Isolate Their Code - How?
    internal class HttpClientFacade : IHttpClientBookEnd
    {
    private static HttpClient _testClient;
    #if DEBUG
    public static void SetTestClient(HttpClient testClient) => _testClient = testClient;
    #endif
    private readonly HttpClient _httpClient;
    public HttpClientFacade() : this(new HttpClient()) { }
    private HttpClientFacade(HttpClient httpClient) => _httpClient = httpClient;
    public async Task SendRequestAsync(HttpRequestMessage msg)
    => new HttpResponseMessageAdapter(await HttpClient().SendAsync(msg));
    private HttpClient HttpClient() => _testClient ?? _httpClient;
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  45. Technical Practices - Isolate Their Code - How?
    internal class HttpClientFacade : IHttpClientBookEnd
    {
    private static HttpClient _testClient;
    #if DEBUG
    public static void SetTestClient(HttpClient testClient) => _testClient = testClient;
    #endif
    private readonly HttpClient _httpClient;
    public HttpClientFacade() : this(new HttpClient()) { }
    private HttpClientFacade(HttpClient httpClient) => _httpClient = httpClient;
    public async Task SendRequestAsync(HttpRequestMessage msg)
    => new HttpResponseMessageAdapter(await HttpClient().SendAsync(msg));
    private HttpClient HttpClient() => _testClient ?? _httpClient;
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  46. Technical Practices - Isolate Their Code - How?
    internal class HttpClientFacade : IHttpClientBookEnd
    {
    private static HttpClient _testClient;
    #if DEBUG
    public static void SetTestClient(HttpClient testClient) => _testClient = testClient;
    #endif
    private readonly HttpClient _httpClient;
    public HttpClientFacade() : this(new HttpClient()) { }
    private HttpClientFacade(HttpClient httpClient) => _httpClient = httpClient;
    public async Task SendRequestAsync(HttpRequestMessage msg)
    => new HttpResponseMessageAdapter(await HttpClient().SendAsync(msg));
    private HttpClient HttpClient() => _testClient ?? _httpClient;
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  47. Technical Practices - Isolate Their Code - How?
    internal class HttpClientFacade : IHttpClientBookEnd
    {
    private static HttpClient _testClient;
    #if DEBUG
    public static void SetTestClient(HttpClient testClient) => _testClient = testClient;
    #endif
    private readonly HttpClient _httpClient;
    public HttpClientFacade() : this(new HttpClient()) { }
    private HttpClientFacade(HttpClient httpClient) => _httpClient = httpClient;
    public async Task SendRequestAsync(HttpRequestMessage msg)
    => new HttpResponseMessageAdapter(await HttpClient().SendAsync(msg));
    private HttpClient HttpClient() => _testClient ?? _httpClient;
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  48. User Interface
    Technical Practices - Isolate Their Code
    @TheQuinnGil QuinnGil.com

    View Slide

  49. 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
    Trust Your Code by controlling interactions with 3rd Party Code

    View Slide

  50. 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

    View Slide

  51. Why?
    Technical Practices - Never `null`
    @TheQuinnGil QuinnGil.com

    View Slide

  52. How?
    Technical Practices - Never `null`
    @TheQuinnGil QuinnGil.com

    View Slide

  53. 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;
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  54. 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";
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  55. 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();
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  56. 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);
    //...
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  57. 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();
    //...
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  58. 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();
    //...
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  59. 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
    Trust Your Code by always having valid objects

    View Slide

  60. Sustainable Code through Technical Practices
    No Primitives
    @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

    View Slide

  61. Primitives?
    Technical Practices - No Primitives
    @TheQuinnGil QuinnGil.com

    View Slide

  62. Technical Practices - What are Primitives?
    ● Data (string, int, double, float, ...)
    @TheQuinnGil QuinnGil.com

    View Slide

  63. Technical Practices - What are Primitives?
    ● Data (string, int, double, float, ...)
    ● Collections (List, Map, Dictionary, ...)
    @TheQuinnGil QuinnGil.com

    View Slide

  64. Technical Practices - What are Primitives?
    ● Data (string, int, double, float, ...)
    ● Collections (List, Map, Dictionary, ...)
    ● Enums
    @TheQuinnGil QuinnGil.com

    View Slide

  65. Technical Practices - What are Primitives?
    ● Data (string, int, double, float, ...)
    ● Collections (List, Map, Dictionary, ...)
    ● Enums
    ● More?
    @TheQuinnGil QuinnGil.com

    View Slide

  66. Why not Primitives?
    Technical Practices - No Primitives
    @TheQuinnGil QuinnGil.com

    View Slide

  67. ● Object oriented programming wants object interaction, not data manipulation
    Technical Practices - Why No Primitives?
    @TheQuinnGil QuinnGil.com

    View Slide

  68. ● Object oriented programming wants object interaction, not data manipulation
    ● Primitives are data, not objects
    Technical Practices - Why No Primitives?
    @TheQuinnGil QuinnGil.com

    View Slide

  69. ● Object oriented programming wants object interaction, not data manipulation
    ● Primitives are data, not objects
    ● Primitives force complex imperative code
    Technical Practices - Why No Primitives?
    @TheQuinnGil QuinnGil.com

    View Slide

  70. ● Object oriented programming wants object interaction, not data manipulation
    ● Primitives are data, not objects
    ● Primitives force complex imperative code
    ● Primitives hinder Emergent Design
    Technical Practices - Why No Primitives?
    @TheQuinnGil QuinnGil.com

    View Slide

  71. ● Object oriented programming wants object interaction, not data manipulation
    ● Primitives are data, not objects
    ● Primitives force complex imperative code
    ● Primitives hinder Evolutionary Architecture
    ● Primitives limit use of Design Patterns
    Technical Practices - Why No Primitives?
    @TheQuinnGil QuinnGil.com

    View Slide

  72. Instead?
    Technical Practices - No Primitives
    @TheQuinnGil QuinnGil.com

    View Slide

  73. Represent the Concept
    Technical Practices - No Primitives
    @TheQuinnGil QuinnGil.com

    View Slide

  74. Technical Practices - No Primitives - Age Example
    public bool ThirteenOrLess(DataPerson person)
    {
    DateTime birthDate = DateTime.Parse(person.BirthDate);
    int age = DateTime.Now.Year - birthDate.Year;
    /* is this right?*/
    return age <= 13;
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  75. public bool ThirteenOrLess(DataPerson person)
    {
    DateTime birthDate = DateTime.Parse(person.BirthDate);
    int age = DateTime.Now.Year - birthDate.Year;
    if (birthDate.Date > DateTime.Now.AddYears(-age)) age--;
    return age <= 13;
    }
    @TheQuinnGil QuinnGil.com
    Technical Practices - No Primitives - Age Example

    View Slide

  76. public bool ThirteenOrLess(DataPerson person)
    {
    DateTime birthDate = DateTime.Parse(person.BirthDate);
    int age = DateTime.Now.Year - birthDate.Year;
    if (birthDate.Date > DateTime.Now.AddYears(-age)) age--;
    switch (person.State)
    {
    case "WA":
    return age <= 13;
    case "AK":
    return age <= 14;
    }
    return false;
    }
    @TheQuinnGil QuinnGil.com
    Technical Practices - No Primitives - Age Example

    View Slide

  77. public bool IsMinor(DataPerson person)
    {
    DateTime birthDate = DateTime.Parse(person.BirthDate);
    int age = DateTime.Now.Year - birthDate.Year;
    if (birthDate.Date > DateTime.Now.AddYears(-age)) age--;
    switch (person.State)
    {
    case "WA":
    return age <= 13;
    case "AK":
    return age <= 14;
    }
    return false;
    }
    @TheQuinnGil QuinnGil.com
    Technical Practices - No Primitives - Age Example

    View Slide

  78. public class Age : IAge
    {
    public bool IsMinor()
    {
    DateTime birthDate = DateTime.Parse(_birthdate);
    int age = DateTime.Now.Year - birthDate.Year;
    if (birthDate.Date > DateTime.Now.AddYears(-age)) age--;
    switch (_state)
    {
    case "WA":
    return age <= 13;
    case "AK":
    return age <= 14;
    }
    return false;
    }
    }
    @TheQuinnGil QuinnGil.com
    Technical Practices - No Primitives - Age Example

    View Slide

  79. public class Age : IAge
    {
    public bool IsMinor()
    {
    DateTime birthDate = DateTime.Parse(_birthdate);
    int age = DateTime.Now.Year - birthDate.Year;
    if (birthDate.Date > DateTime.Now.AddYears(-age)) age--;
    switch (_state)
    {
    case "WA":
    return age <= 13;
    case "AK":
    return age <= 14;
    }
    return false;
    }
    }
    public class Person
    {
    private readonly string _birthdate;
    private readonly string _state;
    public IAge Age() => new Age(_birthdate, _state);
    }
    @TheQuinnGil QuinnGil.com
    Technical Practices - No Primitives - Age Example

    View Slide

  80. public class Age : IAge
    {
    public bool IsMinor()
    {
    DateTime birthDate = DateTime.Parse(_birthdate);
    int age = DateTime.Now.Year - birthDate.Year;
    if (birthDate.Date > DateTime.Now.AddYears(-age)) age--;
    return age <= _state.MinorAge();
    }
    }
    public class Person
    {
    private readonly string _birthdate;
    private readonly State _state;
    public IAge Age() => new Age(_birthdate, _state);
    }
    @TheQuinnGil QuinnGil.com
    Technical Practices - No Primitives - Age Example

    View Slide

  81. Technical Practices - No Primitives - Age Example
    @TheQuinnGil QuinnGil.com
    Represent the Concept

    View Slide

  82. Technical Practices - No Primitives - Units
    public float Convert(float value)
    @TheQuinnGil QuinnGil.com

    View Slide

  83. Technical Practices - No Primitives - Units
    public float Convert(float value)
    {
    return value * 1.609334f;
    }
    @TheQuinnGil QuinnGil.com

    View Slide

  84. Technical Practices - No Primitives - Units
    public float Convert(float value)
    {
    return value * 1.609334f;
    }
    Money?
    @TheQuinnGil QuinnGil.com

    View Slide

  85. Technical Practices - No Primitives - Units
    public float Convert(float value)
    {
    return value * 1.609334f;
    }
    Money? Distance?
    @TheQuinnGil QuinnGil.com

    View Slide

  86. Technical Practices - No Primitives - Units
    public float Convert(float value)
    {
    return value * 1.609334f;
    }
    @TheQuinnGil QuinnGil.com
    Money? Distance?
    Convert To? From?

    View Slide

  87. Technical Practices - No Primitives - Units
    public float Convert(float distance)
    {
    return distance * 1.609334f;
    }
    Missing Meta Data
    Convert To? From?
    @TheQuinnGil QuinnGil.com
    Money? Distance?

    View Slide

  88. Technical Practices - No Primitives - Units
    public class Distance
    ...
    distance.ToKilometer();
    ...
    With Meta Data
    @TheQuinnGil QuinnGil.com

    View Slide

  89. Technical Practices - No Primitives - Age Example
    @TheQuinnGil QuinnGil.com
    Represent the Concept

    View Slide

  90. Sustainable Code through Technical Practices
    No Primitives
    @TheQuinnGil QuinnGil.com
    Trust Your Code by having objects represent the concepts in the code
    ● 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

    View Slide

  91. Sustainable Code through Technical Practices
    @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

    View Slide

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

    View Slide

  93. THANK YOU!
    @TheQuinnGil QuinnGil.com

    View Slide

  94. 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

    View Slide