티스토리 뷰

에세이

전역변수 Apocalypse

June 2015. 3. 28. 01:49

프로젝트가 오픈을 향해서 달려가고 있었다. 프로젝트를 표현할 수 있는 모든 숫자들이 완성에 가까워지고 있었고, 프로젝트에 속한 모든 사람들의 얼굴이 반죽음 상태에 가까워지고 있었다는 점에서 의심할 여지 없는 오픈 직전의 상태였다. 사실 오픈 직전의 상태라는 표현은 돌잔치에 가서 아기한테 '어이구 이제 다 컸네!'라고 말하는 것 만큼이나 객관적인 상태와 동떨어진 감정적인 표현이었다.


당시에 막 2년차를 넘어서 3년차 개발자라는 수식어가 붙었던 나는, 이전 프로젝트들에서 오픈 혹은 그와 비슷한 이벤트를 경험해본 적이 없었기 때문에 오픈에 임박해가면서 점점 급박해지고 리얼해지는 주변 상황이 마냥 신기하기만 했었다. 결함이 쏟아져 나오는 상황도, 주말에 쉴틈없이 배달되는 피자와 쌓여있는 컵라면 들도, 30분이 멀다하고 '소행성이 지구에 충돌한답니다!'와 비슷한 강도로 주변에서 시끄럽게 터져나오는 이슈들도 모두 처음이었고, 그 모든게 다 라이브로 펼쳐졌다. 내가 본 것중 가장 죽어가는 얼굴을 하고 있었던 개발자들이 만들어내는 가장 생동감있는 현장이었다.


보통 큰 규모의 시스템 오픈은 명절 연휴 때 하는 경우가 많았는데, 시스템을 모두 다운시킨 뒤 작업을 해야 되니 휴일이어야 되었고, 혹시라도 일이 예상대로 흘러가지 않았을 때 복구할 시간이 있어야 되었으니, 그 휴일은 되도록 길었으면 좋겠다는 합리적인 판단에서 나온 결론이었다. 이 프로젝트의 오픈이 설날 연휴로 정해진 것이 우연인지 운명인지 아니면 정교한 일정조정으로 유도된 결과인지는 모르겠지만, 어쨌든 우리는 주말을 포함하여 4일이라는 귀중한 시간을 얻었다.


설날이 되었고 프로젝트가 오픈을 향한 카운트다운을 시작했다. 오픈이 없는 프로젝트에서 일하면서 상상했던 오픈은, 모두가 긴장된 표정으로 디스플레이를 바라보고 있었고 침 삼키는 소리 조차 크게 들릴만큼 조용하고 긴장된 분위기에서 PM님이 모든 책임은 내가 다 지고 가겠다는 결연한 표정으로 엔터키를 누르고, 그러자 서버가 일제히 돌아가기 시작하면서 로그가 디스플레이에 올라가기 시작하고, 이윽고 웹 서버의 기동이 완료되면서 '서버가 성공적으로 기동되었습니다'라는 로그와 함께 커서가 깜빡거리고 그 순간 일제히 풀어진 긴장과 함께 개발자들의 함성이 쏟아져나오는 그런 순간이었는데 실제 오픈은 '아직 잡지 못한 결함이 있는데 이거 어떻게 해결하지'라고 소스코드를 노려보고 있다가 쪽지로 '운영 서버에 반영 완료되었습니다'라는 전체 공지 쪽지 한 장이 도착하고, 나와 상관 없는 공지구나 라고 생각하고 쪽지를 지우고 다시 결함을 고치려고 소스 코드를 뒤적거리고 있다가 엄마야 방금 그 쪽지가 오픈했다는 소리구나 라고 깨닫게 되는 생각보다 차분하고 시시한 이벤트였다.


그러니까 진짜 오픈은 고객들이 출근해서 우리 시스템을 사용하기 시작하는 순간이라는 것을 몰랐었다. 그 때는.


