Slide 1

Slide 1 text

Feature Parity in 25% of the Dev Hours with Technical Practices for Sustainable Code @TheQuinnGil QuinnGil.com

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

@TheQuinnGil QuinnGil.com Technical Practices for Sustainable Code

Slide 4

Slide 4 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

Slide 5

Slide 5 text

This is for you. @TheQuinnGil QuinnGil.com

Slide 6

Slide 6 text

Sustainable Code through Technical Practices @TheQuinnGil QuinnGil.com

Slide 7

Slide 7 text

Sustainable Code through Technical Practices @TheQuinnGil QuinnGil.com

Slide 8

Slide 8 text

Sustainable Code through Technical Practices @TheQuinnGil QuinnGil.com

Slide 9

Slide 9 text

Tests @TheQuinnGil QuinnGil.com

Slide 10

Slide 10 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 11

Slide 11 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 No Getters / No Setters @TheQuinnGil QuinnGil.com

Slide 12

Slide 12 text

Technical Practices - No Getters - Defined class FizzBuzzBag { public int Input { get; set; } public string Result { get; set; } } class FizzBuzzBag: def __init__(self): self._result = None self._input = None @property def result(self): return self._result @result.setter def result(self, value): self._result = value @property def input(self): return self._input @input.setter def input(self, value): self._input = value class FizzBuzzBag{ private int input; private String result; public String getResult(){ return result; } public void setResult(String value){ result = value; } public int getInput(){ return input; } public void setInput(int value){ input = value; } } class FizzBuzzBag attr_accessor :input attr_accessor :result end @TheQuinnGil QuinnGil.com

Slide 13

Slide 13 text

Technical Practices - No Getters No Getters? No Way! @TheQuinnGil QuinnGil.com

Slide 14

Slide 14 text

No Getters Technical Practices @TheQuinnGil QuinnGil.com

Slide 15

Slide 15 text

Technical Practices - No Getters Why No Getters? @TheQuinnGil QuinnGil.com

Slide 16

Slide 16 text

Technical Practices - No Getters How? @TheQuinnGil QuinnGil.com

Slide 17

Slide 17 text

Technical Practices - No Getters - How? The Class Does It @TheQuinnGil QuinnGil.com

Slide 18

Slide 18 text

Technical Practices - No Getters public class FizzBuzz{ public int Input { get; set; } public string Result { get; set; } } public static class FizzBuzzUtils{ public static void Calculate(FizzBuzz fb){ if (fb.Input % 3 == 0){ fb.Result = "Fizz"; } if (fb.Input % 5 == 0){ if (fb.Result == null){ fb.Result = "Buzz"; } else { fb.Result += "Buzz"; } } if (string.IsNullOrEmpty(fb.Result)){ fb.Result = fb.Input.ToString(); } } } @TheQuinnGil QuinnGil.com

Slide 19

Slide 19 text

Technical Practices - No Getters / No Setters public class FizzBuzz{ private readonly int _input; public FizzBuzz(int input) => _input = input; public string Result(){ string result = null; if (_input % 3 == 0) result = "Fizz"; if (_input % 5 == 0){ if (result == null) result = "Buzz"; else result += "Buzz"; } if (string.IsNullOrEmpty(result)){ result = _input.ToString(); } return result; } } public class FizzBuzz{ public int Input { get; set; } public string Result { get; set; } } public static class FizzBuzzUtils{ public static void Calculate(FizzBuzz fb){ if (fb.Input % 3 == 0){ fb.Result = "Fizz"; } if (fb.Input % 5 == 0){ if (fb.Result == null){ fb.Result = "Buzz"; } else { fb.Result += "Buzz"; } } if (string.IsNullOrEmpty(fb.Result)){ fb.Result = fb.Input.ToString(); } } } @TheQuinnGil QuinnGil.com

Slide 20

Slide 20 text

Technical Practices - No Getters / No Setters Benefits @TheQuinnGil QuinnGil.com

Slide 21

Slide 21 text

Sustainable Code through Technical Practices No Getters / No Setters @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 Sustainable Code from Encapsulating Behavior

Slide 22

Slide 22 text

Sustainable Code through Technical Practices `if` Only As Guard Clause @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 23

Slide 23 text

Technical Practices - `if` Only As Guard Clause Guard Clause Only? No Way!

Slide 24

Slide 24 text

Technical Practices - `if` Only As Guard Clause Default Path @TheQuinnGil QuinnGil.com

