These slides are designed to accompany Software Engineering: A Practitioner’s Approach, 7/ e (McGraw-Hill, 2009) Slides copyright 2009 by Roger Pressman.! Software Engineering Knowledge!! You often hear people say that software development knowledge has a 3-year half-life: half of what you need to know today will be obsolete within 3 years. Software engineering methods rely on a set of basic principles that govern each area of the technology and include modeling activities and other descriptive techniques. Software engineering tools provide automated or semi-automated support for the. Coupling and Cohesion Module Coupling. In software engineering, the coupling is the degree of interdependence between software modules. Two modules that are tightly coupled are strongly dependent on each other. However, two modules that are loosely coupled are not dependent on each other. Uncoupled modules have no interdependence at all within. High cohesion is generally used in support of low coupling. High cohesion means that the responsibilities of a given element are strongly related and highly focused. Breaking programs into classes and subsystems is an example of activities that increase the cohesive properties of a system.
Software architects and programmers love low coupling. What is coupling? Why is coupling important? Let’s get started.
You will learn
- What is coupling?
- What are common examples of coupling in software?
- How can we reduce the amount of coupling between classes, between components, and the like?
Free Courses - Learn in 10 Steps
Software Design
This is the fifth article in a series of articles on Software Design:
Example of Couping
Let’s start with an example.
Let’s say a friend of mine is developing a Java component, in the form of a JAR file, for me to use. However, there is an implicit constraint imposed here - I need to use Java (or a JVM Based language) to use the utility JAR file! In other words, developing the component as a Java JAR has coupled me to using Java as well. To break free, I need to decouple.
How to Decouple? An Example:
Instead of providing me with a JAR, I could ask my friend to create a web service interface for me to access the same functionality. The concept would look something like this:
The web service is created around the JAR, and can be accessed from a Java, a PHP, or a .NET application. We can use any kind of application to invoke the web service.
This implies we have effectively decoupled from the underlying technology of the component. We are no longer affected by the fact that the component was developed in Java.
Another Example for Low Coupling - Spring Framework
Spring Framework has a highly modular structure:
Suppose we want to use a specific module from this framework; for instance, the Spring JDBC module.
What would happen if Spring tells you that you can only use Spring JDBC if you also use the Beans and Context modules?
You would probably not use it at all, because it introduces additional dependencies such as configuration etc.
Spring does get this right; it does not force you to use Beans or Context along with JDBC. In other words, Spring modules are not coupled with the other ones.
Class-level coupling - The Order
class
Let’s now go one level deeper. Let’s look at Coupling at the level of classes.
Let’s look at a simple shopping cart example:
You would observe that orderTotalPrice()
knows the internal details of the ShoppingCart
and ShoppingCartEntry
classes:
- It accesses the
items
field ofShoppingCart
directly - It accesses the
price
andquantity
fields ofShoppingCartEntry
, also directly
Scenario : Try and imagine a situation where we change the name of the price
field of ShoppingCartEntry
, to something else.
Approach : Code within orderTotalPrice()
would also need to change.
If you change the type of the items
array (possibly to a list) within ShoppingCart
, that would also lead to a change within orderTotalPrice()
.
Order
class is tightly coupled to the ShoppingCart
and ShoppingCartEntry
classes.
How do we decouple them?
Decoupling the Order
class Example
Here is one way of achieving this:
Note the following points:
- Instead of making the
price
andquantity
fields accessible,ShoppingCartEntry
now makes a method namedgetTotalPrice()
available toCartContents
. - The
CartContents
class does something very similar, by also providing agetTotalPrice()
method forOrder
to use. - The
Order
class now only invokes thegetTotalPrice()
methhod exposed byCartContents
, to compute the total cart value intotalPrice()
.
Now,
- If the
price
field inShoppingCartEntry
has its name changed, onlygetTotalPrice()
within the same class would be affected - If the type of
items
withinCartContents
is changed from an array to a list, again only theCartContents
getTotalPrice()
method needs to be altered. - The code within
Order
is not affected by either of these changes at all.
We have now completely decoupled Order
from both ShoppingCartEntry
and CartContents
.
Another Coupling Example with Spring Framework
Consider the following body of code:
You would notice that the BinarySearchImpl
class is directly dependent on the BubbleSortAlgorithm
class. If we need to change the actual sort algorithm, to use quicksort for instance, then a lot of code within BinarySearchImpl
needs to change.
We can solve this issue by making use of interfaces. Here is how our modified code would look like:
If you use the Spring framework, you could use the @Autowired
annotation with the BinarySearchImpl
class, to automatically fetch an implementation of an available sort algorithm:
What we have achieved here is reduce the coupling between BinarySeacrhImpl
and a specific sort algorithm.
A Practical Viewpoint of Coupling
A good way of thinking about coupling, is if you change the inner details of a class or a component, do you need to make changes elsewhere as well?
Such dependencies are not desirable. If you intend to reuse code from one place to another, the related dependencies should be as few as possible.
Coupling can occur at multiple levels in an application:
- Class-level
- API-level
- Component-level
Let’s look at an example of coupling at component level:
Component-Level Coupling
Consider the following organization of an enterprise web application:
If the Security component were coupled with the Logging component, then wherever we need Security, we would also need to access Logging. That’s not good.
Coupling With Layers
Let’s look at an example of a layered web application:
It is organized into these three layers. Also assume that from the Web layer Controller, I need to call multiple methods from the Business layer. Let’s say five different methods need to be called for a single such requirement. This is a clear case of coupling.
A very effective way to avoid such layer-to-layer coupling is to use the Facade Pattern. You can create a Facade component on top of the Business layer, that manages calls to these five methods. The web layer can then make do with calling a single method from the Facade component.
All in all, decoupling makes the code more reusable and testable.
Do check out our video on this:
Summary
In this article, we looked at the concept of coupling at multiple levels: at the class, the component, the API and the layer level. We also looked at how to get around this factor through decoupling, at each of these levels. We identified the key question to ask about coupling: “If something changes at a particular place, would other things need to change as well? And If I use something, would I be forced to use something else as well?”
General Responsibility Assignment Software Patterns (or Principles), abbreviated GRASP, is a set of 'nine fundamental principles in object design and responsibility assignment'[1]:6 first published by Craig Larman in his 1997[citation needed] book Applying UML and Patterns.
The different patterns and principles used in GRASP are controller, creator, indirection, information expert, low coupling, high cohesion, polymorphism, protected variations, and pure fabrication.[2] All these patterns solve some software problem common to many software development projects. These techniques have not been invented to create new ways of working, but to better document and standardize old, tried-and-tested programming principles in object-oriented design.
Larman states that 'the critical design tool for software development is a mind well educated in design principles. It is not UML or any other technology.'[3]:272 Thus, the GRASP principles are really a mental toolset, a learning aid to help in the design of object-oriented software.
Patterns[edit]
In object-oriented design, a pattern is a named description of a problem and solution that can be applied in new contexts; ideally, a pattern advises us on how to apply its solution in varying circumstances and considers the forces and trade-offs. Many patterns, given a specific category of problem, guide the assignment of responsibilities to objects.
Information expert[edit]
Problem: What is a basic principle by which to assign responsibilities to objects?
Solution: Assign responsibility to the class that has the information needed to fulfill it.
Information expert (also expert or the expert principle) is a principle used to determine where to delegate responsibilities such as methods, computed fields, and so on.
Using the principle of information expert, a general approach to assigning responsibilities is to look at a given responsibility, determine the information needed to fulfill it, and then determine where that information is stored.
This will lead to placing the responsibility on the class with the most information required to fulfill it.[3]:17:11
Related Pattern or Principle: Low Coupling, High Cohesion
Creator[edit]
The creation of objects is one of the most common activities in an object-oriented system. Which class is responsible for creating objects is a fundamental property of the relationship between objects of particular classes.
Problem: Who creates object A?
Solution: In general, Assign class B
the responsibility to create object A
if one, or preferably more, of the following apply:
- Instances of
B
contain or compositely aggregate instances ofA
- Instances of
B
record instances ofA
- Instances of
B
closely use instances ofA
- Instances of
B
have the initializing information for instances ofA
and pass it on creation.[3]:16:16.7
Related Pattern or Principle: Low Coupling, Factory pattern
Coupling And Cohesion Software Engineering
Controller[edit]
The controller pattern assigns the responsibility of dealing with system events to a non-UI class that represents the overall system or a use case scenario. A controller object is a non-user interface object responsible for receiving or handling a system event.
Problem: Who should be responsible for handling an input system event?
Solution: A use case controller should be used to deal with all system events of a use case, and may be used for more than one use case. For instance, for the use cases Create User and Delete User, one can have a single class called UserController, instead of two separate use case controllers.
The controller is defined as the first object beyond the UI layer that receives and coordinates ('controls') a system operation. The controller should delegate the work that needs to be done to other objects; it coordinates or controls the activity. It should not do much work itself. The GRASP Controller can be thought of as being a part of the application/service layer[4] (assuming that the application has made an explicit distinction between the application/service layer and the domain layer) in an object-oriented system with common layers in an information system logical architecture.
Related Pattern or Principle: Command, Facade, Layers, Pure Fabrication
Indirection[edit]
The indirection pattern supports low coupling and reuses potential between two elements by assigning the responsibility of mediation between them to an intermediate object. An example of this is the introduction of a controller component for mediation between data (model) and its representation (view) in the model-view control pattern. This ensures that coupling between them remains low.
Problem: Where to assign responsibility, to avoid direct coupling between two (or more) things? How to de-couple objects so that low coupling is supported and reuse potential remains higher?
Solution: Assign the responsibility to an intermediate object to mediate between other components or services so that they are not directly coupled.
The intermediary creates an indirection between the other components.
Low coupling[edit]
Coupling And Cohesion
Coupling is a measure of how strongly one element is connected to, has knowledge of, or relies on other elements. Low coupling is an evaluative pattern that dictates how to assign responsibilities for the following benefits:
- lower dependency between the classes,
- change in one class having a lower impact on other classes,
- higher reuse potential.
High cohesion[edit]
High cohesion is an evaluative pattern that attempts to keep objects appropriately focused, manageable and understandable. High cohesion is generally used in support of low coupling. High cohesion means that the responsibilities of a given element are strongly related and highly focused. Breaking programs into classes and subsystems is an example of activities that increase the cohesive properties of a system. Alternatively, low cohesion is a situation in which a given element has too many unrelated responsibilities. Elements with low cohesion often suffer from being hard to comprehend, reuse, maintain and change.[3]:314–315</ref>
Polymorphism[edit]
According to the polymorphism principle, responsibility for defining the variation of behaviors based on type is assigned to the type for which this variation happens. This is achieved using polymorphic operations. The user of the type should use polymorphic operations instead of explicit branching based on type.
Problem: How to handle alternatives based on type? How to create pluggable software components?
Solution: When related alternatives or behaviors vary by type (class), assign responsibility for the behavior—using polymorphic operations—to the types for which the behavior varies. (Polymorphism has several related meanings. In this context, it means 'giving the same name to services in different objects'.)
Protected variations[edit]
The protected variations pattern protects elements from the variations on other elements (objects, systems, subsystems) by wrapping the focus of instability with an interface and using polymorphism to create various implementations of this interface.
Problem: How to design objects, subsystems, and systems so that the variations or instability in these elements does not have an undesirable impact on other elements?
Solution: Identify points of predicted variation or instability; assign responsibilities to create a stable interface around them.
Pure fabrication[edit]
A pure fabrication is a class that does not represent a concept in the problem domain, specially made up to achieve low coupling, high cohesion, and the reuse potential thereof derived (when a solution presented by the information expert pattern does not). This kind of class is called a 'service' in domain-driven design.
Related Patterns and Principles• Low Coupling.• High Cohesion.
See also[edit]
References[edit]
- ^Craig Larman (2001). Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and the Unified Process(PDF) (2nd ed.). Prentice Hall. ISBN0-13-092569-1.
- ^Muhammad Umair (2018-02-26). 'SOLID, GRASP, and Other Basic Principles of Object-Oriented Design'. DZone.
- ^ abcdCraig Larman (2004). Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development (3rd ed.). Pearson. ISBN978-0131489066.
- ^'Application Layer like business facade?'. Yahoo! Groups (domaindrivendesign). Retrieved 2010-07-15.