In 2000 software engineer and instructor Robert C. Martin, also known as “Uncle Bob” introduced the theory of SOLID principles in his paper Design Principles and Design Patterns. A mnemonic acronym, SOLID stands for the five design principles that Martin believed would help to make software designs more easily understood, flexible, resilient to ever-changing requirements. The principles are Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion.

Symptoms of Rotting Design

Uncle Bob Martin

Martin has identified 4 major symptoms that help identify “rotting” code. They are: rigidity, fragility, immobility, and viscosity.

Rigidity

Rigidity can be identified when nearly every change made to the code causes a cascade of subsequent necessary changes for dependent modules. This code can be very difficult to maintain as seemingly simple tasks spiral into huge projects because of unknown dependencies buried in multiple places.

Fragility

Fragility is a close relative to Rigidity, although the symptom here is the breakage of code in multiple locations when changes are made. Problems may arise in fragile code in areas that have no conceptual relationship to the code that has been updated. Each change seems to make the issues worse than they were before fixes were attempted.

Immobility

This is the inability to reuse code in other parts of your project because the code in question has too much baggage. Even if the software you wish to copy is very similar to the new software you need, the time it would take to clean up the code outweighs the time it would take to build it from the ground up.

Viscosity

According to Martin, Viscosity can come in two forms, viscosity of the design and viscosity of the environment. The viscosity of the design can be measured when the ease of preserving the design of a program is outweighed by the ease of just hacking a solution together. When it is much too difficult to make a change the right way, engineers will fail to do so.

Viscosity of the environment happens when the development environment is slow and inefficient. For instance, if the process of checking in a few files takes hours, engineers may make changes that require as few check-ins as possible as a time-saving measure, regardless of the proper way to do things.

While it is obviously the goal of any good software engineer to write clean clear code, ever-changing project goals and requirements can often be pointed to as the cause of the above code smells. But, it is important to note that the theme running through many of these code smells is the use of improper dependencies. To help manage dependencies, Martin has identified SOLID design patterns, outlined below.

SOLID Design Principles

Single Responsibility Principle

“There should never be more than one reason for a class to change.”

This principle encourages complicated classes to be divided into smaller classes that have explicit responsibilities. While this may seem like a fairly straight forward principle to follow, it is often difficult to put into practice if a class’s responsibility isn’t immediately clear. Martin has helped us capture the responsibility of a class by arguing that responsibility is a “reason to change.” Thus, you can identify bad design when there are multiple entities that change for different reasons.

Open-Closed Principle

“A module should be open for extension but closed for modification.”

Simply put, this principle requires that modules should be written so that they can be extended, without requiring them to be modified. This seems contradictory at first, but the key to making this work is by adequately using abstraction techniques. Proper abstractions allow for features to be added by adding new code and not changing the original codebase. You aren’t likely to break working code if you don’t have to change it.

Liskov Substitution Principle

“Subclasses should be substitutable for their base classes.”

Originally devised by Barbara Liskov, this principle can be a bit difficult to understand. At its core, it means that “subclasses should add to a base class’s behavior, not replace it.” Ideally, parent instances should be able to replace their child instances without creating any unexpected or mysterious behavior.

Interface Segregation Principle

“Many client-specific interfaces are better than one general-purpose interface.”

It is better to break down main classes into smaller more specific classes rather than try to maintain one large generalized class. This way, the class’ clients aren’t relying on methods that they don’t use.

Dependency Inversion Principle

“Depend upon Abstractions. Do not depend upon concretions.”

This principle suggests that higher-level modules should not depend on lower-level modules. The majority of dependencies should be on abstractions from both the higher-level and lower-level modules as well as details.

Implementing these SOLID design principles should help your code become more flexible and weather the inevitable requirement changes that come in any project.

Sources

RubyGarage: SOLID Object-Oriented Design Principles with Ruby Examples

Design Principles and Design Patterns, Robert C. Martin

Wikipedia: SOLID