How to identify an under-abstracted design?
A design can be over-abstracted in some areas and under-abstracted in others. Just as over-abstracted designs can have too many abstractions and classes, under-abstracted designs have too few to handle interactions and satisfy requirements. Intuitively, it might seem that an under-abstracted design would be good, easy, and simple, but the real problem is that an under-abstracted design is difficult to understand, change, and maintain. Ironically, the result of under-abstracted design is high complexity and excessive amounts of code.
The good news is that is easy to identify and address these areas. Once addressed, your confidence and development velocity will increase; and more importantly, you will be able to satisfy new business needs.
What is the best indicator of an under-abstracted design?
In my view, high complexity is the best indicator. Not only will it help identify under-abstracted areas of your design, but real problem areas within your codebase.
A simple and long standing complexity metric is cyclomatic complexity. Cyclomatic complexity (or conditional complexity) is a software metric developed by Thomas J McCabe in 1976. Basically, it is a measure of the number of control flows with a method, function, or module. The metric is computed by counting the number of decision points + 1. For a more formal definition, check out McCabe’s original paper: A Complexity Measure.
With Visual Studio Pro and above, you can identify these areas within a couple of minutes even if you are not familiar with the codebase. To do this in Visual Studio, use the following menu item: Analyze->Calculate Code Metrics for Solution. Visual Studio 2012 allows you to export the metrics to excel so that you can more easily identify the methods that have the highest complexity.
How to evaluate risk by cyclomatic complexity?
There is a strong correlation between defect density and high cyclomatic complexity. Below is a risk evaluation for methods as defined by Software Engineering Institute (SEI):
Cyclomatic Complexity Risk Summary
|1-10||Simple, low risk|
|11-20||Moderate complexity, medium risk|
|21-50||Complex, high risk|
|51+||Untestable (Very high risk)|
Why is using cyclomatic complexity metric important?
In short, complicated methods and classes are tough to understand, difficult to test, challenging to debug, and usually require vast amounts of time and attention to maintain.
To understand code, it must be readable. The concept, although not the method, is somewhat similar to that of general text complexity measured by the Flesch-Kincaid Readability Test. Methods with lower cyclomatic complexity are much easier to test.
When modifying a method with 50+ cyclomatic complexity, chances are very strong that you will introduce at least one defect while either adding a new feature or fixing another defect.
Other good indicators…
Here are a few other indicators to help identify under-abstracted design:
- Duplicate code
How to identify: In Visual Studio 2012, you can identify duplicate automatically using the following menu item: Analyze->Analyze Solution for Code Clones
- No business, service, or data access layers
How to identify: All the code is in the User Interface layer represents a lack of “separation of concerns”; that is, where all of the business logic, security, data access is performed in the user interface layer. This indicator might be obvious to many, but is not followed even more. Even if your design has a clean separation of concerns, there can still be high cyclomatic complexity in the business and UI layers.
- Too many methods and members per class (Large classes)
How to identify: Look for large classes in terms of Lines of Code (LOC) and perform manual inspection. Look for classes that are doing more than one thing. The number of methods and LOC can be subjective, but here is a discussion on stackoverflow of what that number might be.
Under-abstracted design is definitely not great design. In my view, cyclomatic complexity is a simple, well established, metric that can identify under-abstracted areas of your design and codebase. The irony: under-abstracted design results in high complexity and excessive duplicate code.
Remember, complexity is our common enemy so keep fighting it.
Upcoming: How to advance an under-abstracted design?