Understanding Component Cohesion
Let’s talk a litte bit about components and reusability.
In the world o Software Design and Architecture, Robert C. Martin suggests the following principles:
- Reuse-Release Equivalence Principle (REP)
- Common Closure Principle (CCP)
- Common Reuse Principle (CRP)
Reuse-Release Equivalence Principle (REP)
“The granule of reuse is the granule of release.”
In simpler terms, it suggests that for a module to be reusable, it should also be independently releasable. The principle implies three main ideas:
- Reusability and Release Coupling: If a module (like a class library) is to be reused in multiple systems, it should be packaged in a way that allows it to be released independently. This means that other projects can depend on a versioned, stable release of the module without needing the entire project from which it originated.
- Versioning and Stability: Modules intended for reuse should be versioned, tested, and stable. Releasing them independently ensures that any updates or changes can be tracked and managed without affecting dependent projects.
- Granularity of Components: The principle also highlights the importance of defining an appropriate level of granularity when creating reusable components. Overly large modules or complex systems are harder to release independently, so designing modules with reusability and release in mind encourages better modularization and separation of concerns.
Example
Imagine you have a utility library in C# that includes various helper functions for file operations, string manipulations, and HTTP requests. If you follow the REP, you’d package this library as a standalone NuGet package, versioned and documented, so that other projects can consume it without requiring direct access to the source code. Updates to the utility library would be released as new versions, allowing dependent projects to upgrade as needed.
As a result, this helps ensure that reusable components are well-defined, stable, and managed independently, leading to more maintainable and modular code in the long run.
Breaking REP
What about breaking this principle?
A package would break the Reuse-Release Equivalence Principle (REP) if it has dependencies on other packages that are not part of its own release, making it difficult to reuse independently. In other words, if a package cannot function on its own and requires other components (packages) to be fully usable, then it isn’t truly an independent release, and thus, it doesn’t adhere to REP.
Common Closure Principle (CCP)
“Classes that change together should be grouped together.”
In other words, classes that are likely to be modified at the same time (due to the same reason or requirement) should be placed within the same module or package. This principle helps in minimizing the impact of changes — as changes related to a specific feature or functionality will likely be localized within one module, reducing the chance of unintended consequences elsewhere in the system.
- Encapsulation of Change: By grouping classes that are likely to change together, you can better encapsulate changes. When a requirement changes or a bug needs fixing, you only need to modify one module instead of scattering changes across the entire codebase.
- Reduced Deployment Complexity: If a module’s classes are cohesive, changes to a specific part of the system can be deployed with minimal disruption. This containment of change aligns with modularity and versioning, reducing the need to release multiple modules for a single change.
- Reinforces Open Closed Principle (OCP): Organizing classes based on the likelihood of change simplifies maintenance. Since the classes within a module have related responsibilities, developers can more easily understand and make changes in a localized way without impacting other parts of the application.
Example
Imagine a Customer Management System where you have classes like Customer
, CustomerAddress
, and CustomerPreferences
.
Changes to customer-related requirements (like updating how customer data is stored or displayed) would likely affect all these
classes together. According to the CCP, these classes should be grouped together in a single module or namespace, such as CustomerManagement
,
to reflect their close relationship and change likelihood. Usually, in education institutions we’re taught to write classes independently (i.e create a file for each class).
1namespace CustomerManagement2{3public class Customer4{5// Customer details and methods6}78public class CustomerAddress9{10// Address details and methods11}1213public class CustomerPreferences14{15// Preferences details and methods16}17}
Breaking CCP
A violation of CCP would occur if Customer
, CustomerAddress
, and CustomerPreferences
were spread across different modules (e.g., CustomerCore
, AddressManagement
, Preferences
).
This would mean that a simple change to customer-related logic might require changes across
multiple modules, creating dependencies and making maintenance more complex.
Common Reuse Principle (CRP)
“Don’t force users of a component to depend things they don’t need”
In essence, CRP suggests that classes which are likely to be reused together should belong to the same module or package. This helps to minimize unnecessary dependencies by ensuring that a package only includes classes that make sense to be reused as a group.
- Avoiding Unused Dependencies: CRP aims to prevent users of a package from having to depend on classes they don’t need. When classes that don’t belong together are packaged together, it forces dependencies on parts of the code that aren’t relevant to the user’s needs, leading to what’s known as dependency bloat.
- Creating Cohesive Modules: CRP promotes cohesiveness within modules. When a package contains only classes that make sense to be reused together, the module is more cohesive and logically consistent. This makes the package easier to understand, test, and maintain.
- Reducing Compilation and Deployment Overhead: When modules are organized according to CRP, changes within a package will more likely affect only the classes within it. This reduces the risk of unnecessary recompilation or redeployment, as other modules depending on this package will not have to be updated if the unused classes within it are modified.
Example
Another similar example is:
In this example, users needing to work with reporting functionalities only depend on the Reporting package without getting unrelated classes or functionality. This makes the module focused and avoids introducing dependencies on irrelevant code.
- Avoiding Unused Dependencies: CRP aims to prevent users of a package from having to depend on classes they don’t need. When classes that don’t belong together are packaged together, it forces dependencies on parts of the code that aren’t relevant to the user’s needs, leading to what’s known as dependency bloat.
- Creating Cohesive Modules: CRP promotes cohesiveness within modules. When a package contains only classes that make sense to be reused together, the module is more cohesive and logically consistent. This makes the package easier to understand, test, and maintain.
1namespace Reporting2{3public class ReportGenerator4{5// Logic to generate reports6}78public class ReportFormatter9{10// Logic to format reports11}1213public class ReportExporter14{15// Logic to export reports16}17}
Conclusion
The Reuse-Release Equivalence Principle (REP), Common Closure Principle (CCP), and Common Reuse Principle (CRP) are three design principles that guide modularity in software. REP suggests that reusable modules should also be independently releasable, fostering stability and version control.
I hope this helps!
x, gio