[우테코 스터디] 객체지향의 사실과 오해 (3)

 

 

6장 스터디

기능 설계 대 구조 설계

  • 기능 측면 설계 : 제품이 사용자를 위해 무엇을 할 수 있는지에 초점
  • 구조 측면 설계 : 제품의 형태가 어떠해야 하는지에 초점
  • 훌륭한 기능이 훌륭한 소프트웨어를 만드는 충분조건이라면,
  • 훌륭한 구조는 훌륭한 소프트웨어를 만들기 위한 필요조건이다.
  • 미래를 예측할 수없지만, 변경을 수용할 수 있도록 설계에 마련해야 한다
  • 객체지향 접근방법은 자주 변경되지 않는 안정적인 객체 구조를 바탕으로 시스템 기능을 객체 간의 책임으로 분배한다.
  • 시스템 기능을 더 작은 책임으로 분할되고 적절한 객체에게 분배되기 때문에 기능이 변경되더라도 객체 구조는 그대로 유지된다.
  • 이것이 객체를 기반으로 책임과 역할을 식별하고 메시지를 기반으로 객체들의 협력 관계를 구축하는 이유다.
  • 안정적인 객체 구조는 변경을 수용할 수 있는 유연한 소프트웨어를 만들 수 있는 기반을 제공한다.
  • 객체 지도 : 빠르게 변화하는 기능을 수용할 수 있는 자리를 제공한다.

첫번째 재료 : 구조

  • 도메인 모델 : 사용자가 프로그램을 사용하는 대상 분야
    • 필요한 지식만 재구성한 것
    • 대상을 추상화하고 단순화한 것
    • 멘탈 모델 이라고 하며, 상호작용하는 사물들에 대해 갖는 모형이다.
  • 도메인의 모습을 담을 수 있는 객체지향
    • 클래스를 통해 타입을 코드안으로 옮길수 있음
    • 동적인 객체가 가진 복잡성을 극복하기 위해 정적인 타입으로 세상을 단순화
  • 연결완전성, 표현적 차이
    • 도메인에 대한 사용자 모델, 디자인 모델, 시스템 이미지가 유사한 모습으로 유지하도록 만드는 것이 가능하다.
    • 객체는 현실 객체에 대한 추상화가 아니다.
    • 소프트웨어와 현실 객체 사이를 가장 효과적으로 표현하는 방법은 은유이다.
    • 현실 객체를 왜곡한다고 하더라도 소프트웨어 객체는 현실 객체의 특성을 토대로 구축된다. → 표현적, 의미적 차이
  • 불안정한 기능을 담는 안정적인 도메인 모델
    • 도메인에 대한 사용자의 관점을 반영해야 하는 이유는 사용자들이 누구보다도 도메인의 본질적인 측면을 잘 이해하고 있기 때문이다.
    • 본질이라는 것은 변경이 적고 비교적 그 특성이 오랜 시간 유지된다는 것을 의미한다.

요약1> 안정적인 구조를 제공하는 도메일 모델을 기반으로 소프트웨어를 설계하면 변경에 유연하게 대응할 수 있는 소프트웨어를 만들 수 있다.

요약2> 실제로 사용자에게 중요한 것은 도메인 모델이 아닌 기능이며, 이를 서술하기 위해서 유스케이스가 존재한다,

불안정한 재료: 기능

  • 유스케이스 : 사용자가 자신의 목표를 달성하기 위해 시스템과의 상호작용을 한다. 이와 같은 흐름을 텍스트로 정리한 것을 유스케이스라고 한다.
    • 흩어져 있는 기능에 사용자 목표라는 문맥을 제공함으로써 각 기능이 유기적인 관계를 지닌 체계를 이룰 수 있게 된다.
    • 사용자 목표가 유스케이스의 핵심이며, 유스케이스는 공통의 사용자 목표를 통해 강하게 연관된 시나리오 집합이다.
    • 유스케이스는 사용자와 시스템 간의 상호작용을 보여주는 텍스트이다.
    • 유스케이스는 다이어그램이 아니며, 사용자와 시스템 간의 상호작용을 일련의 흐름으로 표현하는 것이다.
    • 유스케이스는 여러 시나리오들의 집합이다.
      • 시나리오 : 유스케이스를 통해 시스템을 사용하는 하나의 특정한 이야기 또는 경로이다.
        • 시나리오를 유스케이스 인스턴스라고 한다.
    • 유스케이스는 단순한 피처 목록과 다르다.
      • feature : 시스템이 수행하는 기능의 목록을 단순하게 나열한 것
        • 피처의 단점은 두 피처를 서로 연관이 없는 독립적인 기능으로 보이게 할 수 있다는 것이다.
    • 유스케이스는 사용자 인터페이스와 관련된 세부 정보를 포함하지 말아야 한다.
      • 자주 변경되는 사용자 인터페이스 요소를 배제하고 사용자 관점에서 시스템의 행위에 초점을 맞춘다.
      • 이처럼 사용자 인터페이스를 배제한 유스케이스 형식을 본질적인 유스케이스라고 한다.
    • 유스케이스는 내부 설계와 관련된 정보를 포함하지 않는다.
      • 유스케이스의 목적은 연관된 시스템의 기능을 이야기 형식으로 모으는 것이지, 내부 설계를 설명하는 것이 아니다.
      • 유스케이스는 객체의 구조나 책임에 대한 어떤 정보도 제공하지 않는다.

