The Clean Coder

It’s a bit interesting that I chose to read the three books Clean Code, The Clean Coder, and Clean Architecture by Uncle Bob in reverse order, for no particular reasons. I’ve finished Clean Architecture back in January but didn’t write a reading notes post for it. I felt that the content was too much to fit in one reading notes post, and also that I haven’t been able to understood some of the content to the extent that I could summarize into bullet points. The Clean Coder is different. It’s short enough, and the messages delivered in the book are crystal clear and quite actionable. This post summarizes what I think are the most important points.

Chapter 1: Professionalism

  • This concept has been repeatedly emphasized across all the book. Software engineers are professionals.
  • Professionals take responsibility for what they produce.
  • Professionals do no harm.
  • Professionals work ethically.

Chapter 2: Saying No

  • Professionals know when/how to say no to things that are impossible.
  • Professionals do not “try”. “Trying” to deliver something is understood by managers as a commitment. It is a silent commitment to sacrifice life and work extra hours. Professionals either work their ass off to “try to deliver” their commitment, or, when they “try” and fail, they are still held responsible for not being able to deliver, and have an even more miserable life.
  • When being pushed to enter a compromise to deliver within impossible timeline, effectively communicate and give good reasoning and estimates, and do not step back.

Chapter 3: Saying Yes

  • It is a commitment. A commitment has three parts: “You say you’ll do it. You mean it. You actually do it.” Lack of any of these three ingredients is not a commitment.
  • Professionals “should work hard to find creative ways to make yes possible,” but “are not required to say yes to everything asked of them.”

Chapter 4: Coding

  • Don’t code at 3am.
  • Don’t “worry code.” Instead, enter a mental state when you’re not distracted by background worries, be it work-related or else.
  • Enter the “flow zone” by methods that suite you (e.g., music, being alone and quite, or whatever). Learn to deal with interruptions.
  • Debugging is coding. It should be thought as so and be performed in the same scenarios as if you are coding. Don’t debug only because you are putting out fire. Good coding techniques (such as TDD) are good for debugging too.
  • Pacing yourself by knowing when to disengage in coding. By disengaging you are actually freeing your mind for more creative thoughts and good things could surprisingly happen (e.g., when you are driving or showering).
  • Dealing with being late. Don’t “hope” it will be done sooner. Don’t rush to deadlines. Don’t work overtime. Define “done” and don’t commit to false delivery.
  • Know when/how to get help, and help others.

Chapter 5: Test Driven Development

  • Three laws of the ideal TDD cycle: (1) Do not write production code before writing the first (failing) test. (2) Do not write more unit tests than sufficient to fail (including not compiling). (3) Do not write more production code than sufficient to pass current failing test.
  • Benefits of this approach: certainty on code written; low defect injection rate; courage to write more test (as opposed to when you see a whole messy code base and fear to touch it because there is no test); tests are documentation; writing tests helps design too: you know when to separate coupling dependency (so that you can mock them in the tests).
  • TDD is not a religion or magic formula. Benefits are not guaranteed if you write bad tests. When in rare cases TDD is not the best choice, professionals are not dogmatic to follow it blindly.

Chapter 6: Practicing

  • Professionals practice. Practice and performance are different. Professionals do not practice when they are expected to perform.
  • Practices can take many forms, including contributing to open-source projects.

Chapter 7: Acceptance Tests

  • Acceptance tests are “written by a collaboration of the stakeholders and the programmers in order to define when a requirement is done.” It serves as a collaboration tool, with the purpose of “communication, clarity, and precision.”
  • Acceptance tests should be automated.
  • Acceptance tests should be written by all stakeholders, and should be written to disambiguate and improve precision. But be ware of “early precision” or “late ambiguity.”
  • Acceptance tests for GUI are hard and should be dealt with cleanly. Separate the concerns. For instance, separate the tests that a button’s underlying logic is executed properly, and that a button’s appearance satisfies ever-changing aesthetic taste by customers.

