How to Write Clean Code
Even bad code can function. But if code isn't clean, it can bring a development organization to its knees. Every year, countless hours and significant resources are lost because of poorly written code.
Within this article we will take the key concepts, and points around writing Clean Code - referenced from the amazing book, The Clean Coder: A Code of Conduct for Professional Programmers by Robert Cecil Martin (aka Uncle Bob).
How should we name our objects, functions, variables and methods?
- Names should be well thought out.
- They should communicate your intent. If you require a comment to describe your name, you have chosen a bad name.
- Use pronounceable names. People will need to talk about your code, make it easy for them.
- Code should read like well written English, writing a line code so it reads like a sentence. The names you choose should lend itself to this, i.e
- Classes are named with a Noun. i.e.
Variables are named with a Noun. i.e
user_account_id = 124816
Method/Functions are named with a Verb. i.e.
Predicates should return a Boolean. i.e
if x == 2:
- Classes are named with a Noun. i.e.
- Ensure you stick to the rule of naming inside of the realms of your scope.
- variables names should be named extremely short if there scope is extremely small.
- variables names should be long if they are in a big long scope, such as a global variable.
- function names should be short if they have a long scope
- function names should be long if they have a short scope
- classes names should be short, as in the realms of Python they can be considered public.
You mentioned nouns and verbs - can you explain what they are?
- Noun: a word that refers to a person, place, thing, event, substance or quality e.g.'nurse', 'cat', 'party', 'oil' and 'poverty'.
- Verb: a word or phrase that describes an action, condition or experience e.g. 'run', 'look' and 'feel'.
How should I construct my functions and how should they operate?
As a general rule of thumb, functions should,
- be small, very small
- do just ONE thing
How do you ensure your function is only doing ONE thing ONLY? Ensure you can extract no further functions from the original function. Once you can extract no more, you can be sure the function is doing one thing, and one thing ONLY.
- You should not pass Boolean or None types into your function
- No more then 3 arguments should be passed into your function
- It is better to raise an exception then return an error code
- Custom exceptions are better then returning error codes
- Custom exceptions should be scoped to the class
Command Query Structure (CQS)
This is one of my favorite disciplines within functions, as this is a great way to create clean functions that only do ONE thing,
- Functions that change state should not return values, but can throw an exception
- Functions that return values should not change state
- It is bad for a single function to know the entire structure of the system
- Each function should only have limited knowledge of the system
If you want your code to be clean, then TDD SHOULD be adopted. Lets look at why, the laws of TDD and the TDD process,
The benefits to TDD are,
- promotes the creation of more efficient code
- improves code quality
- ensures the minimum amount of code is used
- prevents code regression
There are 3 laws to TDD,
- Write no production code until you have create a failing unit test
- Write only enough of a test to demonstrate a failure
- Write only enough production code to pass the test
The process for TDD is,
- RED - Create a test and ensure it fails
- GREEN - Write production code to ensure the test passes
- REFACTOR - Refactor your code and ensure tests still pass
Good architectures are NOT composed of tools and frameworks. Good architectures allow you to defer the decisions about tools and frameworks, such as UIs and databases.
But how is this achieved? This is achieved by building an architecture that decouples you from them - by building your application, not on your software environment, but based on your use-case. Decoupling your applications allows for changes to be made, fair easier that it being a single monolithic application. Also decoupling allows for clear business decisions to be made to each part of your application i.e time/money spent on the UI, API and usecase, i.e core application.
What is a Use Case?
A use case is a list of actions or event steps to achieve a goal. It is important to note within our use-case no mention is made to databases or UIs. Below is an example,
-- Create Order -- - Data Customer-id Customer-contact-id Payment-information Shipment-mechanism - Primary Course Order clerk issues Create Order command with above data System Validates all data System creates order and determines order-id System delivers order-id to clerk - Exception Course
Validation Error - System delivers error message to clerk
As more use cases are defined partitioning it is required to allow clear separation within your system, this design is also know as EBI (Entity, Boundary, and Interactor).
- Business Object (Entities) - Entities are application independent business rules. The methods within the object should NOT be specific to any of the systems. An example would be a Product Object.
- Controller (Interactors) - Use cases are application specific. Use-cases are implemented by interactor objects ; It is the goal of the interactor to know how to call the entities to reach the goal of the use case. An example for our example use case would be CreateOrder.
- User interfaces (Boundaries) - A boundary is the interface that translates information from the outside into the format the application uses, as well as translating it back when the information is going out.
Below shows how this actually looks,
 Clean Code - Robert Cecil Martin