Feeds

Rethink code cohesion

Emergent Design: time to relate

The essential guide to IT transformation

The methods reverseCharacters() and isMightyMouse() are easy to name because they each do a single, identifiable thing. It also helps with debugging. If the characters are not reversing properly, I know exactly where to look to find the bug, because the responsibility for doing this is clearly assigned to the properly named method, and only that method.

Cohesion of perspective level

Another aspect of cohesion you should be aware of is the level of perspective at which a method operates. Put simply, methods tend to accomplish their functionality by either of the following:

  • Code logic directly in the method
  • Calling other methods

The preceding process() method has a little bit of logic in it, but it is purely for sequencing the other methods and organizing the results of their actions. Mostly, process() calls reverseCharacters() and isMightyMouse(), where the actual work is done. This aggregation of behavior that process() does is at a level of perspective we call specification.

Levels of perspective

In UML Distilled: A Brief Guide to the Standard Object Modeling Language, Martin Fowler refers to the levels of perspective that Steve Cook and John Daniels identified in their book Designing Object Systems. The three types of perspective are conceptual, specification, and implementation.

  • The conceptual perspective deals with the system objects, which ideally represent entities in the problem domain I am writing for. If I am designing an application for a bank, these might be account, transaction, statement, customer, and the like.
  • Specification means the public methods that form the interface of each object, but also the private methods to which they are delegated (see the example code on this page). So, process(), being the only public method of Application, is decidedly a specification-level issue, but from the point of view of process(), so are reverseCharacters() and isMightyMouse(). This is because process() is concerned with what they do (how they are called, what they return), but not how they do it.
  • Implementation is concerned with the code that does the actual work. Nice that we still have that, eh?

The reverseCharacters() and isMightyMouse() methods are implementation-level methods; they have the code that does the dirty work.

It would be overstating things to suggest that I always write methods that are purely at one level of perspective or another-even here, process() has a little bit of logic in it, not just a series of method calls. But my goal is to be as cohesive as possible in terms of levels of perspective, mostly because it makes the code easier to read and understand.

It would not be overstating things to suggest that I always strive to write methods that are cohesive in the general sense, that they contain code that is all about the same issue or purpose. When I find poorly cohesive methods, I am going to change them, every time, because I know that method cohesion is a principle that will help me create maintainable code, and that is something I want for myself, let alone my team and my customer.

Class cohesion

Classes themselves also need to be cohesive. The readability, maintenance, and clarity issues that, in part, drive the need for method cohesion also motivate class cohesion.

In addition, we know we want our classes to define objects that are responsible for themselves, that are well-understood entities in the problem domain. A typical mistake that developers who are new to object orientation make is to define their classes in terms of the software itself, rather than in terms of the problem being solved. For instance, consider the following code:


public class BankingSystem {
  // No "method guts" are provided; this is just a 
  // conceptual example
  public void addCustomer(String cName, String cAddress, 
                          String accountNumber, 
                          double balance) {}
  public void removeCustomer(String accountNumber) {}
  public double creditAccount(String accountNumber, 
                              double creditAmount) {}
  public double debitAccount(String accountNumber, 
                             double debitAmount) {}
  public boolean checkSufficientFunds(String accountNumber, 
                                      double checkAmount) {}
  public void sendStatement(String accountNumber) {}
  public boolean qualifiesForFreeToaster(String accountNumber){}
  public boolean transferFunds(String fromAccount, 
                               String toAccount, 
                               double transferAmount) {}
}

It is easy to imagine the thought process that leads to code like this: "I am writing a banking system, and so I will name the class for what it is, a BankingSystem. What does a banking system do? Well, I need to be able to add and remove customers, manage their accounts by adding to them and withdrawing from them," and so on.

Boost IT visibility and business value

More from The Register

next story
Munich considers dumping Linux for ... GULP ... Windows!
Give a penguinista a hug, the Outlook's not good for open source's poster child
The Return of BSOD: Does ANYONE trust Microsoft patches?
Sysadmins, you're either fighting fires or seen as incompetents now
Intel's Raspberry Pi rival Galileo can now run Windows
Behold the Internet of Things. Wintel Things
Microsoft cries UNINSTALL in the wake of Blue Screens of Death™
Cache crash causes contained choloric calamity
Eat up Martha! Microsoft slings handwriting recog into OneNote on Android
Freehand input on non-Windows kit for the first time
Time to move away from Windows 7 ... whoa, whoa, who said anything about Windows 8?
Start migrating now to avoid another XPocalypse – Gartner
You'll find Yoda at the back of every IT conference
The piss always taking is he. Bastard the.
prev story

Whitepapers

5 things you didn’t know about cloud backup
IT departments are embracing cloud backup, but there’s a lot you need to know before choosing a service provider. Learn all the critical things you need to know.
Implementing global e-invoicing with guaranteed legal certainty
Explaining the role local tax compliance plays in successful supply chain management and e-business and how leading global brands are addressing this.
Build a business case: developing custom apps
Learn how to maximize the value of custom applications by accelerating and simplifying their development.
Rethinking backup and recovery in the modern data center
Combining intelligence, operational analytics, and automation to enable efficient, data-driven IT organizations using the HP ABR approach.
Next gen security for virtualised datacentres
Legacy security solutions are inefficient due to the architectural differences between physical and virtual environments.