Frontend Engineer - 박준형

Published on

[ 객체지향의 사실과 오해 ] 스터디 1회

Authors
  • Name
    Twitter

객체란 무엇일까

객체지향이라는 패러다임에 처음 접근하는 사람들의 대부분은 객체지향이란 실세계를 직접적이고 직관적으로 모델링할 수 있는 패러다임이라는 설명을 보게된다. 여기서 핵심은 객체지향 프로그래밍이란 현실 속에 존재하는 사물을 최대한 유사하게 모방해 소프트웨어 내부로 옮겨오는 작업이기 때문에 객체지향 소프트웨어는 실세계의 투영이며 객체란 현실 세계에 존재하는 사물에 대한 추상화라한다.

하지만, 실세계 모방은 객체지향 철학적인 개념을 설명하는데는 적합하지만, 유연하고 실용적인 관점에서 객체지향 분석, 설계를 설명하는데에는 적합하지 않다고한다.

객체지향의 목표는 실세계를 모방하려는것이 아닌 새로운 세계를 창조하는 것이라한다. 소프트웨어 엔지니어의 역할은 단순히 실세계를 소프트웨어 안으로 옮기는것이 아닌, 고객과 사용자를 만족시킬 수 있는 신세계를 창조하는 것 이다 라고한다.

하지만 객체를 설명하는데 실세계에 빗대어 설명하는것만큼 효과적인것이 없어 잠시 동안만 실세계의 모방이라는 과거의 인습에 얽매일것이라고 한다.

커피공화국

요청과 응답으로 구성된 협력

커피공화국에는 커피를 주문하는 손님, 주문을 받는 캐셔, 커피를 제조하는 바리스타로 이루어져있다.

이들을 요청과 등답으로 구성된 협력관계라고 표현한다.

일상에서 발생하는 대부분의 문제는 개인 혼자만의 힘으로 버거울 정도로 복잡하기 때문에 사람들은 혼자서 문제를 해결하기보단 다른 사람들의 도움을 받아 문제 해결하는것을 선호한다.

일반적으로 하나의 문제를 해결하기 위해 다수의 사람 혹은 역할이 필요하기 때문에 한사람에 대한 요청이 또 다른 사람에 대한 요청을 유발하는 것이 일반적이다. 따라서 요청은 연쇄적으로 발생한다.

커피주문이라는 협력은 손님이 캐셔에게 원하는 커피를 주문하며 시작되고 주문을 받은 캐션느 주문 내역이 기록된 컵을 전달함으로써 바리스타에게 주문된 커피를 제조해줄것을 요청한다.

손님 --- 커피를 주문한다 --> 캐셔 --- 커피를 제조하라 --> 바리스타
손님 <-- 커피를 완성한다 --- 캐셔 <-- 커피를 완성하라 --- 바리스타

요청을 받은 사람은 주어진 책임을 다하며 필요한 지식이나 서비스를 제공한다. 즉 다른 사람의 request에 response한다. 요청이 연이어 발생하기 때문에 응답 역시 요청의 방향과 반대 방향으로 연쇄적으로 전달된다.

역할과 책임

역할은 어떤 협력에 참여하는 특정한 사람이 협력안에서 차지하는 책임이나 임무를 의미한다. 손님은 커피를 주문하는 임무를 맡게되고 캐셔는 손님으로 주문을 받아야하고, 바리스타는 주문된 커피를 제조해야할 책임이 있다.

역할이라는 단어는 의미적으로 책임이라는 개념을 내포한다. 특정한 역할은 특정한 책임을 암시한다. 협력에 참여하며 특정한 역할은 수행한느 사람은 역할에 적합한 책임을 수행하게된다.

특정한 역할을 맡고 역할에 적합한 책임을 수행한다는 사실은 몇가지 중요한 개념을 제시한다.

여러사람이 동일한 역할을 수행할 수 있다.

손님입장에선 커피를 마실 수 만있다면, 어떤 캐셔가 주문을 받는지는 중요하지않다. 캐셔가 그만두더라도 다른캐셔가 그역할을 대체한다면 손님입장에서는 상관이없고, 캐셔가 주문을 받고 커피가 완성되었다는 사실을 통보하는 책임만 이행한다면 OK다.

역할은 대체 가능성을 의미한다.

손님 입장에서는 캐셔는 대체가능하다. 둘중 한명이 동일한 역할을 수행할 수 있다면, 요청자 입장에서는 누가 수행하더라도 문제가 되지는 않는다.

책임을 수행하는 방법은 자율적으로 선택할 수 있다.

