목차
- ☆ 표시가 붙은 부분은 스터디 중 나온 얘기 혹은 제 개인적인 생각이나 제가 이해한 방식을 적어놓은 것으로, 책에 나오지 않는 내용입니다. 따라서 책에서 말하고자 하는 바와 다를 수 있습니다.
- 모든 이미지의 출처는 오브젝트(조용호 저) 책 입니다.
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)
- 기존 코드에 아무런 영향도 미치지 않고 새로운 객체 유형과 행위를 추가할 수 있는 객체지향의 특성
- 객체지향 설계가 전통적인 방식에 비해 변경하고 확장하기 쉬운 구조를 설계할 수 있는 이유
'Study > 오브젝트' 카테고리의 다른 글
[오브젝트] 9장. 유연한 설계 (0) | 2022.12.22 |
---|---|
[오브젝트] 8장. 의존성 관리하기 (0) | 2022.12.22 |
[오브젝트] 6장. 메시지와 인터페이스 (2) | 2022.12.08 |
[오브젝트] 5장. 책임 할당하기 (0) | 2022.12.02 |
[오브젝트] 4장. 설계 품질과 트레이드오프 (0) | 2022.12.02 |
댓글