설 연휴가 끝났다. 오픈 전과 오픈 후의 차이는 설날에 집에도 안 보내주면서 나눠준 스팸 선물 세트가 책상 아래에 있고 없고 정도의 차이만 있었고, 나는 이미 오픈이라는 거대 이벤트가 시시하게 끝나서 프로젝트에 대한 흥미를 많이 잃은 상태였다. '그 동안 우리가 이렇게 고생했는데 이 정도 잔결함은 그냥 넘어가주지 않을까' 싶을 정도의 자잘한 결함만 수정하고 있던 나는 의외로 고객들의 업무 첫 날에 아무런 불평도 불만도 결함보고도 없었다는 사실에 '뭐야 설마 이거 잘 돌아가나?'라는 어리둥절한 기분으로 일찍, 그러니까 저녁 12시 쯤에 퇴근할 수 있었고 다음 날 출근하고 나서야 프로세스 상 앞단계의 시스템이 모두 박살이 난 상태여서 우리 파트까지 넘어온 데이터가 없었다는 사실을 알게 되었다.


단기간 내에 시스템을 정상화 시키려는 개발자들의 비정상적일 정도로 장대한 노력이 이어졌고, 치열한 수정끝에 수많은 단계를 거친 데이터들이 하나씩 우리가 담당하고 있던 프로그램에 들어오기 시작했다. '어쨌든 이론상으로는 완벽한 코드니까 운 좋으면 잘 돌아갈지도 몰라'라는 바람은 첫번째 데이터가 도착하는 순간부터 깨지기 시작했고, 화난 고객들의 전화가 사무실에 울려퍼지기 시작했고 전화를 받던 막내 개발자의 얼굴도 울기 직전의 상태가 되었다. 고객들의 항의는 '듀얼 모니터 사용법도 안 알려주고 모니터를 두 개 주면 어쩌라는 거냐'와 같은 비교적 신사적으로 해결할 수 있는 것에서 부터 '눌렀는데 아무 것도 안나와 입력했던건 다 날라가 버렸어'와 같이 담당 개발자의 심장을 멈춰버리게 할 수 있는 것 까지 다양했었다. 전화, 시스템, 직접 방문등 다양한 경로로 전달되는 부정적인 피드백들은 다크 아칸의 그것 만큼이나 개발자들의 에너지를 단번에 날려버렸고, 체력을 방전시켰다.


오픈한지 3일이 지나고, 프로젝트 사무실은 6.25 개전 후 3일째의 서울과 비슷한 상태가 되었다. 그날 저녁에 나는 '여기 데이터 나오는 거 엑셀로 저장하려고 했는데 저장되었습니다 라는 말은 나오는데 실제로 어디에 저장되는지 알 수 없음. 그래서 프린트라도 하려고 인쇄 버튼을 눌렀더니 인쇄되었습니다 라는 말만 나오고 실제로 프린터가 돌아가지는 않는데 이거 왜 그런지 좀 알려줘 당장 급한 건 아닌데 내일 출근하면 제대로 돌아가게 좀 해줘'라고 요약할 수 있는 근래 보기 드문 정중한 결함을 처리하고 있었다. 자바스크립트 코드에 이벤트가 제대로 연결이 되지 않은 것일까, 라고 소스를 뒤져보던 나는 생각보다 소스가 복잡하다는 것을 알게 되었고 이 프로그램을 실제로 개발한 개발자가 누군지 찾아서 물어보려고 했는데, '아 그거요? 그거 만든 분 지난 달에 철수했는데요?'라는 명쾌한 답변을 받고는 나는 왜 지난 달에 투입되었을까 라는 자괴감에 잠시 빠져있다가 코드를 천천히 처음부터 따라가기 시작했다.


어쨌든 컴퓨터 프로그램 코드는 아무리 복잡해도 그 흐름이라는 것이 있는 것이고, 저장 버튼을 눌렀을 때 이 프로그램이 어떤 코드를 타고 엑셀 파일을 만드는지 파악하는 것은 당시 초급 개발자였던 나에게도 크게 어려운 일은 아니었다. 실제로는 놀라울 정도로 빠르게 프로그램의 흐름과 결함의 원인을 파악할 수 있었는데, 저장 버튼에는 '저장되었습니다'라는 다이얼로그를, 인쇄 버튼에는 '인쇄되었습니다'라는 다이얼로그를 출력하는 코드가 자바스크립트로 작성되어 있었고 그 다음은 없었기 때문이었다. 프로그램을 만든 사람은 이미 사라졌으니, 프로그램이 제대로 돌아가는지 확인도 안해보고 완료를 찍은 관리자 혹은 프로그램에 존재하는 버튼들을 한 번씩 눌러보지도 않고 테스트를 마친 테스터들을 원망해야 되나 잠시 고민했었는데 어찌해도 결국 이걸 고쳐야 되는 것은 나라는 사실은 변하지 않았고, '내일 출근할 때 까지 되게 해주세요'라는 말이 비록 그 고객님은 의도하지 않으셨겠지만 '저장기능이랑 인쇄기능 오늘 내로 싹 다 개발해주세요'라는 말로 치환되는 것도 막을 수 없었다.


간신히 새벽에 이루어지는 운영서버 빌드 시간 직전에 개발을 마치고 만신창이가 된 상태로 다음 날 근무에 임했다. 점심을 먹으러 이동하는데 도중에 갑자기 옆에 있던 후배가 정장을 입은 모르는 사람과 반갑게 인사했다. 사실 프로젝트가 이루어지던 장소가 정부청사 였다는 것을 생각하면 정장을 입은 사람들이 돌아다니는게 어색한 그런 장소는 아니었는데, 피곤에 찌들어있는 개발자들 사이에서 그 사람은 꽤 이질적으로 보였다. 여기엔 어쩐 일이냐 아 새 프로젝트 면접보러 왔다 잘 되기를 바란다 등의 짧은 대화가 오고가고 다시 밥 먹으러 가는 길에 물어보지도 않았는데 후배가 그 사람이 누군지 설명해줬다. '저 사람이 그 사람이에요' '누구요?' '그 저장되었습니다 인쇄되었습니다 만든 사람'


당장 뛰어가서 '너 이 새끼야 내가 너 때문에 어제 얼마나 고생한 줄 아느냐 니가 그러고도 여기에 다시 발을 들일 생각을 했냐'라고 따지지 않은 것은 그 사람이 잘 모르는 사람이어서가 아니라 오픈 3일만에 모든 체력이 다 방전되었기 때문이었다. '잘 해결했으니까 뭐 괜찮겠지'라고 열심히 합리화 하고 필수 영양소 보충 정도의 의미를 가진 식사를 마치고 사무실로 복귀했다.


여전히 데이터의 흐름은 불안정했다. 알 수 없는 이유로 다음 단계로 넘어가지 못하는 데이터들이 부지기수 였고, 개발자들이 데이터 하나 하나를 살펴보면서 원인을 고치고 다음 단계로 넘기기 위해 애를 썼지만 그렇게 수작업으로 처리할 만한 양이 아니었다. 뭔가 제대로 돌아가지는 않고 있었지만, 왜 제대로 안 돌아기는지 이유를 알 수 없었기 때문에 딱히 할 수 있는 일도 없었고, 그래서 나는 아까 그 개발자가 남기고 간 소스중에 혹시 다른 함정은 없을까 열심히 기록을 뒤지고 있었고 그 결과 고객보다 먼저 상당수의 결함을 발견해내는 개가를 올렸다.


그런 작은 성취에 만족해가면서 프로젝트 사무실을 조금씩 사람이 살만한 곳으로 바꾸기 위해 다들 노력하고 있던 어느 날이었다. 사무실에 들려서는 안될 단어들이 자꾸 수근수근 수면위로 올라오기 시작했다. '데이터 오염' 그러니까 데이터가 갑자기 의도하지 않은 데이터로 바뀌어 버린다는 말이었다. 우렁각시가 있는 것도 아니고 사용자가 입력하는 것도 아니고 프로그램이 바꾸지도 않았는데 데이터가 어느 순간 갑자기 바뀌어 버린다는게 현대 전산학적의 범주에서는 있을 수 없는 일이다 혹시 고객님의 무의식이 데이터를 잘못 치고서는 나는 잘못한 것이 없어 모두다 너네 잘못이야 라는 합리화에 의해서 원인을 알 수 없는 데이터 오염을 주장하시는 것이 아니냐 라고 응대하기에는 보고되는 현상이 너무 많았다.


