JPA

도메인 주도설계와 OOP의 관계에 대한 chatGPT와의 질의응답

devJK93 2024. 11. 24.

❓ 질의

JPA 를 통한 개발을 진행하고 있는데 Member 클래스는 MemberRepository랑 MemberService를 이용해서 로직을 만들었다. (join, findById, findAll) 같은 것들을 근데 Item 클래스는 비즈니스 로직이 Item클래스 내부에 있는거 같아 public void addQuantity(int quantity) {this.stockQuantity += quantity} 이렇게 하는게 도메인 주도 설계라는데 왜 이렇게 하는거지? 객체지향하고도 관계가 있나?

 

 

 

 

도메인 주도 설계와 객체지향 설계

1. 왜 비즈니스 로직을 도메인 객체(Item) 내부에 두는가?

핵심 이유: 응집성(Cohesion)을 높이고 도메인 객체의 역할을 강화하기 위해

  • 객체는 데이터(stockQuantity)와 그 데이터를 처리하는 행위(addQuantity)를 하나의 단위로 묶어서 관리해야 합니다.
  • 도메인 객체가 자신의 상태를 직접 관리하고 변경하는 책임을 가지게 함으로써, 코드의 응집성캡슐화를 강화할 수 있습니다.

예시: addQuantity

public void addQuantity(int quantity) {
    if (quantity < 0) {
        throw new IllegalArgumentException("Quantity must be positive");
    }
    this.stockQuantity += quantity;
}
    

이 방식은 stockQuantity에 대한 모든 변경 작업을 Item 내부에서만 처리하도록 강제합니다. 이렇게 하면:

  • 데이터와 그 데이터 처리 로직이 응집됩니다.
  • 외부에서 직접 stockQuantity를 수정할 수 없으므로 캡슐화가 유지됩니다.

2. 객체지향 프로그래밍(OOP) 관점에서의 장점

a. 책임(Responsibility)의 명확화

  • 객체지향 설계의 핵심은 객체가 자신의 책임을 스스로 가지는 것입니다.
  • Item 객체는 자신의 재고(stockQuantity)를 관리하는 책임을 가집니다.

b. 캡슐화(Encapsulation)

객체의 데이터를 외부에서 직접 수정하는 것을 방지하고, 필요한 작업만 메서드를 통해 수행하도록 합니다.

잘못된 방식:

item.stockQuantity += 10; // 직접 수정: 유효성 검사가 불가능
    

올바른 방식:

item.addQuantity(10); // 유효성 검사가 포함된 안전한 변경
    

c. 응집성(Cohesion) 증가

  • 관련된 데이터(stockQuantity)와 메서드(addQuantity)가 한 객체 안에 모이면, 객체의 역할이 명확해지고 코드의 구조가 더 단순해집니다.

3. 도메인 주도 설계(DDD) 관점

a. 엔티티(Entity)와 비즈니스 로직

도메인 주도 설계에서는 엔티티 객체(Item)가 도메인 로직을 포함하도록 설계합니다. 엔티티는 데이터뿐만 아니라, 도메인 규칙과 행동도 함께 표현해야 합니다.

예: Item 클래스의 책임

  • 재고 증가 (addQuantity)
  • 재고 감소 (removeQuantity)
  • 판매 가능 여부 체크 (canBeSold)

b. 서비스(Service)의 역할 분리

DDD에서는 서비스는 도메인 객체에 없는 복잡한 로직을 처리하거나, 여러 도메인 객체 간의 협력을 조정하는 데 사용됩니다.

간단한 도메인 로직은 도메인 객체(Item) 내부에 두어 응집도를 높이고, 서비스 클래스가 비대해지는 것을 방지합니다.

잘못된 설계

public class ItemService {
    public void addQuantity(Item item, int quantity) {
        item.setStockQuantity(item.getStockQuantity() + quantity);
    }
}
    

올바른 설계

public class Item {
    public void addQuantity(int quantity) {
        this.stockQuantity += quantity;
    }
}
    

4. Member와 Item의 차이

  • Member 클래스: 단순히 데이터를 조회하거나 저장하는 기능(join, findById, findAll 등)을 제공.
  • Item 클래스: 상태(stockQuantity)를 관리하며, 상태 변경을 수반하는 비즈니스 로직이 많음.

5. 요약

  • 도메인 주도 설계(DDD)는 객체지향의 원칙에 따라, 도메인 객체가 자신의 데이터를 관리하고 변경하는 책임을 가지도록 설계합니다.
  • Item 클래스 내부에 비즈니스 로직을 넣는 이유:
    • 객체지향의 원칙인 책임, 응집성, 캡슐화를 강화.
    • 도메인 로직이 명확하고 변경 관리가 용이.
  • Member 클래스처럼 상태 변화가 적은 객체는 단순히 조회/저장 로직만 가지는 경우도 있지만, Item처럼 상태 변경이 중요한 객체는 도메인 로직을 포함하는 것이 권장됩니다.

❓ 질의

데이터를 가지고 있는 클래스에 메서드가 있으면 응집력이 있다는데 그게 무슨 말이야?

 

 

응집력과 객체지향 설계

1. 응집력(Cohesion)이란?

