Letting aside specific technologies or elaborated development methodologies — to guide you on your path through the software development jungle, a least common
denominator of generally accepted principles and best practices is established.
As a help for understanding and practising, the Clean Code Developer Initiative grouped
these into five levels or degrees (in allusion to martial arts training). We prefer
here to use the term Path while still retaining the distinctive colour codes used
by the original CCDI page.
Each of these paths focusses on a certain aspect of development — and does so by
combining a set of well known principles and guidelines with some suitable practices.
Each path builds upon the preceding path, but you can take on only one path a time.
And you really need to take on such a path personally — try to understand the
principles actively, keep them up in your everyday work and try to adhere to the practices.
It is recommended to stay on a single path for an extended period of time (at least
3 weeks)
No path is inherently “better” than the preceding path — usually, when finished
with blue, you start again with red.
Red Path — understanding
Principles
-
DRY — Don’t Repeat Yourself
-
don’t bore your readers by stating the same again and again — build
viable abstractions instead. Avoid duplicated functionality, remove
unnecessary data redundancy, automate repetitive tasks.
-
KISS — Keep it simple, stupid
-
“Everything should be made as simple as possible, but not simpler” (Einstein).
Write code foremost to be understandable. Resist using an interesting
solution, when there also is a straight forward (albeit boring) standard solution.
-
Avoid Preliminary Optimisation
-
distrust your own cleverness. “More computing sins are committed in the name
of efficiency than for any other single reason – including blind stupidity” (W.A.Wulf).
Defer improvements “for later”. Require an objective proof for performance problems,
based on real-world data.
-
FCoI — Favour Composition over Inheritance
-
build up functionality from self-contained abstractions, instead of cleverly extending,
bending or specialising. Avoid proliferation of special cases.
Practices
-
Boy Scout Rule
-
whenever you enter some area, leave it in somewhat better shape than you found it
-
Root Cause Analysis
-
never do “programming by coincidence”. Try to understand why something works
or breaks. Never act based on assumptions. Don’t treat symptoms. Better don’t act
unless you understand.
-
Use Version Management
-
use a revision control system. Create thematically consistent change sets, write
clear commit messages, learn to handle branching and merging.
-
Simple Refactorings
-
apply the fundamental refactorings “_extract method_” and “_rename_” liberally.
-
Reflection
-
review your own achievements based on the principles (especially but not limited to
those you’re focussing on currently). Partition your work into tasks which can be
finished on one day. Take the time to reflect.
Orange Path — sharpening
Principles
-
SLA — Single Level of Abstraction
-
each piece of code should talk on a distinctive level of granularity.
Don’t mix implementation details with invocation of high-level abstractions.
Refactor code to balance the level of abstraction.
-
SRP — Single Responsibility Principle
-
every class or entity should deal with one topic solely, and do that well.
What needs to be said for a given concern, should be found at a single location.
-
SoC — Separation of Concerns
-
decompose functionality into orthogonal concerns. Increase focussing and cohesion
within a single concern, and decrease coupling amongst separate concerns.
-
Source Code Conventions
-
establish writing conventions based on readability. Code is more often read than written.
Reason about the purpose of conventions, then stick to them. Especially focus on
naming conventions and correct source code comments. Comments should not detail what
you do, but the purpose why you do it.
Practices
-
Issue Tracking
-
capture problems and work items as well delineated issues. Track them in a structured way,
establish ubiquitous procedures for assigning and resolving issues.
-
Automate Tests
-
verify correct integration of the parts by running tests automatically.
Build a safety net allowing to perform refactorings while retaining correct operation.
-
Eager Reading
-
acquire an attitude of concern for the ongoing evolution of the coding craft.
Read books, journals and blogs. Learn a new programming language every year.
-
Code Reviews
-
four eyes are better then two. Present and explain your code to other programmers.
Establish practices like code reviews and pair programming.
Yellow Path — segregating
Principles
-
ISP — Interface Segregation Principle
-
keep interfaces focussed and confined to a set of operations likely to be used in conjunction.
Avoid to tie clients to the details of a service implementation
-
Dependency Inversion
-
revert dependencies with respect to the naive logical meaning. Instead of implementing high-level
functions through low-level functions, turn the latter into services and thus make both depend
on interfaces.
-
Liskov Substitution Principle
-
the special case must be able to stand-in for the general concept in all respects. A subclass
instance is required to take on all responsibilities outlined by the Interface. The special case
must not extend and bend the meaning beyond what was outlined in the abstraction. An ellipse can’t
be kind-of a circle.
-
Rule of Least Surprise
-
every piece of code should behave exactly in the way obvious from the names, the concepts and the
general context. The reader should be able to get the essence of what’s going on already from the
first coarse-grained view.
-
Information Hiding
-
every part — be it function, object, interface or subsystem — should expose only the bare minimum
required to use it effectively.
Practices
-
Automated Unit Tests
-
cover individual components with tests in isolation.
Break the reasoning in terms of contracts down to the implementation level
-
Mockups
-
build mock-ups, dummies, stubs and fakes to create a controlled environment for reasoning and test.
-
Code Coverage
-
base your reasoning and testing on coverage analysis (instructions, branches, decisions).
-
Advanced Refactorings
-
apply the more advanced types of refactoring techniques to rearrange and restructure code fluently.
Ensure correctness through your stock of unit tests.
-
Community Participation
-
participate actively, beyond the local team. Report bugs, provide testcases, work with library developers,
visit local user groups, participate in conferences.
Green Path — decoupling
Principles
-
OCP — Open Closed Principle
-
any class or functional unit should be open towards extensions, but closed against modifications.
Extending it should not require changing the internals, nor tie the extension to these internals.
Increase cohesion, decrease coupling.
-
Tell, don’t ask
-
invoke services instead of doing things yourselves. Don’t inspect state and operate from the outside.
Respect Subsidiarity.
-
Law of Demeter
-
don’t write “train wreck code”. Talk to direct collaborators only. Within each scope, confine yourself
to using the parameters, local methods, locally created objects, associated partners and global services.
Practices
-
Continuous Integration
-
integrate changes timely and frequently. Perform this integration process automatically, in a controlled
and reproducible environment, perform the unit and integration test suites as part of this process.
-
Inversion of Control Container
-
use Dependency Injection to implement IoC. Use service locators, employ the DI patterns or use an existing
DI container implementation or framework.
-
Code Metrices
-
use static analysis and similar quantitative measurements to monitor various aspects of a source base
-
Quality Measurments
-
observe instead of assuming. Monitor the code quality, measure performance, observe defect rates.
Estimate efforts and verify your guesses after the fact. Identify impediments.
-
Learn by Teaching
-
share your experience and knowledge. Explaining something is the best way to understand it yourself.
Blue Path — balancing
Principles
-
Segregate Design and Implementation
-
clearly delineate planning and doing. Design must not duplicate implementation work, and implementation
concerns must not interfere with architectural considerations. Otherwise implementation will supersede
the design and the real system will end in chaos.
-
Implementation reflects Design
-
code in accordance with design. Traces of architecture should be visible down into individual implementation
structures, names, organisation of the code base and the runtime structure. Never play tricks to
undermine and thwart the design and create a second reality.
-
YAGNI — You Ain’t Gonna Need It
-
decide later and don’t do it, if in doubt. Question your own brilliant ideas — write them down, but defer
implementation for later, because, well, you ain’t gonna need that crap. Don’t say “I can do that on a single
afternoon” — be prudent: doing it seriously will be a major undertaking.
Refrain from spending effort without a reason.
Practices
-
Continuous Delivery
-
extend the automated continuous integration into deployment and setup.
Plan and test the steps towards an release, and finally automate them.
Create a platform to roll out development snapshots, integration builds,
release candidates and service updates.
-
Iterative Development
-
development is a learning process. Instead of achieving perfection through a single big bang,
proceed in incremental steps and include feedback from the user or customer. Use each iteration
for a retrospective and adjust your procedures.
-
Components and Contracts
-
employ the thinking in terms of components and contracts from the largest to the smallest.
Each component establishes some kind of isolation, which helps to cut down complexity.
-
Test first
-
start from the usage situation. Each unit, class, component or subsystem has clients.
Instead of detached planning, or worse, guessing what might be cool, work out the requirements
and contract from an exemplary use in code. Transform this into a test before you even think
about how to make it work.