📗 개발자 책 읽기/한권 내용 정리

객체지향의 사실과 오해 - 역할, 책임, 협력 관점에서 본 객체지향 | 조영호

민돌v 2024. 4. 7. 16:12

2년 전에 읽었던 객사오를 다시 읽고, 책의 내용을 정리한 글입니다.

[목차]

  1. 협력하는 객체들의 공동체
    1. 객체란 무엇일까
    2. 협력하는 사람들
    3. 협력 속에 사는 객체
    4. 메세지와 메서드
  2. 이상한 나라의 객체
    1. 객체와 소프트웨어 나라
    2. 객체와 상태
    3. 상태 캡술화
    4. 행동이 상태를 결정한다.
  3. 타입과 추상화
    1. 추상화를 통한 복잡성 극복
    2. 객체지향과 추상화
    3. 객체의 일반화와 특수화
  4. 역할, 책임, 협력
    1. 책임의 분류
    2. 대체 가능성
    3. 책임 주도 개발
  5. 책임과 메세지
    1. 다형성
    2. 유연하고 확장가능하고 재사용성이 높은 협력의 의미
    3. 객체 인터페이스
    4. 인터페이스와 구현의 분리
  6. 도메인 모델

 

 


1. 협력하는 객체들의 공동체

1) 객체란 무엇일까

✔️ 객체란 현실 세계에 존재하는 사물에 대한 추상화이다.

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

  • "상태" 와 "행위"를 "캡슐화"하는 소프트웨어 객체의 "자율성" 을 설명하기에는
    → 객체를 스스로 생각하고 스스로 결정하는 현실 세계의 생명체에 비유해보는 것이 휴과적이다.

  • 객체의 협력
    → [협력하는 사람들]은 현실 세계에서 암묵적인 [약속]과 [명시적인 제약]을 기반으로 [협력] 하며 목표를 달성해 나가는 과정을
    [메세지]를 주고받으며 공동의 목표를 달성한다.

 

🍀 소프트웨어 세계의 객체란, "상태"를 가지며 스스로의 상태를 변화시킬 "행위"를 가지고 있다
🍀 소프트웨어 세계의 객체는, "상태" 와 "행위"를 보호하기 위해 캡슐화 되어있고, 외부 객체와의 협력을 위해 "메세지"를 사용할 수 있다.
🍀 이런 관점에서 객체를 설계한다면, 객체지향적일 것이다..!

 


2) 협력하는 사람들

✔ 현실세계의 직업 처럼 (바리스타, 손님, 캐시어) 소프트웨어상에서의 객체 또한 직업(역할과 책임) 을 엄격하게 분리하는 것이 좋다.
✔ 객체는 역할과 책임을 가지고, 목표를 위해 다른 객체와 협력해야한다.
✔ 특정한 역할은 특정한 책임을 암시한다. (역할 == 책임)?
✔ 사람들이 협력을 위해 특정한 역할을 맡고 책임을 수행한다는 것은 몆가지 중요한 사실을 암시한다! (객체 관계간의)

  1. 여러 사람이 동일한 역할을 수행할 수 있다. → 객체가 주어진 책임을 다한다면, 협력하는 객체는 누구든지 상관없다는 뜻
    • 손님 : 손님은 커피를 마실수만 있다면 어떤 캐시어가 주문을 받는지 상관없다. (바리스타가 받더라도!)
    • 캐시어 : 캐시어는 손님에게 커피를 전달할 수 있다면 어떤 바리스타가 커피를 만들든 상관이 없다.
  2.  역할은 대체 가능성을 의미한다.
    • 위와같은 상황에서, 손님 입장에서 캐시어는 대체 가능하다.(substitutable)
    • 2 명의 동일한 역할을 수행할 수 있다면 요청자 입장에서 둘 중 어떤 사람이 역할을 수행하더라도 문제가 되지 않는다.
  3.  책임을 수행하는 방법은 자율적으로 선택 가능하다.
    • 요청을 받은 사람은 요청을 처리하는 방식을 자유롭게 선택할 수 있다.  (자율성)
      ex) 바리스타 : 커피제작 요청을 받은 바리스타는, 핸드드립 or 머신 추출 or 믹스 커피 등 다양한 행위로 요청에 응답할 수 있다.
    • 즉, 동일한 요청을 받더라도 바리스타의 역할을 수행하는 사람들마다 서로 다른 "방식" 으로 요청을 처리할 수 있다. = [다형성]
    • 한 사람이 동시에 여러 역할을 수행할 수 있다.
      • 한 사람이 캐시어와 바리스타의 역할을 동시에 수행하는 것 또한 가능하다.
      • 소프트웨어 상에서는 설계에 따라 하나의 객체가 여러 책임과 역할을 수행하는 거대 객체가 되기도 했던 것 같다.

 

