Cohesion is a metric that shows how closely related the elements within a single module or class are. According to Wikipedia, high cohesion is a characteristic of a well-designed module where all methods and fields work toward a single task. Cohesion directly affects code maintainability and is contrasted with coupling — the interconnectedness between modules.
Key Takeaways
Cohesion is a metric that evaluates how logically connected the methods, fields, and properties within a single class or module are. A highly cohesive module performs one task and contains only the elements necessary to accomplish it. A low-cohesion module tries to do several things at once — its methods are weakly related in meaning.
In the context of object-oriented programming, cohesion is closely tied to the Single Responsibility Principle (S). If a class has one clear responsibility, its cohesion is generally high. If a class handles UI, business logic, and networking all at once — cohesion is low, and such a class should be split into several separate classes with narrower responsibilities.
Understanding cohesion helps developers make refactoring decisions. When you see a method in a class that does not use any of the class's fields, that is a sign of low cohesion. Such a method is either misplaced in the class, or the class is poorly designed. Striving for high cohesion is an ongoing effort to improve architecture at every level of code.
In software engineering, seven levels of cohesion are distinguished, ranked from worst to best. Understanding this scale allows you to objectively assess the quality of a module and determine the direction for refactoring. The higher the level, the more maintainable and understandable the code will be.
Coincidental cohesion — the worst level, where elements in a module are grouped randomly without any logical connection. Example: a Utilities class containing methods for date formatting, sending emails, and calculating discounts. Such a class cannot be understood without reading all its methods, and changing one method might break others simply because they are located together.
Logical cohesion — elements perform logically related but fundamentally different tasks. A class with methods parseJSON, parseXML, and parseCSV is logically connected by the topic of “parsing,” but each method does fundamentally different work. The problem: when a new format (YAML) is added, the class grows and its interface becomes bloated.
Temporal cohesion — elements are grouped by execution time. An AppInitializer class that sets up the database, loads configuration, and initializes analytics — all of this happens at app startup, but the tasks themselves are unrelated. It is better to split them into separate Initializers for each area of responsibility.
Procedural cohesion occurs when elements are united by a sequence of execution. An “Order Processing” module contains methods validateCart, processPayment, and sendConfirmation — each method is called strictly after the previous one. This is better than coincidental or logical cohesion, but still not ideal: each step could be extracted into a separate module.
Communicational cohesion — elements work with the same data. A UserService class with methods getUser, updateUser, and deleteUser is united by the common User entity. This is significantly better than procedural cohesion: the class has a clear domain. Most Repository classes in mobile projects have communicational cohesion.
Functional cohesion — the highest level, where every element in the module participates in performing a single task. A PasswordValidator class with a single validate method that checks length, character presence, and password complexity is an example of functional cohesion. If such a class changes, it is only because the password validation rules have changed.
Achieving functional cohesion is the primary goal of architectural refactoring. Each class should have exactly one reason to change. In mobile development, functional cohesion is achieved by extracting separate Use Cases, custom Views, formatters, and validators. Each such class is a complete building block with a clear area of responsibility.
Cohesion and coupling are two sides of the same quality. The higher the cohesion within a module, the lower the coupling between modules tends to be. A well-designed system simultaneously strives for high internal cohesion and loose external coupling. This principle has been recognized as fundamental in software engineering since the 1970s.
The cohesion-coupling relationship can be thought of as a balance. If a developer sacrifices cohesion by combining several tasks in one class, neighboring modules gain more dependencies — they have to access this overloaded class for different purposes, which increases coupling. Conversely, splitting into small, highly cohesive classes reduces the number of interaction points between modules.
In practice, this means: when you extract a new class with functional cohesion, you simultaneously free other modules from needing to know the details of its implementation. For example, extracting EncryptionManager into a separate class with functional cohesion gives other modules a simple encrypt/decrypt interface without needing to understand the details of the encryption algorithm.
// Low cohesion — a class does everything at once
class UserManager {
fun fetchAndSaveUser(id: String) { }
fun parseUserJson(json: String): User { }
fun displayUserName(user: User): String { }
fun validateEmail(email: String): Boolean { }
}
// High cohesion — each class solves one task
class UserRepository {
fun fetchUser(id: String): User { }
}
class UserJsonParser {
fun parse(json: String): User { }
}
class UserNameFormatter {
fun format(user: User): String { }
}
class EmailValidator {
fun isValid(email: String): Boolean { }
}
The example shows the difference: UserManager has logical cohesion — all methods are about users, but each does fundamentally different work. After refactoring, each class has functional cohesion, and coupling is reduced because other modules depend only on the class they need, not on the entire UserManager.
LCOM (Lack of Cohesion of Methods) is the best-known metric for measuring class cohesion. LCOM counts how many pairs of methods do not share common fields. A value of 0 means ideal cohesion (all methods work with the same fields), while a high value indicates low cohesion. LCOM4 (an improved version) accounts for transitive connections through other methods.
In Android development, cohesion metrics can be obtained through Detekt with the TooManyFunctions rule. Classes with dozens of methods using different groups of fields likely have low cohesion. In iOS, SwiftLint has file_length and function_body_length rules — indirect indicators: long files and methods often signal low cohesion.
A manual assessment method: ask the question, “Will this class change for one reason or multiple reasons?” If you can name more than one independent reason — the class has low cohesion. A second test: “Can this class be split into two independent classes?” If yes — do it. Regularly checking cohesion during code reviews prevents God classes and reduces technical debt.
The first step is to apply the Single Responsibility Principle. Each class should have one clear responsibility. If a class has a method that does not relate to its main task, extract it into a separate class. The Extract Class or Extract Delegate technique in IDEs automates this process. After extraction, check whether the original class has become more focused.
The second step is to use the Facade pattern to simplify the interface. If a class provides 20 methods but clients only use 3–4, the class may have low cohesion — it offers too much diverse functionality. Group methods by topic, extract separate classes for each group, and either make the original class a facade or remove it.
The third step is to pay attention to field groups. If a class has fields that are only used by a subset of methods — that is an indicator of low cohesion. Split the class by field groups. For example, if a class contains fields userRepository, networkClient, and analyticsTracker, but the first group of methods only uses userRepository while the second uses networkClient — these are two different classes.
The fourth step is to avoid creating “utility” classes with arbitrary static methods. Every static method sitting in a Utils or Helpers class is a candidate for extraction into a specialized class. FormatUtils.dateToString is better moved to DateFormatter, and ValidationUtils.isValidEmail to EmailValidator. This increases the cohesion of each class and makes the code self-documenting.
Frequently Asked Questions
Almost always. Functional cohesion makes code clear and predictable. However, taking it to extremes can lead to excessive fragmentation: creating a separate class for every operation, making the architecture overly complex. The balance is a few classes per feature, each with functional cohesion.
Cohesion is a metric of internal consistency within a single module or class. Modularity is an architectural principle where an application is divided into physical modules. High cohesion is a goal when designing both individual classes and entire modules.
Detekt for Android and Xcode Analyzer for iOS highlight classes with suspiciously many methods or fields. IntelliJ IDEA and AppCode have dependency visualization — you can see the connection graph and spot classes with low cohesion. SonarQube calculates LCOM metrics automatically.
Yes. An interface with connect, disconnect, and isConnected methods has high cohesion — all methods relate to connection management. An interface with connect, parseData, and renderUI has low cohesion. The Interface Segregation Principle (SOLID) requires creating narrowly focused interfaces with high cohesion.
Ask three questions: Can the class purpose be described in one sentence? Do all methods support this purpose? Are there fields in the class that are not used by some methods? If the answer to any question is no — cohesion is low, and the class should be split.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also