How to Implement Solid Principles into an Existing Project

How to implement SOLID principles into an existing project

Single Responsibility Principle - A class should have only one reason to change. If you have a monolithic class, then it probably has more than one reason to change. Simply define your one reason to change, and be as granular as reasonable. I would suggest to start "large". Refactor one third of the code out into another class. Once you have that, then start over with your new class. Going straight from one class to 20 is too daunting.

Open/Closed Principle - A class should be open for extension, but closed for change. Where reasonable, mark your members and methods as virtual or abstract. Each item should be relatively small in nature, and give you some base functionality or definition of behavior. However, if you need to change the functionality later, you will be able to add code, rather than change code to introduce new/different functionality.

Liskov Substitution Principle - A class should be substitutable for its base class. The key here, in my opinion, is do to inheritance correctly. If you have a huge case statement, or two pages of if statements that check the derived type of the object, then your violating this principle and need to rethink your approach.

Interface Segregation Principle - In my mind, this principle closely resembles the Single Responsibility principle. It just applies specifically to a high level (or mature) class/interface. One way to use this principle in a large class is to make your class implement an empty interface. Next, change all of the types that use your class to be the type of the interface. This will break your code. However, it will point out exactly how you are consuming your class. If you have three instances that each use their own subset of methods and properties, then you now know that you need three different interfaces. Each interface represents a collective set of functionality, and one reason to change.

Dependency Inversion Principle - The parent / child allegory made me understand this. Think of a parent class. It defines behavior, but isn't concerned with the dirty details. It's dependable. A child class, however, is all about the details, and can't be depended upon because it changes often. You always want to depend upon the parent, responsible classes, and never the other way around. If you have a parent class depending upon a child class, you'll get unexpected behavior when you change something. In my mind, this is the same mindset of SOA. A service contract defines inputs, outputs, and behavior, with no details.

Of course, my opinions and understandings may be incomplete or wrong. I would suggest learning from people who have mastered these principles, like Uncle Bob. A good starting point for me was his book, Agile Principles, Patterns, and Practices in C#. Another good resource was Uncle Bob on Hanselminutes.

Of course, as Joel and Jeff pointed out, these are principles, not rules. They are to be tools to help guide you, not the law of the land.

EDIT:

I just found these SOLID screencasts which look really interesting. Each one is approximately 10-15 minutes long.

Applying SOLID principles

If Service implements IService and Service2 derives from Service, then Service2 automatically implements IService, since IService only defines a part of the signature of a class viable for a specific purpose. This class, or freely signaturedefinition, is then used to create a Type which in turn defines the objects members.

The signature does not change through inheritance. It can only get extended.
And this is basically the only thing you should use inheritance for:

If the visible behavior of Service2.Method1() is different from the visible behavior of Service.Method1() this means that the visible behavior of Service2 is different from the visible behavior of Service. In that case, you shall not use inheritance, but a new class that implements IService. Because it is a different Service in that case.

Let me give you a concrete example, though in a different context:

A square is technically a special case of a rectangle which implies that Square : Rectangle. However, if the length of a square changes its width also changes. This is not the case for a rectangle. So if you'd have a List<Rectangle> containing regular Rectangle aswell as Square objects, which you could do since Square was defined as a Child of Rectangle, you would have different visible behaviors. Thus, Square cannot be the child of Rectangle, since you cannot use Rectangle in place of Square. So Square : Rectangle is false. You could have both implement an Interface IGeometry which defines Length and Width as Properties and use both Rectangles and Squares in a List<IGeometry>. An interface does not specify behaviour. Just the signature.

If you have an IConfigService you would likewise define the classes FileConfigService and DatabaseConfigService as FileConfigService : IConfigService and DatabaseConfigService : IConfigService and have your classes hold them as IConfigService since they do not have to be concerned about any kind of implementation details - they only need to know that a couple of Methods and Properties exist. That's also why you create an interface for every 'purpose' instead of a big one for everything. And why Interfaces only define public members.

This is essentially what most of SOLID boils down to.

If you only add functionality to your IService implementation, then only change this one class. There's nothing from stopping you.

It's a bit of a different story though if you had something like a webservice on which already existing and running systems depend on - in this case I would have a look into versioning.

SOLID principles and how to actually implement them