🍀 설계하고자하는 서비스에서, 객체의 관계를 묘사할때 가장 중요한 점은 어디까지가 해당 객체의 책임인가인 것 같습니다.
🍀 (2번) 문항은 저에게, 객체지향적인 설계는 변경을 용이하게 만들어준다고 들려집니다.
       → 객체들에게 명확한 책임과 역할을 부여하고,
       → 설계한 객체들의 협력을 명확한 요청과 응답이라는 명확한 메세지로 상태를 변경할 수 있다면
       → [유연하게 객체의 행위나 협력관계를 변경]할 수 있을것만 같습니다.

🍀 객체의 명확한 책임과 역할이 캡슐화 되어있다면, 객체는 외부 상황을 전혀 신경 쓰지 않아도 되기 때문입니다. (1번)
🍀 대체 가능한 역할과 책임은 객체지향의 "다형성"과 깊이 연관되어 있습니다.

✔ 다형성이란? (밑에)

 


3) 협력 속에 사는 객체

객체는 스스로 자율성을 가져야 한다. → 어떤 방식으로 요청에 응답할지, 요청에 응답할지에 대한 여부까지 객체 내부에서 스스로 판단할 수 있게끔 역할과 책임을 주어야 객체지향적인 패러다임 설계이다.

객체의 자율성은 객체의 내부와 외부를 명확하게 구분하는 것으로 부터 나온다.

  • 객체의 사적인 부분(상태 변경) 은 외부에서 일체 간섭할 수 없도록 차단해야 한다!
  • [접근이 허락된 수단]을 통해서만 객체와 [의사소통] 해야한다..! (중요!!)
  • 외부의 협력객체는 해당 객체가 "무엇"을 수행하는지는 알수 있지만, "어떻게" 수행하는지는 알 수 없어야한다.

 

🍀 객체의 자율성은 다른객체를 의존하지 않음에서 나온다고 생각됩니다.
🍀 직접적으로 의존하지 않고, 메세지를 통해 협력하는 관계를 맺는다!

 


4) 메세지와 메서드

✔ 객체과 외부로 부터 협력을 요청하는 메세지를 받으면, 그 행위를 수행하는 것이 메서드(함수, 프로시저 등) 이다.

메세지와 메서드를 명확하게 분리하면 객체의 협력에 참여하는 객체들 간의 자율성을 증진시킨다.
   (객체 안의 메서드끼리도 역할과 책임을 분리하는 의미 같습니다. 메세지를 받는 메서드, 메세제의 행위를 처리하는 메서드)

 


2. 이상한 나라의 객체

1) 객체와 소프트웨어 나라

✔ 객체지향 패러다임의 목적은 현실 세계를 모방하는 것이 아닌, 현실을 기반으로 새로운 세계를 창조하는 것이다.
객체의 상태를 변화(결정) 시키는 것행동이지만, 행동의 결과를 변화시키는 것(결정)하는 것 또한 상태이다.
✔ 즉, 어떤 행동의 성공 여부는 이전 행동에 영향을 받을 수도 있다, (이전 행동으로 상태가 변해서) → 이것은 행동 간의 순서가 중요하다는 것을 의미한다.
✔ 객체는 상태(state), 행동(behavior), 식별자(identity)지닌 실제로 보는 것이 가장 효과적이다.

 


2) 객체와 상태

객체에 상태가 존재하고, 행위는 상태에 의존(과거의 행위)에 의존할 수 있기 때문에 과거의 클래스 패러다임과 다르게 소프트웨어의 설계에서 과거에 얽메이지 않고 현재를 기반으로 객체의 행동 방식을 이해할 수 있게되었다.


✔ 때로는 객체의 상태를 다른 객체를 이용해 표현할 수도 있다.

 


3) 상태 캡술화

