Wikipedia defines the SRP like this: “[T]he single responsibility principle states that every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class. All its services should be narrowly aligned with that responsibility.”
So what does this mean to you and how you code? Well lets look at some code that doesn't and then does follow the SRP.
So now our Services only handle one type of object. From here anything that would send back a User would go through the UserService and Groups through the GroupService. The hidden refactor here is in the Repository layer. They too have been refactored to specific types. This is a simple example and doesn't look like it has very much use right? Wrong. Lets delve into this a little more.
The presentation layer could be a Web Page or a Winform or even a command line app. In the grand scheme of things it doesn't matter and in fact they could be interchangeable. Same with the Data Tier layer. Lets say you choose to use Fluent Nhibernate for the data layer as a wrapper for your database. If your data layer only holds the mappings and the data objects then at any point in your application you could swap to Entity Framework and keep on rolling with very little (if any code change). The key to allowing this to happen is the Logic Layer or Core as I will be referring to it from here on.
The Core layer should hold all your business logic. The repository layer will talk to the Data Layer as a proxy for Core. Core will hold ALL of the contracts (interfaces / abstract classes) that will be injected. That means Core does not have a reference to anyone but everyone has a reference to core.
So why do I have a repository layer you ask? I prefer to use the Repository Pattern in conjunction with my ORM. This allows for testing and if I swap out my ORM I just need to ensure that the new orm's Data Contexts, Inherit from the Interface I wrapped around the previous type.
If all of the business logic is in Core how is it possible not to reference any other project? Two words: Dependency Injection(DI)!! I will cover a brief description of using DI but it has far more features then I will cover here. (note: the Core will reference the Data Layer you will see why below)
I will be using Ninject for all of my examples. There are A LOT of DI frameworks out there. Pick the one that works best for you.
So remember up above when I told you that Interface that was being passed as a parameter to the constructor on the service was dependency injection? Well that is half of the battle. The other half is the Inversion Of Control(IoC) Container. Some of this IoC is specific to MVC but it can be adjusted to use in WinForms applications.
The presentation layer could be a Web Page or a Winform or even a command line app. In the grand scheme of things it doesn't matter and in fact they could be interchangeable. Same with the Data Tier layer. Lets say you choose to use Fluent Nhibernate for the data layer as a wrapper for your database. If your data layer only holds the mappings and the data objects then at any point in your application you could swap to Entity Framework and keep on rolling with very little (if any code change). The key to allowing this to happen is the Logic Layer or Core as I will be referring to it from here on.
The Core layer should hold all your business logic. The repository layer will talk to the Data Layer as a proxy for Core. Core will hold ALL of the contracts (interfaces / abstract classes) that will be injected. That means Core does not have a reference to anyone but everyone has a reference to core.
So why do I have a repository layer you ask? I prefer to use the Repository Pattern in conjunction with my ORM. This allows for testing and if I swap out my ORM I just need to ensure that the new orm's Data Contexts, Inherit from the Interface I wrapped around the previous type.
If all of the business logic is in Core how is it possible not to reference any other project? Two words: Dependency Injection(DI)!! I will cover a brief description of using DI but it has far more features then I will cover here. (note: the Core will reference the Data Layer you will see why below)
I will be using Ninject for all of my examples. There are A LOT of DI frameworks out there. Pick the one that works best for you.
So remember up above when I told you that Interface that was being passed as a parameter to the constructor on the service was dependency injection? Well that is half of the battle. The other half is the Inversion Of Control(IoC) Container. Some of this IoC is specific to MVC but it can be adjusted to use in WinForms applications.
The magic happens on line 12. This Binds a concrete type to the Interface that we passed in. Now any constructor that requires a parameter of type IUserRepository; Ninject will pass a concrete type of UserRepository behind the scenes. BOOM!! Now everybody knows Core, but he doesn't know them.
So why on earth would you want to go through all of this? Unit testing. Doing this allows us to test each method in each class (unit) and we can Mock / Stub the things that do not directly effect this class. Also see: this.
Now one last note. If you read my last blog post; then you know about Automapper. Your presentation layer should NEVER use your data objects.
I like to create an infrastructure folder in my Core layer and Create Objects for the Presentation layer to use. I then wrap my new Presentation Layer object and the Data Layer object in the same interface (as long as the data layer objects are not named horribly) and then user Automapper to map from one to the other in the Core layer. Then I have Presentation Layer objects that live in Core (presentation layer has a reference to Core) and Data Layer Objects that live in the Data Layer (this is where Core needs the reference to Data) that get converted in the Core layer and passed along to their appropriate targets.
Now if you swap out the Presentation Layer. Your new Display objects just need to inherit from the Interface that wraps the Data Layer (or if horribly named, the Interface that you chose with better names) and off you go. If you swap out the Data Layer you can do the same thing.
In conclusion. If I was to give another developer my Core project, they could create an app with the same business rules in technologies that they are more familiar with. When the business rules change you are only editing one spot. All these things in mind no matter what type of development you do (web, console, command line) if you keep everything separate, Maintenance is far easier.
Robert T. Frey
Now one last note. If you read my last blog post; then you know about Automapper. Your presentation layer should NEVER use your data objects.
I like to create an infrastructure folder in my Core layer and Create Objects for the Presentation layer to use. I then wrap my new Presentation Layer object and the Data Layer object in the same interface (as long as the data layer objects are not named horribly) and then user Automapper to map from one to the other in the Core layer. Then I have Presentation Layer objects that live in Core (presentation layer has a reference to Core) and Data Layer Objects that live in the Data Layer (this is where Core needs the reference to Data) that get converted in the Core layer and passed along to their appropriate targets.
Now if you swap out the Presentation Layer. Your new Display objects just need to inherit from the Interface that wraps the Data Layer (or if horribly named, the Interface that you chose with better names) and off you go. If you swap out the Data Layer you can do the same thing.
In conclusion. If I was to give another developer my Core project, they could create an app with the same business rules in technologies that they are more familiar with. When the business rules change you are only editing one spot. All these things in mind no matter what type of development you do (web, console, command line) if you keep everything separate, Maintenance is far easier.
Robert T. Frey


No comments:
Post a Comment