SuperAPI AI Directory

repository-placement

General & other

View repository

Updated 10-15 22:39

About this skill

Placement of Repository Interfaces

Conclusion

Place repository interfaces in the use case layer. Do not place them in the domain layer.

Why Placing Them in the Domain Layer Is Problematic

Physical Proximity Induces Coupling

When they are in the same layer, the domain model becomes easier to use with repositories:

// ❌ 集約の中でリポジトリを使ってしまう
class Order {
  Order withRelatedOrder(OrderId relatedId, OrderRepository repo) {
    Order related = repo.findById(relatedId);  // ← 同じ層にあるから気軽に使える
    return this.withAddedRelatedOrder(related);
  }
}
// ❌ ドメインサービスがリポジトリだらけになる
class OrderDomainService {
  private OrderRepository orderRepo;
  private CustomerRepository customerRepo;
  private ProductRepository productRepo;
  private InventoryRepository inventoryRepo;
  // リポジトリの注入が増え続ける
}

The Domain Ends Up Knowing About "Persistence"

// ドメイン層にこれがあるということは...
interface OrderRepository {
  void save(Order order);      // ← 「保存」という概念を知っている
  Order findById(OrderId id);  // ← 「取得」という概念を知っている
}

Domain model isPure business rulesshould have only.

Advantages of Placing Them in the Use Case Layer

Structure Enforces Design Intent

[ドメイン層]              ← リポジトリをimportできない = 結合しない
     ↑
[ユースケース層]          ← リポジトリインターフェース定義(出力ポート)
     ↑
[インターフェースアダプタ層] ← リポジトリ実装(入力/出力アダプタ)

Physical distance acts as a guardrail:

  • Hard to import from the domain model (separate package/module)
  • The intent that "repositories are ports of the use case layer" is conveyed through structure
  • Easy to follow the rule that aggregates reference by ID

The aggregate ID reference rule can be followed naturally

// ✅ 集約は他の集約をIDで参照
class Order {
  private final CustomerId customerId;  // Customer実体ではなくID
  private final List<ProductId> productIds;
}

// ユースケース層でリポジトリを使って解決
class PlaceOrderUseCase {
  private OrderRepository orderRepo;
  private CustomerRepository customerRepo;

  void execute(PlaceOrderCommand cmd) {
    Customer customer = customerRepo.findById(cmd.customerId);
    // ユースケース層で必要なエンティティを取得
  }
}

Detection Patterns

Signs that a repository is in the domain layer

domain/
  order/
    Order.java
    OrderRepository.java  ← ❌ ここにある

Signs that a repository interface is in the interface adapter layer

interface-adapters/
  repositories/
    OrderRepository.java  ← ❌ ここにある

Correct Placement

domain/
  order/
    Order.java
    OrderId.java

usecases/  (または application/, interactor/)
  order/
    OrderRepository.java      ← インターフェース定義

interface-adapters/  (または adapters/, infra/)
  repositories/
    JpaOrderRepository.java   ← 実装

Relationship with DDD

Traditional DDD InterpretationIn this view, repositories are considered part of the domain (lifecycle management of aggregates).

However, in practice, placing them in the domain layer tends to create coupling. Under Clean Architecture conventions, repository interfaces are treated as output ports of the use case layer.

Approach Advantages Disadvantages
Placed in the domain layer As per DDD textbooks Coupling tends to arise
Placed in the use case layer Matches conventions / dependency direction is clear Differs from DDD purism

Recommendation: Place them in the use case layer and guard them through structure.

Review checklist

  1. Placement check: Are the repository interfaces in the use case layer?
  2. Coupling check: Does the domain model (entities/aggregates) import repositories?
  3. ID reference check: Do aggregates reference other aggregates by ID rather than by entity?

References

  • Martin, Robert C. "Clean Architecture" (2017)
  • Vernon, Vaughn. "Implementing Domain-Driven Design" (2013)

Related Skills (Recommended for Concurrent Reading)

When using this skill, also refer to the following skills:

  • clean-architecture: The 4-layer architecture that forms the foundation of repository placement
  • aggregate-design: Design rules for the aggregates that repositories correspond to
  • repository-design: Repository naming, CQS, and method design