14,390,263 members

# Cohesion and Coupling: Principles of Orthogonal, Scalable Design

Rate this:
17 Mar 2017CPOL
Cohesion and coupling: Principles of orthogonal, scalable design

The sections below are about enabling an application to evolve and be maintained with minimal risks and effort. It is not easy to interpret a lot of complex information derived from the organizational structure of a source code. By separating concerns (link), we minimize complexity. Different responsibilities are maintained in different places. Separation of concerns is about dividing to conquer, about modularity, encapsulation, defining layers, about individual pieces of code that are developed and maintained individually and independently.

Instead of worrying about different sections of the code, we need to focus on localized changes in the right (and expected) places.

## Orthogonality

In geometry, Euclidean vectors are orthogonal if they are perpendicular, i.e., form a right angle. Even if these vectors grow infinitely in space, they will never cross. Well designed software are orthogonal. Their components can grow or be modified without affecting other components.

Orthogonal design is built upon two pillars: cohesion and coupling. These concepts form the basis of software design. However, although well known, they are constantly ignored or misunderstood.

## Coupling

Coupling (also known as Dependency) is a degree to which one program unit (e.g., a class, module, subsystem) relies on other units. It is a measure of strength of the interconnections between elements, which should be minimized.

We want elements that are independent of each other. In other words, we want to develop applications that exhibit loose (rather than tight) coupling.

However, since parts need to communicate among themselves, we do not have completely independent modules. As interconnections grow between the parties involved, one module will need more information about the other, increasing the dependency between them.

The code below is a sample of content coupling. It occurs when one component depends (by modifying or relying) on internal data or behavior of another component. Changing elementary structure or behavior of one component leads to refactoring of other components.

```public class LoggedUsersController
{
public Dictionary<int, DateTime> LastUserLoginDateAndTime { get; set; }
public List Users { get; set; }
}

{
private LoggedUsersController loggedUsers =
new LoggedUsersController();

{
User user = getUserFromDatabase(userId);

if (loggedUsers.Users.Exists(u => u.Id == userId))

else

return user;
}
}
```

Since `RegisterUserLogin` performs direct access to inner content of `LoggedUsersController`, it contributes to a tighter coupling from the caller to the behavior of `LoggedUsers`. A better approach is to isolate the behavior inside `LoggedUsersController`.

```public class LoggedUsersController
{
private List Users;

{
if (this.Users.Exists(u => u.Id == user.Id))

else
}
}

{
private LoggedUsersController loggedUsers =
new LoggedUsersController();

{
User user = getUserFromDatabase(userId);
}
}
```

Now, the `BusinessRule` class is not tied to the implementation of `LoggedUsersController`. Instead, it is interested only in the responsibilities of its interface. It does not know details about the implementation of `LoggedUsersControllers` anymore, which contributes to a looser coupling. Moreover, all the logic related to the data of `LoggedUsersControllers` is handled closer, eliminating the inappropriate intimacy, which increases cohesion of the class.

### Types of Coupling

The types are listed in order of the highest to the lowest coupling.

• Content coupling (worst) occurs when one component depends on internal data or behavior of another component. This is the worst degree of coupling, since changes to one component will almost certainly require modification to others.
• Common coupling occurs when modules share common data, like global variables. As we all know, globals are evil. Changing the shared resource implies changing all the modules using it.
• Control coupling occurs when one service or module knows something about the implementation of another and passes information to control its logic.
• Stamp coupling occurs when modules share objects and use only a part of it. Sharing more data than what was needed allows the called module to access more data than it really needs.
• Data coupling occurs when one module or service shares data between each other. Data passed as parameter to a function call is included in this type of coupling. Although services with many parameters are a bad sign of design, well handled data coupling is preferable when compared to other forms of coupling.
• No coupling (best) – No intersection between modules.

If two or more components need to communicate, they should exchange as little information as possible.

## Cohesion

Cohesion is a measure of responsibility and focus of an application component. It is the degree to which the elements of a module belong together, which should be maximized.

We want strong-related responsibilities in a single component. Thus, we want to develop highly cohesive code.

In a highly cohesive code, all data, methods and responsibilities are kept close. Services tend to be similar in many aspects.

A simple and intuitive way to test the cohesion of a class is to check if all the data and methods that it contains have a close relationship with the class name. Considering this, you should be aware that generic class names tend to generate cohesion problems, because they can get many different responsibilities over time. In fact, classes that have a vague name might one day become god objects (an anti-pattern that defines an “all-knowing” object that contains tons of features and services with many different purposes, which dramatically compromises cohesion and coupling of components).

## The Law of Demeter: Talk Only To Your Closest Friends

Also known as Principle of Least Knowledge or just LoD, the law of Demeter governs the interconnection between components. It reinforces loose coupling and high cohesion by stating that your object-oriented entities should only be talking to their closest friends.

The Law of Demeter states that a method of a given object should only access methods and accessors belonging to:

• The object itself
• Parameters passed in to the method
• Any object created within the method
• Direct component elements of the object

Long chaining of accessors and methods is a sign of bad design.

For example:

