•
공사를 시작하기 전 건축가는 설계도를 검토하고 서류를 작성한다. 당연히 고층 빌딩을 지을 대와 주택을 지을 때, 강아지 집을 지을때 각각 다른 방법으로 준비한다.
•
프로젝트가 무엇이든 준비 작업은 프로젝트의 구체적인 요구사항에 맞춰 구현을 시작하기 전에 상세하게 진행되어야 한다.
•
이 장에서는 소프트웨어 구현에 앞서 꼭 수행해야 하는 준비 작업들을 설명한다.
1. 선행 조건의 중요성
•
좋은 품질의 소프트웨어를 개발하는 개발자들은 프로젝트의 시작과 중간, 끝 단계에서 품질을 중요시 여긴다.
◦
프로젝트의 시작 단계에서 품질을 강조하는 경우, 제품을 계획하고 요구사항을 수집하고 설계한다.
◦
프로젝트의 중간 단계에서 품질을 강조하는 경우, 구현 방법에 역점을 둔다.
◦
프로젝트의 끝 단계에서 품질을 강조하는 경우, 시스템 테스트에 중점을 둔다.
•
선행 조건이 최신 소프트웨어 프로젝트에도 적용되는가?
◦
물론이다. 준비 작업의 가장 중요한 목표는 위험 축소다. 훌륭한 프로젝트 기획자는 프로젝트가 매끄럽게 진행될 수 있도록 위험요소를 초기에 가능한 제거한다.
•
불완전한 준비의 원인
◦
불완전한 준비의 일반적인 원인은 선행 조건 작업에 투입되는 개발자가 자신의 작업을 수행할 수 있을 정도의 전문가적인 지식을 갖고 있지 않기 때문이다.
▪
일반적으로 개발자들은 그러한 활동을 어떻게 수행할 것인지에 대한 교육을 받은 적이 없다.
▪
개발자들이 선행 작업을 어떻게 수행하는지도 모르는데 선행 작업을 더 많이 수행하라고 권하는 것은 말이 안 된다.
◦
선행 작업을 수행하는 방법을 어느정도 알고 있지만 코드를 작성하는데 급급해 준비 작업을 하지 않는 개발자도 있다.
▪
커다란 프로그램은 미리 계획을 세워두는 것만으로도 어느정도 미래의 문제들이 해결된다. 코드 작성에 급급해하지 말자.
◦
개발자가 선행 조건을 준비하지 않는 마지막 이유는 관리자들이 구현에 필요한 선행 조건을 수행하기 위한 시간을 못마땅하게 생각하기 때문이다.
▪
가급적이면 상사가 모르게 선행 조건을 계획하자.
▪
아니면 상사를 설득해보는 것도 좋은 전략일 것이다.
•
구현 전에 선행 조건을 수행하기 위한 필수적인 논의
◦
기술자로서 해야 하는 일 중에는 프로젝트 이해관계자들에게 충분히 개발 프로세스에 대해서 교육하는 것도 포함되어 있다.
◦
여기에는 코드 작성과 테스트, 디버깅을 시작하기 전 요구사항 분석 및 아키텍처 설계에 대해 상사와 논쟁하는 과정이 포함된다.
◦
논리적 설득
▪
큰 프로젝트는 더 많은 계획 수립이 필요하고 작은 프로젝트는 상대적으로 덜 필요하다.
▪
관리 측면에서 계획 수립은 프로젝트에 잘못된 작업으로 인해 자원을 낭비하는 일이 없도록 하는 것이다.
◦
비유적 설득
▪
소프트웨어 시스템을 구축하는 것은 인력과 돈이 필요한 다른 프로젝트와 같다.
▪
집을 지을 때 다양한 절차들이 있듯이 프로젝트를 구현하는데도 다양한 절차가 있음을 비유적으로 표현하면 설득해보라.
◦
데이터에 근거한 설득
▪
지난 25년 간의 연구 결과에서 증명된 사실은 처음부터 작업을 제대로 수행해야 한다는 것이다.
▪
어느정도 프로젝트가 진행된 시점에서 변경사항이 발생하는 것은 생산성을 현저히 저하시키는 행위다.
▪
이것은 가능한 빨리 문제를 찾고 해결하는 것이 좋다는 주장을 뒷받침한다.
•
그래서 소프트웨어 테스트를 작성하라고 하는건가..?
2. 작업 중인 소프트웨어의 종류 결정
•
다음은 일반적인 세 가지 종류의 프로젝트와 각 프로젝트에 적합한 방법을 표로 정리해둔 것이다.
•
다음 표를 참고해서 본인의 프로젝트를 규정하고 그에 맞는 준비 사항들을 알아보자.
비즈니스 시스템 | 특수임무용 시스템 | 임베디드 안전 필수 시스템 | |
일반적인 응용 프로그램 | 인터넷 사이트
인트라넷 사이트
재고 관리
게임
정보 관리 시스템
급여 지급 시스템 | 임베디드 소프트웨어
게임
인터넷 사이트
패키지 소프트웨어
소프트웨어 도구
웹 서비스 | 항공전자 소프트웨어
임베디드 소프트웨어
의료기기
운영체제
패키지 소프트웨어 |
수명 주기 모델 | 애자일 개발
진화적 프로토타이핑 | 단계적 출시
진화적 출시
나선형 개발 | 단계별 출시
나선형 개발
진화적 출시 |
계획 및 관리 | 점증적 프로젝트 계획
필요에 따라 테스트 및 QA 계획 수립
비형식적인 변경 관리 | 기초적인 선행 계획 수립
기초적인 테스트 계획 수립
필요에 따라 QA 계획 수립
형식적인 변경 관리 | 광범위한 선행 계획 수립
광범위한 테스트 계획 수립
광범위한 QA 계획 수립
엄격한 변경 관리 |
요구 사항 | 비형식적인 요구사항 명세 | 중간 수준의 정형화된 요구사항과 명세
필요에 따라 요구사항 검토 | 형식적인 요구사항 명세
형식적인 요구사항 정밀 검사 |
설계 | 설계 및 코드 작성의 병행 | 아키텍처 설계
비형식적인 상세 설계
필요에 따라 설계 검토 | 아키텍처 설계
형식적인 아키텍처 정밀 검사
형식적인 상세 설계
형식적인 상세 설계 정밀 검사 |
구현 | 페어 프로그래밍이나 개별적인 코드 작성
비형식적인 체크인 절차 또는 체크인 절차 없음 | 페어 프로그래밍이나 개별적인 코드 작성
비형식적인 체크인 절차
필요에 따라 코드 검토 | 페어 프로그래밍이나 개별적인 코드 작성
형식적인 체크인 절차
형식적인 코드 정밀 검사 |
테스트 및 QA | 개발자가 자신이 작성한 코드를 테스트
TDD
별도의 테스트 그룹에 의한 테스트 부재 | 개발자가 자신이 작성한 코드를 테스트
TDD
별도의 테스트 그룹 | 개발자가 자신이 작성한 코드를 테스트
TDD
별도의 테스트 그룹
별도의 QA 그룹 |
배포 | 비형식적인 배포 절차 | 형식적인 배포 절차 | 형식적인 배포 절차 |
•
선행 조건에서 반복적인 접근 방법이 갖는 효과
◦
반복적인 방법은 프로젝트가 진행되는 과정에서 조금씩 재작업하기 때문에 전체적으로 드는 비용이 더 적어지게 된다.
◦
선행 조건을 줄이거나 없앤 반복적인 프로젝트는 동일한 조건의 순차적 프로젝트와 두 가지 측면에서 다르다.
▪
첫째, 결합 발생 후 상대적으로 빠르게 발견되므로 평균 결함 수정 비용이 더 적게 든다.
•
결함이 각 단계의 마지막에 발견될 것이므로 결함을 수정하는 과정에서 소프트웨어의 일부분을 재설계하고 코드를 재작성하며 테스드도 다시해야 한다. 이는 결함 수정 비용을 증가시킨다.
▪
둘째, 반복적인 접근 방법에서의 비용은 마지막에 한꺼번에 들지 않고 전체 프로젝트 과정에 조금씩 흡수된다.
◦
저자가 추천하는 방법은 요구사항 중 80% 정도를 미리 명시하고 추가적으로 기술할 시간을 할당해둔 다음 프로젝트를 진행하면서 중요한 요구사항들만을 새로 수용할 수 있도록 설계하는 것이다.
•
반복적인 방법과 순차적인 방법의 선택
◦
다음의 경우, 순차적인 접근 방법을 선택하는 것이 낫다.
▪
요구사항이 안정적일 때
▪
설계가 직관적이며 이해하기 쉬울 때
▪
개발 팀이 해당 응용 분야에 익숙할 때
▪
프로젝트의 위험 부담이 적을 때
▪
장기적인 계획이 중요할 때
▪
요구사항, 설계, 코드 변경 비용이 높을 것 같을 때
◦
다음 경우에는 반복적인 접근 방법이 낫다.
▪
요구사항을 제대로 이해하기 힘들거나 다른 여러 이유로 변경될 가능성이 높을 때
▪
설계가 복잡하거나 어려울 때
▪
개발 팀이 해당 응용 분야에 대해 잘 모를때
▪
프로젝트의 위험 부담이 높을 때
▪
장기적인 계획이 중요하지 않을 때
▪
요구사항, 설계, 코드 변경 비용이 높지 않을 것 같을 때
◦
즉 변동 가능성이 높다면 반복적인 방법을 낮다면 순차적인 방법을 선택하는 것이 좋다.
◦
소프트웨어의 특성상 일반적으로 반복적인 방법이 순차적인 방법보다 훨씬 유용한 경우가 많다.
3. 문제-정의 선행 조건
•
구현에 앞서 첫 번째 선행 조건은 시스템이 해결해야 하는 문제를 명확하게 기술하는 것이다.
◦
이를 제품 정의, 문제 정의라고도 한다.
•
문제 정의는 반드시 도메인 상세 언어로 작성해야 하며 문제는 사용자 관점에서 기술해야 한다.
•
문제 정의를 제대로 하지 않으면 잘못된 문제를 해결하는 데 시간을 낭비할 수도 있으므로 신중히 많은 시간을 들여서 정의하는 것이 좋다.
4. 요구사항 선행 조건
•
요구사항은 소프트웨어 시스템이 무엇을 수행해야 하는지에 대해 상세하게 기술하고 해결책을 구현하기 위한 첫 번째 과정이다.
◦
요구사항을 수집하는 작업을 요구사항 개발, 요구사항 분석, 요구사항 정의, 기능 명세, 명세라고 한다.
•
왜 명시적인 요구사항이 필요한가?
◦
명시적인 요구사항은 개발자 대신 사용자가 시스템의 기능을 주도하게 하는 데 도움이 된다.
◦
요구사항이 명시적이면 사용자가 요구사항을 보고 동의할 수 있다. 그렇지 않으면 개발자의 관점에서 요구사항을 결정해 버리는 경우가 많다.
▪
요구사항을 명시적으로 정의함으로써 사용자가 원하는 것이 무엇인지를 이해할 수 있다.
◦
명시적인 요구사항은 논쟁을 피하게 해준다. 프로그래밍을 시작하기 전에 시스템 기능을 결정하므로 프로그램의 기능에 대해서 다른 개발자가 동의하지 않는다면 요구사항을 살펴보면서 문제를 해결할 수 있다.
◦
요구사항에 집중하면 개발을 시작하고 난 후 변경 사항을 최소화하는 데 도움을 준다.
▪
요구사항이 변경되면 기존의 코드를 재설계해야 하고 새로 설계하는 것보다 시간이 더 오래 걸리게 될 것이다.
◦
요구사항을 제대로 명시하는 것은 프로젝트 성공에 있어 효과적인 구현 기술보다 더 중요하다.
•
견고한 요구사항에 대한 미신
◦
견고한 요구사항은 소프트웨어 개발의 성배와 같다. 요구사항이 견고하면 아키텍처부터 설계, 코드 작성, 테스트까지 프로젝트를 차분하게 잘 진행할 수 있다.
◦
일반적으로 사용자는 코드가 작성되기 전까지 자기에게 필요한 사항을 확실하게 설명하지 못한다.
▪
사용자에게 문제가 있는것이 아니다. 프로젝트를 진행할수록 프로젝트에 더 많이 알듯이 사용자도 마찬가지기 때문이다.
◦
개발 과정에서 사용자는 자연스럽게 자신에게 필요한 요구사항을 더 잘 이해하게 되며 이러한 과정이 요구사항 변경의 주요한 원인이다.
•
구현 중에 요구사항 변경 다루기
◦
다음은 요구사항의 변경을 잘 다루기 위한 몇 가지 방법이다.
1.
요구사항의 품질을 평가한다.
•
요구사항이 충분치 않다면 작업을 멈추고 저장해둔 다음 요구사항을 제대로 수정한 후 일을 진행한다.
•
이는 불필요한 과정이 아니다. 빠르게, 느리게가 중요한게 아니다. 올바르게 가고 있는가가 중요하다.
2.
모든 사람이 요구사항 변경 비용에 대해서 알게 한다.
•
자원의 소모는 사람의 정신을 맑게 해준다.
3.
요구사항 변경 절차를 구축한다.
4.
변경 사항들을 수용하는 개발 접근 방법을 사용한다.
•
진화적 프로토타이핑 접근 방법을 사용하면 요구사항에 능동적으로 대응할 수 있다.
•
작게 구축하여 피드백을 받고 설계를 약간만 수정한 다음 피드백을 받는다. 핵심은 사용자에게 빠르게 피드백을 받을 수 있도록 개발 주기를 짧게 가져가는 것이다.
5.
프로젝트를 취소한다.
•
요구사항이 형편없거나 변경 가능성이 높다면 그 프로젝트는 취소해야 한다.
6.
프로젝트의 사업성을 주시한다.
•
요구사항 문제의 상당수는 프로젝트를 수행하는 사업상 목적을 고려하게 된다면 무의미해진다.
•
정말로 필요한가에 대한 고민을 시켜보자.
5. 아키텍처 선행 조건
•
소프트웨어 아키텍처는 소프트웨어 설계의 상위 부분에 속하며 설계 중에서 더 상세한 부분을 담은 틀이다.
◦
아키텍처는 시스템 아키텍처, 상위 수준 설계, 최상위 설계라고도 불린다.
•
아키텍처가 왜 선행 조건에 포함될까? 그것은 아키텍처의 품질이 시스템의 개념적인 무결성을 결정하기 때문이다. 이는 곧 시스템의 궁극적인 품질을 결정짓는다.
•
좋은 아키텍처는 구현을 쉽게 만든다. 나쁜 아키텍처는 구현을 거의 불가능하게 만든다.
•
전형적인 아키텍처의 구성 요소
◦
좋은 시스템 아키텍처에는 공통 요소가 많다. 다른 사람과 협업을 하게 되므로 반복되는 코드나 함수를 유틸로 뺀다던지, 데이터 소스 접근 방법을 일관화한다든지 말이다.
◦
비즈니스 로직 외의 요소들은 가급적이면 공통 요소들이 처리하게 두는 것이 낫다.
◦
프로그램 구조, 주요 클래스, 데이터 설계, 비즈니스 규칙, 사용자 인터페이스 설계, 자원 관리, 보안, 성능, 확장성, 상호운용성, 국제화와 지역화, 입력/출력, 오류 처리, 장애 허용, 구조적인 실행 가능성, 과도한 엔지니어링, 구입과 구현 결정, 재사용 결정, 변경 전략, 일반적인 아키텍처 품질
6. 선행 조건에 소요되는 시간
•
문제 정의와 요구사항, 소프트웨어 아키텍처 작업에 소요하는 시간은 프로젝트의 필요에 따라 달라진다.
•
일반적으로 제대로 진행되는 프로젝트는 요구사항과 아키텍처, 사전 계획 수립을 위해서 전체 노력의 10%~20% 정도와 전체 시간의 20~30%의 시간을 투자한다.
◦
상세 설계는 제외된 시간이다. 상세 설계는 구현의 일종이다.
•
요구사항이 불안정하고 작업 중인 프로젝트의 규모가 크다면 구현 초기에 발생하는 요구사항 이슈를 해결하기 위해 요구사항 분석가와 작업해야할 수도 있다.
•
요구사항이 불안정하고 작업 중인 프로젝트의 규모가 작다면 직접 요구사항 이슈를 해결해야할 것이다. 요구사항을 정의하는 데 충분한 시간을 투입하여 요구사항의 변경이 구현에 미치는 영향을 최소화하라.
•
소프트웨어 아키텍처에 시간을 할당할 때도 요구사항 개발과 유사한 방법을 사용한다.
◦
지금까지 한 번도 다루지 않은 소프트웨어라면 새로운 분야에서의 불확실한 설계에 대비하여 더 많은 시간을 할애하라.
•
좋은 아키텍처를 위해 소비하는 시간 때문에 다른 작업 영역에 지장을 주지 않도록 하라. 필요하다면 아키텍처 작업 역시 요구사항 작업과 같이 별도의 프로젝트로 진행한다.
요점 정리
•
구현을 준비할 때 가장 중요한 목표는 위험을 줄이는 것이다. 준비 작업이 위험을 증가시키는 게 아니라 감소시키도록 하라.
•
품질이 뛰어난 소프트웨어를 개발하고 싶다면 처음부터 끝가지 소프트웨어 개발 과정 내내 품질에 관심을 두라.
◦
품질에 대한 관심을 처음에 갖는 것이 나중에 갖는 것보다 제품의 품질에 훨씬 큰 영향을 끼친다.
•
프로그래밍을 시작하기 전 적절한 준비의 중요성을 포함한 소프트웨어 개발 과정에 대해 상사와 동료를 설득하는 일도 개발자의 몫이다.
•
프로젝트의 종류가 구현 선행 조건에 중대한 영향을 미친다. 반복적으로 진행해야 하는 프로젝트도 많지만 순차적으로 진행해야 하는 프로젝트도 있다.
•
문제 정의가 명시되어 있지 않다면 구현 시에 잘못된 문제를 풀게 될 것이다.
•
요구사항 개발이 제대로 이루어지지 않았다면 문제의 중요한 사항을 놓칠 수가 있다. 구현 다음 단계부터는 요구사항을 변경할 때 처음부터 20배에서 100배 정도의 비용이 더 들기 때문에 프로그래밍을 시작하기 전에 요구사항어 정확한지 확인해야 한다.
•
아키텍처 설계가 제대로 이루어지지 않았다면 구현 시에 올바른 문제를 잘못된 방법으로 해결할 수 있다.
◦
잘못된 아키텍처로 작성된 코드가 증가할수록 구조적인 변경 비용이 발생하므로 아키텍처가 적합한지 확인하라.
•
프로젝트에서 구현 선행 조건에 어떤 접근 방법을 적용했는지 알고 그에 따라 적절한 구현 방법을 선택하라.