[자바 프로젝트 성공 노하우] ② 성패를 가르는 핵심 요인

일반입력 :2004/10/27 15:00

옥상훈

본론에 들어가기 전에 프로젝트와 관련된 계절 이야기를 하겠다. 여름의 최고조인 8월은 휴가철인 데다가 지난 7월부터 시행된 주 5일제 덕분에 더욱 들뜨는 달이다. 하지만 중대형 SI 프로젝트의 경우 대부분 연초에 시작하기 때문에 이때 즈음이면 개발에 한창 열을 올릴 때라서 들뜬 기분을 만끽하기에는 부담스러운 달에 해당한다. 그래서 이맘때면 개발자들이 대거 프로젝트에 투입되어 사람 수만큼의 열기에 CPU의 열기가 더해서 무척 더위에 시달리는 달이다.

그러나 프로젝트에 있어 여름의 땀은 가을에 프로젝트의 성공이라는 열매를 영글게 해주는 원천이다. 필자도 매년 여름에는 여유롭게 보내기보다 엄청난 코딩을 하면서 땀 흘린 기억이 많다. 그래서 봄은 설계자가 바쁘고 여름은 개발자가 바쁜 계절이다(물론 프로젝트 상태에 따라서 가을, 겨울 그리고 이듬해 봄까지 계속 바쁠 수도 있다). 그럼 본론으로 들어가 프로젝트를 성공적으로 이끄는 방안을 살펴보자.

프로젝트의 성공과 실패를 가르는 요인

프로젝트의 성공과 실패는 여러 측면에서 파악될 수 있다. 이는 프로젝트의 특정 부분은 성공적으로 수행됐지만 다른 부분에서는 실패로 볼 수도 있다는 것이다. 예를 들면 고객이 원하는 모습의 시스템은 구축했으나 기한을 넘겨 비용이 많이 지출돼 손해를 남기는 경우나 고객과의 돈독한 관계 유지를 통해서 시스템을 축소해서 개발을 마무리짓는 등의 경우가 있을 수 있다. 이는 부분적인 측면에서 프로젝트의 성패를 가늠하는 것이고 결국에는 그 요소 중에 비중 있는 것이 프로젝트 성패의 이미지를 만들어준다. 그래서 이러한 프로젝트 성패에 영향을 주는 요소를 먼저 파악하고, 이를 토대로 프로젝트의 성패를 판단할 수 있는 지표를 알아보자.

프로젝트 구성의 3요소, 프로젝트의 리소스

프로젝트 구성의 3요소는 프로젝트를 하기 위해 가장 기초적으로 갖춰야 할 것들이다. 이는 <그림 1>과 같이 소프트웨어, 하드웨어, 그리고 인력이다. 이는 곧 프로젝트에서 가용할 수 있는 리소스에 해당한다. 리소스에 해당한다는 것은 이것들이 ‘돈’이 들어간다는 것을 의미하고, 따라서 리소스를 잘 관리한다는 것은 최소 비용 대비 최대 효과를 낼 수 있는 프로젝트의 원동력이 된다. 그래서 소프트웨어, 하드웨어 및 인력의 동그라미가 만나는 지점은 무형의 관리 요소로 프로젝트 관리자의 역할, 하드웨어/소프트웨어 관리자의 역할로 볼 수 있다.

프로젝트 문제는 리소스로부터 시작

모든 일에서 발생하는 문제에는 원인이 있으며, 그 원인은 그 일을 만든 구성요소 및 구성요소간의 상호작용에 있기 마련이다. SI 프로젝트도 프로젝트 진행에 있어 발생하는 문제는 그 구성요소에 있다. 그 구성요소라 함은 앞에서 얘기한 프로젝트 구성의 요소들로 문제가 그 구성요소 자체인 경우와 구성요소간의 부조화로 발생하는 경우이다.

<그림 1>에서는 프로젝트의 각 리소스를 같은 크기로 그려놓았다. 그러나 실제 프로젝트에서는 어떤 요소는 비대하고 어떤 요소는 상대적으로 협소한 모양을 띄기도 한다. <그림 2>에 이를 나타내봤다. <그림 2>를 보면 하드웨어 부문, 소프트웨어 부문, 인력 순으로 리소스의 크기가 적어지는데, 이렇게 되면 인력 리소스가 하드웨어, 소프트웨어 부문에 비해 상대적으로 부족하기 때문에 관리 및 업무 증가 등에 따른 문제가 발생한다. 물론 <그림 1>과 같이 모든 리소스가 균등한 크기가 되어야 조화롭다는 것은 아니다.

개발자 입장에서는 성능이 뛰어난 하드웨어와 소프트웨어에 충분히 많은 개발자들이 넉넉한 시간을 갖고 프로젝트에 참여하고 싶은 꿈이 있다. 그러나 보통 하드웨어, 소프트웨어가 도입된 후에 개발자들이 본격적으로 투입되기 때문에 인력 리소스가 그리 충분하지 않은 상태에서 개발에 착수하게 되는 경우가 현실이다. 그래서 이러한 것들이 결국에는 문제를 일으켜서 프로젝트에 중대한 영향을 미치게 된다.

프로젝트 리소스로부터 시스템 문제 파악하기

프로젝트의 리소스들이 일으키는 문제는 사람이 자동차를 다루는 것에 비유될 수 있다. 즉 자동차 자체가 결함이 있으면 심각한 문제가 된다는 것이 첫 번째 이유이다. 그리고 자동차가 결함이 없고 뛰어난 성능을 가졌다 하더라도 운전을 능숙하게 하지 못해 사고가 나는 문제가 두 번째 이유이다. 마지막으로 운전은 잘하지만 자동차 관리를 잘못해서 제 성능을 내지 못하는 경우이다. 그래서 프로젝트 리소스로부터의 문제를 파악하는 관점은 다음의 세 가지로 볼 수 있다.