```public class BusinessRule
{
public Bid GetCarAuctionBestBid(int carId)
{
//... some logic here
return bidsLogic.Bids.AllBids.GetBestBid(b => b.CarId = carId);
}
}
```

Even if you need a particular information that is at the end of the chain, digging out the methods and accessors yourself is a terrible idea.

```public class BusinessRule
{
public Bid GetCarAuctionBestBid(int carId)
{
//... some logic here
return bidsLogic.GetBestBid(carId);
}
}
```

Now you are only talking to your closest friend. “`bidsLogic`” resolves its properties internally and exposes services that are explicitly needed by others components. There is another thing going on here. The law of Demeter is not just about chaining. When you do not have to worry about navigating accessor and methods (i.e., when you have what you need by just calling a method or property of a nearby object), we say that you are telling the object what to do. The principle of least knowledge is closely related to the principle “Tell, don’t ask”!

The problem is not to use “get” accessor to understand a behavior of an object. The problem is to make decisions based on that. You do not want to ask the object about its inner state, make decisions about that state and then perform some dark operation. Object-oriented programming tells objects what to do.

The sample below is an example of code that asks too much. The code makes decisions about the state of the bill by adding prices contained in the list of Items assuming that the sum represents the total value of the bill.

```public class BusinessRule
{
public double CalculateDinnersCost(List<Bill> bills)
{
return bills != null ? bills.SelectMany(b => b.Items).Sum(i => i.Price) : 0;
}
}
public class Bill
{
public Bill()
{
this.Items = new List<Item>();
}
public List<Item> Items { get; private set; }

public void Remove(int itemId) {...}
}
```

Instead of asking that much, if the state of an object can be inferred by examining closer accessors and methods, we should consider relocating the logic inside the right object. This is the “Tell, don’t ask” principle: instead of developing procedural code, we tell the objects what to do.

```public class BusinessRule
{
public double CalculateDinnersCost(List<Bill> bills)
{
return bills != null ? bills.Sum(b => b.CalculateTotalCost()) : 0;
}
}
public class Bill
{
private List<Item> items;

public Bill()
{
this.items = new List<Item>();
}

public void Remove(int itemId) {...}

public double CalculateTotalCost()
{
return this.items.Sum(i => i.Price);
}
}
```

## Single Responsibility Principle

The Single Responsibility Principle is straightforward:

Every class should have a single responsibility and have one, and only one, reason to change.

Imagine an entity called `MessagesRegister`, which is responsible for registering alerts and notifications.

This is how `MessagesRegister` works:

• It reads a configuration file

This class can be changed for two reasons. First, the source of the configuration can evolve into something more elaborate over time (instead of XML, a configuration through graphical user interface). Furthermore, the actual processing rule might change.

It is a bad design decision to keep together two pieces of information that are changed for different reasons. The cohesion (i.e., focus and responsibility of the class) is reduced and the principle of separation of concerns is violated.

## Putting It All Together

So… where should I put this code? While coupling measures the degree of dependence between different entities of the system, cohesion is a measure of how focused the responsibilities of a given entity are.

By following these principles, we can enumerate some major achievements in our design:

• Maintenance is child’s play: we keep together things that need to be maintained together and things that are not directly related can be changed without affecting other components.
• The code is readable and algorithms become more self-documenting.
• Classes have well-defined responsibilities and code duplication is drastically reduced.

## Share

Work experience in Microsoft technologies, web and distributed systems. MSc in computer science (field of Machine Learning) at UFPE, bachelor of Computer Engineering at UPE, Microsoft certified and Software engineer at Revenu Québec, Canada.

 First Prev Next
 two additional principles George Shimanovich25-Nov-14 16:43 George Shimanovich 25-Nov-14 16:43
 Re: two additional principles Arthur Minduca28-Nov-14 6:26 Arthur Minduca 28-Nov-14 6:26
 This is a general principle .. --CELKO--25-Nov-14 15:15 --CELKO-- 25-Nov-14 15:15
 Re: This is a general principle .. Arthur Minduca28-Nov-14 6:17 Arthur Minduca 28-Nov-14 6:17
 Re: This is a general principle .. --CELKO--29-Nov-14 3:37 --CELKO-- 29-Nov-14 3:37
 Re: This is a general principle .. Arthur Minduca30-Nov-14 3:10 Arthur Minduca 30-Nov-14 3:10
 Re: This is a general principle .. Dewey17-Mar-17 7:22 Dewey 17-Mar-17 7:22
 images missing BigTimber@home24-Nov-14 3:45 BigTimber@home 24-Nov-14 3:45
 Re: images missing Arthur Minduca24-Nov-14 5:57 Arthur Minduca 24-Nov-14 5:57
 Re: images missing Anders Baumann24-Nov-14 6:20 Anders Baumann 24-Nov-14 6:20
 Re: images missing Arthur Minduca24-Nov-14 6:35 Arthur Minduca 24-Nov-14 6:35
 Re: images missing Anders Baumann24-Nov-14 10:40 Anders Baumann 24-Nov-14 10:40
 Re: images missing Arthur Minduca24-Nov-14 13:47 Arthur Minduca 24-Nov-14 13:47
 Last Visit: 12-Dec-19 21:34     Last Update: 12-Dec-19 21:34 Refresh 1