Slide 25

Slide 25 text

`if` Only As Guard Clause - Default Path public class FizzBuzz{ private readonly int _input; public FizzBuzz(int input) => _input = input; public string Result(){ string result = null; if (_input % 3 == 0) result = "Fizz"; if (_input % 5 == 0){ if (result == null) result = "Buzz"; else result += "Buzz"; } if (string.IsNullOrEmpty(result)){ result = _input.ToString(); } return result; } } @TheQuinnGil QuinnGil.com

Slide 26

Slide 26 text

public class FizzBuzz{ private readonly int _input; public FizzBuzz(int input) => _input = input; public string Result(){ string result = null; if (_input % 3 == 0) result = "Fizz"; if (_input % 5 == 0){ if (result == null) result = "Buzz"; else result += "Buzz"; } if (string.IsNullOrEmpty(result)){ result = _input.ToString(); } return result; } } `if` Only As Guard Clause - Default Path public class FizzBuzz{ private int _input; public FizzBuzz(int input) => _input = input; public string Result(){ if (_input % 15 == 0) return "FizzBuzz"; if (_input % 3 == 0) return "Fizz"; if (_input % 5 == 0) return "Buzz"; return _input.ToString(); } } @TheQuinnGil QuinnGil.com

Slide 27

Slide 27 text

Technical Practices - `if` Only As Guard Clause Cascading Changes @TheQuinnGil QuinnGil.com

Slide 28

Slide 28 text

Technical Practices - `if` Only As Guard Clause Cascading Changes switch and else - always evil @TheQuinnGil QuinnGil.com

Slide 29

Slide 29 text

Technical Practices - `if` Only As Guard Clause How? @TheQuinnGil QuinnGil.com

Slide 30

Slide 30 text

`if` Only As Guard Clause - Default Path public class FizzBuzz{ private int _input; public FizzBuzz(int input) => _input = input; public string Result(){ if (_input % 15 == 0) return "FizzBuzz"; if (_input % 3 == 0) return "Fizz"; if (_input % 5 == 0) return "Buzz"; return _input.ToString(); } } public class FizzBuzz{ private readonly int _input; public FizzBuzz(int input) => _input = input; public string Result(){ string result = null; if (_input % 3 == 0) result = "Fizz"; if (_input % 5 == 0){ if (result == null) result = "Buzz"; else result += "Buzz"; } if (string.IsNullOrEmpty(result)){ result = _input.ToString(); } return result; } } @TheQuinnGil QuinnGil.com

Slide 31

Slide 31 text

Sustainable Code through Technical Practices `if` Only As Guard Clause @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 Sustainable Code from Limited Branching; Smaller Methods; Encapsulated Behavior Decisions

Slide 32

Slide 32 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 33

Slide 33 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 34

Slide 34 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 35

Slide 35 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

Slide 36

Slide 36 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(); //EXCEPTION, COUPLING JObject jsonContent = JObject.Parse(readAsStringAsync); string value = jsonContent.Value("some_key"); return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com

Slide 37

Slide 37 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(); //EXCEPTION, COUPLING JObject jsonContent = JObject.Parse(readAsStringAsync); //IMPERATIVE string value = jsonContent.Value("some_key"); return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com

Slide 38

Slide 38 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(); //EXCEPTION, COUPLING JObject jsonContent = JObject.Parse(readAsStringAsync); //IMPERATIVE string value = jsonContent.Value("some_key"); //EXCEPTION return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com

Slide 39

Slide 39 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 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 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"; } public async Task NetworkCall(HttpRequestMessage r) { IHttpResponseMessageBookEnd httpResponseMessage = await _httpClient.SendAsync(r); IParsedObject parsedObject = await httpResponseMessage.ParsedContent(_parser); string value = parsedObject.StringValue("some_key"); return value.Contains("expected_Value") ? "Success" : "Failure"; } @TheQuinnGil QuinnGil.com

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

Technical Practices - Isolate Their Code - How? HttpClient httpClient = new HttpClient(); @TheQuinnGil QuinnGil.com IHttpClientBookEnd httpClient = new HttpClientFacade();

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 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 Sustainable Code from Full Testability; Narrow Scope of Change; Reduced Complexity

Slide 57

Slide 57 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 58

Slide 58 text

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

Slide 59

Slide 59 text

THANK YOU! @TheQuinnGil QuinnGil.com

Slide 60

Slide 60 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