'데이터를 입력했는데 다른 값이 저장되었답니다!'라는 말을 듣고 미친듯이 달려가서 '어느 화면입니까!' 라고 물어보고 고객이 다시 똑같은 작업을 해보면 그 때는 또 데이터가 정상적으로 들어갔다. 마치 A/S 센터에 고장난 제품을 가져가면 정상적으로 동작하는 것 처럼. 여기가 A/S 센터였다면 '이거 잘 되는데요? 우리가 해드릴게 없네요?'라는 기쁜 멘트를 날릴 수 있었겠지만 프로젝트 입장에서는 가장 골치아픈 문제였다. 이유없이 간헐적으로 발생하는 결함. 재연은 불가능 함. 그런데 무시하기에는 꽤 자주 발생함.


대표적인 수학 난제인 4색 정리의 증명은 컴퓨터를 통해서 이루어졌는데, 이 증명을 두고 수학자들의 논쟁이 매우 심했다고 한다. 컴퓨터에 의한 계산은 그 결과가 잘못 되었을 가능성이 아주 조금이라도 있으니 엄밀한 진리를 추구해야 되는 수학적 증명의 근거로 삼을 수는 없다는 주장이 강했던 것이다. 하지만 반대로 컴퓨터에 의한 계산이 오답이 나올 확률은 '없다'라고 단정해도 좋을 만큼 컴퓨터는 정확한 기계이니 이는 수학적 증명에 활용하기도 충분하다. 라는 주장도 있었을 만큼 컴퓨터는 정확하게 계산하고 정확하게 저장하고 정확하게 출력해주는 기계였다. 그러한 정확성에 대한 믿음이 있었기에 나는 내 인생을 거리낌없이 컴퓨터에 올인 시킬 수 있었고, 그 정확성이 산산조각 나는 현장은 인생을 부정당하는 듯 싶어서 견디기 어려운 현장과도 같았다.


컴퓨터는 인과관계가 매우 뚜렷한 기계였고, 모든 일에는 원인이 반드시 있었다. 물론 당시에 나는 초급 개발자였기 때문에 그 원인을 파악하기는 커녕 현상조차 제대로 이해하지 못하고 있었다. 그러니까 데이터가 이유없이 바뀐다는 사실을 인정하기 보다는 고객들이 착각을 했거나 잘못 봤을 것이다 라는 주장을 굽히지 않고 있었다. 그 때 마찬가지로 소프트웨어 개발현장에서는 들려서는 안될 단어들이 수면위로 올라오기 시작했다. '전역 변수'


전역변수? 당연히 개발자라면 전역변수가 뭔지 안다. 소프트웨어가 돌아가는 컨텍스트(Context) 내에서 어디서도 참조할 수 있는 참으로 넓은 범위의 변수. 심지어 이름도 Global Variable이니 그 변수가 커버하는 범위가 얼마나 넓은지는 개발을 모르는 사람도 유추할 수 있었다. 하지만 포인터를 만나는 순간 C언어는 내 길이 아니다! 라고 선언하고 대학생활 4년을 자바에 올인했던 나로써는 전역변수라는 말이 매우 거북하게 들릴 수 밖에 없었는데, 객체지향 프로그래밍을 배우기 시작했을 때 전역변수에 대한 설명의 끝에는 항상 '쓰지 마'라는 첨언이 있었기 때문이었다. 객체지향 프로그래밍에 대한 가치관이 형성되던 시기에 최소한 GOTO문과 전역변수는 절대로 쓰면 안 된다는 의식이 강하게 박힌 나로써는 객체지향 프로그래밍 6년차때 들여온 전역변수라는 단어가 반가울리가 없었다.