[1] 프로젝트 리소스 자체로 문제가 없는가?

[2] 프로젝트 리소스 활용 기술에 문제가 없는가?

[3] 프로젝트 리소스 관리에 문제가 없는가?

프로젝트 관리자 입장에서는 리소스 관리를 중심으로 문제점을 파악할 것이고, 개발자들의 입장에서는 리소스 자체 문제와 리소스 활용 기술에 관한 문제, 즉 시스템적인 문제를 파악하려 할 것이다. 이러한 문제 중 관리적인 문제는 인적인 요소이므로 시스템적인 문제와는 별개로 다루겠다. 우선 시스템적인 문제를 파악하는 방법을 알아보자.

HW 문제인지 SW 문제인지 파악하라

이런 질문을 받으면 어떤 독자는 간단한 거 아니냐고 말할지도 모른다. 간단하게 볼 수 있는 경우는 소프트웨어나 하드웨어의 안정성이 100%로 확실한 경우인데, 실제 프로젝트에서는 그렇게 100% 확신할 수 있는 상황이 아닌 경우가 많다. 하드웨어 문제인지 소프트웨어 문제인지를 파악하는 것은 문제를 해결하는 첫 단추이다. 그러나 하드웨어적인 문제인지 소프트웨어적인 문제인지가 쉽게 분간이 안 가는 경우가 많다. 특히 하드웨어 문제의 경우 사람이 머리를 다치면 정신도 이상해지듯이 소프트웨어까지 같이 영향을 주는 경우가 많다.

필자도 그런 경우를 몇 번 경험해 시간을 엄청나게 많이 뺐긴 적이 여러 번 있다. 하드웨어적인 문제는 소프트웨어 문제에서 헤매다가 발견했기 때문에 딱 부러지는 팁을 내놓기가 쉽지가 않다. 어쨌든 하드웨어에 이상이 있을 경우 그간 경험을 통해서 본 현상은 다음과 같다.

[1] 3대 서버 자원(CPU, 메모리, 하드디스크)의 성능이 저하된다. 이는 서버 자원 모니터링 툴을 사용해서 보면 프로그램이 별로 안 떠있는데도 사용량이 증가함을 볼 수가 있다.

[2] 프로그램 설치 에러가 자꾸 발생한다. 즉 CD-ROM이나 주변 장치와의 충돌이나 시스템의 불안정 등으로 인해 프로그램 설치가 되지 못하는 경우 등이 있었다.

하드웨어 문제의 경우 초기에 발견되는 경우와 프로젝트 중, 후기에 발견되는 경우에 따라 프로젝트에 끼치는 영향이 크다. 프로젝트 초기의 경우 보통은 개발 진척이 별로 이뤄지지 않은 상태라서 하드웨어의 교체만으로 문제를 초기에 충분히 진화할 수가 있다. 그러나 중, 후기에 발생할 경우에는 그 문제가 하드웨어적인 문제라는 것을 밝히기가 쉽지 않다는 것이 큰 문제가 되며 서버를 교체하면 그동안 개발했던 시스템 구성으로 새로이 서버를 구성해야 하는 부담이 있다. 소프트웨어의 문제시에 발생하는 에러의 경우 하드웨어를 비롯해 그 원인이 다양하므로 다음의 시스템 계층 구조에서 살펴보자.

HW 및 SW 문제는 계층으로 파악하라

<그림 3>은 자바 기반 애플리케이션의 구성 계층을 나타낸 것으로 다른 애플리케이션과 다른 점은 자바 가상머신이 애플리케이션 서버와 자바 애플리케이션 사이에 있다는 점이다.

자바 기반 애플리케이션 구성 계층은 자바 기반의 애플리케이션을 물리적으로 구현하는 단계로 보면 쉽게 이해할 수 있을 것이다. 우선 서버가 제일 먼저 있어야 한다. 이것이 하드웨어 플랫폼 계층이고, 여기에 운영체제가 설치되고, 그 위에 웹 애플리케이션 서버(WAS)를 비롯한 DB 서버, 웹 서버 등 기타 서버가 설치된다. 그리고 JDK가 설치되어 자바 가상머신 환경을 구성해준다. 이렇게 되면 개발환경이 셋팅된 셈이고, 이제 자바 코드가 개발되어 자바 애플리케이션을 구성하며, 그 위에 사용자 인터페이스가 만들어진다.

따라서 시스템에 문제가 발생하면 <그림 3>의 각 구성 계층별로 하드웨어 자체, OS, 자바 가상머신, 애플리케이션서버, 자바 애플리케이션, UI 코드를 한 차원씩 스캔하듯이 검사함으로써 해당 요소의 문제 발생 가능성을 제거하면서 찾아나가야 한다.

FTP 업로드나 다운로드 이상은 시스템의 문제

FTP 서버의 상태와 시스템 문제의 연관성은 얼핏 들으면 작아 보인다. 하지만 FTP는 FTP 서버 그 자체의 성능도 중요하지만 네트워크를 많이 사용하고 파일시스템 또한 많이 액세스한다. 그래서 여기에 문제가 있다는 것은 네트워크나 파일시스템에 뭔가 이상이 있을 수도 있다는 것을 간접적으로 보여준다. 그 외에도 OS, 해킹, 바이러스, 하드웨어 부품 이상 등에서도 기인한다. 다음의 경우는 실제로 FTP의 이상 현상이 나타나면서 서버에 이상이 발생해서 필자가 고생했던 경우들이다.

[1] CPU가 타버렸던 경우