As I see it, you are violating the Single Responsibility Principle, since your RecurringPaymentMarkAsFailure has two responsibilities. Besides the responsibility of makring the payment as a failure, it also adds the responsibility of managing the transaction (the using (BeginTransaction); that is a cross-cutting concern.

You will probably have many classes like these in the system that handle business logic, and probably all (or many) have this exact same transaction code. Instead, consider adhering to the Open/Closed Principle by allowing to add this behavior as decorator. This is well possible, because the transaction is the first AND last operation in this code. A naive implementation of this decorator could look like this:

public class TransactionRecurringPaymentMarkAsFailureDecorator
: RecurringPaymentMarkAsFailure
{
private RecurringPaymentMarkAsFailure decoratedInstance;

public RecurringPaymentMarkAsFailure(
RecurringPaymentMarkAsFailure decoratedInstance)
{
this.decoratedInstance = decoratedInstance;
}

public override IRecurringProfileTransaction MarkPaymentAsFailed(
IRecurringProfilePayment payment, string failureData)
{
using (var t = BeginTransaction())
{
var transaction = this.decoratedInstance
.MarkPaymentAsFailed(payment, failureData);

t.Commit();

return transaction;
}
}
}

This decorator allows you to wrap the class as follows:

var marker =
new TransactionRecurringPaymentMarkAsFailureDecorator(
new RecurringPaymentMarkAsFailure(
/* dependencies */
));

As I said this implementation is a bit naive, since you will probably have many classes that need to be wrapped, and this means that each class would get its own decorator. Although this is completely SOLID, it isn't DRY.

Instead, let all classes that execute use cases implement a single generic interface, something like ICommandHandler<TCommand>. This allows you to create a single generic TransactionCommandHandlerDecorator<TCommand> class to wrap all those instances. Take a look at this article to learn more about this model: Meanwhile… on the command side of my architecture.

Need Help in applying SOLID principles

Question: My UI layer does not have any ref to EF DLL. However, It has
an instance of Repository class. In MVC application, my controller
will have an instance of repository class or UnitOfWork.

Yes, UI layer classes must not have any reference to EF. But to do this, they can't have a reference to the concrete repository. In MVC Application, if you don't use a Service Layer, the Controller will have a reference just on IUserDetailRepository, and wait a concrete type from construction.
About UnitOfWork, it depends on your implementation :-)

a) Is this the right thing to do ?

The right thing to do is called "loose coupling", it seems that your design is choosing this way.

b) Is there any way i can abstract it ?

Yes, you can use a Dependency Resolver. This way, no need to reference concrete types, you will have a code only based on abstractions

c) What if in future i want to swap out EF with Dapper or any other ORM tool ?

You must have a Data Access Layer, for example, a library containing your concrete implementations of your IXxxRepository contracts. In your case, it will be EF implementations. When you will change for Dapper, you will have to re-implement this layer. The refactoring has an acceptable limit.

d) How do i fit my DI tool in this project ? In which layer it should be ?

Best place to place your DI tool will be the UI layer. On application start, you will configure dependencies bindings and everything will work automagically ;)

e) Unit testing. I am aware of StructureMap and want to make use of it in this project in such a way that in future i should be able to swap it out with Ninject. How do i achieve this ?

You want to unplug your Dependency Resolver to plug an other? No problem, just have a forecast when coding configuration of your DR to have the minimum coupling with your application. There are some tips to limit coupling in some cases... In the project I am currently working on, we have first an MVC application and a Service Layer, Business Layer, Data Access Layer, and Infrastructure Layer. We use Ninject as DR, and the infratructure and Web UI layers are the only that have a reference on Ninject. It's very easy to unplug it, and we already tried Unity this way.

One more thing, you shouldn't have a contract for UserDetail. There is no need for that, use Dependency Injection on stateless classes rather than on all classes like DTOs.

How to practice SOLID principle of OOP design?

Sometimes it's easy to write the whole logic into procedural pattern rather than to use SOLID

I cannot agree more, it is easier for us programmer to handle code in procedural pattern. This makes OOP hard for programmer who accustomed to procedural programming.

However I found it easier to write the general interface and consumer first rather than breaking the interface designed to smaller modules. This is, a kind of Test First Development -> Red, green, refactor practice. (please note that, if you want to achieve the neat design, consider following TDD instead this guide. This guide is just a small section of doing TDD)