그런데 자바 프로젝트에 전역변수가 도대체 무슨 말일까, static 변수를 말하는 걸까? 만약에 데이터가 static 변수에 저장된다면 지금의 모든 현상들이 단번에 앞뒤가 맞아떨어지기 시작하기는 했다. static 변수는 시스템내의 모든 사용자가 공유하는 변수이니까 고객A가 쓰는 화면에서 입력한 데이터가 고객B가 입력한 데이터로 바뀌는 것도 얼마든지 가능한 일이었다. 당연히 있어서는 안되는 일이기 때문에 자바 프로그래머들은 static 변수를 전역변수로 사용하지 않고 정말로 본연의 의미에 충실하게 정적으로 사용하는 방법에 대해서 꽤 강도높게 트레이닝을 하고, 그런 연습이 되지 않는 개발자는 보통 static 변수를 아예 사용하지도 않고 절대 변하지 않는 static 상수만 사용한다. 그리고 당연하게도 프로젝트 내에는 static 변수를 사용해서 데이터를 저장하는 바보같은 코드는 없었다. static 변수가 없다면 전역 변수도 없는 것이고, 도대체 왜 프로젝트에 자꾸 전역변수라는 불쾌한 단어가 등장하는지 도무지 알 수가 없었다.


그러나 프로젝트의 고급 개발자들은 나 같은 초급 개발자가 도저히 상상하지 못할 영역의 원인을 찾아냈다. '컴포넌트들이 싱글턴으로 생성된다고 합니다!' 라는 말이 전달되었을 때, 그게 도대체 전역변수와는 무슨 관계이며 데이터 오염과는 무슨 상관이냐 라는 얼빠진 표정으로 설명하러 내려온 선배를 바라보다가, '싱글턴 컴포넌트 안에서는 인스턴스 변수가 전역변수가 되어버리지 않느냐'라는 선배의 친절한 설명에 정신적으로 벼락을 맞은 기분을 느낄 수 밖에 없었다.


스프링 프레임워크는 화면을 처리하는 클래스, 업무 로직을 처리하는 클래스, 데이터베이스 입출력을 저장하는 클래스를 모두 컴포넌트라고 부르고 각각을 컨트롤러, 서비스, DAO라고 부른다. 이러한 컴포넌트들의 인스턴스는 고전적인 자바 프로그램들과는 다르게 개발자가 생성을 하여 사용하는 것이 아니라 스프링 컨테이너가 필요할 때 생성을 해서 사용하게 되는데, 이러한 자동화된 인스턴스의 생성이 시스템이 극히 효율적으로 동작할 수 있도록 만들어준다. 그 정점에 있는 것이 싱글턴 컴포넌트였다.


싱글턴 패턴은 특정 객체의 인스턴스를 최초에 단 하나만 만들고, 이후 해당 객체를 사용할 때마다 이전에 만들어둔 객체를 가져다 쓰게 해주는 패턴이었다. 객체가 단 한 번만 생성되기 때문에 메모리나 시스템 자원의 효율성은 극도로 높아질 수 밖에 없었다. 각각의 메소드가 데이터를 받아서 일정한 처리를 하고 반환값을 내놓는 공장의 기계와도 같은 웹 시스템에서는 더더욱 그 활용성이 높아졌고, 이 때문에 스프링 프레임워크는 별다른 지정을 하지 않을 경우 컴포넌트를 모두 싱글턴으로 생성한다.


각 클래스에 선언된 변수는 자바에서는 보통 필드(Field)라고 부르고 이러한 변수들은 인스턴스가 생성되면 인스턴스 마다 존재하기 때문에 보통 인스턴스 변수(Instance Variable)라고 부른다. 이에 비해서 Static 변수들은 클래스 당 하나씩만 존재하기 때문에 클래스 변수(Class Variable)라고 부른다. 당연히 데이터를 담아두는 객체들은 데이터를 모두 인스턴스 변수에 저장하게 되는데, 사용자의 데이터를 저장할 목적으로 인스턴스 변수들을 잔뜩 담아두는 클래스를 보통 Value Object(VO) 혹은 Data Transfer Object(DTO) 라고 부른다. 사용자의 데이터를 처리하는 것이 주 목적인 대부분의 시스템에서 이러한 VO는 어마어마하게 많은 종류가 만들어지고 또 사용된다. 때문에 인스턴스 변수를 위험하다고 생각하는 사람은 거의 없다.


