Trust Your Code
@TheQuinnGil QuinnGil.com
Seattle Code Camp 2019
Slide 2
Slide 2 text
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 - Defenses
● Defend the Method Perspective
○ PreConditions
○ Nulls
○ Assertions
● Defend the Caller Perspective
○ State Verification
○ Exception Handling
○ OK to call
@TheQuinnGil QuinnGil.com
Slide 8
Slide 8 text
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
Slide 9
Slide 9 text
Is “Defensive Code”
really that bad?
@TheQuinnGil QuinnGil.com
Slide 10
Slide 10 text
Why not “Defensive Code”?
● A defense somewhere is a defense everywhere
@TheQuinnGil QuinnGil.com
Slide 11
Slide 11 text
Why not “Defensive Code”?
● A defense somewhere is a defense everywhere
● Complicates the code
@TheQuinnGil QuinnGil.com
Slide 12
Slide 12 text
Why not “Defensive Code”?
● A defense somewhere is a defense everywhere
● Complicates the code
● Higher Cognitive Load
@TheQuinnGil QuinnGil.com
Slide 13
Slide 13 text
Why not “Defensive Code”?
● A defense somewhere is a defense everywhere
● Complicates the code
● Higher Cognitive Load
● Write more code
@TheQuinnGil QuinnGil.com
Slide 14
Slide 14 text
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
Slide 15
Slide 15 text
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
Slide 16
Slide 16 text
How do we protect the code?
@TheQuinnGil QuinnGil.com
Slide 17
Slide 17 text
How do we protect the code?
@TheQuinnGil QuinnGil.com
I don’t
Slide 18
Slide 18 text
How do we protect the code?
@TheQuinnGil QuinnGil.com
I don’t... directly.
Slide 19
Slide 19 text
Trust Your Code
with
Technical Practices
@TheQuinnGil QuinnGil.com
Slide 20
Slide 20 text
Trusting Your Code
is
Sustainable Code
@TheQuinnGil QuinnGil.com
Slide 21
Slide 21 text
Sustainable Code
through
Technical Practices
@TheQuinnGil QuinnGil.com
Slide 22
Slide 22 text
Sustainable Code
through
Technical Practices
@TheQuinnGil QuinnGil.com
Slide 23
Slide 23 text
Sustainable Code
through
Technical Practices
@TheQuinnGil QuinnGil.com
Slide 24
Slide 24 text
Tests
@TheQuinnGil QuinnGil.com
Slide 25
Slide 25 text
Sustainable Code through Technical Practices
● No Getters / No Setters
● `if` Only As Guard Clause
● Isolate Their Code
● Never `null`
● No `new` inline
● Composition, Not Inheritance
●
● Be Immutable
● No Primitives
● Extract Cohesion
● No Public Statics
● Never Reflection
@TheQuinnGil QuinnGil.com
Slide 26
Slide 26 text
Sustainable Code through Technical Practices
Isolate Their Code
@TheQuinnGil QuinnGil.com
● No Getters / No Setters
● `if` Only As Guard Clause
● Isolate Their Code
● Never `null`
● No `new` inline
● Composition, Not Inheritance
●
● Be Immutable
● No Primitives
● Extract Cohesion
● No Public Statics
● Never Reflection
Slide 27
Slide 27 text
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
Slide 28
Slide 28 text
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
Slide 29
Slide 29 text
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
User Interface
Technical Practices - Isolate Their Code
@TheQuinnGil QuinnGil.com
Slide 49
Slide 49 text
Sustainable Code through Technical Practices
Isolate Their Code
@TheQuinnGil QuinnGil.com
● No Getters / No Setters
● `if` Only As Guard Clause
● Isolate Their Code
● Never `null`
● No `new` inline
● Composition, Not Inheritance
●
● Be Immutable
● No Primitives
● Extract Cohesion
● No Public Statics
● Never Reflection
Trust Your Code by controlling interactions with 3rd Party Code
Slide 50
Slide 50 text
Sustainable Code through Technical Practices
Never `null`
@TheQuinnGil QuinnGil.com
● No Getters / No Setters
● `if` Only As Guard Clause
● Isolate Their Code
● Never `null`
● No `new` inline
● Composition, Not Inheritance
●
● Be Immutable
● No Primitives
● Extract Cohesion
● No Public Statics
● Never Reflection
Slide 51
Slide 51 text
Why?
Technical Practices - Never `null`
@TheQuinnGil QuinnGil.com
Slide 52
Slide 52 text
How?
Technical Practices - Never `null`
@TheQuinnGil QuinnGil.com
Slide 53
Slide 53 text
Technical Practices - Never `null`
public string CalculateThing(ICanBeNull canBeNull)
{
if (canBeNull == null) return "Default";
IAlsoNull alsoNull = canBeNull.Example();
if (alsoNull == null) return "Default";
string sample = alsoNull.Sample();
if (sample == null) return "Default";
return sample;
}
@TheQuinnGil QuinnGil.com
Slide 54
Slide 54 text
Technical Practices - Never `null`
public string CalculateThing(ICanBeNull canBeNull)
{
if (canBeNull == null) return "Default";
IAlsoNull alsoNull = canBeNull.Example();
if (alsoNull == null) return "Default";
string sample = alsoNull.Sample();
if (sample == null) return "Default";
return sample;
}
public string CalculateThing(ICanBeNull canBeNull)
{
return canBeNull?.Example()?.Sample() ?? "Default";
}
@TheQuinnGil QuinnGil.com
Slide 55
Slide 55 text
Technical Practices - Never `null`
public string CalculateThing(ICanBeNull canBeNull)
{
if (canBeNull == null) return "Default";
IAlsoNull alsoNull = canBeNull.Example();
if (alsoNull == null) return "Default";
string sample = alsoNull.Sample();
if (sample == null) return "Default";
return sample;
}
public string CalculateThing(ICanBeNull canBeNull)
{
return canBeNull?.Example()?.Sample() ?? "Default";
}
public string CalculateThing(ICanNotBeNull canNotBeNull)
{
return canNotBeNull.Example().Sample();
}
@TheQuinnGil QuinnGil.com
Slide 56
Slide 56 text
Technical Practices - Never `null`
public string CalculateThing(ICanBeNull canBeNull)
{
if (canBeNull == null) return "Default";
IAlsoNull alsoNull = canBeNull.Example();
if (alsoNull == null) return "Default";
string sample = alsoNull.Sample();
if (sample == null) return "Default";
return sample;
}
public string CalculateThing(ICanBeNull canBeNull)
{
return canBeNull?.Example()?.Sample() ?? "Default";
}
public string CalculateThing(ICanNotBeNull canNotBeNull)
{
return canNotBeNull.Example().Sample();
}
public void Foo()
{
string thing = _bar.CalculateThing(_canBeNull);
//...
}
@TheQuinnGil QuinnGil.com
Slide 57
Slide 57 text
Technical Practices - Never `null`
public string CalculateThing(ICanBeNull canBeNull)
{
if (canBeNull == null) return "Default";
IAlsoNull alsoNull = canBeNull.Example();
if (alsoNull == null) return "Default";
string sample = alsoNull.Sample();
if (sample == null) return "Default";
return sample;
}
public string CalculateThing(ICanBeNull canBeNull)
{
return canBeNull?.Example()?.Sample() ?? "Default";
}
public string CalculateThing(ICanNotBeNull canNotBeNull)
{
return canNotBeNull.Example().Sample();
}
public void Foo()
{
string thing = _bar.CalculateThing(_canBeNull);
//...
}
public void Foo()
{
string thing = _canNotBeNull.Example().Sample();
//...
}
@TheQuinnGil QuinnGil.com
Slide 58
Slide 58 text
Technical Practices - Never `null`
public class NullObject : ICanNotBeNull
{
public IAlsoNotNull Example() => new NullObjectAlso();
}
public class NullObjectAlso : IAlsoNotNull
{
public string Sample() => "Default";
}
public string CalculateThing(ICanBeNull canBeNull)
{
if (canBeNull == null) return "Default";
IAlsoNull alsoNull = canBeNull.Example();
if (alsoNull == null) return "Default";
string sample = alsoNull.Sample();
if (sample == null) return "Default";
return sample;
}
public void Foo()
{
string thing = _canNotBeNull.Example().Sample();
//...
}
@TheQuinnGil QuinnGil.com
Slide 59
Slide 59 text
Sustainable Code through Technical Practices
Never `null`
@TheQuinnGil QuinnGil.com
● No Getters / No Setters
● `if` Only As Guard Clause
● Isolate Their Code
● Never `null`
● No `new` inline
● Composition, Not Inheritance
●
● Be Immutable
● No Primitives
● Extract Cohesion
● No Public Statics
● Never Reflection
Trust Your Code by always having valid objects
Slide 60
Slide 60 text
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
Slide 61
Slide 61 text
Primitives?
Technical Practices - No Primitives
@TheQuinnGil QuinnGil.com
Slide 62
Slide 62 text
Technical Practices - What are Primitives?
● Data (string, int, double, float, ...)
@TheQuinnGil QuinnGil.com
Slide 63
Slide 63 text
Technical Practices - What are Primitives?
● Data (string, int, double, float, ...)
● Collections (List, Map, Dictionary, ...)
@TheQuinnGil QuinnGil.com
Slide 64
Slide 64 text
Technical Practices - What are Primitives?
● Data (string, int, double, float, ...)
● Collections (List, Map, Dictionary, ...)
● Enums
@TheQuinnGil QuinnGil.com
Slide 65
Slide 65 text
Technical Practices - What are Primitives?
● Data (string, int, double, float, ...)
● Collections (List, Map, Dictionary, ...)
● Enums
● More?
@TheQuinnGil QuinnGil.com
Slide 66
Slide 66 text
Why not Primitives?
Technical Practices - No Primitives
@TheQuinnGil QuinnGil.com
Slide 67
Slide 67 text
● Object oriented programming wants object interaction, not data manipulation
Technical Practices - Why No Primitives?
@TheQuinnGil QuinnGil.com
Slide 68
Slide 68 text
● Object oriented programming wants object interaction, not data manipulation
● Primitives are data, not objects
Technical Practices - Why No Primitives?
@TheQuinnGil QuinnGil.com
Slide 69
Slide 69 text
● 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
Slide 70
Slide 70 text
● 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
Slide 71
Slide 71 text
● 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
Slide 72
Slide 72 text
Instead?
Technical Practices - No Primitives
@TheQuinnGil QuinnGil.com
Slide 73
Slide 73 text
Represent the Concept
Technical Practices - No Primitives
@TheQuinnGil QuinnGil.com
Slide 74
Slide 74 text
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
Slide 75
Slide 75 text
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
Slide 76
Slide 76 text
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
Slide 77
Slide 77 text
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
Slide 78
Slide 78 text
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
Slide 79
Slide 79 text
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
Slide 80
Slide 80 text
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
Slide 81
Slide 81 text
Technical Practices - No Primitives - Age Example
@TheQuinnGil QuinnGil.com
Represent the Concept
Slide 82
Slide 82 text
Technical Practices - No Primitives - Units
public float Convert(float value)
@TheQuinnGil QuinnGil.com
Slide 83
Slide 83 text
Technical Practices - No Primitives - Units
public float Convert(float value)
{
return value * 1.609334f;
}
@TheQuinnGil QuinnGil.com
Slide 84
Slide 84 text
Technical Practices - No Primitives - Units
public float Convert(float value)
{
return value * 1.609334f;
}
Money?
@TheQuinnGil QuinnGil.com
Slide 85
Slide 85 text
Technical Practices - No Primitives - Units
public float Convert(float value)
{
return value * 1.609334f;
}
Money? Distance?
@TheQuinnGil QuinnGil.com
Slide 86
Slide 86 text
Technical Practices - No Primitives - Units
public float Convert(float value)
{
return value * 1.609334f;
}
@TheQuinnGil QuinnGil.com
Money? Distance?
Convert To? From?
Slide 87
Slide 87 text
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?
Slide 88
Slide 88 text
Technical Practices - No Primitives - Units
public class Distance
...
distance.ToKilometer();
...
With Meta Data
@TheQuinnGil QuinnGil.com
Slide 89
Slide 89 text
Technical Practices - No Primitives - Age Example
@TheQuinnGil QuinnGil.com
Represent the Concept
Slide 90
Slide 90 text
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
Slide 91
Slide 91 text
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
Slide 92
Slide 92 text
Feature Parity in
25% of the Dev Hours
@TheQuinnGil QuinnGil.com
Slide 93
Slide 93 text
THANK YOU!
@TheQuinnGil QuinnGil.com
Slide 94
Slide 94 text
Sustainable Code through Technical Practices
● No Getters / No Setters
● `if` Only As Guard Clause
● Isolate Their Code
● Never `null`
● No `new` inline
● Composition, Not Inheritance
●
● Be Immutable
● No Primitives
● Extract Cohesion
● No Public Statics
● Never Reflection
@TheQuinnGil QuinnGil.com