3 사상 프로그래밍의 이데올로기 - ChoDragon9/posts GitHub Wiki
목차
- 3.1 프로그래밍 이론
- 3.11 아키텍쳐 기본 기법
- 3.22 아키텍처 비기능 요구사항
- 3.29 7가지 설계 원리
- 3.37 UNIX 사상
- 3.55 UNIX 철학
3. 사상: 프로그래밍의 이데올로기
3.1 프로그래밍 이론
좋은 프로그래머는 시간이 걸리더라도 언어, 도구, 기술, 문제 영역 등 분야를 막론하고 제대로 이해하고 나서 작업에 착수하는 경향이 있다. 제대로 이유를 설명할 수 있을 때까지 끈질기게 이해하고 나서 코드를 확정하도록 하자.
3.2 의사소통
소프트웨어 개발 비용의 대부분은 최초 개발된 이후에 발생한다. 즉, 유지보수에 드는 비용이다. 코드는 작성하는 시간보다 읽는 시간이 압도적으로 많다. 코드를 통해 원활하게 의사소통을 하려면 코드를 작성할 때 다른 사람의 입장에서 생각해야 한다.
3.3 단순함
코드가 단순하다는 것은 코드에서 불필요한 복잡성이 제거된 상태를 가리킨다. 코드가 간결해지면 오류가 발생할 확률도 매우 낮아진다. 본질적인 부분을 눈에 잘 띄게 만들고, 그 이외의 불필요한 부분이 거기에 섞여들지 않도록 설계하자. 불필요한 복잡성을 제거하면 남은 본질이 더욱 두드러지고 이해가 쉬워지며 의사소통이 원활해진다.
3.4 유연성
코드에서 유연성이란 코드 변경이 용이함을 뜻한다. 기존 코드가 새롭게 추가되는 코드를 반발이나 거부 반응 없이 받아들일 수 있는 점, 자신이 망가지지 않도록 완충을 해서 받아들일 수 있는 점, 양쪽 관점으로 유연이라는 표현이 사용되고 있다.
3.9 선언형의 표현
선언형의 표현이란 코드의 의도를 전하고자 할 때 가능한 명령형보다는 선언형으로 표현하는 것을 뜻한다. 명령형 프로그래밍은 문제의 해법, 즉 자료구조와 알고리즘을 기술한다. 반면에 선언형 프로그래밍은 문제의 정의, 즉 해결해야 할 문제의 성질이나 이때 충족해야 할 제약을 기술한다.
3.11 아키텍쳐 기본 기법
아키텍처 기본 기법이란 소프트웨어 아키텍쳐를 적절하게 구축하는 데 필요한 기초 원리다. 제대로 소프트웨어 아키텍처를 구축하려면 기초가 되는 몇 가지 원리에 기반을 두고 수행해야 한다. 소프트웨어 개발의 역사 속에서 수많은 프로그래머가 축적해 온 실천적이며 방대한 경험에 기반하고 있다. 어떤 문제에 대해 특정한 해결책이 다른 방법보다 뛰어나다는 사실을 프로그래머들이 인식하고 그 해결책을 여러 차례 재사용해 왔는 데, 그것이 바로 기본 기법이다.
3.12 추상
추상이란 개념적으로 명확한 선 긋기를 수행하는 것이다. 선 긋기에 따라 어떤 모듈을 그 이외의 모듈로부터 명확하게 구별한다.
추상은 사상
과 일반화
라는 2가지 관점에서 정리된다.
사상
- 복잡한 대상의 몇 가지 성질을 버리고 특정한 성질에 주목하는 것이다.
- 불필요한 것을 버리고 본질을 파악하는 것이다.
일반화
- 구체적인 대상으로부터 공통 성질을 추출해서 더욱 범용적인 개념으로 정식화하는 것이다.
- 다른 여러 개의 대상에 집중할 때 공통된 성질을 찾아내고 공통점을 조합시켜 범용적인 개념을 구상한다.
3.13 캡슐화
관련 있는 데이터와 로직을 그룹핑해서 하나의 모듈을 정의한다. 관계성이 강한 데이터와 로직을 모듈이라는 껍질로 감싸는 것을 캡슐화라고 부른다.
그룹핑을 통해 관련 있는 요소끼리만 특정 추상 개념을 담당하도록 모듈로 모은다. 이렇게 하면 다음과 같은 장점을 얻을 수 있다.
- 관련 없는 요소가 섞이지 않기 때문에 코드가 읽기 쉬워진다.
- 변경 시의 영향이 모듈 안으로 한정된다.
- 영향도가 명확해지므로 코드의 변경이 쉬워진다.
- 각각 독립된 부품이므로 재사용성이 높아진다.
- 작은 단위로 분할되므로 복잡한 문제에 대처할 수 있다.
3.14 정보 은닉
모듈의 구현을 해당 모듈을 사용하는 클라이언트로부터 은닉한다.
모듈이 클라이언트가 알 필요 없는 내부의 상세 부분을 은닉하면 인터페이스가 작아지고 정보의 교환이 단순해지며 코드 전체의 복잡성을 낮출 수 있다.
정보 은닉을 실현하려면 캡슐화를 사용한다. 캡슐화와 정보 은닉은 원래 다른 개념이다.
- 캡슐화
- 관계가 있는 요소를 모아 모듈화하는 것이다.
- 관계가 깊은 데이터와 함수를 한군데로 모은다.
- 정보 은닉
- 모듈의 내부 상태나 내부 함수를 은닉하는 것이다.
- 내부에 대한 외부로부터의 직접적인 접근을 차단한다.
3.15 패키지화
모듈을 의미 있는 단위로 모든 다음 그룹화한다. 이는 소프트웨어 전체를 의미 있는 단위로 분할하는 것이다. 이렇게 분할된 단위를 패키지라고 부른다.
어느 정도 대규모 소프트웨어가 되면 이번에는 대량으로 작성된 모듈이 오히려 복잡성을 낳는 결과를 초래한다. 이것이 바로 패키지다. 패키지화에는 다음과 같은 이점이 있다.
- 소프트웨어 전체가 패키지라는 작은 단위로 분할되므로 복잡도가 낮아진다.
- 패키지 안에 관련 없는 모듈이 섞이지 않으므로 모듈을 관리하기 쉬워진다.
- 수정에 대한 영향도가 패키지 안에 머무를 가능성이 높으므로 코드를 변경하기 쉬워진다.
- 종속 관계가 정리되어 패키지 단위로 재사용하기 쉬워진다.
3.16 관심의 분리
관심이란 소프트웨어의 기능이나 목적을 뜻한다. 관심을 분리한다는 것은 각각의 관심에 관련된 코드를 모아 독립된 모듈로 만들어 다른 코드로부터 분리한다는 뜻이다.
설계 기법에서 패턴의 대부분은 관심의 분리를 실현하려는 목표를 가지고 있다. 가장 대표 적인 패턴이 MVC 패턴이다. MVC 패턴에서는 비즈니스 로직, 사용자에 대한 표시, 입력 처리를 분리한다.
3.17 충족성, 완전성, 프리미티브성
캡슐화에 의해 관련 있는 요소들이 특정 추상 개념을 담당하는 모듈로 모여진다. 모듈이 담당하는 추상에 대한 표현은 충분하고 완전하며 프리미티브여야 한다.
충족성이란 모듈이 표현하고자 하는 추상이 그것을 전하기에 충분한지를 뜻한다. 예를 들어 모듈이 컬렉션을 표현하고 있는 때 remove가 제공된다고 해도 add가 제공되지 않는다면 컬렉션이라는 점을 전하기에는 불충분한다.
완전성이란 모듈이 표현하고자 하는 추상이 모든 특징을 갖추고 있는지를 뜻한다. 뭔가 빠진 것이 없이 모든 것을 갖추고 있다면 어떤 클라이언트에서도 사용하기 쉬워진다. 예를 들어 모듈이 컬렉션을 표현하고 있을 때 요소의 개수를 구하는 size가 제공되지 않는 다면 완전하다고 할 수 없다.
프리미티브성이란 모듈이 표현하고자 하는 추상이 모두 순수한지 아닌지를 의미한다. 예를 들어 모듈이 켈렉션을 표현하고 있을 때 아이템 1개 추가하는 add가 제공된다면 아이템을 10개 추가하는 add10은 필요하지 않다. 추상의 순수성이라는 관점에서 보면 오히려 불필요한 기능이다.
3.18 정책과 구현의 분리
모듈은 정책 혹은 구현을 다룬다. 다만 하나의 모듈에서 양쪽 모두를 다루어서는 안 된다.
정책 모듈
- 해당 소프트웨어의 전체에 종속되는 비즈니스 로직이나 그 밖의 모듈에 대한 파라미터를 선택하는 부분이다.
- 해당 소프트웨어에 특화되어 있다. 해당 소프트웨어에 변경이 생기면 정책 모듈은 변경을 강요당한다.
구현 모듈
- 해당 소프트웨어의 전제의 종속되지 않는 독립적 로직 부분이다.
- 특정 소프트웨어에 종속되지 않는 순수한 모듈이므로 다른 소프트웨어에서도 재사용할 수 있다.
3.19 인터페이스와 구현의 분리
모듈은 인터페이스 파트와 구현 파트 2개의 분리된 부분으로 구성한다.
인터페이스 파트란 모듈이 가진 기능을 정의하고 모듈의 사용 방법을 정하는 부분이다. 클라이언트에서 접근할 수 있는 함수의 원형으로 구성된다.
구현 파트란 모듈이 가진 기능을 실현하는 코드 부분이다. 모듈이 내부에서 사용하는 로직과 데이터가 표함된다. 구현 파트는 클라이언트에서 접근할 수 없다.
모듈의 인터페이스 사양만 제시되므로 단순하고 이해가 쉬워져 모듈을 쉽게 사용할 수 있다. 사용법과 기능의 실현 방법이 서로 독립성으로 확보할 수 있다.
모듈에 관한 설계 원리로 구현이 아닌 인터페이스에 맞춰 프로그래밍하라
라는 격언이 있다. 이에 따라 모듈끼리의 호출은 서로 인터페이스만 사용하도록 한다.
인터페이스의 구현은 인터페이스 뒤쪽으로 숨겨 이를 직접 호출하는 것을 허용하지 않도록 한다.
3.20 참조의 단일성
모듈의 요소에 관한 선언과 정의는 1회로 제한한다. 정의가 1회라는 말은 예를 들어 변숫값을 초기화했다면 이후 값을 변경하지 않는다는 뜻이다. 이렇게 하면 변숫값의 변화를 추적하지 않아도 되므로 직관적인 코드가 된다.
참조 투과성
- 호출 결과가 파라미터에만 종속된다 : 파라미터로 같은 값을 넘겨주면 항상 같은 반환값을 돌려주는, 즉 반환값이 파라미터값에만 종속되는 특성이다. 이런 특성을 가리켜 순수하다고 표현한다.
- 호출이 다른 기능의 동작에 영향을 주지 않는다 : 함수가 부작용을 갖지 않는 특성이다. 부작용이란 어떤 처리가 상태의 변경을 일으켜 이후의 처리 결과에 영향을 주는 것이다.
3.21 분할 정복
커다란 문제를 그 자체로 해결하려면 어려워지고 시간이 많이 걸린다. 최악의 경우 해결할 수 없을 때도 있다. 규모가 너무 큰 탓에 문제가 너무 복잡하기 때문이다. 제어하기 쉬운 규모까지 문제를 분할하고 거기서부터 착수하는 방식이 효율적이다.
3.22 아키텍처 비기능 요구사항
비기능 요구사항이란 기능 외적인면 전반에 관한 요구사항을 뜻한다. 소프트웨어가 품질이 좋으면서 진정으로 사용자에게 유용하려면 기능뿐만 아니라 비기능 요구사항도 충족해야 한다. 아키텍처 설계에서 비기능은 기능과 같은 정도로 중시해야 한다. 비기능 요구사항의 관점에는 다음과 같은 것이 있다.
변경 용이성 / 상호 운용성 / 효율성 / 신뢰성 / 테스트 용이성 / 재사용성
비기능적인 특성은 개발이나 유지보수, 운용, 컴퓨터 리소스의 효율적 활용에 커다란 영향을 미친다. 배포 후 운용에서 발생하는 대형 장애의 대부분은 성능이나 시스템 다운 등 비기능적인 특성에 기인한다. 그만큼 중요한 사항임에도 기능에 비해 비기능은 경시되고 있으며 이를 별도 주목하지 않고 뒤로 미루려는 경향이 있다. 본래는 개발 초기, 즉 아키텍처 설계 시점부터 고려되어야 할 관점이다.
기밀성 인가되지 않은 개인, 엔티티, 프로세스에 대해 정보를 사용 불가 또는 비공개로 하는 특성으로 정의된다. 허가되지 않은 사람이 정보를 사용하지 못하게 만드는 것이다. 예를 들어 제3자가 중요한 정보에 쉽게 접근할 수 있다면 정보 유출로 이어진다. 따라서 중요한 정보에는 접근을 통제한다. 정보를 암호화함으로써 혹시나 정보 유출이 발생하더라도 유출된 정보를 볼 수 없게 만드는 대책도 수행한다.
무결성 자산의 정확함과 완전함을 보호하는 특성으로 정의된다. 예를 들어 제 3자가 멋대로 중요한 정보를 조작하거나 삭제한다면 정보의 이용 가치는 없어져 버린다. 게다가 조작된 사실을 눈치채지 못한다면 중대한 문제로 발전할 수 있다. 따라서 무결성을 확보하기 위해 디지털 서명 등의 기술을 이용한다.
가용성 인가된 개체가 요구했을 때 접근 및 사용이 가능한 특성으로 정의된다. 원할 때 정보에 접근할 수 있고 이용할 수 있어야 한다. 조직 입장에서 유지하고 있는 중요한 정보에 언제라도 확실히 접근할 수 있어야 한다는 점은 필수 사항이다. 예를 들어 시스템 장에 등으로 정보에 접근할 수 없거나, 컴퓨터 바이러스에 감염되어 시스템을 이용할 수 없다면 커다란 문제다. 따라서 시스템이나 정보를 이중화하거나 백신 프로그램을 통해 바이러스 감염을 차단함으로써 장애 발생을 줄인다.
3.23 변경 용이성
변경 용이성이란 해당 소프트웨어를 얼마나 쉽게 개선할 수 있는지에 대한 능력을 뜻한다. 구체적으로 해당 소프트웨어를 쉽게 수정할 수 있는 지, 쉽게 확장할 수 있는지, 쉽게 재조직할 수 있는 지, 쉽게 다른 플랫폼으로 이식할 수 있는지 등의 능력을 뜻한다.
소프트웨어가 처음 배포된 채 그대로 사용되는 경우가 일단 없다. 소프트웨어 이용 기간중 끊임없이 변경과 확장이 이루어진다. 게다가 기존의 요구사항은 변경되고 새로운 요구사항이 추가된다. 특히 비즈니스에서 사용하는 대규모 소프트웨어는 일반적으로 수명이 길다. 때에 따라서는 수십 년 이상 사용할 때도 있다. 사용자의 요구사항을 장기간에 걸쳐 세심하고 빠르게 대응하려면 코드를 변경하기 쉬운 아키텍처가 필요하다.
좋은 아키텍처 설계에서 핵심은 소프트웨어의 어느 부분이 변경에 대해 높은 유연성을 지녀야 하는 지, 반대로 변경이 발생하지 않는 부분이 어디인지를 파악하는 것이다. 그런 다음 유연성을 지녀야 할 부분은 변경을 고려한 설계를 지원하는 패턴을 사용하므로써 유연성을 높여 둔다.
보수성이란 문제점의 해결, 다시 말해 오류가 발생한 코드의 수정이 용이함을 뜻한다. 보수성을 높이려면 변경을 국소화해서 다른 모듈에 부작용이 미치는 것을 최소화하는 아키텍처를 채택한다.
확장성이란 신규 기능 추가, 신규 버전으로 모듈 교체, 불필요한 기능이나 모듈의 제거 등과 같은 작업의 용이함을 가리킨다. 확장성을 가지려면 모듈 간의 결합도가 약해야 한다. 확장성이 지향하는 목표는 클라이언트에 영향을 미치지 않고 모듈의 교환이 가능한 구조다. 기존 아키텍처에 새로운 모듈을 통합할 수 있는 구조도 필수적이다.
재구축이란 모듈 간 관계의 재조직화를 수행하는 것이다. 모듈이 다른 서브 시스템으로 이동하는 등 위치를 변경할 때 재구축이 필요하다. 재구축을 쉽게 수행하려면 모듈의 구현에는 영향을 미치지 않고, 모듈을 유연하게 배치할 수 있는 구조를 만들어 둘 필요가 있다.
이식성이란 소프트웨어를 다양한 하드웨어 플랫폼, 사용자 인터페이스, 운영체제, 프로그래밍 언어, 컴파일러 등에 적합하게 만들 때의 용이함을 뜻한다. 이식성을 높이려면 하드웨어 종속성을 고려하면서 소프트웨어를 설계할 필요가 있다. 하드웨어에 종속되지 않는 소프트웨어를 만들려면 예를 들어 시스템 라이브러리나 사용자 인터페이스 라이브러리 등 플랫폼 고유의 기능을 다루는 부분들 전용 모듈로 독립시켜 두면 좋다.
3.24 상호 운용성
상호 운용성이란 소프트웨어가 다른 소프트웨어와 정보를 주고받을 수 있는 능력을 뜻한다. 소프트웨어 간에 같은 교환 형식을 매개로 데이터를 주고받거나, 같은 형식의 파일을 읽고 쓰거나, 같은 프로토콜을 사용함으로써 서로 연결할 수 있는 능력이 요구된다.
소프트웨어는 시스템의 일부이며 독립해서 존재하는 것이 아니다. 다른 시스템이나 환경과 빈번하게 상호 작용한다. 다른 소프트웨어와 연결할 수 있다는 것은 기존 자산을 그대로 활용할 수 있다는 뜻이다. 게다가 신규로 개발할 소프트웨어가 줄어든다는 효과도 있다. 따라서 연결성이 좋다는 것은 소프트웨어 용도의 선택지를 크게 확장하고 개발 기간 단축과 비용의 대폭 삭감으로 이어진다.
외부 기능이나 자료구조로의 접근이 명확하게 정의된 아키텍처를 설계하자. 연결의 용이성은 소프트웨어의 가치를 높인다.
3.25 효율성
효율성이란 소프트웨어가 실행되면서 동반되는 리소스 사용에 있어서 적절한 성능을 끌어 내는 능력을 뜻한다. 효율성은 크게 2가지 관점으로 나뉜다.
시간 효율성
시간이라는 관점에서 리소스의 사용 효율을 정의한다. 일정 시간 내에 처리를 몇 건 끝낼 수 있는지를 뜻하는 처리율, 사용자의 입력조작부터 응답가지 걸리는 시간인 응답시간, 사용자의 작업 개시로부터 요구받는 정보의 출력을 끝내기가지 걸리는 시간인 소요 시간 등으로 계측한다.
자원 효율성
컴퓨터 자원이라는 관점에서 리소스의 사용 효율을 정의한다. CPU 사용 시간이나 메모리 사용량, 스토리지 소비량, 네트워크 전송량 등으로 계측한다.
3.26 신뢰성
신뢰성이란 소프트웨어가 예외적인 상황 혹은 예기치 못한 방법이나 부정한 방법으로 사용된 상황에서도 기능을 유지하는 능력을 뜻한다.
신뢰성에는 2가지 측면이 있다.
결함 허용력
소프트웨어에 장애가 발생했을 때 정상적인 동작을 계속 유지하는 능력이다. 예외 발생에 대해서 올바른 행위를 보증하는 한편 내부적으로 복구를 실시한다. 소프트웨어는 예외를 복구한 뒤에 예외가 발생한 위치에서 조작의 실행을 재개하거나 반복할 필요가 있다. 예를 들어 분산 시스템에서 통신 이상이 발생했다면 일단 연결을 해제하고 나중에 다시 연결하는 식으로 소프트웨어의 동작을 복구한다.
견고성
부정한 사용 방법이다 입력 실수로부터 소프트웨어를 보호하는 능력이다. 갖가지 사용 방법에 대해 시스템 차원에서 정의된 상태로 이행한다. 예외 현상을 일으킨 처리의 경우 이에 대한 반복이나 내부 복구가 반드시 요구되는 것은 아니다. 소프트웨어를 정의된 상태로 이행하는 것을 보증한다.
결함 허용력 관점의 대책으로 아키텍처 내부의 중복을 갖게 한다. 장애 발생 시에는 제공하는 기능을 한정하고 중요한 기능만을 제공해서 처리의 지속성을 우선시하는 설계(fail soft)도 고려한다.
견고성 관점의 대책으로 장애 발생 시에 해당 부분을 분리하는 설계(fail safe)를 검토한다. 애초에 장애가 발생하지 않도록 미리 사용자가 잘못된 조작을 해도 안전하게 가동할 수 있는 설계(fool proof)도 고려한다.
3.27 테스트 용이성
테스트 용이성이란 소프트웨어에 대해 효과적이면서 효율적으로 테스트를 수행하는 능력을 뜻한다. 테스트가 효과적이라는 말은 테스트가 깊이 있고 질이 높다는 뜻이다. 테스트를 통해 소프트웨어의 구석구석까지 빠짐없이 품질을 검증할 수 있음을 의미한다. 테스트가 효율적이라는 말은 테스트의 비용이나 노력이 적은 것을 가리킨다. 적은 비용으로 빠르게 품질을 검증할 수 있음을 의미한다.
소프트웨어의 규모와 복잡성이 증가할수록 테스트는 더욱 난해해지고 비용이 많이 든다. 따라서 소프트웨어가 원활하게 동작할 뿐만 아니라 테스트를 쉽게 수행할 수 있는 아키텍처가 요구된다. 개발 단계에서든 유지보수 단계에서는 수정한 소프트웨어의 품질을 담보한다는 것은 보편적으로 중요한 과제다. 소프트웨어가 제대로 동작하는지에 대한 평가는 요구되는 비중이 높은 능력이다.
테스트 용이성을 위해 설계할 때는 모듈 간 종속 관계를 제거하는 것이 핵심이다. 종속 관계가 있으면 테스트하기 어려운 부분을 만났을 때 테스트 전체가 발목이 잡힐 가능성이 커진다. 최대한 종속 관계를 제거하고 작은 단위로 테스트가 가능해지도록 설계하자.
3.28 재사용성
재사용성이란 소프트웨어를 전체가 됐든 일부가 됐든 다른 소프트웨어 개발에 재사용하는 능력을 뜻한다. 재사용성에는 2가지 측명이 있다.
재사용하는 소프트웨어 개발
프로젝트 내의 기존 모듈, 예전 프로젝트의 모듈, 각종 라이브러리 등을 이용하는 것을 의미한다. 재사용 가능한 모듈을 개발 중인 소프트웨어에 그대로 혹은 변형해서 통합한다.
재사용을 위한 소프트웨어 개발
장래의 프로젝트에서 재사용할 수 있는 모듈을 현재 소프트웨어 개발 과정에서 창출하는 것을 의미한다. 다른 소프트웨어에서 재사용하기 위한 소프트웨어를 개발한다.
재사용하는 소프트웨어를 개발할 때는 아키텍처의 구성을 기존 구조나 모듈에 플러그인 할 수 있도록 한다. 여기에는 소프트웨어 컴포지션을 지원한다는 목적이 있다. 소프트웨어 컴포지션이란 소프트웨어를 기존 모듈을 가지고 조립하는 것이다.
난이도 3배의 법칙
재사용 가능한 모듈을 만드는 작업은 단일 소프트웨어에서 사용할 모듈을 개발할 때보다 3배 어렵다는 법칙이다. 재사용 가능한 모듈을 만드는 프로그래머는 일반화된 문제를 처리해야 한다. 모듈 자체를 일반화할 뿐만 아니라 모듈의 테스트도 일반적인 케이스로 실시할 필요가 있다.
테스트 3종류의 법칙
재사용 가능한 모듈은 공유하기 전에 3가지의 다른 소프트웨어로 테스트할 필요가 있다는 법칙이다. 재사용 가능한 모듈은 자신이 현재 당면한 문제를 해결하는 것만으로는 불충분하며 더 일반적인 문제도 해결할 수 있어야 한다. 처음부터 완벽하게 일반화된 모듈은 작성할 수 없다. 프로토타입을 작성하고 실제 문제 영역에 부딪치며 다듬어가는 방식이 효율적이다.
같은 문제 영역에서 몇 가지 소프트웨어를 구현하다 보면 설계가 능숙해지고, 난관을 돌파한 경험을 통해 해당 문제 영역에 특화된 프레임워크를 설계할 수 있다. 프레임워크는 인터페이스가 정해져 있는 허브 같은 것으로서, 프레임워크에 문제 영역의 가변적인 부분을 컴포넌트로 탈착할 수 있다. 이른바 플러그인 설계다. 그렇게 만들어진 소프트웨어는 자유로이 변경과 확장이 가능해진다. 개발을 반복하며 성공에 도달한 행운의 프로젝트가 도달할 수 있는 이상향이다.
3.55 UNIX 철학
UNIX 철학이란 UNIX의 배후에 있는 설계 철학으로, 말하자만 'UNIX적인 사고방식'이다. UNIX는 오래전부터 존재했으며 아직도 업무 일선에서 계속 사용되고 있다. 설계 철학이 뛰어나고도 보편적이기 때문이다.
3.56 작은 것이 아름답다
작은 소프트웨어는 단순하고 다루기 쉬우며 큰 소프트웨어보다 훨씬 뛰어나다. 따라서 소프트웨어는 작게 만들고 작게 유지하도록 한다.
작은 소프트웨어는 다음과 같은 장점이 있다.
- 이해가 쉽다
- 보수가 쉽다
- 다른 소프트웨어와 조합하기 쉽다
반면에 큰 소프트웨어는 다음과 같은 문제가 있다.
- 복잡하고 코드를 이해하기 어렵다
- 예측하지 못하고 사태에 대응할 수 없다
3.57 한 번에 하나의 작업
가장 좋은 소프트웨어란 생애 중에 단 하나의 작업만을 제대로 완수하는 소프트웨어다. 하나의 작업에 집중함으로써 코드에 불필요한 부분을 없앨 수 있다. 하나의 작업에 집중함으로써 해당 작업의 본질을 파악할 수 있다. 하나의 작업을 제대로 하는 소프트웨어를 만들 수 없다면 문제를 아직 완전하게 이해하지 못했다는 뜻이다.
3.58 즉시 프로토타입 진행
어떤 아이디어가 성공할 것 같은지, 눈에 보이는 형태로 현실화할 수 있는지를 확인하려면 시험 삼아 만들어보는 방법이 가장 좋다. 이렇게 만든 시제품을 프로토타입이라고 부른다. 프로토타입을 작성하면 전제의 착오가 조기에 발견되어 작은 피해에 머무른다. 잘못된 전제 그대로 몇 개월 동안이나 개발을 진행하다가 배포 직전이 되어 불의의 습격을 받을 일은 없다.