SOLID OO Principles

      4 Comments on SOLID OO Principles

As much as we're like to believe that "loose coupling, high cohesion" is enough, when you actually dive into the concept, you find that it's more descriptive than prescriptive. If you want to know how to actually apply these to your day to day development, you have to get into the SOLID principles which describes the five tangible aspects that "good" OO design should contain.

First, is the Single Responsibility Principle or SRP. In short, it means that like things should be together and nothing more. If you have a class that handles all aspects of one process or everything about a single object, that's good. If your class also manipulates other objects or is just a place to catch a bunch of methods, you're doing it wrong. Within the web2project world, we have a Link class with these methods:

At first glance, you can tell that most of these methods have to do with normal CRUD operations and probably interact directly upon the CLink object. Unfortunately, we have one other method on that class:

Yes, unfortunately that is a real method name..

When you glance at this method, the name alone should be a sign that a lot of happening here. In fact, since there are potentially three other object id's as input, it's safe to assume we're interacting with those three other objects. If those objects ever change, we end up with "shotgun surgery" where a small change to one part of the system causes little changes all over the place. This is painful to maintain even in the short term.

Next, we have the Open/Closed Principle or OCP or in more plain terms "software entities should be open for extension but closed for modification." You might have heard this said another way in your favorite Open Source project as "Don't Hack Core." In practice, this one can be enforced by extremely selective use of the private and final keywords.

If you are considering reasons to mark something as private, stop and reevaluate your goals. Are you just trying to limit its use outside the class or is there really only One True Way to perform the task? If you want to limit its outside use, consider the protected keyword instead. It allows for your class to be extended and for the method to be overridden if needed.

Next, we have the Liskov Substitution Principle or LSP and honestly, this is the hardest one for me to grasp. In short, the idea is that objects in a given class hierarchy should be replaceable with their subtypes without modifying the "correctness" of the system. In proper terms, it means that method/class preconditions cannot be strengthened, post conditions can't be weakened, all exceptions thrown must equally interchangeable, and method signatures should be completely compatible.

I'll hold my example for this one until Monday. It's quite long and involved.. and still doesn't make 100% sense to me. Input will be welcome.

The next concept is the Interface Segregation Principle or ISP. The formal definition is "many client specific interfaces are better than one general purpose interface" but in layman's terms, it's much simpler. As time goes on and requirements change, our systems grow. Without careful consideration and strategy, our class hierarchy will both grow and get "messy". Methods that made sense on one class at the beginning of the project or didn't have a logical location end up in odd places. Suddenly, we end up with a painful game of Go Fish.

"Excuse me mister Project class, can you tell me who is assigned to work on you? Nope, go fish."

The most useful aspect of this principle is that – once you being to apply it – the oddities stand out. For example, when we look at this (contrived) example:

All of those methods relate to user validation and/or authentication, so they make sense together. Any object that implements the interface should be "highly coherent," but then look at this (luckily, contrived) example:

The first four methods make sense on a "Setup" interface and describe what looks like a reasonable lifecycle of a module. The last method – changeDisplayOrder – has little to do with setup and seems to relate to a View layer consideration. Something is wrong here.. or in other terms, we have a "code smell".

The final concept of SOLID is the Dependency Inversion Principle or DIP. In the computer science world, the formal definition is "Depend upon abstractions, not concretions." In the real world, it means when we have to introduce class dependencies, we should be as broad as possible in what we expect. Within web2project, part of our class structure looks like this:

Since we have uniform interfaces, instead of our controllers being wholly dependent on the CProject or CLink object, we can interact with the w2p_Core_BaseObject to do things like this:

The controller can interact with each of these objects in exactly the same ways without knowing exactly which object its using. That is powerful and makes the controller reusable all over the system.

As a side note, if you look closely at CProject and CLink with load, store, and check, you'll notice that this looks a lot like Nouns, Verbs, and Uniform Interfaces.. sound familiar?

Regardless, the SOLID principles alone aren't going to give you better OO Design. There are legitimate reasons and situations to bend or even break them but it should not be on a whim or from ignorance. On the flip side, we still have to apply our own judgement on where and how to apply them too. We need to consider what we gain and/or improve as a result. Checking off the "we support SOLID" box isn't sufficient.

About Keith Casey

This should be something about myself. I've had suggestions that it should be "useful information" but I'm not sure about that.