응집력은 클래스 내부 요소들(데이터와 메서드)이 얼마나 밀접하게 연관되어 있는가를 의미합니다.

  • 높은 응집력:
    • 클래스의 필드(데이터)와 메서드가 밀접하게 관련되어 있습니다.
    • 클래스의 메서드들이 주로 클래스 내부의 데이터를 처리합니다.
    • 코드가 직관적이고 유지보수가 쉽습니다.
  • 낮은 응집력:
    • 클래스가 관련 없는 데이터와 메서드를 포함하고 있습니다.
    • 클래스의 메서드가 외부 데이터를 처리하거나, 클래스의 데이터와 관련 없는 작업을 수행합니다.
    • 코드가 복잡하고 유지보수가 어려워집니다.

2. "데이터와 메서드가 응집되어 있다"의 의미

클래스가 자신의 데이터를 가지고 있고, 그 데이터를 처리하는 메서드를 포함하고 있다면, 해당 클래스는 높은 응집력을 가진다고 할 수 있습니다.

예시 1: 높은 응집력

public class BankAccount {
    private double balance;

    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }

    public void deposit(double amount) {
        this.balance += amount;
    }

    public void withdraw(double amount) {
        if (amount > balance) {
            throw new IllegalArgumentException("Insufficient balance");
        }
        this.balance -= amount;
    }

    public double getBalance() {
        return balance;
    }
}
    

특징:

  • 데이터(balance)와 메서드(deposit, withdraw, getBalance)가 밀접하게 연결되어 있습니다.
  • 클래스 외부에서는 balance를 직접 수정할 수 없고, 제공된 메서드를 통해서만 조작 가능합니다.
  • 클래스는 "은행 계좌"라는 하나의 책임에 집중하고 있습니다.

예시 2: 낮은 응집력

public class BankAccountManager {
    private String logger;

    public void log(String message) {
        System.out.println(message);
    }

    public void calculateInterest(BankAccount account) {
        double interest = account.getBalance() * 0.01;
        System.out.println("Interest: " + interest);
    }
}
    

문제점:

  • BankAccountManager는 "로그 관리"와 "이자 계산"이라는 서로 관련 없는 작업을 수행합니다.
  • 데이터(logger)와 메서드(log, calculateInterest) 간의 관련성이 부족합니다.
  • 응집력이 낮아지고, 클래스의 역할이 모호합니다.

3. 응집력의 장점

a. 가독성

  • 높은 응집력은 클래스의 역할을 명확하게 만듭니다.
  • 클래스를 읽는 사람이 "이 클래스는 무엇을 하는지" 쉽게 이해할 수 있습니다.

b. 유지보수성

  • 응집력이 높은 클래스는 변경 사항이 발생해도 클래스의 코드 내부에서만 변경이 이루어지므로, 수정 범위가 좁습니다.
  • 다른 클래스와의 의존성이 줄어들어 유지보수가 쉽습니다.

c. 재사용성

  • 응집력이 높은 클래스는 명확한 책임을 가지므로, 필요한 곳에서 재사용하기가 쉽습니다.

4. 객체지향의 원칙과 응집력

a. 캡슐화(Encapsulation)

클래스 내부 데이터를 보호하고, 필요한 작업만 메서드를 통해 수행하게 만드는 것이 캡슐화입니다. 캡슐화는 데이터와 메서드를 응집력 있게 묶는 객체지향 프로그래밍의 핵심 원칙입니다.

b. 단일 책임 원칙(SRP)

응집력이 높은 클래스는 단일 책임 원칙(SRP, Single Responsibility Principle)을 따르는 경향이 있습니다. 클래스는 하나의 역할만 담당하며, 이 역할에 필요한 데이터와 메서드만 포함합니다.

5. 예시로 응집력 이해하기

데이터와 메서드가 응집력이 높은 경우

public class Item {
    private int stockQuantity;

    public Item(int stockQuantity) {
        this.stockQuantity = stockQuantity;
    }

    public void addStock(int quantity) {
        this.stockQuantity += quantity;
    }

    public void removeStock(int quantity) {
        if (quantity > stockQuantity) {
            throw new IllegalArgumentException("Not enough stock");
        }
        this.stockQuantity -= quantity;
    }

    public int getStockQuantity() {
        return stockQuantity;
    }
}
    

특징:

  • Item 클래스는 자신의 데이터(stockQuantity)를 직접 관리하고 변경합니다.
  • 외부에서 데이터에 접근하거나 수정하려면 반드시 addStock 또는 removeStock 메서드를 사용해야 합니다.
  • 클래스의 역할이 명확하고, 데이터와 메서드가 밀접하게 연관되어 있어 응집력이 높습니다.

데이터와 메서드가 응집력이 낮은 경우

public class ItemManager {
    public void updateStock(Item item, int quantity) {
        item.stockQuantity += quantity; // 직접 접근
    }

    public void logStock(Item item) {
        System.out.println("Stock: " + item.stockQuantity);
    }
}
    

문제점:

  • ItemManagerItem의 데이터를 직접 수정하고 관리합니다.
  • 데이터(stockQuantity)와 메서드가 분리되어 있어 응집력이 낮고, 데이터 보호(캡슐화)가 이루어지지 않습니다.
  • 로직이 여러 곳에 분산되어 유지보수가 어렵습니다.

6. 요약

  • 응집력(Cohesion): 클래스 내부의 데이터와 메서드가 얼마나 밀접하게 연관되어 있는지를 나타냅니다.
  • 높은 응집력:
    • 클래스의 데이터와 메서드가 밀접하게 연결되어 있습니다.
    • 객체지향의 원칙인 캡슐화단일 책임 원칙(SRP)을 따릅니다.
  •  

댓글