✔ 위에서 정의한대로와 같이, 객체의 상태는 객체 자신만이 변경가능해야 합니다.
✔ 객체는 상태를 캡슐안에 감춰둔 채 외부로 노출하지 않습니다.
✔ 객체가 외부에 노출하는 "행동"뿐이며, 외부에서 접근할 수 있는 유일한 벙법 역시 "행동"뿐이다.
✔ 객체의 행동을 유발하는 것은 외부로부터 전달된 "메세지"이지만, 상태를 변경할 지는 객체 "스스로" 결정한다!
✔ 상태를 노출시키지 않고 [행동을 경계로 캡슐화] 하는 것은 객체의 자율성을 높이고, 자율적인 객체는 [스스로 판단하고 스스로 결정] 하기 때문에 객체들간의 [협력은 유연해지고 간결] 해진다.

 

🍀 이것이 상태를 캡슐화 해야하는 이유! → 유연하고 간결한 협력을 위해 객체의 자율성을 높이자!

 


4) 행동이 상태를 결정한다.

상태를 중심으로 객체를 바라보면 안된다. → 상태를 먼저 보고 행동을 나중에 결정하는 것은 설계에 나쁜 영향을 준다.

  1. 상태를 먼저 결정할 경우 캡슐화가 저해된다. - 상태에 초점을 맞출경우 공용 인터페이스에 그대로 노출될 확률이 높다.
  2. 객체를 협력자가 아닌 고립된 섬으로 만든다. - 객체는 협력을 위해 존재한다. 상태에 초점을 맞추면 협력하지 못할 가능성이 높다.
  3. 객체의 재사용성이 저하된다. - 마찬가지로 다양한 협력에 참여하는 능력이 저하되기에 재사용성이 저하된다.

✔ 결과적으로 "우리가 어플리케이션 안에서 어떤 행동을 원하느냐" 가 어떤 객체가 적합한지를 결정한다.

✔ 객체의 적합성을 결정하는 것은 상태가 아닌 [객체의 행동]이다.

✔ ! 행동을 결정한 후에야, 행동에 필요한 정보를 고려할 수 있고 그것이 상태가되어야 적합하다.

✔ 협력 안에서 "객체의 행동" 은 [객체가 협력에 참여하면서 완수해야 하는 책임을 의미한다.]

 

🍀 책임주도설계 - RDD(Responsibility Driven Design)
🍀 협력안에서 객체의 행동을 생각하도록 유도함으로써 → [응집도 높고 재사용 가능한 객체]를 만들 수 있다.
🍀 "행동이 상태를 결정한다."

 


3. 타입과 추상화

1) 추상화를 통한 복잡성 극복

✔ 추상화 : 물체를 의도적으로 생략하거나 감춤으로써 복잡도를 극복하는 방법
✔️ 진정한 의미에서 추상화란, 현실에서 출발하되 불필요한 부분을 도려내가면서 사물의 놀라운 본질을 드러나게 하는 과정
✔ 전철 노선도 : 전철노선도는 하나의 유연한 직선 혹은, 타원이지만 실상황에서의 노선도는 복잡하기 그지없다. (꼬불꼬불)

 


2) 객체지향과 추상화

✔ 객체가 아무리 다양한 특징을 가진다고 해도, 공통점만을 취해 단순화시킬 수 있다. (추상화)

개념으로 분리해도 그 안에 다양한 특징으로 다시 분리될 수 도 있다.

분류는 추상화를 위한 도구이다.
✔ 분류란, 객체에 특정한 개념을 적용하는 작업. 즉, 객체에 특정한 개념을 적용하기로 결심했을 때 우리는 그 객체를 특정한 집합의 멤버로 분류하고 있는 것이다.

 


3) 객체의 일반화와 특수화

✔ 특정 개념을 가진 객체를 분류했을때, 해당 집합의 일부 객체만 특정한 행동을 할 수 있다고 가정하자. (트럼프 인간 < 트럼프 병사 < 트럼프 여왕)
✔ 이러한 관계를 일반화와 특수화라고 한다.
✔ 객체지향에서 일반화/특수화를 관계를 결정하는 것은 [상태]가 아닌 [행동]이다.
✔ 특수 타입은 일반 타입보다 더 많은 행동을 가진다.
✔ 단, 특수 타입은 일반적인 타입이 할 수 있는 모든 행동을 동일하게 수행할 수 있어야 추상화가 가능하다.

📌서브타입은 슈퍼타입을 대체할 수 있어야한다. (트럼프 여왕은 모든 행동을 할 수 있으므로, 트럼프 인간의 역할을 대체할 수 있다.)

 


4. 역할, 책임, 협력

1) 책임의 분류

