본문 바로가기
Study/오브젝트

[오브젝트] 7장. 객체 분해

by Nahwasa 2022. 12. 8.

스터디 메인 페이지

목차

    - ☆ 표시가 붙은 부분은 스터디 중 나온 얘기 혹은 제 개인적인 생각이나 제가 이해한 방식을 적어놓은 것으로, 책에 나오지 않는 내용입니다. 따라서 책에서 말하고자 하는 바와 다를 수 있습니다.

    - 모든 이미지의 출처는 오브젝트(조용호 저) 책 입니다.

     

     


     

    CHAPTER 07. 객체 분해

    ⚈ 문제를 해결하기 위해 사용하는 저장소는 장기 기억이 아니라 단기기억이다.

    • 문제 해결에 필요한 요소의 수가 단기 기억의 용량을 초과하는 순간 문제 해결 능력은 급격하게 떨어진다. -> 인지 과부하(cognitive overload)
    • 인지 과부하 방지 : 단기 기억 안에 보관할 정보의 양을 조절하는 것

    인류가 복잡한 분야(소프트웨어 개발 영역)의 문제를 해결하기 위해 사용한 것

    • 추상화 : 불필요한 정보를 제거하고 현재의 문제 해결에 필요한 핵심만 남기는 작업. 즉, 한 번에 다뤄야 하는 문제의 크기를 줄이는 것 -> 한 번에 단기 기억에 담을 수 있는 추상화의 수에는 한계가 있지만 추상화를 더 큰 규모의 추상화로 압축시킴으로써 단기 기억의 한계를 초월할 수 있다.
    • 분해(decomposition) : 큰 문제를 해결 가능한 작은 문제로 나누는 작업

     


    01 프로시저 추상화와 데이터 추상화

    프로그래밍 언어의 발전

    • 좀 더 효과적인 추상화를 이용해 복잡성을 극복하려는 개발자들의 노력에서 출발
    • 어셈블리어 : 기계어에 인간이 이해할 수 있는 상징을 부여하려는 노력
    • 고수준언어 : 인간의 눈높이에 맞는 기계 독립적이고 의미 있는 추상화를 제공하려는 시도
    • 프로그래밍 언어를 통해 표현되는 추상화의 발전 -> 다양한 프로그래밍 패러다임의 탄생으로 이어짐

     

    추상화와 분해

    • 프로그래밍 패러다임 : 적절한 추상화의 윤곽을 따라 시스템을 어떤 식으로 나눌 것인지를 결정하는 원칙과 방법의 집합
    • 모든 프로그래밍 패러다임은 추상화와 분해의 관점에서 설명할 수 있다.
    • 소프트웨어는 데이터를 이용해 정보를 표현하고 프로시저를 이용해 데이터를 조작한다.
    • 프로시저 추상화(procedure abstraction) : 프로그램이 무엇을 해야 하는지를 추상화
      • 프로시저 추상화를 중심으로 시스템을 분해 -> 기능 분해(functional decomposition, =알고리즘 분해)
    • 데이터 추상화(data abstraction) : 소프트웨어가 무엇을 알아야 하는지를 추상화.
      • 데이터 추상화를 중심으로 시스템을 분해할 경우엔 두 가지 중 하나를 선택해야 함 -> 1. 데이터를 중심으로 타입을 추상화(추상 데이터 타입, Abstract Data Type), 2. 데이터를 중심으로 프로시저를 추상화(객체지향, Object-Oriented)
      • '역할과 책임을 수행하는 객체'가 바로 객체지향 패러다임이 이용하는 추상화. 기능을 '협력하는 공동체'를 구성하도록 객체들로 나누는 과정이 바로 객체지향 패러다임에서의 분해를 의미.

     


    02 프로시저 추상화와 기능 분해

     책에서 객체지향 분해가 '효과적'이라고 말하는 이유를 보기 위해 우선 전통적인 기능 분해 방법을 살펴보는 내용이다.

     

    ⚈ ☆절차지향 패러다임 생각하고 보면 될듯.

     

    ⚈ 전통적인 기능 분해 방법

    • 기능 분해의 관점에서 추상화의 단위는 프로시저. 시스템은 프로시저를 단위로 분해된다.
    • 프로시저는 반복적으로 실행되거나 거의 유사하게 실행되는 작업들을 하나의 장소에 모아놓음으로써 로직을 재사용하고 중복을 방지할 수 있는 추상화 방법
    • 시스템은 입력 값을 계산해서 출력 값을 반환하는 수학의 함수와 동일 -> 시스템은 필요한 더 작은 작업으로 분해될 수 있는 하나의 커다란 메인 함수
    • 하향식 접근법(Top-Down Approach)을 따른다. -> 가장 최상위 기능을 정의하고 최상위 기능을 좀 더 작은 단계의 기능으로 분해해 나간다. 분해는 세분화된 마지막 하위 기능이 프로그래밍 언어로 구현 가능한 수준이 될 때까지 계속됨. (트리 구조)
    • 기능 분해의 결과는 최상위 기능을 수행하는 데 필요한 절차들을 시간 순서에 따라 나열한 것
    직원의 급여를 계산한다
      사용자로부터 소득세율을 입력받는다
        "세율을 입력하세요: "라는 문장을 화면에 출력한다
        키보드를 통해 세율을 입력받는다
      직원의 급여를 계산한다
        전역 변수에 저장된 직원의 기본급 정보를 얻는다
        급여를 계산한다
      양식에 맞게 결과를 출력한다
        "이름: {직원명}, 급여: {계산된 금액}" 형식에 따라 출력 문자열을 생성한다

     

    기능 분해 방법은 기능을 중심으로 필요한 데이터를 결정한다.

    • 먼저 필요한 기능을 생각하고 이 기능을 분해하고 정제하는 과정에서 필요한 데이터의 종류와 저장 방식을 식별

     

    하향식 기능 분해의 문제점 1 - 하나의 메인 함수라는 비현실적인 아이디어

    • 어떤 시스템이라도 시간이 지나고 사용자를 만족시키기 위한 새로운 요구사항을 도출해나가면서 지속적으로 새로운 기능을 추가하게 된다.
    • 이 때 대부분의 경우 추가되는 기능은 최초에 배포된 메인 함수의 일부가 아닐 것이다.
    • "실제 시스템이 정상(top)이란 존재하지 않는다."

     

     하향식 기능 분해의 문제점 2 - 메인 함수의 빈번한 재설계

    • 새로운 기능을 추가할 때마다 매번 메인 함수를 수정해야 한다.
    • 기존 코드를 수정하는 것은 항상 새로운 버그를 만들어낼 확률을 높인다 -> 시스템은 변경에 취약해진다.

     

     하향식 기능 분해의 문제점 3 - 비즈니스 로직과 사용자 인터페이스의 결합

    • 하향식 접근법은 비즈니스 로직을 설계하는 초기 단계부터 입력 방법과 출력 양식을 함께 고민하도록 강요한다.
    • 사용자 인터페이스는 시스템 내에서 가장 자주 변경되는 부분이고, 비즈니스 로직은 변경이 적게 발생한다. 하지만 하향식 접근법은 이 둘을 섞기 때문에 사용자 인터페이스를 변경하는 경우 비즈니스 로직까지 변경에 영향을 받게 된다.
    • 따라서 변경에 불안정한 아키텍처를 낳는다.

     

     하향식 기능 분해의 문제점 4 - 성급하게 결정된 실행 순서

    • 설계를 시작하는 시점부터 시스템이 무엇(what)을 해야 하는지가 아니라 어떻게(how) 동작해야 하는지에 집중하도록 만든다.
    • 실행 순서나 조건, 반복과 같은 제어 구조를 미리 결정하지 않고는 분해를 진행할 수 없기 때문에 중앙집중 제어 스타일(centralized control style)의 형태를 띌 수밖에 없다.
    • 문제는 함수의 제어 구조가 빈번한 변경의 대상이라는 점 -> 결과적으로 기능을 추가하거나 변경하는 작업은 매번 기존에 결정된 함수의 제어구조를 변경하도록 만든다.

     

     하향식 기능 분해의 문제점 5 - 데이터 변경으로 인한 파급효과

    • 하향식 기능 분해는 어떤 데이터를 어떤 함수가 사용하고 있는지를 추적하기 어렵다. (개별 함수에서 어떤 데이터가 쓰이는지는 쉽지만, 그 반대로 어떤 데이터가 어느 함수에서 사용하는지 추적하기가 어렵다는 말)
    • 따라서 데이터 변경으로 인해 어떤 함수가 영향을 받을지 예상하기 어렵다.

     

     하향식 기능 분해의 문제점 해결책 : 정보 은닉과 모듈

    • 의존성 관리 : 데이터 변경으로 인한 영향을 최소화하려면 데이터와 함께 변경되는 부분과 그렇지 않은 부분을 명확하게 분리해야 한다.
    • 변경에 대한 영향을 최소화하기 위해 영향을 받는 부분과 받지 않는 부분을 명확하게 분리하고 잘 정의된 퍼블릭 인터페이스를 통해 변경되는 부분에 대한 접근을 통제하자 -> 정보 은닉과 모듈 개념 제시

     

     하향식 분해가 유용한 경우

    • 설계가 어느 정도 안정화 된 후에는 설계의 다양한 측면을 논리적으로 설명하고 문서화하기에 용이하다.
    • 하향식은 이미 완전히 이해된 사실을 서술하기에 적합한 방법이다.
    • 작은 프로그램과 개별 알고리즘을 위해서는 유용한 패러다임 -> 특히 이미 해결된 알고리즘을 문서화하고 서술하는 데는 훌륭한 기법.

     


    03 모듈

     시스템의 변경을 관리하는 기본적인 전략

    • 함께 변경되는 부분을 하나의 구현단위로 묶고 퍼블릭 인터페이스를 통해서만 접근하도록 만드는 것 -> 즉, 기능이 아니라 변경의 방향에 맞춰 시스템을 분해하는 것.

     

    정보 은닉(information hiding)

    • 시스템에서 자주 변경되는 부분을 상대적으로 덜 변경되는 안정적인 인터페이스 뒤로 감쳐워 한다
    • 외부에 감춰야 하는 비밀에 따라 시스템을 분할하는 모듈 분할 원리

     

    모듈의 장점과 한계

    • 모듈 내부의 벼눗가 변경되더라도 모듈 내부에만 영향을 미친다.
    • 비즈니스 로직과 사용자 인터페이스에 대한 관심사를 분리한다.
    • 전역 변수와 전역 함수를 제거함으로써 네임스페이스 오염(namespace pollution)을 방지한다.

     


    04 데이터 추상화와 추상 데이터 타입

    타입(type) : 변수에 저장할 수 있는 내용물의 종류와 변수에 적용될 수 있는 연산의 가짓수. (예를들어 정수 타입이라면 변수는 임의의 정숫값으로 간주) -> 변수의 값이 어떻게 행동할 것이라는 것을 예측할 수 있게 한다.

     

    기능 분해의 시대에 사용되던 절차형 언어들은 적은 수의 내장 타입만을 제공했으며 새로운 타입을 추가하는 것이 불가능하거나 제한적이었다. -> 보완하기 위해 데이터 추상화(data abstraction) 개념을 제안.

     

    추상 데이터 타입을 구현하기 위해 필요한 프로그래밍 언어의 지원

    • 타입 정의를 선언할 수 있어야 한다
    • 타입의 인스턴스를 다루기 위해 사용할 수 있는 오퍼레이션의 집합을 정의할 수 있어야 한다
    • 제공된 오퍼레이션을 통해서만 조작할 수 있도록 데이터를 외부로부터 보호할 수 있어야 한다
    • 타입에 대해 여러 개의 인스턴스를 생성할 수 있어야 한다

     

    ☆ 추상 데이터 타입은 struct라고 보면 될 것 같다.

     


    05 클래스

    클래스 vs 추상 데이터 타입

    • 클래스는 상속과 다형성을 지원하는 데 비해 추상 데이터 타입은 지원하지 못한다
    • 객체지향 프로그래밍(Object-Oriented Programming) : 상속과 다형성 지원
    • 객체기반 프로그래밍(Object-Based Programming) : 상속과 다형성을 지원하지 않는 추상 데이터 타입 기반의 프로그래밍 패러다임
    • 추상 데이터 타입 : 오퍼레이션을 기준으로 타입을 묶는 방법
    • 객체지향 : 타입을 기준으로 오퍼레이션을 묶는다.

     

    개방-폐쇄 원칙(Open-Closed Principle, OCP)

    • 기존 코드에 아무런 영향도 미치지 않고 새로운 객체 유형과 행위를 추가할 수 있는 객체지향의 특성
    • 객체지향 설계가 전통적인 방식에 비해 변경하고 확장하기 쉬운 구조를 설계할 수 있는 이유

    댓글