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

5b92c5ea42bc2c2ab28d973d5da63cd6?s=47 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.

5b92c5ea42bc2c2ab28d973d5da63cd6?s=128

Quinn

September 14, 2019
Tweet

Transcript

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

  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
  3. This is for you. @TheQuinnGil QuinnGil.com

  4. Trust Your Code @TheQuinnGil QuinnGil.com

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

  6. Untrusted Code - Defensive Code • Defend the Method Perspective

    ◦ PreConditions ◦ Nulls ◦ Assertions @TheQuinnGil QuinnGil.com
  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
  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
  9. Is “Defensive Code” really that bad? @TheQuinnGil QuinnGil.com

  10. Why not “Defensive Code”? • A defense somewhere is a

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

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

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

    defense everywhere • Complicates the code • Higher Cognitive Load • Write more code @TheQuinnGil QuinnGil.com
  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
  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
  16. How do we protect the code? @TheQuinnGil QuinnGil.com

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

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

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

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

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

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

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

  24. Tests @TheQuinnGil QuinnGil.com

  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 • <Strong opinions loosely held> • Be Immutable • No Primitives • Extract Cohesion • No Public Statics • Never Reflection @TheQuinnGil QuinnGil.com
  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 • <Strong opinions loosely held> • Be Immutable • No Primitives • Extract Cohesion • No Public Statics • Never Reflection
  27. Technical Practices - Isolate Their Code - 3rd Party public

    async Task<string> 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<string>("some_key"); return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com
  28. Technical Practices - Isolate Their Code - 3rd Party public

    async Task<string> 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<string>("some_key"); return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com
  29. Technical Practices - Isolate Their Code - 3rd Party public

    async Task<string> 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<string>("some_key"); return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com
  30. Technical Practices - Isolate Their Code - 3rd Party public

    async Task<string> 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<string>("some_key"); return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com
  31. Technical Practices - Isolate Their Code - 3rd Party public

    async Task<string> 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<string>("some_key"); return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com
  32. Technical Practices - Isolate Their Code - 3rd Party public

    async Task<string> 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<string>("some_key"); //EXCEPTION return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com
  33. Technical Practices - Isolate Their Code - 3rd Party public

    async Task<string> 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<string>("some_key"); return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com
  34. Technical Practices - Isolate Their Code - 3rd Party public

    async Task<string> 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<string>("some_key"); return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com
  35. Technical Practices - Isolate Their Code - 3rd Party public

    async Task<string> 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<string>("some_key"); return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com
  36. Technical Practices - Isolate Their Code - 3rd Party public

    async Task<string> 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<string>("some_key"); return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com
  37. Technical Practices - Isolate Their Code - 3rd Party public

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

    async Task<string> 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
  39. Technical Practices - Isolate Their Code - 3rd Party public

    async Task<string> 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
  40. Technical Practices - Isolate Their Code - 3rd Party public

    async Task<string> 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<string>("some_key"); return value.Contains("expected_Value") ? "Success" : "Failure"; } public async Task<string> 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
  41. What Else? Technical Practices - Isolate Their Code @TheQuinnGil QuinnGil.com

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

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

  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<IHttpResponseMessageBookEnd> SendRequestAsync(HttpRequestMessage msg) => new HttpResponseMessageAdapter(await HttpClient().SendAsync(msg)); private HttpClient HttpClient() => _testClient ?? _httpClient; } @TheQuinnGil QuinnGil.com
  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<IHttpResponseMessageBookEnd> SendRequestAsync(HttpRequestMessage msg) => new HttpResponseMessageAdapter(await HttpClient().SendAsync(msg)); private HttpClient HttpClient() => _testClient ?? _httpClient; } @TheQuinnGil QuinnGil.com
  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<IHttpResponseMessageBookEnd> SendRequestAsync(HttpRequestMessage msg) => new HttpResponseMessageAdapter(await HttpClient().SendAsync(msg)); private HttpClient HttpClient() => _testClient ?? _httpClient; } @TheQuinnGil QuinnGil.com
  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<IHttpResponseMessageBookEnd> SendRequestAsync(HttpRequestMessage msg) => new HttpResponseMessageAdapter(await HttpClient().SendAsync(msg)); private HttpClient HttpClient() => _testClient ?? _httpClient; } @TheQuinnGil QuinnGil.com
  48. User Interface Technical Practices - Isolate Their Code @TheQuinnGil QuinnGil.com

  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 • <Strong opinions loosely held> • Be Immutable • No Primitives • Extract Cohesion • No Public Statics • Never Reflection Trust Your Code by controlling interactions with 3rd Party Code
  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 • <Strong opinions loosely held> • Be Immutable • No Primitives • Extract Cohesion • No Public Statics • Never Reflection
  51. Why? Technical Practices - Never `null` @TheQuinnGil QuinnGil.com

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

  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
  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
  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
  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
  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
  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
  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 • <Strong opinions loosely held> • Be Immutable • No Primitives • Extract Cohesion • No Public Statics • Never Reflection Trust Your Code by always having valid objects
  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 • <Strong opinions loosely held> • Be Immutable • No Primitives • Extract Cohesion • No Public Statics • Never Reflection
  61. Primitives? Technical Practices - No Primitives @TheQuinnGil QuinnGil.com

  62. Technical Practices - What are Primitives? • Data (string, int,

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

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

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

    double, float, ...) • Collections (List, Map, Dictionary, ...) • Enums • More? @TheQuinnGil QuinnGil.com
  66. Why not Primitives? Technical Practices - No Primitives @TheQuinnGil QuinnGil.com

  67. • Object oriented programming wants object interaction, not data manipulation

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

    • Primitives are data, not objects Technical Practices - Why No Primitives? @TheQuinnGil QuinnGil.com
  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
  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
  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
  72. Instead? Technical Practices - No Primitives @TheQuinnGil QuinnGil.com

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

  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
  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
  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
  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
  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
  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
  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
  81. Technical Practices - No Primitives - Age Example @TheQuinnGil QuinnGil.com

    Represent the Concept
  82. Technical Practices - No Primitives - Units public float Convert(float

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

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

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

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

    value) { return value * 1.609334f; } @TheQuinnGil QuinnGil.com Money? Distance? Convert To? From?
  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?
  88. Technical Practices - No Primitives - Units public class Distance

    ... distance.ToKilometer(); ... With Meta Data @TheQuinnGil QuinnGil.com
  89. Technical Practices - No Primitives - Age Example @TheQuinnGil QuinnGil.com

    Represent the Concept
  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 • <Strong opinions loosely held> • Be Immutable • No Primitives • Extract Cohesion • No Public Statics • Never Reflection
  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 • <Strong opinions loosely held> • Be Immutable • No Primitives • Extract Cohesion • No Public Statics • Never Reflection
  92. Feature Parity in 25% of the Dev Hours @TheQuinnGil QuinnGil.com

  93. THANK YOU! @TheQuinnGil QuinnGil.com

  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 • <Strong opinions loosely held> • Be Immutable • No Primitives • Extract Cohesion • No Public Statics • Never Reflection @TheQuinnGil QuinnGil.com