Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Technical Practices for Sustainable Code 2019-0...

Quinn
September 14, 2019

Technical Practices for Sustainable Code 2019-09-14

Highly maintainable code is hard to produce.
Object oriented code was supposed to enable us to write clean, understandable code - and yet... we're often stuck with incomprehensible code we can't get tests around. Most of this isn't good object oriented code.
Good object oriented code is maintainable.
Writing good object oriented code is hard.
Without maintainability we can not have sustainable code, it will rot and have to be re-written. As an industry we're often given principles (DRY, SOLID, Abstraction, Code Reuse...) which sound great to have in out object oriented code. Knowing the principles is clearly not enough to enable us to write good object oriented code. We need some hands on keyboard deliberate practices that help us get there.
I just happen to write my code using some technical practices that drive good object-oriented code.
This talk goes into a few of technical practices I've found to have the biggest impact towards good object oriented code. Strictly applying just these practices will help the maintainability of the code.
These technical practices produce simple, understandable, testable code which results in extremely maintainable code that we can work in to consistently and quickly deliver value to our customers.

Quinn

September 14, 2019
Tweet

More Decks by Quinn

Other Decks in Programming

Transcript

  1. Feature Parity in 25% of the Dev Hours with Technical

    Practices for Sustainable Code @TheQuinnGil QuinnGil.com
  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. 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
  4. 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 No Getters / No Setters @TheQuinnGil QuinnGil.com
  5. 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
  6. 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
  7. 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
  8. 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 • <Strong opinions loosely held> • Be Immutable • No Primitives • Extract Cohesion • No Public Statics • Never Reflection Sustainable Code from Encapsulating Behavior
  9. 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 • <Strong opinions loosely held> • Be Immutable • No Primitives • Extract Cohesion • No Public Statics • Never Reflection
  10. `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
  11. 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
  12. Technical Practices - `if` Only As Guard Clause Cascading Changes

    switch and else - always evil @TheQuinnGil QuinnGil.com
  13. `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
  14. 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 • <Strong opinions loosely held> • Be Immutable • No Primitives • Extract Cohesion • No Public Statics • Never Reflection Sustainable Code from Limited Branching; Smaller Methods; Encapsulated Behavior Decisions
  15. 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
  16. 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
  17. 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
  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(); JObject jsonContent = JObject.Parse(readAsStringAsync); string value = jsonContent.Value<string>("some_key"); 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) { //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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. Technical Practices - Isolate Their Code - How? HttpClient httpClient

    = new HttpClient(); @TheQuinnGil QuinnGil.com IHttpClientBookEnd httpClient = new HttpClientFacade();
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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 Sustainable Code from Full Testability; Narrow Scope of Change; Reduced Complexity
  36. 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
  37. 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