반응형

소프트웨어 개발 프로젝트뿐만 아니라, 지금 하고 있는 일의 의미와 목적에 대해 생각해 본적이 있는가? 모든 일에는 그 목적을 위해 제때 적절한 사람이 해야 할 일이 있게 마련이다.

시점의 변화

일을 하다 보면 본래 목적과 의미를 잊어버린 채 전혀 엉뚱한 이슈에 많은 시간을 낭비하는 경우가 많다(원래 목적과는 상관없는 이슈로 몇 시간씩 회의해 본 일이 있다면 쉽게 이해할 수 있지 않을까?).

지금 무엇을 하고 있는가?
소프트웨어 프로젝트의 실패 원인 중 대부분은 ‘무엇을 왜 만들고 있는가’라는 고객의 요구사항을 제대로 파악하지 못하는 데 있다. 오픈을 얼마 남기지 않은 프로젝트 중반에 고객의 수정사항은 늘어가고, 고객들은 기능적인 면보다는 화면 디자인(색이나 폰트 사이즈 등)에 더 민감한 모습을 나타낸다. 또한 대부분의 고객은 자신이 원하는 바가 무엇인지를 제대로 알지 못하지만, 고객 자신이 좋아하고 좋아하지 않는 것에 대해서는 정확하게 알고 있다.

성공적인 프로젝트를 위해서는 가장 먼저 고객의 요구사항을 적절하게 파악하는 것이 중요하다. UML 유스 케이스 다이어그램(Use Case Diagram)이나 스토리보드 등이 매우 효율적으로 사용될 수 있으며 간단한 HTML이나 RIA(FLEX etc), 혹은 4GL(VB)로 만든 기능이 없는 스토리 위주의 샘플 애플리케이션은 고객의 요구사항을 수집하는 데 매우 좋은 도구가 될 수 있다. 복잡한 비즈니스 프로세스가 있는 업무의 경우에는 BPA 등의 도구를 사용해 워크플로우를 시각화시켜 두면 복잡한 흐름을 일목요연하게 정리할 수 있다.

이런 도구들로 수집한 요구사항에 대해 고객으로부터 확인을 받아 놓는다면(회의록에 대한 싸인이나 위의 산출물에 대한 고객 확인을 받아 놓는 것) 그 요구사항에 따라 스케줄된 일정에 새로운 변경이 이뤄졌을 경우에 합당한 개발 비용과 시간을 요구할 수 있을 것이다. 이처럼 소프트웨어 개발 프로젝트는 고객의 요구사항만 제대로 파악하고 있어도 80%는 성공한 것이다.

● TAG : 요구사항 분석, Use Case Diagram, sample software, 복잡한 비즈니스 프로세스, 워크플로우, BPA


닭 잡는데 소 잡는 칼 사용하기
모든 기술 역시 그 태생에 목적과 이유를 가지고 있다. 소프트웨어 개발에서 중요한 점 중에 하나가 현재 소프트웨어 개발 규모와 요구사항에 맞게 적절한 기술을 사용하는 것이다. 일반적으로 개발자들은 기술적인 호기심으로 인해 신기술 도입에 대한 욕심이 많다. 또한 매니저는 매니저 나름대로 신기술을 적용한 시스템이라는 ‘업적’을 원한다.

그러나 그런 기술들은 그만큼의 습득 시간과 비용을 요구한다. 예를 들어 몇 년 전 EJB 붐이 일었을 때, 많은 사이트들이 값비싼 WAS를 도입해 개발한 적이 있다. EJB는 분산 컴포넌트와 트랜잭션의 보장이 가장 큰 장점이다. 하지만 정작 이런 사이트들에서 그런 고차원적인 트랜잭션 처리가 필요한 경우는 실제 얼마나 있었을까? 그 당시 많은 사이트들이 고가의 WAS를 도입했음에도 불구하고 WAS를 단순한 JSP/Servlet 컨테이너 수준으로 밖에 사용하지 못했거나, EJB 역시 단순한 POJO식의 Business Object 이상으로 사용하지 못한 경우를 많이 봤다.

