어떻게 소프트웨어를 빠르게 개발할 것인가?

이 글은 IT전문 출판사 한빛미디어 웹사이트에 실린 것으로 회사 측의 허락을 얻어 테크잇에서 퍼블리싱하는 것입니다. 

소프트웨어는 빠르게 개발하는 것이 중요하다. 소프트웨어 개발에 오랜 시간이 걸리면 시장 진입 시점을 놓칠 수 있다. 소프트웨어 시장은 급물살을 탄 듯 빠르게 변해서 오랜 개발 끝에 제품을 출시하면 어느새 시장 상황이 달라져있다. 

또는 그 사이 경쟁사들이 신제품을 내놓는 바람에 자사에서 개발 막바지에 이른 새 제품이 빛을 보지 못한다. 또한 프로젝트가 장기화되면 개발자와 프로젝트 참여 인원들이 점점 지치고 의욕을 잃는다. 이런 일들이 프로젝트 진행을 더욱 더디게 하는데, 설상가상으로 기간이 길어질수록 새로운 요구사항이 추가될 공산이 크다. 기획자는 변화하는 시장 상황을 무시할 수가 없기 때문이다. 

이쯤 되면 프로젝트는 더 늘어지고 품질은 더 떨어진다. 최근 대부분의 개발 방법론은 소프트웨어의 발 빠른 개발을 중시하며 회사에서도 이를 위해 각고의 노력을 기울인다. 그럼 어떻게 해야 소프트웨어를 빠르게 개발할 수 있을까? 이를 위해 고려해야 할 것이 매우 많지만, 여기서는 스펙을 중심으로 살펴본다.  

 예를 들어보자. 빌딩을 쌓을 때는 1층을 쌓고 2층을 쌓아야 한다. 1층을 쌓기 전에 2층을 쌓는 사람은 없다. 조립식 빌딩이라면 얘기가 다르지만 모름지기 빌딩은 순차적으로 쌓아나간다. 소프트웨어도 이런 식으로 순차적으로 개발해야 한다면 매우 오랜 시간이 걸릴 것이다. 

거대한 소프트웨어라면 수십 년이 걸리지 않을까? 다행히도 소프트웨어는 빌딩처럼 1층이 완성되기를 기다렸다가 2층을 쌓을 필요가 없다. 1층과 2층의 인터페이스만 잘 정하면 따로따로 만들어 나중에 합치면 된다. 각각 만들고 나중에 합치는 방법도 있지만, 1층과 2층의 골조만 만들어 합친 후 동시에 만드는 방법을 더 선호한다. 나중에 합치면 그 과정에서 문제가 발생하지만 처음부터 합쳐놓고 동시에 만들면 그런 문제가 줄기 때문이다.  

 이렇게 소프트웨어를 동시에 개발해 프로젝트 기간을 단축하려면 사전 단계인 분석, 설계가 정교하게 되어야 한다. 특히 컴포넌트를 잘 나누고 인터페이스를 견고하게 정의해야 한다. 인터페이스는 간결하게 정의해서 모듈 간의 연동을 쉽게 하고 확고하게 정해서 함부로 바꾸지 않도록 한다. 

물론 한번 정의한 인터페이스가 프로젝트 종료 시까지 변경되지 않는다면 가장 바람직하겠지만, 쉽지 않다. 개발 도중에 인터페이스를 변경하면 처음에 잘 정의한 경우보다 수십 배의 비용이 더 들어간다. 따라서 분석, 설계 시 최대한 세심한 노력을 기울여 인터페이스가 변경되지 않도록 정의해야 한다. 프로젝트 규모가 크고 참여 인원이 많을수록 순차적 개발보다 병렬 개발이 더 효과적이다. 수십 명의 개발자가 참여하는 프로젝트라면 순차적 개발은 거의 불가능하다. 이들 개발자가 처음부터 잘 통합된 소스코드를 기반으로 병렬로 개발해야 프로젝트를 빨리 끝낼 수 있다. 

 인터페이스는 상호 간의 약속이다. 클라이언트와 서버 모듈을 병렬 개발할 때 인터페이스는 클라이언트 개발팀과 서버 개발팀 간의 약속이다. 인터페이스를 확정하면 서로 약속한 것이니, 헤어져서 따로 개발해도 문제가 없을 정도로 신뢰도가 높아야 한다. 프로젝트 기간 내내 인터페이스를 잘 유지하기 위해서는 지속적인 통합이 필요하며 이를 위해서는 유닛 테스트, 테스트 자동화가 유용하다. 

