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