cohesion

What Is Cohesion?

 

Yesterday we examined Coupling. Today we’ll look at Coupling’s alter-ego: Cohesion.

You’ve probably heard that code with low Cohesion is likely to be problematic, while highly cohesive systems are easier to maintain.

It’s true; but why? What is Cohesion?

I like this definition:

A class has high Cohesion if it contains methods and data that ‘naturally belong together’.

Conversely, a class has low Cohesion if the methods and data don’t fit well together.

Unfortunately, this definition is a bit wishy-washy; what does ‘naturally belongs together‘ actually mean?

OK, time for a couple of examples.

Firstly, say, we have a Customer class in an eCommerce system. Customer has the following methods:

  • CalcDeliveryRoute()
  • PrintOrderReport()
  • Save()

Do these look like they belong together? No, they don’t. The responsibilities of the three methods vary wildly: 

  • Programmers from the IT department are responsible for data persistence. They change the implementation of the Save() method.
  • PrintOrderReport() is an administrative function. The Accounting department uses it to track large customer orders. Accountants are requesting modifications to this report. 
  • Finally, Operations and Logistics drive changes to CalcDeliveryRoute()

Let’s get more precise with our definition of Cohesion. Robert C. Martin (aka Uncle Bob) has restated the Single Responsibility Principle, which is all about Cohesion, as: 

“A module (or class) should be responsible to one and only one actor.”

Actor‘ is a term from Unified Modelling Language (UML) meaning ‘a distinct group of system users’. 

Is our Customer class cohesive? No, since three separate actors may request changes to it: 

  • Logistics for CalcDeliveryRoute()
  • the Accounting department for PrintOrderReport(), and 
  • IT to the Save() method.

OK, what about an example of a cohesive class? Class ShoppingCart in the same eCommerce system has these methods and getter properties:

  • Add()
  • Remove()
  • Clear()
  • Total
  • Contents

All five behaviours manage merely the contents of ShoppingCart. A single ‘actor’ would request changes to the cart’s operations. ShoppingCart is highly cohesive.

Finally, it is worth noting that we developers can reduce Cohesion even if all existing methods and data structures reside inside the one class. How would this happen? Simple—by not putting a new behaviour onto the class that it naturally belongs to. 

To illustrate this point, we’ll continue with the ShoppingCart example. Let’s say new legislation requires eCommerce websites to display the GST amount pre-checkout.

Programatically, one way to a high Cohesion implementation would be to put a GST or GstAmount getter property on the ShoppingCart class.  

Unfortunately, the developer didn’t realise that the GST calculation depends on a fixed GST rate and ShoppingCart.Total and can therefore be encapsulated in ShoppingCart. No, they decided to implement GST calculations outside of ShoppingCart. In so doing, the developer has unwittingly dealt the eCommerce system a blow—Cohesion is now lower. This seemingly small mistake, left unchecked, will see us having code like this littering the application:

  var gst = cart.Total * GST_RATE; 

or even

  var gstAmt = cart.Total * 0.15;

while the more cohesive outcome might have looked like this:

var subtotal = cart.Subtotal;   // before GST
var gst = cart.GstAmount;       // GST calculated inside ShoppingCart
var total = cart.Total;         // Subtotal + GstAmount

Carefully consider where you place behaviour—small mistakes today may blow up into maintainability headaches in the future.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply