clean code is a classic.
I am not the first to summarize; I won’t be the last! Thank you to my partner for gifting this book to me when I started my career change. 🙏 After I read Clean Code: A Handbook of Agile Software Craftsmanship, it was requested I share insights with my team. Any chance to share knowledge is a win! I share the details included in my presentation here, focusing on the most widely applicable content.
Quick notes:
- ❌ The author uses Java-specific references frequently. I’ve removed these because they aren’t relevant to myself or my team.
- 👀 There’s an immense level of detail. Please feel free to jump around as you see fit!
Here, we’ll cover:
- 🎬 The Presentation
- 💡 My 3 Big Takeaways
- 💻 What is clean code?
- 🏗️ Foundations: names, functions, comments, and formatting
- 🚀 Put it into Practice
- 🥸 Code Smells
- 🤔 Questions to consider
- 🫶 Bonus Recommendation
🎬 the presentation
The conversation that was sparked pleasantly surprised me when I presented to the team in the Western hemisphere. Some insights:
- Although one teammate read this several years ago, it’s still pertinent for them in their current DevOps role!
- Our team is responsible for taking this seriously and taking the time to do this in our daily work.
- We all need to practice this, regardless of our current experience level.
Here is a link to the slides! And here’s a recording of the presentation (~15 minutes):
💡 my 3 big takeaways
- Writing code is a process. Start with a draft, refine, and repeat. It takes practice.
- What ultimately matters is that your team agrees on standards and sticks to them.
- It is everyone’s responsibility to keep a codebase clean!
💻 what is clean code?
For me, clean code is beautiful and embodies discipline. It is concise and clear to any reader. Business needs and team members will inevitably change! So, it’s important to hone the craft to solve a problem with meaningful code for others to understand.
I especially like the application of the referenced “broken windows” metaphor:
“A building with broken windows looks like nobody cares about it. So, other people stop caring. They allow more windows to become broken. Eventually, they actively break them. They despoil the facade with graffiti and allow garbage to collect. One broken window starts the process toward decay.”
Dave Thomas & Andy Hunt
Several other interpretations of “clean code“ were provided by others in the industry. Here are some of the meaningful interpretations I extracted:
- elegant/pleasing
- efficient
- readable
- does one thing well
- easy for others to enhance
- well-tested
- minimal/simple and orderly, well-cared-for
- no duplication
- no surprises - it returns exactly what you expect
Without developer discipline, building new features slows over time. As the mess grows, so does the time needed for the codebase, especially for new team members! They must wade through it to make an impact.
Clean code sometimes requires pushback on timelines (within reason) for higher-quality output. Other team members (i.e., managers or product) rely on our honest estimations. Sure, we could get it working as a bare minimum, but we also need time to care for the code, keeping the product/service smooth and efficient. This should be acknowledged and considered. Why? Because even when we say we’ll return to it, historically, we won’t.
Tidiness takes a team effort to clean up - and maintain - the codebase. Martin recommends the Boy Scout rule when working: “Leave the campground better than you found it.” Care about your craft!

🏗️ foundations: names, functions, comments, and formatting
What does this actually consist of? Let’s cover major areas where pain points arise.
names
What’s in a name anyway? Well, a lot of meaning, actually!
variable naming tips:
USE
- Pronounceable - “Humans are good at words…If you can’t pronounce it, you can’t discuss it without sounding like an idiot.”
- Searchable - For example, static numbers or hard-to-read code like a regex pattern for a valid phone number
^\+[1-9]\d{1,14}$could have a named variable ofvalidE164FormatRegexinstead. - Intention-revealing
- Meaningful context - Instead of a vague
idvariable, we can be more specific with something likeserviceXCustomerIDto make it clear what we’re working with.
AVOID
- Disinformation - If a variable is a number, it should not be named
moneyString! - Abbreviations
- Unnecessarily long names or similar spelling
- Characters that look alike - Common offenders are lowercase
Land uppercaseior number zero and uppercaseo. - Number series naming -
a1anda2mean nothing to the reader in a program. - Avoid programming terms when a variable is not used for that use
- Noise words - These include words like “a” or “the” if it doesn’t add useful meaning.
- Encodings and mental mapping - This adds unnecessary cognitive load to decipher meaning.
class naming tips:
USE
- Verb/verb phrases for methods - Methods take action!
- One word per concept - Try to retain the same lexicon and be consistent.
- Solution domain - Use commonly known terms that programmers will understand.
- Problem domain - When there is no “programmer-ese,” rely on the problem space to describe the class.
- Meaningful context
AVOID
- Noun phrase names
- Too much context
- Cleverness, slang, puns - Too many teams are globally distributed, and these won’t have the same meaning in all countries or even within different teams in the same country!
functions
Functions are the heart of any program. They should have consistent blocks and indentation for an easily followed nested structure.
- Functions should also be small. How small?
“The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that.”
- Functions should only do one thing.
- The output should be exactly what you expect.
- If you can, extract another function.
- Functions should have one level of abstraction.
- The function should only be able to access one abstraction level below itself.
- Functions should be able to be read from top to bottom.
- Well-written code reads like a narrative as if in a set of “to” statements.
- Avoid switch statements when possible.
- Switch statements are hard to keep small, but they are sometimes useful. When using switch statements, Martin recommends burying it as low-level as possible, preferably in a class (creating polymorphic objects), to ensure it is not repeated and hide it from the rest of the code.
- Use descriptive names for functions.
- Verbs or verb phrases are great here. Let’s name functions by the action they perform! Don’t be afraid of long names if it adds clarity.
- Keep function arguments to a minimum.
- Think carefully and use a data structure if you need more than 2 arguments.
- Verbs or keywords can make the intended use of arguments more obvious.
- Functions should have obvious side effects.
- If a side effect is intended, make that clear in the name. Avoid it if possible.
- Functions should either do something or answer something, but not both.
- Prefer exceptions to returning error codes.
- Martin recommends exceptions to handle errors separately.
- Don’t repeat yourself (DRY).
comments
Everyone has their own view on this. Regardless, note point 2 in my main takeaways. If your team agrees on a pattern, adopt the pattern. Ultimately, the best advice I’ve received is that a comment should explain why you made a decision (like business needs) and not what your code is doing.
- Delete dead code.
- We have version control for a reason!
- Good comment examples:
- legal comments
- informative, truly useful comments
- explanation of intent
- amplify section importance
- add clarification
- warning of consequences
- TODO comments (within reason)
- Bad comment examples (most comments):
- mumbling, personal journal/log comments
- redundant comments
- misleading comments (not precise enough to be accurate)
- mandated comments or noisy comments
- don’t use a comment when you can use a function or a variable!
- position markers
- closing brace comments
- attributions and bylines
- commented out code
- HTML comments
- nonlocal info
- too much info
- not obvious connections
- function headers
formatting
Why is this a foundation? It’s too important to ignore, and so many linting tools exist. There’s no excuse. Because there are many tools, I won’t go into excessive detail!
- Vertical formatting (200-500 lines per file recommended)
- smaller files reduce scrolling
- space between concepts keeps them readable
- order concepts from high to low priority
- Horizontal formatting (20-60 characters per line, 45 on average recommended)
- keep lines short
- horizontal spacing can add clarity and understanding
- indentation shows the hierarchy
- avoid silent/floating semi-colons!
Again, it doesn’t matter what you do for formatting as long as everyone agrees and follows it on the team!
We’ve covered the foundational concepts! But, as Martin says, just because we might be able to recognize “dirty” code or “code smells,” we must also put it into practice!
“So too being able to recognize clean code from dirty code does not mean that we know how to write clean code!”
Chapter 1, “The Art of Clean Code?”
🚀 put it into practice
To put some of the following chapters into practice, I’ve pulled some of the more interesting or applicable concepts and suggestions!
- Abstract and hide your data:
- Reduce data manipulation and exposure where it doesn’t belong.
- Data structures expose data and don’t have meaningful functions.
- Objects hide data behind abstractions and expose functions to operate on the data.
- Error handling:
- Martin recommends exceptions over errors to keep the calling code cleaner and extract error-handling logic.
- Provide context with your exceptions for more informative error messages.
- Wrap third-party APIs to best handle errors from the source.
- Avoid passing or returning null. Sometimes, an API may return null, and you cannot avoid it.
- Boundaries for Third-Party Tools:
- Wrap an implementation around third-party code to control what is used and reduce affected code when a change you can’t control occurs.
- Read the docs, test and explore a tool, and build “learning tests” (super powerful to identify API changes early) to get to know the API well!
- Define the interface you want when you face the unknown. This guides design decisions. It’s better to depend on the code you can control!
- Unit Tests:
- Tests are just as important to keep clean! Write small, readable tests.
- Tests reduce fear of maintenance, refactors, or improvements.
- Test code doesn’t need to be as efficient as production code.
- Focus on one concept per test. Ideally, use only one assertion per test - or minimal - for easier debugging.
- Clean tests have 5 FIRST rules:
- FAST - should run quickly, so you run them often/fix them ASAP
- INDEPENDENT - should not depend on each other, diagnosis is difficult
- REPEATABLE - able to happen in any environment, reduce failure excuses
- SELF-VALIDATING - boolean output, pass or fail
- TIMELY - write in a timely fashion just before the production code
- The three laws of TDD (Test-Driven Development) from the book:
- You may not write production code until you have written a failing unit test.
- You may not write more of a unit test than is sufficient to fail, and not compiling is failing.
- You may not write more production code than is sufficient to pass the currently failing test.
- Classes:
- Classes should be small! “The first rule of
functionsclasses is that they should be small. The second rule offunctionsclasses is that they should be smaller than that.” - Avoid a “god class” that tries to do all things.
- Follow the Single Responsibility Principle.
- Organize classes in the common standard: list variables, private instance variables, then easily read from top to bottom with important items at the top.
- Organize classes to reduce change in the case of adding functionality later and isolate the class as much as possible from external change.
- Classes should be small! “The first rule of
- Systems:
- For systems, consider an example from the book:
- A hotel is built by construction and engineering teams.
- A hotel is used by regular people on a vacation or business trip.
- These functions are entirely independent and build/use should be the same in systems, too! E.g. Separate tests from the compilation.
- Separate the construction of a system from the usage implementation.
- Dependencies of “main” should direct away from “main.”
- The Single Responsibility Principle or Inversion of Control moves responsibilities from an object to others dedicated to the purpose.
- Meaning an object doesn’t instantiate dependencies itself.
- Implement only what’s needed today; refactor and scale over time (incremental agility).
- Evolve from simple to sophisticated over time and with more resources!
- Optimize decision-making with modularity and separation of concerns; no one person can make decisions.
- “We often forget that it is also best to postpone decisions until the last possible moment.”
- Waiting allows for informed decisions.
- Domain-specific language helps code read like structured prose a domain expert might write. This reduces incorrect translations!
- For systems, consider an example from the book:
- Final thoughts and reminders:
- Run all the tests! They should be easy.
- Refactor! It should be incremental (write, pause, reflect, write).
- Write dirty code, then clean it up. 🧹
- Eliminate duplication and ensure clear expressiveness for others to read.
- Choose good names, keep functions and classes small (but not too small), and use standard nomenclature and programming patterns.
- Practice makes perfect!
“Of course bad code can be cleaned up. But it’s very expensive. As code rots, the modules insinuate themselves into each other, creating lots of hidden and tangled dependencies.”
🥸 code smells
Below is a table of common issues provided by Martin (excluding Java-related items).
You may need to scroll to see all the goodies!
| Comments | Environment | Functions | Names | Tests | General 1 | General 2 | General 3 |
|---|---|---|---|---|---|---|---|
| inappropriate information | build requires more than one step | too many arguments | choose descriptive names | insufficient tests | multiple languages in one source file | artificial coupling | be precise |
| obsolete comment | tests require more than one step | output arguments | choose names at the appropriate level of abstraction | use a coverage tool! | obvious behavior is unimplemented | feature envy | replace magic numbers with named constants |
| redundant comment | flag arguments | use standard nomenclature where possible | don’t skip trivial tests | incorrect behavior at the boundaries | selector arguments (bool) | structure over convention | |
| poorly written comment | dead function | unambiguous names | an ignored test is a question about ambiguity | overridden safeties | obscured intent | encapsulate conditionals | |
| commented-out code | use long names for long scopes | test boundary conditions | duplication | misplaced responsibility | avoid negative conditionals | ||
| avoid encodings | exhaustively test near bugs | code at wrong level of abstraction | inappropriate static (referring to a method, prefer non-static methods) | functions should do one thing | |||
| names should describe side-effects | patterns of failure are revealing | base classes depending on their derivatives | use explanatory variables | hidden temporal couplings (don’t hide it when it’s necessary) | |||
| test coverage patterns can be revealing | too much information - hide info, keep it tight and small | function names should say what they do | don’t be arbitrary | ||||
| tests should be fast | dead code | understand the algorithm | encapsulate boundary conditions | ||||
| vertical separation | make logical dependencies physical | functions should descend only one level of abstraction | |||||
| inconsistency | prefer polymorphism to if/else or switch/case | keep configurable data at high levels | |||||
| clutter | follow standard conventions | avoid transitive navigation |
That’s a wrap!
🤔 questions to consider:
- Have you read Clean Code? Did you have any different insights or any I missed?
- What was your favorite or least favorite part?
- Do you agree/disagree with anything “Uncle” Bob Martin shared that I have listed?
- Have you - or are you - putting anything into practice in your daily work?
- Is this most relevant to new engineers, or is it also useful for seniors or managers?
🫶 bonus recommendation
I recently began listening to the Working Code Podcast (from the 2020 start…it’s how I listen to all podcasts). The hosts reviewed Clean Code in episodes #22 and #23.
Thus far, I highly recommend the podcast! The real banter is great for anyone who works remotely to feel like they can enjoy technical conversations anytime!
// comments
Loading comments…
leave a comment