
I am a firm believer in leveraging patterns and practices when I write code. Actually, I am fanatical about it. In my current role, I have had to refactor the worst code I have ever seen in my 27 years of software development. The code has been so bad at times, I nearly have gone code blind. During my many refactoring passes, I had to overcome several bouts of severe mental anguish to the point I wanted to walk away from it all. I am being a bit overly dramatic, but the experience really sucked.
Fortunately, I survived the pain and torture of refactoring what I call extreme functional spaghetti coding. Some of the methods I refactored were over 1000 lines of code. Nested “if” statements, abbreviated variable names, and pseudo business logic were everywhere. Best practices like DRY (Don’t Repeat Yourself) and SOLID (more on that in a minute) must have been completely foreign concepts to the so-called developers who had been touching the code. And then there was the constant copying and pasting of really bad code. Just when I thought I had finished refactoring, I would find more things to address.
Then there was the heavy use of try/catch statements. Instead of leveraging try/catches for true error handling, these were used to swallow the errors generated by the horrendously sh*tty code. Yes, I said it. I couldn’t help myself.
Here’s a contrived example:
try
{
// Really bad code that throws random errors.
string ABC = null;
string DEF = "";
ABC = GetABCData();
if (ABC.Contains("Something_"))
{
// Do something with ABC value
DEF = ABC.Substring(0, ABC.IndexOf("_"));
}
}
catch
{
// Swallow the error because our logs are filling up with errors.
}
I’m a C# developer by default which is truly a wonderful language to code in. Granted I’ve been using JavaScript for just as long including just about every framework that’s out there. I’m actually fairly adept at React and Angular using TypeScript. However, my true passion is object-oriented programming in C#. After many months of refactoring this particular solution, which by the way is a Dynamics 365 plugin that provisions SharePoint Online infrastructure, I finally had things in order. Now when I need to find and correct defects (yes, I have a defect or two every now and then) I know exactly where to go and what layer of the solution architecture things reside in.
What does SOLID mean to me?
Interestingly enough, with the many software developer interviews I have had the term SOLID rarely comes up. When I do the interviewing, however, it is one of the fundamental concepts I hope a candidate is very familiar with. And I don’t mean reciting what the acronym stands for which is Single responsibility principle, Open-closed principal, Liskov substitution principal, Interface segregation principle, and Dependency inversion principle. I won’t go into each one, but I will explain how I apply these 5 principles in a practical way when I code solutions. I would encourage the reader to check out this Wikipedia article.
Single Responsibility Principle
For me, the first principal could also be called separation of concerns. When I create classes and write methods, I keep this in the forefront of my mind. Each method should do one thing, this even includes the way I handle accessors to my classes. A public method should call a private member which supports one of the four pillars of object-oriented programming principles called Encapsulation. This principal also translates to layers of a solution and the patterns that support it. I am a huge fan of having a service layer that uses a repository pattern for data access. Each service and repository only handle one type and one responsibility.
Open-closed Principle
The second principal, Open-closed, for me describes using inheritance and interfaces to establish base or core behaviors of a class. The base classes are not open to modification if a child class needs new behaviors. However, one might encounter a situation where the behavior should bubble up to the interface and the base class. Think DRY (Don’t Repeat Yourself).
Liskov Substitution Principle
This principle is just as fun to say as it is to implement. Two pillars of OOP, polymorphism and inheritance are addressed in this principle. With the use of interfaces that define the behaviors of base classes, you should be able to swap concrete implementations without breaking code. I was going to attempt to provide a concrete example of this principle, but I will save that for another blog post.
Interface Segregation Principle
Bearing in mind the tenants of the single responsibility principle, this principle enforces that from an interface perspective. When coding solutions and using interfaces (and I hope you do), you should not force behaviors on classes that won’t use or need them. In practice, I strive to keep things generic as possible while leveraging interfaces. The best example of that would be my use of ICollection<T> when returning collections of objects of a particular type. I do this in lieu of concrete implementations like List<T>. They both will get you to the same destination, but I like to live by principles and good design patterns whenever possible.
Dependency Inversion
For me, this principle translates directly to dependency injection. To me it’s where the rubber meets the road in terms of the other principles. Interfaces are used to define behaviors in concrete classes that handle the heavy lifting in a .NET solution. Those interfaces are then injected into the constructors of classes (or sometimes in methods) to receive dependent services to do their jobs. Those services then should inherit from an abstract base class each focusing on a single responsibility. I think that is the true essence of DRY principles.
Putting It All Together
I hope this post has given you an idea of how to use SOLID design principles in a practical way and how those principles translate to the way you might structure your solution using the four object-oriented design pillars – Abstraction, Encapsulation, Inheritance, and Polymorphism.
One Final Thought – SOLID is not YAGNI
Using SOLID design principles is paramount to delivering solid software solutions and is absolutely necessary for success. Some might think You Ain’t Gonna Need It (YAGNI), but you truly do.
Thanks for reading my post!
- What SOLID means to me and it’s not YAGNI – February 6, 2025
- Why Working Remotely Works for Me – January 30, 2025
- Why I Won’t Be Working for the Secret Service Anytime Soon – January 24, 2025
Leave a Reply