Share
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
Transcript
94 slides
-
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 -
Untrusted Code - Defensive Code • Defend the Method Perspective
◦ PreConditions ◦ Nulls ◦ Assertions @TheQuinnGil QuinnGil.com -
Untrusted Code - Defenses • Defend the Method Perspective ◦
PreConditions ◦ Nulls ◦ Assertions • Defend the Caller Perspective ◦ State Verification ◦ Exception Handling ◦ OK to call @TheQuinnGil QuinnGil.com -
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 -
Why not “Defensive Code”? • A defense somewhere is a
defense everywhere @TheQuinnGil QuinnGil.com -
Why not “Defensive Code”? • A defense somewhere is a
defense everywhere • Complicates the code @TheQuinnGil QuinnGil.com -
Why not “Defensive Code”? • A defense somewhere is a
defense everywhere • Complicates the code • Higher Cognitive Load @TheQuinnGil QuinnGil.com -
Why not “Defensive Code”? • A defense somewhere is a
defense everywhere • Complicates the code • Higher Cognitive Load • Write more code @TheQuinnGil QuinnGil.com -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
Technical Practices - What are Primitives? • Data (string, int,
double, float, ...) @TheQuinnGil QuinnGil.com -
Technical Practices - What are Primitives? • Data (string, int,
double, float, ...) • Collections (List, Map, Dictionary, ...) @TheQuinnGil QuinnGil.com -
Technical Practices - What are Primitives? • Data (string, int,
double, float, ...) • Collections (List, Map, Dictionary, ...) • Enums @TheQuinnGil QuinnGil.com -
Technical Practices - What are Primitives? • Data (string, int,
double, float, ...) • Collections (List, Map, Dictionary, ...) • Enums • More? @TheQuinnGil QuinnGil.com -
• Object oriented programming wants object interaction, not data manipulation
Technical Practices - Why No Primitives? @TheQuinnGil QuinnGil.com -
• Object oriented programming wants object interaction, not data manipulation
• Primitives are data, not objects Technical Practices - Why No Primitives? @TheQuinnGil QuinnGil.com -
• 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 -
• 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 -
• 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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
Technical Practices - No Primitives - Age Example @TheQuinnGil QuinnGil.com
Represent the Concept -
Technical Practices - No Primitives - Units public float Convert(float
value) @TheQuinnGil QuinnGil.com -
Technical Practices - No Primitives - Units public float Convert(float
value) { return value * 1.609334f; } @TheQuinnGil QuinnGil.com -
Technical Practices - No Primitives - Units public float Convert(float
value) { return value * 1.609334f; } Money? @TheQuinnGil QuinnGil.com -
Technical Practices - No Primitives - Units public float Convert(float
value) { return value * 1.609334f; } Money? Distance? @TheQuinnGil QuinnGil.com -
Technical Practices - No Primitives - Units public float Convert(float
value) { return value * 1.609334f; } @TheQuinnGil QuinnGil.com Money? Distance? Convert To? From? -
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? -
Technical Practices - No Primitives - Units public class Distance
... distance.ToKilometer(); ... With Meta Data @TheQuinnGil QuinnGil.com -
Technical Practices - No Primitives - Age Example @TheQuinnGil QuinnGil.com
Represent the Concept -
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 -
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 -
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