프로젝트

[Next Step 사전과제] 도메인 설계(1) - 행동과 책임

nkdev 2025. 9. 18. 17:00

책임 주도 설계(RDD, Responsibility-Driven Design)의 핵심은 ‘행동’을 먼저 정하고, 그 행동을 수행할 책임을 누가 질 것인가? 이다.

그렇다면 해당 요구사항에서 행동이 뭔지 정의하고 나서 그 행동을 하는 객체를 선정해보자.

 

'상영한다' -> 영화

'예매한다' -> 손님

'좌석을 선택한다' -> 손님

 

처음에 책임과 그 책임을 수행할 객체를 선정했던 방식이다.

'~~한다'라는 행동을 모두 책임으로 선정하고, 그 책임을 수행할 객체를 할당했다.

 

이렇게 자연어로 된 '~~한다'라는 '행동'을 발견했다고 얘네를 곧바로 객체가 수행할 책임'으로 정의하면 안 된다.

행동은 단지 '시스템이 사용자에게 제공해야할 기능(use case)'를 드러내는 것이고, 

책임은 '어떤 객체가 그 행동을 통해 보장해야 할 것'을 의미한다.

 

그래서 행동은 책임의 후보가 될 수 있는 것으로 이해해야 한다. 모든 행동을 곧바로 메서드로 옮기기보다는, 그 사이에 정제하는 과정이 필요하다. 행동이 책임이 되기도 하지만, 무조건 1:1 대응이 되는 건 아니다. 중요한 건 그 행동을 수행할 책임을 어떤 객체가 맡아야 하는지 정하는 것이고, 그래야! 객체지향스러운 책임 할당이 가능하다.

 

저렇게 행동을 곧바로 책임으로 보게 되면

class User {
    public void selectSeat(Seat seat) {
        // 좌석을 직접 예약 처리
        if (!seat.isReserved()) {
            seat.setReserved(true);
        } else {
            throw new IllegalStateException("이미 예약된 좌석입니다.");
        }
    }
}

이렇게 User가 좌석이 어떻게 예약되는지 다 알아야 하고, User가 Seat 내부 상태까지 모두 변경시키게 되므로 두 객체가 종속관계가 되어버린다. 응집도가 낮아지고 결합도가 높아짐

 

반면 행동을 '객체의 책임'으로 재정의한 경우

class User {
    public Reservation reserve(Seat seat, Showing showing) {
        // 좌석에게 '선택 요청'만 보냄
        seat.reserve();  
        return new Reservation(this, showing, seat);
    }
}

class Seat {
    private boolean reserved;

    public void reserve() {
        if (reserved) {
            throw new IllegalStateException("이미 예약된 좌석입니다.");
        }
        this.reserved = true; // Seat가 자기 상태를 스스로 변경
    }

    public boolean isReserved() {
        return reserved;
    }
}

User는 좌석이 어떻게 예약되는지 몰라도 되고, 단지 Seat에게 reserve()메시지를 던지면 된다. 

Seat는 자기 상태(reserved)를 스스로 관리하는 자율적인 객체가 된다.

만약 좌석 예약 조건이 새로 생기거나 수정되어도 Seat객체만 수정하면 된다.