It’s so hard and useless to write clean code from scratch. First, make your code work. Then cover it with tests. Your team gets time to test your code, and you have a space to make it clean

Clean code is a result of the refactoring

Functions

Principle 1. A name of a function should tell what it does without looking at the implementation

Principle 2. Any function should be responsible for just one thing. If a function has two responsibilities, its name should reflect both. If it has three or more responsibilities — it’s a bad function

It’s also worth to mention that name of any function should tell about all side effects inside

Principle 3. ‘Action’ is a function that changes a state of a system and never returns a value. ‘Function’ is a function that returns a value and never changes a state of a system. A function shouldn’t be ‘Action’ and ‘Function’ at the same time

Principle 4. There are no function parameters — perfect! Just one parameter — fine! Two parameters — well, it’s still okay. Three and more parameters — if your domain doesn’t tell that is right, it’s wrong

When it has a small number of parameters:

  • Tests become easier
  • It doesn’t take many pieces of knowledge to use
  • It gets simpler to understand how it works

Principle 5. All rows in a particular function should belong to the same level of abstraction

It is one of my favorite principles :) Just look at the example below

Principle 6. All rows in a particular function should follow the same convention

Principle 7. Temporal binding is a situation when the order of rows in a function is crucial. Functions should avoid having temporal bindings inside

In practice, it’s impossible to follow this principle in 100% of cases. Even some examples in this article don’t follow it. But it’s nice to reduce the number of temporal bindings as much as possible

Principle 8. When it’s not obvious what the function’s call is about, it’s nice to store the call’s result in a variable with an expressive name

Principle 9. If several conditional operators belong to the same logical condition, they should be compounded into a single function, property, or variable with an expressive name

p.s. Every name should be expressive

Principle 10. Error handling should take a separate layer of abstraction

It shouldn’t be messed up with other logic

Principle 11. Object function should have a higher priority over a static one

The main reason is that a particular function can be polymorphic in the future. But, it doesn’t say that it shouldn’t use a static function at all!

Principle 12. Function length should be equal to or less than 20 rows. The depths of nesting if/else should be equal to or less than 2

Classes, Structures, and Other Custom Types

Principle 1. A class name should stick to the standard naming

E.g., if a class conforms to the BUILDER pattern, its name should contain the ‘Builder’ word — class AccountBuilder

Principle 2. A protocol name shouldn’t contain the ‘Protocol’ word — ‘AccountSubscriptionProtocol’ It is better to define a protocolAccountSubscription’ but if it has just one class that conforms it, call the class ‘AccountSubscriptionDefault’ which means ‘default’ implementation

Principle 3. You should avoid using abstract words like Processor, Data, Info in class/struct names

E.g., what is the difference between Account and AccountInfo? What is the info? There could be Account and AccountLegalDetails

Principle 4. You should avoid transitive dependencies

Transitive dependencies are difficult to refactor. And they break encapsulation

Principle 5. Every class should have the same vertical separation

General

Principle 1. The same word should have just one meaning. And only this word should be used everywhere when talking about the same thing. There should be no other synonyms

E.g., if ‘add’ means appending an element to an array, or a character to a string, don’t use it to have a sum of numbers. Use ‘plus’ for it

E.g., if ‘create’ means just creating an object and return it, don’t use it when you want to create something in the database. Use ‘save’ instead. And don’t use synonyms like ‘build’ or ‘make’ Otherwise, rename this word everywhere (DDD, ubiquitous language)

Principle 2. You should put pieces of code in places where you expect to find them

Suppose you open a class or file to find some function but don’t see it. And then you recall this function is placed in another file. It is nice to think about moving the function to the first file you’ve visited

Of course, if it doesn’t contradict architectural principles!

Principle 3. You shouldn’t use external libraries directly in your code. You should use wrappers on them

Following this principle allows:

  • Having an ability to quickly replace one library with another without changing the rest code (rare case, but still)
  • Picking an interface better for your needs (you can choose another name of a method or even combine several methods to a single one)
  • Writing tests for the wrappers that will tell your teammates how they are used

Principle 4. Client code shouldn’t be responsible for creating objects, but only for their usages. It should contain a layer consists of factories to create all objects. The FACTORY pattern allows creating objects, entities, satisfying all invariants (hi there, Eric Evans). And the DEPENDENCY INJECTION pattern tells how the objects should be passed around (SOLID, Dependency Inversion Principle)

Principle 5. All constants should be defined on the highest level or even in separate config classes/structures rather than be magical values inside the code

Principle 6. Having code duplication is bad. Duplicated rows should be moved into a separate function. And repeated switch/case — into some ABSTRACT FACTORY

Principle 7. You shouldn’t make a decision on how your code will be used

Yet another principle I especially like :) It is related to SOLID, Open-Closed Principle

Principle 8. You shouldn’t have pieces of code that are never used

It’s quite a common situation when there are commented rows ‘not to lose changes’ Or class methods included in runtime but never called. Don’t be worry about losing some knowledge. Git remembers everything

Principle 9. All pieces of code should be consistent — follow the same conventions. However, if the conventions contradict code best practices, they (conventions) should be reconsidered

P.S.

First of all, I would like to say thanks to Robert Martin and Eric Evans. Almost everything in this article I took from ‘Clean Code’ and ‘Domain-Driven Design’ I’m a big fan of those guys!

There are principles I didn’t include (TDD, parallel programming, …). I didn’t do it for several reasons:

  • I didn’t manage to put some of them into practice
  • For now, I’m quite stupid to understand some others
  • Some of them I simply might miss while reading
  • And others are obvious (follow SOLID, keep modularity, comments are bad, …)

I highly recommend everyone to read these books. You will find there a right way to design systems and write extensible and readable code. And it can help you to fall in love with the development process, and not consider the development is just a work

Another P.S.

I think it’s wrong to follow each principle in 100% of cases

E.g., Apple doesn’t do this when it returns the removed element from an array while using ‘remove(at:)’ — it behaves like a ‘Function’ and ‘Action’ at the same time. And it is quite comfortable to use

However, when you decide not to follow a particular principle, try to pick a strong defense argument. Because in most cases, these principles work

And The Last P.S.

Keep your code straightforward. Don’t try to use elaborate solutions with generic types, tons of abstractions, etc. People call it ‘overengineering’

Sometimes I check myself by showing my code to people who are quite far from development. And if I’m writing on Swift, a Java developer should mostly understand it, at least its Domain part

In the very beginning, I saw complicated code written by ‘senior developers’ I worked with. It was QUITE challenging to understand it, and when I came at them and asked: “Could you, please, clarify what is going here?” They said: “What exactly you didn’t understand?”

Funny…

I felt so stupid because I understood almost nothing and didn’t manage to identify particular things

Well, looking at their code today and keeping in mind the principles and how it could be, I wouldn’t say: “Could you, please, clarify..” anymore. I would say: “Could you, please, refactor this piece of shit? My time is valuable enough not to spend it digging in over 100-row functions, to check that you correctly build a request object and send it to the server”

References

  • Clean Code: A Handbook of Agile Software Craftsmanship, by Robert C. Martin
  • Domain-Driven Design: Tackling Complexity in the Heart of Software, by Eric Evans

Software Developer