재료 합치기 : 기능과 구조의 통합

  • 도메인 모델, 유스케이스, 책임-주도 설계
  • 변경에 대한 파급효과를 최소화하는 것이 훌륭한 객체지향 설계자가 갖춰야 할 기본적인 설계 능력이다.
  • 시스템에 할당된 커다란 책임은 시스템 안의 작은 규모의 객체들이 수행해야 하는 더 작은 규모의 책임으로 세분화된다.
  • 어떠한 객체를 선택할 것인가에서 도메인 모델을 활용할 수 있다.
  • 객체 설계는 요구사항들을 식별 - 도메일 모델 생성 - 클래스에 메서드 추가 - 요구사항 충족을 위한 메시지 전송의 순서로 표현된다.
  • 책임 주도 설계 : 시스템의 기능을 역할과 책임을 수행하는 객체들의 협력 관계로 바라보게 함으로써 두 가지 기본 재료인 유스케이스와 도메인 모델을 통합한다.
    • 사용자 관점에서 시스템의 기능을 명시하고, 사용자와 설꼐자가 공유하는 안정적인 구조를 기반으로 기능을 책임으로 변혼하는 체계적인 절차를 따라야 한다.
  • 시스템 : 사용자로부터 메시지를 수신하는 거대한 객체이다.
  • 도메인 모델이 안정적인 이유?
    • 비즈니스가 없어지거나 완전히 개편되지 않는 한 안정적으로 유지된다.
    • 개념 간의 관계는 비즈니스 규칙을 기반으로 하기 때문에 비즈니스 정책이 크게 변경되지 않는 한 안정적으로 유지된다.
    • 안정적인 도메인 모델을 기반으로 시스템의 기능을 구현할 경우 시스템의 기능이 변경되더라도 비즈니스의 핵심 정책이나 규칙이 변경되지 않는 한 전체적인 구조가 한 번에 흔들리지 않는다.
    • 이는 객체지향이 기능의 변경에 대해 좀 더 유연하게 대응할 수 있는 패러다임이기 때문이다.

요약1> 객체지향의 단점

  • 도메인을 모델링하기 위한 기법과 도메인을 프로그래밍하기 위한 기법이 동일하다.
    • 매끄러운 변환이 가능하며, 이를 연결완전성이라 한다.
    • 모델에서 코드로 매끄러운 흐름
  • 연결완전성의 역방향이 성립한다.
  • 가역성 : 연결완전성과 반대로 코드에서 모델로의 매끄러운 흐름을 의미하는 것

7장 스터디

  • 코드와 모델을 밀접하게 연관시키는 것은 코드에 의미를 부여하고 모델을 적절하게 한다.
  • 코드는 아래 세 가지 관점을 모두 제공해야 한다.
  • 개념 관점 : 설계는 도메인 안에 존재하는 개념과 개념 사이의 관점을 표현한다.
  • 명세 관점 : 사용자의 영역인 도메인을 벗어나 개발자의 영역인 소프트웨어로 초점이 옮겨진다.
  • 구현 관점 : 실제 작업을 수행하는 코드와 연관돼 있다.
  • 인터페이스 정리하기
    • 객체가 수신한 메시지가 객체의 인터페이스를 결정한다.
    • 메시지가 객체를 선택하고, 선택된 객체는 메시지를 자신의 인터페이스로 받아들인다.
    • 객체가 어떤 메시지를 수신한다는 것은 그 객체의 인터페이 안에 메시지에 해당하는 오퍼레이션이 존재하는 것을 의미한다.
  • 도메인 개념을 참조하는 이유
    • 어떤 메시지가 있을 때 그 메시지를 수신할 객체를 어떻게 선택할 것인가
      • 가장 적절한 것을 선택하는 것이다.
      • 소프트웨어 클래스가 도메인 개념을 따르면 변화에 쉽게 대응할 수 있다.
  • 인터페이스와 구현을 분리하라
    • 명세 관점과 구현 관점에 뒤섞이지마라.
    • 명세 관점은 클래스의 안정적인 측면을 드러내야 한다.
    • 구현 관점은 클래스의 불안정한 측면을 드러내야 한다.
    • 인터페이스가 구현 세부 사항을 외부로 노출하기 시작하면 아주 작은 변동에도 전체 협력이 요동치는 취약한 설계를 얻을 수밖에 없다.
    • 클래스를 명세 관점과 구현 관정으로 나누어 볼 수 있어야 한다는 것이다.

요약1> 캡슐화를 위반해서 구현을 인터페이스 밖으로 노출하면 안된다.

요약2> 인터페이스와 구현을 명확하게 분리하지 않고 흐릿하게 섞어놓아도 안된다.

요약3> 결국 세 가지 관점 모두에서 클래스를 바라볼 수 있어야 한다.