객체지향의 사실과 오해라는 책을 읽으면서 새롭게 알게된 점, 그리고 우아한테크코스 7기의 프리코스 마지막 미션 편의점을 수행하면서 느낀 점을 함께 적어보고자 합니다. 한 편의 독후감이자 회고가 될 수 있겠네요.
1. 어떠한 관점으로 객체를 바라볼 것인가?
필자는 객체를 그저 인스턴스의 한국말이라고 생각했습니다. 클래스를 바탕으로 생성되는, 실제 힙 메모리에 할당되는 데이터라고만 생각했습니다. 하지만, 이는 이 책에서 언급하는 객체에 대한 하나의 오해였다는 걸 깨달았습니다.
객체지향에서의 제대로 객체를 이해하기 위해서는 나무가 아닌 숲을 봐야만 합니다.
Car라는 클래스를 통해 생성한 객체를 바라본다면, 그 객체가 갖고 있는 필드 혹은 메서드에만 집중해서는 안됩니다.
그 객체가 해당 어플리케이션에서 어떠한 책임을 갖고 있으며, 어떠한 역할을 수행하고 있는가?를 바라보아야 합니다.
올바른 객체를 설계하기 위해서는 먼저 견고하고 깔끔한 협력을 설계해야 한다.
협력을 설계한다는 것은 설계에 참여하는 객체들이 주고받을 요청과 응답의 흐름을 결정한다는 것을 의미한다.
이렇게 결정된 요청과 응답의 흐름은 객체가 협력에 참여하기 위해 수행될 책임이 된다.
객체지향의 사실과 오해 129P
객체를 구상하기 위해서는 먼저 어떠한 협력을 할 것인지를 결정해야 합니다. 이번 프리코스 4주차의 편의점 미션은 하나의 객체로는 절대로 원하는 프로그램을 만들 수 없습니다. 따라서 객체와 객체가 서로 도와야만 합니다. 즉, 요구사항을 바탕으로 어떠한 협력을 할 것인지를 먼저 정해야했습니다.
4주차 미션에서는 재고 관리 / 프로모션 할인 / 멤버십 할인 / 영수증 출력이라는 네 가지의 큰 협력이 필요했습니다.

