CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jean-Paul S. Boodhoo

Develop With Passion

One Class To Rule Them All

One of the things that has really been hitting me in the face lately is the importance of adhering as closely as possible to the Single Responsibility Principle.

SRP simply states that:

 “A class should have only one reason to change”.

On the surface this can be a very simple principle to grok, the reality is that ensuring that a class is doing only one thing can be a skill that developers will continue to evolve over the course of their career.

Most people have come across the term cohesion, which describes how well the different behaviors of an object work together to accomplish a common task. Cohesion and SRP are one in the same. When looking at any arbitrary class in your codebase, it can often be very easy to determine whether a class is breaking SRP:

  • A UI that performs direct DB manipulation as well as validation of data entry.
  • “Bucket” utility classes that do everything from sending email to performing string manipulation.

Each extra responsibility you add to a class gives it another reason to change. Instead of composing highly cohesive objects each with a discrete responsibility that can be orchestrated together to accomplish a common task, many people opt for the behavior bloat that often can result when the time to factor out discrete behaviors has been skipped.

In my experience over the last couple of years, when you have someone sitting beside you, making you question strongly as to whether a particular piece of behavior is being placed correctly, it will almost always help drive out more cohesive objects that are focused around a single responsibility. Not only does this make them more testable. It also shields the rest of the system from any changes that may come along in that component, as its set of behaviors are fixed around one particular piece of functionality.

Single Responsibility is what drives us to create object oriented systems, that also leverage layering schemes, to ensure that ,even at the logical layering level, a “layer” as a whole is adhering to SRP. This means that when I create a “Presentation” layer, the layer and any of its accompanying components are focused around presentation related behavior. A DAL will be focused solely around providing data access services to the rest of the application. The domain model will be focused around encapsulating the business rules, and the heart of the system.

When you look at your codebases, ask yourself some hard questions and see whether or not you are placing too much responsibility on one object, component, or layer. By striving to follow this principle more diligently you will foster and encourage practices that lead to more loosely coupled, highly cohesive systems. Ultimately, all of the principles and practices of good OO software design come back in one way or another to trying to follow this principle as closely as possible!!


Published Apr 09 2007, 06:18 AM by bitwisejp
Filed under:

Comments

Eric Wise said:

I think as far as SRP is concerned you have to use the 90/10 rule.  90% of the time it's inappropriate and raises complexity.  The other 10% of the time it's actually kind of useful as an organizational tool.

I have had a bucket utility class in my .net 2.0 web projects for some time now.  It only has a few methods in it, but they're useful generalizations:

1. GetFriendlyDate() returns empty string if datetime.minvalue.

2. SetListItemByValue() given a dropdownlist and a string value, selects the listitem if found.

3. SetListItemByText() same as above, but checks text instead.

etc.  All-in-all there's less than 10 in here, I suppose I could break them up into ComboBoxHelper, DateHelper, etc but other coders seem to find it more intuitive when they're doing repeated web formatting stuff to go to a utlities style class.

I would like to know what you do with these little tidbit helper functions and the organizational logic behind it.

# April 9, 2007 9:53 AM

bitwisejp said:

@ewise,

I have to disagree. The 90/10 rule with regards to SRP is what leads people down the path of procedural programs that masquerade as OO programs. One of the reasons that the "complexity" may increase is that as a developer/designer you now need to prove why a method just belongs in a bucket as opposed to being factored out into a behavior on a first class object.

I am not saying that utility classes don't exist. How many times have we written string utilities, form utilities etc. These do not go away. What I am saying is the need for them becomes significantly decreased when you are trying to think in terms of behaviors around a certain logical component.

All of the three examples that you mentioned to me, I usually handle in a completely object oriented way. Is this the way that you have to do it, no. Is it the destination I arrived at incrementally using tests as a means to drive out the objects, yes. By creating adapters for my listboxes that my presenter can manipulate I remove the need for utility methods that work against plain old list boxes. By introducing a NullableDateTime, I remove the need for magic numbers (DateTime.minvalue) and can ask the date object to render itself, and it will take care of what to do when its internal value is null.

When I do resort to the "utility" classes, I try to keep them as cohesive as possible also. Which means rather than having a class called ProjectUtilis, I create utility classes that revolve around one specific area of functionality (StringUtility).

# April 9, 2007 2:14 PM

Jeffrey Palermo said:

@Eric,

I hadn't given it much thought, but for the project that I'm currently finishing up (8 months, 80,000 lines of code), I don't have any "utility" classes or function classes.  If I have a class with no state (no private fields), it's a logical service and implements an interface which means something in the system.  

I admit that 3 years ago I used plenty of utility classes.  I've experienced the mindshift.

# April 9, 2007 4:35 PM

Ayende Rahien said:

I do make use of several utility classes, but I tend to divide them by functionality.

Jeffery, how would you have this scenario:

public void QueueToExecute(ICommand command)

{

  Validation.NotNull(command, "command");

  // do stuff

}

Where the util class is Validation

# April 9, 2007 5:36 PM

Jeffrey Palermo said:

@Ayende,

I have to admit that JP's advice was critical in my tweaking my general approach to logical services and managing dependencies.

Instead of thinking of the Validation class as a utility, I would think of it as a logical service within my application.  It has no state, just behavior.  Since you don't have a return value, I'll assume that you throw an exception and _never_ expect command to be null.  Being null would result is a very unstable system.  With that assumption, I'd defind an IValidation interface with NotNull().

It wouldn't be reasonable to have many, many classes all require an IValidation instance in order to function, so I'd make Validation a static class that uses my IoC container, StructureMap to locate a default implementation of IValidation.  At test time, I can fake out the interface to test my code.  Checking for null is pretty straight-forward, but imagining other validation requirements isn't difficult.

Allow me to follow up by saying that I don't check for nulls in my code except where it may be a valid system condition.  If someone passes null to my code, they will get exactly what they deserve (borrowed from Ward Cunningham).  Otherwise, I'd have check-for-null validation literally in every class in my application, and I don't see that value proposition of that.

Another example of my above scenario is SystemClock.  Instead of this being a utility class for SystemClock.GetCurrentDateTime(), it's a static class that uses my ISystemClock interface.  I can mock the interface to test code that relies on behavior for when it's a weekday vs. a weekend.

# April 10, 2007 10:28 AM

Ayende Rahien said:

> Another example of my above scenario is SystemClock.  Instead of this being a utility class for SystemClock.GetCurrentDateTime(), it's a static class that uses my ISystemClock interface.  I can mock the interface to test code that relies on behavior for when it's a weekday vs. a weekend.

SystemClock is an interesting idea, I use it quite a bit, because I work on systems where time is a variable as well.

You really want to be able to see the results of calculations made a week ago, or a week from now.

# April 10, 2007 6:00 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!

Our Sponsors