Reinforce the principles of cohesion and coupling as they apply to class modeling.
Cohesion and Coupling Revisited
Cohesion and coupling are measures of quality for your model. As such, they should be applied to every activity of the modeling process.
Like encapsulation, cohesion and coupling may and should be applied to every level your model, not just to individual class design.
Key to achieving High Cohesion
The key to achieving high cohesion and low coupling is defining purpose. The best way I have found to understand this concept is to think in terms of human interaction. People and organizations work best when they have a single, well-defined purpose. When the purpose is poorly defined, people have a hard time setting priorities, developing a plan of action, and coordinating unrelated tasks.
Cohesion Business Example
Companies have repeatedly demonstrated that branching into multiple areas can have extremely damaging effects on operations.
For example, I worked for NIKE when it thought it would be a good idea to expand from athletic shoes to athletic equipment.
The two seemed related, but when the business tried to adapt, people found that NIKE did not have the infrastructure to handle the new line of business. Both the new line of business and the existing footwear business took a nosedive. When NIKE dropped back to a focus on footwear only, the business recovered and grew at an unprecedented rate.
Coupling: Coupling is usually contrasted with cohesion. Low coupling often correlates with high cohesion, and vice versa.
The software quality metrics of coupling and cohesion were invented by Larry Constantine, an original developer of Structured Design who was also an early proponent of these concepts (see also SSADM). Low coupling is often a sign of a well-structured computer system and a good design, and when combined with high cohesion, supports the general goals of high readability and maintainability.
Systems, applications, components, and objects react in the same way. Actually, it is the developers who react in the same way. Development becomes increasingly complex as you attempt to put more and more functionality into the same component.
More and more code is required to track object state, juggle priorities, and manage the execution of loosely related or unrelated activities.
Refactoring for higher cohesion
Refactoring for higher cohesion and looser coupling is usually a matter reassigning responsibilities and the associated functionality.
The diagrams below will show you two examples of refactoring.
In the first example, the initial job description for a Software Developer is refactored so that the skill and tool sets in the initial definition are distributed into three distinct job classifications.
In the second example, the definitions for a security user interface and a security client are refactored so that their responsibilities are divided in such a way so as to allow the user interface to change without disturbing or even touching the logic behind it.
Initial Job Description Example 1: View the diagram below to examine the initial job description for a Software Developer.
Refactoring Revisited
In this definition the distinct skill and tool sets are distributed into three distinct classifications.
You initial reaction might be would not that be nice.
But most organizations do not have the resources to use a different person for each job description.
The point is not whether each job is assigned to a different person.
The point is that the jobs may be assigned separately or together without losing sight of the distinct responsibilities and the corresponding skills and tools. Flexibility and focus have been improved.
The result is a set of responsibilities that are easier to measure and manage
Example 2: View the diagram below to read about a refactored version of the job description for a Software Developer.
In this definition the user interface contains the screen elements needed to obtain the user input and the logic to prevent unlimited attempts.
The client application knows what database to access and how to lookup the user. Changing the security database to another database engine would require significant changes to the client application.
View the diagram below to see a refactored definition for 1) a Security User Interface and 2) Security Client Application
You can see from the examples that refactoring based on cohesion and coupling typically results in more objects that are also smaller and simpler, and consequently far more reusable.
This definition divides the responsibilities into a) user data entry and b) user access, c) the security system, and d) the database behind the security system. This approach allows the user interface to change without disturbing or even touching the logic behind it. The interface is completely ignorant of how it is being used. It merely provided fields to receive and display information. In fact the same interface could be used at many different levels through the system, e.g. application security, system security, and function level security.
The client application knows nothing about presentation or the actual validation. Its sole responsibility is to obtain valid input for the security system Validate User interface.
The security system knows how to interpret security information about a user, but not how its knowledge will be presented to the user. It does not even know where the security data is physically stored.
The security system database knows the current database and how to format the validation request in to the SQL or other language needed to get an answer from the current database. This separation of the database from the security system using an interface allows for the replacement or upgrade of the database without changes to the applications that use it as long as the interfaces remain the same.
Refactored Definition for an Interface
1) Refactored definition 2) Security Client Application 3) Security System 4) Security System Database Interface
Refactored definition
This definition divides the responsibilities into a) user data entry and b) user access, c) the security system, and d) the database behind the security system. This approach allows the user interface to change without disturbing or even touching the logic behind it. The interface is completely ignorant of how it is being used.
It merely provided fields to receive and display information. In fact the same interface could be used at many different levels through the system, e.g. application security, system security, and function level security.
Security Client Application
The client application knows nothing about presentation or the actual validation. Its sole responsibility is to obtain valid input for the security system "Validate User" interface.
Security System
The security system knows how to interpret security information about a user, but not how its knowledge will be presented to the user.
It does not even know where the security data is physically stored.
Security System Database Interface
The security system database knows the current database and how to format the validation request in to the SQL or other language needed to get an answer from the current database. This separation of the database from the security system using an interface allows for the replacement or upgrade of the database without changes to the applications that use it as long as the interfaces remain the same.
Decomposing and Redistributing the Statement Method
The obvious first target of my attention is the overly long statement method. When I look at a long method,
I am looking to decompose the method into smaller pieces. Smaller pieces of code tend to make things more manageable.
They are easier to work with and move around. The first phase of the refactorings in this module show how I split up the long method and move the pieces to better classes. My aim is to make it easier to write an HTML statement method with much less duplication of code. My first step is to find a logical clump of code and use Extract Method. An obvious piece here is the switch statement.
This looks like it would make a good chunk to extract into its own method. When I extract a method, as in any refactoring,
I need to know what can go wrong. If I do the extraction badly, I could introduce a bug into the program. So before I do the refactoring I need to figure out how to do it safely. I've done this refactoring a few times before, so I have written down the safe steps in the catalog.
First I need to look in the fragment for any variables that are local in scope to the method we are looking at, the local variables and parameters.
This segment of code uses two: 1) each and 2) thisAmount. Of these each is not modified by the code but thisAmount is modified. Any nonmodified variable I can pass in as a parameter. Modified variables need more care. If there is only
one, I can return it.
The temp is initialized to 0 each time around the loop and is not altered until the switch gets to it. So I can just assign the result.
Cohesion Coupling - Exercise
Click the Exercise link below to refactor examples taken from the course project to improve cohesion and reduce coupling. Cohesion Coupling - Exercise