1화: 출근 첫날부터 자바 8한테 두들겨 맞았다
강남대로 한복판, 통유리로 둘러싸인 고층 빌딩 7층 엘리베이터 문이 열리는 순간 특유의 공기가 피부에 와닿았다. 갓 뽑아낸 믹스커피의 달콤 쌉싸름한 향과 밤샘 야근의 흔적이 눅눅하게 밴 차가운 에어컨 바람. 수십 대의 듀얼 모니터가 사방에서 뿜어내는 푸르스름한 열기 속에서, 기계식 키보드의 타건음이 정갈하면서도 불규칙한 리듬으로 울려 퍼지고 있었다. 바로 내가 오늘 처음 출근한 SI 전문 기업, 새벽기술 플랫폼 1팀의 전경이었다.
비록 첫 직장이 전형적인 레거시 SI 회사라 할지라도 내 발걸음엔 망설임이 없었다. 대학 시절부터 부트캠프 멘토링까지, 나는 컴파일러의 깐깐한 수호자인 Rust와 함께 살아온 개발자였다. 소유권(Ownership) 시스템과 수명주기(Lifetime)의 엄밀함을 통달했고, zero-cost abstraction의 미학을 몸으로 익힌 자부심이 있었다. 동기들이 메모리 누수와 세그멘테이션 폴트로 밤새 비명을 지를 때, 나는 컴파일러가 선사하는 완벽한 타입 안전성 아래서 느긋하게 커피를 홀짝이던 부류였다. 비록 대규모 실무 운영이나 고부하 배포 실무를 직접 겪어본 적은 없었지만, 내 가슴속엔 굳건하고 근거 있는 오만이 자리 잡고 있었다.
'Java 8과 Spring Boot 2.1이라... 뭐, 까마득한 옛날 유물이지만 프로그래밍 언어와 백엔드 시스템의 본질이야 다 거기서 거기지.'
경영지원팀에서 신규 입사자용 업무 세트를 받아 들었다. 묵직한 무게감을 자랑하는 새벽기술 표준 노트북과 사내 VPN 보안 토큰, 사내 메신저 계정, 그리고 SVN 형상 관리 저장소 접속 정보가 적힌 종이 한 장이었다. 묵직한 노트북을 품에 안으니 비로소 직장인이 되었다는 실감이 조금 들었다.
"강현호 씨 맞으시죠? 이쪽으로 오세요."
나를 반갑게 맞이해 준 사람은 플랫폼 1팀을 이끄는 박정수 팀장이었다. 둥근 뿔테 안경 너머로 지친 기색이 역력했지만, 인상은 서글서글했다.
"반갑습니다, 팀장님. 오늘부터 플랫폼 1팀으로 출근하게 된 강현호입니다. 잘 부탁드립니다."
겉으로는 가장 예의 바른 신입사원의 미소를 지었지만, 속으로는 이미 회사의 기술 스택을 둘러보며 혼자만의 등급 평가를 내리고 있었다.
"오느라 고생했어요, 현호 씨. 우리 팀 자리가 이쪽입니다. 인사들 하세요. 오늘 새로 합류한 강현호 씨입니다."
팀장의 소개에 모니터 뒤에서 두 사람이 고개를 들었다. 먼저 밝은 인상의 서지수 선배가 손을 흔들었다.
"어서 오세요, 현호 씨! 반가워요. 모르는 거 있으면 편하게 물어보세요."
"감사합니다, 지수 선배님. 열심히 배우겠습니다."
그리고 그 옆자리, 키보드를 조용히 두드리고 있던 한지훈 선배가 가볍게 고개를 숙였다. 무채색 티셔츠에 무심한 눈빛. 전형적인 숙련 직장인의 아우라였다.
"안녕하세요, 한지훈입니다."
"아, 네! 한지훈 선배님, 잘 부탁드립니다!"
속으로는 '다들 순해 보이시네. 내가 빠르게 적응해서 레거시 코드 구조를 신기술 스타일로 확 개선해 드리면 다들 놀라겠지?' 하는 기분 좋은 상상에 젖어 들었다.
박정수 팀장이 내 파티션 책상 위에 두꺼운 바인더 하나를 툭 내려놓았다.
"자, 현호 씨. 첫날이니까 너무 부담 갖지 말고, 우리 팀이 주력으로 관리하는 고객사 한빛상사의 1월 정기 배치 연동 시스템 runbook이랑 인프라 구조부터 읽어보세요. 코드도 SVN에서 체크아웃 받아서 로컬 빌드가 잘 돌아가는지 확인해보시고요."
"네, 팀장님! 바로 확인해서 로컬 환경 구축 완료하겠습니다."
나는 자신만만하게 대답하고 노트북 전원을 켰다. 보안 프로그램을 서너 개 설치하고 VPN 토큰을 연결한 뒤, 안내받은 SVN 저장소 URL에서 `trunk` 소스코드를 받았다.
'자, 이제 빌드를 돌려볼까?'
터미널을 열고 프로젝트 루트 디렉터리로 이동했다. 폴더 구조를 보니 단일 프로젝트가 아니었다. 공통 코어부터 도메인, 웹, 배치, 외부 연동 레이어까지 14개의 서브 모듈이 그물망처럼 얽혀 있는 거대 모노리스(Monolith) 구조였다.
나는 거침없이 명령어를 입력했다.
`mvn clean package`
엔터를 누르는 순간, 터미널 스크롤이 미친 듯이 올라가기 시작했다. 묵직한 자바 가상 머신이 올라가고, 사내 Nexus 서버와 통신하며 POM 파일과 의존성 JAR 라이브러리들을 긁어모으는 로그가 쏟아졌다.
[INFO] Scanning for projects...
[INFO] Building Module 01: Core-Common 1.0.0-SNAPSHOT
[INFO] Building Module 02: Core-Domain 1.0.0-SNAPSHOT
...
'음, 역시 의존성 다운로드 때문에 처음엔 좀 걸리겠지.'
나는 의자에 턱을 괴고 화면을 바라보았다. 1분, 2분... 5분이 지났다.
터미널 로그는 끊임없이 올라가고 있었지만, 모듈 04를 빌드하는 시점에서 진행률이 도무지 나아질 기미를 보이지 않았다. 사내 폐쇄망 Nexus 서버와의 의존성 라이브러리 검증, MyBatis 매퍼 XML 검증, 공통 및 배치 모듈 컴파일과 테스트를 거쳐 마지막 웹 WAR와 배치 실행 JAR를 패키징하는 단계가 차례로 이어지며 묵직한 쿨러 팬 소리만 거세졌다.
'어? 왜 이렇게 느리지? 증분 빌드 캐시나 의존성 락이 안 작동하나?'
10분이 지났다. 내 머릿속에서는 빌드 시스템에 대한 비판이 꿈틀거리기 시작했다.
'Rust에서도 매크로 전개나 대규모 크레이트의 Cold Build는 결코 빠르지 않다. 하지만 멀티 크레이트 워크스페이스 분리와 증분 빌드(Incremental Build), sccache 캐싱을 제대로 구성했다면 수정되지 않은 코드를 매번 다시 훑을 이유가 없다. 왜 이 자바 시스템은 의존성 그래프의 변경점을 감지하지 못하고 매번 처음부터 전체 재빌드를 강요하는 걸까?'
12분쯤 지났을 때, 옆자리 서지수 선배가 믹스커피 두 잔을 들고 다가왔다. 종이컵 하나를 내 책상 위에 살포시 내려놓으며 서지수 선배가 가볍게 웃었다.
"현호 씨, 첫날이라 `clean`으로 전체 모듈 빌드 돌리는 거죠? 처음엔 사내 Nexus에서 3자 라이브러리랑 부모 POM 검증받느라 시간이 좀 걸려요."
"아, 네! 선배님. 원래 첫 로컬 환경 구축 시에는 항상 이렇게 전체 모듈을 통째로 빌드하나요?"
"그럼요. 첫날 전체 환경 잡을 때나 운영 통합 배포 전에는 `clean`으로 묶어서 전체 상호의존성을 다 검증하고, 평소 자기 모듈 수정할 때는 지훈 선배처럼 `.m2` 로컬 저장소 써서 영향받는 서브 모듈만 단독 빌드해요. 안 그러면 매번 개발하다 하루 다 지나니까요."
"아, 그렇군요! 설명 감사합니다, 선배님."
나는 겉으로는 가장 정중하게 고개를 숙였지만, 속으로는 여전히 회의적인 웃음을 지었다.
'실무진이 빌드 타임을 줄이려고 영향받는 서브 모듈을 직접 골라 단독 빌드하는 땜질식 요령이라니... 아키텍처 자체가 제대로 모듈화되고 바운디드 컨텍스트로 격리되어 있다면 이런 수동 선택에 의존할 필요조차 없을 텐데. 모듈 간 결합도가 너무 높으니 매번 수동으로 대상을 골라야 하는 구조인 거지.'
빌드가 15분을 넘어가는 동안, 나는 파티션 건너편 팀원들의 모습을 유심히 살폈다. 박정수 팀장은 붉은 펜을 들고 다음 주 정기 배포 스케줄과 DB 쿼리 실행 계획서를 꼼꼼히 검토하며 인덱스 스캔 비용을 짚어보고 있었고, 한지훈 선배는 마우스 클릭 한 번 없이 단축키만으로 SVN diff와 스테이징 서버의 thread dump를 덤덤하게 비교 분석하고 있었다. 모두가 각자의 영역에서 무서운 집중력으로 운영 실무를 처리하는 풍경이었다.
그리고 정확히 20분 14초가 지났을 때, 마침내 터미널에 빌드 완료 문구가 떴다.
[INFO] BUILD SUCCESS
[INFO] Total time: 20:14 min
'20분 14초... 진짜로 20분이 걸렸네. 하지만 드디어 내 로컬 환경 구축도 끝났다.'
내가 기지개를 켜며 숨을 돌리던 바로 그 순간이었다.
띠링! 띠링!
사내 메신저 알림음이 정적을 깨며 굉음처럼 울렸다. 서지수 선배와 한지훈 선배의 모니터 오른쪽 아래에 붉은색 경고 창이 솟아올랐다.
[긴급] 한빛상사 운영팀 PM 임동현: "플랫폼 1팀 팀장님, 한빛상사 정기 배치 연동 인터페이스에서 데이터 전송 실패 티켓 접수되었습니다. 즉시 확인 바랍니다."
박정수 팀장이 자리에서 벌떡 일어났다.
"지수 씨, 외부 연동 구간 타임아웃 로그랑 Oracle 세션 상태부터 먼저 확인해요. 지훈 씨는 배치 쓰레드 상태랑 스케줄러 큐 풀 확인해 주시고."
"네, 팀장님! 1월 정기 배치 데이터 송수신 구간 타임아웃 로그 수집하겠습니다."
사무실 공기가 순식간에 차갑게 경직되었다. 첫날부터 터진 진짜 장애 티켓의 등장에 내 심장도 순간 쿵쾅거렸다. 하지만 방금 빌드를 마친 내 듀얼 모니터에는 온전한 전체 소스코드가 떠 있었다. 나도 모르게 자신감이 다시 불끈 솟구쳤다.
'장애라고? 내가 방금 막 전체 모듈 빌드를 끝냈으니 전체 소스가 내 로컬 IDE에 온전히 로딩되어 있잖아. 레거시 코드 어디서 NullPointerException이 터졌거나 실수로 타입 캐스팅이 꼬였는지 소스 디버거를 붙여 찾아내면 첫날부터 내 존재감을 확실히 증명할 수 있겠는데?'
내가 의욕만 앞서 조급하게 키보드로 손을 가져가려 하자, 옆자리에서 가만히 모니터를 주시하던 한지훈 선배가 덤덤하게 내 노트북 화면 앞을 가로막았다.
"현호 씨."
"아, 네, 선배님! 제가 방금 로컬 빌드를 마쳤는데, 소스 디버거 붙여서 예외 터진 코드 위치부터 바로 찾아볼까요?"
한지훈 선배는 낮고 침착한 눈빛으로 나를 바라보며 조용히 말했다.
"급할수록 코드부터 건드리지 말고, 로그랑 runbook부터 읽고 가시죠."
<2화에서 계속됩니다>
놀랍게도 자바 8 스프링부트 2.x 쓰는 좆소가 아직도 많다
ㅇㅅㅇ
GPT한테 만화로 만들어 달라해봐
그건 아직 프로그램 안만들었음. 추후 만들예정 ㅇㅅㅇ 손으로 하기 귀찮음
https://m.dcinside.com/board/programming/2933816?recommend=1
이거처럼 만들어봐
진짜 본격적인 컴하하 소설이네 ㅋㅋ 근데 은근 재밌다