The other day, I was watching this video of Robert Martin where he mentions the three symptoms to spot a bad code. And I couldn’t have agreed more.
Your code is rigid if you can’t change a piece of code without changing the other modules that are irrelevant and have no relationship to the code you try to change.
Rigid code is the code that has dependencies that snake out in so many directions that you cannot make an isolated change without changing everything else around it. — Robert Martin
For instance, you try to change some low-level detail in the data layer, and all of a sudden you get a compile error in the class that does the formatting for your View.
If you often find yourself touching almost all the modules of your project, whenever you make changes in a single class, it might mean a symptom of rigid code.
Fragile code is a lot worse than Rigid code. At least we get a compile error in a rigid code.
In fragile code, if you change a small piece of code in a module, you break an entirely different feature in an entirely different module. And there is no easy way to find these errors during development.
Fragile code breaks in bizarre and strange ways that you cannot predict. — Robert Martin
If you often get customer tickets saying a feature is broken, whenever you push a fix for an entirely different use case, it might mean your code is fragile.
Non-reusable code is, as the name suggests, the code that cannot be reused.
For instance, you might want to implement a feature in your project that is the same as the one your colleague has done for a different project. But you cannot easily reuse the code from that project because that code depends on some other irrelevant feature of their project which in turn depends on some framework or database system which you don’t want in your project. And you better off writing your own implementation for that feature.
This is the famous Gorilla-Banana problem:
You want a banana but what you get is a gorilla holding a banana and the entire jungle with it. — Joe Armstrong
When you write code, ask yourselves these questions:
Is this code too rigid? Is it possible to change the internals of this module in the future without touching the code in other modules and other layers?
Is this code too fragile? Will it be hard to find all the places to refactor for any changes in the future?
Should this feature be reusable? If so, does this code depends on any unwanted modules or frameworks that can be avoided?
If we look closely, the common thread of all the above three problems is coupling. The modules depend upon each other in undesirable ways and that results in spaghetti code.
The code should be decoupled across the modules and layers. High-level policies and the abstractions should not depend on low-level details. Invert the dependency of the modules at the necessary places. And write classes that do only one thing and have only one reason to change.
Good code should explain what it's doing. It should be boring to read. Everything is perfectly obvious. That is good code. — Robert Martin
Also published in my Medium publication.
Software's architecture is often compared to the structure of a home -- the foundation and building blocks to what will become a house. So doesn't it make sense to compare our code to the clutter in our home? Let's identify some easy wins for cleaning up our codebase and take action on them.