그 인스턴스 변수가 싱글턴 컴포넌트에 속하지만 않는다면 말이다.


시스템 내에 단 하나만 존재하는 싱글턴 컴포넌트의 인스턴스 안에서, 인스턴스 변수는 절묘하게도 시스템 내에 단 하나만 존재하는 전역변수가 되어버린다. 그럴 수도 있겠다는 생각을 하지 못한 것은, 보통 인스턴스 변수는 VO 안에나 선언하고, 컨트롤러나 서비스 같은 컴포넌트 클래스 안에는 다른 컨트롤러, 서비스와 같은 컴포넌트들만 인스턴스 변수로 선언하지 일반적으로 데이터를 담아두는 변수를 거기에 선언하는 경우는 없기 때문이었다. 각각의 메소드들이 독립적으로 동작하는 스프링 프레임워크의 구조상 굳이 컴포넌트에 인스턴스 변수를 선언해서 거기에 데이터를 저장할 하등의 이유가 없었다. 하지만 프로젝트 초창기에 누군가가 무심결에 데이터를 인스턴스 변수에 저장하는 코드를 만들어냈고, 그 코드는 레퍼런스가 되어서 상당히 많은 클래스들이 아무 생각 없이 데이터를 인스턴스 변수에 저장하기 시작했다. 마치 프로메테우스의 첫 장면 처럼 퍼져나간 잠재적인 결함은 많은 사람들이 시스템을 동시에 사용해보지 않으면 발견되기 어렵다는 절묘한 조건으로 테스트 기간을 조용한 잠복기로 넘길 수 있었고, 프로젝트가 오픈한 뒤에야 전면적인 증상을 발현시켜서 프로젝트를 죽여가고 있었다.


비상이 걸렸다. 전역변수가 될 수 있는 클래스들의 목록이 뽑혀나오기 시작했고, 원인이 파악되었으니 당장 해결하라는 불호령이 여기저기에서 울려퍼지기 시작했다. 사실 해결책은 의외로 단순했다. 인스턴스 변수가 문제이니 인스턴스 변수를 제거하고, 해당 변수를 모두 메소드 내의 지역 변수(Local Variable)로 바꾸면 끝나는 일이었다. 하지만 문제는 시스템은 이미 오픈해서 운영단계로 넘어갔다는 점이고, 어찌되었던 인스턴스 변수를 지역 변수로 바꾸는 일은 기계적으로 할 수 있는 일은 아니었다. 해당 변수가 사용되는 로직을 모두 살펴보고 문제가 없는지 확인한 뒤 수정하고, 충분한 테스트를 거쳐서 운영서버에 반영해야 되는 꽤 신중한 수정이었다. '우리 고객님들이 불편해하고 있지 않느냐! 1분이라도 빨리 수정하지 못하겠느냐!'라고 외치는 높으신 분들에게는 제안하기 어려운 해결책이었다.


그래서 뼈를 깎는 심정으로 선배들이 제안한 방법은, 모든 인스턴스 변수를 내부 클래스로 감싸는 방식이었다. 이렇게 하면 각 지역변수에서는 새로운 인스턴스를 선언하고 그 안에 있는 변수를 사용하기 때문에 싱글턴 컴포넌트 내에 있는 변수라고 할지라도 각각의 업무 요청마다 독립적으로 저장될 것이 보장되었다. 제법 합리적인 해결책이라는 생각이 들었지만, 한편으로는 인스턴스 변수를 지역 변수로 바꾸는 것에 비해서 조금 더 기계적인 해결책일 뿐 위험성은 여전하다는 생각이 들었다.


