소프트웨어를 개발하다보면 상황에 의해 그 전체가 완전히 바뀔 수 있습니다.
상황이 바뀌었음에도 어제의 계획에 집착하는 것은 큰 화를 불러올 수 있습니다.
애자일함, 나아가 성공적인 개발은 변화를 깨닫고 적응하는 능력입니다. 이렇게 적응한 후에야 사용자 필요를 진짜로 만족시키는 시스템을 만들면서도 여러 요구조건을 맞출 수 있습니다.
- 고객이 결정하도록 하라
개발자는 설계에 관한 결정을 내릴 때 참여해야 하나, 프로젝트 및 비즈니스에 대한 결정을 모두 내려야 하는 건 아닙니다.
어떤 작업을 할 때, 한 방법은 빠르지만 사용자가 할 수 있는 기능을 제약하고 다른 방법은 구현하는데 시간이 더 걸리지만 사용자에게 더 많은 유연성을 준다고 예를 들어 보겠습니다. 만약 개발 관리자가 첫번째 옵션을 선택했다면, 여러 제약이 나타남에 따라 고객의 컴플레인이 들어올 수 있고 결과적으로 필요 이상의 돈, 시간, 노력이 더 들 수 있습니다.
따라서 이러한 부분에 대해 개발자가 바로 결정하기보단, 고객이 직접 결정하도록 하는 것이 좋습니다.
• 결정하지 말아야 할 것을 결정하라
개발자와 관리자가 수행하는 가장 중요한 설계 결정은 무엇이 자신의 권한 밖인지를 정하고 그 이슈를 사업주가 결정하도록 하는 것입니다.
고객에게 얘기할 땐 가능한 선택사항을 준비해 장단점을 제시하고, 예상 비용과 이익에 대해 기술적 관점이 아닌 사업적 관점에서 보여주도록 합니다. 이렇게 고객이 아는 상태에서 결정을 하고, 그것을 감수해야 하도록 합니다.
- 설계가 강요하는 대신 안내하도록 하라
'설계' 는 개발 과정에서 필수 단계입니다. 설계를 하면 시스템의 세부를 이해하고 서브시스템과 부분 간의 상호 관계를 아는데 도움이 됩니다. 또한, 설계는 시스템 구현의 방향을 지시합니다.
애자일 방법론은 개발 단계에서 매우 빠른 시점에 코딩할 것을 권합니다. 이 말은 설계가 필요없다는 뜻은 아닙니다.
좋은 설계를 따르는 일은 여전히 중요하고, 시스템이 조직되는지를 보여주는 핵심 다이어그램을 작성하는 일은 필수적입니다.
하지만 당장 필요한 설계를 미리 할 때조차 예기치 못한 일들이 생깁니다. 현재 시점에서 따라가는 설계는 요구사항에 대한 현재의 이해에 기초한 것을 명심하고, 설계와 설계를 구현하는 코드는 끊임없이 진화한다는 점을 알고 있어야 합니다.
• 설계는 구현하는데 필요한 만큼만 상세해야 한다
설계자가 도면에 자신의 생각을 공들혀 표현한 후 프로그래머가 코딩하도록 생각의 간극을 가로질러 도면을 던졌을 때, 건네받은 설계가 작업이 진행한 한참 후에 이상적이지 않다는 점을 드러낸다면 다시 되돌아가기엔 너무 늦었습니다.
설계에는 두 가지 수준, 즉 '전략적' 인 것과 '전술적' 인 것이 있습니다.
• 전략적 설계 vs 전술적 설계
전략적 수준의 설계는 메서드, 매개 변수, 필드 등의 세부 내용이나 객체 간 상호작용의 정확한 순서에 대한 세부 내용을 명시해서는 안됩니다. 이런 내용은 전술적 설계에 맡겨야 하고 이 전술적 설계는 프로젝트가 진화할 때에만 드러납니다.
좋은 전략적 설계는 올바른 방향을 가리키는 지도와 같은 역할을 합니다.
전술적 설계에선 책임의 관점에서 가능한 클래스 설계를 논의하는 것이 적절합니다.
설계에 대한 가장 좋은 피드백은 코드 자체에서 옵니다. 요구사항이 조금 변해도 계속 구현하기 쉽다면 그 설계는 좋은 설계입니다.
만일 요구사항이 조금 변했는데도 큰 혼란, 코드의 긴 라인에 걸쳐 혼란이 온다면 설계를 개선해야 합니다.
- 기술 사용을 정당화하라
• 프레임워크를 무턱대고 고르지 말자
기술을 쓰면 멋있고 프로그래머의 솜씨를 향상시킬 거 같다는 이유로 기술을 선택하는 경우가 있습니다.
실제로 주위에서 이런 사례나, 제안을 하는 개발자를 여럿 봐왔습니다. 한마디로, 이러면 안됩니다.
새로운 기술이나 프레임워크에 대해 생각하기 전에 해결하려는 문제가 무엇인지 확인해야 합니다.
• 새로운 기술이 문제를 정말 해결하는가?
새로운 기술이 실제로 당면한 문제를 정말 해결하는지에 대해 집중해야 합니다.
새로운 기술이 해로운 부작용 없이 원하는 내용을 수행할 수 있다는 것을 확인하고, 필요하다면 작은 프로토타입도 작성해야 합니다.
• 이 새로운 기술에 얽매이게 되는가?
어떤 기술은 적용하면 돌이킬 수 없을 수도 있습니다. 나중에 조건이 바뀌었을 때, 가역성 (사고가 진행되어 온 과정을 거꾸로 되밟아 갈 수 있으며, 진행되어 온 행위를 거꾸로 말소해 나감으로써 원상을 회복할 수 있는 능력) 의 부족은 프로젝트에 치명적입니다.
기술이 어느정도 개방적인지 얼마나 독점적인지를 충분히 고려해야 합니다.
• 유지보수 비용은 어떤가?
시간이 가면서 새로운 기술을 유지보수 하는 일이 더 비싸진다면, 이것은 잘못된 투자입니다.
실제로 개발자들은 늘 새로운 기술을 원하고, 무언가 작은 프로젝트를 진행하게 될 때 새로운 프레임워크 혹은 언어를 도입해보고 싶어 합니다. 그 프로젝트가 정말 작아도 계속해서 무언가의 기능을 맡고있다면, 이는 결국 프로젝트를 진행했던 개발자 외의 다른 개발자도 맡아야 할 때가 생깁니다. 본인만의 욕심으로 사용했던 새로운 기술이 다른 누군가의 손을 타게되고 힘든 유지보수를 불러올 수 있습니다.
• 다운로드해 얻을 수 있는 프로그램을 새로 만들지 말라
가끔 어떤 개발자들은 충분히 신뢰할 수 있는 라이브러리를 굳이 다시 만드려고 합니다.
버전이 너무 낮거나, 호환이 되지 않는다면 약간의 보수는 필요할 수 있겠지만 대체로 그렇지는 않습니다.
이런데에 시간을 들이는 것 보다, 도메인이나 어플리케이션에 국한된 프로그램을 만드는 데 더 많은 시간과 노력을 들여야 합니다.
- 코드를 릴리즈할 수 있게 유지하라
• 체크인한 코드는 항상 바로 쓸 수 있어야 한다
팀에서 일할 때 자신이 만든 변경 사항에 민감해야 하고, 자신이 시스템의 상태와 팀 전체의 생산성에 영향을 준다는 사실을 계속 명심해야 합니다. 다른 개발자가 프로젝트 코드를 망치는 것 또한 참아선 안됩니다.
• 로컬 테스트를 실행하라
작업한 코드가 컴파일 되고 모든 단위테스트를 통과함을 확인하는 것으로 시작해야 합니다.
• 최신 소스를 체크아웃하라
버전 관리 시스템에서 소스 코드 최신 사본을 가져와서 자주 그것으로 컴파일하고 테스트해야 합니다.
위의 과정들을 진행하며 문제를 발견할지도 모릅니다. 만약 문제가 생긴다면, 체크인한 사람에게 바로 그 사실을 알려야 합니다.
혹은 이런 과정들을 지속적 통합 시스템이 자동으로 해주도록 시스템을 갖춰야 합니다.
- 일찍, 자주 통합하라
애자일의 주요 특징은 일시적이 아닌 지속적인 개발입니다.
이 점은 특히 프로젝트에서 다른 팀원이 작업한 코드와 통합할 때 필요하지만, 간혹 개발자들은 통합을 미루기도 합니다.
하지만 통합은 제품 개발에서 주요 위험 분야의 하나입니다. 서브시스템이 통합되지 않은 채 커지도록 놔두면 점점 더 큰 위험을 불러일으킵니다.
• 통합하면서 격리할 수 있다.
통합과 격리는 상호배타적인 것이 아닌, 동시에 수행할 수 있습니다.
Mocking 객체를 사용해 코드를 의존성에서 분리하여 통합 전에 테스트하도록 합시다. Mocking 객체는 실제 객체의 기능을 제공하지 않지만 다루기 쉽고 테스트를 위해 필요한 행동을 시뮬레이션하기가 더 쉽습니다.
Mocking 객체를 사용해 격리된 채 자신의 코드를 단위테스트하고, 정확히 동작한다면 바로 통합하면 됩니다.
격리되어서 코드를 개발하다가 갑자기 한꺼번에 통합하려 할 때, 굉장한 conflict 를 겪을 수 있습니다.
비록 격리 상태에서 개발할 때 더 빠르고, 더 생산적이며 문제를 효과적으로 찾을 수 있다는 장점도 있지만 2~3일 이상 통합을 늦춰서는 안됩니다.
• 대규모 통합을 절대 받아들이지 말라
일찍 통합함으로써 어떻게 서브시스템들이 상호 작용, 동작하는지 알게 되고 정보를 어떻게 공유해 통신하는지 평가하게 됩니다.
이런 쟁점에 대해 더 일찍 이해하고 다룰수록 그 쟁점을 고칠 때 일이 더 적어집니다.
조금 단순하게 git 을 예로 들어보겠습니다. 지금의 팀에서도 하나의 프로젝트에 2~3명의 개발자가 작업할 경우, merge 를 미루다가 이후에 많은 부분에서 conflict 가 발생하고, 그럼 누군가는 이를 해결하는 동안 그 사이 추가된 코드와 또 conflict 이 나는 문제를 아주 가끔씩 볼 수 있었습니다.
최대한 자주 merge 를 하여 이런 문제를 없애고, branch merge 에도 hook 을 추가해 jenkins 에 등록한 테스트 코드가 돌아가도록 자동화함으로써 생산성을 끌어올릴 수 있습니다.
- 배치를 일찍 자동화하라
우리가 개발하는 어플리케이션은 당연히 실전 환경에서도 잘 동작해야 합니다.
이 얘기는 어플리케이션을 대상 머신에 신뢰할 만하고 반복적인 방식으로 배치할 수 있어야 함을 의미합니다.
아마도 서버라면 production 환경에서의 배포, 모바일 어플리케이션이라면 다수의 사용자가 사용하는 모바일 기기가 그 대상일 것입니다.
• 품질보증에서는 배치를 테스트해야 한다
현재 품질보증을 위해 어플리케이션을 수동으로 설치한다면, 시간이 좀 들더라도 그 과정을 자동화하는 것을 고려해야 합니다.
시스템 배치를 자동화하면 프로젝트 생애 동안 의존 관계에 있는 변화를 따라가는 일이 더 쉬워집니다.
대체로 이런 작업은 조금 귀찮기도 하지만, 이러한 자동화를 통해 라이브러리 및 컴포넌트 등의 문제를 더 빨리 캐치할 수 있습니다.
- 데모를 사용하여 자주 피드백을 받아라
고객의 요구를 받을 때와 개발한 내용을 보여줄 때의 시간 간격이 클수록 고객의 기대에서 더 멀어지게 됩니다.
개발할 때 고객의 입력을 받기 위해 자주 이야기를 나눈다면 모두에게 이득입니다.
고객은 진행상황을 더 잘 알게 되고, 향상된 이해와 기대에 기초해 개발자를 인도할 수 있으며 개발자는 고객의 실제 필요에 가깝게 프로그래밍할 수 있습니다.
따라서 피드백을 자주 받고, 그 반복 주지가 매 분기나 매년이라면 주간이나 격주로 줄여야 합니다.
사실 이부분은 약간의 딜레마가 있을 수 있습니다. 너무 잦은 피드백을 받다가 개발이 뒤죽박죽 되는 케이스 또한 꽤나 많이 봐왔습니다.
책에서는 이상향에 대해 얘기하지만, 실무에서 그 적절한 포인트를 찾는 것은 각자의 역할일 것 같습니다.
- 짧은 반복을 사용하여 점진적으로 배포하라
통합 프로세스와 애자일 방법론 모두 반복적이고 점진적으로 개발하라고 말합니다.
점진적인 개발에서는 어플리케이션의 기능을 한 번에 몇 개의 작은 그룹 단위로 개발하고, 그 시점에서 제품을 릴리즈하거나 데모를 보일 수 있습니다.
반복적인 개발에서는 다양한 개발 작업(분석, 설계 구현, 테스트, 피드백 등) 을 반복이라 불리는 작고 반복하는 주기로 수행합니다.
프로젝트 규모가 클수록 실패하기 쉽습니다. 아마도 그런 프로젝트는 보통 반복적이고 점진적인 개발 계획을 따르지 않거나 반복의 주기가 너무 길었을 것 입니다.
규모가 큰 프로젝트에 잰걸음으로 달려든다는 생각은 애자일 접근의 핵심입니다.
W3C 의 XML 사양을 예로 보겠습니다. XML 문서의 구조와 어휘를 정의하는 문서 타입 정의(DTD) 는 원래 사양의 일부로 배포되었습니다. DTD 는 설계할 때의 쟁점을 해결했지만 실제 사용하면서 많은 제약과 문제가 두드러졌습니다.
이후 사용자 피드백과 더 깊은 이해를 바탕으로 스키마와 같이 문서 구조를 정의하는데 더 효과적인 다음 세대 해결책이 나왔습니다.
즉 일찍 릴리즈함으로써 결험과 통찰을 얻어 더 좋은 결과물이 나온 것입니다.
대규모 어플리케이션을 하나로 제공하지 말고 더 작고 유용한 조각으로 나눠서 만드는, 점진적 개발을 따라야 합니다.
NASA 도 우주 왕복선에 사용할 복잡한 소프트웨어 개발에 반복적이고 점진적인 개발을 사용한다고 하니 말이죠.
출처 : 애자일 프랙티스(책)
'소프트웨어 개발방법론 > 애자일 방법론' 카테고리의 다른 글
애자일 코딩 (0) | 2021.05.29 |
---|---|
애자일 피드백 (0) | 2021.05.22 |
애자일 기르기 (0) | 2021.05.08 |
애자일 시작하기 (0) | 2021.05.01 |
애자일 소프트웨어 개발 (0) | 2021.04.24 |