Software Development

Vertical Slice Architecture

In the world of software architecture, different approaches have been developed to manage complexity, maintainability, and scalability. Two prominent architectures are the Layered Architecture and the Vertical Slice Architecture. This article explores these architectures, with a particular focus on Vertical Slice Architecture. Let us delve to understand the concepts of coupling and cohesion, and how these architectures impact design flexibility.

1. Layered Architecture

Layered Architecture is one of the most common architectural patterns used in software development. It organizes the application into layers, each responsible for a specific concern. Typically, these layers include:

  • Presentation Layer: Responsible for handling user interface and user experience.
  • Application Layer: Manages business logic and application workflows.
  • Domain Layer: Contains core domain logic and entities.
  • Infrastructure Layer: Handles data persistence, external services, and cross-cutting concerns.

This structure promotes separation of concerns, making the application easier to maintain and test. However, it can also lead to tight coupling between layers, especially as the application grows.

1.1 Code Example: Layered Architecture

Here’s a simple example of how a user registration feature might be implemented in a Layered Architecture:

// Presentation Layer (Controller)
@PostMapping("/register")
public ResponseEntity<String> registerUser(@RequestBody UserDto userDto) {
    userService.registerUser(userDto);
    return ResponseEntity.ok("User registered successfully");
}

// Application Layer (Service)
public void registerUser(UserDto userDto) {
    User user = userMapper.toEntity(userDto);
    userRepository.save(user);
}

// Domain Layer (Entity)
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    // getters and setters
}

// Infrastructure Layer (Repository)
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

1.2 Layered Architecture Use Cases

  • Small to Medium-Sized Applications: Ideal for applications where the scope is limited, and the complexity can be managed through clear separation of concerns.
  • Enterprise Applications: Suitable for enterprise-level applications with well-defined layers, such as ERP systems, where different teams manage different layers.
  • Applications with Stable Requirements: Works well when the requirements are stable, and there are fewer changes anticipated in the system.
  • Monolithic Applications: Commonly used in monolithic applications where all features are tightly integrated and managed in a single codebase.
  • Applications with Complex Business Logic: Useful when the application has complex business rules that are best managed within a centralized business logic layer.

2. The Vertical Slice Architecture

Vertical Slice Architecture takes a different approach by organizing the application into vertical slices, each representing a specific feature or functionality. Instead of separating the application into horizontal layers, Vertical Slice Architecture groups all necessary components for a feature, such as the user interface, business logic, and data access, into a single module.

This architecture promotes modularity, making it easier to add or modify features without impacting other parts of the application. Each slice is self-contained, which reduces coupling between different parts of the application and increases cohesion within a slice.

Java vertical slice architecture
Fig. 1: Representation of Vertical Slice Architecture

2.1 Code Example: Vertical Slice Architecture

In Vertical Slice Architecture, the same user registration feature would be implemented as a self-contained slice:

// User Registration Slice (Controller + Service + Repository in one module)
@PostMapping("/register")
public ResponseEntity<String> registerUser(@RequestBody UserDto userDto) {
    User user = new User(userDto.getUsername(), userDto.getPassword());
    userRepository.save(user);
    return ResponseEntity.ok("User registered successfully");
}

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    // Constructor, getters, and setters
}

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

2.2 Vertical Slice Architecture Use Cases

  • Large-Scale Applications: Ideal for large, complex applications where features can be developed and deployed independently.
  • Microservices Architecture: Aligns well with microservices, where each slice can be developed, deployed, and scaled as a separate service.
  • Applications with Frequent Changes: Suitable for applications that require frequent updates or have evolving requirements, as slices can be modified without affecting others.
  • Feature-Based Development: Best for applications where development is organized around distinct features, allowing teams to focus on delivering specific functionality end-to-end.
  • High Modularity Requirements: Useful when the application demands high modularity, allowing individual slices to be developed, tested, and deployed independently.

3. Coupling and Cohesion

Coupling and cohesion are two fundamental principles in software design that greatly influence the maintainability, scalability, and robustness of an application.

3.1 Coupling

Coupling refers to the degree of interdependence between software modules. In highly coupled systems, changes in one module are likely to affect other modules, making the system more fragile and harder to maintain. Low coupling, on the other hand, means that modules are more independent, allowing changes to be made to one module without significant impact on others.