점심 시간이 얼마 남지 않았을 시점이었다. 높으신 분들의 초조함이 어깨를 짓누르고 있었다. 역시나 인스턴스 변수를 클래스로 감싸는 것이 지금 선택할 수 있는 최선일까 잠시 고민해봤다. 오랫동안 고민을 할 수는 없었던 것이, '완벽한 해결책을 찾으려고 조금 늦었습니다'라는 변명이 도저히 통할 수 있는 분위기가 아니었기 때문이었다. 도대체 왜 스프링 프레임워크는 컴포넌트를 모두 싱글턴으로 생성해서 우리에게 이런 시련을 주는 것일까 원망스러웠다. 이 프로젝트에 들어오기 전까지 스프링 프레임워크를 확장하고 배포하고 교육하는 프로젝트에서만 2년 동안 일했었는데, 결국 2년간 쌓아온 스프링 프레임워크와의 신뢰관계가 이렇게 실전 프로젝트에서 단번에 무너지는건가 싶었다.


그런데 문득 떠오르는 것이 있었다. 신입사원이던 당시 나는 스프링 프레임워크를 프로젝트에 들어와서 처음 배웠고 뭔가 제대로 배우기도 전에 프레임워크 교육의 강사로 교육을 진행하게 되었었다. 내용도 이해를 못 하고 뭔가를 가르친 다는 것은 말도 안되는 일이었기 때문에 프레임워크 교재와 강의자료를 읽고 또 읽고 이해하려고 노력했던 시절이 있었다. 스프링 프레임워크가 컴포넌트 생성을 싱글턴으로 하는 것이 디폴트 설정이라는 것도 그 때 외웠던 내용 중 하나였다. 수료테스트 때 나오는 거니까 잘 봐두시라고 멘트를 날렸던 기억도 있었다.


싱글턴 설정이 디폴트라는 것은, 바꾸어 말하면 설정을 바꿀 수도 있다는 말이었다. 당시에는 xml에서 컴포넌트를 선언했기 때문에 xml에다가 설정을 했었었다 지금은 어노테이션(Annotation)으로 컴포넌트를 선언하니까 분명히 컴포넌트의 생성 방식을 바꾸는 명령어도 있을 것이다. 프로젝트에 인터넷이 되지 않아서 핸드폰으로 잠시 찾아보고 곧 익숙한 단어를 찾을 수 있었다. 프로토타입(Prototype)이라는 키워드는, 싱글턴과 반대되는 동작을 했다. 필요할 때마다 기존 인스턴스를 재활용하는 것이 아니라 새로운 인스턴스를 생성해서 사용한다. 그렇다면 이 클래스들이 디폴트 설정을 따라가지 않도록 프로토타입 선언을 추가해주면 인스턴스 변수에 의한 데이터 오염도 사라지는 것이 아닐까?


공명심에 매몰되어 버린 신입사원들 처럼 '제가 답을 찾았습니다!'라고 외치면서 주목받는 것은 바보같은 짓이라는 것을 알고 있었기에 옆 자리에 있는 선배에게 조용히 물어봤다. '선배님, 이거 프로토타입으로 선언하면 해결되지 않을까요?' 종이에 몇가지 케이스를 그려서 설명을 했다. 잠시 바라보던 선배가 '될 것 같은데요?'라는 대답을 했고, 두 명이 된다고 했으니 이건 되는거다 라는 확신으로 후배에게 '문제가 발생하는 클래스 맨 위에 @Prototype 이라고 적어주세요. 아니아니 거기 말고 그 위에. 예, 거기. 다른 클래스도 좀 해주고 점심 빌드때 반영되게 커밋 좀 해주세요' 라고 부탁했다.