당시 미션을 수행하면서 작성했던 설계도입니다. 굉장히 정신없지만, 무엇보다도 이들이 어떠한 협력을 수행하고 있는가가 드러나있지 않았어요. 단순히 프로그램의 흐름만을 정리한 느낌이 강했습니다. 그리고, 개념적인 관계보다는 실제로 구현할 클래스로만 표현되었다는 점에서 객체 간 협력을 고려하지 않았다는 걸 알 수 있었습니다.
2. 결합도가 낮은 설계를 하려면?
이번 편의점 미션을 수행하면서, 가장 부족했다고 느꼈던 건 객체 간 결합도가 높았다는 점이었습니다.
특히, 객체가 다른 객체에게 메서드를 호출할 때, 불필요한 데이터까지 같이 넘기는 경우가 많았습니다.
public static Product createDefault(final ProductDto dto) {
return new Product(new Tag(dto.name(), dto.price()), 0);
}
이는 당시에 제가 작성했던 정적 팩토리 메서드 중 하나였습니다.
ProductDto의 정보를 토대로 Product를 생성하는 메서드였습니다.
ProductDto가 갖고 있는 이름과 가격 정보를 바탕으로 Tag를 생성하고 수량이 0인 Product를 생성하는 코드입니다.
그런데 꼭 dto 전부를 넘겼어야 할까요?
public static Product createDefault(final String name, final int price) {
return new Product(new Tag(name, price), 0);
}
이렇게 이름과 가격만 전달하면 Product는 ProductDto의 내부를 몰라도 되며, ProductDto의 내부가 변경되더라도 그 영향을 받지 않습니다. 이렇게 해도 정상적으로 동작하는 이유는 Product의 createDefault는 단순히 수량이 0인 기본 Product를 생성하는 책임을 갖고 있기 때문입니다. 이름과 가격만 전달받는다면, 수량이 0인 Product는 얼마든지 생성할 수 있는 것이죠.
객체가 어떤 메시지를 수신하고 처리할 수 있느냐가 객체의 책임을 결정한다.
책임-주도 설계 방법에서는 What/Who 사이클에 따라 협력에 참여할 객체를 결정하기 전에
협력에 필요한 메시지를 먼저 결정한다. 메시지가 결정된 후에야 메시지를 수신할 후보를 선택하는 것으로
초점이 이동한다.
객체지향의 사실과 오해 159P
수량이 0인 기본 Product를 생성하라는 메시지를 전달하기로 했다면, 그 메시지 전달에 필요한 값만 전달하면 되는 것입니다. ProductDto를 통째로 전달할 필요가 없던 것이죠.
이러한 사소한 행동 하나하나가 쌓여서 프로그램의 결합도의 수준을 결정할 것이라는 사실을 알 수 있었습니다. 이는 곧, 객체의 자율성에 영향을 주기도 합니다. ProductDto를 전달한다면, ProductDto가 아니면 기본 Product를 생성할 수 없는 것이죠. 이름과 가격만 전달하면 그 내부에서는 이를 어떻게 결정할 지 그 객체가 스스로 결정할 자율성을 보장하지 못하게 됩니다. 객체의 자율성에 대한 이야기는 다음 장에서 언급하겠습니다.
3. What/Who 사이클
What/Who 사이클이라는 용어가 의미하는 것은 객체 사이의 협력 관계를 설계하기 위해서는 먼저 '어떤 행위(what)'를 수행할 것인지를 결정한 후에 '누가(who)' 그 행위를 수행할 것인지를 결정해야 한다는 것이다. 여기서 '어떤 행위'가 바로 메시지다.
객체지향의 사실과 오해 158P
올바른 객체지향을 설계하기 위해서는 어떻게(How)가 아니라 무엇을(What) 할 지 결정해야 합니다. 협력을 하기 위해 무엇을 할지 결정한다면, 그 뒤에 이것을 누가 수행할 지 결정하는 과정에서 객체가 결정될 것입니다. what은 메시지라고 할 수 있는데요. 객체와 객체는 이 메시지를 통해서만 협력할 수 있습니다. 이를 통해, 객체의 결합도를 낮추는 것이죠.
USB와 노트북이 서로 연결하려면 노트북에 USB 포트가 있어야 합니다. 이는 곧, 인터페이스를 의미하는데요. 서로 다른 메커니즘으로 구현된 두 객체가 하나의 협력을 수행하기 위해서는 반드시 인터페이스가 존재해야 합니다.
객체지향에서의 메서지는 곧, 인터페이스이기도 합니다. 서로 다른 관심사와 책임을 갖는 두 객체가 협력하기 위해 필요한 것이죠. 따라서 메시지에는 무엇(what)에 대한 정보만 있어야 합니다. 구체적인 방법인 how가 메시지에 담겨있다면, 불필요한 책임까지 넘기게 됩니다.
앞서 기본 Product를 생성하는 createDefault의 경우, 수량이 0인 Product를 생성한다라는 메시지를 전달하는 것입니다.
그런데 이 메시지에 ProductDto를 같이 담아 전달한다면, 이는 곧 ProductDto를 사용해서 Product를 생성하라는 메시지로 변질됩니다. 이는 what + how가 되어 버립니다.
Product가 ProductDto를 사용하면 안된다는 요구사항이 생긴다면? createDefault의 시그니처를 변경해야 하며, 이는 createDefault를 사용하는 모든 곳에서 변경이 일어납니다. What/Who 사이클을 알게 된 후라면, 이름(name)과 가격(price)만 전달하고, 그 뒤로는 알아서 해!라는 메시지로 바꿀 수 있겠네요.
이처럼 What/Who 사이클을 통해 객체 간 결합도를 낮춤과 동시에 각 객체를 자율적으로 만들 수 있습니다.
앞으로 서류 발표까지 남은 기간동안 기출문제를 풀어볼텐데 그 때는 협력의 관점으로 문제를 접근하고, 무엇을 해야 할지와 그에 따른 메시지를 선정하는 연습을 해야할 것 같습니다.
참고 자료 :
객체지향의 사실과 오해 | 조영호 - 교보문고
객체지향의 사실과 오해 | 객체지향에 대한 선입견을 버려라!『객체지향의 사실과 오해』는 객체지향이란 무엇인가라는 원론적면서도 다소 위험한 질문에 답하기 위해 쓰여진 책이다. 안타깝
product.kyobobook.co.kr
'소프트웨어 개발 이론' 카테고리의 다른 글
JIRA를 활용한 프로젝트 업무 관리 - 대학생 버전 (0) | 2024.02.16 |
---|---|
요구사항 도출하기 (0) | 2024.02.11 |