필자가 운영했던 사이트에서 나타났던 것으로 FTP로 파일을 올리거나 받는데 중간에 자꾸 끊기거나 파일이 불완전하게 전송되곤 했었다. 그래도 FTP가 좀 불안한 것 외에는 1년 정도 리눅스 서버로 잘 썼는데 이사를 하면서 다시 켜서 FTP를 하려고 하니 점점 불안한 상태가 계속 되다가 결국에는 서버가 완전히 다운되어 부팅조차 되지 않았다. 용산 전자상가에 가져가보니 CPU 두 개 중 한 개가 타버렸다는 것이었다.

[2] OS 및 백도어 침입

다른 사이트의 경우인데, 여기도 서버는 그럭저럭 돌아갔지만 FTP 다운로드를 하면 파일이 전부 받아지지 않고 중간에 끊기는 것이었다. 그래서 백업받으려면 조금씩 나눠서 받아야 했다. 그 외에 DB 연결도 불안해 커넥션풀링에 자꾸 리크 현상이 발생하는 것이었다. 그래서 서버 전문가에게 물어보니 OS가 패치되지 않아 불안한 상태였고, 백도어에 의한 침입이 있었다는 것이었다.

그리고 중요한 것 하나를 덧붙이면, FTP가 불안하면 불안할수록 어떻게든 꼭 백업을 해야 한다는 것이다. 필자가 호스팅받는 사이트에서 FTP가 불안했던 적이 있었는데 그 뒤로 얼마 되지 않아 하드디스크 내용을 잃어버린 사태가 발생했다. 그 때문에 작업했던 소스를 30% 정도 잃어서 아직도 복구하지 못한 부분이 있다. 어쨌거나 필자가 FTP 부분을 이렇게 강조하는 이유는 그런 뼈저린 아픔이 있기 때문이기도 하다.

서버 자원 사용이 많으면…

실제 시스템의 사용자가 매우 많다는 것이 원인이라면 서버 자원의 사용이 많은 경우는 문제의 소지가 있다. 서버의 주요 3대 자원으로 CPU, 메모리, 하드디스크가 있다. 이러한 서버 자원의 성능과 용량은 시스템의 안정성과 성능에 매우 큰 영향을 미친다. 그래서 이를 기본으로 서버의 용량을 산정하고, 특히 프로젝트에서는 어느 정도 여유 있게 용량을 산정해 서버를 도입한다. 이렇기 때문에 서버 자원이 지나치게 많이 사용되고 있다면 비정상적으로 자원이 낭비되고 있다는 것을 의미한다.

서버 자원의 모니터링은 서버 관리자에 있어 가장 기본이면서도 중요한 관리 활동이다. 또한 개발자들도 이러한 지식이 있다면 더 적은 자원을 쓰면서도 빠르게 작동하는 소프트웨어 개발을 할 수가 있다. 다음의 예들은 서버 자원의 사용이 지나치게 많아서 문제가 발생했던 경우들이다.

[1] 하드디스크의 가용 용량이 다 된 경우

이는 대형 사이트에서 많이 발생한다. 필자도 여러 사이트에서 겪었다. 테스트할 때는 데이터 및 사용자가 적어서 별 문제가 없었지만 개발이 완료되어 시스템이 오픈됐을 때, 실제 데이터가 올라가고 사용자가 증가하면서 서버가 갑자기 죽는 경우가 발생한 적이 있었다. 물론 그전에 모니터링을 통해서 미리 발견했다면 서버가 다운되지는 않았을 것이다.

기억나는 것 중 몇 가지만 들면, DB 서버에 회원의 이미지를 저장하는 시스템이었는데 사용자가 기하급수적으로 늘면서 이미지 데이터가 계속 입력되다보니 결국에는 하드 용량을 다 차지하면서 서버가 죽어버린 것이었다. 그 외에 웹 서버 로그가 계속 증가하면서 하드디스크를 다 차지해 시스템이 다운된 경우도 있었다.

[2] 메모리 사용량이 증가해 있는 경우

자바 프로젝트의 경우 더욱 빈번하다. 메모리 사용이 증가한다는 것은 프로세스가 많다는 것인데, 이 프로세스가 유효하지 않은 프로세스이면 결국에는 서버의 다운으로 이어진다. 특히 자바는 자바 가상머신에 의한 메모리 관리가 이뤄지기 때문에 사용자가 메모리를 직접 제어할 수가 없고, 가비지 컬렉션에 의해 간접적으로 제어가 이뤄진다. 그래서 메모리 문제가 발생하면 어떤 코드에서 발생하는지를 찾아서 해결해야 한다(이는 메쏘드 프로파일링 툴이나 명령어 등으로 찾아낼 수가 있다).

참고로 CPU 사용량이 100% 가까이 증가하면서 장애를 일으키는 경우는 드물다. 이는 장애발생이 일어나는 상황이 다른 서버 자원으로부터 비롯되기 때문에 CPU가 100%까지 사용되려면 오히려 다른 애플리케이션이 가장 잘 실행될 수 있는 상황에서 일어날까 말까 하기 때문이다.

로그량이 지나치게 증가하면…

로그는 시스템이 어떤 상태였고 뭘 했다는 기록이다. 그래서 시스템에 이상이 오면 반드시 로그를 살펴서 무엇이 원인인지를 찾아내야 한다. 이는 시스템 관리자의 기본 사항이다.

여기에 덧붙여 로그량이 지나치게 증가할 경우 로그를 남기는 프로그램에 문제가 있음을 의미한다. 일단은 로그를 남기는 프로그램이 엄청나게 많은 횟수로 호출되고 있다는 것이다. 이것이 필요에 의한 정상적인 호출이면 로그를 줄이거나 로그를 남기지 않게 하는 방법, 그리고 로그를 지우거나 일정 주기로 다른 곳으로 옮기는 방법이 있다. 그러나 비정상적인 호출에 의한 것이라면 그 원인을 찾아서 제거해야 한다. 로그량의 증가는 하드디스크 사용량의 증가를 야기해서 하드디스크를 많이 액세스해야 하는 다른 서버의 활동에 방해를 일으킨다. 그리고 로그를 출력하는 만큼 CPU를 비롯한 많은 자원을 소모해 다른 프로세스의 성능을 저하시킨다. 다음의 경우는 로그량이 증가해서 문제가 되는 경우를 예로 들었다.

[1] 호출 빈도에 유의하지 않고 로그인 코드를 넣은 경우

아는 후배한테 들은 얘기인데, 로그인 전문 프로그램을 같이 설치해서 웹 프로그램에 그 로그인 코드를 삽입한 적이 있다. 그런데 실수로 그 코드가 삽입된 부분이 다른 여러 프로그램에 의해 기하급수적으로 중복 호출되는 것이었다. 그래서 서버는 하루 만에 로그로 꽉 차버렸고, 심지어 시스템이 다운되고 나중에 해당 코드를 삭제한 경우가 있었다.

[2] 로그 출력의 부하 때문에 서버가 느려진 경우

로그 출력은 파일 외에 System.out도 있다. 개발하다 보면 디버깅을 위해 System.out.println(“”)이라는 코드를 삽입하고, 나중에 그 코드를 제거하지 않은 경우가 많다. 그래서 서버 콘솔에 엄청나게 많은 로그가 출력되어 다른 작업을 느리게 만드는 경우가 종종 있다.

느린 만큼 심각하다?

교통방송을 들으면 ‘느린 만큼 빨라진다’라는 캠페인을 들은 적이 있을 것이다. 이는 느리게 움직여서 질서를 지키면 그 만큼 더 빠르다는 것인데 서버 시스템의 경우 CPU에 의해서 매우 질서정연하게 통제되기 때문에 ‘느리다’는 것은 심각한 현상이 아닐 수 없다. 하물며 개인 PC도 느리면 심각한 상태(원인은 주로 OS 이상, 바이러스, 비정상적인 소프트웨어, 하드디스크 에러, 메모리 부족, CPU 성능 등)라는 것을 의미하는데 대형 서버는 오죽할까? 서버가 느린 원인은 간단히 다음의 판별식으로 나타낼 수 있다.

if (서버용량 < 처리량 )

앞의 식은 매우 간단해 보이는데 문제는 서버 용량과 처리 용량을 산술적으로 비교할 수치를 계산해낼 수가 없다는 것이다(공식은 쉽게 개념을 잡으라는 뜻에서 나타낸 것으로 알아주길 바란다). 여기서 용량은 CPU, 메모리, 하드디스크, 네트워크 대역폭 등 서버가 특정 프로그램을 구동해 처리하는 데 쓰이는 자원을 의미한다.

그래서 서버가 느린 경우는 두 가지 측면에서 파악될 수 있다. 먼저 서버 용량의 문제로서 서버의 용량이 적거나 다 소진돼 상대적으로 적은 경우가 있다. 그리고 처리량의 문제로서 처리량이 매우 증가해 서버의 처리 용량을 초과하는 경우이다. 서버 용량의 문제는 앞에서 어느 정도 짚었고, 처리량의 문제를 중심으로 살펴보면 다음과 같다.

[1] 불필요한 프로그램의 잦은 호출

이는 두 말 할 것도 없다. 불필요한 프로그램이 자주 호출되면 그 만큼 서버의 자원이 소모됨을 의미한다. 필자가 참여했던 프로젝트 중에 시스템을 재구축하는 곳이 있었는데 ‘리팩토링’ 기법을 써서 불필요한 코드를 지우고 클래스를 재구성해 준 적이 있다. 코드를 보면 한번만 호출되어 처리되어도 무방한 메쏘드가 계속 반복 호출되고, 프로그램마다 그러한 코드가 들어있는 경우가 많았다.

이러한 것은 개발 생산성에도 매우 안 좋은 영향을 끼친다. 특히 반복문이 들어 있는 코드의 경우 불필요한 코드가 들어가지 않도록 주의를 기울여야 한다. 또한 한 번에 처리할 수 있는 로직을 여러 번에 걸쳐서 처리하는 경우나 변수를 재사용하지 않고 임시 변수를 많이 사용하는 경우가 이에 해당한다. 특히 이러한 코드는 프로그램을 매우 복잡하게 만들기 때문에 나중에 유지보수에도 많은 영향을 준다.

[2] 특정 자원을 장시간 사용하는 경우

이는 주로 대용량의 계산이나 데이터 처리에서 나타난다. DB를 사용하는 사이트에서는 거의 빠지지 않고 이러한 현상이 나타난다. 필자가 웹 ERP 시스템에서 출력하는 프로그램을 개발해 주었는데, 고객이 요구한 리포트의 출력을 위한 계산이 매우 복잡해서 일반 쿼리로 작성을 하니 쿼리가 몇 백 줄에 이르렀다. 그래서 그 프로그램을 호출하면 시간도 많이 걸리고 서버가 죽기도 했다. 그래서 해당 프로그램이 호출되기 전에 미리 배치 작업을 통해서 데이터를 처리해 보여주는 식으로 문제를 해결했던 적이 있다.

DB 사용 시스템 문제의 대부분은 ‘DB 접속’

자바 프로그램은 DB와의 연결을 JDBC라는 인터페이스를 통해서 구현한다. 그래서 각 DB 벤더별로 JDBC 인터페이스 함수를 구현한 JDBC 드라이버를 사용하면 소스코드를 크게 안 고치고도 여러 종류의 DB에 접속이 가능한 장점이 있다. 그러나 DB 자원의 사용에 있어 주로 발생하는 문제점은 DB 접속과 관련된 것이 대부분이다. 그런데 DB 접속 관련 문제는 하드웨어적인 문제와 소프트웨어적으로 나타나는 문제 두 가지로 나뉜다.

