Ch.7 유연한 설계
인지 과부하를 예방하자
단기 기억 vs. 장기 기억
단기 기억에 저장할 수 있는 정보의 개수는 많아야 5~9개를 넘지 못한다.
사람이 새로운 정보를 받아들이는 데 5초 정도의 시간이 소요된다고 한다.
문제 해결에 필요한 요소의 수가 단기 기억의 용량을 초과하는 순간 문제 해결 능력이 급격히 떨어지게 되는데, 이런 현상을 '인지 과부하(cognitive overload)'라고 부른다.
추상화하기
인지 과부하를 예방하는 가장 좋은 방법은 단기 기억 안에 보관할 정보의 양을 조절하는 것이다.
'추상화'를 통해 불필요한 정보를 제거하고 핵심만 남기자.
일반적인 추상화 방법은 '분해'를 통해 한번에 다뤄야 하는 문제의 크기를 줄이는 것이다.
프로시저 추상화와 데이터 추상화
프로시저 추상화 (Procedure Abstraction)
SW가 무엇을 "해야하는가"를 추상화
시스템 분해 방법은?
기능 분해 (Functional Decomposition) a.k.a. 알고리즘 분해 (Algorithmic Decomposition)
프로시저란?
반복적으로 실행되거나 거의 유사하게 실행되는 작업들을 하나의 장소에 모아놓음으로써 로직을 재사용하고 중복을 방지할 수 있는 추상화 방법이다.
시스템을 최상위의 가장 추상적인 메인 함수로 정의하고, 메인 함수를 구현 가능한 수준까지 분해하는 방법이다.
e.g., 급여를 계산한다 = 사용자로부터 소득세율을 입력받는다 + 직원의 급여를 계산한다 + 양식에 맞게 결과를 출력한다
모든 문장이 정제를 통해 하나 이상의 단순한 문장의 조합이 된다.
전통적인 기능 분해 방법은 하향식 접근법 (Top-Down Approach)
문제점은...
시스템이 하나의 메인 함수로 구성돼 있지 않다.
(비현실적이다.)
기능 추가나 요구사항 변경으로 인해 메인 함수를 자주 수정해야 한다.
(시스템 안은 여러 개의 정상이 있다.)
비즈니스 로직이 사용자 인터페이스와 강하게 결합된다.
(비즈니스 로직과 사용자 인터페이스가 변경되는 빈도는 다르다.)
하향식 분해는 너무 이른 시기에 함수들의 실행 순서를 고정시키기 때문에 유연성과 재사용성이 저하된다.
(실행 순서가 중요해서 시간 제약이 강조된다.)
(함수의 제어 구조는 빈번한 변경의 대상이라는 것이 문제가 된다.)
이를 해결하기 위해서는 안정적인 논리적 제약을 설계의 기준으로 삼는 것!
데이터 형식이 변경될 경우 파급효과를 예측할 수 없다. (부수효과)
(어떤 데이터를 어떤 함수가 사용하고 있는지를 추적하기 어렵다.)
그래도 이런 경우 유용하다.
설계가 어느 정도 안정화 된 후(이미 완전히 이해된 경우)에는 설계의 다양한 측면을 논리적으로 설명하고 문서화하기 용이하다.
데이터 추상화 (Data Abstraction)
SW가 무엇을 "알아야 하는가"를 추상화
시스템 분해 방법?
타입 추상화 (Type Abstraction) a.k.a. 추상 데이터 타입 (Abstract Data Type)
프로시저 추상화 (Procedure Abstraction) a.k.a. 객체지향 (Object-Oriented)
모듈
정보 은닉 (Information Hiding)
시스템을 모듈 단위로 분해하기 위한 기본 원리로, 시스템에서 자주 변경되는 부분을 상대적으로 덜 변경되는 안정적인 인터페이스 뒤로 감춰야 한다는 것이 핵심.
서브 프로그램이라기보다는 '책임의 할당'
모듈 (Module)
시스템의 변경을 관리하는 기본 전략은:
함께 변경되는 부분을 하나의 구현 단위로 묶고,
퍼블릭 인터페이스를 통해서만 접근하도록 하는 것이다.
즉, 기능이 아닌 변경의 방향을 기반으로 시스템을 분해하는 것!
시스템을 모듈 단위로 분해하려면:
시스템이 감춰야 할 비밀을 찾아라.
외부에서 내부의 비밀에 접근하지 못하도록 퍼블릭 인터페이스를 만들어라. (정보 은닉)
모듈은 다음 두 가지 비밀을 감춰야 한다:
복잡성 - 모듈이 너무 복잡하면 이해/사용이 어렵다.
변경 가능성 - 변경 가능한 설계 결정이 외부에 노출될 경우 실제 변경이 발생했을 때 파급효과가 커진다.
모듈의 장점과 한계
장점
모듈 내부 변수가 변경되더라도 내부에만 영향을 미친다.
비즈니스 로직과 사용자 인터페이스에 대한 관심사를 분리한다. (GUI가 추가되어도 비즈니스 로직은 변경되지 않는다.)
전역 변수, 전역 함수를 제거함으로써 네임페이스 오염을 방지한다. (다른 모듈에서도 동일 이름을 사용할 수 있다.)
단점은 인스턴스의 개념을 제공하지 않는다는 것.
예제에서 좀 더 높은 수준의 추상화를 위해 직원 전체가 아닌 개별 직원을 독립적인 단위로 다룰 수 있어야 하고, 이를 위해 추상 데이터 타입이 등장한다.
데이터 추상화와 추상 데이터 타입
추상 데이터 타입의 전제조건
다음 특성을 위한 프로그래밍 언어의 지원이 필요하다.
타입 정의를 선언할 수 있어야 한다.
타입의 인스턴스를 다루기 위해 사용할 수 있는 오퍼레이션의 집합을 정의할 수 있어야 한다.
제공된 오퍼레이션을 통해서만 조작할 수 있도록 데이터를 외부로부터 보호할 수 있어야 한다.
타입에 대해 여러 개의 인스턴스를 생성할 수 있어야 한다.
하지만 프로그래밍 언어의 관점에서 추상 데이터 타입은 내장 데이터 타입과 동일하다. 단지 타입을 개발자가 정의할 수 있다는 게 다를 뿐...
상속과 다형성을 지원하지 않는 추상 데이터 타입 기반의 프로그래밍 패러다임을 객체기반 프로그래밍(Object-Based Programming)이라고 부르기도 한다.
클래스
클래스는 추상 데이터 타입인가?
둘이 같은 점도 있지만 동일하지 않다.
클래스는 상속과 다형성을 지원하는 데 비해 추상 데이터 타입을 지원하지 못한다.
추상 데이터 타입은 오퍼레이션을 타입으로 묶는 반면, 객체지향은 타입을 기준으로 오퍼레이션을 묶는다. (반대)
객체지향은 절차 추상화 (Procedural Abstraction)이다.
변경을 기준으로 선택하라
타입 변수를 이용한 조건문을 다형성으로 대체한다. (Replcae Type Code with Class)
클라이언트가 객체의 타입을 확인한 후 적절한 메서드를 호출하는 것이 아니라 객체가 메시지를 처리할 적절한 메서드를 선택하는 것이다.
이렇게 OCP를 적용해보자!
Last updated