개발자는 자신이 작성한 모듈을 완성한 후에 소스코드 관리시스템에 등록하는 것이 아니라 좀 더 잦은 주기로 등록해서 프로젝트 주기 내내 소스코드가 정상적으로 빌드되도록 유지해야 한다. 너무 늦게 통합할 경우 많은 문제를 일으키는 ‘통합의 지옥’을 맛보게 된다. 커밋은 전체 클래스 또는 전체 컴포넌트를 모두 구현할 때까지 기다릴 필요없이 기능이 하나 완성될 때마다 한다. 

하지만 항상 빌드는 되어야 한다. 또한 내가 소스코드를 수정하는 동안 다른 곳을 수정한 동료들의 소스코드와 머지merge가 잘 되어 제대로 빌드되는지 확인해야 한다. 보통은 적어도 하루에 한 두 번 이상 커밋을 한다. 며칠씩 커밋을 하지 않고 지나가지는 않는다. 지속적인 통합을 위해서는 툴을 사용해도 되고, 직접 스크립트를 작성해 구축해도 된다. 지속적인 통합을 도와주는 툴을 CIContinuous Integration 툴이라고 하며 Jenkins, Bamboo 등이 있다. 

CI 툴은 자체가 중요하지는 않지만 지속적인 통합을 쉽게 해준다. 무엇보다 중요한 것은 지속적인 통합 활동을 ‘꾸준히’하는 것이다. 지속적인 통합을 위해 반드시 필요한 것은 주기적인 빌드다. 빌드 온 커밋build on commit을 하기도 하고 데일리 빌드daily build를 하기도 한다. 밤에 빌드를 한다고 해서 나이틀리 빌드nightly build라고도 한다. 프로젝트 기간 내내 데일리빌드는 실패가 없어야 한다. 데일리 빌드가 실패했다면 인터페이스가 깨졌거나 어떤 개발자가 깨진 소스코드를 올렸을 수 있다. 빌드가 깨지면 여러 개발자들이 개발에 차질을 빚게 된다. 

데일리 빌드가 깨진 것을 브로큰트리broken tree라고 하며 이는 즉각 해결해야 개발에 차질이 없다. 시스템 규모가 클수록 병렬 개발은 필요하다. 거대 시스템 구조를 얼마나 단순화하는지가 설계의 관건이다. 아키텍트는 복잡한 시스템을 최대한 간결하게 해서 시스템 개발과 유지보수 효율을 높여야 한다. 병렬 개발을 할 때 어려운 점은 내가 필요로 하는 컴포넌트가 아직 구현되지 않아서 기능을 확인할 수 없다는 것이다. 예를 들어보자. 

나는 사용자 관리 화면을 개발하고 있고 getUserList()라는 함수가 필요하다. 나는 사용자 목록을 출력하는 화면을 만들고 있는데 다른 개발자는 아직 이 함수를 구현하지 못한 상태다. 그럼 나는 getUserList() 함수가 개발되기 전까지는 내가 만든 사용자 목록 화면을 테스트해볼 수가 없다. 그럴 때는 getUserList() 함수에 가짜 코드를 추가하면 된다. 실제로는 DB에 쿼리를 해서 사용자 목록을 가져와야 하지만 가짜로 하드 코딩을 해서 사용자 목록을 넘겨주는 것이다. 물론 이런 가짜 코드는 필요에 따라 언제든지 넣고 뺄 수 있어야 한다. C언어로 개발한다면 다음과 같은 형태가 될 것이다. 아주 간단한 예를 든다. 

이와 비슷하게, 개발 언어에 따라 적절한 방법으로 병렬 개발하는 아이디어를 적용하면 된다. 병렬 개발을 할 때 위와 같이 각자 서로 다른 모듈을 개발하는 경우가 있고 하나의 모듈을 여러 개발자가 개발하는 경우도 있다. 잘 분석, 설계된 소프트웨어라면 이와 같은 방법으로 병렬 개발을 진행해 소프트웨어를 빨리 개발할 수 있다. 

테크잇 뉴스레터를 전해드립니다!

오피니언 기반 테크 블로그 'TechIt'
테크 비즈니스를 보는 다양한 통찰들을 이메일로 간편하게 받아 볼 수 있습니다.

About the author

한빛미디어
한빛미디어

한빛미디어 / 더 나은 세상을 위한아시아 출판 네트워크

No more pages to load


TechIT

테크 비즈니스를 보는 다양한 통찰 '테크잇'

독자 여러분들께서 좋은 의견이나 문의 사항이 있으시면 아래 양식에 따라 문의 주시기 바랍니다.

Contact