In Layered Architecture:

  • The coupling tends to occur between layers, especially if business logic is spread across multiple layers. For example, a change in the data access layer might necessitate changes in the business logic or presentation layers.
  • This inter-layer dependency can lead to ripple effects when changes are required, making the architecture harder to adapt as the system grows.

In Vertical Slice Architecture:

  • Coupling is minimized by encapsulating all necessary components for a feature within a single slice. Each slice operates independently, reducing the risk of changes in one slice affecting others.
  • This low coupling promotes more stable and maintainable systems, as features can evolve independently without causing unintended side effects in other parts of the application.

3.2 Cohesion

Cohesion refers to how closely related and focused the responsibilities of a single module are. High cohesion within a module means that all parts of the module work together towards a single purpose, making the code more understandable, maintainable, and reusable.

In Layered Architecture:

  • Cohesion can be low within layers, especially when the same layer contains logic for multiple features. For instance, the business logic layer might have various methods and classes that serve different parts of the application, leading to a mix of responsibilities.
  • This lack of focus within layers can make the system harder to understand and maintain, as developers need to navigate through unrelated code to make changes or fix issues.

In Vertical Slice Architecture:

  • Cohesion is high because each slice contains all the components needed for a single feature or functionality. The code within each slice is tightly focused on achieving a specific goal, making it easier to understand and work with.
  • This high cohesion leads to more maintainable code, as developers can easily locate the relevant code for a feature and make changes without affecting unrelated parts of the application.

4. Design Flexibility

Design flexibility refers to the architecture’s ability to adapt to changes in requirements, technologies, or business needs. Flexibility is a critical factor in determining how future-proof an architecture is, as it directly impacts the ease with which new features can be added, existing features can be modified, or the system can be scaled.

Layered Architecture, while promoting separation of concerns, can become rigid and challenging to adapt as the application grows.

Vertical Slice Architecture, with its modular approach, offers greater design flexibility. Since each slice is self-contained, new features can be added, and existing features can be modified without affecting other parts of the application. This modularity allows for easier experimentation, faster iterations, and smoother scaling of the application.

5. Comparison Between Layered and Vertical Slice Architectures

AspectLayered ArchitectureVertical Slice Architecture
Separation of ConcernsPromotes clear separation between layers (e.g., UI, business logic, data access). Easier to manage when dealing with distinct concerns.Focuses on separating features instead of layers. Each slice is self-contained with all necessary components, reducing the need for inter-layer communication.
CouplingCan lead to tight coupling between layers, making it harder to change one layer without affecting others.Reduces coupling by encapsulating all relevant components within a single slice. Changes in one slice usually don’t affect others.
CohesionMay result in lower cohesion within layers, especially when different features share the same layer.Promotes high cohesion as each slice contains only the components needed for a specific feature, making it more focused.
MaintainabilityCan be difficult to maintain as the application grows, especially with tightly coupled layers and shared responsibilities.Easier to maintain since each slice is independent, making it simpler to manage changes or updates.
ScalabilityScalability can be challenging due to interdependencies between layers. Scaling specific features may require changes across multiple layers.Highly scalable, as individual slices can be scaled independently without impacting other slices.
TestingTesting may require mocking or stubbing layers, which can add complexity to the testing process.Testing is more straightforward, as each slice is self-contained, reducing the need for extensive mocking and stubbing.
FlexibilityLess flexible when dealing with changes, as modifications in one layer may necessitate changes in others.Offers greater flexibility, as changes in one slice typically don’t affect other slices.
Learning CurveLower learning curve for those familiar with traditional architectures, but can become complex as the application grows.Higher initial learning curve, especially for developers new to this approach, but pays off in terms of maintainability and flexibility.
Development SpeedMay be slower in large applications due to the need to navigate and update multiple layers.Can lead to faster development, especially for adding new features, as each slice can be developed independently.

6. Conclusion

Both Layered and Vertical Slice Architectures have their strengths and challenges. Layered Architecture is well-suited for small to medium-sized applications where separation of concerns is critical. However, as applications grow in complexity, Vertical Slice Architecture offers a more flexible and modular approach, with improved cohesion and reduced coupling.

Understanding these architectures and their implications on coupling, cohesion, and design flexibility can help you make informed decisions when designing your software systems.

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button