[1] 하드웨어적인 문제

서버의 네트워크 상태가 불안해서 DB 접속 포트와의 통신이 제대로 안 되어서 발생하는 경우이다. 특히 DB 접속이 되었다 안 되었다 반복한다면 더욱 그럴 가능성이 높다. 필자가 운영하는 사이트에서 서버를 띄우면 처음 얼마동안은 빠르게 잘 나오다가 얼마 안 있어 접속이 되지 않아 Exception이 발생한 적이 있었다. 그래서 또 다시 서버를 띄웠더니 또 얼마동안은 잘 되다가 또 접속이 되지 않는 것이었다. 그래서 필자는 소프트웨어적인 문제인 줄 알고 코드를 다시 살펴봤지만 여전히 그 현상은 계속 되었다. 나중에 네트워크 쪽 이상임을 발견하고 해당 문제를 해결하니 안정적으로 접속되는 것이었다.

필자는 이 사실을 알게되는 데까지 몇 개월 걸렸다. 이는 그 문제가 처음에는 소프트웨어적인 부분에서 나타났기 때문에 필자가 소프트웨어 부분만 고치면 다 해결되는 것으로 확신했었다. 그리고 이런 경우에 발생한 Exception은 여러 가지였다. NullPointerException을 비롯해서 ProtocolViolationException 등 여러 가지가 발생해 필자로 하여금 혼돈을 일으키게 만들었다.

[2] 소프트웨어적인 문제

소프트웨어적인 문제는 JDBC 코드의 사용법에 직결된다. 자바라는 언어가 메모리 관리를 개발자가 하지 않기 때문에 DB 연결코드 작성시 개발자가 잊고서 DB 관련 자원(Connection, Statement, PreparedStatemen, ResultSet 객체)을 제대로 해제하는 코드를 넣지 않는 경우가 많다. 필자도 코딩을 하다 보면 가끔 빠뜨리는 경우도 있었다. 그래서 해당 프로그램이 계속 호출되다 보면 DB 자원을 기존에 호출됐던 프로그램에서 잡고 있게 되고, 나중에 호출되는 프로그램에서는 DB에 접속할 수가 없게 된다. 더구나 해당 코드에 DB 자원을 해제하는 코드를 잘 넣었다 치더라도 Exception이 발생했을 경우 이를 캐치해서 자원을 해제하는 코드를 넣지 않았을 때도 마찬가지다. 이때는 주로 NullPointerException, SQLException 등이 일어난다. 이는 <박스>에서 보다 자세히 다루도록 하겠다.

배열과 객체 값을 참조하는 코드에서는…

배열과 객체 값을 참조하는 코드에서는 NullPointerException을 조심하라! 배열과 객체를 사용할 경우에는 NullPointerException이 자주 발생한다. 이는 배열과 객체들의 값을 일일이 코드로 체크하지 못하는 경우가 많기 때문이다. 특히 이런 경우가 웹 프로그램에서 발생했을 경우에는 NullPointerException이라는 메시지 외에 아무 것도 안 뜨기 때문에 원인을 찾는 데 어려움이 있다. 배열은 배열이 초기화되지 않았을 경우 NullPotinterException이 나타나고, 배열의 인덱스 값이 바운더리를 넘어가면 ArrayOutOfBoundException이 발생한다.

프로젝트 리소스는 꼼꼼이 관리하라

보통 개발자들은 프로젝트의 기술적인 부분이 매우 중요하다고 생각한다. 필자도 그랬으나 프로젝트를 거듭하다보면 프로젝트 리소스 관리의 중요성을 절실히 느낀다. 관리적인 요소는 간과하기 쉬우나 그 관리적인 요소가 기술적인 요소와 다른 점은 그것의 부실 또는 부재의 영향이 크다는 것이다. 기술적인 요소가 부족하거나 문제가 생기는 경우 만약 그것을 인지한다면 충분한 인력과 기술을 투입해 막을 수 있지만 관리적인 요소가 부족하면 프로젝트는 종잡을 수 없는 방향으로 흘러가 나중에 그 상황을 해결하기 위해 막대한 비용이 들게 된다.

프로젝트는 각 리소스가 프로젝트의 실행계획에 따라 적시에 활용된다. 프로젝트의 리소스가 실행계획을 따른다는 것은 시간적 제약이 있다는 것이고, 이는 곧 비용과 직결되므로 프로젝트 관리의 대상이 된다. 특히 대형 프로젝트의 경우 관리만 전담하는 팀을 따로 두는 것을 보면 그 중요성을 더욱 실감할 수 있다. 앞에서 프로젝트를 자동차 운전에 비유했듯이 좋은 차와 훌륭한 카레이서가 있어도 이를 잘 관리하는 능력이 없다면 우승은 그림의 떡이 된다.

프로젝트 리소스 관리 문제 파악하기

앞에서 프로젝트의 리소스로부터 문제가 시작된다고 했다. 이것들은 프로젝트를 진행함에 있어서 그 자체로 문제가 되거나 하드웨어와 소프트웨어가 복합된 문제, 인력과 관리가 복합된 문제, 소프트웨어와 인력이 복합된 문제 등 다양하게 나타난다.

하드웨어의 경우 서버의 성능, 용량, 안정성, 확장성이 있으며, 네트워크 전송 속도, 트래픽량, 안정성 등이 있다. 소프트웨어의 경우 개발 툴, 코드 표준 또는 프레임워크, 애플리케이션 서버(웹 서버, 웹 애플리케이션 서버, 데이터베이스 서버), 데이터베이스 구성, 개발자의 코드, 자바 가상머신, 서버 아키텍처 등 문제가 열대우림처럼 매우 다양하다. 인력에 있어서는 프로젝트 팀의 기술적 성숙도, 팀원간의 커뮤니케이션 등 인간적인 문제 등이 있다.

