새소식

반응형
Study/오브젝트

[Object] 4장 : 설계 품질과 트레이드오프

  • -
반응형

 

객체지향 설계의 핵심은 책임이다

  • 책임 - 객체지향 애플리케이션 전체의 품질을 결정
  • 객체지향 설계란 
    • 올바른 객체에게 올바른 책임을 할당하면서 낮은 결합도와 높은 응집도를 가진 구조를 창조하는 활동

설계는 변경을 위해 존재하고 변경에는 어떤 식으로든 비용이 발생한다.

->  훌륭한 설계란 합리적인 비용 안에서 변경을 수용할 수 있는 구조를 만드는 것

데이터 중심의 영화 예매 시스템

객체지향 설계에서 시스템을 객체로 분할하는 두 가지 방법 

  • 상태(데이터)를 분할의 중심축으로 : 객체는 자신이 포함하고 있는 데이터를 조작하는 데 필요한 오퍼레이션을 정의 
  • 책임을 분할의 중심축으로 : 객체는 다른 객체가 요청할 수 있는 오퍼레이션을 위해 필요한 상태를 보관

객체의 상태

  • 객체가 저장해야 하는 데이터의 집합 (상태 = 데이터).
  • 객체의 상태는 구현에 속한다.
    • 구현은 불안정하기 때문에 변화기 쉽다
    • 상태를 객체 분할의 중심축으로 삼으면 구현에 관한 세부사항이 객체의 인터페이스에 스며들게 되어 캡슐화의 원칙이 무너진다
    • 상태 변경 -> 인터페이스 변경을 초래 -> 인터페이스에 의존하는 모든 객체에게 변경의 영향이 퍼짐
    • 따라서 변경에 취약

객체의 책임

  • 인터페이스에 속한다
  • 책임을 드러내는 안정적인 인터페이스 뒤로 책임을 수행하는 데 필요한 상태를 캡슐화 -> 구현 변경에 대한 파장이 외부로 퍼져나가는 것을 방지
  • 따라서 책임에 초점을 맞추면 상대적으로 변경에 안정적인 설계를 얻을 수 있다

가끔씩은 좋은 설계보다는 나쁜 설계를 살펴보는 과정에서 통찰을 얻기도 한다

-> 객체의 상태를 기반으로 한 설계를 살펴보자

 

설계 트레이드오프

좋은 설계 

-> 높은 응집도와 낮은 결합도를 가진 모듈로 구성된 설계

-> 오늘의 기능을 수행하면서 내일의 변경을 수용할 수 있는 설계

캡슐화

객체지향에서 가장 중요한 원리

상태와 행동을 하나의 객체 안에 모으는 이유는 객체의 내부 구현을 외부로부터 감추기 위해서이다

객체지향이 강력한 이유는 한 곳에서 일어난 변경이 전체 시스템에 영향을 끼치지 않도록 파급효과를 적절하게 조절할 수 있는 장치를 제공하기 때문

외부에는 상대적으로 안정적인 부분만 공개함으로써 변경의 여파를 통제

변경될 수 있는 어떤 것이든 캡슐화해야 한다

응집도 

모듈에 포함된 내부 요소들이 연관돼 있는 정도 

모듈 내의 요소들이 하나의 목적을 위해 긴밀하게 협력한다면 그 모듈을 높은 응집도를 가짐 

객체지향의 관점에서 응집도는 객체 또는 클래스에 얼마나 관련 높은 책임들을 할당했는지를 나타낸다

변경이 발생할 때 모듈 내부에서 발생하는 변경의 정도

응집도 높음 = 변경의 대상과 범위가 명확해지므로 코드를 변경하기 쉬워짐 = 하나의 변경을 수용하기 위해 모듈 전체가 함께 변경됨, 하나의 변경에 대해 하나의 모듈만 변경됨

결합도 

의존성의 정도 

다른 모듈에 대해 얼마나 많은 지식을 갖고 있는지를 나타내는 척도 

어떤 모듈이 다른 모듈에 대해 너무 자세한 부분까지 알고 있다면 두 모듈은 높은 결합도를 가진다

어떤 모듈이 다른 모듈에 대해 꼭 필요한 지식만 알고 있다면 낮은 결합도를 가진다

객체지향의 관점에서 객체 또는 클래스가 협력에 필요한 적절한 수준의 관계만을 유지하고 있는지를 나타낸다

