# IDomainService vs IApplicationService in DDDplus: Layered Architecture Guide

> Understand the difference between IDomainService and IApplicationService in DDDplus. Learn how each layer orchestrates workflows and encapsulates business logic for effective DDD.

- Repository: [Funky Gao/cp-ddd-framework](https://github.com/funkygao/cp-ddd-framework)
- Tags: architecture
- Published: 2026-03-02

---

**In the DDDplus framework, `IApplicationService` orchestrates use-case workflows and coordinates domain objects, while `IDomainService` encapsulates pure business logic that cannot be assigned to entities or value objects.**

The cp-ddd-framework (DDDplus) implements strict architectural boundaries between the application and domain layers through marker interfaces. Understanding the distinction between `IDomainService` and `IApplicationService` ensures business logic remains isolated from orchestration concerns, maintaining the integrity of your Domain-Driven Design architecture.

## Architectural Layer Responsibilities

DDDplus enforces a clear separation between the **horizontal application layer** and the **vertical domain layer**. This separation is codified in the framework's specification module through two distinct marker interfaces.

### The Application Layer Contract

Located in [`dddplus-spec/src/main/java/io/github/dddplus/model/IApplicationService.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-spec/src/main/java/io/github/dddplus/model/IApplicationService.java), this interface represents the application layer's entry point. The source code documentation explicitly states: *"应用层，负责组织业务场景，编排业务，隔离场景对领域层的差异"* (Application layer, responsible for organizing business scenarios, orchestrating business, and isolating scenario differences from the domain layer).

**`IApplicationService`** implementations handle:

- Transaction management and security concerns
- Input validation and DTO mapping
- Coordination of multiple domain objects and services
- Driving the overall use-case workflow

### The Domain Layer Contract

Defined in [`dddplus-spec/src/main/java/io/github/dddplus/model/IDomainService.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-spec/src/main/java/io/github/dddplus/model/IDomainService.java), this interface marks pure domain logic. The interface documentation clarifies: *"只负责业务规则，不负责业务流程，业务流程由 `IApplicationService` 负责"* (Only responsible for business rules, not business process; business process is handled by `IApplicationService`).

**`IDomainService`** implementations contain:

- Complex business calculations and algorithms
- Validation logic that spans multiple aggregates
- Business rules that cannot naturally belong to a single entity or value object
- Pure logic independent of the orchestrating use-case

## Key Differences

Understanding the conceptual boundary between these interfaces prevents architectural leakage:

- **Orchestration vs. Implementation**: `IApplicationService` answers "what to do" by coordinating the workflow and delegating to appropriate domain objects; `IDomainService` answers "how to do it" by implementing the specific business behavior.

- **Layer Awareness**: Application services understand the surrounding context, external APIs, and presentation concerns; domain services operate within a bounded context without knowledge of the triggering scenario.

- **Transaction Boundaries**: Application services define transaction scopes and handle infrastructure concerns; domain services focus exclusively on business invariants and calculations.

## Implementation Examples

### Defining an Application Service

Application services implement `IApplicationService` and focus on workflow coordination:

```java
package com.example.app.service;

import io.github.dddplus.model.IApplicationService;
import org.springframework.stereotype.Service;
import com.example.domain.OrderDomainService;

@Service
public class OrderAppService implements IApplicationService {

    private final OrderDomainService domainService;

    public OrderAppService(OrderDomainService domainService) {
        this.domainService = domainService;
    }

    /** Application-level workflow: validates input → delegates to domain → persists result */
    public void placeOrder(PlaceOrderCmd cmd) {
        // 1️⃣ Validation / transaction handling (application concerns)
        // 2️⃣ Delegate core business rule to the domain service
        domainService.processOrder(cmd.getOrderId(), cmd.getItems());
        // 3️⃣ Additional post-processing, notifications, etc.
    }
}

```

### Defining a Domain Service

Domain services implement `IDomainService` and contain only business-centric logic:

```java
package com.example.domain;

import io.github.dddplus.model.IDomainService;
import org.springframework.stereotype.Component;
import com.example.model.Order;
import com.example.repository.OrderRepository;

@Component
public class OrderDomainService implements IDomainService {

    private final OrderRepository repository;

    public OrderDomainService(OrderRepository repository) {
        this.repository = repository;
    }

    /** Pure domain rule – calculate total & enforce invariants */
    public void processOrder(String orderId, List<Item> items) {
        Order order = repository.findById(orderId);
        order.calculateTotal(items);
        order.checkBusinessConstraints(); // domain-specific validation
        repository.save(order);
    }
}

```

### Wiring Layers Together

Controllers interact exclusively with the application layer:

```java
@RestController
@RequestMapping("/orders")
public class OrderController {

    private final OrderAppService appService;

    public OrderController(OrderAppService appService) {
        this.appService = appService;
    }

    @PostMapping
    public ResponseEntity<Void> create(@RequestBody PlaceOrderCmd cmd) {
        appService.placeOrder(cmd);          // Application layer entry point
        return ResponseEntity.ok().build();
    }
}

```

## Framework Enforcement

DDDplus provides compile-time validation to prevent layer violations. The `ArchitectureEnforcer` class in [`dddplus-enforce/src/main/java/io/github/dddplus/ArchitectureEnforcer.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-enforce/src/main/java/io/github/dddplus/ArchitectureEnforcer.java) analyzes dependencies to ensure domain services remain free of application concerns.

Additionally, the `@DomainService` annotation in [`dddplus-runtime/src/main/java/io/github/dddplus/annotation/DomainService.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-runtime/src/main/java/io/github/dddplus/annotation/DomainService.java) marks concrete implementations for framework processing and validation.

## Summary

- **`IApplicationService`** orchestrates use-cases, manages transactions, and coordinates domain objects within the application layer.

- **`IDomainService`** encapsulates pure business logic, complex calculations, and cross-aggregate business rules within the domain layer.

- The separation is enforced at compile-time by `ArchitectureEnforcer` to maintain strict architectural boundaries as defined in `dddplus-spec`.

## Frequently Asked Questions

### Can an Application Service call another Application Service?

While technically possible, this pattern indicates a missing domain concept or improper layer assignment. Application services should compose **domain services** rather than other application services to keep the domain layer rich and the application layer thin.

### Should Domain Services access Repositories?

Yes, domain services may access repositories to load aggregates required for business operations, as demonstrated in the `OrderDomainService` example. However, they should remain unaware of transaction boundaries and persistence details, which are application layer concerns.

### How does DDDplus prevent mixing these layers?

The framework uses `ArchitectureEnforcer` to perform static analysis at compile time, detecting improper dependencies such as application logic leaking into domain services or domain services depending on application layer components.

### When should logic reside in a Domain Service versus an Entity?

Place logic in a **domain service** when it involves multiple aggregates, requires external business rules, or does not naturally belong to a single entity. Keep logic in **entities** when it modifies the entity's own state and enforces local invariants.