본문 바로가기
독서에서 한걸음

[오브젝트] 책임 중심 설계와 데이터 중심 설계 (1)

by oncerun 2023. 2. 25.
반응형

 

조영호 님의 Object라는 책을 통해 객체지향 설계와 데이터 중심 설계에 대한 이야기를 읽었다. 

 

객체지향 설계에 대한 가장 중요한 요소는 책임이라는 설명과 이를 객체의 상태에 맞춰 설계를 하면 유연성이 사라지고 높은 의존성과 낮은 응집도를 통해 변경에 취약해진다고 한다. 

 

실제 예시에 대한 설계를 보면서 데이터 중심 설계의 문제를 하나씩 리뷰해 보자. 

 

설계의 기초는 도메인에 대한 이해다. 다만 해당 내용은 책의 내용으로 밝히지 않고 진행하려고 한다.

 이 책은 객체지향의 사실과 오해를 읽고 그 다음 순서로 읽는 것을 추천하고 개발자라면 두세 번은 아니더라도 한 번은 꼭 읽어 봤으면 좋겠다. 

 

 

책임을 중심으로 설계를 진행할 때 해결하려는 문제를 큰 협력이라는 틀을 잡고 이 큰 협력을 해결하기 위해 작은 협력으로 나눈다. 그리고 그러한 협력을 완성하기 위해 어떠한 역할이 있는지 확인한다.  역할이 정의됐다면 이는 역할마다의 책임이 할당되어 적합한 객체를 생성하게 된다.

 

이때 책임이 무엇인가라는 질문을 통해 가장 먼저 책임을 판별하는 고민을 하게 된다. 

이러한 반복과정을 통해 서로 협력하여 도메인의 문제를 해결하고 이 과정에서 수많은 트레이드오프를 겪으면서 설계를 완성하게 된다고 생각했다. 

 

예를 들어 카페를 운영한다고 생각해보자. 코로나로 인해 손님들의 백신접종 여부를 판별한 후 입장하고 주문을 해야 한다.

 

카페 도메인에서 입장에 관한 협력에서 해결하려는 문제는 카페의 입장 시 코로나 백신 접정 여부 확인 후 입장하는 것이다. 

 

손님이 주문을 하는 과정까지 정리하면 글이 길어지므로 입장에 관련된 부분의 책임만 추려보자. 

 

1. 손님이 입장한다. 

2. 코로나 백신접종 여부를 판별한다. 

 

손님이라는 역할이 존재하고 이 역할은 입장하는 책임이 있다. 

카페는 손님이 어떻게 입장하는지 상관없다. 이 행동은 자율적인 손님이 알아서 할 문제이다.  

 

이를 인터페이스를 통해 나타내보자.

public interface Customer {

    public boolean enter();
    
}

 

내 첫 설계는 다음과 같이 작성했었다. 

 

" 손님이 입장한 후 코로나 예방접종 검사결과를 반환한다 "

 

이것은 조금 생각해 보면 유연하지 않은 설계이다.  손님이 입장 시 코로나 예방접종을 검사할 것이라는 의도가 표현되어 있기 때문에 이를 구현한 클래스들은 예방접종 검사하는 기간이 끝나면 영향을 받게 된다. 

그리고 어떤 카페에 입장하는지도 표현되지 않은 것 같다. 다시 한번 생각해 보자. 

카페는 손님이 알고 있어야 하는 정보다. (적어도 이 조그마한 협력에서는) 

 

 

다음과 같이 예시를 들어보자. 

 

손님이 건물에 도착했다. 카페에 입장을 했으면 메뉴판을 받아야 한다.

그러니까 이 책임은 카페에 입장하고 검사받고 메뉴판을 반환하는 것까지의 책임이 있다고 하자.

public interface Customer {
    Menu enter(Cafe cafe);
}

( 아.. Mene라는 네이밍이 맞나.. Menu의 복수형은 없는데. 그래도 MenuList보단 나을 것 같은데.)

 