한 모듈이 변경되기 위해서 다른 모듈의 변경을 요구하는 정도 -> 하나의 모듈을 수정할 때 얼마나 많은 모듈을 함께 수정해야 하는지

내부 구현을 변경했을 때 이것이 다른 모듈에 영향을 미치는 경우 두 모듈 사이의 결합도가 높다고 표현한다

퍼블릭 인터페이스를 수정했을 때만 다른 모듈에 영향을 미치는 경우에는 결합도가 낮다고 표현한다

 

데이터 중심의 영화 예매 시스템의 문제점

캡슐화 위반 

인스턴스 변수가 존재한다는 사실을 퍼블릭 인터페이스에 드러낸다

접근자와 수정자 메서드는 객체 내부의 상태에 대한 어떤 정보도 캡슐화하지 못한다(getter, setter)

높은 결합도 

구현이 객체의 인터페이스에 드러난다는 것은 클라이언트가 구현에 강하게 결합된다는 것을 의미

데이터 중심 설계 : 제어 객체가 다수의 데이터 객체에 강하게 결합된다.

 -> 전체 시스템을 하나의 거대한 의존성 덩어리로 만듦 

 

결합도로 인해 어떤 데이터 객체를 변경하더라도 제어 객체를 함께 변경할 수밖에 없다.

-> 어떤 변경이라도 일단 발생하고 나면 시스템 전체가 요동친다.

낮은 응집도

변경의 이유가 서로 다른 코드들을 하나의 모듈 안에 뭉쳐놓았기 때문에 변경과 상관이 없는 코드들이 영향을 받게 된다

하나의 요구사항 변경을 반영하기 위해 동시에 여러 모듈을 수정해야 한다.

어떤 요구사항 변경을 수용하기 위해 하나 이상의 클래스를 수정해야 하는 것은 설계의 응집도가 낮다는 증거

 

자율적인 객체를 향해

속성의 가시성을 private으로 설정했다고 해도 접근자와 수정자를 통해 속성을 외부로 제공하고 있다면 캡슐화를 위반한 것

스스로 자신의 데이터를 책임지는 객체

우리가 상태와 행동을 객체라는 하나의 단위로 묶는 이유는 객체 스스로 자신의 상태를 처리할 수 있게 하기 위해서이다.

객체 내부에 저장되는 데이터보다 객체가 협력에 참여하면서 수행할 책임을 정의하는 오퍼레이션이 더 중요하다.

 

데이터 중심 설계의 문제점

데이터 중심 설계가 변경에 취약한 이유 

  • 데이터 중심 설계는 본질적으로 너무 이른 시기에 데이터에 관해 결정하도록 강요한다
  • 협력이라는 문맥을 고려하지 않고 객체를 고립시킨 채 오퍼레이션을 결정한다.

데이터 중심 설계는 객체의 행동보다는 상태에 초점을 맞춘다

  • 데이터 중심 설계의 첫 질문 : "이 객체가 포함해야 하는 데이터가 무엇인가?" 
  • 데이터 중심 설계에 익숙한 개발자 : 일반적으로 데이터와 기능을 분리하는 절차적 프로그래밍 방식을 따른다. 
  • 접근자와 수정자를 과도하게 추가하게 된다. -> 접근자와 수정자는 public 속성과 큰 차이가 없기 때문에 캡슐화가 무너진다. 
  • 개선된 코드에서도 데이터를 먼저 결정하고 데이터를 처리하는데 필요한 오프레이션을 나중에 결정하므로 데이터에 관한 지식이 객체의 인터페이스에 고스란히 드러난다. -> 캡슐화에 실패하고 코드는 변경에 취약해진다.
  • 결론적으로 데이터 중심의 설계는 너무 이른 시기에 데이터에 대해 고민하기 때문에 캡슐화에 실패하게 된다.
  • 객체의 내부 구현이 객체의 인터페이스를 어지럽히고 객체의 응집도와 결합도에 나쁜 영향을 미치기 때문에 변경에 취약한 코드를 낳게 된다.

데이터 중심 설계는 객체를 고립시킨 채 오퍼레이션을 정의하도록 만든다. 

중요한 것은 객체가 다른 객체와 협력하는 방법이다. 

데이터 중심 설계에서 초점은 객체의 외부가 아니라 내부로 향한다. 

-> 이미 구현된 객체의 인터페이스를 억지로 끼워 맞출 수밖에 없다. 

따라서 변경에 유연하게 대처하지 못한다.

반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.