자, 그럼 프로젝트의 문제점이 어떻게 나타나는지 살펴보고, 이와 관련된 필자 또는 주변 동료들의 경험과 해결책을 알아보자.

서버의 결함은 빨리 파악해서 조치하라

여기서 말하는 서버는 하드웨어적인 것과 소프트웨어적인 것일 수도 있는데, 하드웨어적인 결함은 초기에 발견되면 서버 교체를 통해 빨리 수습이 가능하지만 개발 및 테스트 단계에서 나타나면 심각한 문제를 야기한다. 아마도 이런 문제에 머뭇거리는 관리자가 있다면 그 문제의 심각성을 알리고 최대한 빨리 조치할 수 있도록 해야 한다.

[1] 하드웨어적 결함에 대한 조치는 빠를수록 좋다.

필자가 개인적으로 운영하는 서버의 경우 결함이 매우 늦게 발견되어 나중에 수리하는 데도 몇 달이 걸린 경험이 있다. 만약 이 서버에 실제 프로젝트를 개발하고 있었다면 수개월 지연됐을 것이다. 한편 모 기관의 프로젝트에서는 하드웨어의 결함을 조기에 발견해 개발하는 데 큰 불편 없이 마무리한 적도 있다.

[2] 소프트웨어적 결함은 빨리 알려서 조치를 받아라.

필자가 참여했던 프로젝트에서 WAS를 설치해 개발했는데 그 서버가 자주 다운되는 것이었다. 그래서 제작사 기술 지원팀에 매번 문의를 해서 코드를 바꾸기도 하고 패치를 적용하기도 했다. 서버가 자주 다운되어 이골이 날 무렵 결국에는 다른 WAS 제품으로 바꾸어줌으로써 문제는 해결됐다. 하지만 그 말썽 많았던 서버 때문에 허비했던 시간은 보상받을 수가 없었다.

하드웨어와는 달리 소프트웨어 제품의 결함은 밝혀내기가 쉽지 않을 뿐더러 그 결함을 쉽게 인정하지 않기 때문에 개발자들의 소프트웨어 코드에 원인을 돌린다. 그래서 그 문제가 오래 지속될 가능성이 높다. 이럴 경우 소프트웨어 엔지니어와 개발자, 관리자의 긴밀한 협조 하에 문제를 최대한 빨리 해결하는 노력이 필요하다.

교육과 커뮤니케이션을 통해 업그레이드하라

대부분의 프로젝트에서는 개발자들이 해당 분야의 경험을 갖고 있기를 바란다. 그래서 새로운 기술의 경우 유경험자 없이 몸으로 부딪치면서 해야 한다. 그래서 자바 유경험자가 별로 없었던 초창기에는 기업별로 자바 교육이 많이 이뤄졌었다. 이러한 교육은 기본적인 스킬 업그레이드 부분도 있지만 개발 표준을 잡아나가는 데에도 의의가 있다.

[1] 모르는 것을 부끄러워 할 필요 없다.

프로젝트에 가면 연차가 낮을수록 모르는 것에 대해 부끄러워하고 감추려는 경향이 있다. 반대로 연차가 높은 사람들은 처음부터 모르는 것을 인정하고, 시스템 교육 때나 그것을 잘 아는 사람들에게 물어봄으로써 해당 기술을 쉽게 수용한다. 더군다나 자고 일어나면 계속 새로운 기술이 쏟아지기 때문에 모든 것을 두루 섭렵한다는 것이 결코 쉬운 일이 아니다. 편하게 자기가 뭘 모르는지를 정확히 파악하고 업무에 필요한 기술을 정확히 익혀서 사용할 줄 아는 자세가 중요하다.

[2] 아무리 스킬이 안 되더라도 도망은 가지 말자.

이는 필자가 K정부기관에서 자바로 내부 업무시스템을 구현했던 프로젝트였다. SI 업계에 자바 프로젝트가 시작된 지 오래 되지 않아서 자바 개발자의 몸값이 지금에 비하면 하늘을 찌를 듯(?)이 높았던 때였다. 이렇게 몸값이 높은 이유는 지금 생각해보면 기술의 난이도보다는 개발자의 수요공급의 문제로 여겨진다. 왜냐면 그런 스킬을 가진 개발자들이 흔치 않았기 때문이다.

어찌됐든 그 프로젝트에서는 개발의 생산성이 너무 낮아서 매일 프로젝트 관리자는 본사와 고객사측으로부터 쪼임을 당하고 있었고, 급기야 자바 생산성 향상을 위해서 자바 컴포넌트를 도입했고 그리고 인력을 더 투입했다. 첫날에는 필자가 쉬운 부분을 주었고 그 개발자는 간단히 프로그램을 완성하는 것 같았다. 그래서 본격적으로 구현할 업무의 일부분을 맡겼다. 그런데 그 다음날 해당 개발자는 나타나지 않았다. 필자도 매우 황당했지만 그 개발자는 컴퓨터와 수첩 등 물건을 그대로 놔두고 나타나지도 않았고 연락도 두절됐다. 나중에 어찌어찌해서 연락이 닿았는데 도망간 이유가 개발이 너무 어려워서 포기했다는 것이었다.

표준 없는 개발은?

개발에서 표준은 생산성 및 유지보수 측면에서 매우 중요한 역할을 한다. 그 표준화된 코드를 사용하도록 하기 위해서는 개발자 관리 측면의 노력을 아끼지 말아야 한다. 실제로 개발자 두 명과 함께 참여했던 프로젝트에서는 그냥 알아서 개발하라고 했었고, 다른 프로젝트에서는 필요한 표준 코드를 만들고 무조건 거기에 따르도록 했다. 나중에 프로젝트 종료할 즈음 코드를 보니 전자는 각양각색의 코드가 나왔으며, 후자는 한 사람이 작성한 듯한 코드가 나왔다.

