Don’t Repeat Yourself, or DRY, is a key principle of software engineering. Various sites on the web and various courses state this principle as:
“Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.”
One of the things this means, practically, is that the abstractions that you use in your code should provide for reuse such that there is never a need to copy code.
Reuse of code can be accomplished by properly designing your objects (abstractions) such that they have a single responsibility. For example, if you have several objects that communicate with a data layer, you should abstract the data layer away into a data access class that is then injected into the constructor of objects that need to converse with the data layer. This provides for better data encapsulation and allows for better unit testing as you can create a fake for the data access object. Another example of how you can reuse code is through the use of base classes that provide functionality that is common to a set of potentially derived classes.
I recently presented a course on best practices for Object Oriented Design at my company and ran across a very cool tool that was mentioned in a Pluralsight course by Steve Smith. The tool is Atomiq by goldfinch. It is a completely free tool that they make available (self-admitedly) to drum up business for their static analysis tool, Nitriq. Atomiq searches your code and finds code duplication and similarities. It provides statistics and easy way to navigate to duplications within the code. It provides a very nifty graphic to show where duplicates are and it even has a command line EXE for which a threshold can be set for use with a continuous integration builder (very cool!).
I decided to test drive Atomiq using some old code to which I had access. I knew this code would give Atomiq a run for its money as this code has been around for a decade and has been touched and tweaked and, well, defiled by many developers. After letting Atomiq analyze the entire project, this is the wheel graphic that was generated by Atomiq:
Wheel Output From Atomiq For Solution with Lots of Repetition – (Class Names Removed to Protect the Innocent)
As I suspected, Atomiq found many sources of repetition in this solution. Each line crossing this Spirograph looking picture represents an opportunity to refactor this code such that the repetition goes down and the maintainability goes up.
I had another project where I was playing around prototyping a couple ICommand
objects for use in ESRI’s ArcMap. In this project, the two commands were generated using the ArcMap ICommand
generation tool in Microsoft Visual Studio. Because the classes were auto-generated, the same base code was added to each. For example, this code (along with a few other lines) was auto-generated into both classes:
#region COM Registration Function(s)
[ComRegisterFunction]
[ComVisible(false)]
static void RegisterFunction(Type registerType)
{
ArcGisCategoryRegistration(registerType);
}
[ComUnregisterFunction]
[ComVisible(false)]
static void UnregisterFunction(Type registerType)
{
ArcGisCategoryUnregistration(registerType);
}
#endregion
This duplicated code caused Atomiq to (rightly) generate this graph:
Atomiq Output Because of Duplicate Auto-Generated ICommand Template Code
For this particular duplication, Atomiq found 65 lines that were similar. Also, Atomiq showed this similarity view, that showed the same code side-by-side:
- Atomiq Similarity View Showing ESRI ICommand Boilerplate
This is one example where Atomiq shows a great place to do some refactoring. By pulling all of the ESRI ArcMap boilerplate code into a base class, we can move all of this duplicate code to one place and then create derived classes from this base class. For this example, I just started by refactoring out a part of the similar code, as shown here:
using ESRI.ArcGIS.ADF.BaseClasses
[ComVisible(true)]
public abstract class MyBaseCommand : BaseCommand
{
[ComRegisterFunction]
[ComVisible(false)]
static void RegisterFunction(Type registerType)
{
ArcGisCategoryRegistration(registerType);
}
[ComUnregisterFunction]
[ComVisible(false)]
static void UnregisterFunction(Type registerType)
{
ArcGisCategoryUnregistration(registerType);
}
}
After reanalyzing the code, the 65 similar lines dropped to 55:
After refactoring – Duplicate Lines Dropped from 65 to 55
By iterating in this same fashion, Atomiq can help to eliminate duplications and make this code more maintainable.
While there is no silver bullet, Atomiq is a very good (and very free) tool to use in making sure that you write code that complies with the DRY principle. When coupled with the command line version for a continuous integration builder, this is a great way to improve code quality.
CodeProject
I'm a learner/coder/leader who is curious about how technologies and people work together to solve interesting problems. I have a passion for software and doing what I can to improve the lives of the people who create and use it.