Feeds

Rethink code cohesion

Emergent Design: time to relate

Website security in corporate America

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.

Choosing a cloud hosting partner with confidence

More from The Register

next story
'Windows 9' LEAK: Microsoft's playing catchup with Linux
Multiple desktops and live tiles in restored Start button star in new vids
Not appy with your Chromebook? Well now it can run Android apps
Google offers beta of tricky OS-inside-OS tech
New 'Cosmos' browser surfs the net by TXT alone
No data plan? No WiFi? No worries ... except sluggish download speed
SUSE Linux owner Attachmate gobbled by Micro Focus for $2.3bn
Merger will lead to mainframe and COBOL powerhouse
iOS 8 release: WebGL now runs everywhere. Hurrah for 3D graphics!
HTML 5's pretty neat ... when your browser supports it
Greater dev access to iOS 8 will put us AT RISK from HACKERS
Knocking holes in Apple's walled garden could backfire, says securo-chap
NHS grows a NoSQL backbone and rips out its Oracle Spine
Open source? In the government? Ha ha! What, wait ...?
Google extends app refund window to two hours
You now have 120 minutes to finish that game instead of 15
Intel: Hey, enterprises, drop everything and DO HADOOP
Big Data analytics projected to run on more servers than any other app
prev story

Whitepapers

Providing a secure and efficient Helpdesk
A single remote control platform for user support is be key to providing an efficient helpdesk. Retain full control over the way in which screen and keystroke data is transmitted.
Saudi Petroleum chooses Tegile storage solution
A storage solution that addresses company growth and performance for business-critical applications of caseware archive and search along with other key operational systems.
Security and trust: The backbone of doing business over the internet
Explores the current state of website security and the contributions Symantec is making to help organizations protect critical data and build trust with customers.
Reg Reader Research: SaaS based Email and Office Productivity Tools
Read this Reg reader report which provides advice and guidance for SMBs towards the use of SaaS based email and Office productivity tools.
Security for virtualized datacentres
Legacy security solutions are inefficient due to the architectural differences between physical and virtual environments.