EPISODES: A Pattern Language of Competitive Development (에피소드: 경쟁적 개발의 패턴 언어)
에피소드: 경쟁적 개발의 패턴 언어 (EPISODES: A Pattern Language of Competitive Development)
Part I
- 저자: Ward Cunningham (ward@c2.com), Cunningham & Cunningham, Inc.
- 제출: 제2회 프로그래밍 패턴 언어 국제 컨퍼런스 (PLoP), 일리노이주 몬티첼로, 1995년 9월 6-8일
- 초안 검토: 1995년 8월 6일
이 패턴 언어는 기업가적 조직(entrepreneurial organization)에 적합한 소프트웨어 개발 형태를 설명합니다. 우리는 기업가가 똑똑하고 의욕 넘치는 소수 정예 팀에서 일한다고 가정합니다. 또한, 시장의 기회(market windows)가 빨리 닫히고 개발 자금이 부족한 경우가 많으므로, '타임 투 마켓(time to market)'이 매우 중요하게 여겨진다고 가정합니다. 하지만 일부 기업가들과 달리, 우리는 두 번째 버전을 제때 출시하는 것, 그리고 세 번째, N번째 버전을 수년 후에도 계속 출시할 수 있는 능력에 높은 가치를 둡니다. 즉, 우리는 성공을 기대하며, 고객이 원하는 한 개발을 지속함으로써 그 성공을 활용할 의도를 가지고 있습니다.
이 패턴들은 소프트웨어를 개발하는 방법을 설명합니다. 방법론 문서가 프로세스를 설명하는 방식과는 다르지만, 공정하게 말해 프로세스 패턴이라고 할 수 있습니다. 또한 다른 패턴들이 설명하는 설계나 조직을 설명하는 것도 아닙니다. 패턴으로서 이것들은 프로세스에서 발생하는 문제를 해결하는 무언가(things)를 설명합니다. 그 '무언가'는 문서나 회의 같은 물리적인 것일 수도 있고, 헌신이나 마음가짐 같은 정신적인 것일 수도 있습니다.
우리는 특히 중요한 결정으로 이끄는 일련의 정신 상태(sequence of mental states)에 관심이 있습니다. 우리는 이 일련의 과정을 에피소드(episode)라고 부릅니다. 에피소드는 결정이 내려지는 절정(climax)을 향해 구축됩니다. 결정 전에는 사실을 찾고, 의견을 나누고, 집중력을 기르며, 미리 알 수 없는 사건에 대해 전반적으로 준비합니다. 절정 이후에는 결정이 알려지지만 에피소드는 계속됩니다. 에피소드의 꼬리 부분에서 우리는 결정에 따라 행동하고, 이를 공포하며, 그 결과까지 끝까지 수행합니다. 또한 에피소드의 흔적을 산출물 속에 남깁니다. 우리는 종종 미래의 에피소드에서 생각의 조각들을 주워 담아야 하는 곳이 바로 이 흔적입니다.
우리는 결정에 이르는 모든 생각을 기록해야 한다고 제안할 만큼 순진하지 않습니다. 그러기에는 생각은 너무 복잡하고 결정은 너무 많아 실용적이지 않습니다. 우리가 제안하는 것은 후속 에피소드를 위한 준비가 더 원활하게 진행될 수 있도록 전략적 위치에 힌트와 포인터를 배치하라는 것입니다. 물론 원활하지 않을 수도 있습니다. 특정 영역을 건드리는 각 에피소드는 더 많은 기대를 안고 진행되기 때문입니다. 우리는 그저 상황에 잘 대처하기를 바랄 뿐입니다. 우리의 에피소드가 앞이나 뒤가 너무 무겁지 않고, 항상 길어지지만은 않는 등 형태가 잘 잡혀 있다면 우리가 잘 해냈다는 것을 알 수 있을 것입니다.
"제대로 할 시간은 없어도, 다시 할 시간은 항상 있다"
옛말에 이런 한탄이 있습니다. 우리는 이것을 경쟁적 삶의 사실로 받아들입니다. 경쟁적 압박 속에서 우리는 우리가 원하는 만큼 신중한 결정을 내릴 수 없는 자신을 발견합니다. 이 패턴들은 반복적인 개발을 통해 지속적인 전진을 유지하기 위해 어떤 결정을 내릴 수 있는지, 사실상 어떤 결정을 내려야 하는지를 알려줍니다.
이 패턴들을 유용하게 사용하기 위해 반드시 경쟁 상황에 있어야 하는 것은 아닙니다. 이 패턴들이 만들어내는 개발 방식은 대규모 조직 내의 사내 벤처 그룹이나, 코드를 빠르고 무한히 개발하고자 하는 모든 그룹에 똑같이 적용될 수 있습니다.
이 언어는 다양한 개발 이슈를 다룹니다. 이것들은 하향식(top-down) 또는 연대순(chronological)으로 설명될 수 있는 주제 영역으로 구성되었습니다. 실제 개발이 그렇게 구조화되거나 순서대로 진행된다고 생각하지 마십시오. 실제로는 이 패턴들이 순서와 상관없이, 때로는 직무 기술서에 그렇게 하라고 명시된 사람들에 의해, 때로는 그렇지 않은 사람들에 의해 반복해서 적용될 것입니다. 차트 1은 작업(task)과 주체(agent)별로 패턴을 배치한 언어의 지도를 보여줍니다. 여기서 작업은 수행되는 일의 종류를 의미하고 주체는 그 일을 하는 사람의 종류를 의미합니다. 이것을 너무 심각하게 받아들이지 마십시오. 훨씬 더 중요한 것은 패턴 간의 관계입니다. 하나의 패턴이 다른 패턴으로 이어질 때 패턴은 서로 관련됩니다. 이는 패턴에 작용하는 강력한 힘들이 해결책을 통해 균형을 이룰 때 발생합니다. 이러한 강력한 힘의 해결은 필연적으로 주의를 기울여야 할 더 약한 힘들을 드러냅니다. 우리가 패턴 간의 관계에서 포착하는 것이 바로 이러한 주의의 이동입니다. 이러한 관계들은 일련의 패턴들을 패턴 언어로 변화시킵니다. 자연어처럼 의식적인 노력 없이도 사용되는 시스템이 되는 것입니다.
제품 (Product)
우리는 첫 몇 가지 버전이 출시된 후, 그리고 고객들이 향후 개선 사항에 대한 관심을 잃기 훨씬 전인, 개발 프로세스의 긴 중간 지점에서 이야기를 시작합니다. 우리는 가장 길고 가장 큰 중첩된 에피소드인 제품 이니셔티브(Product Initiative)로 시작합니다.
제품 이니셔티브 (Product Initiative)
시장 상황이나 운영 조건이 제품 기능의 증대나 수정을 필요로 할 수 있습니다. 또는, 기존의 제품 계획이 특정 날짜에 특정 기능을 요구할 수도 있습니다. 어쨌든, 이제 여러 그룹의 주의를 특정 제품 목표로 향하게 할 때입니다.
제품과 관련된 모든 사람은 기회가 주어진다면 추가하고 싶은 기능과 특징에 대한 위시리스트(wish-list)를 축적하고 있습니다. 계속 늘어나는 기능을 모두 흡수하도록 설계된 제품은 일관성이나 방향성을 잃을 위험이 특히 큽니다.
따라서: 제품 개선을 위한 가장 중요한 방향을 명확히 설명하십시오.
관련된 모든 그룹의 모든 구성원이 적어도 이 이니셔티브를 요약하고 그 비즈니스적 타당성을 옹호할 수 있어야 합니다. 새로운 이니셔티브가 이전 이니셔티브와 일치할 필요는 없습니다. 과거의 성과를 제품에서 철회하거나 적절한 지원을 중단하여 후퇴하려는 의도는 없습니다. 하지만, 이니셔티브 내의 모든 사람의 마음속에서 관련성이 적은 생각들을 줄이거나 대체하려는 의도는 분명히 있습니다.
주요 자원 할당에 대한 책임이 있는 상위 경영진으로부터 이니셔티브가 나오기를 기대하십시오. 제품 이니셔티브가 개발진 내부에서 끓어오르는 것도 가능합니다. 중요한 것은 합의가 어떻게 이루어졌든 간에, 모두가 그 이니셔티브를 현재의 방향으로 받아들이는 것입니다.
명확한 이니셔티브는 암시적 요구사항(Implied Requirements)을 수반하며, 이는 마케팅 워크스루(Marketing Walkthrough)에서 신중하게 논의되어야 합니다. 명확한 일정과 자원 목표는 이니셔티브의 초점을 더욱 강화합니다. 이니셔티브가 진행되는 동안, 경영진은 각 요구사항에 대한 작업 그룹(Work Groups)의 완료 여유분(Completion Windows/Headroom)을 추적해야 합니다. 이니셔티브가 미끄러지면(지연되면), 선의와 미래의 이니셔티브를 희생하면서 한 가지 주제에 과도한 주의를 할당하는 결과를 낳습니다. 최악의 경우 암시적 요구사항을 검토하고 조직 차원의 재약속 회의(Recommitment Meeting)에서 연기하거나 폐기해야 할 수도 있습니다.
마케팅 워크스루 (Market Walkthrough)
제품 이니셔티브는 시장 또는 비즈니스 용어로 표현됩니다. 제품은 프로그램이나 다른 기술 조각 이상의 것입니다. 다비도우(Davidow)는 그의 저서 '첨단 기술 마케팅(Marketing High-Technology)'에서 이를 명확히 합니다. 기술을 제품으로 만드는 것은 마케팅 기능입니다. 그리고 마케팅은 운영의 양측, 즉 제품의 고객과 프로그램의 개발자 모두와 좋은 접촉을 유지해야 합니다. 마찬가지로, 개발팀은 이니셔티브가 제공하는 고객의 니즈를 이해하고, 시장 관련 질문이 발생했을 때 이를 정독할 수 있는 자신감과 자원을 가져야 합니다.
따라서: 모든 이니셔티브를 개발 및 마케팅 직원의 대부분이 참여하는 프로그램 및 제품 컨셉에 대한 워크스루(검토 회의)로 시작하십시오.
구매자와 사용자의 관점뿐만 아니라 개발의 관점에서도 이니셔티브를 이해하십시오. 이니셔티브가 계약 조건에서 나오거나 이와 관련된 경우, 지금이 검토하기 좋은 시기입니다. 마지막으로, 암시적 요구사항으로 사용되는 것과 같은 기본 용어에 대해 모두가 동의해야 합니다.
예시: 한 트레이딩 소프트웨어 회사가 파생상품 계약에 대한 두려움이 커짐에 따라 개선된 가격 모델과 관련 분석 기능을 추가하여 이에 대응하고 있습니다. 마케팅 부서는 파생상품 포트폴리오를 보유하고 있으며 개발팀과 협력할 의지가 있는 주요 고객을 선정했습니다. 마케팅 워크스루에서 회사 사장은 파생상품 시장의 변화를 개략적으로 설명하고, 뉴욕 지역 고객 담당자는 "월가"에서 인기 있는 최신 가격 모델을 요약하며, 스태프 도메인 전문가는 회사의 제품에 유사한 기능을 통합하기 위한 비전을 설명합니다. 워크스루는 마케팅과 개발팀이 고객의 니즈와 구현 가능성을 연결하기 시작하는 긴 질의응답 시간으로 끝납니다.
암시적 요구사항 (Implied Requirement)
제품 이니셔티브는 추가 개발의 방향을 확인시켜 주었고, 마케팅 워크스루는 그 배후에 있는 고객의 동기와 개발 가능성을 탐색했습니다. 우리는 입장과 태도가 이해되기를 기대하지만, 회사를 위해 일을 잘하겠다는 모두의 일반적인 헌신 외에는 아직 어떤 약속도 하지 않았습니다.
약속은 사람들 간의 합의를 의미합니다. 개발 약속은 일반적으로 개발자가 고객의 니즈를 시기적절하고 만족스러운 방식으로 충족시킬 의무를 지게 합니다. 여기서의 긴장감(tension)은 사전 분석을 고갈시키거나 솔루션을 과도하게 제약하지 않으면서, 약속이 의미를 가질 수 있을 만큼 충분히 상세하게 니즈를 정의하는 데 있습니다.
따라서: 기능의 덩어리(chunk)를 선택하고 이름을 붙이십시오.
제품 이니셔티브와 일치하며 고객에게 의미가 있는 이름을 사용하십시오. 이 이름들이 전통적인 의미에서의 요구사항을 실제로 나열하지 않으면서도 고객의 요구사항을 암시하도록 허용하십시오.
예시:
- 연말 세금 보고서
- 달러화 표시 일본 채권
- 고품질 인쇄
- 노트북에서의 연결 해제 작업(오프라인 작업)
이 이름들은 다음과 같은 반복적인 질문의 빈칸을 채울 것입니다: "누가 _____에 대한 프로그래밍(또는 사양, 고객 연락, 매뉴얼 업데이트, 릴리스 노트)을 담당하고 있습니까?"
개발 (Development)
다음 패턴들은 점점 더 기능이 향상된 프로그램을 빈번하고 정기적으로 릴리스하도록 이끄는 개발팀 활동을 생성합니다. 중요한 아이디어는 요구사항, 사양, 설계 및 구현의 동시 개발입니다. 이러한 책임을 한 개인이 맡는 경우, 적절한 시기에 적절한 모자를 쓸(역할을 할) 수 있다고 가정합니다. 마찬가지로 다른 사람들이 각 역할을 맡는 경우, 각자가 생산적이고 다른 사람의 작업으로부터 혜택을 받을 수 있도록 활동을 조정할 수 있다고 가정합니다.
이 패턴들은 또한 현재 가장 합리적인 일을 할 수 있는 상당한 자유를 보존하면서 일종의 일정을 생성합니다. 우리의 일반적인 전략은 몇 개의 고정된 목표 날짜에 맞춰 개발하는 것입니다. 납품일이 다가왔을 때, 개발 기간을 되돌아보며 우리가 가능한 모든 시간을 현명하게 사용했다고 자신 있게 말하고 싶습니다.
작업 큐 (Work Queue)
암시적 요구사항은 다양한 필요성, 의존성, 위험 및 보상을 가질 인도 가능한(deliverable) 프로그램 개선 사항을 제안합니다. 인도물(deliverable)은 구체적이거나 측정 가능한 것보다는 비전이나 욕구로 표현되어 불명확하게 정의될 수 있습니다.
만약 우리가 기존의 방식대로 일정을 짠다면, 아마도 각 항목에 대한 요구사항 분석 블록으로 시작할 것입니다. 그 뒤에 사양, 설계, 구현, 그리고 마침내 통합 및 테스트 블록이 매달릴 것입니다. 여기에 몇 가지 거친 추측과 몇 가지 순서 제약을 더하면, 짠! 누가 언제 무엇을 끝낼지 말해주는 30피트짜리 다이어그램이 나옵니다. 그런 문서는 그 자체로 생명력을 얻어 개발자의 마음에 두려움을 심어주고, 더 많은 산출물이 아닌 더 나은 투입을 얻는 것이라는 진짜 일정 관리 업무로부터 다른 모든 사람의 주의를 분산시킵니다.
따라서: 투입(input)보다 산출(output)이 적은 일정을 만드십시오.
암시적 요구사항(실제로는 이름들일 뿐인) 목록을 시작점으로 삼고, 더 긴급하거나 우선순위가 높은 항목을 선호하여 그럴듯한 구현 순서로 정렬하십시오. 두 개 이상의 항목에서 작업을 팩터링(공통화)할 수 있다면, 공통 요소에 가치를 확립하고 구현 우선순위를 암시하는 이름을 부여하여 그렇게 하십시오.
예시:
- 결제일(Settlement-Date) 포지션
- 결제일 기준 세금 보고서
- 포트폴리오별 거래일 대 결제일 회계 선호도
예기치 않은 상호 작용이 표면화되거나 비즈니스 현실이 새로운 우선순위를 요구할 때 이 목록을 재정렬할 준비를 하십시오. 완료된 작업은 목록에서 제거하십시오. 관찰된 결함만으로는 완료된 작업을 목록으로 되돌리기에 충분하지 않습니다. 그러나 독립적으로 일정이 잡힌 수정 활동이 결함 추적에서 제거하는 것보다 작업 큐의 다른 모든 작업과 경쟁하도록 일정을 잡는 것이 더 적절한 누락 사항을 발견할 수도 있습니다.
작업 그룹 (Work Group)
우리는 제품 이니셔티브와 관련된 작업을 설명하고 긴급성에 따라 정렬되며 완료된 작업이 상단에서 제거됨에 따라 위로 이동하는 작업 큐를 가지고 있습니다. 이제 우리는 어떤 개인도 압도하거나 과소 활용하지 않으면서 인력을 할당해야 합니다.
따라서: 작업 큐의 맨 앞에 있는 대략 2개월 분량의 작업에 인력을 배치하십시오.
실제 요구사항과 암시적 요구사항을 이해하고, 적절한 사양을 개발하고, 설계를 완료 또는 확장하고, 테스트를 조립하고, 인도물의 모든 측면을 구현하기 위해 필요에 따라 함께 일하겠다는 그들의 약속을 구하십시오. 개인이 자신에게 할당된 가장 긴급한 작업에 전념할 것을 기대하십시오. 프로젝트와 개인 간의 예측 불가능한 의존성을 보완하기 위해 어느 정도의 자유를 허용하십시오. 특정 항목의 작업은 개발 에피소드(Development Episode)의 중심이 되는 의사 결정의 폭발을 중심으로 집중력이 오르내리는 일반적인 흐름으로 수행될 것을 기대하십시오.
작업 큐 보고서 (Work Queue Report)
분석가, 설계자, 구현자가 섞여 있는 일반적인 상황에서 매주 비례적인 양의 분석, 설계 및 구현이 이루어진다고 가정할 수 있습니다. 이는 모든 참석자가 자신의 전문 분야를 설명하는 데 5분을 할애하는 주간 상태 회의에서 확인할 수 있습니다. 그러나 상태 회의 장소에서 일정이 미끄러지는 것을 감지하기란 놀랍도록 어려울 수 있습니다.
따라서: 매주 정기적인 개인 인터뷰를 통해 상태를 수집하십시오.
유사 작업(Comparable Work)과 대조하여 남은 노력 일수(days of remaining effort) 추정치를 요청하십시오.
예시: "새 세금 계산 기능에 꼬박 이틀을 썼고, 조(Joe)와 UI 작업에 하루를 썼어." "계산 기능을 끝내려면 방해받지 않는 날(uninterrupted days)이 며칠이나 필요할 것 같아?" "음, 한 이틀? 발생주의(accruals) 작업이랑 별반 다르지 않아." "그럼 조와 작업하는 건?" "글쎄, 진짜 작업은 시작도 못 했어. 지난주에 3일 동안 못했지? 아마 여전히 3일은 필요할 거야."
이 추정치들을 개별 희석 요인(개인이 일주일 동안 개발에 쓸 수 있는 방해받지 않는 날이 며칠인가)과 함께 사용하여 각 할당된 인도물의 완료까지 경과 일수를 예측하십시오. 이 데이터로 완료 여유분(Completion Headroom)을 계산하고 게시하십시오. 흥미로운 방식으로 변경된 숫자를 설명하는 몇 문장의 표지를 포함하십시오.
작업 큐 보고서 예시:
| 진행 중인 작업 (우선순위 순) | Sue (60%) | Bill (70%) | Joe (25%) | Kay (70%) | Ed (10%) | Ray (75%) | 가장 빠른 완료일 | 여유분 (Headroom) |
|---|---|---|---|---|---|---|---|---|
| 결제일 포지션 | 3 | 2 | 6월 5일 | 12 | ||||
| 결제일 세금 보고서 | 2 | 2 | 6월 8일 | 9 | ||||
| 거래 vs 결제 선호도 | 1 | 4 | 6월 7일 | 10 | ||||
| 등등 | 5 | 5 | 6월 21일 | 8 | ||||
| 등등 | 9 | 3 | 6월 25일 | 4 |
(참고: 가용성(availability)은 주당 방해받지 않는 시간 비율, 숫자는 남은 작업 일수)
유사 작업 (Comparable Work)
개발자들은 날짜와 관련해서는 놀라울 정도로 추정을 못 합니다. 반면, 그들은 과거에 수행한 거의 모든 프로젝트에서 어떤 상황이 어떤 문제로 이어졌는지에 대한 좋은 기억력을 가지고 있으며, 새로운 프로젝트에서도 같은 상황을 감지하는 육감을 가지고 있습니다.
따라서: 개발자가 유사 작업을 선택하여 노력을 추정하게 하십시오.
이전의 어떤 작업보다 2/3 정도 복잡한 작업은 아마도 2/3 정도의 시간이 걸릴 것입니다. 유사 추정은 유사 작업을 선택할 때 고려하지 않은 숨겨진 복잡성이 없다면, 불명확하게 정의된 프로젝트에 대해서도 보통 정확합니다. 숨겨진 복잡성은 보통 작업을 실제로 시작한 지 며칠 안에 드러납니다. 진지하게 받아들여지지 않은 추정에 대해 이의를 제기하는 것은 괜찮지만, 숨겨진 복잡성을 발견했을 때 개발자를 지난주 추정에 묶어두려 하지 마십시오. 힘내십시오, 가끔 표면으로 드러나는 '숨겨진 단순함'이라는 것도 있으니까요.
기억을 돕기 위해, 보고서 예시에서처럼 현재 노력에 투입된 '방해받지 않은 날'을 기록하십시오. 이 데이터는 오늘의 프로젝트가 내일의 유사 작업이 될 때 편리한 참조가 될 것입니다. 직장에서의 일주일이 개발에 꼬박 2~3일 이상을 산출할 것이라고 기대하지 마십시오. 또한, 이 데이터를 성과 평가에 사용하려고 하지 마십시오. 그렇게 하면 좋은 추정에 필요한 솔직한 관계가 파괴될 것입니다. 게다가 숫자가 크거나 작은 것이 성과 향상을 나타내는지는 불분명합니다. 프로젝트가 작업 분할(Work Split)을 겪게 되면 축적된 노력 데이터를 비례 배분해야 합니다. 어떤 비율이 떠오를 것입니다. 단지 날짜를 두 번 세지만 마십시오.
완료 여유분 (Completion Headroom)
모든 프로젝트는 몇 개의 확고한 날짜에 맞춰 납품을 약속해야 합니다. 이는 사실 다행스러운 일인데, 잘 안 풀리는 작업에서 빠져나올 수 있는 거의 유일한 방법이기 때문입니다. 작업 분할(Work Split)은 이해되지 않거나 잘 진행되지 않는 작업 부분은 미루고, 작동하거나 체면을 세울 수 있는 부분은 살림으로써 우아한 탈출구를 제공합니다. 작업 분할은 마감일 전에 작업의 일부를 여전히 완료해야 하므로 어느 정도 사전 통지가 필요합니다.
따라서: 작업 큐 보고서의 남은 노력 추정치로부터 작업 그룹 완료 날짜를 예측하십시오.
각 작업 그룹의 가장 빠른 완료 날짜 중 가장 큰(늦은) 것을 선택하여 적용될 수 있는 확고한 납품일과 비교하십시오. 그 차이가 당신의 완료 여유분입니다. 여유분은 종종 주마다 하루 이틀 정도 오르락내리락(jitter)할 것입니다. 하지만 어떤 작업 그룹의 여유분이 꾸준히 증발하는 것은 경영진의 주의가 필요하다는 확실한 지표입니다. 당신은 작업 큐를 재정렬하거나, 전체 항목을 나중 릴리스로 연기하거나, 앞서 언급한 작업 분할을 하거나, 아니면 재약속 회의(Recommitment Meeting)라는 공개적인 망신을 당할 수 있는 선택권이 있습니다.
개발 에피소드 (Development Episode)
작업 그룹의 구성원은 암시적 요구사항에서 추론된 필요에 따라 선정되었습니다. 각 구성원은 개발의 특정 시점에 중요해질 특정 기술을 가지고 있습니다. 이에 대해 우리는 감사할 수 있습니다. 그러나 구성원의 특정 강점을 지나치게 강조하면, 모두의 일반적인 능력을 감소시키고, 구성원의 초점을 단지 그 전문 분야를 적용하는 것으로 불필요하게 좁히며, 전문화되지 않은 작업에 대한 책임이 누구에게 있는지 모호하게 만들고, 새로운 기술 학습을 저해할 위험이 있습니다.
따라서: 마치 아무도 다른 할 일이 없는 것처럼 모든 개발에 그룹 활동으로 접근하십시오.
활동이 에너지가 구축되어 의사 결정의 절정(climax)에 이른 후 소산되는 일반적인 에피소드 과정을 따르도록 기대하십시오. 에피소드의 정점에서 목적은 명확해야 하고, 용어는 잘 이해되어야 하며, 알려진 것은 잘 탐구되고 알려지지 않은 것은 식별되어야 합니다. 개별적인 강점이 일종의 공통 의식으로 융합되는 것은 바로 이 지점입니다. 획기적인 결정이 쉽게 나옵니다. 돌파구가 흔하게 일어납니다. 창조적인 행위가 공유된 것입니다.
더 나은 결정을 내리는 것 외에도, 집단적 에피소드는 참가자들에게 매우 긍정적인 영향을 미칩니다. 되돌아보면, 사람들은 종종 핵심 아이디어의 실제 출처를 식별하는 데 어려움을 겪습니다. 비전문가는 전문가의 사고 과정에 대한 귀중한 통찰력을 얻습니다. 전문 지식은 탈신비화되고, 공유되며, 그룹 전체로 확산됩니다. 전문 분야의 대가(Master)는 이러한 공유가 그룹 내에서 자신의 지위를 떨어뜨리지 않는다는 것을 깨닫게 될 것입니다. 통찰력이 대가에게서 솟아오를 때, 그는 다른 사람들도 같은 통찰력에 근접하기를 기대하며 잠시 지체할 것이고, 그들의 실제 인식 경험이 그들에게는 엄청난 가치가 있고 자신에게는 작은 손실임을 알게 될 것입니다. 시모어 페퍼트(Seymour Papert)는 이것을 "아하(Ah Ha)"라고 불렀으며 강사들에게 "아하를 훔치지 말라"고 충고했습니다(Mindstorms).
비공식 노동 계획 (Informal Labor Plan)
개발 에피소드는 큰일을 빨리 끝내려고 노력하는 사람들의 삶 속에 적용되어야 하는 이상형을 제시합니다. 개발자들은 종종 한 번에 하나 이상의 진행 중인 개발 에피소드에 의무를 지게 됩니다. 작업 큐는 하나의 우선순위를 제공하지만, 작업이 바로 눈앞에 있을 때 가능한 많은 작은 트레이드오프(tradeoffs)를 무시합니다.
따라서: 개인이 자신의 단기 계획을 고안하게 하십시오.
개발 에피소드에 암시된 그룹 활동의 많은 부분이 함께 문제를 해결할 시간을 찾는 그룹 구성원 간의 쌍(pair-wise)으로 이루어질 것임을 받아들이십시오. 개발적 절정이 일어나도록 의도된 회의를 소집하려는 유혹을 피하십시오. 그런 일은 일어나지 않습니다. 대신 개인이 관심을 표현하고 서로에게 약속하게 하십시오. 그리고 어떤 에피소드의 에너지가 저항할 수 없는 수준에 도달했을 때 이 의도를 즉시 수정하도록 하십시오.
개발 에피소드는 실제로는 일련의 프로그래밍 에피소드(Programming Episodes)로 구성되며, 그룹 의식의 근사치라도 형성하려면 그중 일부는 (적어도) 쌍으로 이루어져야 합니다. 개인의 노동 계획은 이러한 연결이 일어나게 하는 도구입니다. 짝 프로그래밍 시설(Pair Programming Facilities)은 이러한 계획을 복도에서의 우발적인 약속 정도로 줄일 수 있는 물리적 환경의 구성입니다.
작업 분할 (Work Split)
작업 그룹은 암시적 요구사항을 그들이 찾을 수 있는 가장 시기적절하고 만족스러운 방법으로 해결하고 인도하기로 약속합니다. 그들은 특정 날짜를 약속한 것은 아닙니다. 그러나 그들은 낮은 완료 여유분이라는 궁극적인 문제 신호를 통해 그들의 노력을 가시화할 의무가 있습니다. 여유분은 개발 활동이 유사 작업의 활동과 일치하지 않을 때 사라집니다. 흔한 문제는 문제에 너무 가까이 있는 사람들에 의한 선의의 요구사항 확대(escalation)입니다.
따라서: 작업을 긴급한 요소와 연기된 요소로 나누어 개발 작업의 절반 이하만이 긴급한 쪽에 속하도록 하십시오.
충분한 완료 여유분을 확보하기 위해 필요하다면 더 많이 연기하십시오. 구현되지 않을 부분에 대한 분석과 설계는 연기하십시오. 이 조언은 통념과 배치됩니다. 종종 분할은 원래 계획했던 기본 작업으로 돌아가는 방법일 뿐입니다. 불완전한 "선행(up-front)" 작업으로 인한 누락과 불편함을 커버하기 위해 아키텍처 대체(Architectural Substitution)를 신뢰하십시오. 분할된 두 부분은 작업 큐에 현저히 다른 긴급성을 가지고 나타날 것입니다.
재약속 회의 (Recommitment Meeting)
작업 분할은 개발 그룹 내부에서 시작하여 일정을 준수할 수 있는 메커니즘을 제공합니다. 만약 일정 및 작업 큐 조정을 통해 암시적 요구사항을 충족할 수 없어 제품 이니셔티브가 위험에 처한다면, 다른 개발 주도 활동이 도움이 될 가능성은 낮습니다. 이니셔티브를 시작한 수준 이상의 경영진이 갑자기 현재 상황에 이르게 된 모든 정황에 관심을 갖게 될 것입니다. 이는 자연스럽고 적절한 일입니다. 하지만 이때는 생산성이 높은 시간이 아니며 너무 오래 지속되어서는 안 됩니다.
따라서: 관심 있는 경영진과 주요 개발 인력을 소집하여 회의를 여십시오.
참석한 모두가 간단한 조정(주말 근무나 인력 충원 등)으로는 도움이 되지 않는다는 것에 동의할 때까지 회의에서 이력을 검토하게 하십시오. 결국 해결책이 나타나는데, 보통 다음과 같은 질문의 형태를 띱니다: "X를 하기 위해 필요한 최소한의 작업량은 얼마인가?" X는 한 사람이 생각하는 이니셔티브의 가장 중요한 부분입니다. 이 질문은 최근의 작업 큐 보고서를 참조하여 빠르고 자신 있게 답변되어야 합니다. 이 과정은 계획 Y와 Z에 대해 반복될 수 있습니다. 궁극적으로 계획이 선택될 것입니다. 그러면 회의의 나머지 시간은 결정의 함의를 이야기하고 새로운 계획 및/또는 일정에 대한 모든 당사자의 약속(commitment)을 얻는 데 할애됩니다.
물론 이것은 또 다른 형태의 에피소드입니다. 결정은 비즈니스 자원의 할당에 관한 것이며 상위 경영진에게 속합니다. 그러나 참석한 모든 사람이 기여할 수 있으며, 솔직하고 정직하며 방어적이지 않고 건설적인 방식으로 기여해야 합니다.
프로그래밍 (Programming)
프로그래밍은 미래의 행동에 대한 결정을 내리고 인코딩(encoding)하는 행위입니다. 인코딩은 모든 결정의 근거와 결과를 신중하게 고려할 것을 요구합니다. 종종 결정은 불완전한 것으로 판명되고 새로운 의문이 제기됩니다. 이 섹션에서는 불완전하거나 모호하거나 의심스러운 사실이 존재하는 상황에서의 의사 결정을 고려합니다. 우리는 인공물과 개인에게 지식을 집합시키는 패턴과, 요구되는 지식이 즉시 이용 가능한 것을 초과할 때 의사 결정을 제한하는 패턴을 포함합니다.
요구사항 워크스루 (Requirement Walkthrough)
작업 그룹의 모든 구성원이 동시에 작업의 암시적 요구사항을 고려하기 시작하는 것은 아닙니다. 예측할 수 없는 상황으로 인해 개인들은 각기 다른 속도로 작업 큐의 자신의 몫을 처리하게 됩니다. 비록 모든 구성원의 노력이 기여로 간주되어야 하지만, 문제에 먼저 접근한 사람이 다른 사람에게 영향을 미치는 결정에 대해 부적절한 영향력을 행사하는 것처럼 보일 수 있습니다.
따라서: 한 구성원이 암시적 요구사항의 일부를 고려하기 시작하자마자 전체 작업 그룹을 소집하십시오.
표현된 니즈와 욕구, 그것을 가진 개인들, 그리고 그것을 충족시키기 위한 유력한 전략을 고려하십시오. 이것은 개발 에피소드의 시작이며 첫 번째 비공식 작업 계획을 스케치하기 좋은 시간입니다. 이는 그룹 구성원의 조정으로 이어질 수 있습니다. 또한 CRC 수준의 설계를 하기에 좋은 곳입니다.
기술 메모 (Technical Memo)
개발 에피소드는 작업 그룹의 주의를 요하는 다른 활동들과 뒤얽힐 수 있습니다. 게다가 어떤 개념들은 흡수하기 위해 조용한 사색이 필요하거나, 도움 없이는 기억해 내기 힘들 만큼 충분한 세부 사항을 포함할 수도 있습니다.
따라서: 개발 중인 프로그램 내에서 쉽게 표현되지 않는 주제를 다루는, 인쇄 가능한 일련의 기술 메모를 유지하십시오.
각 메모는 단일 주제에 초점을 맞추고 텍스트는 짧고 요점을 명확히 하십시오. 신중하게 선택되고 잘 작성된 메모는 전통적인 포괄적 설계 문서를 쉽게 대체할 수 있습니다. 후자는 고립된 지점을 제외하고는 빛을 발하는 경우가 거의 없습니다. 그러한 지점들을 기술 메모로 격상시키고 나머지는 잊으십시오.
참조 데이터 (Reference Data)
요구사항 워크스루는 개발 에피소드가 시작될 때 검색, 검토 및 흡수될 관련 정보 소스를 식별할 것입니다. 다양한 데이터는 쉽게 해석되기 전에 변환이 필요할 수 있습니다. 그러한 활동은 의사 결정의 절정(climax)을 특징짓는 강렬함을 만드는 인식을 구축합니다. 그러나 절정 이후에는 초점이 최근의 결정과 그 함의에 맞춰집니다. 통찰력에 기여한 데이터와 처리 과정은 쉽게 잊힙니다.
따라서: 예시, 테스트 케이스, 고객 데이터를 기계가 읽을 수 있는 예제로 수집하십시오.
스프레드시트 프로그램을 사용하여 데이터를 적절히 정리하고 변환하십시오. 주요 관찰 사항을 잊지 않도록 시트에 텍스트 주석으로 메모와 관찰 내용을 남기십시오. 개발 내내 이것을 가까이 두고 유용할 때 개발 환경으로 쉽게 가져올 수(import) 있도록 하십시오. 애플리케이션을 위해 개발된 테스트 스위트(Test Suites)에 통합하는 등 개발 전반에 걸쳐 이 데이터와 대조하여 프로그램을 확인하십시오.
프로그래밍 에피소드 (Programming Episode)
프로그래밍은 미래에 무슨 일이 일어날지를 지금 결정하는 행위입니다. 프로그래밍 언어는 단순히 코딩이라고 불리는 과정을 통해 결정을 인코딩하는, 운영상 정밀한 방법을 제공합니다. 프로그래머는 이전에 코딩된 결정을 해석하고 이를 자신의 결정 및 기술 메모나 도메인 전문가와 같은 다른 소스에 대한 해석과 통합함으로써 미래의 행동에 대해 추론합니다. 프로그래밍 결정의 깊이, 품질, 가치는 프로그래머의 집중 능력에 의해 제한될 것입니다.
따라서: 이산적인(discrete) 에피소드로 프로그램을 개발하십시오.
에피소드에 적합한 인도물을 선택하고 이를 전달하기 위해 충분한 정신적 지분(mind share)을 투입하십시오. 에피소드가 진행됨에 따라 집중력이 높아지는 것을 인식하십시오. 각 소스(위에서 언급한)를 고려하고 의식적으로 그 권장 사항을 포함하거나 배제하십시오.
아직 내려지지 않은 결정에 종종 수반되는 두려움을 동기로 사용하십시오. 에피소드 내의 당신의 위치를 이전에 성공적이었던 에피소드의 유사한 지점과 비교해 보십시오.
예시: "이 채권 분석의 6개 항(terms)을 우리 라이브러리에 있는 4개의 계산 클래스에 바인딩할 수 있는 방법에 대해 벌써 두 번이나 맴돈 기분이야." "그래, 지금 당장은 주요 4개 항을 배치하고 에러 케이스를 살펴본 뒤, 점심 먹고 나서 어떻게 진행할지 힌트를 얻을 수 있다면 좋겠어."
내릴 수 있는 결정을 밀어붙이십시오. 에피소드를 포기하지 마십시오. 그것은 당신에게 패배감을 안겨주고 미래에 같은 수준의 집중력을 달성하는 것조차 불가능하게 만들 것입니다. 가능해 보이는 결정을 내리십시오. 그 결정을 코딩하십시오. 그런 다음 코드를 검토하여 결정의 범위와 그에 대한 확신이 코드에 명백한지 확인하십시오. 코딩은 프로그래밍 에피소드의 내리막길에서 발생합니다. 코딩은 프로그래밍 결정을 공포(promulgate)하는 가장 직접적인 방법입니다.
부록 A: 보충 패턴 요약
지면 관계상 모든 EPISODE 패턴을 포함할 수는 없습니다. 이 표는 EPISODES 패턴 언어 2부에 포함될 패턴들을 나열합니다.
| 패턴 | 솔루션 |
|---|---|
| 짝 프로그래밍 (Pair Programming) | 프로그래밍 에피소드에 성찰적 명료화(reflective articulation), 잠재적 프로세스 체크, 패턴 전파, 탐색 공간 가지치기, 일반적인 호의(good will)를 추가합니다. |
| 짝 프로그래밍 시설 (Pair Programming Facilities) | 가구를 배치하십시오. 폰트를 조정하십시오. 케이블을 늘리십시오. 문이 열린 개인 사무실과 두 개의 의자를 사용하십시오. 저자성/소유권을 버리십시오. |
| 위기 프로그래밍 에피소드 (Crisis Programming Episode) | 필요 이상으로 큰 작업 그룹을 소집하십시오. 해결책이 명확해지면 멤버들이 빠지게 하십시오. |
| 조사 컨텍스트 (Investigation Context) | 검사 및 상호 참조 도구를 사용하여 있는 그대로(as-is)의 프로그램에 대한 멘탈 모델을 조립하십시오. |
| 스파이크 솔루션 (Spike Solution) | 작업의 대표 기능을 최소한의 솔루션으로 패치, 디버그 및/또는 코딩하십시오. 진전을 위해 변수보다 프로토콜을 먼저 코딩하고 리터럴 스텁을 사용하십시오. |
| 리터럴 스텁 (Literal Stub) | 현재의 조사 컨텍스트에서 결국 계산하게 될 것임을 알고 있는 값을 (즉시) 반환하십시오. |
| 일반화된 솔루션 (Generalized Solution) | 건너뛰었거나 누락된 솔루션 부분에 대해 코딩하십시오. 여전히 남은 기능을 스텁 처리하거나 '해석 불가능하게 구현(UninterpretablyImplement)' 하십시오. |
| 프로세스 체크 (Process Check) | 무엇을 작업하고 있습니까? 왜 그것을 작업하고 있습니까? 더 이상 그것을 작업하지 마십시오. |
| 아키텍처 대체 (Architectural Substitution) | 기존 아키텍처에 잘 맞지 않는 기능을 위해 새로운 아키텍처를 만드십시오. 새 기능에 필요한 메커니즘을 이해하기 위해 필요하다면 그 아키텍처를 격리된 상태에서 개발하십시오. |
| 아키텍처 스푸프 (Architectural Spoof) | 구식 아키텍처 및/또는 그 대체물에 충분한 호환성 프로토콜을 추가하여 두 가지가 공존할 수 있게 하십시오. 수정 목록(Modification Lists)이 두 아키텍처를 모두 포함하도록 이름을 재사용하십시오. |
| 동기 부여된 통합 (Motivated Consolidation) | 동기가 부여된(자금이 지원된) 기능 세트를 지원하는 데 필요한 아키텍처 부분만 정리(clean)하십시오. |
| 에피소드 리뷰 (Episode Review) | 문제 해결 관점보다는 솔루션 공유 관점에서 에피소드 산출물을 검토하십시오. |
| 작업 산출물 (Work Product) | 솔루션을 복제하는 데 필요한 변경 사항의 전송 가능하고 통합 가능한 요약을 만드십시오. |
| 필드 패치 (Field Patch) | 비상시 현장 위치로 효율적으로 배포할 수 있는 형태로 작업 산출물을 묶으십시오. 이 패치들을 다른 작업 산출물처럼 통합하십시오. 패치는 스윕 변이를 유발할 수 있지만, 이는 하나의 연속적인 개발의 일부로 간주되어야 합니다. 진정으로 일회성 수정이 필요한 경우, 서브클래스를 사용하고 표준 구성에서 스크립트로 제외하십시오. |
| 스윕 변이 (Sweep Mutation) | 스윕은 런타임 메모리 환경에서 내보내지거나 가져올 때 애플리케이션 데이터 클러스터를 순회(traverse)하는 프로세스입니다. 외부 세계에서 객체의 가능한 모든 버전을 발견할 것을 예상하십시오. 이것들을 읽을 때 가장 최신 형태로 변이(mutate) 시키십시오. 새 객체나 수정된 객체가 기록될 때 가장 최신 형태로 기록하십시오. |
| 변이 이력 (Mutation History) | 스윕 변이는 우리가 특정 객체의 모든 이전 버전에 익숙해야 함을 요구합니다. 영향을 받는 클래스의 변이 스윕 메서드 내에 "평가 가능한 주석(evaluatable comment)"으로 그 이력을 유지하십시오. |
| 작업 통합 (Work Integration) | 최근의 작업 산출물을 모으십시오. 완전성과 충돌을 확인하십시오. 적절하게 편집하십시오. |
| 개발 빌드 (Developmental Build) | 완전한 소스에서 이미지를 재조립하십시오. 회귀 테스트를 실행하고 결과를 배포 가능한 이미지에 저장하십시오. 이 이미지를 작업 산출물이 고유하게 포함된 상태로 빌드 저장소에 게시하십시오. 기계적으로 에피소드 산출물을 조립하십시오. 충돌 해결을 감독하십시오. |
| 빌드 저장소 (Build Repository) | 개발 빌드를 구축하고 테스트하는 데 사용된 보조 정보와 함께 수집하십시오. 릴리스에 포함되고 모든 열린 포크(fork)가 닫히면 릴리스되지 않은 빌드를 도태시키십시오(cull). |
| 테스트 스위트 저장소 (Test Suite Repository) | 참조 데이터, 프로그래밍 에피소드, 일반적인 테스트 개발로부터 테스트를 수집하십시오. 테스트를 프로그래밍 에피소드와 개발 빌드에 배포하십시오. 코드인 것처럼 보존하고 보호하십시오. 유연성을 만드십시오. |
| 테스트 스위트 브라우저 (Test Suite Browser) | 빌드 통계에서 스위트, 케이스, 변수, 인스펙터 및 디버거로 파고드십시오(Drill down). 기대값을 가져오고, 입력하고, 계산하십시오. 실패 분포(체계적 vs 산발적)를 시각화하십시오. |
| 테스트 픽스처 (Test Fixture) | 테스트를 수행하기에 적합한 객체를 구성하거나 검색하십시오. 테스트 케이스가 심문(interrogation)이라면, 픽스처는 피심문자를 불러내어 질문을 시작하는 심문자입니다. 장기적인 픽스처 유지보수는 개발의 책임입니다. 픽스처가 개발 에피소드의 조사 컨텍스트에 나타나도록 하십시오. |
| 구성 스크립트 (Configuration Script) | 전체 구성(full configuration)에서 개발하십시오. 원하지 않는 기능을 제거하거나 비활성화하는 스크립트를 적용하여 배포하십시오. |
| 구성 이력 (Configuration History) | 특정 제품에 적용된 구성 스크립트와 필드 패치의 이력을 축적하십시오. 결함이 있는 구성의 디버깅 가능한 버전을 재구성할 수 있도록 위기 프로그래밍 에피소드에서 이력을 사용할 수 있게 하십시오. |