Let’s start with a consideration: most of the time, the most important characteristic of a good codebase is to be easy to maintain and evolve. And the reason is simple: if it’s easy to change, you can easily improve any of the other aspects like performance or reliability. In other words, you need a good design.
But ok…what does “good design” mean?
There are many different “tools” that you could want to learn/apply to evaluate and improve your design. For example we have SOLID. We have the Four Rules of Simple Design. I also recently discovered CUPID. Then you can also learn some design pattern. Maybe you heard (or you use) also TDD. For sure you could want to write some cool Object Oriented code or some even cooler functional code. And how about start applying some DDD? You can also run static code analysis and extract some metrics.
Add to the list as many approaches, principles, practices you want, for sure there are hundreds I did not mention.
All of these “tools” are really interesting and valid. The problem is that they are many.
If you are an experienced developer with some passion for design, you can probably quickly spot which “tool” to use, when and how. However if you are not so much experienced, you can easily get lost.
Some of these “tools” are not even so simple when you really start to understand them. E.g. Single Responsibility Principle is really difficult to me because it implies understanding not only which are the responsibilities of your system but which are the different reasons that could trigger a change (and even worse this could be connected to the organisation of the company). TDD is something so simple in theory…and so difficult to master: are you sure your tests are really driving your design? Are you sure your tests are not slowing you down too much when refactoring the code? Are you sure you are in the case where TDD makes sense?
Moreover, typically when you change your code to fulfil some principle, you move away from another one. And that’s perfectly normal, because there’s no perfect solution. It’s (almost) always a matter of compromises.
The result in my experience is that when discussing a piece of code in a pair session or in a code review, the discussion could become difficult, especially if I’m discussing with a less experienced developer that, maybe, never heard about many of these topics. If I start mentioning a different principle every 5 lines of code, I can clearly see him/her getting lost after 1 minute.
So I asked myself: ok, given what I learnt in my career, which is the best simple advice I can give to anyone that wants to improve the quality of his/her code?
Several years ago I had the opportunity to attend a training held by J. B. Rainsberger. In that training there was a session in which I was explained The Two Elements of Simple Design. The article (that is the short version of the explanation I had in the training) starts from the 4 rules of simple design and explains why you can reduce your explicit rules just to 2: removing duplication and improving names.
I discovered that this works in a very good way, exactly like described. If you focus on these 2 aspects, your design will improve in many ways. Many problems will emerge automatically and many solutions will come automatically. Moreover it’s easy to apply because you only have 2 points to focus on and you can quickly become better and better so it’s really efficient also for non experienced developers.
So this is my takeaway: first aspects to focus on while writing/reviewing the code are removing duplication and improving names.
Then, everything else.