Chapter 8: Testing Strategies

  • “Test Automation Pyramid”: unit tests, component tests, integration tests, system tests, and manual exploratory tests, should respectively target coverage goals of ~100%, ~50%, ~20%, ~10%, and ~5%.
  • Unit tests should be specifications at the lowest language level.
  • Component tests are acceptance tests for individual components. It should be tested that components give expected outcomes when given corresponding input, without going inside the components.
  • Integration tests focus on the interactions between components. They “make sure that the components are properly connected and can clearly communicate with each other.”
  • System tests are ultimate integration tests for the whole system. They don’t care about business rules, but about system is properly wired up, and its components interact as designed.
  • Manual exploratory tests involves human playing with the system, as opposed to above test types which are all expected to be automation. “The goal is not coverage … rather, the goal is to ensure that the system behaves well under human operation and to creatively find as many peculiarities as possible.”

Chapter 9: Time Management

  • Meetings are necessary while meetings are time-wasters. Meetings should all have an agenda and a goal.
  • You don’t have to accept every meeting, especially ones that (1) interest you but not immediately necessary (carefully select which ones to attend because there are way too many of them), (2) are about something you can contribute but not immediately significant (discuss your participation with team/manager), or (3) requested by someone in authorities (ask team/manager).
  • “A good manager will be more than willing to defend your decision to decline attendance because that manager is just as concerned about your time as you are.”
  • Don’t be shy about leaving a dysfunctional meeting early. Don’t be rude and storm out either.
  • Stand-up meetings should be really succinct.
  • Iteration planning/retrospective/demo meetings should be short too.
  • Kent Beck: “Any argument that can’t be settled in five minutes can’t be settled by arguing.” Go to get some data. Don’t “agree and not engage.” In the worst case, flip a coin to decide what to do, but determine upfront when to retrospectively look back and evaluate correctness of decision.
  • Focus-Manna. Get enough sleep, have caffeine/tee wisely, find ways to recharge, exercise, and balance input/output of you (writing software is creative process; you have to keep in-taking creativity in order to keep being creative).
  • Pomodoros. Why not?
  • Avoid “priority inversion” (i.e., doing things of low importance/value and feel fulfilled and content, and not delivering real work). This is unprofessional.
  • When hitting blind alleys, know to turn around.

Chapter 10: Estimation

  • “An estimate is not a number. An estimate is a distribution.”
  • PERT (Program Evaluation and Review Technique) is a trivariate analysis on O–optimistic estimate, N–nominal estimate, and P–pessimistic estimate. PERT gives a formula that approximates a \(\beta\)-distribution, where the expected duration of the task is \(\mu = \frac{O + 4N + P}{6}\), and the standard derivation of the probability distribution of the task is \(\sigma = \frac{P - O}{6}\).
  • When it comes to a sequence of tasks, PERT states the expected duration is simply the sum of those of individual tasks, i.e., \(\mu = \sum\mu_t\), and with a standard derivation that is the square root of the sum of squares of those of individual tasks, i.e., \(\sigma=\sqrt{\sum \sigma_t^2}\).
  • Other estimation methods include letting the team use fingers or poker cards to indicate the days needed. Or, arrange a set of tasks according to their relative difficulty, and assign predefined sequence points to them (affinity estimation).

Chapter 11: Pressure

  • Avoid pressure by not committing to impossible things, and by staying clean. A good way to testing your discipline is to consider would you stick to the disciplines when you are in a crisis? If yes, then you truly believe them.
  • Handle pressure by keeping calm, good communication, staying to disciplines, and getting help.

Chapter 12: Collaboration

  • Professional programmers take time to understand the business, and do not blindly drown in the sea of technology.
  • Professional programmers pair with peers to deliver best results, share collective ownership of the code with team, and do not protectively guard against others from touching his code.

Chapter 13: Teams and Projects

  • Build a “gelled” team, and let the team work on projects.
  • Do not just assemble teams around projects and disassemble them afterwards.

Chapter 14: Mentoring, Apprenticeship, and Craftsmanship

  • The ideal way to help a true professional grow should be similar to training professionals in other domains, e.g., doctors. Mentoring and apprenticeship should play a central role, and the ultimate goal is to pass the craftsman spirit on to the new professional.