Originally published at Delivery Hero Tech Blog on July 19th, 2021.

We live in a fast-paced world. Today, even the children’s books reflect how fast the world we live in can move. Oliver Jeffers, the author of the New York Times Bestseller “Here We Are,” writes to his son: “Things can sometimes move slowly here on Earth. More often, though, they move quickly.” (1) Everything around us can change at any time, and we know this fact well at Delivery Hero. We need to adapt ourselves and our business to the changing needs of our environment.

Since the software we are building reflects the business we run every day, our codebases need to follow the same path. Change inside our most precious possession, codebases, is inevitable, and success comes with how fast our code can react to the changing business requirements.

Change is only fast when it is easy to do. If you run your business on a codebase that is not easy to understand, it would also be vulnerable to change. When a piece of code is not readable, then the software engineer will have to put the time and effort into understanding what it does. Sometimes changing the code can become scary because you cannot understand what side effects you’ll trigger once you change some part of the code. In those cases, the change will become costly, and the business will suffer by not catching up to the competition. However, if the codebase is readable and understandable, maintaining and changing the code will also become more manageable. Even the mutation of business requirements won’t scare the engineers because they can adapt without fear of hurting the business.

Cohesion is one of the concepts that we can keep in mind when designing maintainable systems. The word was coined by Larry Constantine in the mid-1960s and first published in 1968, along with its equally important fellow, coupling (which we’ll talk about in a different article). (2) Larry Constantine argues that “of the two, cohesion emerges from extensive practice as more important .” However, they are interrelated, and “Attempting to divide a cohesive module would only result in increased coupling and decreased readability.” (3) In a software module, cohesion defines how well the individual parts are related to each other. When those parts are highly connected, then we can say that the module is highly cohesive. On the other hand, if they’re not operating or depending on each other, the module has low cohesion.

Although cohesion is a very old concept, it is one of the most fundamental metrics to better software development. In the late 1990s, Robert C. Martin attempted to consolidate cohesion and coupling notions into a principle which today we know as the Single Responsibility Principle. (4) Some might argue that software engineering is a field where new concepts and stacks emerge every day. It is partly true that you can find something new every minute. However, Martin Fowler states that “The fundamentals of good software development have stayed more similar than not in my 30+ years in the industry. Details change, sure, but the energy spent honing core skills will continue to pay.” (5). Even with the latest architectural trends like Microservices, cohesion and coupling stay relevant, especially within the services. That’s why the authors of Fundamentals of Software Architecture, Mark Richards and Neal Ford, put great emphasis on cohesion and coupling while talking about the scope of architecture characteristics as well as modularity. (6)

While cohesion is an abstract concept, there are some predefined types of cohesion that we can explore as examples.

Cohesion types from worst to best

When we’re talking about cohesion, we generally prefer high cohesion (and loose coupling). However, it’s also true that not all types of cohesion benefit the architecture and the codebase. So, it’s good practice to investigate how to achieve better cohesion and high cohesion – although, this works on a case-by-case basis.

We can benefit from Object-Oriented Programming and borrow the Class concept as our module example to understand cohesion.

Coincidental cohesion — the worst

Functions in a class are not related at all. They’ve just been grouped arbitrarily like in a Utility class.

Logical cohesion

Class functions are logically related, although operationally different. Think of a class for sending a notification, for example. One function handles push notifications, the next one sends emails, and the third sends text messages. They’re logically doing the same thing (sending notifications), but what they do is entirely different.

Temporal cohesion

Functions in a class are related based on when they’re run. Whenever an exception occurs in one of the functions, another function is called to do the cleanup. They’re doing two different things, so they’re only temporally cohesive.

Procedural cohesion

If you can properly run a specific function only after a different function is run, then those two functions are procedurally cohesive. For example, think of a function that is checking user permissions. Only if the user is authorized, the target function is run. Then these two functions have procedural cohesion.

Communicational cohesion

When two functions are operating on the same set of data, they’re communicationally cohesive. For example, let’s say we have a class that is handling the payments. One of the functions writes the successful payment information to the database. Then the other function reads that data to start the shipping process. In this case, these two functions have communicational cohesion.

Sequential cohesion

If one function’s output is another one’s input, then those two functions are sequentially cohesive. Think of a function that is creating a user profile. It accepts certain user information as well as a username. Instead of asking the user for a username, another function creates a slug from the user’s first and last names. In this case, these two functions have sequential cohesion.

Functional cohesion — the best

When functions of a class all contribute to a single task, then they are functionally cohesive. For example, let’s say we have a class implementing the builder pattern. The class is named CarBuilder, and all of its functions are used to build a car. Thus, the class has functional cohesion.

Conclusion

In their book, Structured Design, Edward Yourdon and Larry Constantine introduced these seven types of cohesion. Trying to achieve highly cohesive modules is a good approach that might lead to maintainable systems. However, it is also essential to note what types of cohesion we are targeting; not all types of high cohesion will lead to a manageable codebase. While the first three types suggested a poor and costly design, they explained, the last three are generally acceptable (3). In the end, the chase of better cohesion will provide less complex systems that are easier to change and adapt to the ever-changing business needs.

References

(1) Oliver Jeffers. (n.d.). Here We Are. Available at: https://www.oliverjeffers.com/here-we-are .

(2) history.computer.org. (n.d.). Computer Pioneers – Larry L. Constantine. Available at: https://history.computer.org/pioneers/constantine.html. .

(3) Yourdon, E., Constantine, L.L. and Internet Archive (1975). Structured design. Internet Archive. New York: Yourdon Inc. Available at: https://archive.org/details/structureddesign00your .

(4) blog.cleancoder.com. (n.d.). Clean Coder Blog. Available at: https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html. .

(5) Twitter. (n.d.). https://twitter.com/martinfowler/status/1166775236374736897. Available at: https://twitter.com/martinfowler/status/1166775236374736897 .

(6) www.oreilly.com. (n.d.). Fundamentals of Software Architecture . Available at: https://www.oreilly.com/library/view/fundamentals-of-software/9781492043447/ .