One of the reasons that developers may resort to hacks and thus introduce design smells instead of adopting a systematic process to achieve a particular requirement is ‘viscosity’. Software viscosity refers to the “resistance” (i.e., increased effort and time) that must be encountered when the correct solution is being applied to a problem. If, on the other hand, a hack requires less time and effort (i.e., it offers “low resistance”), it is likely that developers will resort to that hack, giving rise to design smells.
Recently, an architect shared her experience on how the viscosity of the environment can lead to the introduction of Insufficient Modularization smell. [Note: This smell arises when an abstraction exists that has not been completely decomposed, and a further decomposition could reduce its size, implementation complexity, or both.]
She had just joined a globally distributed software development project concerning a critical clinical workflow product. The ownership of the code base was with the central team located in Country A, and she was a part of the offshore development team located in Country B.
In the first few weeks of her involvement, she realized that there were a number of smells in the design and code. For instance, she came across a class in the source code that was very long and dense – it had around 40,000 source lines of code and the Weighted Methods per Class – i.e., the sum of Cyclomatic complexities of the methods of a class – exceeded 2000! In other words, this class was a clear example of Insufficient Modularization. When she approached her team members, she realized that they were already aware of the size and complexity of this class. In fact, she also came to know that this class was prone to defects and was subjected to frequent changes.
Being new to the project, she was puzzled about why this class was so huge and why no refactoring had been performed on it so far. Upon further probing, she found out that the real problem was due to the process being followed in the project! There were two aspects that contributed to this problem. First, to prevent unwarranted modifications to the critical product, the project relied on a stringent process to control changes to the source code. As per this process, whenever a new class was introduced by the team in Country B, it needed to be approved by the central team in Country A because it owned the code base. This approval process was a long and arduous affair requiring multiple email and telephone interactions to champion the need for adding a new class.
Second, the project management was understandably very concerned about the timely release of this product in the market and continuously pressurized the team in Country B to finish coding and bug-fixing activities as early as possible. Naturally, in such a situation, the team in Country B wanted to avoid the time-consuming approval process for new classes. Consequently, the team decided not to introduce any new classes and instead decided to merge all new code in existing classes. This led to the bloating of existing classes in the design. The nature of the change approval process also discouraged refactoring. For instance, refactoring the class with 40000 lines would require breaking it up into several smaller cohesive classes. Since the approval for all these newly-created classes would require a long time, the team in Country B was not keen to refactor such large and complex classes. Since refactoring was not taken up at regular intervals, even during the maintenance phase, the existing classes continued to bloat and became increasingly bug-prone.
There are two key take-aways from this anecdote:
• Although software processes are meant to facilitate the creation of higher quality software, if they are difficult to follow or not user-friendly, people will either bypass the process, or avoid it completely, or take short-cuts thus affecting the quality of software. Organizations should, therefore, strive to make software processes user-friendly.
• Project management is often unaware of the impact of software processes. In the above case, if the project management were to be aware of the nature of the change approval process and its impact on the schedule, they could have taken appropriate steps to avoid incurring technical debt. For instance, they could have optimized the change approval process (perhaps by having it done in the same country) so that the schedule is met. Alternately, they could have modified the schedule to ensure that the team in Country B feels encouraged to follow good design practices and the change approval process set in place.
[Source: “Refactoring for Software Design Smells: Managing Technical Debt”, Girish Suryanarayana, Ganesh Samarthyam, Tushar Sharma, ISBN – 978-0128013977, Morgan Kaufmann/Elsevier, 2014. URL: http://amzn.com/0128013974]