Lee's Grow up

[독서리뷰] 객체지향의 사실과 오해 리뷰 본문

일상/독서

[독서리뷰] 객체지향의 사실과 오해 리뷰

효기로그 2020. 3. 19. 14:08
반응형

이책을 처음 알게된 시점은 인프런의 김영한님의 JPA 강의를 보는데 강의 초반에 해당 책을 짧게 소개해주면서 강의를 진행했습니다. 그리고 강의를 계속 보는데 객체적인 관점?에 대해 강조를 많이 하시고, 실제 듣다 보면 나도 객체지향적인 프로그래밍 방식을 사용하고 있지 않구나라는 생각이 들어 해당 책을 구매해서 읽어 보고 독후감 같은 느낌으로 내용을 정리해봅니다.

시작하며

사실 객체 지향하면 떠오르는 추상화, 캡슐화, 상속, 다형성 4개의 단어가 떠오릅니다.
그리고 우린 이러한 객체 지향이란 특성을 이해하기 위해서 실제 세계를 기반으로 객체의 개념을 이해했습니다.
예를 들어 저는 클래스는 붕어빵틀이고 객체는 붕어빵이다 라는 문구를 통해 객체 = 클래스 라는 개념이 머리속에 자리잡혔던 것 같습니다. 이 책은 이런 저를 비웃기라도 하듯 객체란 무엇인지 부터 설명을 시작합니다.

객체지향의 목표는 실세계를 모방하는 것이 아니다, 오히려 새로운 세계를 창조하는 것이다.

객체란 실 세계를 모방하는 것이 아니다. 우리는 객체를 이해하기 위해 실세계를 모방 해왔습니다. 예를 들어 자동차 클래스를 만들고, 핸들, 기어 등을 가지며 전진, 후진 등의 기능을 가진 객체를 만들면서 객체의 속성과, 기능을 배워왔습니다. 하지만 실제로 프로그랭을 하면서 자동차, 붕어빵 등의 클래스를 만든 기억이 존재하나요? 물론 누군가는 있을수도 있지만 거의 존재하지 않습니다. 그렇다면 현실과 객체의 세계는 어떤 부분이 다를지 생각해봅니다.

객체간 메세지를 전달하며 상호 간 협력하는게 객체 지향입니다. 앞서 언급한 자동차의 경우 실 세계에선 '사람'이 '자동차'의 시동을 걸고, 주행을 할 뿐입니다. 그러나 객체 세계에서의 자동차는 스스로 시동걸기와, 주행의 기능을 가지고 있습니다. 그리고 '사람'은 '자동차'에게 요청(메세지)를 보낼 뿐입니다. 객체 세계에서의 자동차는 마치 하나의 생명체 같이 메세지를 받으면 자율적으로 메세지에 대한 처리를 합니다.

결론 : 실제는 객체와 현실은 전혀 다른 세계이기 때문에 그 차이를 인지하고 객체지향적으로 접근하는 것

그래서 객체란 무엇이고 객체 지향의 본질은 무엇인데?

이 책에서는 객체가 객체 답기 위해선 아래 3가지를 충족해야 한다고 정의합니다
  • 객체는 협력적이어야 한다. 혼자 모든걸 해결하려 하지 말아라.
  • 객체는 자율적이어야 한다.
  • 데이터와 프로세서를 분리하지 않고, 둘다 스스로 가짐으로써 자율적인 존재이다.

객체는 자율적이어야 한다에 대해서 조금 더 설명을 하자면, 객체는 요청(메세지)에 따라 스스로 판단하고, 행동할 수 있어야 된다는 말입니다.

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

여기서 1,2번은 앞서 설명한 내용과 중복이 됩니다. 그만큼 이 책에서 강조하는 부분이라 생각합니다. 추가로 눈치가 빠르신 분들은 객체라는 단어 말고 역할, 책임, 협력, 메세지,라는 단어가 계속 반복해서 나오는걸 눈치채셨을 겁니다. 이 키워드들은 앞으로 계속 강조되는 부분이니 기억해두길 바랍니다.

객체의 행동, 상태, 식별자

우리는 방금까지 객체는 어때야 하고, 객체 지향이란 어떤것인지에 대해 알아봤습니다. 이제 객체란 무엇인지 조금 더 구체적으로 설명을 합니다. 이 책인 객체를 다음과 같이 정의합니다.

  • 객체란 식별 가능한 개체 또는 사물이다. 구체적인 사물또는 추상적인 개념일 수 있다.

이러한 객체들의 상태를 변경할 수 있는것은 오로지 객체 자신의 행동입니다. 여기서 행동에 대해서 이책은 아래와 같이 정의합니다.

  • 행동이란 외부의 요청 또는 수신된 메세지에 응답하기 위해 동작하고 반응하는 활동. 활동의 결과로 객체는 자신의 상태를 변경하거나 객체에게 메세지를 전달할 수 있다.

마지막으로 식별자란 말 그대로 객체는 식별이 가능하다는 뜻입니다. 현실 세계이든 객체 세계이는 상태의 변화는 존재합니다. 여기서 우리가 Member member = new Member 이라고 선언 후, member.setName("Lee") 로 객체를 선언했고, 동일하게 member2 객체를 만들어준다. 이때 name이 같다고 해서 두 객체는 같은 객체라고 할 수 있는가? 당연히 아닙니다. name이 동등할 뿐이지 두 객체가 동일하지는 않다는 말입니다.

모든 것은 행동이 상태를 결정한다

위 주제가 핵심 주제라고 생각합니다. 예를 들어 우리가 Car 클래스를 하나 만든다고 생각해봅니다. 이때 우리는 어떻게 합니까? 저의 경우 아래와 같이 행동 할 것 입니다.

  1. 클래스를 하나 생성한다.
  2. 속성을 정한다. id 값을 넣고, 자동차의 모델명, 색상, 바퀴 등등등..

이 책은 이와 같은 접근 방법은 잘못되었다고 정의합니다. 우리가 만드는 협력 속에서 Car 객체는 어떤 객체와 어떤 메세지를 주고 받을지 예상을 하고 객체의 속성을 결정하는가? 즉 행동을 생각한 후 행동을 수행할 객체를 선택, 필요한 속성이 결정되어야 합니다.

협력안에서의 객체의 행동은 객체가 완수해야할 책임이라고 표현합니다. 따라서 어떤 행동 즉 책임이 필요한가를 결정하는 과정이 전체 설계를 주도해야 합니다. 이에 따라 객체가 선택되고 속성이 정의되어야 합니다. 이 같은 방법을 따르면 응집도 높고 재사용이 가능한 객체를 만들 수 있게 해줍니다.

타입과 추상화

도로 위 여러 종류의 승용자, 트럭, 화물차 등이 달리고 있을 때 우리는 '차'라는 분류로 하나로 묶을 수 있다. 이와 같이 사물들의 공통접을 취하고 차이점은 버리는 일반화를 통해 단순화하는 것을 추상화라고 합니다.

객체지향에서의 추상화는 중요합니다. 이런 추상화를 통해서 나오는게 객체의 타입입니다.
그렇다면 타입을 결정짓는 요소는 무엇인가? 결국엔 여기서도 행동이다. 어떤 행동에 따라 객체들을 분류하고, 추상화해서 타입이 결정된다. 그리고 이러한 타입을 구현할 수 있는 한가지 방법이 클래스일 뿐 클래스는 객체가 아닙니다.

타입이 같은 객체끼리 같은 메세지를 수신하지만, 결과적으로 각 객체별로 내부 표현 방식이 다를 수 있기 때문에, 동일한 메세지에 대한 처리가 다릅니다. 이를 다형성이라고 말합니다.

결론 : 즉 객체의 타입이든, 속성이든 정의를 하기 위해선 객체와 객체 사이 어떤 메세지가 주고 받을지 즉 행동을 최우선으로 생각하고, 그에 따른 객체의 타입과 속성을 결정해야 합니다.

역할, 책임, 협력

역할, 책임, 협력, 메세지 키워드 중 메세지에 대한 중요성과 설명을 했고, 쉬어가는 타임으로 역할, 책임, 협력에 대해서 알아보겠습니다.

협력은 말 그대로 협력입니다. 객체는 협력속에서 책임에 따른 역할이 존재합니다.
예를 들어 어떤 사람이 자동차에 시동을 걸고 전진한다고 생각해봅니다.

이때 사람이라는 역할은 제가 될 수도, 여러분이 될 수도 자동차라는 역할은 승용차, 세단, 트럭 어떤 객체가 될 지 모릅니다. 여기서 '사람' 이라는 역할과 '자동차'라는 역할을 만들어서 협력을 구성했습니다. 이렇게 '역할'은 객체의 추상화입니다.
또한, 협력 또한 추상화할 수 있습니다. 예를 들어 제가 승용차에 시동을 건다, 제가 트럭에 시동을 건다.. 와 같은 협력을 사람이 시동을 건다. 라는 간단한 협력으로 추상화할 수 있게 해줍니다.

위 과정에서 어떤 객체가 요청에 대해 대답해 줄 수 있거나, 적절한 행동을 할 의무가 있는 경우 객체가 책임을 가진다고 말합니다.
예시에서 사람이라는 역할이 자동차라는 역할에게 시동을 걸라는 메세지를 요청합니다. 이때 자동차라는 역할은 스스로 시동을 걸고 어떠한 행동이나 응답을 해야 한다는 책임이 생깁니다.
이와 같은 과정에서 자동차마다 시동을 거는 방식이 다를겁니다. 이를 시동을 건다 라는 책임으로 인터페이스를 구성합니다.

객체지향 설계 기법

  • 책임주도 설계
    • 협력에서 책임 식별후, 적합한 객체에 책임을 할당하는 방식
    • 여태 강조한 협력속에서 어떤 책임이 필요하고, 어떤 객체가 필요한지 결정하는 과정이 전체 설계 자체를 주도하는 방식
  • 디자인 패턴
    • 정해진 협력, 책임, 역할의 템플릿으로, 책임-주도 설계의 절차를 따르지 않고도, 빠르게 협력, 책임, 역할을 선택 가능
  • 테스트 주도 개발
    • 책임을 수행할 객체 또는 클라이언트가 기대하는 객체의 역할이 메세지를 수신할 때 어떤 결과를 반환하고, 그 과정에서 어떤 객체와 협력할 것인지에 대한 기대를 코드의 형태로 작성하는 방식
    • 이 과정에서, 테스트 코드는 덤이고, 리팩토링의 이점도 존재
객체를 올바르게 설계하기
  • 깔끔한 협력을 설계
  • 협력의 흐름에 따라 객체의 책임 설계
  • 책임을 결정한 후에 그 행동을 수행하는데 필요한 데이터를 고민

결론 : 협력을 설계하고, 협력에서의 책임을 기준으로 전체적인 설계가 주도되어야 한다.쉽게 말해 메세지를 먼저 정하고, 해당 책임들을 역할(객체)에개 적절하게 할당하는 방식으로 설계가 주도되어야 한다.

책임과 메세지

객체 지향의 강력함을 누리기 위한 출발점은 책임을 자율적으로 만드는 것입니다. 그리고 이것은 여러분이 선택하는 메세지에 따라 달라집니다.
자율적인 객체란? 객체 스스로 판단에 따라 책임을 수행하는 것을 뜻하며, 또한 해당 책임에 따라 적절한 객체를 할당하는 과정이 객체 지향의 설계입니다. 이 때문에 책임-주도 설계 방식이 널리 사용

객체는 스스로 판단에 따라 책임을 수행해야 한다고 말했습니다. 그렇기 때문에 메세지는 너무 세세한 요구를 하면 객체의 자율성을 무너뜨립니다.
예를들어, 자동차가 시동을 걸어야 하는 책임이 있다고 가정합니다. 이때, 세세하게 스마트 키를 이용해서 시동을 걸어라, 일반 키를 이용해서 시동을 걸어라 등의 세세한 메세지는 객체의 자율성을 무너트립니다. 자율적인 객체는 스스로가 판단해서 스마트키이든, 일반 키 방식이든 선택해서 시동을 걸어야 합니다.
그렇다고 너무 추상적인 책임은 좋지 못합니다. 예를 들어 그냥 시동을 걸어라일 경우, 자동차의 시동인지 오토바이의 시동인지 알 수 없기 때문입니다. 따라서 협력 관계 속에서 절절한 수준에서 추상적으로 책임을 선택해야합니다.

인터페이스, 다형성

자동차의 시동을 걸어라라는 메세지를 수신했을 때, 스마트키 자동차와, 일반 키로 동작하는 자동차는 같은 메세지를 수신하지만 다른 행동을 합니다. 이와 같이 다형성이라는 형질을 이용해, 송신자는 수신자를 몰라도 요청이 가능하게 되면서 수신자의 외부와 내부처리를 분리하는 캡슐화도 가능합니다.

다형성의 장점

  • 송신자는 수신자가 누구인지 상관없이 메세지만 수행하면 된다.
  • 메세지만 변경이 없다면, 수신자를 변경하거나 수정해도 송신자에겐 영향이 없다.
  • 협력에 영향 없이 다양한 적절한 객체들이 수신자로 대체할 수 있다.

이와 같이 송신자와 수신자를 분리할 수 있는 이유는 바로 객체들간 통신은 메세지를 통해 이루어지기 때문이다. 그래서 객체가 메세지를 선택하는게 아닌, 메세지를 중심으로 적절한 객체를 선택, 메세지를 중심으로 협력을 설계해야 합니다.

**결론 : 메세지를 기반으로 책임을 자율적으로 만들어야 한다.

기능의 관점, 구조의 관점

실세계이든 객체 세계이든 변화는 막을 수 없다. 그렇기 때문에 기능의 관점으로 설계를 할 경우, 재사용이 불가능하고 수정이 반복이 된다. 예를 들어 길을 찾아가는데 사람에게 물어가며 길을 찾아간다고 생각해보자. 누군가가 앞으로 가시다가 사거리에서 우회전... 편의점에서 좌회전...등등 직관적이고 해결이 쉽겠지만, 3년후 같은 같은 위치에서 같은 질문을 했을 경우 해당 위치에 편의점이 없어질수도, 극단적으로 사거리가 없어질수도 있다. 아무도 예측이 불가능합니다.
그렇다면 지도를 보고 찾아가는 구조의 관점으로 접근해보자. 전체적인 지형의 형태로 길을 찾아가기 때문에 해당 건물에 편의점이 음식점으로 바뀌어도 원하는 길을 찾아가는데 문제가 없습니다.

기능 설계 vs 구조 설계

그렇다면 기능은 필요가 없는가? 전혀 아니다. 기능은 즉 서비스입니다. 설계 초반에 사용자가 원하는 요구를 파악하고, 충족하기 위해 어떤 기능을 제공해야 하는지 초점을 맞춰야 합니다.
구조는 기능을 구현하기 위한 기반으로, 변경을 수용할 수 있도록 안정적이어야 합니다.

기능과 구조를 표현하기 위한 기법

  • 기능 표현 : 유스케이스 모델링
  • 구조 표현 : 도메인 모델링

유스케이스 모델을 통한 기능과, 도메인 모델을 통한 구조를 책임-주도 설계로 합쳐서 안정적인 시스템을 만드는 방법을 연습해야 한다.
또한 코드 작성은 도메인 모델을 기반으로 작성해 방향성을 잃지 않고 코드를 작성하도록 한다.

결론 : 요구사항을 식별, 도메인 모델을 생성한 후, 코드를 작성 후, 요구사항을 충족시키기 위해 객체들간의 메세지 전송을 정의해야 한다.

마무리

책에 대한 전반적인 리뷰를 마무리하며, 해당 책에는 이상한 나라의 엘리스라는 책을 기준으로 더 많은 내용과 설명을 몰입도 있게 표현하고 있으니, 조금이라도 객체지향에 대한 호기심이 생긴 사람이라면 적극적으로 읽어볼 것을 추천합니다. 또한 책의 분량도 많지 않기 때문에 부담 없이 읽으면서 조금 더 견문??이 넓어지는 듯한 생각이듭니다. 책을 적극적으로 추천합니다.

결론 모아보기
  1. 실제는 객체와 현실은 전혀 다른 세계이기 때문에 그 차이를 인지하고 객체지향적으로 접근하는 것
  2. 객체의 타입이든, 속성이든 정의를 하기 위해선 객체와 객체 사이 어떤 메세지가 주고 받을지 즉 행동을 최우선으로 생각하고, 그에 따른 객체의 타입과 속성을 결정해야 한다.
  3. 협력을 설계하고, 협력에서의 책임을 기준으로 전체적인 설계가 주도되어야 한다.쉽게 말해 메세지를 먼저 정하고, 해당 책임들을 역할(객체)에개 적절하게 할당하는 방식으로 설계가 주도되어야 한다.
  4. 메세지를 기반으로 책임을 자율적으로 만들어야 한다.
  5. 요구사항을 식별, 도메인 모델을 생성한 후, 코드를 작성, 요구사항을 충족시키기 위해 객체들간의 메세지 전송을 정의해야 한다.
반응형
Comments