요청을 받은 사람들은 요청을 처리하는 방법을 자유롭게 선택할 수 있다. 바리스타는 커피 제조 요청을 받고 자신만의 독특한 방법으로 커피 제조를 할 수 있다. 이처럼 요청에 대해 서로 다른 방식으로 응답할 수 있는 능력을 다형성이라고한다.

한 사람이 동시에 여러 역할을 수행할 수 있다.

캐셔와 바리스타는 개별적인 역할을 이용해 협력관계를 묘사했지만, 한사람이 캐셔와 바리스타 두 역할을 동시에 수행할 수 도있다.

역할, 책임, 협력

기능을 구현하기 위해 협력하는 객체들

앞의 예시에서 사람을 객체로, 요청을 메세지로, 요청을 처리하는 방법을 메서드로 바꾸면 대부분의 설명을 객체지향이라는 문맥으로 옮길수 있다.

커피주문이라는 협력관계를 통해 알아본 역할, 책임, 협력의 개념을 객체지향이라는 문맥으로 옮겨본다.

역할과 책임을 수행하며 협력하는 객체들

사람들은 특정한 목표를 이루기 위해 서로 협력한다. 협력의 핵심은 특정한 책임을 수행하는 역할들 간의 연쇄적인 요청과 응답을 통해 목표를 달성한다는 것이다. 목표는 사람들의 협력을 통해 달성되며, 더 작은 책임으로 분할되고 책임을 수행할 수 있는 적절한 역할을 가진 사람에 의해 수행된다. 각 개인은 책임을 수행하기 위해 다른 이에게 도움을 요청하기도하며 이를 통해 연쇄적인 요청과 응답으로 구성되는 협력 관계가 구성된다.

객체의 세계는 현실세계와 유사하다고한다. 워드 커닝험(Ward Cunningham)켄트 벡(Kent Beck)은 어떤 객체도 섬이 아니라하며 객체 공동체 안에 성실히 살고있는 객체 시민은 자신에게 주어진 역할과 책임을 다하는 동시에 시스템의 더 큰 목적을 이루기 위해 다른 객체와도 적극적으로 협력한다 라고 설명한다.

애플리케이션은 객체들이 애플리케이션의 기능을 구현하기 위해 협력한다는 점이다.

기능은 더 작은 책임으로 분할되고, 책임은 적절한 역할을 수행할 수 있는 객체에 의해 수행된다. 객체는 자신의 책임을 수행하는 도중에 다른 객체에게 도움을 요청하기도하며, 결론적으로 시스템은 역할과 책임을 수행하는 객체로 분할되고 기능은 객체 간의 연쇄적인 요청과 응답의 흐름으로 구성된 협력으로 구현된다.

역할은 관련성 높은 책임의 집합이다. 객체의 역할은 다음과 같은 특징을 지닌다.

  • 여러 객체가 동일한 역할을 수행할 수 있다.
  • 역할은 대체 가능성을 의미한다.
  • 각 객체는 책임을 수행하는 방법을 자율적으로 선택할 수 있다.
  • 하나의 객체가 동시에 여러 역할을 수행할 수 있다.

역할은 유연하고 재사용 가능한 협력관계를 구축하는데 중요한 설계요소다.

협력속에 사는 객체

객체지향 애플리케이션의 윤곽을 결정하는것은 역할, 책임, 협력이지만 실제로 협력에 참여하는 주체는 객체다.

객체는 기능을 구현하기 위해 존재한다. 아주 작은 기능조차 객체 혼자 감당하기에는 버거울 정도로 복잡하고 거대하기 때문에 일반적으로 객체는 다른 객체와의 협력을 통해 기능을 구현하게 된다.

객체는 충분히 협력적이어야한다. 객체는 다른 객체의 요청에 충실히 귀 기울이고 다른 객체에게 적극적으로 도움을 요청할 정도로 열린 마음을 지녀야한다. 외부의 도움을 무시한 채 모든 것을 스스로 처리하려고 하는 객체는 내부적인 복잡도에 의해 자멸하게된다. 그렇다고 명령에 따라 수동적인 존재를 의미하는것은 아니다. 객체는 다른 객체의 명령에 복종하는 것이 아니라 요청에 응답할 뿐이다. 요청에 응할지 여부도 객체 스스로 결정할 수 있다.

객체는 충분히 자율적이어야한다. 자기 스스로 원칙에 따라 어떤 일을 하거나 자기 스스로를 통제하여 절제하는것을 의미한다.

상태와 행동을 함께 진니 자율적인 객체

흔히 객체를 상태와 행동을 함께 진니 실체라고 정의한다. 이 말은 객체가 협력에 참여하기 위해 어떤 행동을 해야한다면 그 행동을 하는데 필요한 상태도 함께 지니고 있어야 한다는 것을 의미한다. 커피를 제조하는 바리스타가 제조법을 모른다는것이 말이 안된느것처럼 객체가 어떤 행동을 하기 위해 필요한 상태를 알지 못한다는것도 말이 되지 않는다.