객체의 책임'객체가 무엇을 알고있는가(knowing)''무엇을 할 수 있는가(doing)'으로 구성된다.
✔ 이러한 분류에서 객체의 책임을 크게 [하는 것] 과 [아는 것] 으로 분류할 수 있다.

  • 하는 것(doing)
    1. 객체를 생성, 계산을 하는 것 등 스스로 하는 것
    2. 다른 객체의 행동을 시작시키는 것
    3. 다른 객체의 활동을 제어하고 조절하는 것
  •   아는 것(knowing)
    1. 개인적인 정보에 관해 아는 것
    2. 관련된 객체에 관해 아는 것
    3. 자신이 유도하거나 계산할 수 있는 것에 관해 아는 것

✔ 즉, 책임은 외부에 제공할 정보(아는것) 과 외부에 제공할 서비스(하는것)의 목록이기에 [객체의 공용 인터페이스]를 구성할 수 잇다, (public interface)

 


2) 대체 가능성

✔ 역할은 협력 안에서 구체적인 객체로 대체될 수 있는 추상적인 협력자이다. (객체가 적합한 역할과 책임을 수행하기에)
✔ 따라서 역할은 다른 객체에 의해 대체 가능함을 의미한다.
✔ 객체가 역할을 대체하기 위해서는역할이 수행하는 모든 책임을 동일하게 수행할 수 있어야한다.
✔ 여기서 일반화/특수화 관계가 성립할 수 있다. (서브타입은 슈퍼타입의 모든 행동, 즉 역할을 대체할 수 있음)

 

🍀 요약하자면, 역할의 대체 가능성은 행위 호환성을 의미하며 → 행위 호환성은 동일한 책임의 수행을 의미한다.
🍀 특정한 기능을 위해 객체간의 협력이 필요할때, 협력은 객체들의 역할로 이루어져 있고, 역할은 대체 가능하다.
🍀 죽, 기능을 구현할때 특정 요건에 따라 역할을 대체 할 수 있고, 이는 일반화/특수화 (서브타입/슈퍼타입)을 사용하여 추상화 할 수있음을 의미한다.

 


3) 책임 주도 개발

✔ 만약 책임을 여러 종류의 객체가 수행할 수 있다면, → 협력자는 객체가 아닌 추상적인 역할로 대체가능하다. (추상화, 다형성)

 


5. 책임과 메세지

1) 다형성

✔ 다형성이란, 서로 다른 유형의 객체가 동일한 메시지에 대해 서로 다르게 반응하는 것을 의미한다.
✔ 다형성의 가능성 : 메시지는 "무엇"이 실행될지 명시하지만 "어떻게" 실행될 것인지는 수신자만이 알 수 있다.
✔ 다형성은 객체들의 대체 가능성을 이용해 설계를 유연하고 재사용 가능하게 만든다.
✔ 다형성을 사용하면 송신자가 수신자의 종류를 모르더라도 메시지를 전송할 수 있다, (역할을 추상화하였기 때문에)
✔ 즉, 다형성은 수신자의 종류를 캡슐화 한다.

 


2) 유연하고 확장가능하고 재사용성이 높은 협력의 의미

🍀 객체지향 패러다임의 "다형성" 이 가지는 장점에 대한 정리!!

✔ 송신자(요청자)가 수신자(응답자)에 대해 매우 적은 정보만 알고있더라도 상호 협력이 가능하다는 사실이 설계 품질에 큰 영향을 미친다.

  1. 협력이 유연해진다.
    • 송신자는 수신자에 대해 어떤 가정도 하지 않고 수신자를 다른 타입의 객체로 대체하더라도(다형성) 송신자는 전혀 알지 못한다.
    • 따라서 [송신자는, 수신자의 변경에 의한 파급효과(side-effect) 가 없다.]
  2. 협력이 수행되는 방식을 확장할 수 있다.
    • 송신자에 아무런 영향을 끼치지 않고 수신자를 교체할 수 있기 때문에 새로운 유형의 객체를 협력에 끼워 맞출 수 있다.
  3. 협력이 수행되는 방식을 재사용할 수 있다.
    • 협력에 영향을 미치지 않고서도 다양한 객체들이 수신자(응답자)의 자리를 대체할 수 있기 때문에 다양한 문낵에서 협력을 재사용할 수 있다.
    • 협력자들이 추상적인 역할로 추상화 되었기 때문에!!!!!!

 

