Posts Tagged SOLID
Back in 2010 I wrote what became my most popular post in this blog: A Good Example of Liskov Substitution Principle, based on a scenario that came up in a project I worked on at the time. I just realized I’ve never blogged about another scenario that came up in the same project as a good example I use for the Open-Closed Principle (OCP), which is described as follows:
Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”; that is, such an entity can allow its behaviour to be extended without modifying its source code. – Wikipedia
I use a simple application to illustrate the scenario. This is a desktop application. The main menu has one sub-menu for each module (e.g., Orders and Employees). Each module has its own sub-menu to expose related functionality:
Initially, the menu was all implemented in the same place… the main window:
The “code behind” the main window called out services in the different modules:
Any time a new feature was added to a module, the main window had to be changed. With several features across several modules being written actively, the main window was a big bottleneck: many developers were trying to change it at the same time! Implemented that way, the main window violated OCP: to extend the menu (adding modules or features to them), the main window had to be changed.
In order to make the main window OCP-compliant, and therefore, improving the implementation, here are the changes made to app…
The main menu in the main window was defined, since it’s that window’s responsibility to host a menu. However, it is NOT its responsibility to know what items go in the menu. In other words, the menu is empty:
The code behind the main window that used to call services in the modules was removed, and the classes started to use an AppMenuBuilder class, which returned a list of MenuItems to be added to the menu. Each module was represented by a Module class (e.g.: OrderModule, EmployeeModule…). In the real world application these modules were registered and initialized automatically using an IoC container (but that’s beyond the point of this post).:
The AppMenuBuilder class simply registered IModuleMenuBuilder instances, and it used those to figure out what menu items were needed:
Each implementation of IModuleMenuBuilder was responsible for creating the menu items that the module needed, and what to execute when the menu item was invoked. See the OrderMenuBuilder as an example:
The MenuItemFactory offered an easy way to create the MenuItem and hook it up to the action to be executed:
Again, the real world implementation of that factory was slightly different: it implemented an IMenuItemFactory interface, which got injected into each Module class. But again, that part is beyond the point of this post. The idea behind having the MenuItemFactory was so to make it easy to hook other operations to the menu system-wide. For example, let’s say we wanted to log every action invoked by any option on the menu. Here’s a simple logger:
Here’s how the MenuItemFactory would leverage additional actions:
And once again, in the real world application this was a little more robust, where “things to be added to the menu actions” were registered automatically to the IoC container.
After making those changes, the main window became open for extension, but closed for modification: options could be added to the menu and actions could be associated with them, and the main window didn’t have to be changed.
Back in February I had the opportunity to speak at the Agile.NET conference in Houston. I did my presentation on SOLID, which I had to streamline its content in order to fit the 60-minute slot. The session was recorded and the video has been made available online here.
It’s usually not easy to find good examples that explain the Liskov Substitution Principle (LSP) to developers. But really, how hard could it be? The definition is so simple:
“What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.”
Say what? I don’t know about you, but that kind of definition usually flies way over my head. Some people use the Rectangle versus Square example to explain the principle, which is a good one, but that doesn’t necessarily relate to things we normally do.
I like Uncle Bob’s definition a lot better:
“Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.”
Recently we’ve run across a violation to that principle in a project. We have an interface defined like so:
It’s a very small interface that represents resources that can be loaded in memory, and persisted afterwards in case there were changes to it.
Let’s pretend we have the following implementations of that interface:
The actual implementation of those methods doesn’t matter here; just assume that the real implementation loads and persists application and user settings.
Somewhere in the application we have some way to retrieve a list of instances of implementations of that interface, kind of like this:
Some place else, we have a method that takes in a list of those objects, and call Persist on them:
And somewhere else we may use those methods, like so:
Everything works great, until a new class is added to the system in order to handle, let’s say, some “special settings”:
It looks like the Load method does whatever stuff it’s supposed to do in order to handle loading these special settings. The Persist method, on the other hand, throws a NotImplementedException. As it turns out, those settings are meant to be read-only, therefore, the Persist method can’t really do anything.
The system is told to load the new class along with the other ones that implement that same interface:
Now when we run the app everything should still work fine, until we hit the code that tries to persist all of those loaded resources, at which point we get a big and fat “NotImplementedException”.
One (horrible) way to address this would be to change the SaveAll method:
If the specific resource being processed is of type SpecialSettings, we skip that one. Brilliant! Well, maybe not. Let’s look back at a simplified definition of the Liskov Substitution Principle:
“An object should be substitutable by its base class (or interface).”
Looking at the SaveAll method it should be clear that “SpecialSettings” is NOT substitutable by its “IPersistedResource” interface; if we call Persist on it, the app blows up, so we need change the method to take that one problem into consideration. One could say “well, let’s change the Persist method on that class so it won’t throw an exception anymore”. Hmm, having a method on a class that when called won’t do what its name implies is just bad… really, really bad.
Write this down: anytime you see code that takes in some sort of baseclass or interface and then performs a check such as “if (someObject is SomeType)”, there’s a very good chance that that’s an LSP violation. I’ve done that, and I know so have you, let’s be honest.
Another great definition for LSP comes from this motivational poster that the folks at Los Techies put together:
So what’s the fix?
The fix here is to tailor the interface based on what each client needs (Interface Segregation Principle, or ISP). The LoadAll method (which is one client of those classes) is really only concerned about the “Load” capability, whereas the “SaveAll” method (another client) is only concerned about the “Persist” capability. In other words, these is what those clients need:
The SaveAll takes in something tailored to its needs, IPersistResource’s, and the same goes for LoadAll, which only cares about ILoadResource’s (in the real app, the actual instantiation of these classes happen somewhere else). This is what the granular new interfaces look like:
Yup, it’s pretty much the former “IPersistedResource” split up into two separate interfaces, tailored to their client needs. Both the UserSettings and ApplicationSettings classes can implement these two interfaces, whereas the SpecialSettings class would only implement ILoadResource; this way, it isn’t forced to implement interface members it can’t handle.
Very often people ask what’s the most appropriate number of members in an interface. In the real world example I gave here, the original interface had only 2 members; one could say that was small enough, but as it turns out, it wasn’t. The IPersistedResource interface was doing too much (both loading *and* persisting stuff) based on the clients that use its implementers. In the end, two interfaces with a single method on them fit the bill a lot better. Interfaces with single responsibility? Yup, Single Responsibility Principle (SRP); as with design patterns, sometimes SOLID principles go hand in hand together.
Also check out A Good Example of Open-Closed Principle!