Say that we want to create the ServiceAttendance to do scanEmployeeID. We will have an interface like (please notice the example is in C# naming):

public interface IServiceAttendance{
bool ScanEmployeeId();
}

Please note that I decide the method to return bool instead of void to determine success/failure operation. Please notice the consumer example below does not implement any DI because I just want to show how to consume it. Then in the consumer, we can have:

public void ConsumeServiceAttendance(){
IServiceAttendance attendance = Resolve<IServiceAttendance>();
if(attendance.ScanEmployeeId()){
// do something
}
}

This concludes the consumer. Now we move to implementation. Say that you can develop it using procedural programming and got the monolithic code block. You can state the implementation with pseu-like statement.

public class ServiceAttendance : IServiceAttendance{
public bool ScanEmployeeId(){
bool isEmpValid = false;
// 1 scan the employee id
// 2 validate the login
// 3 if valid, create the login session
// 4 notify the user
return isEmpValid;
}
}

Now we have 4 steps to be done in this one operation. My principal is, not to do over 3 facade process in one method so I can simply refactor the 3 and 4 to one process. Now we have

public class ServiceAttendance : IServiceAttendance{
public bool ScanEmployeeId(){
bool isEmpValid = false;
// 1 scan the employee id
// 2 validate the login
// 3 if valid, create the login session and notify the user
return isEmpValid;
}
}

This, we have 3 main operation. We can analyze whether we need to create a smaller module or not by breaking down the operation. Say we want to break the second operation. We can get:

// 2 validate the login
// 2.1 check if employee id matches the format policy
// 2.2 check if employee id exists in repository
// 2.3 check if employee id valid to access the module

The breakdown operation itself is obvious enough to break the second module into another smaller module. For 2.2 and 2.3, we need a smaller module to be injected. Simply because it will need dependency to repository, thus need to be injected. The same case apply for operation step 1 scan the employee id, because it will need dependency to fingerprint scanner, so the scanner handler must be implemented in separated module.

We can always breakdown the operation, as we can do it in 2.1:

// 2.1 check if employee id matches the format policy
// 2.1.1 employee id must match the length
// 2.1.2 employee id must has format emp#####

Now I am unsure if 2.1.1 and 2.1.2 need to be broken down into 2 separated modules, it is up to you to decide. And now we got the interfaces, then we can start the implementation. Expect to throw exceptions during validation or you will need to pass custom class to handle error messages.

Are there SOLID principle exceptions?

The Open-Closed principle is important and useful, but it is not something that should be applied blindly to all classes and all modules. In some cases, creating the abstractions that enable extensibility is just not worth it, because no extensions are expected. In other cases, we can anticipate that requirements will change, but we're not sure what kind of changes to expect, or we're not sure about the other requirements, so we prefer to postpone the decision, and begin with a simpler module implementation that does not respect OCP.

Moving data between interfaces without violating SOLID principles?

Ok, so thanks to your suggestions (Fendy, Andy, MrDosu), here's the far-cleaner Facade implementation:

public class Cart
{
private List<ICartItem> CartItems;

// ...Other Class Methods...

[HttpPost]
public void AddItem(int productVariantID)
{
var product = ProductService.GetByVariantID(productVariantID);

if (product != null)
{
CartItems.Add(CartItemConverter.Convert(product));
CartService.AddItem(productVariantID);
}
}

[HttpPost]
public void RemoveItem(int productVariantID)
{
CartItems.RemoveAll(c => c.VariantID == productVariantID);
CartService.RemoveItem(productVariantID);
}

public IEnumerable<ICartItem> GetCartItems()
{
return CartItems;
}

// ...Other Class Methods...
}

Since I only care about cart-related properties after my items have been added to the cart, I can remove references to IStoreProduct and ISubscription. If I ever end up needing to extract more information (YAGNI applies here), I can use the Adapter pattern (via the ProductService) to populate the necessary data.

How to keep a big SOLID project manageable?

It's possibile that you will have more code, and for sure each implementation will cost you more because, for example, instead of modifying a specific service you will have to create a new one with interaction of existing infrastructure, and if your modifications will affect also other modular pieces, you have to refactor all other related interfaces without coupling models, services and so on.

Modules/Services must interact but they don't have to be coupled. The more pieces are decoupled the more it costs you (time/effort). The first question is how much are you interested in a real strong SOLID application and which benefit do you take implementing it.

Anyway, when you say:

References sounds like the way to go but it could show over 100 ref and a lot of them may not have anything to do with functionality of the class.

This seems in contrast with the I principle: Interface segregation principle

Because you should have more specific, smaller interfaces instead of fat interfaces. But for sure it is possible that you will have a higher number of nested calls (interacting services through interfaces, for example)

You second problem also:

So when investigating a specific flow and we encounter a injection we need to dig in to what object that really is injected to know which code that is executed

Seems related to problem 1. Because with smaller and more specific interface, and specific flow, you should understand the code involved and it should be clearer than a non SOLID application

Solid Principle examples anywhere?

Have a look at Mark Seeman's blog or, even better, buy his book. It covers so much more than just DI. I appreciate you probably just want a simple sample to get going with. However, it's a subject that many who claim to understand don't and therefore worth learning well.

That said, here's a very simple example. The terminology, as I understand it, is
Inversion of Control and Dependency Injection. Inversion of Control refers to the fact that you give control of a class's dependencies to some other class, opposed to the class controlling the dependency itself, usually via the new keyword. This control is exerted via Dependency Injection where a class is given, or injected, with its dependencies. This can be done via an IoC framework or in code (known as Pure DI). Injection can be performed in the class's constructor, via a property or as a method's parameter. Dependencies can be any type, they don't have to be abstract.

Here's a class that lists Tour de France winners who haven't doped:

class CleanRiders
{
List<Rider> GetCleanRiders()
{
var riderRepository = new MsSqlRiderRepository();

return riderRepository.GetRiders.Where(x => x.Doping == false);
}
}

This class is dependent on the MsSqlRiderRepository. The class takes control of the creation of the instance. The problem is that this dependency is inflexible. It's hard to change it to a OracleRiderRepository or a TestRiderRepository.

IoC and DI solve this for us:

class CleanRiders
{
private IRiderRepository _repository;

public CleanRiders(IRiderRepository repository)
{
_repository = repository;
}

List<Rider> GetCleanRiders()
{
return _repository.GetRiders.Where(x => x.Doping == false);
}
}

Now the class is only depending on an Interface. Control of the dependency has been given up to the class's creator and must be injected via its constructor:

void Main()
{
var c = new CleanRiders(new MsSqlRepository());

var riders = c.GetRiders();
}

Arguably, a more flexible, testable and SOLID approach.



Related Topics



Leave a reply



Submit