Separation of Concerns
Last updated
Last updated
The development process has too many different responsibilities. User interface design, database processes, exception handling, and many other tasks can be examples of responsibilities. Separation Of Concerns recommends that these different responsibilities be isolated from each other and each handled within a separate component. This makes the software more sustainable and maintainable.
As the simplest definition; we can define it as a component focusing only on its own work. For example; All structures such as logic, business, and helpers are located in different places and managed from here. The simplest example can be said to be MVC. MVC is a structure derived from Separation Of Concerns, and considering Model-View-Controller from different points comes from this principle. Of course, this can be described as the simplest form of Separation Of Concerns. The main purpose of this principle is that we should divide all requirements into the smallest parts that can be divided.
Why Separation Of Concern?
Separation Of Concerns is one of the most fundamental principles in software development. In fact, it is so critical that two of the 5 SOLID principles (Single Responsibility Principle and Interface Segregation Principle) are directly derived from this concept.
The active implementation of Separation Of Concerns will prevent the disruption or impact of other structures when adding or enhancing new modules or services within our application. This ensures that the task at hand is completed quickly, more efficiently, and securely by focusing on a single point.
In addition to all these benefits, it directly influences high code quality because the interdependence between codes is kept at the lowest level, making the code easier to understand.
As mentioned earlier, Separation Of Concerns is just the foundation of this task. When dealing with architecture and aiming to find a solution, a variety of technical options and technologies come into play. For example, various options such as DDD (Domain Driven Design), TDD (Test Driven Development), MVC, AOP (Aspect Oriented Programming) are available. However, fundamentally, all structures somehow either become Separation Of Concerns or support it.
Advantages In Software Design:
Modularity: Breaking down the software into small components enables us to design and develop each one separately. This ensures that when changes affect one component, the impact on other components is minimized.
Usability: Separating each component provides a better experience for users. Users can focus only on the components they need, avoiding unnecessary complexity.
Conceptual Integrity: Addressing each component separately improves conceptual integrity. This allows us to better understand what each component does and how they are interconnected within the system.
Successful SoC Example: In this example, we will examine C# code handling a shopping cart. As a successful example of SoC, I present a sample that keeps the code clean and well-separated.
In this example, the ShoppingCart and Item classes are separated. While ShoppingCart manages the functionality of the shopping cart, Item represents shopping items. Each class focuses on its own responsibility and is organized in accordance with the SoC principle.
Unsuccessful SoC Example: Below, an unsuccessful example of SoC is presented. This example includes complex C# code that combines user authentication and shopping cart operations:
In this example, the User class combines user authentication, shopping cart operations, and managing the shopping cart functionality in the same class. This leads to complexity in the code, violates the SoC principle, and sets the stage for the God Class problem.
A successful SoC example reflects a scenario where each class focuses on a specific responsibility, and each class has its own unique functionality. In contrast, an unsuccessful SoC example combines different responsibilities, making the code complex. The SoC principle helps the code be cleaner, more sustainable, and less prone to errors.
Successful SoC Example 2: As another example, let’s consider a SoC-compliant part of a customer order management application
In this example, the CustomerOrder class represents a customer order, while the OrderProcessor performs order creation and price calculation functions. Each class has a clear and separated role.
Unsuccessful SoC Example 2: In the following example, you will find an unsuccessful version of a customer order management application that does not adhere to SoC.
In this example, the CustomerOrder class includes both order creation and price calculation, as well as saving to the database. This brings together different concerns and does not adhere to the SoC principle.
These examples can be used to illustrate why SoC is important and how it should be implemented. Successful SoC helps make the code more maintainable, understandable, and extensible.
Successful SoC and DDD Example: The following example demonstrates the successful use of SoC and DDD in an e-commerce application
In this example, the Product, Order, and OrderLine classes represent the core business logic in the domain layer. The OrderService manages order-related processes in the application services layer. This design cleanly separates business logic and database access, adhering to DDD principles.
Unsuccessful SoC and DDD Example: The following example represents an e-commerce application that does not adhere to DDD and SoC.
In this example, the ECommerceApp class includes both order creation and obtaining product information. This violates the SoC principle by combining different responsibilities and does not adhere to DDD principles by not using a clean domain model.
A successful SoC and DDD application defines business logic clearly, separates the domain model from application services, and makes large and complex projects more manageable.