여기까지 손님이라는 역할과 입장이라는 책임을 부여했다.

 

 

두 번째는 코로나 예방접종을 검사하는 것이다.  이 역할의 책임은 손님의 예방접종을 확인하는 것이다. 

public interface VaccinationStatusChecker {
    boolean isVaccinationCompleted(Customer customer);
}

 

 

협력과 역할, 책임이라는 것을 지속적으로 인식하면서 설계를 할 때 역할이 여러 개로 분할될 수 있다고 자꾸 가정하는 것 같다. 

책에서 이러한 고민에 대한 조언은 이러한 역할의 책임을 처리하는 객체가 단 하나밖에 없으면 이를 객체로 일치화 시켜도 된다고 했다. 

 

하지만 내가 만든 예시에서 예방접종을 하는 객체는 여러 개일 수 있고 (실세계에서 고장으로 인해 기계가 변경된다거나 등등..)  손님도 드라이브쓰루 고객일 수도 있고, 단순 걸어서 입장하는 손님 등등 다양한 손님 유형이 있다고 판단해서 인터페이스로 만들었다. 

 

 

잠깐! 정리

 

1. 손님 역할은 입장하는 책임이 있다. 

 

2. 카페는 손님을 받고 검사해야 하는 책임이 있는데, 이를 위해선 몇 가지 정보가 필요하다. 

 

메뉴라는 상태와 백신접종여부를 검사하는 상태를 알고 있어야 책임을 수행할 수 있다. 

 

3. 카페는 손님이 입장하면 VaccinationStatusChecker에게 백신접종을 확인해 달라고 메시지를 보낸다. 

 

4. VaccinationStatusChecker는 상태를 점검한다. 이 결과에 따라 손님이 카페에 입장하거나 그럴 수 없을 것이다. 

 

이를 구현하면 다음과 같다.

 

public class WalkInCustomer implements Customer{

    @Override
    public Menu enter(Cafe cafe) {
        return cafe.check(this)
                .orElseThrow(() -> new SorryException("미안해요.. 정책이 그래서.."));
    }
}

 

만약 손님을 더 구현한다면 check 할 때 필요한 예방접종 서류라던지, QR 코드라던지 협력에 필요한 상태가 더 있어야 할 것이다. 

 

즉 손님은 협력안에서 enter라는 메시지를 받으면 자기가 알고 있는 여러 정보를 토대로 처리하거나 다른 객체에게 메시지를 통해 위임한다. 

 

public class FoodCafe implements Cafe{

    private Menu menu;
    private VaccinationStatusChecker checker;

    @Override
    public Optional<Menu> check(Customer customer) {
        if (checker.isVaccinationCompleted(customer)) {
            // 손소독제 바르고 뭐하고..
            return Optional.of(menu);
        }
        return Optional.empty();
    }
}

 

Cafe는 검사해 달라는 요청을 받았다. cafe 자신이 백신접종 여부를 처리할 수 없으니 이를 담당하고 있는 백신상태검사기에게 이를 요청하고 그에 따른 적절한 반환 값을 준다. 

 

이게 도메인이 너무 구체적이지 않아서 구현할 때도 수많은 고민을 하게 된다. 

예제를 만들면서도 느끼지만 역시 구체적인 도메인은 개발을 편하게 하고 도메인에 대한 꼼꼼한 이해는 유연한 설계를 만드는 토대라고 생각된다. 

 

 

이제 다음글에는 데이터 중심으로 설계한 경우를 살펴보자. 

 

반응형

'독서에서 한걸음' 카테고리의 다른 글

[오브젝트] 데이터 중심 설계(3)  (0) 2023.02.26
[오브젝트] 책임 중심 설계와 데이터 중심 설계 (2)  (0) 2023.02.26
아싸  (0) 2023.02.20
읽고 싶은 책이 늘었다.  (0) 2023.02.06
debounce  (0) 2023.01.21

댓글