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

Technical Practices for Sustainable Code 2019-09-14

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

    View full-size slide

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

    View full-size slide

  3. @TheQuinnGil QuinnGil.com
    Technical Practices for
    Sustainable Code

    View full-size slide

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

    View full-size slide

  5. This is for you.
    @TheQuinnGil QuinnGil.com

    View full-size slide

  6. Sustainable Code
    through
    Technical Practices
    @TheQuinnGil QuinnGil.com

    View full-size slide

  7. Sustainable Code
    through
    Technical Practices
    @TheQuinnGil QuinnGil.com

    View full-size slide

  8. Sustainable Code
    through
    Technical Practices
    @TheQuinnGil QuinnGil.com

    View full-size slide

  9. Tests
    @TheQuinnGil QuinnGil.com

    View full-size slide

  10. 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

    View full-size slide

  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

    ● Be Immutable
    ● No Primitives
    ● Extract Cohesion
    ● No Public Statics
    ● Never Reflection
    No Getters / No Setters
    @TheQuinnGil QuinnGil.com

    View full-size slide

  12. 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

    View full-size slide

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

    View full-size slide

  14. No Getters
    Technical Practices
    @TheQuinnGil QuinnGil.com

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  18. 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

    View full-size slide

  19. 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

    View full-size slide

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

    View full-size slide

  21. 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

    View full-size slide

  22. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  25. `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

    View full-size slide

  26. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  30. `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

    View full-size slide

  31. 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

    View full-size slide

  32. 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

    View full-size slide

  33. 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

    View full-size slide

  34. 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

    View full-size slide

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

    View full-size slide

  36. 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

    View full-size slide

  37. 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

    View full-size slide

  38. 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

    View full-size slide

  39. 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

    View full-size slide

  40. 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

    View full-size slide

  41. 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

    View full-size slide

  42. 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

    View full-size slide

  43. 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

    View full-size slide

  44. 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

    View full-size slide

  45. 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

    View full-size slide

  46. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  51. 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

    View full-size slide

  52. 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

    View full-size slide

  53. 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

    View full-size slide

  54. 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

    View full-size slide

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

    View full-size slide

  56. 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

    View full-size slide

  57. 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

    View full-size slide

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

    View full-size slide

  59. THANK YOU!
    @TheQuinnGil QuinnGil.com

    View full-size slide

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

    View full-size slide