협력하는 객체들의 공동체
- 협력의 풍경
- 요청과 응답으로 구성된 협력
- 역할과 책임
- 상태와 행동을 가진 자율적 존재
- 메시지와 자율성
- 객체지향의 본질
객체지향은 클래스가 아니라 협력이야. 대부분의 개발자가 객체지향을 배울 때 클래스, 상속, 캡슐화부터 시작하잖아. 저자 조영호는 그 순서가 근본적으로 잘못됐다고 보거든.
저자는 커피 주문이라는 일상적인 장면으로 시작하지. 카페에 가면 손님이 주문하고, 캐셔가 주문을 받고, 바리스타가 커피를 만들잖아. 이 세 사람은 각자의 역할을 가지고, 각자의 책임을 수행하며, 서로 요청과 응답을 주고받으면서 하나의 목표(커피를 만들어 손님에게 전달)를 달성해.
이게 바로 객체지향의 본질이라는 거지. 객체지향 시스템은 객체들이 협력하는 공동체야. 클래스 다이어그램을 그리는 게 아니라, 객체들이 어떻게 협력하는지를 설계하는 것이 먼저라는 이야기.
협력은 구체적으로 어떻게 이뤄지냐면, **요청(request)**과 **응답(response)**이야.
손님이 캐셔에게 "아메리카노 한 잔 주세요"라고 요청하지. 캐셔는 바리스타에게 "아메리카노 하나 만들어주세요"라고 다시 요청해. 바리스타가 커피를 만들어서 응답하고. 이 요청-응답의 연쇄가 협력의 실체야.
여기서 중요한 건 요청을 받은 쪽이 스스로 판단해서 응답한다는 점이지. 캐셔가 바리스타에게 "원두를 15그램 넣고 92도 물을 250ml 부어"라고 지시하지 않잖아. 그냥 "아메리카노 하나"라고 요청할 뿐이야. 어떻게 만들지는 바리스타가 알아서 결정하거든.
이 비유가 객체지향에서 왜 중요하냐면 — 객체 간의 상호작용도 이래야 한다는 거지. 하나의 객체가 다른 객체의 내부를 이리저리 건드리면서 일을 시키면 그건 협력이 아니라 통제야. 요청만 보내고, 응답을 받으면 돼.
협력이 가능하려면 참여자 각각에게 **역할(role)**이 있어야 하고, 그 역할에 따른 **책임(responsibility)**이 있어야 하지.
손님의 역할은 주문하는 것, 캐셔의 역할은 주문을 받고 전달하는 것, 바리스타의 역할은 커피를 만드는 것. 이 역할들이 겹치지 않으면서도 빈틈없이 전체 협력을 커버해.
역할의 핵심적인 특징 두 가지가 있어:
- 대체 가능성 — 역할은 특정 사람에 묶이지 않아. 바리스타가 누구든 간에 "아메리카노를 만들 수 있다"는 역할을 수행할 수 있으면 되거든. 오늘 근무하는 바리스타가 내일 바뀌어도 카페는 돌아가지. 이게 객체지향에서 **다형성(polymorphism)**의 근원이야.
- 다중 역할 — 한 사람이 여러 역할을 맡을 수도 있어. 작은 카페에서는 캐셔가 바리스타 역할도 겸하잖아. 객체도 마찬가지로 여러 역할을 동시에 수행할 수 있지.
저자가 여기서 강조하는 건, 객체지향 설계의 출발점은 클래스가 아니라 역할과 책임을 식별하는 것이라는 점이야. 어떤 역할이 필요하고, 그 역할이 어떤 책임을 져야 하는지를 먼저 정하고, 그다음에 그 역할을 수행할 객체를 결정하는 순서가 올바르지.
객체란 뭐냐면, **상태(state)**와 **행동(behavior)**을 가진 자율적 존재야.
바리스타를 예로 들면, 바리스타는 자신의 상태(기술 수준, 컨디션, 사용 가능한 재료 등)를 가지고 있고, 행동(커피를 만드는 것)을 수행할 수 있지. 그리고 자율적으로 판단해. 어떤 원두를 쓸지, 물 온도를 몇 도로 할지는 바리스타가 자기 상태와 판단에 따라 결정하거든.
이 "자율적"이라는 단어가 핵심이야. 객체는 수동적인 데이터 덩어리가 아니지. 스스로 판단하고 행동하는 능동적 존재야. 이게 절차지향과 객체지향의 근본적인 차이거든. 절차지향에서는 데이터가 있고 그 데이터를 처리하는 프로시저가 따로 있잖아. 객체지향에서는 데이터와 프로시저가 하나의 자율적 단위로 묶여 있지.
객체들은 어떻게 소통하냐면, **메시지(message)**를 통해서야.
앞에서 나온 "요청"이 프로그래밍 세계에서는 메시지가 되지. 한 객체가 다른 객체에게 메시지를 보내면, 받는 쪽이 그 메시지를 어떻게 처리할지 스스로 결정해. 이게 **메서드(method)**야. 메시지를 받으면 어떤 메서드를 실행할지는 수신자가 결정하는 거지.
메시지를 보내는 것과 메서드를 호출하는 것을 구분하는 게 중요해. 많은 개발자가 이 둘을 같은 것으로 취급하는데, 개념적으로는 달라. 메시지를 보내는 건 "무엇을 해달라"는 요청이고, 메서드는 그 요청을 "어떻게 처리할지"에 대한 수신자의 결정이거든.
이 구분이 중요한 이유는 자율성 때문이야. 메시지를 보내는 쪽은 수신자가 어떤 메서드로 처리할지 몰라. 알 필요도 없지. 그냥 "이거 해줘"라고 요청하고, 결과만 받으면 돼. 수신자의 내부 구현에 의존하지 않는 것 — 이게 캡슐화의 본질이고, 유연한 설계의 기반이야.
저자가 말하는 객체지향의 본질은 이거야:
- 객체지향은 협력하는 객체들의 공동체를 설계하는 것이야
- 협력은 요청과 응답의 연쇄로 이뤄지지
- 각 객체는 역할과 책임을 가져
- 객체는 상태와 행동을 갖춘 자율적 존재야
- 객체 간 소통은 메시지를 통해 이뤄지며, 수신자의 자율성이 보장되어야 해
클래스, 상속, 인터페이스 같은 프로그래밍 언어 차원의 메커니즘은 이 본질을 구현하기 위한 도구일 뿐이지. 도구부터 배우면 본질을 놓치기 쉽다는 게 저자의 문제의식이고, 이 책 전체가 그 문제의식에서 출발해.
정리
1장 읽고 기억할 거 세 가지:
- 객체지향 = 클래스가 아니야. 객체지향의 핵심은 협력이고, 클래스는 그걸 구현하는 도구일 뿐이지
- 요청만 보내고 방법은 맡겨라. 객체의 자율성을 보장하는 것이 좋은 객체지향 설계의 시작이야
- 역할과 책임을 먼저 식별해라. 클래스를 먼저 그리지 말고, 어떤 역할이 필요하고 각 역할이 어떤 책임을 져야 하는지부터 생각해