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. 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
  2. Untrusted Code - Defensive Code • Defend the Method Perspective

    ◦ PreConditions ◦ Nulls ◦ Assertions @TheQuinnGil QuinnGil.com
  3. Untrusted Code - Defenses • Defend the Method Perspective ◦

    PreConditions ◦ Nulls ◦ Assertions • Defend the Caller Perspective ◦ State Verification ◦ Exception Handling ◦ OK to call @TheQuinnGil QuinnGil.com
  4. 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
  5. Why not “Defensive Code”? • A defense somewhere is a

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

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

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

    defense everywhere • Complicates the code • Higher Cognitive Load • Write more code @TheQuinnGil QuinnGil.com
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. Technical Practices - What are Primitives? • Data (string, int,

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

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

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

    double, float, ...) • Collections (List, Map, Dictionary, ...) • Enums • More? @TheQuinnGil QuinnGil.com
  45. • Object oriented programming wants object interaction, not data manipulation

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

    • Primitives are data, not objects Technical Practices - Why No Primitives? @TheQuinnGil QuinnGil.com
  47. • 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
  48. • 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
  49. • 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
  50. 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
  51. 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
  52. 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
  53. 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
  54. 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
  55. 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
  56. 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
  57. Technical Practices - No Primitives - Units public float Convert(float

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

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

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

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

    ... distance.ToKilometer(); ... With Meta Data @TheQuinnGil QuinnGil.com
  63. 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
  64. 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
  65. 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