🍀 다형성은, 개별 객체가 아니라 객체들이 주고받는 메시지에 초점을 맞출때 가장 강력하고 적합하다.
🍀 메시지를 중심으로 설계된 구조는 유연하고 확장 가능하며 재사용 가능하다.
🍀 메시지를 중심으로 한다는 것은 → 협력자들의 책임과 역할에 따라 행위의 주체자를 결정한다는 것 → 협력의 역할을 추상화 하였을 때 다형성의 진가가 드러난다..!!!!!!

 


3) 객체 인터페이스

✔ 일반적으로 인터페이스란, 어떤 두 사물이 마주치는 걍계 지점에서 [서로 상호작용할 수 있게 이어주는] 방법이나 장치
✔ 인터페이스의 특징

  1. 인터페이스 사용법을 익히며 내부구조를 몰라도 대상을 조작할 수 있다.
  2. 인터페이스 자체는 변경하지 않고 [단순히 내부 구성이나 작동 방식만을 변경하는 것]은 [인터페이스 사용자에게 어떤 영향도 미치지 않는다.]
  3. 대상이 변경되더라도 동일한 인터페이스를 제공하기만 하면 아무론 문제 없이 상호작용 할 수 있다.

✔ 객체가 다른 객체와 상호작용할 수 있는 유일한 방법은 "메시지 전송" 이다.

 


4) 인터페이스와 구현의 분리

✔️ 훌령한 객체란 구현을 모른 채 인터페이스만 알면 쉽게 상호작용할 수 있는 객체를 의미한다.
✔️ 이것은 객체를 설계할 때 객체 외부에 노출되는 인터페이스와 객체의 내부에 숨겨지는 구현을 명확하게 분리해서 고려해야 한다는 것을 의미한다. → [인터페이스와 구현의 분리 원칙]

✔️ 인터페이스와 구현의 분리 원칙은, 변경을 관리하기 위한것이다.

  • 📌  송신자와 수신자가 구체적인 구현 부분이 아니라 느슨한 인터페이스에 대해서만 결합되도록 하는 것 (인터페이스이 구현은 변경에서 자유롭기에 유연하다고 표현한다.)

 

🍀훌륭한 기능이 훌륭한 소프트웨어의 충본조건이라면, 훌륭한 구조는 필요조건이다.
🍀객체지향적 설계는 요구사항 변경시 유연하게 대비하기위한 목적을 가진다.

 


6. 도메인 모델

✔ 도메인 모델이란, 사용자가 프로그램을 사용하는 대상 영역에 관한 지식을 선택적으로 단순화하고 의시적으로 구조화한 현태이다.
✔ 도메인 모델은 소프트웨어가 목적하는 영역 내의 개념고 개념 간의 관계, 다양한 규칙이나 제약 등을 주의 깊게 추상화 한것이다.
✔ 제품을 설계할 때 제품에 관한 모든 것이, 사용자들이 제품에 대해 가지고 있는 멘탈 모델과 정확하게 일치해야 한다. → [최종 코드는 사용자가 도메인을 바라보는 관점을 반영해야 한다.]

✔ 이러한 관점의 도메인 모델은 "사용자 관점에서 설계하기 때문에" 본질적인 측면을 가장 잘 이해하고 있고, 본질적이기에 변경이 비교적 적다는 특성을 가진다...(잘 이해가 안감)
✔ 유스케이스 관점에서의 설계는 이해관계자들간의 행위 중심으로 파악되기에 불안정하다. (기능 중점적이기에)

✔ 결론은 기능과 구조가 통합되어야한다. (유스케이스 관점과 도메인 모델 관점, 책임-주도 설계)

 

🍀 객체지향의 가장 큰 장점은, 도메인을 모델링하기 위한 기법과 도메인을 프로그래밍하기 위해 사용하는 기법이 동일하다는 점이다.
🍀 따라서 도메인 모델링에서 사용한 객체와 개념을 프로그래밍 설계에서의 객체와 클래스로 매끄럽게 변화할 수 있고 이같은 특성을, [객체지향의 연결완전성] 이라 한다.

 


 

책을 다시 읽어보니, 처음 읽었을 때 얼마나 이해를 못하며 읽었는지 알 수 있었습니다..
지금도 완벽하게 이해가된건 아닌거 같고, 1년 혹은 2년 뒤 도메인 모델 관점에 대한 경험을 쌓고 다시 읽으면 또 다른 인사이트를 얻을 수 있을 것만 같은 기분이 드네요


천천히더라도 꾸준히 공부해서 다시 읽을 수 있는 그날이 오길!

 

끝!