[소프트웨어공학] 3. Software Process
지난 글에서 소프트웨어 공학의 중요성을 정리하면서 소프트웨어 개발 프로세스에 대한 내용을 가볍게 정리했다.
각각의 소프트웨어 개발 방법론마다 디테일한 부분의 차이는 있을지 몰라도, 요구사항 분석, 소프트웨어 설계, 구현, 테스트, 유지보수라는 5가지 단계는 모든 개발 방법에서 공통적으로 수행되는 단계이다.
이번 글에서는 이 각각의 단계를 구체적으로 알아보기에 앞서
소프트웨어 개발 방법론마다 어떤 형태의 Software Process 를 가지고 있는지 하나씩 정리해본다.
Software Process
소프트웨어 프로세스는 소프트웨어를 개발하는데 필요한 activity들의 구조화된 집합을 말한다.
소프트웨어 프로세스의 종류는 다양하지만 모든 프로세스에는 공통적으로 스펙 분석, 설계및 구현, 테스트, 유지보수 단계가 포함된다.
Software Process Model 은 특정한 관점에서 소프트웨어 프로세스를 바라본 것을 말한다.
소프트웨어 프로세스 모델은 크게 Plan-Driven 과 Agile 2가지 종류가 존재한다.
Plan-Driven은 이름 그대로 시작부터 끝까지 모든 프로세스 과정의 행동들이 계획되어있는 것을 말한다.
따라서 지금까지 계획대비 어느 정도 진척이 되어있는지 언제나 진행상황을 체크할 수 있다.
Agile 은 민첩하다는 뜻을 갖고 있는 단어로, 점진적으로 계획을 세우는 모델이다.
하나의 시스템이 여러 버전으로 점점 발전되는 방향으로 개발되며, 고객의 요구사항 변경에 쉽게 대처할 수 있다는 특징이 있다.
Agile 방식은 요구사항을 분석하여 파악한 specification 이 있을 때, 이 스펙을 쪼개어 개발하는 경우가 많다.
이 경우, 각각의 쪼개진 단위를 increments 라고 부르며, increments 단위로 계획을 세워 개발하고 테스트한다.
Plan-Driven 과 Agile 모두 '스펙 정의 - 설계 - 구현 - 테스트 - 유지보수' 라는 순서대로 개발을 진행한다.
다만 하나의 개발 사이클에서 개발하는 단위의 규모에서 차이점이 발생한다.
Agile은 이 개발 사이클을 작게 여러번 가져가고, Plan-Driven은 크게 1번만 가져가는 것이 차이점이다.
하지만 실제로는 plan-driven 과 agile 을 구분하지 않고 이 두 방식이 모두 포함된 process 로 개발하는 경우가 많다.
소프트웨어 프로세스에는 정답이 없으며, 상황에 따라 그때 그때 더 적절한 소프트웨어 프로세스 모델이 존재하기 때문이다.
Software Proceess Model
이제 구체적인 소프트웨어 프로세스 모델들을 하나씩 정리해본다.
주요 소프트웨어 프로세스 모델은 크게 3가지가 있다.
- Waterfall Model
한국어로는 폭포수 모델이라고 부른다.
마치 폭포수가 위에서 떨어지면 거슬러 올라갈 수 없듯이, '스펙 정의 - 설계 - 구현 - 테스트' 단계를 수행할 때 하나의 단계가 다 끝나면 다음 단계로 넘어가고 이전 단계로 돌아가지 않는 형태의 개발 방법론을 말한다.
위에서 정의한 Plan-Driven 과 Agile 중에서 Plan-Driven 에 속하는 방식이다.
- Incremental Development
개발할 스펙을 여러 조각 (increment) 들로 쪼개고, 조각들을 순서대로 개발해서 차근차근 합치는 방식이다.
위에서 본 것처럼 보통은 애자일 방식으로 많이 하지만 Plan-Driven 으로 할 수도 있다.
만약 모든 요구사항을 다 분석하고 계획을 세운 다음 쪼개서 개발하면 그때는 Plan-Driven 이고, 각 조각마다 계획을 세우고 개발하면 그때는 Agile 이 된다.
- Integration and Configuration
기존에 만들어진 커스텀 설정이 가능한 소프트웨어들을 적절히 설정하고 하나로 조립하여 소프트웨어를 개발하는 방식이다.
즉, 기존 소프트웨어를 현재 상황에서 사용할 수 있게 Configuration을 바꿔서 가져다가 재사용하는 것을 말한다.
이 방식도 Plan-Driven과 Agile 모두 가능하다.
어떤 소프트웨어를 어떻게 바꿔서 가져다가 사용할지 모두 계획을 세워두고 하면 Plan-Driven 이고, 그때 그때 increments 에 필요한 것만 찾아서 가져오면 Agile 방식이 된다
소프트웨어 프로세스 모델은 이 3가지 말고도 여러가지 모델들이 있지만, 이 3가지 모델을 이해하면 다른 모델들도 쉽게 이해할 수 있다.
이제 이 3가지 주요 모델들의 장단점과 특징을 살펴보자.
Waterfall Model
waterfall 모델은 위 그림과 같은 단계로 개발이 진행된다.
그림을 보면 알 수 있듯, Requirements definition 부터 시작해서 단계를 넘어가는데, 하나의 단계를 마치기 전에는 다른 단계로 넘어갈 수 없다. 그리고 한번 다음 단계로 넘어가면 이전 단계로 돌아갈 수도 없다.
(Operation and maintenance 단계에서만 이전 단계로 갈 수 있다.)
위 그림을 보면 Implementation and unit testing 과 integration and system testing 에서 2가지 테스트가 존재한다.
unit testing 은 component testing 이라고도 부르며, 개발자가 자신이 구현한 부분을 테스트하는 것을 말한다.
system testing 은 회사에 테스트를 전문으로 하는 QA 팀에서 하는 테스트를 말한다.
아무리 QA팀이 있다고 해도 개발자가 자신이 개발한 코드를 테스트하지 않는 것은 말이 안된다.
그래서 unit testing 과 system testing 이 구분되어 있다.
- 장점
각 단계가 마무리될 때마다 문서가 나온다.
예를 들어 객체지향적으로 프로그램을 설계한다고 했을 때, System and software design 단계가 마무리되면 개발할 모든 클래스와 해당 클래스가 가진 public function (인터페이스) 중심으로 문서가 나온다.
이렇게 문서까지 만들고나서 다음 단계로 넘어가고, 그 단계에서도 작업을 마친 뒤 문서까지 남기고 다음으로 넘어가며, 문서를 기반으로 새로운 사람이 오더라도 기존 소스코드를 이해할 수 있다.
- 단점
각 단계를 겹치는 부분없이 깔끔하게 나눈 뒤, 하나의 단계를 마치고나면 이전 단계로 돌아가지 않기 때문에, 고객의 요구사항이 변경되었을 때 유연하게 대처하기 힘들다.
실제로 고객의 요구사항이 변하지 않는 경우는 거의 없다.
그냥 고객의 요구사항이 변하는 것은 개발자의 숙명이니 받아들여야 한다.
고객의 요구사항 뿐만 아니라 개발 플랫폼이 바뀌는 경우도 있다.
예를 들면 처음엔 윈도우 앱만 만들면 되었는데, 나중에 앱 버전까지 만들기를 요구하는 경우다.
- 사용 상황
waterfall 모델은 초기 단계에서 requirement 가 잘 이해될 때, 그리고 변화가 거의 일어나지 않을 때 사용하기 좋다.
사실 이런 경우는 거의 없지만, 그래도 예를 들어보면 금융회사의 서비스의 경우 시스템의 보안과 안정성이 매우 중요하다.
이 경우 요구사항이 계속 바뀌면 소프트웨어의 퀄리티가 떨어질 수 밖에 없다.
따라서 처음부터 요구사항을 철저히 분석해서 스펙이 변하지 않을 정도로 꼼꼼하게 만든 뒤에 다음 단계로 넘어간다.
Incremental Development
위에서도 적었듯 스펙을 increment 단위로 나눠서 개발하는 방법론이다.
이 방법론의 기본적인 아이디어는 다음과 같다.
1. 일단 초기 버전을 개발한다.
2. 유저한테 초기 버전을 공개한다.
3. 유저의 피드백을 받고 여러 버전을 거쳐 수정해나간다.
그래서 위 그림을 보면 outline description, 즉 완전한 description 이 아니라, 스펙에 대해서 개요 수준의 간단한 description 만 작성하고, 일단 그 description 에 대해 개발을 진행한다.
incremental development 의 예시로 throw-away prototyping 방식이 있다.
제대로 동작하는 완전한 버전이 아니라 어떻게 동작하는지 느낌만을 보여주는 프로토타입을 만들고 버린다.
이 방식의 목적은 requirement definition 을 더 발전시키기는 것이다.
처음에는 requirement에 대해 잘 이해하고 있지 못한 채로 시작하지만, 프로토타입을 구현하면서 점점 진짜 필요한 요구사항이 무엇인지 이해해나간다.
예를 들어 고객이 요구하는 UI 스펙이 '그냥 보기 좋고 쓰기 쉬운 것' 이라고 해보자.
이 말만 보면 어떤 것을 원하는지 그림이 안 그려진다.
사실 고객도 자신이 원하는 게 구체적으로 없는 상태인 것이다.
그냥 만들어진 결과를 놓고 봤더니 보기도 좋고 쓰기도 쉬우면 좋다는 것
그래서 이런 상황에서는 일단 프로토타입을 만들면서 고객이 원하는 것이 무엇인지 점점 찾아나가야 한다.
프로토타입을 만들고 고객이 이렇게 저렇게 바꿔달라고 하면 기존 프로토타입을 폐기하고 다시 수정한다.
이 과정을 반복하면 고객이 원하는 프로토타입이 점점 나올 것이고, 고객이 원하는 프로토타입이 나오면 그 프로토타입으로 개발한다.
- 장점
유저에 의해 specification 이 점점 더 명확해지고 발전되어간다.
- 단점
10개의 프로토타입을 만들어도 9개는 버려지고 최종본 하나만 남다보니, 결론적으로 9개의 프로토타입을 만든 시간은 버려지는 것과 같다.
즉, 하나의 최종본을 만들기까지 시간이 오래 걸린다.
그리고 유저 피드백을 받을 때마다 매번 스펙부터 다시 짜기는 현실적으로 어렵다보니 바로 코드로 들어가서 수정하는 경우가 많다.
따라서 소프트웨어의 수정이 반복될수록 소프트웨어 구조가 점점 나빠지는 경향이 있다. (기능을 추가하는 것은 어렵고 비용이 많이 드는 행위이기 때문이다.)
그리고 프로토타입을 만들고 버리기를 반복하다보니 소프트웨어가 개발된 그 히스토리를 명확히 이해하기가 힘들다는 단점이 있다.
- 사용 상황
이 방법은 사용자와 상호작용을 자주하는 작은 규모의 소프트웨어 개발에 적용하기 좋다.
예를 들어 게임같은 경우도 유저가 재밌어할 때까지 개발해야 하므로 사용자의 반응을 살피려면 이런 개발 방법이 적합할 수 있다.
그리고 큰 소프트웨어의 경우에도 요구사항이 잘 이해되지 않는 부분에 대해서 (보통은 UI 부분) 그 부분을 개발할 때도 적용할 수 있다.
즉, 꼭 작은 소프트웨어에만 사용할 수 있는 것은 아니다.
Integration and Configuration
이 방법은 기본적으로 소프트웨어 '재사용(reuse)' 기반의 접근 방법이다.
기존에 존재하는 어플리케이션이나 컴포넌트의 설정값만 조금 바꿔서 재사용 하는 것이다.
이 방법은 현재 많은 소프트웨어를 개발하는데 사용하는 일반적인 방법이다.
(오픈소스나 라이브러리를 사용하는 등등)
이때 '재사용하는 소프트웨어' 에도 여러 가지 종류가 있다.
- stand-alone application system
독립적으로 동작하는 소프트웨어에 약간에 수정을 가해서 우리 어플리케이션에서 사용하는 것 (합치는 것은 아니다)
ex) CRM software : 쇼핑몰에서 물건을 산 뒤, 빅데이터 분석을 통해 나와 비슷한 사람들이 많이 산 물건을 추천해주는 시스템이 존재할 수 있다. 또는 일본 호텔을 검색했더니 비슷한 항공편, 관광 정보를 계속 보여주기도 한다.
이처럼 고객에게 효과적으로 마케팅하기 위해 고객의 관심 정보를 저장하여 활용하는 프로그램을 CRM software 라고 한다.
이 프로그램은 단독적으로 이 기능만을 위해 개발이 되었고, 다양한 회사에서 이 프로그램을 가져다가 자기 회사 고객 정보를 넣어 사용한다.
(salseforce, Microsoft Dynamics 365 등)
- Collections of Object
해시맵, 스택, 연결리스트, 집합과 같은 자료구조를 매번 구현하는 것은 불편하다.
이렇게 자주 사용되는 자료구조들은 보통 프레임워크에 미리 구현된 컴포넌트로서 가져다가 사용한다.
그리고 이렇게 미리 작성된 소스코드를 가져다 사용하면 편리하기만 할 뿐만 아니라 여러 사람들이 검증해서 개발하였기 때문에 버그가 적고 더 안전하다는 장점도 있다.
Ex) Python PyPI, Java Spring framework
(자료구조로 설명해주셨는데 왜 스프링이 나오는지는 처음에 이해가 안됐다.
다만 Collecction of Object 분류가 소프트웨어를 '소스코드' 단위로 가져와서 사용하는 경우라고 생각하면 이해가 된다.
스프링도 객체지향 원칙을 지키면서 웹 개발을 할 수 있도록 도와주는 소스코드 덩아리기 때문이다.)
- Web Service
프로그램은 소스코드 형태가 아닌, 이미 배포되어있는 웹 서비스 형태로도 사용할 수 있다.
그리고 그때 그때 필요한 기능을 API 호출해서 (remote invocation) 사용한다.
예를 들어 결제 시스템도 이미 웹에서 잘 돌아가고 있는 것에 API 만 호출해서 사용하는 것들을 예시로 볼 수 있다.
Ex) 자바 rmi, REST, SOAP
이렇게 다양한 종류의 재사용 가능한 프로그램을 사용하여 개발하는 과정은 크게 위와 같이 나타낼 수 있다.
먼저 요구사항을 분석하고 어떤 기능을 재사용하여 구현할 지 결정한다. (requirement specification)
다음으로는 재사용할 소프트웨어를 찾고 (software discovery), 재사용하기에 적절한지 평가한다. (software evaluation)
어떤 재사용할 소프트웨어도 내 요구사항에 완벽하게 들어맞는 소프트웨어는 거의 없기 때문이다.
평가 결과 이 스펙에 맞게끔 사용할 수 있겠다 싶으면 사용하고, 아니다 싶으면 다시 요구사항 분석으로 돌아간다.
만약 그렇게 찾은 소프트웨어가 Application System 이라면 (위에서 말한 salesforce 같은 경우) 코드 레벨에서 우리가 할 수 있는 건 없기 때문에 그냥 완성된 어플리케이션을 가져다 사용하면 된다.
만약 컴포넌트로서 사용할 수 있는 요소라면 적용할 수 있는 부분은 가져와서 적용하고 (adapt components) 필요한 기능이 구현되어있지 않은 부분은 직접 개발해서 (develop new components) 우리 어플리케이션과 통합한다. (integrate system)
- 장점
완전 0에서부터 모든 것을 다 개발할 필요가 없기 때문에 전체적인 개발 분량이 줄어들어 '비용'과 '위험'을 줄일 수 있다.
(여러 사람들이 사용하고 있는 소프트웨어를 재사용하다보니 비교적 더 검증이 잘 되어있으므로 위험도 줄어든다.)
따라서 사용자에게 더 빠르게 소프트웨어를 만들어 제공할 수 있다. (delivery, deployment, release)
- 단점
기존 소프트웨어를 재사용하기 위해 사용자의 요구사항을 재사용하려는 소프트웨어에 맞춰 수정해야 할 수 있다.
결과적으로 시스템이 사용자의 진짜 모든 요구를 다 만족시켜주지 못한다.
또한 직접 어떻게 컨트롤할 수 없는 재사용 컴포넌트에 의존하기 때문에, 기존 소프트웨어를 발전시키는데 방해가 되기도 한다.
기존 기능을 발전시키려고 하는데, 다른 재사용 컴포넌트와 버전 충돌이 발생하는 경우가 대표적인 예시
지금까지 Software Process 의 개념과 3가지 기본적인 Software Process Model 에 대해 정리하였다.
간단하게 요약해보면
1. waterfall 모델
모든 요구사항을 다 파악하고 각 단계가 마무리 되어야만 다음 단계로 넘어가진다.
매 단계가 끝날 때마다 문서가 나오는 점은 좋지만 유연하지 못하다는 단점이 있다.
2. Incremental Development
모든 요구사항을 다 파악하고 increment 단위로 쪼개서 개발할 수도 있지만 (plan-driven)
보통은 요구사항을 간단하게 파악하고, 일단 초기버전을 만든 뒤 유저 피드백을 받아가면서 점점 개선해나가는 agile 방식으로 개발한다.
사용자와 상호작용이 잦은 규모가 작은 소프트웨어 뿐만 아니라 규모가 큰 소프트웨어에서도 상호작용이 잦은 UI 같은 부분만 이 방식으로 개발하기도 한다.
장점은 사용자도 잘 모르는 그들의 요구사항을 점점 명확하게 파악하면서 개발할 수 있지만, 매번 프로토타입을 만들고 버려가면서 개발하기 때문에 비용이 많이 들고, 수정이 반복될수록 소프트웨어 질이 떨어지며, 히스토리를 파악하기 힘들다는 단점이 있다.
3. Integration and Configuration
기존 소프트웨어를 가져다가 사용하여 개발하는 방식으로, 지금 대부분은 소프트웨어는 이렇게 개발한다.
기존 소프트웨어를 가져다가 사용할 때는 이미 완성된 어플리케이션을 가져다가 쓰거나, 소스코드 단위로 가져다가 쓰거나, 웹 서비스 단위로 가져다가 쓸 수 있다.
기존 소프트웨어가 특히 더 자주 가져다가 쓰이는 유명한 소프트웨어라면 더 안전하고 검증되어있기 때문에 비용 뿐만 아니라 위험도 줄일 수 있다는 장점이 있다.
하지만 내 소프트웨어에 새로운 기능을 추가하거나 수정할 때 재사용 컴포넌트와 충돌하여 새롭게 업그레이드를 못하는 문제가 발생하기도 한다.
다음 글에서는 소프트웨어 프로세스를 구성하는 각각의 Activity를 자세히 정리해본다.