요즘처럼 JSTL, WebWork, Struts, Spring, Mapper, AOP 등과 같은 각종 오픈소스 프레임워크와 새로운 개념들이 난무하는 세상에서, 자칫하면 신기술에 대한 욕심으로 무리한 선택을 할 수도 있다. 프레임워크와 기술은 도구일 뿐이다. 아무리 좋은 도구라도 사용법을 제대로 알지 못한다면, 이런 도구들은 오히려 소프트웨어 프로젝트에 해가 될 수 있다.

그러나 한 번 더 생각해 보자. 소프트웨어 개발을 위해서는 시스템 기능과 요구사항에 적합한 적절하고 사용하기 쉬운 기술이 선택되어야 하며, 기술을 도입하는 데는 그만한 도입에 대한 비용(구입 비용뿐만 아니라 교육 및 습득에 대한 비용)이 고려되어야 한다.

● TAG : 오픈소스, 개발자와 매니저의 욕심, 도구는 도구일 뿐, 적절한 도구 사용하기

Simple is best! Easy is best!
모든 기계가 그렇듯이 복잡한 기계일수록 고장이 잘 난다. 소프트웨어도 마찬가지다. 복잡한 아키텍처일수록 문제가 생겼을 경우에 디버깅하기가 어렵고, 변경 사항이 생겼을 때 반영하기가 어렵다. 디자인 패턴으로 무장한 컨설턴트가 와서 시스템을 온통 디자인 패턴으로 도배해 놓을 수도 있다. 그렇지만 그것을 디버깅해야 하는 것은 그 컨설턴트가 아니라 개발자 여러분이다(디자인 패턴이 나쁘다는 것은 아니다. 불필요한 패턴 사용으로 시스템의 복잡도를 올리는 것에 대한 일종의 경고인 셈이다).
가능하면 시스템은 간단하게 설계하자. 고수가 설계한 시스템일수록 단순하고 고장이 적다.

좋은 기술이나 개념은 천재의 머릿속에서 나올 수 있다. 그러나 그것을 실제로 사용하는 사람은 천재가 아니라 평범한 사람들이다. 천재들의 수준에 맞춰 개발된 기술들을 과연 범인들이 쉽게 사용할 수 있을까? 인기 있게 널리 오래 사용되는 기술은 대부분 개념을 이해하기 쉽고 사용하기 쉬운 기술이다. 고수들이 만들어내는 각종 이론들로 무장한 시스템들이 아니라 오히려 이해하기 쉬운 시스템인 것이다.
 
● TAG : 간단할수록 튼튼하다. 쉬운 기술이 널리 퍼진다.

깊게 그리고 넓게
기술을 깊게 공부해야 하는 것은 당연한 이야기이지만, 지식의 깊이와 폭에 대한 균형이 필요하다. 예를 들어 소켓(Socket) 프로그래밍을 할 때, 자바의 경우 Multiplexing 성능이 떨어지기 때문에 C 언어로 MultiPlexer를 구현하고 JNI로 연결하면 훨씬 더 좋은 성능을 낼 수 있다.

화면이 많고 권한 처리가 복잡한 엔터프라이즈 솔루션의 경우에는 엔터프라이즈 포털(Enterprise Portal)과 같은 솔루션을 선택하면 시행착오를 줄이면서 양질의 소프트웨어를 만들어 낼 수 있다. SAP와 CRM 등을 통합할 때 모두가 자신이 강점을 지닌 언어로 개발할 수 있지만, 그보다 EAI 솔루션을 사용한다면 쉽고 성능 좋은 시스템 통합을 이끌어 낼 수 있다. 어느 정도 수준의 개발자라면 고객의 요구사항을 구현하는 것은 그다지 어려운 일은 아닐 것이다. 

그러나 이미 구현되어 있는 솔루션이나 오픈소스 아키텍처에 대한 지식이 있다면 처음부터 구현하는 게 아니라 그것들을 활용함으로써 주어진 시간과 비용 내에서 시행착오를 줄이고 양질의 소프트웨어를 만들어 낼 수 있다.

● TAG : 이미 있는 것들 찾아보기, 활용하기, 폭넓은 지식 가지기

마일스톤
마일스톤이란 ‘이정표’를 의미하는 것으로 프로젝트 일정 가운데 중요시점으로 생각하면 된다. 예를 들어 요구사항 분석 완료 시점, 각각 컴포넌트 완성 시점, 릴리즈 시점, 알파, 베타 테스트 시기 등이 이에 속한다.

