Most of you have lived a day when you are greeted at your desk by the morning refreshing breeze(air wick), and a few have smelt it turning pungent at the sight of bugs raised. You take a few sips of coffee while shallow debugging just enough to conclude, “This is easy, couple of line changes and it would work like a charm!”. In the following Stand-Up, you face the grinning QA and declare a good and lavish 8 hours for the fix in front of your team and the scrum master. After some dig up, you realize the module you are fixing has a dependency elsewhere; it hits harder when you find yourself chasing a rabbit hole of dependencies. With only a few hours remaining, you succumb “lavish estimate is not lavish enough”.
Most of you know what follows next. In tough situations like these, the developer with his hands dirty is often seen as a dentist performing open-heart surgery. The developer might have a good number of valid reasons to explain this absolute plethora of mess, but it all sounds Greek and Latin to the managers.
When was the last time the code you wrote has slowed you down? You modify a small part of the codebase and that slows down the whole app. Or worse of all, you change a small part of one module and some functionality of a totally unrelated(you think) module breaks down!
Let’s try to identify the symptoms and classify the reasons behind them.
Code is rigid when changing a piece of code requires subsequent changes in a functionally independent module.
In a hospital management system, suppose you want to restrict the OPD visit hours, but this modification requires you to change the working hours of Doctors and staff, the design is said to be rigid.
“Code that has a dependency that snake in so many directions, that you cannot make an isolated change without changing anything around it.”
— Uncle Bob.
Rigid code often results in developers fearing to fix the non-critical problems because they would not know how long it will take.
Code is considered fragile when you develop a new feature that works completely fine, but it also induces an error in a completely different module. Fragile code is more painful than Rigid code; there is no easy way to find the errors in a completely independent module during the development.
Suppose you want to update patients’ admission forms, but after the changes, you find the billing module is throwing unexpected errors.
“Fragile code breaks in bizarre and strange ways that you cannot predict. In extreme cases, your senior would tell you not to touch that module, that module is too fragile, every time had anyone modifies it, something else goes wrong. This is the ultimate failure of software development.”
— Uncle Bob.
It gets challenging to maintain a codebase with fragility. Every fix or new feature introduces a few bugs in unexpected modules. Here the developer has to hunt the cause of errors, and on the other hand, he has to bear the distrusting management and clients.
Code reuse is the practice of using existing code for a new function or software. Reusable code could be a library/module that is called multiple times within the codebase; or, the desired code can be copy-pasted from a completely separate software. But to reuse code, that code needs to be of high-quality — reliable, generic, and secure.
“The desirable part of the code are horribly coupled to the undesirable parts of the code that you cannot use the desirable part of the code somewhere else.”
— Uncle Bob.
You often find a piece of code that does what you need it to do, but it does more than that. The baggage around it is so much that you better off develop it from scratch or even duplicate it within the same codebase.
The absence of reusable code often causes code redundancy. As time goes by, one can’t even recognize what code is unnecessary and eventually, the whole project becomes clumsy and hard to maintain.
The above is a summary of symptoms that show that your code smells bad. The common factor for all the above three problems is Coupling. The modules depend upon each other in undesirable ways and that results in coupling. The code should be decoupled across the modules and layers to avoid them.
There are many techniques and practices out there which prevent bad code. SOLID Principles is a coding standard that all developers should have a clear concept for properly developing software to avoid a bad design. The broad goal of the SOLID principles is to reduce dependencies so that engineers change one area of software without impacting others. Additionally, they’re intended to make designs easier to understand, maintain, and extend.