April 29th, 2006
Cohesion tells us how narrowly defined an object is. An object with high cohesion is defined for one purpose and it only performs that purpose. An object with low cohesion tends to try to do a lot of different things. Cohesion also tells us if too many objects are attempting to do the same thing. So, if I have a system of objects to implement my NetRunner game and every card has a unique class with a rendering method and that method is nearly identical in all classes, then that system has low cohesion because too many objects are doing the same thing.
- OOAD 101 Lesson 1: What is an object and what is object-oriented?
- OOAD 101 Lesson 2: Coupling and cohesion trump reuse and inheritance
- OOAD 101 Lesson 3: Understanding Coupling
- OOAD 101 Lesson 4: Understanding cohesion
The very difficult question is how does one objectively measure cohesion? For example, take the AccountReceivables class shown here:
I can tell you that the cohesion is pretty low, but why? The industry has done a poor job at providing measures of cohesion. Just look at the depressing conclusions of this abstract from an IEEE paper on measures of cohesion:
It is a little over ten years since Chidamber and Kemerer’s object-oriented (OO) metric suite which included the Lack of Cohesion Of Methods (LCOM) metric was first proposed . Despite considerable effort both theoretically and empirically since then, the software engineering community is still no nearer finding a generally accepted definition or measure of OO cohesion. Yet, achieving highly cohesive software is a cornerstone of software comprehension and hence, maintainability. In this paper, we suggest a number of suppositions as to why a definition has eluded (and we feel will continue to elude) us. We support these suppositions with empirical evidence from three large C++ systems and a cohesion metric based on the parameters of the class methods; we also draw from other related work. Two major conclusions emerge from the study. Firstly, any sensible cohesion metric does at least provide insight into the features of the systems being analysed. Secondly however, and less reassuringly, the deeper the investigative search for a definitive measure of cohesion, the more problematic its understanding becomes; this casts serious doubt on the use of cohesion as a meaningful feature of object-orientation and its viability as a tool for software comprehension.
Most engineers essentially eyeball it. The more experienced engineers, mostly through instinct, know exactly what to refactor to fix the design issue, but the rest are left to struggle.
In lesson 2, I stated my position that OOAD should be done via examing coupling and cohesion and creating refactoring and design plans based on that analysis. In lesson 3, I provided an objective measure of coupling. To continue on this path, we must have an objective measure of cohesion. And since the industry has not provided one, through the years I have had to develop one myself. The method is called cohesion grid analysis.
The keys is to classify behavior into primary dimensions. For the systems we write today, there are three primary dimesions:
- Architecture Categories: This is a list of the primary architecture categories For example, if the system architecture was MVC, then the there would be three items in this dimension (model, view, controller).
- Design Pattern Category: These are the categories from the Design Patterns book I mentioned in Lesson 1. The categories are creational, structural, and behavioral.
- Domain: This is a list of the primary types of objects in the application domain. For example, in the NetRunner game this would include the card types like Operation Cards, Agendas, Ice, etc.
To perform the analyis, construct a grid of two of the three dimensions. When I focus on infrastructure, the grid is of architecture and design pattern categories. When I am focusing on application behavior, it is typically domain and architecture.
So going back to our AccountsReceivable class, how do we measure its cohesion? Lets look at an “architecture by patterns grid”. To do that, though, we need to know what our architecture categories are. Say we based our architecture off of MVC and came up with the following categories:
- Game Renderer: These component renders the game board.
- Game Logic: These components execute the game logic.
- Game Model: These components represent the game board objects (such as cards, bits, data forts, etc.).
Given that, then our grid will be:
The more grids an object fills, the lower its cohesion. Furthermore, the more objects in the same grid, the lower the system cohesion.
Here is the grid analysis of the AccountsReceivable:
To fill it in we asked the following questions:
- Is the object creating game rendering objects? no
- Is the object used to represent the game rendering layout? no
- Is the object used to perform the rendering operation? yes
- Is the object used to create game logic objects? no
- Is the object used to represent the game logic state? no
- Is the object used to perform game logic operations? yes (note the play method would have to do both game logic moves, such as resolving by yielding control to the next player AND game object behavior such as adding 9 bits to the bit pool).
- Is the object used to create game model objects? no
- Is the object used to represent game object state? yes
- Is the object used to perform game object operations? yes
So the cohesion of this object is (number of grids checked/num total grids) or 4/9. We can now use this analysis to create a refactoring plan. We can set the goal of the plan to upgrade the cohesion to 3/9. And we may decide to do that by altering the design such that our AccountsRecievable object (which is really a game model object) no longer be responsible for the behavior of game logic.
Entry Filed under: Software Development