잠시 뒤 점심시간이 되었고 빌드 서버는 긴급반영을 시작했다. 배포가 완료된 뒤 숨죽여서 데이터들의 흐름을 살펴보였고, 동맥경화에 걸린 듯이 이유없이 정체되어 있던 데이터들이 매우 정확한 값을 가지고 프로세스를 타기 시작하는 것을 보고 선배와 나와 후배 모두가 속으로 환호성을 질렀다. 그리고 밥 먹으러 가자는 말을 차마 못하시고는 '그런데 그거 말야 언제까지..'라고 조심스럽게 말을 꺼내는 PL님에게 '그거요? 아까 10분만에 다 해결했는데요?'라는 내 인생 최고의 멘트를 날릴 수 있었다.


오픈 이후 가장 가벼운 마음으로 점심을 먹고 돌아와서 다른 결함을 처리하고 있는데, 갑자기 가장 높으신 분이 나와 선배를 호출했다. 보통 높으신 분들이 일천한 개발자들을 직접 부르는 일은 없었기 때문에 무척 긴장한 상태로 회의실에 들어갔다. 들어가자 마자 '전역변수 그거 문제 말야. 언제까지 해결되나?'라고 불어보시길래 '이미 다 해결했습니다!'라고 말하고 싶은 충동을 억누르면서 '테스트도 해보고 제대로 안 되었을 때 버퍼 같은 것도 생각하면 일주일 정도 걸리지 않을까요?'라는 원론적인 대답을 했다가 '수단과 방법을 가리지 말고 내일까지 다 끝내라'라는 카리스마 넘치는 지시를 받았다.


최선을 다하겠다는 결연한 표정으로 회의실을 나오면서 생각했다. 학교에서 배운 소프트웨어 공학에 근거해서 생각해보면, 프로그램에 지대한 영향을 미칠 수 있는 큰 수정은 반드시 여러 단계를 거쳐서 검증된 뒤에 사용자에게 반영되어야 된다. 그렇지 않으면 더 큰 사고가 발생할 수 있기 때문이다. 하지만 이론적인 공학론은 이 전쟁터 같은 현장에서는 전혀 통할 수도 용납될 수도 없는 이론이었고, 그래서 우리는 맨날 살얼음판 위에서 말뚝을 박는 심정으로 프로그램을 고쳐나갔다. '그래도 이미 다 고쳐놔서 다행이에요'라고 선배와 이야기 하면서 자리로 돌아와서, 후배한테 '아까 그거 이제 잘 돌아가죠? 이상없죠?'라고 물어보고 정말 잘 돌아간다는 정말 기쁜 대답을 받고 나서야 묵시록처럼 펼쳐졌던 전역변수의 지배에서 벗어날 수 있었다.


나는 이 프로젝트의 영웅이었고, 구원자였다. 그러니까 다른 120명의 영웅들과 마찬가지로 말이다. 비록 하루 하루 신화처럼 갱신해나가는 그 놀라운 업적에도 불구하고 매일 매일 당장 와서 고쳐내라는 말에 사무실을 뛰어다니고 이 따위로 만들고 밥은 왜 먹으러 나가냐는 말에 상처를 받고 이미 처리한 100개의 결함에 대한 뿌듯함 보다는 아직 처리하지 못한 1개의 결함에 대한 불안감 때문에 퇴근을 못하고 있기는 했지만 그렇다고 해서 무엇보다도 소중한 인생의 한 조각을 프로젝트의 오픈에 기꺼이 양보한 그 모든 사람들의 노력이 폄하될 수 있는 것은 아니었다.


프로젝트가 오픈으로부터 달려나가고 있었다. 놀라울 정도로 시시했던 오픈의 순간을 뒤로하고 프로젝트는 진짜 완성을 향해, 끝없이 추격해오는 미완성으로부터 도망쳐나가고 있었다. 여러가지로 미숙했던 우리도 이 모든게 다 끝나고 나면 조금 더 완숙해지지 않을까 하는 약간의 기대와 함께.

'에세이' 카테고리의 다른 글

10년이 지났다  (1) 2015.12.15
개발의 현황  (0) 2015.09.23
당신의 생각이 알고 싶어  (1) 2014.03.18
Last man standing  (0) 2013.11.16
근로자의 날  (0) 2013.05.20
댓글