표준화되어 있는 코드는 유지보수를 할 때에도 고칠 부분만 찾아서 원하는 기능으로 구성할 수 있으나, 표준화되어 있지 않은 코드는 각각의 경우마다 일일이 코드를 해석해야 한다. 더구나 에러가 발생했을 경우에는 더욱 찾아내기가 힘들어진다.

프로젝트 관리자의 정치적 역량

프로젝트 관리자의 정치적 역량에 따라 시스템이 좌우된다. 프로젝트 초기에 관리자의 말 한마디에 따라 시스템이 달라진다. 이는 관리자 선에서 구현 가능한 범위를 어떻게 규정짓느냐에 따른 문제인데, 그 프로젝트의 리소스 및 상황을 전혀 고려하지 않고 고객에게 점수를 얻기 위해 무조건 가능하다는 식으로 얘기하는 경우가 있다. 이와 반대로 일단은 고객에게 무조건 안 된다고 거절하는 스타일이 있다. 프로젝트를 하다보면 앞의 두 가지 스타일을 적절히 적용해야 한다. 즉 해줄 수 있는 것은 확실히 해주고 안 되는 것은 확실히 거절해야 한다는 것이다. 그렇지 못할 경우에는 개발자들이 엄청난 부담을 떠안게 된다.

[1] 정말 안 되는 것은 안 된다고 하라.

개발이 완료되지 않은 상태에서 관리자의 정치타협으로 프로젝트를 종결했다가 나중에 된서리를 맞은 적도 있다. U사에서 모 정부기관 프로젝트에서 내부 업무 시스템을 구축하는 것이었다. 그 프로젝트는 처음에 고객과 약속한 시점까지 개발을 끝내고 완료보고를 하고 모두 철수했다. 그런데 그 프로젝트 관리자는 이내 다른 회사로 이직했고, 얼마 안 있어 고객 측에서 연락이 왔다. 프로젝트 완료보고서 상에는 다 된 것으로 나타나 있지만 실제 시스템에는 개발되지 않은 것이 몇몇 있었던 것이다. 고객사 측에서는 강력히 이의를 제기했고, 필자의 회사 측에서 관리자급 인력 및 엔지니어 몇 명이 휴일까지 나가 힘들게 마무리해 주었다. 마무리되지 않은 부분에 대해 완벽히 처리해 주었는지 자세히는 몰랐지만, 그 후에 그 정부기관에서는 U사와의 거래가 끊기고 말았다.

[2] 적당한 타협점도 찾을 수 있어야 한다.

프로젝트관리 측면에서 정치적으로 어느 정도 고객 측과 타협해나가는 것도 중요한 스킬이다. 앞의 사례의 경우 차라리 안 된 부분은 처음부터 못하겠다고 해서 개발범위에서 제외했으면 좋았을 것이다.

커뮤니케이션이 시스템을 만들어나간다

필자는 초창기에는 개발자의 코드 한 줄이 시스템을 만들어 나간다고 생각했었다. 그러나 프로젝트를 해보면서 느끼는 것은 코드 한 줄은 개발자의 코드이지 고객이 원하는 시스템의 코드가 아닐 수도 있다는 것이다. 그렇기 때문에 고객이 원하는 시스템을 이해하기 위해서 고객과 커뮤니케이션을 하는 것이 중요하다.

[1] 고객과의 커뮤니케이션을 통해 시스템을 서로 이해해야 한다.

필자가 S사 CRM 사이트 구축에 참여했던 프로젝트였다. 고객과의 충분한 대화를 통해서 고객이 정확히 무엇을 요구하는지를 파악했고, 필자는 그들에게 필자가 이해한 시스템의 모양을 설명해주었다. 그래서 생각보다 빨리 시스템의 설계가 이뤄졌고, 개발 완료 예상 기간을 알려주었다. 실제로 개발에 들어갔을 때는 예상기간보다 몇 주 빨리 끝나게 됐고 만족스럽게 시스템을 구축하고 나올 수가 있었다.

그와 반대로 고객과의 충분한 커뮤니케이션을 하지 않고서 그냥 넘겨짚기만 해서 계속 개발해 나가다가 개발이 완료되어갈 즈음 처음에 얘기했던 것과는 완전히 다르게 구현되어 시스템을 뒤엎은 경우가 있다.

[2] 말 한마디가 천냥 빚을 지게 할 수도 있다.

필자가 S사 프로젝트를 진행하며 있었던 일인데, 회계 관련 데이터를 받아서 처리하는 부분을 개발하고 있었다. 그런데 이 데이터는 A팀→B팀→C팀을 거쳐서 오는 것이었다. 그랬기 때문에 수주가 지나도록 제대로 된 데이터를 못 받아봤고, 자연히 시스템의 개발도 느려졌다. 그런 상황에서 고객이 호통을 치면서 도대체가 언제 되냐고 물었다. 그 질문에 필자는 ‘데이터만 다 전달되어 오면 내일이라도 된다’고 했다. 그런데 그 고객은 ‘데이터가 전달되면’이라는 조건은 무시하고 내일까지 되는 걸로 이해해버렸다. 그 말 한마디 때문에 모든 팀이 고생하며 개발했고, 결국에는 수주동안 지연됐던 일이 수일 내에 해결됐다. 이는 어차피 해야 할 일이었기 때문에 결과적으로는 잘 된 일이라고 본다. 만일 불필요한 일이었다면 개발자들에게 쫓겨났을 지도 모른다.