마일스톤을 설정하는 이유는 마일스톤 전의 작업에 대한 검증을 통해 발생한 문제를 다음 단계까지 전파시키지 않기 위함이며, 요즘의 개발 방법론들이 잦은 Release와 Feed Back 등을 강조하는 것 역시 잦은 마일스톤을 설정함으로써 문제를 가능한 한 빨리 발견하고 풀어내기 위함이다(불확실성의 제거).

마일스톤이 설정된 주기는 그 각각이 전체 프로젝트에 대한 미니 프로젝트가 되며, 각 마일스톤 시 필요한 최소한의 산출물에 대한 정리와 검증(확인을 통한 문제 발견)이 뒤따라야 한다. 정확한 마일스톤을 설정한다면, 소프트웨어 개발 프로젝트에서 발생할 수 있는 위험 요소를 줄이는 데 큰 도움이 될 것이다.

나만의 도구를 갖추자
소프트웨어 개발에 있어서 IDE나 디버거(Debugger)와 같은 툴은 생산성에 지대한 영향을 준다. 개발자라면 적어도 자기가 가지고 다니는 도구 세트 하나는 있어야 하지 않을까? 여기서는 이미 많이 알려진 IDE나 디버깅(Debugging) 툴보다 소프트웨어 프로젝트에 필요한 각종 자동화 도구에 대해 간략하게 소개한다.

소스 관리
일주일 전에는 잘 돌아가던 모듈인데 일주일 동안의 작업 내용이 반영된 후에는 뭔가 문제가 생겼다. 어떻게 해야 할까? 어느 부분을 수정했는지 알 수 있다면 좀 더 빨리 문제의 원인을 밝혀낼 수 있지 않을까?

운영 중인 시스템이 새로운 코드를 반영한 후에 문제가 생겼다. 수정한 부분을 찾는 것보다 이전의 소스 코드로 원상 복귀하는 것이 운영을 정상화하는 데 더 빠르다. 그렇다면 예전에 개발한 소스는 어디에 있을까?

고객별로 릴리즈한 버전이 많은데 A 고객의 이슈를 해결한 버전은 도대체 어느 버전일까? 여러 사람이 협업 작업을 한다면 공통으로 소스 코드는 어떻게 관리해야 할 것인가? 소스를 한 곳에서 중앙 집중적으로 관리하고 협업을 가능하게 해주며 소스에 대한 변경 내역을 관리할 수 있게 해주는 것이 바로 소스 관리 시스템이다. 널리 사용되고 있는 무료 소스 관리 시스템에는 CVS와 SubVersion이 있다.

● TAG : 소스 관리, CVS, SubVersion
빌드 도구
빌드는 소프트웨어 개발에서 항상 수행해야 하는 작업이다(물론 JSP나 ASP 등의 스크립트 언어로만 개발한다면 모르겠지만). 컴파일하고 기다리고 결과가 나오면 검증하고 에러가 없으면 릴리즈(또는 배포)하고 항상 해야 하는 반복적인 작업이다.
에러가 발생하지 않는 상황이라면 특별하게 할 일도 없다. 우리가 빌드를 기다리는 것은 혹시나 있을지 모르는 에러에 대비하기 위한 것일 뿐 빌드와 배포는 커맨드들을 반복해 입력하는 단순 작업에 해당한다.

이런 단순 작업을 내가 아닌 누군가가 해준다면 그 시간에 코드를 최적화하거나 좋은 소프트웨어 구조로 리펙토링하는 등의 생산적인 작업을 할 수 있지 않을까? 그 누군가가 바로, 빌드 자동화이다. 기본적인 도구로는 make, ant, maven과 같이 커맨드들을 조합해 빌드해 주는 도구가 있고, 여기에 Daily Build (Daily Build의 중요성은 여기서 언급하지 않더라도 『조엘 온 소프트웨어』와 같은 유수의 개발 관련 서적에서 이미 충분히 언급되어 있다)나 스케줄에 따른 빌드나 Release 버전 생성을 자동으로 수행해 주는 빌드 자동화 소프트웨어가 있다. 이러한 소프트웨어들은 빌드 배포에 대한 스케줄링뿐만 아니라, 자동화된 릴리즈 버전 생성 등이 가능하고 빌드 중의 에러에 대해 담당자에게 SMS나 이메일 등으로 ALERT해 주는 기능을 가지고 있으므로, 대규모 협업 프로젝트에서 매우 유용하게 사용될 수 있다.

대표적인 공개 소프트웨어로는 Cruise Control, Ant Hill 등이 있다. Cruise Control은 Text 기반의 도구로 매우 강력한 빌드 자동화 기능을 제공하지만 Text 기반이기 때문에 다소 사용하기가 어렵다. Ant hill의 경우에는 Web UI를 제공하기 때문에 상대적으로 사용하기는 쉽지만 대신 Cruise Control과 같은 강력한 기능을 제공하기는 어렵다. 그리고 빌드 과정 중에 빌드된 컴포넌트가 제대로 작동하는지 여부를 자동으로 테스트하기 위해 JUnit과 같은 테스트 프레임워크가 있다. 빌드 자동화는 ant와 같은 빌드 도구, JUnit과 같은 테스트 도구, 그리고 Cruise Control 등과 같은 빌드 자동화 도구로 구성되고, 빌드와 릴리즈(배포)를 수행함으로써 시간 절약은 물론, 품질에 대한 향상까지 기대할 수 있다.

● TAG : ant, maven, cruise control, anthill, JUnit

테스트 도구
테스트와 QA(Quality Assurance)에 대한 중요성은 언급하지 않더라도 이미 잘 인식하고 있으리라 믿는다. 테스트의 종류에는 컴포넌트별 단위 테스트, 시나리오에 따른 기능 테스트, 적절한 용량을 커버하고 성능을 낼 수 있는지를 검증하는 부하 테스트, 그리고 장애에 대한 대처 능력을 시험하는 장애 테스트 등이 있다.
그 중에서 테스트팀이나 QA팀이 아닌 개발자들이 일반적으로 수행할 수 있는 테스트로는 컴포넌트별 단위 테스트와 부하 테스트를 꼽을 수 있다. 단위 테스트는 소프트웨어 개발 주기 중 테스트 단계에서뿐만이 아니라 개발단계 중간에서도 컴포넌트가 제작될 때마다 모듈의 기능을 검증해 버그를 예방할 수 있다.

단위 테스트는 JUnit 등의 단위 테스트를 자동화할 수 있으며, 위에서 설명한 것처럼 빌드 절차에 자동화해 포함시켜 빌드 때마다 개발한 컴포넌트 기능의 이상 여부를 검증할 수 있다. 부하 테스트는 소프트웨어의 비기능적인 요소인 성능이나 용량을 측정하는 데 사용되는데 개발자 단계의 부하 테스트를 통해 알고리즘의 최적화 여부나 과부하시에 장애(Dead Lock, Lock 대기 현상, CPU 과점유)를 검증할 수 있다.
 

● TAG : 단위 테스트, 기능 테스트, 성능 테스트, JUnit, MS Stress, JMeter, Load Runner

커뮤니케이션 도구
팀원 간의 작업 배분, 이슈에 대한 기술적인 토론, 고객의 변경된 요구사항의 반영 내용, 그리고 버그에 대한 이슈 등을 해결해 나가는 것이 개발이라고 할 수 있다. 보통 이런 이슈들은 회의나 이메일, 전화 등을 통해 이뤄지는데, 각각의 이슈에 대해 서로 이야기한 내용과 협의한 내용들에 대해 문서화해 추후에 이슈에 대해 어떻게 대처를 하고 소프트웨어 코드에 반영을 했는지를 추적해야 할 경우가 있다.

이런 이슈에 대한 추적과 커뮤니케이션을 가능하게 해주는 것이 Issue Tracking 시스템이다. 이슈를 오픈하고 관련된 사람을 추가하며 이슈에 대한 진행 상황과 중요도를 기입함으로써 현재 시스템에 대한 이슈에는 어떤 것이 있는지 알려주고, 진행되고 있는 상태를 쉽게 관리할 수 있게 해준다.

해당 이슈가 반영된 버전을 기입해 어느 버전에 문제가 있고 해결되었는지를 판단하게 함으로써 적절한 Release 버전을 판단할 수 있게 한다. 그리고 이슈가 해결되었을 때는 SubVersion과 같은 소스 관리 시스템에서 이슈를 해결한 Revision Number를 Issue Tracking 시스템에 기입해 이슈를 어떤 식으로 소스 코드에 반영했는지를 추적할 수 있게 한다. 주로 버그 관리에 많이 사용되는데, 그 외의 개발 요구사항을 반영하는 데도 응용할 수 있다. 대표적인 소프트웨어로는 BugZilla나 JIRA와 같은 소프트웨어를 들 수 있다.


● TAG : Issue Tracking System, Bugzilla, JIRA

튼튼한 소프트웨어를 만드는 관점 갖추기
마지막으로 실제 개발을 할 때 생각해야 할 것 몇 가지만을 짚고 넘어가도록 하자.

개발자는 메모리로부터 자유로울 수 없다.
자바 언어가 나오면서 개발자들은 malloc과 free(C 언어에서 메모리를 할당하는 함수)로부터 자유로워졌다. Garbage Collector라는 강력한 기능이 자동으로 메모리를 관리해 준다. 그렇다면 진정 우린 메모리에서 자유로울 수 있을까?

32비트 머신을 가정했을 때, 32비트 머신의 프로세스당 메모리 사용량은 2^32=4G이다. 여기서 유닉스의 경우는 이 가운데 2GB가 공유 메모리 영역이고 실제 자바가 사용할 수 있는 것은 2GB이다. 이 중에서 클래스(Class)나 메소드(Method)가 올라가는 Perm 영역이 대략 64~256MB이고, JVM 자체가 로딩되는 메모리 영역을 다 합하면 실제로 자바 애플리케이션의 Heap Size는 최대 1.5~1.7GB 내외이다.

그 영역 안에서도 애플리케이션이 기본적으로 꾸준히 사용되는 영역이 400~500MB라면, 일반적으로 1GB 내에서 프로그래밍을 해야 한다는 이야기다.
물론 64비트 JVM이 출시되고 GC의 성능이 좋아지면서 메모리에 대한 부담이 줄어드는 것은 사실이지만, 소프트웨어를 개발한다면 항상 메모리 사용에 대해 충분히 고려하고 시스템을 설계해야 한다.

● TAG : 메모리 신경 쓰기

성능에 대해 고민하기
성능에 대해 개발자들만큼 민감한 사람들이 또 있을까? 그렇지만 그들이 작성한 코드는 정말 최적의 성능을 낼 수 있도록 구현되어 있을까? 직접 작성한 코드를 한 두명의 유저 기반에서 테스트했을 때는 잘 돌아간다. 그렇지만 실제 환경이 여러 명의 동시 접속자를 지원하는 서비스라면? SQL 문장이나 잘못된 Synchronized 처리 등은 실제 환경이나 동시 사용자가 많지 않으면 성능에 영향을 주지 않는다.

성능에 대한 좋은 가이드와 프로그래밍 방법은 항상 고민해야 하는 문제이고, 여기에 성능에 대한 검증을 어떻게 할 것인지를 고려해 코드를 만들어야 할 것이다.
컴포넌트별로 테스트시에 Profiler나 APM-Application Performance Management Tool 등을 이용하면 도움이 되고 간단한 부하 테스트를 더한다면 성능 상에 문제가 있는 코드가 아닌지 좀 더 쉽게 검증할 수 있다. 물론 어느 정도 경험이 쌓인다면 이런 도구 없이도 코딩 시에 성능에 문제가 되는 코드의 대부분은 걸러낼 수 있을 것이다.


● TAG : 성능 고려하기, 성능 테스트, Profiler, APM
로깅 습관화
결함(Defect)이 없는 소프트웨어는 있을지 몰라도 문제(Bug)가 없는 소프트웨어는 존재하지 않는다. 그러므로 문제가 있을 때 어떻게 빨리 발견해 해결할 것인지가 중요하다. 그런 방법 중의 하나가 디버깅을 위한 로깅(LOGGING) 처리이다. 로깅은 장애나 문제가 없을 때는 그다지 소용 없는 코드이고 시간 낭비처럼 보일 수 있지만 잘 구현된 로그인(LOGGIN)은 문제 해결 시간을 줄이는 데 큰 도움을 준다. 그렇다고 로깅이 범람해서는 안 된다. 로그(LOG) 메시지도 비즈니스 로직처럼 설계가 필요하다. 적절한 로깅 설계와 반영에 대해 습관을 들이도록 하자.

● TAG : Logging, Debugging

+ Recent posts