변경 내역
-
2006.07.25 작성.
이 글은 월간 마이크로소프트웨어(일명 마소) 2006년 2월호 벅스라이프 칼럼에 기고한 글입니다. 물론 구성이나 내용 상의 차이가 있을 수 있습니다.
얼마 전 세미나에서 한 중견 개발자를 만나 개발 관련 이야기를 나누던 중 소프트웨어 개발의 경쟁력은 어디서 온다고 생각하느냐란 그의 질문에 답을 하지 못하고 우물쭈물했던 경험이 있다. 원고를 제의받고 과거에 저지른 실수나 그로부터 얻은 교훈에 대해 생각해 보던 중 연습장에 갈겨 쓴 메모를 몇 차례 살펴보니 나름대로의 대답을 얻은 것 같다.
소프트웨어 개발을 해나가다 보면 한 번쯤 더 이상 나빠질 것도 없다는 태도에 직면하게 된다. 일상에 찌든 나머지 새로운 무엇을 시도할 의욕이 없거나, 여러 차례 변화를 시도해봤지만 뜻대로 되지 않아 용기를 잃은 경우 등 수많은 이유를 핑계로 우리는 현재에 안주하려는 경향이 있다. 소프트웨어 개발을 업으로 살아가는 필자나 독자도 한번쯤은 이런 무기력감을 느껴본 적이 있을 것이다. 끝없이 발생하는 요구사항 변경, 프로그램 버그 때문에 지치기 일쑤다. 이런 무기력함이 자연스럽게 나을 리 없으니 하나씩 문제를 해결해 나가야 할 터다. 대부분의 독자들은 필자보다 훨씬 경력이 화려하겠지만 이 글 속에서 공감대를 얻기를 바란다.
눈덩이가 눈사태가 될 때
바로 최근의 일이다. 개발용 서버에 원격으로 접속해서 이런저런 작업을 하고 있었다. 그런데 느닷없이 창이 회색으로 변하면서 아무 것도 보이지 않게 됐다. 개발용 서버에 설치된 원격 접속 소프트웨어에 문제가 있어서 가끔 이런 일이 발생하곤 했다. 때문에 놀라지 않고 서버를 재부팅시켰다. 문제는 그 이후에 발생했다. 개발용 서버에 설치된 CruiseControl .NET이 오작동을 일으킨 것이다.
CruiseControl.NET이란?
CruiseControl.NET(http://cruisecontrol.sourceforge.net/)은 자바 오픈소스 프로젝트인 CruiseControl를 마이크로소프트 닷넷 프레임워크 프로젝트용으로 포팅한 Continuous Integration System이다. 간단히 말해 소스 버전 관리 시스템에서 변경된 소스코드를 가져와서 빌드, 단위 테스트 등을 한 다음 그 결과를 사용자에게 통보해주는 도구이다.
<화면 1> 프로젝트 빌드가 깨진 CruiseControl.NET
<화면 1>에서 보듯 첫 번째 프로젝트의 빌드 작업을 끝내지 못하고 있었다. 여기서 잠깐 첫 번째 프로젝트에 표시된 메시지를 주의 깊게 봐야 한다. 만약 필자가 메시지에 주의를 기울이고 다음 작업을 하기 전에 한 번 더 생각했더라면 이후에 발생할 ‘재앙’을 피할 수 있었을 것이다. 하지만 당시에는 처음 맞이하는 상황에 당황했었다. 우선 [관리도구 | 서비스]에서 CruiseControl.NET을 중지시키려 했다. 하지만 정상 종료가 되지 않았다는 에러 메시지가 떴다. 하는 수 없이 PsKill을 사용해서 CruiseControl.NET의 윈도우 서비스 프로세스를 강제 종료시켰다.
PsKill
PsKill은 Sysinternals가 제공하는 시스템 관리 도구인 PsTools에 포함된 도구 중 하나다. 일반적으로 윈도우 서비스 프로세스 등은 작업 관리자에서 프로세스를 종료시킬 수 없다. 이런 경우에 PsKill을 사용하면 프로세스를 끝낼 수 있다.
윈도우나 특정 소프트웨어가 난데없이 ‘맛이 갔다’면 사람들은 어떻게 반응할까? 대부분은 문제의 원인을 찾아보기보단 소프트웨어를 재설치 한다. 필자도 마찬가지였다. 프로젝트 설정 파일을 백업받고 [제어판 | 프로그램 추가/제거]에서 CruiseControl.NET을 삭제한 후 다시 설치했다. 백업받은 설정 파일을 [잘라내기 | 붙여넣기]했다. 하지만 새로 설치한 CruiseControl.NET은 오류를 발생시키고 작동하지 않았다. 이벤트 로그를 보니 해당 네트워크 포트를 다른 프로세스가 사용하고 있다는 메시지를 볼 수 있었다.
문제를 간단하게 해결하기 위해서 개발 서버를 재부팅시켰다. 만약을 위해 CruiseControl .NET을 제거하고 다시 설치했다. 바로 이 지점에서 ‘재앙’을 일으켰는데, 기존 프로젝트 설정 파일을 백업받지 않고 함께 지워버린 것이었다. 눈치 챘을 때는 이미 엎질러진 물이었고 복구할 방법은 전혀 없었다. 하는 수 없이 기본 설정 파일 내용 중 처음 두 개의 프로젝트 내용만 복구한 후 CruiseControl.NET을 콘솔 모드로 실행시켜 봤다. 콘솔 모드를 택한 것은 작업 과정을 실시간으로 모니터링하기 위함이었다. 이번에도 첫 번째 프로젝트에서 작동이 멈췄다.
결국 수백 줄의 설정 파일은 사라졌고 문제는 해결되지 않았다. 한편으론 허탈하고 다른 한편으론 화도 나서 바람을 쐬러 사무실 밖에 나갔다 돌아왔다. 처음부터 다시 시작하자는 마음으로 작업 로그에 기록된 처음 작업으로 돌아가서 <화면 1>을 보는 순간 깨달음을 얻었다(진리란 어찌나 단순한 것이던가). Activity 메시지를 보면 Checking Modifications라고 되어 있다. 다시 말해 소스 버전 관리 시스템 저장소가 깨진 것일 가능성이 높은 것이었다. 명령 창에서 저장소 복구 명령어(<리스트 1>)를 실행시키고 첫 번째 프로젝트를 빌드해 봤다. 역시나 불길한 빨간색 아이콘이 사라지고 그 자리에 안정감 있는 녹색 아이콘이 대신 들어섰다.
<리스트 1> 소스 버전 관리 시스템 복구
D:\>svnadmin recover D:\repository\first_project\ Repository lock acquired. Please wait; recovering the repository may take some time... Recovery completed. The latest repos revision is 34.
이 사건의 교훈은 간단하다. 트러블슈팅 시에는 무턱대고 여기저기 찔러보지 말고 가능한 많은 자료를 모은 후에 작업해야 한다는 것이다. 약간만 마음의 여유를 갖고 오류 메시지를 봤더라면 프로젝트 설정 파일을 지우는 만행(?)도 저지르지 않고 2시간이 아닌 10분 만에 시스템을 복구했을 터였다. 또한 문제가 발생한 시점에 바로 관련 자료를 백업하는 것도 중요하다. 이를 위해서는 중요 자료의 목록을 사전에 작성해 놓아야 함은 물론이다. 이번 경우에는 이 중 어느 것도 이뤄지지 않았다. 다만 작업 단계 초기부터 작업 일지를 작성한 것은 나름대로 적절했다고 생각한다.
갑과 을의 관계
사람에 따라 버그의 정의는 달라지는데 필자의 경우에는 프로젝트를 지연시킬 수 있는 모든 상황을 버그라고 부른다. 이에 따라 부정확한 요구사항, 잘못 추정된 일정 등을 모두 버그라고 생각한다. 그 중에서 가장 골치 아픈 것은 ‘갑과 을의 관계’라고 부르는 상황이다. 고객과 개발자 또는 개발에 참여하는 개발진 사이에 징검다리가 많으면 일이 꼬이기 마련이다. 필자의 회사까지 포함하여 총 5개 업체의 서비스가 연동돼야 하는 프로젝트가 있었는데 3개 업체는 프론트-엔드(Front-end) 서비스를 제공하고 필자의 회사가 최종 고객사에 부가가치를 더한 서비스를 제공하는 형태였다.
서비스 제공업체 3사는 모두 국제 표준을 자신의 서비스에 맞춰 변형했다. 그래서 표준 XML 스키마 파일을 구하면 작업이 수월해지리라 믿었다. 자바나 닷넷 등에서는 XSD 파일을 소스코드로 변환해주는 도구가 있었기 때문이었다. 그러나 필자의 믿음과 달리 상황은 악화되기만 했다. 무엇보다도 3사의 메시지 포맷 모두 XML 유효성 검사를 통과하지 못했다. 이를테면 메시지의 중요도를 나타내는 XML 요소 Priority에는 Normal, High, 또는 Low 값만 허용된다. 그러나 실제 메시지에는 NORMAL 값이 들어 있는 경우가 있었다. 아키텍처를 설계한 사람과 개발진과의 의사소통이 전혀 없었는지, 문서상의 스펙과 다르게 구현된 경우도 있었다. 예를 들어 문서는 MsgID가 필수요소이고 만약 MsgID가 메시지에 포함되어 있지 않으면 예외처리하도록 명시되어 있다. 그러나 실제 구현상에서는 MsgID를 전혀 보내주지 않았다.
<리스트 2> 올바른 메시지 예제
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <DeliverReq xmlns="http://tempurl.org/Spec"> <MsgID>msg_id</MsgID> <Priority>Normal</Priority> </DeliverReq> </soap:Body> </soap:Envelope>
<리스트 3> 실제 메시지 예제
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <DeliverReq xmlns="http://tempurl.org/Spec"> <Priority>Normal</Priority> </DeliverReq> </soap:Body> </soap:Envelope>
이런 경우는 명백히 서비스 제공업체의 잘못이다. 하지만 문제를 해결해야 하는 쪽은 필자나 이 글을 읽고 있는 독자일 수도 있다. 옳고 그름에 관계없이 힘을 쥐고 있는 ‘갑’의 입장에 따라 업무를 추진해야 하는 경우는 많다. 사실 필자는 입사 초기에도 이 프로젝트를 진행했었다. 그때는 업체 관계자에게 전화만 하다가 일정을 지연시켰고 여러 가지 문제가 추가로 발생하면서 프로젝트 자체가 취소됐었다. 이번에는 지난번 경험을 참고로 무사히 프로젝트를 마무리했는데, 그 ‘보잘 것 없는’ 노하우를 공개한다. 만약 ‘을’의 입장에 놓여있다면 다음의 권고가 도움이 될 것이다.
-
혼자 모든 것을 책임지려고 하지 않는다. 필자는 서비스 계약을 따온 영업 담당자에게 협조를 구했다. ‘갑’의 영업 및 기술 담당자의 연락처를 얻어내는 역할만이라도 해줄 원군이 있다면 중요한 업무, 즉 개발에 전념할 수 있다.
-
프로젝트 시작 전에 예상되는 리스크 목록을 작성한다. 형식에 얽매이지 말고 자연스럽게 쓰면 된다. 목록은 사고를 미연에 방지하고 일정을 조정하는데 쓰인다. 또한 관계자에게 목록을 전달하여 협조를 구하면 프로젝트 진행에 도움이 된다.
리스크 목록 샘플
개발자 연락처
이전에는 서비스 제공업체에서 개발자의 연락처를 알려주지 않으려 했다. 계속되는 요청 때문에 일을 할 수 없다는 개발자의 불만이 있었다고 한다. 하지만 개발자와 직접 대화할 필요가 있었고 결국에는 알려줬다. 작업시간 단축을 위해서는 미리 협의를 하여 개발자의 연락처를 받아내야 한다.
급히 확보해야 하는 문서
서비스 운영 시행 세칙, 연동 규격, 샘플, 연동테스트 방안 등
욕심도 적당히
개발자에겐 기술에 대한 욕심이 있다. 필자도 다르지 않아서 마틴 파울러(Martin Fowler)나 켄 핸더슨(Ken Henderson) 등의 블로그를 RSS 리더로 구독하거나, 파이썬 등과 같은 언어를 익히는데 시간을 투자하곤 한다. 하지만 기술에 대한 관심을 프로젝트에 지나치게 투영하면 득보다는 실이 많다. ‘두 번째 시스템 효과’를 한 번쯤 겪게 된다. 최초의 간결하고 성공적이었던 소프트웨어 후속 버전에 지나치게 많은 기능을 추가하려고 하는 바람에 프로젝트 전체가 좌초될 수 있다.
부끄럽게도 최근까지 필자는 욕심이 지나친 나머지 프로젝트 일정을 지연시켜서 상사로부터 질책을 받았었다. 기존 서버보다 성능 면에서 월등히 나은 프로그램을 짜야 하는 것이 필자에게 부여된 임무였다. 프로젝트 자체가 새로운 기술적 시도를 요구하는 것이기도 했다. 그래서 필자는 부담감 없이 생소한 기술을 시험해보기로 했다.
네트워크 프로그래밍은 ACE를 사용하고 임시 저장소 기술은 버클리(Berkeley) DB 등을 사용하기로 했다. 버클리 DB는 이미 사용해 본 적이 있어서 어느 정도 자신이 있었지만 ACE에는 문외한이나 다름없었다. ACE나 다른 기술을 테스트하는데 거의 일주일이 소요됐다. 게다가 본격적으로 개발 작업에 들어가서도 ‘산 넘어 산’이었다. 한 번은 클라이언트와의 접속이 끊길 때마다 10번에 1번 꼴로 세그멘테이션 오류가 발생했다. 하지만 익숙하지 않은 ACE 프레임워크를 사용한 터라 도무지 문제를 찾아낼 수 없었다. 천신만고 끝에 문제는 해결했지만 중간 성능 테스트를 해보니 예상한 것보다 훨씬 느렸다. C++로 개발한 서버 애플리케이션이 C#으로 짠 서버보다 한참 뒤떨어지는 성능밖에 못 보여주니 답답했다. 그렇게 시간은 흘렀다.
당초 명확한 기한이 없는, 주요 업무가 끝난 후에나 진행하는 프로젝트라 여유 있게 생각했다. 그러나 상황은 일순간에 달라져서 2주안에 가시적인 성과를 내놓아야 했다. 같이 작업하던 동료와 필자는 이 상태로는 기간 내에 완성할 수 없다는데 동의했다. 결국 필자가 웹 서비스로 서버를 구현하고 동료가 윈도우 클라이언트를 개발하기로 했다. 이미 웹 서비스 기술에는 익숙해 있던 터였고 멀티쓰레드 서버를 직접 구현하지 않아도 되니 개발기간을 단축할 수 있었다. 변경된 설계를 들고 상사에게 가니 불호령이 떨어질 수밖에 없었다. 그 동안 프로젝트에 투자한 시간과 노력을 생각하면 당연했다. 더욱이 처음부터 빨리 끝낼 수 있는 설계를 할 수 있었던 것 아니냐는 질책도 피할 수 없었다. 물론 처음 프로젝트를 시작할 때는 웹 서비스 기술에 확신이 없었기 때문에 일반적인 소켓 프로그래밍을 생각했던 것이지만 중간에 얼마든지 재검토할 수도 있었을 것이다.
다행스럽게도 변경된 설계로 정해진 기간에 개발을 완료할 수 있었다. 그러나 이 사건은 제법 쓴 교훈을 남겼다. 주요 프로젝트에 새로운 기술을 함부로 도입해서는 안 된다는 것이다. 물론 개발자는 자신이 가지고 놀 장난감이 있으면 더욱 의욕에 불탄다. 하지만 필자의 경우처럼 작업 공간을 장난감으로 채우는 실수를 범하지 않기 바란다.
윈도우를 다시 설치했더니
작년 여름이었던 것 같다. 1년여 동안 그럭저럭 버텨주던 윈도우의 상태가 좋지 않았다. 큰맘 먹고 하루 종일 열심히 윈도우와 작업용 소프트웨어를 다시 설치했다. 여기서 어떤 문제가 발생했는지 벌써 눈치 챈 독자도 있을 것이지만 소스코드 빌드가 되지 않았다. 문제의 원인은 제각각이었다. 필요한 어셈블리(닷넷에서의 DLL)가 어셈블리 캐시에 등록되지 않은 경우, 소스코드 디렉토리가 IIS에 응용 프로그램으로 등록되어 있지 않은 경우, 그리고 이제는 기억나지 않는 수많은 문제들이 타이타닉 호를 침몰시킨 빙산 마냥 난데없이 나타났다. 꼬박 하루 동안 문제를 모두 해결했지만 이런 생각이 들었다. 만약 필자가 퇴사하면 업무 인수인계를 받는 사람도 고생하게 되는 것은 아닐까? 인수를 받은 사람이 안 되겠다 싶으면 전화해서 물어볼 테니 필자 자신을 위해서라도 효과적인 방안이 필요했다.
이런 종류의 의존성 문제는 필자와 같이 윈도우를 재설치할 때만 나타나지는 않는다. 여러 사람이 함께 작업할 때는 더욱 신경 써야 하는데, 만약 한 개발자가 다른 개발진에 통보하지 않고 외부 컴포넌트를 설치해서 사용한다면 다른 개발자는 소스코드 빌드가 실패하는, 결코 기분 좋을 리 없는 화면을 보게 될 것이다. 이런 문제를 방지하기 위해 프로젝트에 참여하는 모든 PC 환경을 동일하게 만들고 외부 컴포넌트 사용을 제한하기도 한다.
필자는 다른 접근을 사용했다. 우선 여러 컴포넌트가 덕지덕지 설치되지 않은 컴퓨터를 구했다. ‘How to setup a .NET Development Tree Wrapup’을 참조해서 소스코드 트리를 다시 구성하고 빌드 자동화 스크립트를 작성했다. 그리고 앞서 언급한 Continuous Integration System을 구성했다. 이제는 새로운 의존성이 추가되었을 때, 즉각 CI 시스템으로부터 빌드가 깨졌음을 보고받는다. 업무 인수인계를 받을 사람이 윈도우부터 새로 설치한다고 하더라도 소스 버전 관리 시스템에서 소스코드를 다운받기만 하면 무사히 빌드가 될 것을 확신할 수 있다.
C++에서 C#으로
필자는 대학에서 주로 C++로 과제를 했다. 최근에는 거의 대부분의 교과 과정이 자바로 바뀌었다고 한다. 덕분에 필자가 처음 C#으로 프로그래밍 할 때는 예상치 못한 사태에 당황하기 일쑤였다. 그럴 때는 자신도 모르게 손톱을 깨물곤 했다. 덕분에 손톱 성할 날이 없었으니 정신적인 고통과 육체적인 고통을 동시에 받았다고 할 수 있다.
한 번은 이런 일이 있었다. 개발한 서버 애플리케이션이 클라이언트의 요청을 처리하는데, 주기적으로 메시지 포맷 에러가 발생했다. 하지만 필자가 테스트용으로 개발한 클라이언트와 통신할 때는 도무지 문제가 재현되지 않았다. 반나절을 테스트해도 원인은 모습을 드러내지 않았다. 이쯤 되자 필자는 “내 프로그램은 완벽해! 분명히 클라이언트를 개발한 업체가 문제일거야”라며 스스로에게 거짓말을 하게 됐다. 사실 프로토콜이 고객사 측에 공개되어 있어서 직접 클라이언트를 개발하는 업체도 있었다. 클라이언트의 소스코드를 보여 달라고 고객사에 요청할 수도 없는 노릇이고, 상용 서버에서 패킷 캡처를 할 수도 없으니 답답했다. 로그를 다시 살펴보는 수밖에 없다고 생각했다. 그런데 한참 동안 이벤트 로그를 쳐다보다가 이상한 점을 찾게 됐다.
<리스트 3> 이벤트 로그 예제
Timestamp: 2006-01-04 오전 10:29:12 Message: MSG FORMAT ERROR ------------------------------------------------- MsgType: Authentication Request TransactionID: this is a sample transaction id. - ID: userid Password: password
얼핏 보기에 <리스트 3>에는 문제가 없는 것 같아 보인다. 하지만 <리스트 4>의 소스코드와 로그를 다시 비교하면 눈에 잘 보이지 않는 이상한 점이 있다.
<리스트 3> 이벤트 로그 소스코드
StringBuilder sb = new StringBuilder(); sb.AppendFormat("TimeStamp: {0}\n",request.TimeStamp); …… 중략 sb.AppendFormat("TransactionID: {0}\n ",request.TransactionID); sb.AppendFormat("ID: {0}\n ",request.ID); sb.AppendFormat("Password: {0}\n ",request.Password);
이벤트 로그 6번째 줄의 ‘-’가 의심스러웠다. C++에서는 NULL이 문자열의 종료를 나타내지만 닷넷에서는 수많은 문자 중 하나로 취급되는 것이 원인이었다. 클라이언트가 <리스트 5>와 같은 문자열을 보내오면 닷넷의 System.String 인스턴스에는 “password”가 아닌 “password ?”로 표현됐다. 결국 <리스트 6>의 함수를 사용함으로써 이 버그는 해결됐다.
<리스트 7> NULL 종료 문자열 파싱
public static string ExtendedTrim(string source) { string dest = source; int index = dest.IndexOf('public static string ExtendedTrim(string source) { string dest = source; int index = dest.IndexOf('\0'); if( index > -1 ) { return source.Substring(0,index+1); } return dest; }'); if( index > -1 ) { return source.Substring(0,index+1); } return dest; }
새로운 기술을 익히는 과정에서 발생하는 버그에 대해서는 뚜렷한 해결책이 없는 것 같다. 평소 여가시간의 일부를 할애해서 꾸준히 공부하고 시행착오를 겪으면서 문제 해결 능력이 키워지는 것 같다. 그런 의미에서 필자도 아직 풋내기일 것이다. 다만 문제를 해결한 후에 미래의 후임자가 똑같은 문제에 봉착하지 않도록 주요 사항을 문서 형태로 정리하는 것은 누구라도 할 수 있는 일이라고 생각한다. 필자는 여기서 언급한 문제에 대해 ‘닷넷 프레임워크 기반의 소켓 프로그래밍 가이드’라는 문서로 정리한 바 있다. 혹시라도 관심 있는 독자는 참고 문헌을 참조하면 되겠다.
문서는 있는데
일전에 한 업체의 내부 시스템을 수정해야 할 일이 발생했다. 필자가 입사하기 1년 전쯤에 개발된 시스템으로 클라이언트와 서버 어플리케이션을 모두 합쳐서 10여개 정도 되는 규모였는데, 내부 망을 이전한 후 어플리케이션 일부가 작동하지 않는다고 했다.
개발에 참여한 사람들은 퇴사한 탓에 문서밖에 믿을 것이 없었다. 하지만 문서를 어디서부터 읽어야 할지 알 수가 없었다. 데이터베이스나 소켓 통신과 관련된 부분을 수정해야 함은 분명했지만, 정확히 무엇을 고쳐야 하는지 알 수 없었다. 결국 소스 코드를 이 잡듯이 뒤져서 관련 코드를 수정했고, 이제는 테스트를 해볼 차례였다.
불행히도 필자 회사에는 테스트할 수 있는 환경이 없었다. 전임자가 데이터베이스 스키마를 남겨놓기는 했지만, 각 레코드 값이 무엇을 의미하는지는 문서는 말해주지 않았다. 결국 고객사측에 전화해서 혹시 관련문서를 받은 적이 있는지 묻는 수밖에 없었다. 개발사가 고객사측에 문서를 요청하는 웃지 못 할 사태였다. 다행히 문서를 받을 수 있었고, 덕분에 어떻게든 주어진 업무를 끝낼 수 있었다.
로버트 L. 글래스는 사실 일반적인 소프트웨어 프로젝트에서 산출물 목록을 보면, 유지보수 문서화는 목록에 있지도 않고, 설계서와 같은 생명주기 초기 문서에 대한 업데이트 계획도 없음을 볼 수 있을 것이다.
(7)라고 했다. 이런 일이 소프트웨어 업계에서는 흔하다는 의미로 받아들여도 될 것이다. 개발 과정에서 발생하는 버그는 유지보수에서 발생하는 그것에 비하면, 유치하다고 할 정도다. 특히 개발자와 유지보수하는 사람이 다를 때는 더욱 그런데, 유지보수를 하는 사람이 소프트웨어의 구조를 숙지하지 못하고 있기 때문이다. 그런 측면에서 유지보수에 적합한 문서를 작성할 필요가 있는데, 이때 필자는 다음과 같은 사항에 특히 신경 쓴다.
-
관련자 연락처
-
자주 발생하는 사고 또는 문의에 대한 목록과 대응방법.
-
이전 유지보수 작업에 대한 작업일지 (후임자에겐 생소한 내용일 수 있다.)
글을 마치며
필자도 한때는 마우스 클릭만으로 멋진 소프트웨어를 만드는 미래를 꿈꾼 적이 있었다. 실상은 무척이나 달라서 은 탄환은 공포영화에나 등장하는 구세주인 것 같다. 하지만 시행착오를 거듭하더라도 그때마다 한 가지 교훈을 얻는다면 문제를 한방에 해결해주지는 못하더라도 많은 도움을 줄 것이라 생각한다.
참고 문헌
-
The Mythical Man-Month, Frederick P. Brooks
-
How to setup a .NET Development Tree Wrapup
-
소프트웨어 공학의 사실과 오해, 로버트 L. 글래스