프로젝트 관리는 ‘지속적으로’

‘피부 관리’는 지속적으로 받음으로써 그 효과를 발휘한다. 프로젝트도 피부와 같이 관리가 없으면 칙칙해지고 제멋대로 가기 마련이다. 지난 호에서도 얘기했듯이 조그만 프로젝트일수록 관리가 느슨한 경향이 있기 때문에 관리의 부재로 인한 위험이 매우 크다. 최소한 일주일에 한 번은 팀원이 어떤 일을 하고 어떤 어려움이 있는지 등을 살펴야 한다.

[1] 소형 프로젝트의 경우 프로젝트 관리가 없으므로 실패할 확률이 높다.

아르바이트는 개발자라면 한번쯤 해본 경험이 있을 것이다. 그러나 제 시간에 끝내고 돈 받은 경우는 그리 많지 않을 것이다. 특히 회사 일을 하면서 몰래 아르바이트를 하는 경우는 더욱 그러하고, 혼자가 아니라 여러 사람들과 같이 하게 되면 더욱 리스크가 높아진다. 이는 제대로 된 프로젝트의 관리가 이뤄지지 않기 때문에 소프트웨어의 품질뿐만 아니라 납기를 맞추기도 힘들어진다. 더구나 여러 사람이 하는 경우에는 그 사람들간의 커뮤니케이션이 원활하지 않기 때문에 프로젝트의 방향을 잃을 가능성이 높다는 것이다.

[2] 아는 사람의 경우 정에 연연하다 보면 더욱 느슨하게 프로젝트가 진행되는 경향이 있다.

필자의 경우 아는 사람의 부탁을 받아 간단한 메뉴를 수정해주는 데 한 달반이 걸린 적이 있었다. 그 사람에게 얘기는 안했지만 실제로 일은 마지막 7일 정도만 해서 마무리지었다. 이는 그럭저럭 잘 끝났지만 또 다른 아는 사람에게 부탁받아서 만들어 주기로 한 쇼핑몰의 경우 결국에는 반 정도 해주고 돈도 못 받고 흐지부지 끝나고 말았다.

인간적인 기본 사항은 필수

이는 따로 강조하지 않아도 분별 있는 사람이면 충분히 알 것이라고 본다. 근데 가끔 문제가 되는 것은 프로젝트 팀원이 어떻게 하든 아무 말 없이 그냥 묵과하는 관리자이다. 나중에는 이런 것들이 결국에는 고객들에게 불만으로 나오게 될 것이 확실하므로 그런 것들은 지적해 주어야 할 것이다.

다음 호는 자바 프로젝트로 업그레이드하기

이번 달에는 프로젝트의 리소스를 파악하고 프로젝트 리소스가 일으키는 문제, 프로젝트 관리적 문제 등을 살펴봄으로써 프로젝트의 성공과 실패의 요인을 분석해봤다. 그리고 이에 따른 다양한 사례도 살펴봤다. 다음 호에는 자바 프로젝트를 통해서 자신의 몸값을 올릴 수 있는 노하우와 자바 프로젝트의 진행과정에 따르는 뒷이야기, 그리고 앞으로 자바 개발자로서의 비전과 가야할 길 등을 제시하겠다. @

<리스트 1>은 finally 절이 없으므로 만일 쿼리나 DB 서버 자체의 이유로 에러가 발생하면 Statment 객체와 Connection 객체가 닫히지 않아 이들의 자원 사용이 증가해 DB에 접속할 수 없게 된다. <리스트 2>처럼 finally에서 Statment와 Connection을 닫아주어야 한다.

[2] 객체를 불필요하게 남발하진 않는가?

Connection과 Statement는 DB의 설정치 만큼 생성될 수 있는 객체의 개수가 제한되어 있다. 제한되어 있기 때문에 이들 객체의 생성에는 신중을 기해야 한다. 사실 여기만 조심하면 크게 에러날 일은 없다. 앞에서 얘기했듯이 Connection 객체는 한 페이지에서 한번 연결된 것을 계속 사용할 수가 있다. 그렇지 않고 쿼리를 할 때마다 Connection 객체를 생성하면 접속 때 발생하는 부하량과 접속한 개수만큼 Connection 개수룰 차지하게 되어 자원의 낭비가 심해진다.

Connection의 사용은 한 페이지에서 한 개를 사용한다고 생각하면 되는데, Statement 객체는 새로운 쿼리마다 객체를 새로 생성해야 한다. 이는 Statmenent 변수를 여러 개 쓰거나 같은 Statement 변수에 새로운 쿼리를 할당해서 쓰는 방법이 있다. 전자의 경우 Statement가 배 이상으로 사용되어 자원의 낭비 때문에 DB 접속이 안 되는 경우가 자주 발생한다. 그래서 필자는 후자의 방법을 쓴다. 하나의 Statement 변수에 새로운 쿼리를 할당해서 쓰는데, 주의할 점은 다음의 쿼리에서 Statement를 쓰기 전에 반드시 close해주고 써야 한다. <리스트 3>에 이를 나타냈다.

[3] JDBC 관련 객체는 공유하면 안 된다.

JDBC 관련 객체는 물리적으로 떨어져 있는 DB와 소켓 통신을 대행해주는 객체이다. 따라서 이러한 변수를 다른 페이지(JSP)에서 공유를 해버리면 데이터가 꼬이게 된다. 즉 JDBC 관련 처리는 메쏘는 내에서 처리가 되어야 한다. 따라서 이러한 객체들은 메쏘드 내에 선언되어 그 안에서 사용되면 별 문제가 없지만, 메쏘드 외부(인스턴스 변수)에 선언되면 다른 메쏘드에서 해당 객체를 사용할 수 있게 된다. 이렇게 되면 쿼리의 결과가 서로 꼬이게 된다.