Friday, January 09, 2009

The Toilet Paper (Installment 25): Single-Responsibility Principle (SOLID, part 2)

A class should have exactly one reason to change

The Single-Responsibility Principle (SRP) helps you create classes that are resilient in the face of requirements changes. Put more simply, the SRP guides you in creating individual classes that are highly focused on a single implementation concept, so that each individual class is less likely to be affected by each requirements change. Each class is very limited in what it knows how to do and what it knows about, so an individual requirement change is less likely to affect that class. As a result, classes that change less often and accumulate less code are less likely to accumulate bugs as well. They can be tested thoroughly and raise the overall quality of your application.

Let's look at an example. Suppose we have a Product class that models information and behavior associated with some widget we're selling. It might look something like this:
public class Product {
public String Name { get; private set; }
public String Sku { get; private set; }
public Money ShippingCharges(Destination dest) {…}
public Money CalculateDiscount(Contract contract){…}
}
Assuming that the implementations of how to calculate shipping charges and discounts are inside both of those methods, this class clearly has multiple responsibilities – three, in fact. First, it models a product, which has properties, shipping charges and discounts. But this class also charges shipping and calculates discounts. This may not seem that important, but it means that this particular class is harder to understand and changes more often than would otherwise be necessary. The biggest shortcoming, however, is that the logic for these calculations is hidden inside the Product class, making these non-trivial bits of code harder to find and harder to test independently.

To solve this, refactor this class so that it delegates the responsibility of how doing the calculations are done to two other, more specialized classes, such as ShippingChargeCalculator and PriceDiscounter. That would leave you with three classes, each of which has one reason to change, decreasing the complexity of the system and increasing maintainability, flexibility, and testability.

You can find much more on the SRP on Google. Try searching for "ActiveRecord Single-Responsibility Principle" for hours of enjoyment!

No comments: