객체지향의 사실과 오해 Chapter 5,6

위승현·2024년 12월 9일

CS

목록 보기
6/6

객체에게 책임을 부여할 때 그 책임의 수준은 너무 구체적이어서도 안되고
너무 추상적이어서도 안된다.

추상적일수록 자유도는 올라가지만 의도가 명확하게 표현되지 못할 수도 있고
구체적일수록 자유도는 낮아지지만 의도가 명확하게 표현될 수 있다.

즉 우리는 책임을 협력에 참여하는 의도를 명확히 설명할 수 있는 선까지 추상적으로
표현하여 할당해야하는 것이다.

그렇다면 어떻게 적절히 자율적이지만 의도를 파악할 수 있는 책임을 할당할 수 있을까?

바로 객체가 어떻게 해야하는지가 아니라 무엇을 해야하는가를 설명하면 된다.

책에서 나온 예시로 판사가 모자장수에게 '증언하라' 라는 메시지를 넘겨
모자장수가 그 책임을 수행할 의무를 갖게 되었을 때처럼 이는 무엇을 해야하는지 결정하지만
그것을 어떻게 해야하는지는 언급하지 않는다.

메시지에는 추가적으로 인자를 통해 정보를 제공할 수 있다
만약 모자장수에게 어제 왕국에서 목격한 것을 증언하라고 요청하고 싶다면

모자장수.증언하라(어제,왕국)

이런 형태로 메시지를 보낼 수 있다.

메시지를 수신받으면 객체는 자신이 그 메시지를 처리할 수 있는지 확인한다.
이는 객체가 메시지에 해당되는 행동을 수행해야할 책임이 있는지 확인한다는 의미이다.

객체끼리는 메시지 전송을 통해서만 요청 응답할 수 있기에 객체가 수신할 수 있는
메시지의 모양이 객체가 수행할 책임을 결정하게된다.

다형성은 대체 가능성을 의미한다.
동일한 메시지를 처리하는 방식은 달라지더라도 다 처리할 수 있기 때문이다.
즉 다형성을 통해 메시지를 이해할 수 있는 어떤 객체와도 협력할 수 있는
유연하고 확장 가능한 구조를 만들 수 있다.

유연하고 확장가능하고 재사용성이 높은 협력?

  1. 협력이 유연해진다
    메시지 송신자는 수신자가 메시지를 이해한다면 누구라도 상관하지 않는다.
    다른 타입의 수신자로 대체되어도 송신자는 알지 못하여 협력의 변경이 유연해진다.

  2. 협력이 수행되는 방식을 확장할 수 있다.
    수신자 교체가 송신자에게 영향이 안가기에 협력의 세부사항을 쉽게 수정할 수 있다.
    새로운 유형의 객체를 만들어 협력에 끼워맞추는게 가능하기 때문이다.

  3. 협력이 수행되는 방식을 재사용할 수 있다.
    다양한 객체가 수신자를 대체할 수 있기에 다양한 문맥에서 재사용이 가능하다.

즉 훌륭한 객체지향 설계는 어떤 객체가 어떤 메시지를 전송할 수 있는가와
어떤 객체가 어떤 메시지를 이해할 수 있는가를 중심으로 객체사이의 협력관계를 구성하는 것이다.

객체지향 설계를 클래스 중심으로 하지말고, 객체를 개별적으로 생각하지 않으며
데이터를 중심으로 객체를 설계하지 않으려고 노력하고 메시지가 객체를 선택하도록
선택된 객체들이 그 메시지를 통해 협력 관계를 구성하도록 노력한다면
좋은 객체 지향 설계를 만들어낼 수 있다.

그렇다면 메시지 중심으로 설계를 진행하면 좋은 설계가 나올 것을 알 수 있다.
메시지를 결정하고 객체가 그 메시지를 따르게 하는 묻지말고 시켜라 스타일을 따르면
자연스레 송신자는 수신자가 어떤 객체인지 상관이 없어지고 이는 수신자의 캡슐화를 증진시킨다.

그냥 메시지를 전송하기만 하고 잘 응답해줄 것이라고 믿을 뿐이다.
처리하는 방식은 메시지를 수신한 객체가 알아서 할 것이다. 수신자의 상태를 고민하지마라.


인터페이스

GUI, API 도 인터페이스의 일종이다.
인터페이스는 두 사물이 상호작용할 수 있게 이어주는 방법이나 장치를 의미한다.

  1. 인터페이스는 사용법을 익히면 내부 구조, 동작 방식을 몰라도 쉽게 대상을
    조작하거나 의사를 전달할 수 있다. (추상화)

  2. 인터페이스 자체는 변화하지 않는다. 구현체가 변화하며 내부 구성이나 작동 방식을
    변경하는 것은 인터페이스 사용자에게 영향을 미치지 않는다. (캡슐화)

  3. 대상이 변경되어도 동일한 인터페이스를 제공하면 문제없이 상호작용이 가능하다. (다형성)

위에서 말했듯이 객체가 상호작용하는 방법은 메시지 전송이기에
객체의 인터페이스는 객체가 수신할 수 있는 메시지 목록으로 구성된다.

메시지를 통한 상호작용은 자기 자신과의 상호작용도 존재한다.
나 자신에게 메시지를 전송하여 스스로 뭔가를 요청하는 경우도 있다는 뜻이다.

객체의 외부와 내부를 명확하게 분리해야한다.
외부는 객체가 수신할 수 있는 메시지들의 목록을 가진 추상적인 인터페이스/공용 인터페이스이다.

내부는 무엇일까?
내부의 구조와 작동방식을 가리키는 고유 용어는 바로 구현 implementation 이다.
객체는 상태와 행동(메서드) 를 가진다.

결국 객체의 내/외부를 분리하라는 것은 공용 인터페이스와 구현을 명확하게 분리하라는 의미이다.
인터페이스와 구현체를 분리한다는 것은 변경될만한 부분을 구현체에 숨기라는 의미이다.
일반적으로 이 원칙을 수행하기위한 객체 설계 방법을 캡슐화 라고 한다.


캡슐화

  1. 상태와 행위의 캡슐화
    객체는 상태와 행위의 조합이라고 했다. 객체는 스스로 상태를 관리하며 변경한다.
    또 외부에 응답하는 행동을 보관한다. 이 관점을 데이터 캡슐화라고 한다.
    이렇게 객체와 행위를 묶은 후 외부에서 반드시 접근해야만 하는 행위만 골라
    공용 인터페이스를 통해 노출시킨다.

  2. 사적인 비밀의 캡슐화
    객체도 개인적인 비밀이 노출되는 것에 민감하다.
    외부의 객체가 자신의 내부 상태를 관찰하거나 제어하는 것을 막기위해
    의사소통이 가능한 특별한 경로만 외부에 노출한다.
    이렇게 의사소통만 할 수 있게 고정된 경로를 공용 인터페이스라고 한다.
    자율적인 객체는 공용 인터페이스를 수정하지 않는 한 자신과 협력하는 외부 객체에
    영향을 미치지않고 내부 구현을 자유롭게 수정이 가능하다.

캡슐화를 통해 송신자는 수신자가 책임을 수행하는 방법에는 관심도 없고
아예 볼 수 조차 없어진다.

따라서 책임이 자율적일수록!
즉, 수신자가 어떤 책임을 수행하는 방식이 자유로울수록!

수신자의 외/내부가 명확하게 분리되고
내부 변경이 외부에 영향을 끼치지않고,
수신자가 대체될 수 있는 유연성이 제공되고,
객체의 역할이 이해하기가 쉬워지며,
협력이 단순해지는 것이다.

이 말을 어렵게한다면
책임이 자율적일수록 적절히 추상화되며, 응집도가 높아지고, 결합도가 낮아지며
캡슐화가 증진되고 인터페이스와 구현체가 명확히 분리되며 설계의 유연성, 재사용성이 향상된다.


구조 and 기능

사람들에게 길을 묻는 행위는 기능에 구조를 종속시키는 것이고
지도를 보고 길을 찾는 것은 구조에 기능을 종속시키는 것이다.

지도는 사람들에게 길을 묻는 것보다 범용적으로 사용할 수 있으며 이해하기 쉽다.
자주 변경되는 기능이 아닌 안정적인 구조에따라 기능을 종속시키는 것이
좋은 객체지향 설계를 만드는데 도움이 될 것이다.

기능 측면의 설계는 제품이 사용자를 위해 무엇을 할 수 있는지 초점을 둔다.
구조 측면의 설계는 제품의 형태가 어떠해야하는지 초점을 맞춘다.

설계에서는 기능과 구조를 조화롭게 만들어야한다.
요구사항은 변한다. 만약 요구사항이 처음부터 끝까지 변하지 않는다면 설계가 어떠한가는
중요하지 않을 것이다.
하지만 요구사항은 항상 변경된다.
따라서 변경에 대비하기위해 설계를 중요하게 생각하고 구성하는 것이다.

훌륭한 설계자는 사용자가 만족할 훌륭한 기능 + 예측 불가능한 요구사항 변경에 유연하게
대처할 수 있는 안정적인 구조를 설계해야한다.

따라서 변경의 여지를 남겨놓아 변경을 대비하는 설계를 해야하는데
이는 지도의 예시처럼 안정적인 구조를 중심으로 설계하는 것이 가장 좋은 방법이다.

자주 변경되지 않는 안정적인 객체 구조를 바탕으로 시스템 기능을 객체간의
책임으로 분배한다.
구조에 집중하고 기능이 객체의 구조를 따르게 만들어야한다.

이 두 재료를 어떻게 어디에서 구하느냐를 알아보자.

도메인 모델 : 안전한 재료 (구조)

은행, 게임, 병원 등 자신이 가지고 있는 특정한 분야의 문제를 해결하기 위해서
우리는 소프트웨어를 사용한다. 이런 대상 분야를 도메인 이라고 한다.

도메인 모델은 도메인을 추상화, 단순화해서 표현한 것을 의미한다.
도메인 모델은 이해관계자들이 바라보는 멘탈 모델이다.
멘탈 모델이란 사람들이 자기 자신과 상호작용하는 사물들에 대해 갖는 모형이다.
세상에 존재하는 현상을 이해하고 반응하기 위해 모두 자신의 마음에 멘탈 모델을 구축한다.

제품 설계 멘탈 모델은 디자인 모델, 사용자 모델, 시스템 이미지로 이루어진다.

디자인 모델은 설계자가 생각하는 시스템 개념 모델이고
사용자 모델은 사용자가 제품에 가진 개념들의 모델이다.

이 둘이 비슷하면 좋겠지만 사용자와 설계자는 시스템 이미지 자체를 통해서만
의사소통할 수 있기에 비슷하도록 노력하는 수 밖에 없다.

객체지향을 이용하면 이 모두가 유사한 모습을 유지하도록 도와주는데
이러한 특징을 연결 완전성 or 표현적 차이라고 한다.

소프트웨어 객체는 현실 객체에 대한 추상화보다는 은유를 기반으로 재창조한 것이 맞다.
현실 객체가 하지 못하는 행동을 할 수 있지만 현실 객체를 토대로 구축된다.
이 의미적 거리를 가리켜 표현적 차이, 의미적 차이라고 하낟.

게임이나 인터넷은 현실세계에 존재하지 않는 서비스를 창조하는 과정이다.
그렇다면 우리가 은유를 투영해야하는 대상은 무엇일까?

바로 사용자가 도메인에 대해 생각하는 개념들이다.
따라서 우리는 도메인 모델을 은유의 대상으로 삼아야한다.

도메인 모델을 기반으로 코드를 작성하면 안정적이고 좋은 이유는
사용자들이 누구보다도 도메인의 본질적인 측면을 잘 이해하고 있기 때문이다.
도메인을 구성하는 개념들 사이의 관계를 제일 잘 알고있는 사람들이 사용자들이다.


유스케이스 불안정한 재료 : 기능

기능적 요구사항이란 시스템이 사용자에게 제공해야하는 기능의 목록을 정리한 것이다.
사용자가 시스템을 사용하여 달성하고자 하는 목표를 만족시키기위해
사용자와 시스템 간의 상호작용 관점에서 시스템을 바라보아야한다.
이러한 흐름을 텍스트로 정리한 것이 유스케이스이다.

유스케이스는 하나의 시나리오가 아닌 사용자가 목표를 이루기 위한 시나리오들의 집합이다.

자주 변경될 사용자 인터페이스 같은 요소는 제외하고 시스템의 행위에 초점을 맞춘
유스케이스 형식을 본질적인 유스케이스 라고 한다.

유스케이슨느 시스템의 내부 구조, 실행 메커니즘에 대한 어느 정보도 제공하지 않는다.
단지 사용자가 시스템을 통해 무엇을 얻을 수 있고 어떻게 상호작용 하는가의 정보만 기술된다.


기능과 구조의 통합

우리는 불안정한 기능을 안정적인 구조에 담아 변경에 대한 파급효과를 최소화해야한다.
시스템의 기능을 시스템의 책임으로 바꿔야한다? 이게 뭐가 다른건데?

도메인을 구성하는 기본적 개념과 관계를 포함하는 도메인 모델 기반에
시스템의 기능을 대응시키면 기능이 변경되거나 추가 되어도
대부분의 클래스 구조가 유지된다.
비즈니스 핵심 정책이나 규칙이 변경되지않는 한 전체 구조가 한번에 흔들리지는 않는다.

객체지향의 큰 장점은 도메인 모델링 기법과 프로그래밍 기법이 동일하다는 점이다.
도메인 모델링의 객체와 개념을 프로그래밍 설계의 객체와 클래스로 변환할 수 있다.
앞에서 설명했던 연결 완전성의 개념이 적용되는 모습이다.

둘은 동일한 기법을 공유하기에 코드의 수정으로도 도메인 모델의 변경을 알 수 있다.
코드에서 모델로의 매끄러운 흐름을 의미하는 것을 가역성 reversibility 라고 하낟.

profile
개발일기

0개의 댓글