Reading.CleanArchitecture.MainComponent

Main Component

(Clean Architecture by Robert C. Martin)

The Main Component chapter discusses the core entry point of a software system and its role in initializing the application, wiring dependencies, and starting the execution flow. The main component serves as the highest-level module, orchestrating the application setup without containing any business logic.


Key Concepts of the Main Component

1. Purpose of the Main Component

  • The main component is responsible for:
    1. Initializing the system by setting up all necessary components, services, and dependencies.
    2. Wiring dependencies between different layers and modules.
    3. Delegating execution to the appropriate use cases or controllers.
  • It is not responsible for business logic or core application workflows. Its job is purely organizational and bootstrapping.

2. The Dependency Rule in the Main Component

  • The main component must follow the dependency rule:
    • It depends on the core layers (e.g., entities, use cases) but not the other way around.
  • Example:
    • The main component can initialize use cases, repositories, and frameworks, but these should not depend on the main component.

3. Structure of the Main Component

  • The main component is often located in the outermost layer of the architecture.
  • It contains the entry point of the application (e.g., main() function or equivalent in your framework).

4. Responsibilities of the Main Component

a. Dependency Injection:
  • The main component wires dependencies by providing concrete implementations of interfaces.
  • Example:javaCopyEdit
public class Main {
    public static void main(String[] args) {
        OrderRepository orderRepository = new SqlOrderRepository();
        PlaceOrderUseCase placeOrderUseCase = new PlaceOrderUseCase(orderRepository);
        OrderController orderController = new OrderController(placeOrderUseCase);
    }
}
b. Configuration:
  • The main component configures external systems (e.g., database connections, API keys).
  • It loads configuration settings, such as environment variables or application properties.
c. Application Startup:
  • Starts necessary services (e.g., web servers, background jobs) and delegates control to the appropriate entry point.

Example in a Web Application:

public class Main {
    public static void main(String[] args) {
        SpringApplication.run(ApplicationConfig.class, args);
    }
}
d. Integrating Frameworks:
  • Frameworks like Spring, Django, or Express are often initialized in the main component.
  • This keeps frameworks confined to the outermost layer, following the framework independence principle.

5. What the Main Component Should Avoid

  • Avoid Business Logic:
    • The main component should not implement use cases or business rules.
    • Example of bad practice:
public static void main(String[] args) {
    // Business logic directly in the main function
    System.out.println("Processing order...");
}

Avoid Tight Coupling:

  • The main component should not directly couple frameworks with core logic.

Example of a Main Component

E-Commerce System Example

Entities Layer:

public class Order {
    private List<Product> products;

    public double calculateTotal() {
        return products.stream().mapToDouble(Product::getPrice).sum();
    }
}

Use Case Layer:

public class PlaceOrderUseCase {
    private OrderRepository orderRepository;

    public PlaceOrderUseCase(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    public void execute(Order order) {
        orderRepository.save(order);
    }
}

Interface Adapter Layer:

@RestController
public class OrderController {
    private PlaceOrderUseCase placeOrderUseCase;

    public OrderController(PlaceOrderUseCase placeOrderUseCase) {
        this.placeOrderUseCase = placeOrderUseCase;
    }

    @PostMapping("/orders")
    public ResponseEntity<String> placeOrder(@RequestBody Order order) {
        placeOrderUseCase.execute(order);
        return ResponseEntity.ok("Order placed successfully");
    }
}

Main component

public class Main {
    public static void main(String[] args) {
        // Dependency wiring
        OrderRepository orderRepository = new SqlOrderRepository();
        PlaceOrderUseCase placeOrderUseCase = new PlaceOrderUseCase(orderRepository);
        OrderController orderController = new OrderController(placeOrderUseCase);

        // Framework initialization (e.g., starting the server)
        SpringApplication.run(ApplicationConfig.class, args);
    }
}

6. Testing the Main Component

  • The main component itself typically doesn’t require detailed testing since it contains no business logic.
  • Focus on testing the components it initializes (e.g., use cases, repositories).

Key Takeaways

  1. Purpose: The main component is responsible for initializing and wiring the system but contains no business logic.
  2. Dependency Rule: It depends on the core application but is independent of it.
  3. Framework Isolation: Frameworks are confined to the main component or outer layers.
  4. Modular Startup: Each component (e.g., use cases, repositories) is initialized separately, maintaining clear boundaries.
This entry was posted in Без рубрики. Bookmark the permalink.