객체의 자율성은 내부와 외부를 명확하게 구분하는 것으로부터 나온다. 사적인 부분은 객체 스스로 관리하고 외부에서 일체 간섭할 수 없어야하며, 외부에서는 접근이 허락된 수단을 통해서만 객체와 의사소통해야한다. 객체는 다른 객체가 무엇을 수행하는지는 알수있지만, 어떻게 수행하는지에 대해서는 알 수 없다.

협력과 메세지

객체는 협력을 위해 다른 객체에게 메시지를 전송하고 다른 객체로부터 메시지를 수신한다. 따라서 객체지향의 세계에서 협력은 메시지를 전송하는 객체와 메시지를 수신하는 객체 사이의 관계로 구성된다.

메시지를 전송하는 객체를 송신자, 수신하는 객체를 수신자라고 부른다.

객체는 다른 객체와 협력하기 위해 메시지를 전송한다. 수신자는 메시지를 이해할 수 있는지 여부를 판단한후 자신만의 방법에 따라 메시지를 처리한다. 이를 메서드라고 부른다.

객체지향 프로그래밍 언어에서 메서드는 클래스 안에 포함된 함수 또는 프로시저를 통해 구현된다. 따라서 어떤 객체에서 메시지를 전송하면 결과적으로 메시지에 대응되는 특정 메서드가 실행된다.

메시지를 수신한 객체가 실행 시간에 메서드를 선택할 수 있다는 점은 다른 언어와 객체지향 언어를 구분 짓는 핵심특징 중 하나다.

손님은 커피를 주문하며 커피가 완성되는것에는 기대하지만, 캐셔가 바리스타에게 어떻게 전달하는지와 바리스타가 커피를 어떻게 제조하는지에대해서는 관여하지 않는다. 각 객체는 커피 제조라는 메시지에 응답하기 위해 자신만의 자율적인 방법에 따라 커피를 제조할 수 있다.

외부의 요청이 무엇인지 표현하는 메시지와 요청을 처리하기 위한 구체적인 방법인 메서들르 분리하는 것은 객체의 자율성을 높이는 핵심 메커니즘이다. 이것은 캡슐화라는 개념과도 깊이 관련되어있다.

본질

  • 객체지향이란 시스템을 상호작용하는 자율적인 객체들의 공동체로 바라보고 객체를 이용해 시스템을 분할하는 방법이다.
  • 자율적인 객체란 상태와 행위를 함께 지니며 스스로 자기 자신을 책임지는 객체를 뜻한다.
  • 객체는 시스템의 행위를 구현하기 위해 다른 객체와 협력한다. 각 객체는 협력 내에서 정해진 역할을 수행하며 역할은 관련된 책임의 집합이다.
  • 객체는 다른 객체와 협력하기 위해 메시지를 전송하고, 메시지를 수신한 객체는 메시지를 처리하는데 적합한 메서드를 자율적으로 선택한다.

객체를 지향하라

많은 사람들은 객체지향이라는 말을 들으면 조건반사적으로 클래스라는 단어를 떠올린다. 어떤 객체지향 프로그래밍 언어를 이야기할 때 대부분의 사람들은 클래스를 정의하는 방법과 클래스 사이의 상속에 초점을 맞춘다. UML의 가장 대표적인 다이어그램으로 클래스 다이어그램을 꼽는다. 하지만 앞서 말했던 객체지향의 분석, 설계의 목적은 훌륭한 클래스를 식별하는 것이라고 말하지않았다.

클래스가 객체지향 프로그래밍 언어의 관점에서 매우 중요한 구성요소인것은 분명하지만 핵심을 이루는 중심 개념이라고 말하기에는 무리가있다. 자바스크립트 같은 프로토타입 기반 객체지향 언어에는 클래스가 존재하지 않으며 오직 객체만이 존재한다. 프로토타입 기반 객체지향 언어에서는 상속 역시 클래스가 아닌 객체 간의 위임 메커니즘을 기반으로 한다.

지나치게 클래스를 강조한느 언어적인 관점은 객체의 캡슐화를 저해하고 클래슬르 서로 강하게 결합시킨다. 애플리케이션을 협력하는 객체들의 공동체가아닌 클래스로 구성된 설계도로 보는 관점은 유연하고 확장가능한 애플리케이션 구축을 방해한다.

클래스의 구조와 메서드가 아닌 객체의 역할 책임 협력에 집중하라. 객체지향은 객체를 지향하는것이지 클래스를 지향하는것이 아니다.