요약
- Parnas는 동일한 알고리즘을 쓰고 심지어 동일한 실행 가능한 표현을 만들 수도 있는 두 개의 KWIC 시스템을 비교했다. 두 시스템의 차이는 설계 지식이 어디에 놓이는가였다. 처리 단계 인터페이스는 공유 형식을 드러냈고, 정보 은닉 모듈은 변동 가능한 결정을 한곳에 가둬 두었다.
- 변경 표는 구체적이었다. 행을 메모리 밖으로 내보내거나 문자 패킹 방식을 바꾸면 첫 번째 분해에서는 모든 모듈이 영향을 받았지만 두 번째에서는 Line Storage만 영향을 받았다. 순환 시프트의 표현 방식을 바꾸는 경우 첫 번째 설계에서는 세 모듈, 두 번째에서는 한 모듈이 영향을 받았다.
- 정보 은닉은 기밀 유지도, 접근 제어도, 객체 지향도, 자동적인 속도 향상도 아니다. 논문 자체가 프로시저 호출 오버헤드를 경고하고, 자신의 인터페이스 중 하나가 불필요한 순서를 드러내는 설계 오류라고 명시한다.
인수 테스트 이후부터 시작된다
작은 테스트 하네스를 상상해 보라. 두 구현에 같은 제목들을 넣는다. 모든 순환 시프트와 최종 알파벳 순서를 검사한다. 둘 다 통과한다. 이 시점의 정확성이 유일한 기준이라면 두 아키텍처는 무승부다.
Parnas는 의도적으로 독자에게 그 쉬운 결론을 주지 않았다. 1972년 12월Communications of the ACM에 실린On the Criteria To Be Used in Decomposing Systems into Modules에서 그는 두 방식 모두 작동한다고 말한다. 두 방식은 알고리즘과 데이터 표현을 공유할 수 있고, 어셈블 이후에는 실행 형태까지 동일할 수 있다. 구별은 시스템을 변경하고, 문서화하고, 이해하기 위해 사용하는 표현에서 나타난다. 즉 작업이 어떻게 배정되는지, 어떤 결정이 인터페이스를 넘어가는지, 그 결정이 바뀔 때 누구와 협의해야 하는지이다.
그래서 유용한 실험은 출력이 동일함이 확인된 뒤에야 시작된다. 행 표현을 바꾸고, 모든 행을 메모리에 두지 않고, 시프트를 요청 시점에 계산하고, 알파벳 정렬을 여러 요청에 걸쳐 나눠 보라. 새로운 선택을 이해해야 하는 작업 배정의 수를 세어 보라. 그 결과로 나타나는 파급 반경은 스냅숏 인수 테스트가 볼 수 없는 아키텍처적 속성이다.
KWIC은 설계 우화가 되기 전에 실제 색인 문제였다
KWIC은 Key Word in Context의 약자다. Hans Peter Luhn의 1960년 논문은 키워드가 제목의 주변 단어들과 함께 표시되는 기계 생성 색인을 기술했으며, 이를 통해 현재의 색인을 기계적으로 만들 수 있었다. Parnas는 그 정보 검색 형식을 발명한 것이 아니다. 그는 경쟁하는 분해 방식들을 비교하면서 논거가 큰 애플리케이션에 파묻히지 않을 만큼 작고 이미 이해 가능한 시스템을 골랐다.
그가 단순화한 KWIC은 순서 있는 행 집합을 입력으로 받는다. 각 행은 단어들로 이루어져 있고 각 단어는 문자들로 이루어져 있다. 첫 단어를 끝으로 반복해서 옮기면 행은 자신의 순환 시프트들을 만들어 낸다. 시스템은 모든 행의 모든 시프트를 알파벳 순서로 출력한다.
이 예제는 의도적으로 작았다. Parnas는 능숙한 프로그래머라면 일주일에서 두 주 만에 만들 수 있다고 추정했다. 요점은 KWIC이 산업 규모의 프로젝트 관리를 요구한다는 것이 아니라, 작은 시스템이 숨은 가정을 충분히 들여다볼 수 있을 정도로 드러낸다는 것이었다.
첫 번째 절단은 시간을 따랐다
전통적인 분해는 처리 순서를 그대로 반영했다. Input은 행을 읽어 코어에 저장했다. Circular Shift는 시프트 색인을 만들었다. Alphabetizing은 그 색인을 재정렬했다. Output은 결과를 형식화했다. Master Control은 나머지 넷의 순서를 제어했다.
이 배치는 모듈화된 것처럼 보였다. 각 작업에 이름이 있었고 프로그램은 관리 가능한 조각들로 나뉘어 있었다. 그러나 인터페이스는 단순히 어떤 작업이 다른 작업에게 어떤 서비스를 필요로 하는지를 진술한 것이 아니었다. 인터페이스에는 코어 레이아웃, 색인, 포인터 규약, 표 형식이 포함되어 있었다. Input은 네 개의 문자를 한 워드에 압축했다. Circular Shift와 Alphabetizing은 앞선 배열들이 어떻게 표현되는지 알고 있었다. Output은 알파벳 정렬 단계와 입력 단계 양쪽이 만든 배열을 사용했다.
처리 단계들은 서로 분리되어 있었지만, 저장 방식에 대한 지식은 공유되고 있었다. 흐름도는 제어를 나누면서 여러 변경 가능한 결정을 경계의 틈새에 남겨 두었다.
두 번째 절단은 결정을 따랐다
대안적 분해는 각 모듈을 한 단계에 대응시키지 않았다. Line Storage는 행의 표현을 소유하고 문자·단어·행을 주소 지정하는 연산을 노출했다. Input은 그 연산들을 사용했다. Circular Shifter는 클라이언트가 시프트들이 저장되는지, 색인되는지, 요청 시점에 계산되는지 알 필요가 없도록, 시프트된 행들의 모음처럼 보이는 인터페이스를 제시했다. Alphabetizer는 정렬 연산을 노출했고, Output은 그 결과 추상화를 소비했으며, Master Control이 작업을 조율했다.
여기서 "모듈"은 서브루틴이 아니라 책임의 배정을 뜻했다. 이 구별이 핵심이다. 한 모듈은 여러 호출 가능한 루틴을 담을 수 있다. 반대로 효율적인 어셈블된 프로그램은 둘 이상의 모듈이 기여한 코드를 포함할 수 있다. 소스 파일, 클래스, 패키지, 프로세스, 팀은 때때로 모듈 경계를 구현할 수 있지만, 어느 것도 자동으로 Parnas가 뜻한 경계는 아니다.
기준은 지식이었다. 각 모듈은 자신은 알지만 다른 이들이 알 필요 없는, 어렵거나 바뀔 가능성이 높은 설계 결정으로 특징지어졌다. 모듈의 인터페이스는 클라이언트가 요구하는 만큼만 그 결정에 대해 드러내야 했다.
다섯 가지 변경이 차이를 드러냈다
Parnas의 비교는 슬로건보다 더 유용하다. 영향을 받는 집합을 특정하기 때문이다.
첫째, 입력 형식 변경은 두 분해 모두에서 Input 내부에 머물렀다. 정보 은닉이 표의 모든 행에서 이긴 것은 아니다. 전통적인 설계는 이미 그 선택을 잘 배치해 두고 있었다.
둘째, 시스템이 더 이상 모든 행을 메모리에 유지할 수 없게 되었다고 하자. 첫 번째 분해에서는 모든 모듈이 코어 행 형식을 사용하므로 모든 모듈이 변경되었다. 두 번째에서는 행이 상주하는지, 페이징되는지, 어떻게 표현되는지를 오직 Line Storage만 알고 있었다.
셋째, 네 개의 문자를 한 기계 워드에 압축한다는 결정을 바꿔 보라. 역시 첫 번째 설계는 그 형식을 모든 프로그램에 걸쳐 흩었지만 두 번째는 Line Storage 안에 가뒀다.
넷째, 순환 시프트를 원래 행들에 대한 색인에서 명시적으로 저장된 행들로 바꾸거나, 요청되는 문자를 그때그때 계산하도록 해 보라. 첫 번째 설계에서 Circular Shift, Alphabetizer, Output은 그 표현을 알고 있었다. 두 번째에서는 Circular Shifter만이 그것을 소유했다.
다섯째, 목록 전체를 한 번 정렬하는 대신 필요할 때마다 다음 항목을 찾거나, 색인이 만들어지는 기간에 걸쳐 정렬 작업을 나눠 보라. 첫 번째 설계에서 Output은 완성된 색인을 기대했다. 두 번째에서는 클라이언트가 알파벳 정렬이 언제 일어나는지 감지할 수 없었으므로, 대안은 Alphabetizer 안에 머물렀다.
이것들은 모든 미래 요구사항이 파일 하나만 바꾼다는 약속이 아니다. 이름 붙은 가정은 의도적으로 배정될 수 있다는 증거다. 첫 번째 분해는 실행의 그림을 최적화했다. 두 번째는 변동성에 대한 지식의 분배를 최적화했다.
인터페이스는 메커니즘을 숨기면서도 너무 많이 드러낼 수 있다
Parnas는 두 번째 설계를 완전한 것으로 제시하지 않았다. 그의 Circular Shifter 인터페이스는 앞선 행들의 시프트가 먼저 오고, 각 행의 원본이 연속 회전들보다 앞선다는 점을 명시했다. 클라이언트는 그 순서를 필요로 하지 않았다. 이 규약은 시프트를 알파벳 순서로 직접 생성하는 구현을 막고 Alphabetizer를 사실상 텅 비게 만들었다.
그는 이 선택을 설계 오류로 분류했다. 시프트를 저장하거나 계산하는 방법은 숨겨져 있었지만, 불필요한 순서 보장이 새어 나온 것이다. 이것은 "데이터를 함수로 접근하라"는 말보다 엄격한 테스트다. 표현을 감싼 래퍼는 메서드 이름, 반환 형태, 열거 순서, 타이밍 보장으로 그 표현의 변동성을 전부 재현할 수 있다.
따라서 인터페이스 검토의 질문은 내부 필드가 비공개인가만이 아니다. 공개된 각 사실이 클라이언트에게 필요한가이다. 정보 은닉은 결정에 의존할 자격이 있는 사람과 컴포넌트의 수를 줄이는 것이지, 불투명성 자체를 치찬하는 것이 아니다.
이 기준이 뜻하지 않는 것
"은닉"이라는 단어는 논문이 지지하지 않는 보안적 해석을 부르기 쉽다. 이것은 암호화도, 인가도, 샌드박싱도, 런타임 격리도 아니다. 비밀은 안전하게 암호화되면서도 모든 모듈이 이해해야 하는 스키마로 표현될 수 있다. 변동 가능한 결정은 완전히 공개되어 있으면서도 하나의 프로그래밍 인터페이스 뒤에 가둬질 수 있다.
정보 은닉이 곧 객체 지향인 것도 아니다. 추상 데이터 타입이나 클래스는 표현에 대한 접근을 제어하는 유용한 메커니즘이 될 수 있다. 동시에 구현 순서, 영속성 세부사항, 바뀌기 쉬운 분류 체계를 노출할 수도 있다. Parnas의 기준은 클래스가 없는 언어에서도 적용되며, 단일 타입보다 큰 작업 배정에 걸쳐 적용된다.
"높은 응집도"와 "낮은 결합도"는 나중에 쓸모 있는 어휘지만, 숨은 결정의 이름을 붙이는 것을 대신하지 못한다. 컴파일 의존성은 또 다른 문제다. 빌드 시스템은 클라이언트의 소스와 논리가 여전히 유효하더라도 라이브러리가 바뀌면 클라이언트를 다시 컴파일할 수 있다. 반대로 서비스는 독립적으로 배포하면서도 소비자들이 문서화되지 않은 순서나 오류 규약에 개념적으로 의존할 수 있다.
성능도 자동이 아니다. Parnas는 모든 세분화된 연산이 복잡한 프로시저 호출이 되면 두 번째 설계가 느려질 수 있다고 경고했다. 그는 전통적인 호출 오버헤드를 치르지 않고 설계 경계를 유지하는 방법으로 특수화된 전송과 어셈블 시점 삽입을 스케치했다. 트레이드오프는 공학적으로 다루어야 하며, 원칙이 그것을 사라지게 하지 않는다.
Parnas는 나중에 KWIC의 또 다른 새는 곳을 발견했다
나중의 성찰은 교훈을 더 날카롭게 했다. Parnas는 원래 예제가 여전히 모듈들이 문자열을 문자의 열이라고 가정하도록 허용했다고 지적했다. 이 공유된 가정은 자주 쓰이는 문자열을 압축된 정수로 표현하는 것을 막을 수 있었다. 유명한 정보 은닉 예제조차 중요할 수 있는 모든 표현 결정을 숨기지는 않았던 것이다.
이 인정은 그 아이디어를 의례화로부터 지켜 준다. 모듈 다이어그램이 있다는 사실이 올바른 정보가 숨겨져 있다는 증거는 아니다. 설계자들은 불확실성 속에서 미래의 결정을 찾아내야 하고, 틀릴 수도 있다. 해법은 API를 영구적이라고 선언하는 것이 아니라, 클라이언트가 실제로 알아야 하는 것이 무엇인지를 계속 다시 살펴보는 것이다.
아이디어는 커뮤니티를 통해 성장했다
1972년 논문은 Parnas의 1971년 정보 분배에 관한 연구 위에 세워졌다. 그 연구는 모듈 간 연결을 서로가 상대에 대해 만드는 가정의 관점에서 기술했다. 1976년 프로그램 패밀리에 관한 그의 연구는 시간 지평을 넓혔다. 관련된 프로그램들이 존재할 것이라면, 그 공통 속성들은 각 버전이 개별적으로 다뤄지기 전에 설계되어야 한다는 것이다.
1985년에 Parnas, Paul C. Clements, David M. Weiss가 함께The Modular Structure of Complex Systems를 발표했다. 그들은 모듈 구조, 사용 구조, 프로세스 구조를 구별하고, 유지보수자가 무관한 세부사항을 읽지 않고도 이해해야 할 부분을 찾도록 돕는 모듈 가이드를 기술했다. 이것은 각주가 아니라 계속이다. 작업 배정 구조가 호출 순서나 런타임 프로세스와 혼동되는 일을 막아 주기 때문이다.
이후 연구자들은 KWIC을 공유 데이터, 파이프-필터, 이벤트 기반 등 다양한 아키텍처 스타일을 비교하는 데 사용했다. 추상 데이터 타입, 캡슐화 메커니즘, 소프트웨어 아키텍처, 제품군 방법들은 이 대화를 더 발전시켰다. 1972년의 결과는 이후의 모든 것을 소유한다고 주장하지 않으면서도 여전히 강력하다. 그 지속적 기여는 실험 그 자체다. 관찰 가능한 출력을 일정하게 유지한 채, 결정 하나를 건드리고, 알아야 할 필요가 얼마나 멀리 퍼지는지를 보라.
출처
- David L. Parnas,On the Criteria To Be Used in Decomposing Systems into Modules, ACM
- David L. Parnas,Information Distribution Aspects of Design Methodology
- David L. Parnas,On the Design and Development of Program Families
- David L. Parnas, Paul C. Clements, David M. Weiss,The Modular Structure of Complex Systems, McMaster 기록
- Peter J. Denning, David Parnas 인터뷰,Communications of the ACM
- David Garlan, Mary Shaw,An Introduction to Software Architecture, Carnegie Mellon Software Engineering Institute
- H. P. Luhn,Key word-in-context index for technical literature
회원 브리핑
프로필 심층 컨텍스트
올바른 멤버십 등급으로 로그인하면 전체 브리핑과 출처 노트를 볼 수 있습니다.
Strategic Circle 전용
Strategic Circle
모든 독자에게 공개됩니다. 가입 후 로그인하면 프로필 브리핑를 열람할 수 있습니다.
Strategic Circle 가입하기Leadership Alliance 전용
Leadership Alliance
자격을 갖춘 IP 자산 소유자 및 운영진을 위한 콘텐츠입니다. 로그인하면 Leadership Alliance 브리핑을 열람할 수 있습니다.
Leadership Alliance 가입하기





