Showing Posts From

야근

배포 전 마지막 체크리스트: 놓친 게 뭐지?

배포 전 마지막 체크리스트: 놓친 게 뭐지?

오후 4시의 슬랙 메시지 "오늘 배포 맞죠?" 기획자 메시지다. 알고 있다. 3일 전부터 알고 있었다. 손이 떨린다. 커피를 너무 마신 건지, 아니면 그냥 배포 전이라서 그런 건지 모르겠다.체크리스트를 연다. 노션에 만들어둔 거다. 지난번 배포 때 새벽 2시에 롤백하면서 "다음엔 이런 일 없게 하자"고 다짐하며 만든 것. 근데 이게 문제다. 체크리스트를 볼 때마다 항목이 늘어난다. 처음엔 10개였다. 지금은 37개다. 체크리스트라는 이름의 불안 데이터베이스 백업. 체크. 스테이징 환경 테스트. 체크. API 문서 업데이트. 체크. 슬랙 배포 공지. 체크. 여기까진 기본이다. 문제는 여기서부터다. "혹시 인덱스 추가한 거 확인했나?" 확인했다. 근데 다시 확인한다. EXPLAIN 결과를 또 본다. 쿼리 플랜이 이상하진 않다. 근데 프로덕션 데이터로도 테스트했나? 스테이징이랑 데이터 양이 다른데? 다시 확인한다."Redis 캐시 워밍업은?" 아. 맞다. 배포하고 첫 요청 때 DB 커넥션 폭증하는 거. 지난번에 그거 때문에 30초간 타임아웃 났었지. 체크리스트에 추가한다. 38개. "로그 레벨 확인했나?" 디버그 모드로 돌린 적 있었나? 없다. 근데 확인한다. 혹시 모르니까. "헬스체크 엔드포인트는?" 당연히 있다. 근데 실제로 동작하나? 5분 전에 확인했는데 또 확인한다. 이게 무한루프다. 후배의 PR "형, PR 올렸어요." 오후 5시. 배포 3시간 전. 제목을 본다. "hotfix: 결제 금액 소수점 처리". 소수점? 결제에? 심장이 뛴다. "이거 급한 거야?" "아뇨, 발견해서 고쳤어요." 발견? 언제? 어디서? 코드를 본다. Math.round() 하나 추가한 거다. 테스트 코드도 있다. 근데 불안하다. 결제는 민감한 부분이다. 이거 지금 넣어야 하나? 다음 배포로 미뤄야 하나? "스테이징에서 테스트했어?" "네." "얼마로?" "1000원이요." 1000원. 실제 결제는 십만원대도 있는데."십만원으로도 해봐." "네." 기다린다. 10분. 답이 온다. "됐어요." 됐다고? 뭐가? 테스트가 통과했다는 건가, 아니면 문제없다는 건가? 전화한다. 직접 확인하는 게 빠르다. 통화 15분. 괜찮은 것 같다. 근데 '것 같다'가 문제다. "일단 빼자. 다음 배포 때 넣어." "네..." 후배 목소리가 풀이 죽는다. 미안하다. 근데 배포는 조심해야 한다. 체크리스트에 항목 추가. "긴급 수정사항 재확인". 39개. 오후 6시의 회의 "배포 전 최종 확인 회의 시작하겠습니다." 누가 시작하자고 했나. 기억이 안 난다. 근데 매번 한다. 참석자: 나, 후배 둘, 기획자, QA, DevOps 형. 기획자가 묻는다. "이번 배포 범위가 어떻게 되죠?" 말한다. 회원가입 플로우 개선, 상품 상세페이지 성능 개선, 관리자 대시보드 차트 추가. "회원가입 플로우에서 소셜로그인도 테스트했죠?" 했다. 구글, 카카오, 네이버. 전부 했다. "탈퇴한 회원이 재가입하는 케이스는?" 아. 안 했다. "확인해볼게요." 회의 중간에 노트북 연다. 스테이징 접속. 테스트 계정 하나 탈퇴시킨다. 재가입 시도. 에러. "unique 제약조건 위반". 이메일 컬럼에 unique 인덱스가 걸려있는데, soft delete 방식이라 탈퇴해도 데이터가 남는다. "이거 고쳐야겠는데요." 기획자가 묻는다. "시간 얼마나 걸려요?" 모른다. 30분? 1시간? DB 마이그레이션까지 하면 2시간? "배포 연기할까요?" 연기. 그 단어만 들어도 한숨 나온다. 기획자도, 대표님도, 전부 오늘 배포 알고 있다. "아니요. 고치겠습니다." 회의 끝. 오후 6시 40분. 긴급 수정 손이 빠르게 움직인다. 이럴 때는 생각하지 말고 코딩한다. deleted_at 컬럼 추가. unique 인덱스를 partial index로 변경. WHERE deleted_at IS NULL. MySQL은 partial index를 지원하지 않는다. 망했다. 다른 방법. unique 제약조건 제거하고, 애플리케이션 레벨에서 체크. 안 된다. 동시성 이슈. 같은 이메일로 동시 가입하면? 세 번째 방법. email + deleted_at 복합 unique. 이것도 안 된다. deleted_at이 NULL이면 중복 허용된다. 네 번째 방법. 탈퇴할 때 이메일을 수정한다. "deleted_{timestamp}_{original_email}". 이건 된다. 근데 더럽다. 정말 더럽다. 시간이 없다. 일단 이걸로 간다. 코드 수정. 10분. 테스트 코드 작성. 15분. 스테이징 배포. 5분. 테스트. 10분. 동작한다. 더럽지만 동작한다. PR 올린다. 제목: "hotfix: 탈퇴 회원 재가입 이슈 수정". DevOps 형한테 메시지. "긴급 수정 하나 더 들어갑니다." "알았어. 근데 배포 시간 좀 늦어질 것 같은데." "얼마나요?" "30분?" 오후 7시 30분. 원래 배포 시간. 지금 8시로 밀린다. 체크리스트를 다시 본다. 39개 항목. 하나하나 다시 확인한다. 배포 30분 전 체크리스트 완료. 전부 체크했다. 근데 불안하다. 뭔가 놓친 것 같다. 모니터링 대시보드를 연다. 그라파나. 지난 일주일 트래픽 패턴을 본다. 평일 저녁 8시. 동접 2000명. 초당 요청 150개. DB 커넥션 풀 사용률 60%. 괜찮다. 여유롭다. 근데 혹시 모른다. 배포하면 캐시가 날아간다. 첫 요청들이 몰린다. DB 커넥션이 순간적으로 튄다. "혹시 캐시 워밍업 스크립트 준비했나?" 준비 안 했다. 체크리스트엔 있는데 실제론 안 했다. 지금 만들까? 30분 안에? 불가능하다. "캐시 없이 버틸 수 있나?" 계산한다. 캐시 미스율 100%라고 가정. 모든 요청이 DB로. 초당 150개. DB는 초당 500개까지 처리 가능하다고 했다. AWS 스펙 문서에서 봤다. 근데 그건 단순 SELECT 기준이다. JOIN 많은 쿼리는? 집계 쿼리는? 모른다. "일단 가자." 결정했다. 캐시 워밍업 없이 간다. 문제 생기면 그때 대응한다. 체크리스트에 항목 하나 더 추가. "배포 후 캐시 모니터링". 40개. 배포 시작 오후 8시. DevOps 형이 메시지 올린다. "배포 시작합니다." 슬랙 배포 채널에 공지 올라간다. "@channel 배포 시작. 약 15분 소요 예정." 그라파나를 본다. 초당 요청 수. DB 커넥션. CPU 사용률. 메모리. 디스크 IO. 전부 정상이다. 아직은. Jenkins 로그가 흐른다. [INFO] Building application... [INFO] Running tests... [INFO] All tests passed. [INFO] Creating Docker image... [INFO] Pushing to registry...손에 땀이 난다. 마우스가 미끄럽다. 후배가 옆에서 묻는다. "형, 괜찮을까요?" "모르지." 솔직한 대답이다. 배포는 매번 도박이다. 아무리 체크해도 변수는 있다. [INFO] Deploying to production... [INFO] Updating service... [INFO] Waiting for health check...헬스체크. 30초 걸린다. 가장 긴 30초다. [INFO] Health check passed. [INFO] Deployment completed.완료. 그라파나를 본다. 트래픽이 들어온다. 초당 요청 수가 튄다. 150에서 200으로. DB 커넥션. 60%에서 85%로. 응답 시간. 평균 200ms에서 800ms로. 에러율. 0%에서 0.3%로. 심장이 뛴다. 배포 후 10분 슬랙에 메시지가 터진다. "로그인이 느려요." "상품 페이지 로딩 중..." "관리자 페이지 접속 안 돼요." 패닉이다. 응답 시간을 본다. 계속 오른다. 800ms, 1200ms, 1500ms. 에러율. 0.3%, 0.5%, 1.2%. 뭐가 문제지? 로그를 연다. Elasticsearch. 에러 로그를 검색한다. java.sql.SQLException: Timeout: Pool empty. Unable to fetch a connection in 30 seconds.커넥션 풀. 비었다. 예상했던 거다. 캐시가 없어서 DB 쿼리가 몰렸다. "커넥션 풀 늘려야겠어요." DevOps 형한테 메시지. "DB 커넥션 풀 100에서 200으로 늘려주세요." "지금요?" "네, 지금요." 설정 변경. 재시작. 5분. 다시 본다. 응답 시간 떨어진다. 1500ms에서 1000ms로. 800ms. 600ms. 에러율. 1.2%에서 0.8%. 0.5%. 0.2%. 안정화된다. 슬랙 메시지. "다시 괜찮아진 것 같아요." 한숨 쉰다. 등에 땀이 찬다. 배포 후 1시간 오후 9시. 모니터링 지표 전부 정상이다. 트래픽: 초당 요청 160개 응답 시간: 평균 250ms 에러율: 0.05% DB 커넥션: 70% 배포 전보다 약간 느리다. 캐시가 아직 다 안 차서 그렇다. 체크리스트를 다시 본다. 40개 항목. 결국 놓쳤다. 커넥션 풀 증설. 체크리스트엔 없었다. 추가한다. 41개. "다들 수고했어요." 팀원들한테 메시지 보낸다. 답장 온다. "수고하셨습니다." "고생했어요 형." "역시 형이에요." 역시가 아니다. 운이 좋았을 뿐이다. 퇴근 오후 10시. 사무실을 나선다. 혼자다. 다른 팀원들은 9시에 나갔다. "먼저 갈게요." "네, 조심히 가세요." 혼자 남아서 1시간 더 모니터링했다. 안정화 확인. 엘리베이터를 탄다. 거울에 비친 내 얼굴. 피곤하다. 폰을 본다. 아내 메시지. "저녁 먹었어?" "아직." "편의점에 뭐 있어. 데워먹어." 고맙다. 집에 도착한다. 10시 40분. 편의점 도시락을 데운다. 전자레인지 돌아가는 소리. 3분. 소파에 앉는다. 도시락을 먹는다. 맛은 모르겠다. 넷플릭스를 켠다. 뭔가 틀어놓는다. 뭔지 모른다. 폰을 본다. 슬랙. 알림 없다. 다행이다. 그라파나 앱을 연다. 습관이다. 지표 확인. 전부 정상. 앱을 닫는다. 폰을 내려놓는다. 눈을 감는다. 그래도 다음날 출근한다. 팀원이 말한다. "어제 배포 잘됐죠?" "응. 좀 삐걱거렸는데." "그래도 잘 넘어갔잖아요." 맞다. 잘 넘어갔다. 기획자가 메시지 보낸다. "어제 배포 건 잘 적용됐어요. 고객 반응 좋네요." 고객 반응. 좋다고 한다. CS 채널을 확인한다. 어제 배포 관련 문의. 없다. 회원가입 전환율 대시보드. 전일 대비 12% 상승. 상품 페이지 체류시간. 평균 23초 증가. 숫자로 보니 실감난다. 체크리스트를 연다. 41개 항목. 다음 배포 때도 이걸 볼 것이다. 또 항목이 늘어날 것이다. 또 불안할 것이다. 그래도 배포는 한다. 이게 개발자다.체크리스트는 늘어나고, 불안은 줄지 않지만, 배포는 계속된다. 그게 우리 일이니까.

코드 리뷰에서 '이건 안 됩니다'라고 말하기의 어려움

코드 리뷰에서 '이건 안 됩니다'라고 말하기의 어려움

코드 리뷰에서 '이건 안 됩니다'라고 말하기의 어려움 시작은 슬랙 알림 아침 10시. 슬랙 알림이 울렸다. "김 개발님, PR 올렸습니다~ 확인 부탁드려요!" 이모티콘까지 붙어있다. 귀엽다. 하지만 나는 안다. 저 PR을 열면 내 30분이 사라진다는 걸. 커피 한 모금 마시고 깃허브를 켰다.파일 하나에 500줄 첫 줄부터 한숨이 나왔다. public class UserService { // 500줄의 메서드들... }500줄이 한 파일에 있다. 메서드 하나가 100줄이다. if문이 5단 중첩이다. 작동은 한다. 테스트도 통과한다. 효율적이기까지 하다. 하지만 읽을 수가 없다. 나는 스크롤을 내리며 생각했다. "이거 어떻게 말하지?" 후배는 2년차다. 나름 열심히 한다. 야근도 마다 않는다. 근데 코드가 이렇다. 직책이 있으면 쉽다. "팀장 지시사항입니다" 하면 끝이다. 근데 나는 그냥 선임이다. 사실상 테크 리드인데 직책이 없다. 연봉도 별로 안 높다. "이건 안 됩니다" 라고 말할 권한이 애매하다. 댓글 창 앞에서 10분 커서가 댓글 입력창에서 깜빡인다. 뭐라고 쓸까. "이 코드는 가독성이 떨어집니다" - 너무 딱딱하다. "메서드를 좀 더 나눠주시면..." - 너무 약하다. "이렇게 하면 나중에 유지보수가..." - 잔소리 같다. 결국 이렇게 썼다. "수고하셨습니다. 몇 가지 제안 드립니다." 제안. 안전한 단어다. 명령이 아니다. 거절 가능하다.그리고 댓글을 달기 시작했다. "이 메서드가 100줄이 넘어서 한눈에 파악하기 어려울 것 같습니다. 책임별로 나눠보면 어떨까요?" "if 중첩이 깊어서 읽기 어렵습니다. Early return 패턴을 고려해보시면..." "변수명이 a, b, c로 되어있어서 의도를 파악하기 어렵습니다." 댓글 7개를 달았다. 20분이 걸렸다. 말투를 신경 썼다. "하세요" 대신 "하면 어떨까요". "틀렸습니다" 대신 "어려울 것 같습니다". 제출 버튼을 누르기 전에 다시 읽었다. 기분 나쁘게 들리지 않나. 너무 약하게 들리지 않나. 5분 더 고민했다. 그리고 제출을 눌렀다. 30분 뒤의 답장 "아 그렇군요! 그럼 이렇게 수정하면 될까요?" 답장이 빨랐다. 기분 나쁘지 않은 것 같다. 다행이다. 근데 수정본을 보니 별로 안 바뀌었다. 메서드 이름만 바꿨다. 구조는 그대로다. 여전히 100줄이다. "음... 제가 말씀드린 건 구조를 나누는 거였는데요." 이렇게 쓰려다 지웠다. 너무 직접적이다. "좋습니다! 다만 메서드 길이도 함께 조정하면 더 좋을 것 같아요." 또 제안이다. 명령이 아니다. "아 네! 그럼 어떻게 나누는 게 좋을까요?" 질문이 왔다. 이제 내가 예시를 보여줘야 한다.브랜치를 따서 직접 수정했다. 30분이 걸렸다. 500줄을 5개 클래스로 나눴다. 메서드는 20줄 이내로 줄였다. 변수명을 의미 있게 바꿨다. "이런 식으로 나누면 각 클래스의 책임이 명확해집니다." 커밋을 푸시하고 링크를 보냈다. "오 이해했습니다! 감사합니다!" 이모티콘 3개가 붙었다. 1시간이 지났다. 내 일은 못 했다. 직책 없는 테크 리드의 딜레마 팀장이 있긴 하다. 근데 팀장은 코드를 안 본다. 관리만 한다. 회의만 한다. 실제 기술 결정은 내가 한다. 아키텍처도 내가 짠다. 코드 리뷰도 내가 한다. 근데 직책은 없다. 명함에 "선임 연구원"이라고 적혀있다. 연구는 안 하는데. 월급은 6500이다. 동기들은 7천 넘게 받는다고 한다. "직책 주면 안 되냐"고 팀장한테 물었다. "위에서 아직 승인이 안 났어요. 조금만 기다리세요." 1년째 기다리는 중이다. 직책이 없으니까 말하기가 애매하다. "이건 안 됩니다"라고 딱 잘라 말할 수 없다. 권한이 없다. 그래서 항상 "제안"한다. "부탁"한다. "의견"을 낸다. 피곤하다. 점심시간의 고민 점심은 김치찌개집에 갔다. 사장님이 이름을 안다. "개발님 오셨어요~" 단골이다. 주 3회는 온다. 김치찌개를 먹으면서 생각했다. '내가 너무 약하게 말하나?' '아니면 적당한 건가?' '다른 회사 시니어들은 어떻게 하지?' 스택오버플로우에 비슷한 질문이 있었다. "How to give code review feedback without sounding harsh?" 답변들을 읽었다."Be specific and objective" "Focus on the code, not the person" "Suggest alternatives instead of just criticizing"다 알고 있다. 근데 한국 회사에서는 다르다. 위계가 있다. 눈치가 있다. 분위기가 있다. "이 코드는 SOLID 원칙을 위반합니다"라고 말하면 학술 논문이다. "형, 이거 좀 이상한 것 같은데요"라고 말해야 먹힌다. 근데 나는 형도 아니고 팀장도 아니다. 그냥 선임이다. 밥을 다 먹고 사무실로 돌아왔다. 슬랙에 알림이 7개다. 오후 3시, 두 번째 PR 또 알림이 왔다. "김 개발님, PR 수정했습니다!" 열어봤다. 여전히 별로다. 클래스를 나누긴 했는데 책임 분리가 안 됐다. 그냥 줄 수만 줄였다. 또 댓글을 달아야 한다. 커서가 깜빡인다. 뭐라고 쓸까. "이건 여전히 개선이 필요할 것 같습니다" - 너무 애매하다. "제가 보여드린 예시와 조금 다른 것 같아요" - 비교하는 것 같다. "다시 한 번 수정 부탁드립니다" - 짜증난 것 같다. 5분 고민했다. 그리고 이렇게 썼다. "방향은 좋습니다! 다만 클래스 간 의존성을 조금 더 정리하면 좋을 것 같아요. 각 클래스가 하나의 책임만 가지도록 해보시겠어요?" 또 제안이다. 칭찬 먼저 하고 제안한다. 샌드위치 피드백이다. 좋은 말 - 개선점 - 좋은 말. 근데 빵이 너무 얇다. 속이 뻔히 보인다. 회의 중에도 생각남 4시에 주간 회의가 있다. 기획자가 발표한다. "이번 기능은 간단합니다." 간단하다는 말이 나오면 복잡한 거다. 팀장이 묻는다. "개발 기간 얼마나 걸릴까요?" 나를 본다. "2주 정도 필요할 것 같습니다." "1주면 안 될까요?" "백엔드 구조를 새로 짜야 해서..." "기존 코드 활용하면 되지 않나요?" 기존 코드가 엉망이라서 못 쓴다. 리팩토링 필요하다. 근데 말할 수 없다. "기존 코드가 엉망입니다"라고 하면 누구 책임이냐고 물어본다. 내 책임이다. 내가 리뷰했으니까. "...최대한 단축해보겠습니다." 회의가 끝나고 자리로 돌아왔다. 슬랙에 또 알림이다. "김 개발님, 이해가 잘 안 가서요. 잠깐 설명 부탁드려요." 일어나서 후배 자리로 갔다. 설명하는 20분 "여기 이 부분이요." 후배가 화면을 가리킨다. "이걸 왜 나눠야 하는지 모르겠어요." 내가 작성한 예시 코드를 보고 있다. "지금은 UserService가 너무 많은 일을 하잖아." "네." "사용자 조회, 생성, 수정, 삭제, 권한 체크, 알림 발송까지." "네." "나중에 알림 로직만 바꾸고 싶으면?" "...UserService를 수정하면 되는데요?" "그럼 사용자 조회 기능도 영향받을 수 있어." "아..." "그래서 책임을 나누는 거야. 알림은 NotificationService로." "아 그렇구나!" 이해했다는 표정이다. 20분이 걸렸다. PR 댓글로는 5분이면 쓸 내용이다. 근데 직접 설명하면 20분이다. 자리로 돌아왔다. 시간을 봤다. 5시다. 오늘 내 코드는 한 줄도 못 썼다. 퇴근길 지하철에서 6시에 퇴근했다. 지하철에 앉아서 폰을 봤다. 유튜브에 추천 영상이 떴다. "시니어 개발자가 코드 리뷰하는 법" 봤다. 외국 개발자가 나온다. 영어로 말한다. "Be direct but kind." "Explain why, not just what." "It's about the code, not the coder." 다 맞는 말이다. 근데 저 사람은 직책이 있을 거다. Senior Engineer라고 명함에 적혀있을 거다. 나는 선임 연구원이다. 연구 안 하는. 댓글을 봤다. "우리 팀장은 그냥 '이거 왜 이렇게 짰어?' 하고 끝남 ㅋㅋ" "권한 없으면 말 안 먹힘. 그냥 포기." 공감이 됐다. 집에 와서 7시에 집에 도착했다. 아내가 야근이다. 라면을 끓였다. 신라면에 계란 1개. 먹으면서 슬랙을 봤다. 습관이다. "김 개발님 감사합니다! 이해했어요!" 후배가 메시지를 보냈다. 기분이 좋았다. 잠깐. 그리고 다음 메시지가 왔다. "그런데 이 부분은 원래대로 해도 될까요? 지금 방식이 더 익숙해서요." 한숨이 나왔다. 익숙하다는 건 핑계다. 바꾸기 귀찮다는 소리다. 댓글을 쓰려다 멈췄다. '또 설득해야 하나?' '그냥 놔둘까?' '나중에 문제 생기면 내가 고치면 되지.' 근데 그게 계속 쌓인다. 레거시가 된다. 결국 이렇게 답했다. "일단 현재 방식으로 머지하시고, 다음 스프린트 때 리팩토링 태스크로 잡읍시다." 타협이다. 읽음 표시가 떴다. 답은 없다. 아마 다음 스프린트 때도 우선순위 밀린다. 밤 10시, 침대에서 넷플릭스를 틀었다. 근데 집중이 안 된다. '내가 너무 약하게 말하나?' '직책이 있으면 다를까?' '다른 회사로 이직하면 나아질까?' 생각만 했다. 이직하려면 코테 준비해야 한다. 알고리즘 공부해야 한다. 피곤하다. 주말에 하자. 주말은 늦잠 자고 치킨 먹는 날이다. 폰을 내려놨다. 잠이 안 온다. 슬랙 알림이 또 울릴까봐 무음으로 해뒀다. 근데 자꾸 폰을 본다. 습관이다. 알림은 없다. 다행이다. 아내가 11시에 들어왔다. "오늘 어땠어?" "그냥 그랬어. 너는?" "디자인 수정 요청 5번 받았어." "힘들었네." "너도?" "응." 더 말하지 않았다. 둘 다 피곤하다. 다음날 아침 9시에 출근했다. 커피를 뽑았다. 아이스 아메리카노. 자리에 앉아서 슬랙을 켰다. 알림 3개다. 첫 번째: "김 개발님, 새 PR 올렸습니다~" 두 번째: "급한데 리뷰 부탁드려요!" 세 번째: "이번엔 잘한 것 같아요 ㅎㅎ" 깃허브를 켰다. 또 500줄이다. 커피를 한 모금 마셨다. 댓글 입력창을 열었다. 커서가 깜빡인다. "수고하셨습니다. 몇 가지 제안 드립니다." 오늘도 제안한다. 명령이 아니다. 직책이 생길 때까지. 아니면 이직할 때까지.직책 없는 테크 리드는 오늘도 제안한다. 조심스럽게.

명절에만 내려가는 지방의 부모님 근황

명절에만 내려가는 지방의 부모님 근황

명절에만 내려가는 부모님 전화는 미루고, 죄책감은 쌓이고 부모님 전화번호. 화면에 떠 있다. 콜. 콜. 받아야 한다. 알고 있다. 손가락이 안 움직인다. '뭐라고 말하지?' 일이 많다고? 그건 이미 알고 계신다. 잠은 잘 잤냐고? 하루에 4시간 정도. 밥은? 라면. 화면이 꺼진다. 응답 안 함. 딩동. 카톡 오셨다. 엄마다. "아들, 괜찮아? 요즘 바쁜지?" 어제 생각났을 거다. 아무 이유 없이.연 2회의 약속 명절. 설과 추석. 딱 2번. "내려올 때 뭐 먹고 싶어?" "그냥 집밥이 좋아요." "에이, 뭘 자꾸 그래. 소고기 구워줄게." 기차표를 끊는다. 4시간. 지방행 기차 안. 옆 자리 할머니가 도시락을 먹는다. 냄새가 좋다. 집이 생각난다. 부모님이 역에 나와 계신다. 엄마 머리가 좀 더 희어졌나. 아빠 등이 굽었나. 작년엔 이렇지 않았는데. '언제 봤더라?' 반년 전. 그 사이에 부모님은 또 반년을 사셨다. 밥상이 차려진다. 아내는 없다. 일이 있다고 했다. 엄마는 알겠다고 하셨다. "일이 많긴 해?" "네. 많습니다." "그래도 밥은 잘 먹어야 해." "네." "고등학교 때부터 밥 못 먹더니 여전하네." 웃음이 나온다. 엄마가 반찬을 또 담아주신다. 시간이 이렇게 빨리 흐르나. 3일이 다가 온다 설날 아침이 거의 다 됐다. 아침 5시. 엄마가 일어나신다. 아빠도. "언제 올라가?" "오후 기차 탈게요." "그래? 일이 많긴 해." 모두가 알고 있다. 내가 떠난다는 걸. 밥을 다시 먹는다. 엄마가 만든 밥. "요거랑 이것도 싸줄게. 기차에서 먹어." 비닐봉지를 줄 번이. 집이 들어있다. 기차역에서. 엄마가 운다. 슬쩍. "또 언제 와?" "추석에요. 6개월만." "그래. 잘 있어. 밥 잘 먹고." 기차가 움직인다. 창밖이 흐릿해진다. 엄마가 손을 흔드신다. 보인다. 보이지 않을 때까지.전화를 받는 이유들 집에 와서 슬랙이 울린다. 배포 브랜치 충돌. 누가 merge 받았어? 일로 돌아온다. 전화는 또 미룬다. 그런데 밤 11시쯤이다. 엄마 전화. "아들, 뭐 해?" "그냥 일이 좀..." "아, 그래. 잠깐만. 아빠 말씀 있으신대." 아빠 목소리. "응? 잘 있냐?" "네, 잘 있습니다." "요즘 회사는?" "그냥 그렇습니다." 얘기할 게 없다. 아빠도 아는데. "그래. 밥은 잘 먹고." "네." 엄마가 다시 받으신다. "오빠네 카톡 봤어? 요즘 애들이..." 듣는다. 일은 손에 있지만 듣는다. 이게 전화의 정체다. 뭔가 중요한 얘기가 있어서가 아니다. 그냥 목소리가 듣고 싶은 거다. "알았어요, 엄마." "그래. 잘 자고." 끊는다. 슬랙 메시지는 여전히 파란색으로 깜빡인다.죄책감은 내 것 전화를 자주 못한다. 이건 사실이다. 일이 많아서? 피곤해서? 뭐라고 변명할 수도 있다. 근데 다 핑계다. 아내도 엄마한테 자주 전화한다. '뭐 해?' '밥 먹어?' 그 정도. 그런데 난 못 한다. 뭐라고 얘기할지 모르는 게 아니다. 말하는 게 어색해서다. 부모님을 사랑한다고 말하지 못한다. (너무 어색하잖아.) 그냥 밥 먹으라고 한다. 밥이 답이라고 생각하는 것처럼. 부모님도 안다. 명절에 만나서 쓸데없는 얘기 하고 가는 게 전부라는 걸. 그래도 기다린다. 명절을. 명절의 다른 의미 기차표를 끊는다. 달력을 본다. 내 삶에 이 날들이 표시된다. 빨간 날. 명절은 일을 멈추는 날이다. 슬랙을 끈다. 배포를 연기한다. 긴급 버그도 내일이다. 대신 밥을 먹는다. 엄마 손으로 만든. 아빠가 신문을 본다. 엄마가 밥을 담는다. 나는 먹는다. 시간이 멈춘다. 아니, 멈추지 않는다. 그냥 느껴진다. "밥 더 먹어." "고마워요." "뭐 감사해. 엄마 손으로 하는 게 얼마나 남으려고." 며칠이 끝난다. 떠난다. "추석에 또 봐." 그때까지 살아야 한다. 부모님도. 나도. 6개월. 그 사이에 또 뭐가 나이가 들겠지. 전화를 하지 않아도 안다. 부모님은 내 일이 많다는 걸. 내 삶이 바쁘다는 걸. 그래도 기다린다. 내 목소리를. 자주 전화하지 못한다. 명절 때만 내려간다. 그게 전부다.명절 후 기차 안. 창밖은 점점 도시가 된다.

점심시간 김치찌개집 단골이 되다

점심시간 김치찌개집 단골이 되다

점심시간 김치찌개집 단골이 되다 "김개발님 오셨어요" - 이름으로 불리는 순간 아, 진짜 이 맛을 뭐라고 설명해야 할까. 단순히 음식 때문만은 아니다. 어제도 갔고, 오늘도 갔고, 내일도 갈 것 같은 이 불안감과 묘한 중독성을 말하는 거다. 회사 출입구에서 나와 왼쪽으로 50미터, 골목 안으로 들어가면 낡은 간판에 '할매 김치찌개'라는 글씨가 흐릿하게 남아있다. 처음 그곳을 찾아간 건 신입사원 때였다. 배고프고, 근처에 뭐가 있나 돌아다니다가 우연히 들어간 식당. 그때만 해도 그냥 "아, 여기 괜찮네" 정도의 느낌이었다. 가격도 저렴했고, 맛도 무난했고, 사장님이 불친절하지도 않았다. 그게 함정이었다. 지금은 상황이 완전히 달라졌다. 몇 주 전부터 사장님이 내 이름을 부르기 시작했다. "김개발님 오셨어요!"라고. 처음엔 당황했다. 내가 언제 이름을 말했나 싶어서. 나중에 알고 보니 회사 사람들이 자주 와서, 그들이 "김개발이 자주 온다"고 한 말을 사장님이 기억하고 있었던 거다. 그게 얼마나 무섭고 부끄러운 일인지 아나?그런데 여기서 웃긴 게, 내가 인정하기 싫지만 그 순간이 정말 좋다는 거다. 회사에서는 에러 처리하고, PR 리뷰하고, 기획자의 말도 안 되는 요구사항을 들어야 하는데, 이 골목 안 식당에서만큼은 "어서오세요"가 아니라 "김개발님"이라고 불린다. 그 사람이 나를 기억한다는 사실만으로도 뭔가 내가 존재한다는 걸 확인하는 느낌이다. 개발자는 모니터에만 붙어있다가 번아웃되는 직업인데, 여기서 10분간 국물에 고개를 묻고 있으면 그게 다 사라진다. 사실 점심시간이라는 게 백엔드 개발자의 유일한 진짜 휴식시간이다. 아침 9시에 들어오면 슬랙이 이미 100개 정도 쌓여있고, 배포 관련 문제로 팀원들이 나를 찾고, 레거시 코드는 왜 이렇게 짜놨는지 답답하고, 회의는 또 회의고... 그 와중에 점심이 되면 일단 컴퓨터에서 눈을 떼는 게 규칙이다. 눈을 못 떼면 "빨리 돌아와야 해" 같은 불안감에 밥도 못 넘긴다. 단골손님의 특권 - 맥락 없이 통하는 소통 "어제 묵은지는 정말 좋더라, 오늘 또 소비했어요?" 사장님이 나한테 하는 인사가 이 정도다. 완전한 문장도 아니고, 생략도 많고, 문법도 이상하지만 그게 뭔가 따뜻하다. 마치 엄마가 "밥 먹었어?" 하는 것처럼. 누군가 내 일상의 디테일을 기억하고 있다는 것 자체가 현대 도시생활에선 거의 사치에 가깝다. 나도 그에 맞춰서 비슷하게 대답한다. "네, 정말 맛있어요. 추천 받고 매일 와도 질리지 않아요." 이런 식의 기계적인 대답이 아니라, 그냥 "네, 진짜요"라고만 말한다. 그럼 사장님이 웃는다. 깊은 의미는 없겠지만, 그 웃음이 얼굴에 찬 피로를 녹인다.메뉴 변화도 나는 항상 감지한다. 몇 주 전에 묵은지를 한 번 써봤던 날, 사장님이 "이거 좋지?" 하면서 자기 엄지손가락을 펴 보였다. 나는 "진짜 있어야 할 것 같은데 왜 이제야 했어요?"라고 말했고, 그 이후로 늘 기본으로 깔려있다. 이게 얼마나 사치스러운 경험인지 알아? 음식점에서 내 입맛을 기억해주고, 그에 맞춰 메뉴를 조정해주는 일이. 회사에서는 절대 이런 일이 일어나지 않는다. 내가 얼마나 열심히 일해도, PR 리뷰를 퀄리티 있게 해도, 버그를 다 잡아내도, 사람들은 "어? 그럼 이것도 좀 봐줄래?" 하고 자연스럽게 더 많은 걸 요구한다. 내 취향이나 상태 따위는 관심 없다. 그냥 한 명의 자원이고, 리소스일 뿐이다. 근데 여기선 다르다. "요즘 바쁜 것 같은데 피곤해 보여. 국 많이 줄까?"라는 질문이 나온다. 응? 내가 뭐라고 한 적도 없는데? 그냥 얼굴을 봤을 뿐인데? 이게 진짜 음식점 사장님과의 상호작용이 맞나 싶을 정도다. 거의 매일인데 뭔가 불안한 그 느낌 그런데 이게 문제다. 나는 지금 이 상황에 거의 중독된 상태다. 점심시간에 다른 곳을 먹을 생각을 하면 뭔가 불안하고, 이 식당을 못 가는 날은 온종일 마음이 뜬뜬하다. 전에는 가끔 건너편 회사원 식당에서 콩나물밥도 먹고, 라면도 사 먹고 그랬는데 이제는 생각도 안 난다. "아 그거요" - 내 입버릇처럼, 이건 뭐라고 설명해야 할까. 강박증인가? 아니면 그냥 일 때문에 지친 마음이 찾아낸 피난처인가? 내일도 갈 것 같고, 그 다음날도 갈 것 같은데, 이게 정상인가 싶기도 한다. 며칠 전에는 회사에서 집에 가기 전에 여기 들렀다. 점심도 먹었는데 왜 또 들렀냐고? 커피를 마실 겸. 아니, 거짓말하자. 그냥 여기 있고 싶었다. 따뜻한 국물을 들이켜고, 누군가 "어서오세요"가 아니라 내 이름을 부르는 곳에 있고 싶었다. 그 10분 안에 모든 것이 괜찮은 것처럼 느껴진다. 레거시 코드도, 불합리한 기획도, 없는 승진도, 다 사라진다.문제는 여기가 한계라는 거다. 사장님은 내 이름을 부르지만, 내 삶의 문제를 해결하는 건 아니다. 오늘도 회사에 돌아가면 또 다른 배포가 있을 테고, 후배의 코드는 또 엉망일 테고, 기획자는 또 "간단하죠?"라고 할 거다. 하지만 점심시간 12시부터 12시 40분까지는, 이 골목의 따뜻한 김치찌개 냄새 속에서 나는 "김개발"이 아니라 그냥 누군가로부터 기억되는 누군가다. 아내한테 이 이야기를 했더니 웃었다. "당신, 거기 진짜 매일 가네. 이미 사장님이 당신 좋아하는 거 아니야? 당신도 거기 좋아하는 거 아니고?" 맞다. 이건 상호적인 관계다. 내가 단골이 되고 싶어 한 게 아니라, 어느 순간 둘 다 이렇게 되어버렸다. 사장님도 나를 보면 반갑고, 나도 사장님을 보면 안심이 된다. 내일도 점심시간 12시에 그곳으로 갈 거다. 아마도 모레도, 그다음날도. 완벽하지 않은 내 일이나 다른 복잡한 상황들을 정당화하려고 이렇게 글을 쓰는 건 아니겠지만, 적어도 이 10분 40초는 나를 단순하게 만들어준다. 코드도 없고, 버그도 없고, 기획자도 없는 그곳에서 나는 그냥 밥 먹는 사람이 되면 된다. 혹시 누군가 이 글을 읽으면서 "아, 나도 그런 곳이 있었는데"라고 생각할 수도 있겠다. 그 공간의 이름이 뭐든 상관없다. 사장님이 너를 기억하는 식당일 수도, 창가 카페일 수도, 산책로의 벤치일 수도 있다. 중요한 건 그곳이 너를 알아준다는 거다. 별 것 아닌 것 같지만, 이 시대에 누군가에게 기억되는 것만큼 큰 위로는 없다.결국 난 김치찌개가 아니라 그곳에서 불리는 이름이 그리워 하는 거겠지.

펜 돌리면서 버그를 찾는 개발자의 생각법

펜 돌리면서 버그를 찾는 개발자의 생각법

펜 돌리면서 버그를 찾는 개발자의 생각법 어제 오후 3시, 또 그 현상이 나타났다. 프로덕션 서버에서 특정 사용자의 결제 데이터가 중복으로 저장되는 버그. 이미 이틀을 싸우고 있는 녀석이다. 내 옆자리 후배 이준호는 집중해서 자기 일을 하고 있었다. 나는 천천히 펜을 집었다. 펜을 돌리는 것. 이건 버그와 싸울 때 나의 무기다. 모니터 앞에 앉아서 눈은 코드를 쫓지만, 손가락 사이에서 돌아가는 펜이 진짜 일을 한다. 누군가는 명상이라고 하겠지만, 나는 이걸 그냥 "생각하는 시간"이라고 부른다.펜 한 바퀴가 가진 의미 버그는 절대 논리적으로만 찾아지지 않는다. 이건 내가 7년간 개발하면서 배운 가장 확실한 진리다. 어제 스택오버플로우에서 본 것처럼 타임아웃 설정 부분도 있고, 동시성 이슈가 있을 수도 있고, 혹은 내가 전혀 생각하지 못한 다른 곳에서 뭔가 튀어나올 수도 있다. 이런 여러 가능성들이 머리 안에서 동시에 맴돌 때, 펜을 돈다. 펜이 한 바퀴 도는 동안 내 뇌는 다음을 한다:에러 로그를 다시 한 번 읽는다 결제 로직의 진입 지점을 추적한다 혹시 놓친 try-catch 블록이 있나 생각한다 동시에 진입하는 두 개의 요청이 있을 가능성을 본다그리고 펜이 세 바퀴쯤 돌 때쯤, 뭔가 떠오른다. "혹시... 트랜잭션 격리 수준?" 속으로 외치고 싶지만, 옆자리 준호가 있다. 내가 너무 집중한 나머지 펜을 돌리는 속도가 점점 빨라진 건 알고 있다. 소리도 나고. 타닥타닥. 쓸딱쓸딱. 학창시절 수학 시험 본다고 볼펜을 돌릴 때 그 속도다. 옆자리 시선의 무게 완전히 솔직하게 말하자면, 펜을 돌리면서 동시에 신경 쓰는 게 있다. 바로 내 옆자리다. 개발팀 레이아웃은 이렇다. 나와 준호가 마주 보는 책상에 앉아 있고, 그 옆에 은지가 앉아 있다. 우리 셋이 사실상 가장 자주 버그를 만나는 팀이기도 하다. 그래서 매일 누군가는 펜을 돌리고 있다. 특히 어려운 버그가 나타났을 때, 나는 두 가지를 동시에 한다:버그를 찾는다 옆자리에 방해가 되지 않을까 신경 쓴다이건 굉장히 비효율적이다. 하지만 이게 사람이다. 그날 오후, 펜을 돌리던 중 가만히 준호의 방향을 봤다. 그는 여전히 자기 화면에만 집중해 있었다. 그러면서도 뭔가 느낀 듯 몇 번이나 방향을 살짝 틀어 내 쪽을 쳐다봤다. "버그 있어?" 하고 묻지는 않았지만, 그 시선만으로 충분했다. 그리고 그 순간 나는 또 다른 가능성을 떠올렸다.생각하는 펜, 말하는 펜 시간이 지나면서 나는 펜을 단순히 "생각 도구"로만 쓰는 게 아니라, "소통 도구"로도 쓰게 되었다. 회의 중에 누군가 기획자가 "이거 간단하죠?"라고 물을 때, 나는 펜을 돌린다. 그리고 그것을 보는 나머지 팀원들은 안다. "어라, 김개발이가 펜을 돌린다? 뭔가 깊게 생각할 게 있는 건가?" 한 번은 CEO 앞에서 프로젝트 보고를 했을 때도 있었다. 내가 펜을 돌리기 시작하자 팀장이 슬슥 내 손목을 눌렀다. "진정해, 괜찮아." 펜을 돈다는 것은 내 안의 신호다. 심각함의 척도다. 1회전: 좀 이상한데? 3회전: 뭔가 크리티컬한 이슈가 있는데? 5회전 이상: 아, 이거 진짜 골치 아픈 버그네. 그리고 옆자리 준호도 그걸 알게 되었다. 어느 날부턴 내가 펜을 돌리면 자기도 슬쩍 준비한다. "어? 내가 리뷰를 받게 되나?" 하고. 실제로 많은 경우 그렇다. 내가 펜을 돌리다가 갑자기 "야, 너 이 부분 봤어?" 하며 모니터를 보여주게 되니까. 침묵의 협력 버그를 찾는 과정에서 가장 아름다운 순간은 언제인가. 그건 누군가 나의 펜 도는 소리를 들었을 때다. 어제 그 결제 버그는 결국 내가 푼 게 아니었다. 내가 펜을 3분 정도 돌리고 있다가, 은지가 옆에서 조용히 말했다. "혹시 데이터베이스 컨넥션풀 리셋 타임이랑 타이밍 맞나?" 정확했다. 정확했어. 나는 그 순간 웃음이 나왔다. 우리는 말이 없었지만, 펜을 돌리는 내 행동만으로도 같은 방향으로 생각하게 된 것이다. 아무도 "진정하세요" 하지 않았다. 아무도 "이미 확인했어?" 라고 질문하지 않았다. 그냥 은지는 조용히 나오면서, 자신이 생각한 것을 던져주었다. 이게 바로 개발팀의 협력이다. 코드를 공유하고, 깃허브 이슈를 열고, PR을 리뷰하는 것도 좋지만, 가끔은 그냥 "옆에 있어주는 것"이 최고의 협력이 될 때가 있다.왜 옆자리를 신경 쓰나 지금 생각해보면 이상하다. 왜 내가 펜을 돌리면서 옆자리를 신경 쓰는가. 사실은 이렇다. 개발자들은 대부분 혼자인 것처럼 느껴진다. 깊은 코드의 우물 속에 혼자 떨어져 있는 것 같다. 하지만 나는 항상 옆자리를 본다. 왜냐하면 그 옆자리가 내가 혼자가 아니라는 증거이기 때문이다. 연봉이 높다고 해서 행복한 건 아니고, 위치가 높다고 해서 덜 외로운 것도 아니다. 하지만 옆에 누군가 있다는 건 다르다. 특히 그 사람이 내가 펜을 돌릴 때 뭔가를 느끼고, 나도 그 사람이 펜을 돌릴 때 뭔가를 느낀다면 더욱. 매일 아침 9시에 출근해서 커피 3잔을 마시고, 점심은 김치찌개를 먹고, 배포일에는 10시까지 남아있는 이 루틴. 그 속에서 나를 지탱해주는 건 사실 성취감도 기술도 아니었다. 그냥 옆자리였다. 옆자리에서 "혹시 데이터베이스 컨넥션풀 리셋 타임이랑 타이밍 맞나?"라고 물어주는 은지. 내가 펜을 돌릴 때도 자기 일을 계속하지만 가끔 슬쩍 쳐다보는 준호. 팀장이 PR 리뷰를 몰아줄 때도 옆에서 "힘내" 하는 눈빛으로 응원해주는 그들. 펜은 계속 돈다 오늘도 슬랙 알림이 울렸다. "프로덕션 환경에서 API 응답이 간헐적으로 500 에러를 반환합니다." 내 손이 자동으로 펜을 집었다. 손가락 사이에서 펜이 회전을 시작했다. 옆자리 준호와 은지가 동시에 내 쪽을 봤다. 말 없이. "또 뭐야?" 라고 말하지 않았지만, 그들의 눈빛이 말해주고 있었다. 그리고 이번엔 내가 먼저 입을 열었다. "500 에러라고? 너희는 프로젝트에서 최근에 뭐 바뀐 거 없어?" 은지가 답했다. "어제 배포에서 타임아웃 설정만 조정했는데?" 그리고 준호가 덧붙였다. "혹시 그거 때문일까?" 이렇게 버그는 해결된다. 혼자가 아니라 함께. 펜을 돌리는 내 습관은 이상해 보일 수도 있지만, 사실은 아주 자연스러운 개발자의 신호 언어다. 그리고 그 신호를 받아주는 옆자리의 존재는, 내가 이 일을 계속할 수 있게 해주는 가장 소중한 것이다. 옆자리에 방해가 될까봐 신경 쓰면서도 펜을 도는 이유는, 사실은 나와 함께할 누군가를 바라는 마음이 아닐까. 버그를 혼자 잡는 것도 좋지만, 함께 잡는 게 훨씬 낫다는 걸 알기 때문이다. 내일도 펜을 돌릴 것 같다. 그리고 옆자리가 있을 것 같다. 그것으로 충분하다.펜 하나로 말 없이 나누는 이 신뢰가 결국 버그보다 더 중요한 것 같다.

Spring Boot 버전 업그레이드: 일주일을 잃다

Spring Boot 버전 업그레이드: 일주일을 잃다

Spring Boot 버전 업그레이드: 일주일을 잃다 아, 그거요. 이 이야기를 하려면 먼저 지난 월요일 아침으로 돌아가야 한다. 커피를 마시면서 슬랙을 보다가 기술 뉴스 채널에서 "Spring Boot 3.2.0 릴리즈! 획기적인 성능 개선과 새로운 기능들"이라는 메시지를 봤다. 그 순간의 나는 정말 한심한 수준의 낙관주의자였다. 마치 신작 게임이 나왔다고 생각하고 선구매하는 게이머처럼, 나는 "오, 이 정도면 업그레이드 간단하겠는데?"라고 생각했다. 지금 생각해보니 그게 모든 고통의 시작이었다. 호기심 같은 업그레이드의 시작 현재 프로젝트는 Spring Boot 2.7.15 버전을 쓰고 있었다. 안정적이고, 버그도 별로 없고, 팀원들도 익숙한 버전. 근데 왜 하필 그날 업그레이드를 시작했을까? 이유는 정말 초라한 수준이었다. "요새 Spring Boot 3.2를 안 쓰면 구시대 개발자처럼 보일 거 같은데?" 이 정도의 이유였다.build.gradle 파일을 열고 springBootVersion을 3.2.0으로 바꿨다. 엔터를 쳤다. IDE는 즉시 빨간 줄을 그었다. 대량의 빨간 줄이었다. 처음엔 괜찮을 거라고 생각했다. 점진적으로 해결하면 되겠지, 하는 마음으로. 결국 모든 프로젝트의 죽음은 이런 순진함에서 시작된다. 의존성 지옥의 나락으로 첫 번째 문제는 Gradle 버전이었다. Spring Boot 3.2.0은 Gradle 7.6 이상을 요구했는데, 우리 프로젝트는 7.3을 쓰고 있었다. 간단하다고 생각했다. Gradle 버전을 올리면 되겠지. 그런데 Gradle 버전을 올리니까 이번엔 Java 버전 문제가 나왔다. 프로젝트에서 Java 11을 쓰고 있었는데, Spring Boot 3.x는 최소 Java 17을 요구한다. 알겠다, Java 버전도 올리자. Java 17로 올렸다. 이제 정말 되겠지? 아니었다. 이건 마치 도미노 같았다. 한 개를 넘치니까 다 넘어지는 그런 느낌이었다. 프로젝트에서 쓰던 Querydsl이 호환성 문제를 일으켰다. Maven 중앙 저장소를 뒤져보니, 우리가 쓰던 Querydsl 4.4.0은 Spring Boot 3.x와 호환성 문제가 있었다. 최신 버전인 5.0.0으로 올려야 했다. Querydsl 5.0.0으로 올렸다. 그럼 이제 되겠지? gradle build를 실행했다. 또 다른 에러가 나왔다. javax 패키지들이 사라졌다는 것이었다. Spring Boot 3.0부터 javax.*에서 jakarta.*로 완전히 전환되었기 때문이다. 이건 단순 버전 업 문제가 아니라 전체 구조 변경이었다. // 이게 모두 바뀌어야 함 import javax.persistence.Entity; import javax.persistence.GeneratedValue;// 이렇게 import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue;프로젝트 전체에서 javax를 jakarta로 바꾸는 작업이 시작되었다. IDE의 대량 검색-바꾸기 기능을 썼지만, 손으로 일일이 확인해야 하는 경우도 많았다. 왜냐하면 javax.servlet도 바꿔야 하고, javax.validation도 바꿔야 하고, javax.mail도... 이 작업만 3시간이 걸렸다. 화요일: 첫 번째 깨달음 화요일 오전. 슬랙에서 후배 개발자가 물어봤다. "선임님, 이 PR 리뷰 좀 해주실 수 있나요?" 나는 "오케이, 잠깐만" 이라고 했지만, 내 손은 여전히 EntityManagerFactory 설정 파일을 수정 중이었다. 일주일에 보기로 했던 신입 면접 준비도 날려먹었다. 점심 시간에 회사 근처 김치찌개집에서 사장님과 뵈면서도 "요새 너무 바빠서 ㅋㅋㅋ" 하고 웃었지만, 사실 웃음 뒤에는 절망이 묻어있었다."Spring Boot 3.2 하면서 뭐 이렇게 복잡해?" 라고 생각했지만, 알고 보니 그건 시작일 뿐이었다. 수요일: Jackson의 배신 수요일이 되자, 빌드 에러는 줄었지만 이번엔 런타임 에러가 터지기 시작했다. API 응답이 JSON으로 변환되지 않았다. 원인은 Jackson 라이브러리 업데이트였다. 예전 버전에서는 기본적으로 작동하던 기능들이 새 버전에서는 명시적으로 설정해야 했다. // 기존엔 이게 자동으로 됐는데... LocalDateTime.now()// 이제는 이렇게 설정해야 함 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createdAt;프로젝트 곳곳에 있는 API 응답 DTO 수십 개를 일일이 확인하고 수정했다. 각각의 LocalDateTime에 어노테이션을 달아야 했다. 이 작업을 하면서 나는 진짜로 "차라리 Spring Boot 2.7 유지하는 게 낫지 않을까?"라는 생각을 처음으로 진지하게 해봤다. 슬랙에 투덜거렸다. "이거 왜 이리 복잡하냐고... 대충 호환 모드 같은 게 없나?" 팀장이 답장했다. "그냥 고민 좀 해봐. 급할 건 없으니까." 하지만 그건 팀장 말이었고, 내 심리 상태는 이미 "이건 내가 해결해야 하는 문제"라는 강박에 빠져있었다. 목요일: 데이터베이스 커넥션의 악몽 목요일. 애플리케이션이 어느 정도 떠올랐다. 그런데 데이터베이스 커넥션에서 문제가 터졌다. Connection pool 에러였다. Spring Boot 3.x에서는 기본 데이터베이스 커넥션 풀이 HikariCP에서 다른 것으로 변경되었을 뿐 아니라, 설정 방식도 살짝 달라져있었다. # 예전엔 이게 먹혔는데 spring: datasource: hikari: maximum-pool-size: 20# 새 버전에선 이렇게 해야 함 (세부사항이 좀 다름) spring: datasource: hikari: max-lifetime: 1800000 idle-timeout: 900000설정 파일을 뒤지고, Spring Boot 공식 문서를 뒤지고, 스택오버플로우를 샅샅이 뒤졌다. "아 그거요" 하면서 몇 가지 설정을 건드렸더니, 로컬 환경에서는 돌아갔다. 근데 스테이징 환경에서는 안 돌아갔다. 왜냐하면 스테이징 환경은 우리 프로젝트가 쓰는 여러 마이크로서비스 중 하나일 뿐이었고, 다른 서비스들도 같은 데이터베이스를 쓰고 있었기 때문이다. 커넥션 풀 설정을 건드리니까 다른 서비스들의 연결이 끊어졌다. 데이터베이스 팀에 연락했다. 죄송합니다, 제가 실수했습니다. 다시 설정할 테니 잠깐만요. 금요일: 마이크로미터 메트릭 문제 금요일이 되자, 모니터링 시스템이 문제를 일으켰다. Prometheus 메트릭 수집이 안 되고 있었다. Spring Boot 3.x에서 메트릭 수집 방식이 바뀌면서 기존 설정이 더 이상 작동하지 않았다. Micrometer 라이브러리의 주요 메서드와 클래스 이름이 바뀌었다. // 예전 코드 MeterRegistry meterRegistry; meterRegistry.counter("custom.metric").increment();// 새 코드 (내부 동작 방식이 좀 다름) @Timed(value = "custom.metric") public void someMethod() { // ... }금요일 오후 3시. 나는 모니터링 알림이 작동하는 것을 보기 위해 필사적이었다. 왜냐하면 월요일에 본배포가 예정되어있었기 때문이다. 퇴근 시간을 넘겨서 계속 작업했다. 6시, 7시, 8시... 9시가 되어서야 메트릭 수집이 정상화되었다. 집에 도착한 건 10시가 넘었다. 아내는 이미 잠들어있었다. 나는 라면을 끓여먹고 침대에 쓰러졌다. 둘째 주 월요일: 통합 테스트의 지옥 둘째 주 월요일. 로컬 빌드는 성공했지만, CI/CD 파이프라인에서 테스트가 실패했다. "어? 로컬에선 되는데?" 이건 개발자가 가장 싫어하는 상황이다. 로컬 환경과 테스트 환경의 차이 때문이었다. 통합 테스트에서 쓰는 TestContainers의 버전과 Spring Boot 3.x의 호환성 문제였다. Docker를 통해 테스트 DB를 구성하는데, 이 과정에서 버전 미스매치로 인한 타이밍 이슈가 발생했다. 테스트를 하나씩 실행하면 성공하는데, 전체 테스트를 실행하면 일부가 실패했다. 이건 경합 조건(race condition) 같은 거였다. TestContainers 버전을 올렸다. 그럼 이제 되겠지? 아니었다. 이번엔 다른 테스트가 실패했다. 결국 나는 8시간을 테스트 디버깅에만 썼다. 마지막에는 테스트 타임아웃 설정을 조정하고, 데이터베이스 초기화 순서를 바꿔야 했다.셋째 주 초: 배포와 롤백의 악몽 업그레이드를 시작한 지 8일째. 드디어 본배포 준비가 됐다고 생각했다. 배포는 성공했다. 서버가 떠올랐다. 모든 것이 정상으로 보였다. 그런데 2시간 뒤, 모니터링 대시보드에서 에러율이 갑자기 올라갔다. 원인은 Spring Security 설정이었다. Spring Boot 3.x에서 보안 설정 방식이 바뀌면서, 기존 설정이 예상하지 못한 동작을 하고 있었다. 특정 엔드포인트에 대한 권한 체크가 너무 엄격해져있었다. 30분 뒤 롤백 결정. 내가 업그레이드한 Spring Boot 3.2 버전은 다시 2.7로 돌아갔다. 슬랙 타이머가 종료되었다. 돌아온 월요일: 후회와 깨달음 원점으로 돌아왔다. 일주일을 완전히 낭비했다. 이 시간에 내가 할 수 있었던 것들을 생각해봤다.신입사원 온보딩 프로세스 개선 레거시 코드 리팩토링 테크 로드맵 수립 아내와 시간 보내기 충분한 숙면대신 나는 뭘 했나? javax → jakarta 변환하고, 테스트 타임아웃 튜닝하고, Spring Security 설정을 삽질했다. 후배들이 물어봤다. "선임님, Spring Boot 3.2는 괜찮던데요?" "음, 아직 좀 이른 거 같아. 마이너 버전 유지하자." 팀장은 나에게 물었다. "이번에 뭘 배웠어?" 나는 웃었다. "아, 그거요. 버전 업그레이드는 정말 신중해야 한다는 거요." 얻은 교훈 (그리고 다음번엔 이렇게 할 거) 일주일을 낭비한 대가로, 나는 몇 가지 중요한 걸 배웠다. 먼저, 주요 메이저 버전 업그레이드는 절대 혼자 끙끙대며 하지 말 것. 팀과 함께 계획을 세우고, 명확한 일정과 롤백 계획을 세워야 한다. 둘째, 마이너 버전 유지의 가치를 인정할 것. Spring Boot 2.7이 LTS 버전이고 충분히 안정적이라면, 굳이 3.x로 업그레이드할 이유가 있을까? 비용과 이득을 따져봐야 한다. 셋째, 호환성 문서를 미리 읽을 것. Spring 공식 마이그레이션 가이드가 있다. 읽어봤으면 훨씬 빨랐을 거다. 넷째, 의존성 버전 고정의 중요성. Gradle의 dependency lock을 활용하면, 버전 충돌을 미리 감지할 수 있다. 마지막으로, 신중함의 가치. 호기심과 선도적 기술 도입은 좋지만, 모든 비용을 개인이 떠안는 건 아니다. 에필로그: 그래도 계속 개발하는 이유 이 이야기를 읽으면, "개발 일이 답답하네. 그냥 그만두지?"라고 생각할 수도 있다. 근데 솔직히, 이런 일들이 반복되어도 나는 개발을 계속한다. 왜냐하면 이 불편함 뒤에 무언가가 있기 때문이다. 새로운 기술을 배우는 과정은 고통스럽지만, 배운 후에는 문제 해결 능력이 한 단계 올라간다. Spring Boot 3.x로 업그레이드하면서 나는 Jakarta 네임스페이스, 마이크로미터 메트릭, Spring Security 설정 등에 대해 깊이 있게 배웠다. 다음에 비슷한 문제가 나타나면, 훨씬 빨리 해결할 수 있을 거다. 그리고 이 경험이, 다른 후배들에게 "신중함이 얼마나 중요한지"를 가르쳐주는 좋은 사례가 될 수도 있다. 결국 개발이라는 일은 이런 반복이다. 실패하고, 배우고, 다시 시도하고. 매번 조금씩 성장한다. 물론 일주일을 날린 건 별로 기분 좋지 않은 결과지만, 그래도 내일은 또 다른 문제를 해결하러 깃을 켤 것이다. 왜냐하면 개발자는 그렇게 되어있으니까.차라리 처음부터 "유지보수 vs 혁신"을 제대로 따져볼 걸.

이직해야 하나 고민되는데 면접 준비할 에너지가 없어요

이직해야 하나 고민되는데 면접 준비할 에너지가 없어요

이직은 하고 싶은데 면접 준비는 왜 이리 힘든가 7년차 개발자로서 받는 가장 흔한 질문이 있다. "이직은 안 해요?" 동기들은 이미 7000만원대 연봉을 받고 있고, 나는 여전히 6500만원에서 맴돌고 있다. 계산기를 두드려보면 매년 500만원씩 손해 보는 셈이다. 7년이면 3500만원이다. 자동차 한 대 값이다. 그런데도 나는 왜 자리를 뜰 생각을 못 할까? 아, 맞다. 면접 준비가 너무 피곤하니까. 슬랙 채널에서 누가 "요즘 시장 좋네, 우리 팀 사람 찾고 있어"라는 글을 봐도 마음 한구석이 철렁하면서도 동시에 한숨이 나온다. 왜냐하면 그것이 나의 인생이 바뀌는 시발점이 될 수도 있기 때문이다. 그리고 그 변화를 위해서는 LeetCode를 켜서 Medium 난이도의 그래프 문제를 50개쯤 풀어야 하고, 시스템 디자인 유튜브 영상을 보면서 '넷플릭스는 어떻게 스트리밍 인프라를 구축했을까' 같은 걸 공부해야 한다는 것을 알기 때문이다. 그런데 나는 지금 피곤하다. 진짜 피곤하다. 동기들 연봉을 마주하는 그 감정 매해 신년 회식이나 대학 동기들 단톡방에서 나오는 말들을 들으면, 이상하게 가슴이 철렁내린다. "어, 너 회사 잘하네. 근데 연봉은 괜찮아?" 이 질문이 나를 가장 킹받게 한다. 괜찮아? 괜찮은 게 아니다. 동기 A는 작년에 전직했다며 7500만원을 받고 있고, 동기 B는 스타트업에서 성공했다며 8000만원대라고 했다. 나는 여전히 6500만원이다. 7년을 같은 회사에서 일했는데, 그동안 시간만 흘렀지 연봉은 거의 오르지 않았다. 매년 300만원 정도 오르니까 인상률로 따지면 4~5% 정도? 물가상승률은 뛰어넘지 못한다. 돈 때문에 일하는 건 아니라고 자기를 속이고 싶지만, 현실은 냉혹하다. 아내가 월급 통장에서 돈을 빼갈 때 나는 항상 조금 쑥스럽다. 내가 버는 돈인데도 말이다. 아내는 좋다고 하지만, 나는 안다. 우리 또래 남편들 중에 6500만원인 사람이 몇 명이나 되는지를.이직해야 한다는 걸 알고 있다. 정말 알고 있다. 100% 확실하다. 그런데도 나는 여전히 자리에 앉아 있고, 사무실의 재미있는 것들에 적응했다. 팀장은 나를 믿고 있고, 후배들은 나를 찾는다. PR 리뷰를 잘하면 칭찬받는다. 이 모든 게 나를 붙잡고 있다. 하지만 진짜 문제는 그게 아니다. 진짜 문제는 이걸 다 뒤로하고 새로운 회사에 가기 위해 필요한 절차들이다. LeetCode 앞에서 멈춘 발걸음 이직 준비의 첫 번째 관문은 코딩 테스트다. 요즘은 대부분의 회사가 LeetCode 같은 플랫폼에서 나오는 식의 문제들을 본다. 내가 면접을 본다고 치면, 분명히 누군가는 나에게 "자, 30분 안에 이 그래프 문제를 풀어보세요"라고 할 것이다. 여기서부터 문제가 시작된다. 내 일은 그런 식의 코딩이 아니다. 나는 Spring Boot로 백엔드 서버를 짜고, 데이터베이스를 설계하고, 캐시 전략을 짠다. 내 일 중 70%는 이미 누군가 만들어놓은 프레임워크나 라이브러리를 활용하는 것이다. 알고리즘? 그런 건 면접 때만 필요한 것이다. 실무에서는 문제가 이미 구조화되어 있고, 나는 그것을 가장 효율적으로 구현하면 된다. 그런데 LeetCode를 켜면 어떻게 되는가? 동적 프로그래밍, 그래프의 DFS, BFS, 트라이(Trie), 세그먼트 트리... 이런 것들이 갑자기 나타난다. Hard 난이도의 문제들은 보자마자 머리가 복잡해진다. "이게 뭐가 필요한 거지? 왜 이렇게 복잡하지?" 하면서 해석만 10분을 날린다. 면접 준비를 위해서는 최소한 Medium 난이도의 문제를 50개 정도는 풀어야 한다고 한다. 몇몇 블로거는 100개를 푼다고 했다. 하루에 2~3개씩 풀면 한 달이 걸린다. 그리고 풀고 나서는 그 알고리즘을 다시 복습해야 한다. 퇴근하고 집에 가면 몇 시일까? 보통 6시30분이다. 식사를 하고 나면 7시30분이다. 아내와 얘기하고 나면 8시다. 여기서 30분이라도 LeetCode를 켜자니 너무 피곤하다. 브라우저 탭을 열기만 해도 피곤한데, 문제를 읽는 것부터 시작해서 풀고, 다른 사람의 솔루션을 보고, 댓글을 읽고... 이 모든 과정이 너무 길다. 차라리 넷플릭스를 킨다. 유튜브를 본다. 핸드폰에서 밈을 본다. 이게 훨씬 쉽고, 뇌가 피로를 덜 느낀다. 그리고 10시경 침대에 눕는다. 내일도 LeetCode를 해야지 하는 생각을 하면서. 그 다음날도 같은 일이 반복된다.시스템 디자인 인터뷰의 공포 LeetCode도 힘든데, 그 다음이 있다. 바로 시스템 디자인 인터뷰다. "넷플릭스는 어떻게 전 세계에서 동시에 스트리밍을 서비스할까요?" "우버는 어떻게 실시간으로 기사와 손님을 매칭할까요?" "당신이 페이스북의 뉴스피드를 설계한다면 어떻게 하겠어요?" 이런 질문들 앞에서 나는 항상 무너진다. 내 답변은 항상 비슷하다: "음... 데이터베이스는 MySQL 쓰고, 캐시는 Redis 쓰고, 로드 밸런싱은... 아, 그냥 AWS에서 해주겠죠?" 면접관의 얼굴이 굳는 것을 알 수 있다. 시스템 디자인을 제대로 준비하려면 따로 시간을 들여야 한다. 유튜브 채널도 봐야 하고, "System Design Interview" 같은 책도 읽어야 한다. 대규모 트래픽을 어떻게 처리할 것인가, 데이터 일관성은 어떻게 유지할 것인가, 네트워크 파티션이 발생했을 때는 어떻게 할 것인가... 이런 것들을 모두 체계적으로 학습해야 한다. 이건 1주일에 되는 게 아니다. 최소한 1~2개월은 걸린다. 내가 지금 준비한다면? 아, 다음 프로젝트 마감이 2주밖에 안 남았다. 레거시 코드도 봐야 하고, 후배 PR도 리뷰해야 한다. 배포 예정도 있다. 금요일에는 정말 밤 10시까지 남아있는 날도 생길 수 있다. 이런 상황에서 시스템 디자인을 1시간씩이라도 공부한다? 현실적이지 않다. 동기들의 성공담, 나의 무기력함 지난주 대학 동기들 단톡방에서 누군가가 말했다. "어, 나 이사를 했어. 이직하면서 집도 하나 더 샀어." 나는 그 메시지를 읽고 폰을 놨다. 그리고 팔을 베개에 두고 천장을 봤다. 동기 C는 정말 운이 좋은 애다. 처음부터 회사를 잘 고른 덕분에 지금 연봉이 9000만원대라고 한다. 동기 D는 스타트업에서 초기 멤버로 들어가서 이제 매니저까지 올라왔다. 동기 A는 정확히 2년 단위로 옮기면서 매번 연봉을 30~40% 올렸다고 한다. 나는? 나는 2년 전부터 "이번 연말에 이직해야지"라고 마음먹었다가 결국 다음해 초로 미뤘다. 그리고 작년 초에도 "이번 상반기에..."라고 했다가 지금은 올해 말쯤? 내년 초? 어정쩡한 상태다. 가장 좌절감을 느끼는 순간은, 누군가 나에게 "너 왜 이직 안 해?"라고 물을 때다. 그 질문 자체가 이미 답을 포함하고 있기 때문이다. "너는 왜 움직이지 않고 있니?"라는 비난이 담긴 질문이다. 그리고 나는 할 말이 없다. 연봉을 500만원 올리기 위해서는 면접을 봐야 하는데, 면접을 보려면 준비를 해야 하는데, 준비를 하려면 에너지가 필요한데, 그 에너지가 없다. 이게 악순환이다. 악순환의 늪에서 빠져나올 수 없는 것처럼 느껴진다.일이 많아서가 아니라, 일이 편해서다 여기서 인정해야 할 게 하나 있다. 내가 이직 준비를 못하는 이유가 '일이 너무 많아서'만은 아니라는 거다. 물론 일은 많다. 하루하루 할 일은 항상 넘쳐난다. 아침에 출근하면 이메일 50개가 와 있고, 슬랙 메시지 200개가 쌓여 있다. PR 리뷰를 5개, 버그 리포트를 3개 받는다. 그리고 내 일들. 배포 준비, 성능 최적화, 새로운 기능 개발. 그래도 실은 정해진 8시간 안에 거의 다 끝난다. 9시 출근 6시 퇴근이 원칙이고, 배포날 외에는 야근을 거의 하지 않는다. 그럼 내가 LeetCode를 할 시간이 없는 이유가 뭐냐고 물으면? 솔직하게 답하자면, 일이 편하기 때문이다. 내 자리는 편안하다. 내가 정말 싫어하는 사람이 없다. 팀장은 내 능력을 인정해주고, 후배들은 내 말을 듣는다. 내가 "이건 이렇게 하는 게 낫다"고 말하면, 대부분 그렇게 된다. 이 정도의 influence는 다른 회사에서 쉽게 얻을 수 없다. 그리고 무엇보다, 이 일을 하는 것이 힘들지 않다. 새로운 기술을 배울 필요도 없다. 이미 안다. Spring Boot? 7년간 써왔다. MySQL? 누구보다 잘 안다. Redis? 당연히 안다. 새로운 회사에 가면? 새로운 기술스택이 있을 수도 있다. 새로운 조직 문화도 있을 것이다. 새로운 사람들도 만나야 한다. 처음부터 다시 배우고, 적응하고, 인정받으려고 노력해야 한다. 그런데 지금 나는 이미 적응했다. 이미 인정받고 있다. 왜 이 편한 자리에서 일어나서 새로운 불편함으로 들어가야 하나? 연봉 500만원의 증가? 그건 추상적이다. 하지만 지금 이 자리의 편함? 그건 구체적이다. 만질 수 있다. 느낄 수 있다. 이것이 내가 이직을 미루는 진짜 이유다. 퇴근 후의 나는 정말 피곤한가? 그런데 한 가지 더 솔직하게 인정해야 할 것이 있다. 퇴근 후에 나는 정말 피곤한가? 사실... 피곤한 건 맞다. 하지만 피곤의 종류가 다르다. 신체적 피로는 사실 많지 않다. 나는 책상에 앉아서 마우스와 키보드를 쓰는 일을 한다. 신체를 많이 쓰지 않는다. 그런데도 6시 반쯤 되면 온몸이 무거워진다. 이건 정신적 피로다. 뇌를 계속 굴려서 나는 피로가 아니라, 선택을 계속 해서 나는 피로다. "이 코드는 어떻게 리팩토링할 것인가?" "이 버그의 원인은 뭐지?" "후배 코드의 이 부분이 문제인데, 어떻게 피드백할까?" "그 기획자의 요청은 가능할까?" 아침부터 저녁까지, 내 뇌는 계속 무언가를 결정하고 있다. 문제를 분석하고, 솔루션을 생각하고, 사람들과 커뮤니케이션한다. 6시 반에 회사를 나올 때쯤이면, 이 뇌는 진짜 더 이상 더하고 싶지 않다. 추가로 복잡한 작업을 하고 싶지 않다. 그래서 넷플릭스를 킨다. 유튜브를 본다. 핸드폰으로 밈 영상을 본다. 이런 것들은 뇌가 거의 일을 하지 않아도 된다. 정보가 일방적으로 들어오고, 나는 그냥 받으면 된다. 하지만 LeetCode? 그건 내 뇌가 또 일을 해야 한다는 뜻이다. 문제를 읽고, 로직을 생각하고, 코드를 짜고, 테스트 케이스를 생각한다. 퇴근해서 또 일을 하라는 거다. 이게 가능한가? 일단 며칠은 된다. 처음 이직을 생각할 때는 정말 열정으로 가득 차서 "일주일에 5일은 공부하겠다"고 마음먹는다. 그리고 월요일부터 수요일까지는 정말 한다. 그런데 목요일이 되면? 목요일 오후 4시쯤 기획자가 "이거 좀 빨리 봐주실래요?"라고 메시지를 보낸다. 내가 봐야 할 것 같은 느낌이 들기 시작한다. 목요일 저녁 10시에 배포 점검 메시지가 온다. 다음날 배포가 있을 수 있다는 거다. 그럼 금요일 밤이 걱정된다. 그런 불안감이 쌓이면, 목요일 밤에는 LeetCode를 케지 않는다. 차라리 숙면을 취한다. 그리고 토요일 오전? 솔직히 말해서 자고 싶다. 일주일간 일한 몸을 쉬고 싶다. 일요일? 내일 월요일이다. 월요일은 항상 힘들다. 일요일은 월요일을 위해 정신을 모아야 한다. 이렇게 한 주가 지나간다. LeetCode는 여전히 0개다. 그래도 누군가는 한다 내가 정말 고민스러운 점은, 나 같은 상황에서도 누군가는 성공한다는 거다. 내 대학 동기 중에 E라는 친구가 있다. 얘도 나랑 비슷하게 중견 회사에 다니고 있었다. 연봉도 비슷했다. 하지만 얜 결심했다. 정확히는 1년 전에 결심했다. "3개월에 이직한다. 이건 아니다." 그리고 얜 정말 했다. 평일 저녁마다 1시간씩. 주말에도 2시간씩. 3개월간 거의 모든 저녁을 LeetCode에 썼다고 했다. 내가 물었다. "힘들지 않았어?" 얜 말했다. "미쳤을 정도로 힘들었지. 근데 나는 더 이상 기다릴 수 없었어. 연봉이 올라야겠다는 생각이 집착이 됐어. 그 집착이 날 끝까지 밀어붙였어." 그리고 얜 성공했다. 유명한 스타트업으로 옮겼고, 연봉은 8500만원이 됐다. 보너스까지 치면 1억을 넘는다. 얘를 볼 때마다 나는 자책한다. 나는 왜 그정도의 집착을 가질 수 없을까? 왜 나는 편함에 안주할까? 그래서 가끔 정말 이직하기로 '결심'한다. 하지만 결심과 실행 사이의 거리가 너무 멀다. 현실은 복잡하다 솔직하게 말하자면, 이 문제는 단순하지 않다. "이직하고 싶으니까 준비하면 되지 않냐?"라고 말할 수 있지만, 현실은 그렇지 않다. 첫째, 나는 정말 이직하고 싶은가? 이 질문에 솔직한 답은 "글쎄... 그런 것 같은데?"이다. 연봉이 올랐으면 좋겠다. 하지만 지금 이 자리를 잃고 싶지는 않다. 이 두 가지를 동시에 가질 수는 없을까? 둘째, 면접 준비는 정말 필수적인가? 내가 지금의 자리에서 한 일들을 생각해보면, LeetCode에서 나올 법한 그래프 알고리즘이나 동적 프로그래밍을 쓴 적이 거의 없다. 하지만 면접관들은 그걸 묻는다. 왜냐하면 그게 '검증된 방식'이기 때문이다. 지능을 검증하는 방식. 하지만 정말 필요한 건 맞다. 나도 안다. 그리고 이것이 나를 더욱 막힌다. 선택지가 명확하기 때문이다. 면접을 본다는 것 = 준비를 한다는 것 = 저녁 시간을 포기한다는 것. 셋째, 내가 정말 피곤한가, 아니면 그냥 동기부여가 부족한가? 이건 진짜 구분하기 힘들다. 나는 정말 피곤하다고 느낀다. 하지만 동시에 나는 넷플릭스를 보면서 3시간을 보낸다. 이건 모순이다. 동기부여가 충분했다면, 나는 넷플릭스를 끄고 LeetCode를 켰을 거다. 하지만 나는 그렇게 하지 않는다. 왜냐하면 동기부여가 부족하기 때문이다. 그리고 동기부여가 부족한 이유는 뭘까? 아, 그건 내가 지금 편하기 때문이다. 혼자가 아니라는 생각 가끔 개발자 커뮤니티에 들어가서 다른 사람들의 고민을 읽다 보면, 내가 혼자가 아니라는 걸 알 수 있다. "7년차인데 연봉이 6500만원입니다. 이직해야 할까요?" 이런 글에 달리는 댓글들을 보면, 대부분 같은 조언을 한다. "이직하세요. 시장 가격보다 훨씬 적게 받고 계세요." "면접 준비가 힘들겠지만, 한 번 시작하면 가능합니다." "제 경험상 3개월이면 충분합니다." 좋은 조언들이다. 하지만 그 글을 쓴 사람도 나처럼, 그 댓글을 읽고도 행동을 취하지 못할 가능성이 높다. 왜냐하면 댓글은 힘을 주지 못하기 때문이다. 위로는 된다. 하지만 실제로 LeetCode를 켜라고 강요할 수는 없다. 내가 정말 필요한 건, 동료가 옆에서 "야, 너 진짜 하자"라고 말해주는 것이다. 아니면 팀을 꾸려서 함께 공부하는 것이다. 아니면 정말 갈등적인 상황이 닥치는 것이다. 예를 들어, "넌 이 회사에서 절대 매니저가 될 수 없어"라는 말을 들으면, 나는 행동할 것 같다. 하지만 지금은? 지금은 다 가능할 것 같다. 이대로도 괜찮을 것 같다. 5년 더 있어도 밥은 먹고 살 것 같다. 이게 나를 가장 걱정하게 만드는 부분이다. 계단을 놓친 게 아닐까 또 다른 두려움이 있다. 바로 "이미 늦지 않았을까?"라는 생각이다. 7년차면 아직 충분히 젊은 나이다. 하지만 업계에서는 이미 나를 뭔가 '정해진' 사람으로 보고 있을 수도 있다. "아, 그 사람은 중견 회사에서 7년 있던 사람이네. 그럼 안정적인데 도전을 안 한다는 뜻이겠네." 이걸 극복하려면, 새 회사에서도 빠르게 적응해야 한다. 그리고 성과를 내야 한다. 그런데 나는 지금 기반이 없는 상태다. 새 회사의 시스템도 모르고, 사람

주말 슬랙 알림 공포증: 무음 설정의 비극

주말 슬랙 알림 공포증: 무음 설정의 비극

주말 슬랙 알림 공포증: 무음 설정의 비극 가을이 들어서니 퇴근길이 조금 더 편해졌다. 해가 일찍 지니까 야근을 하지 않는 이상 어두운 건물을 빠져나올 수 있다는 뜻이니까. 어제도 그랬다. 금요일 6시 딱 맞춰 자리에서 일어났고, 모니터를 끄고 슬랙을 열었다. 상태 메시지를 "자리 비움"에서 "주말 모드"로 바꾸고, 손가락이 거기서 멈췄다. 슬랙 알림 설정 화면. 그 초라한 체크박스들이 나를 바라보고 있었다. 금요일 저녁, 결정의 순간 보통 금요일 밤이 되면 이 문제가 터진다. 혼자만의 싸움이 아니라, 개발자라면 누구나 겪는 그 오래되고도 끝나지 않는 문제. "슬랙 무음으로 할 거야, 아니면 소리 켜둘 거야?" 회사 지친다고 늘 투덜대던 선배 개발자 김상현이는 올해 초 이렇게 말했었다. "나? 그냥 핸드폰 내려놔. 금토일 슬랙 안 본다. 죽고싶지 않으면." 그의 얼굴에선 반은 농담이고 반은 진지함이 묻어났다. 나는 한참을 생각했다. 그게 가능할까? 정말?나는 그정도까진 못하겠다고 생각했다. 온전히 손을 놓는 건 너무 무섭다. 배포 이슈라도 터지면? QA 팀에서 급한 버그를 발견하면? 아니면 시스템이 다운되면? 일단 한 번 "음소거" 버튼을 눌렀다. 휴대폰의 슬랙 앱을 열어서 알림을 모두 끐다. "세상이 아무리 떠들어도 나는 모를 일"이라는 생각으로. 그런데 마음이 놓이지 않는다. 30분을 버티더니 다시 설정 화면으로 돌아갔다. 조용할 땐 너무 조용하고, 그 조용함 속에서 내 상상만 자꾸 살아난다. 우리 서비스 메인 데이터베이스가 지금 이 순간 죽어가고 있는 건 아닐까? Redis 캐시가 터졌을지도 모르지? 아니면 저 신입 개발자 이준호가 실수로 프로덕션에 직접 핫픽스를 푸시했거나. 음... "도움말"이 라는 설정으로 바꿔봤다. 긴급 메시지만 울리게. 하지만 슬랙에서 "긴급"의 정의가 뭔지는 아무도 명확히 알지 못한다. 결국 일요일 자정을 넘길 무렵, 나는 이 설정들을 전부 다시 기본값으로 되돌렸다. 음성 알림, 배지, 데스크톱 알림 전부. "차라리 좀 울리는 게 낫지." 이렇게 중얼거리며. 월요일 아침의 악몽 실제로 그런 일이 터진 건 3주 전이었다. 정확히는 지난 8월 셋째 주 토요일이었다. 금요일 오후 4시쯤에 우리 팀에 신규 배포가 들어갔다. 여름 행사 특수 기간을 대비하는 배포였고, 내가 리뷰한 PR 3개, 다른 팀원들이 리뷰한 PR 4개가 포함되어 있었다. 보통 배포는 금요일 오전에 하는 게 회사의 암묵적인 룰인데, 이번엔 기획팀 요청으로 오후에 했다. "마지막 데이터 정합성만 한 번 더 체크하려고요."라는 명목 아래. 배포 후 한 시간 정도 모니터링을 하고 나서 나는 좀 이상한 느낌이 들긴 했지만, 에러 로그도 없고 응답 속도도 괜찮아 보였다. 금요일 6시. 회사를 나왔다. 토요일은 아내가 일찍 집에 올 예정이라서 카페를 한 바퀴 돌고 회사 근처 마트에 들렀다가 집으로 돌아갔다. 첫 번째 무음 설정을 했다. 휴대폰에서. "주말이야, 조용해지자." 토요일은 정말 조용했다. 슬랙이 울리지 않았다는 게 아니라, 나는 그걸 들을 수 없도록 설정했으니까. 아내랑 영화도 봤고, 점심에 밖에서 밥도 먹었다. 일요일도 비슷했다. 치킨을 시켜먹고, 개인 노트북으로 쓸데없는 깃허브 레포지토리도 만들어 봤다가 포기했다. 휴대폰은 책상 한구석에 놔뒀다. 월요일 아침 7시 40분. 회사로 출근하는 지하철 안에서 휴대폰의 알림을 다시 켰다. 아이폰 화면에 한 번에 터져나온 슬랙 알림. 빨간 배지에 "47"이라고 떠있었다. 47개. 토요일 오후 2시부터 일요일 밤 11시까지, 거의 36시간 동안 온 메시지들. 내 얼굴이 확 굳었다. 슬랙을 열었다. [12:47] 팀장: 배포 후 데이터 정합 이슈 감지. 회원 경험치 산정에 문제 있는 것 같음. 확인 부탁 [12:59] 이준호: 김개발님 계신가요? [13:15] 팀장: 김개발님 일하시나요? 응답 부탁 [13:47] QA담당자: 심각해보이는데 배포 롤백할까요? [14:02] 팀장: 긴급 회의실 1번방 입장 부탁 [14:15] 팀장: 김개발님 연락 안 되네요. 우선 롤백 결정 [14:33] CTO: 앞으로 변경사항 발생했을 때 담당 개발자 연락 안 되면 팀장이 직접 롤백하기로. 공지 예정 [14:47] 이준호: 형... 왜 연락이... [15:22] QA담당자: 롤백 완료. 원인 파악 필요. 코드 리뷰 다시 해야 할 것 같음 후속 메시지는 토요일 밤부터 일요일 내내 이어졌다. 동료들이 원인을 찾아내려고 한 흔적들, 몇 가지 추측들, 그리고 점점 우울해지는 톤. 내 손이 떨렸다. 원인은 결국 월요일 아침 회의에서 밝혀졌다. 내가 승인한 PR 중 하나였다. 신규 기능을 추가할 때 캐시 무효화 로직을 제대로 넣지 않아서, 기존 데이터와 새 데이터가 섞여서 나왔던 거였다. 코드만 봐도 한 30초면 문제를 찾을 수 있는 수준이었다. 나는 그날 오후 3시경 PR을 승인했고, 리뷰하면서 커피를 마셨고, 그때 화면에 다른 창을 띄웠었다. 그래서 그 부분을 놓쳤다. 팀장은 차분하게 말했다. "배포 전에 충분한 모니터링 시간이 없었고, 금요일 오후 배포가 그래서 위험한 거다. 근데 역시 배포 담당자가 주말에라도 연락은 돼야 할 것 같아. 그게 프로페셔널이니까." 내가 "죄송합니다"라고 말하는 동안, 마음속으로는 다른 생각이 맴돌고 있었다. "아, 그래. 내가 무음으로 설정하지 말았어야 했나?"트루 스토리: 다른 동료들은? 그 이후로 나는 다른 팀원들과 아주 솔직한 대화를 나눴다. "너희 금토일 슬랙은 어떻게 해?" 결과는 놀랍게도 다양했다. 먼저 박세진 선배. 15년차 벡엔드 개발자다. 그이는 "핸드폰 자체를 집에 안 가져가"라고 했다. 회사 휴대폰 따로, 개인 휴대폰 따로. 퇴근하고 회사 핸드폰을 락커에 둔다는 뜻이었다. "그렇게라도 해야 미쳐 안 된다고." 그 다음은 신입 이준호. 그이는 "뭐 어차피 내가 롤백할 권한도 없으니 음소거 해도 되겠지?"라고 했다. 면접 때는 "회사를 위해 개인 시간도 아끼겠습니다"라고 했지만, 현실은 다르다고. 밀실에서 혼잣말로 한숨을 쉬는 모습이 보였다. 그리고 QA팀의 이수영 팀장. 그이는 "그냥 개인 휴대폰엔 안 깔아. 회사 노트북이랑 회사 핸드폰은 회사 건물 밖으로 안 가져간다"고 했다. "배포 담당자랑 팀장만 음성 알림을 켜. 나머지는 배지만 켜서 나중에 확인하고, 정말 긴급하면 전화를 해." 가장 현실적인 건 아키텍처를 담당하는 김수진이었다. "배포 관리 정책을 바꿨어. 금요일 오후 배포는 원칙적으로 금지. 긴급이면 수동으로 팀장 승인 받고, 그때는 배포 담당자가 일요일 저녁까지는 깨어 있기로 계약서처럼 합의." 나는 이 대화들을 들으면서 깨달았다. 결국 "정답은 없다"는 것을. 모두가 놓친 포인트: 시스템의 문제 월요일 회의가 끝나고 나서 한 가지 더 진행된 게 있다. 신규 정책 수립이었다. CTO가 주도해서 만든 규칙:금요일 오후 3시 이후 프로덕션 배포 금지 (긴급 제외) 배포 담당자는 배포 후 최소 2시간 모니터링 필수 긴급 배포는 팀장이 반드시 동반하고, 배포 담당자 연락처 3곳 모두에 연락 배포 롤백 프로세스 자동화 (수동 롤백 시간 단축) 모니터링 대시보드 표준화 (동일한 항목을 모두가 체크)여기서 재미있는 건, 이 규칙들이 사실 "개발자의 주말을 보호하기 위한" 규칙이 아니라, "배포 이슈를 줄이기 위한" 규칙이라는 점이었다. 결과적으로 개발자 복지가 향상됐지만, 그건 부수효과였다. 내가 느낀 건 이거였다: 개발자 개인이 슬랙 음소거를 고민하는 게 아니라, 회사가 시스템을 고민해야 한다는 거. 문제는 금요일 오후 배포가 터졌을 때 개발자가 주말에 대응할 수 있는 여건이 아니었다. 문제는 배포 담당자만 원인을 알고 있어서, 다른 팀원들이 복구를 하지 못했다. 문제는 롤백 프로세스가 느려서 36시간이나 서비스가 깨진 상태로 남았다. 그 모든 게 개발자 개인의 휴대폰 음소거 설정이 해결할 수 있는 문제가 아니었다. 다음 주 월요일, 나는 슬랙 설정을 다시 만졌다. 이번엔 자신감 있게 "모든 알림 켜기"를 눌렀다. 하지만 이상하게도 마음이 불안했다. 왜냐하면 이제 토요일 오전에 알림이 울려도, 그건 시스템의 문제이지 내가 음소거를 하지 않은 문제는 아니라는 걸 알았으니까.결국 우리는 뭘 배워야 하나 지금 시점에서 돌아보면, 이 사건은 여러 층의 실수가 겹쳐진 결과였다. 첫째, 내 리뷰가 정확하지 않았다. 그건 인정한다. 오후 3시쯤 피로도가 높아진 상태에서 캐시 로직까지 한눈에 보기는 어려웠고, 나는 충분히 신경을 쓰지 않았다. 둘째, 금요일 오후 배포라는 시스템의 문제가 있었다. 팀장도, CTO도, 아무도 지적하지 않았다. "그런가보네?"라고 넘어갔다. 셋째, 배포 후 모니터링이 불충분했다. 1시간 정도만 한 후 "괜찮겠지"라고 생각했는데, 실제로는 특정한 기간대의 특정한 행동을 했을 때만 버그가 터지는 거였다. 넷째, 그리고 내가 무음 설정을 했다. 이건 앞의 세 문제를 안고도, 마지막 방어선을 없앤 셈이다. 근데 생각해보니 넷째가 가장 비난하기 쉬운 부분이어서, 결국 나만 욕먹은 거다. "휴대폰 확인 좀 해. 어른답게."라는 눈길들. 분명히 내 잘못도 있다. 50%는 내 책임이다. 근데 나머지 50%는? 그건 개발팀의 프로세스, 배포 정책, 모니터링 시스템, 회사 문화였다. 그리고 문제는, 이 50%를 개발자 개인이 해결해야 한다고 생각하는 경향이 업계 전체에 있다는 거다. "너는 열정이 있으니까, 주말도 슬랙을 체크해." "너는 시니어니까, 배포 관련 알림은 꺼도 안 된다." "너는 팀 리드니까, 팀원 문제는 언제든 해결할 수 있도록." 이런 문화들. 다들 어느 정도는 옳은 말이지만, 어느 정도는 우리를 갈아서 커피를 만드는 과정이기도 하다. 우리가 만든 새로운 규칙 회의가 계속되면서, 재미있는 일들이 생겼다. 팀원들이 하나둘 자기 생각을 말하기 시작했다. 보통 개발자들은 회의에서 조용한데, 이번엔 달랐다. 이준호: "그 금요일 오후 3시 금지 정책, 혹시 긴급 배포가 생기면 누가 판단하는 거죠?" 수진: "좋은 질문. 팀장이 하나 다 결정하기엔 너무 많으니까, 기획팀, QA팀, 개발팀 합의로." 이준호: "그럼 합의하는 과정에 제한 시간이 있어야 하지 않을까요? 왔다갔다 하다가 배포 시간이 늦어지면, 또 금요일 저녁이 될 텐데." 세진: "맞다. 결정 30분 이내. 결정이 못 나면 일단 롤백하고 월요일에 다시 배포." 김수진: "좋아. 그럼 롤백 프로세스도 표준화 해야지. 지금은 수동으로 하니까 시간이 오래 걸려." 팀장: "롤백 스크립트 만들 사람?" "..." 결국 그건 내가 하기로 했다. 하지만 이번엔 다르게 생각했다. 이 스크립트를 나만 알고 있으면 또 다음에도 나한테 물어볼 거다. 그래서 나는 문서화하기로 했고, 팀원들이 전부 롤백할 수 있도록 교육하기로 했다. "난 모르겠어"라고 말할 수 있는 환경을 만들자는 뜻이었다. 정답은 여기에 있지 않다, 하지만 8월의 일이 있은 지 지금 거의 2개월가 지났다. 금요일 오후 배포는 이제 거의 없다. 긴급으로 생기면 팀장과 CTO가 직접 와서 상황을 본다. 내 휴대폰 알림이 울려도, 그건 정말 급할 때만이다. 근데 솔직히 말해서, 나는 여전히 금요일 퇴근 후 슬랙 앱을 음소거한다. 완전히 차단하는 건 아니고, "중요" 태그가 달린 메시지들만 알람이 오도록 설정했다. 그리고 화요일부터 금요일까지는 그 설정도 안 본다. 그냥 슬랙 앱을 삭제했다. 회사 노트북은 회사에 두고, 퇴근하면서 PC를 종료한다. 아내가 최근에 물었다. "일 생각 안 하니?" 나는 "일 생각이 나면 월요일까지 기다리지 뭐."라고 대답했다. 그 대답에 아내는 웃었고, 나도 웃었다. 하지만 속으로는 이렇게 생각했다. 일이 정말 나가리면, 그건 내 책임만이 아니다. 그걸 수습할 시스템과 팀, 회사의 문제도 있다. 내가 토요일 오전 11시에 알림 하나를 못 봤다고 해서, 전체 배포 프로세스가 무너져서는 안 된다. 만약 그게 무너지는 거라면, 그건 내 휴대폰 설정이 아니라 회사의 시스템이 약한 거다. 그래서 나는 이제 다르게 생각한다. 슬랙을 음소거하는 게 죄책감이 아니라, 권리라고. 정시 퇴근이 "게으름"이 아니라 당연한 일과라고. 배포 담당자가 주말 연락이 안 돼도 롤백할 수 있는 시스템이 갖춰지는 게 "프로페셔널"이라고. 다음 달 예산 회의에서, 내가 모니터링 자동화 도구 도입을 건의하기로 했다. 그리고 배포 후 자동 테스트 강화도 건의하기로 했다. 롤백 자동화 시스템도. 왜냐하면 결국, 문제의 답은 개발자의 주말 시간에 있지 않으니까.좋은 시스템도 결국은 휴일에 음소거를 믿고 일어난다.

기획자의 '이거 간단하죠?'는 왜 그렇게 화날까

기획자의 '이거 간단하죠?'는 왜 그렇게 화날까

기획자의 '이거 간단하죠?'는 왜 그렇게 화날까 그 문장이 울리는 순간, 나는 이미 죽어있다 슬랙 메시지 알림음. 오후 4시 47분. 주말까지 정확히 14시간 41분 남은 금요일 오후다. "김개발님, 회의실에서 봅시다 :)" 기획팀 매니저 박기획의 메시지다. 나는 이미 알고 있다. 이 시간, 이 요일, 이 톤의 메시지가 뭘 의미하는지. 지난 7년간 이 회사에서 나는 이 패턴을 수백 번 봤다. 피할 수 없는 그것. 요구사항 폭탄. 회의실에 들어서자마자 박기획은 내 눈을 반짝이며 봤다. 그 표정. 그 표정만으로도 이미 내 코르티솔 수치는 상승 중이다. 아이패드를 집어 들더니 와이어프레임을 보여줬다. "이거 이번 스프린트에 들어가면 좋을 것 같은데요. 다른 건 다 돼 있고, 그냥 프론트에서 보내는 유저 행동 데이터를 받아서... 실시간으로 대시보드에 띄워주고, 각 유저별로 세분화된 분석 리포트를 PDF로 생성하면 되는 거고... 근데 이거 간단하죠?" 그 순간, 나는 내 영혼이 몸을 떠나가는 것을 느꼈다.'간단하다'는 말의 무게 "간단하죠?" 이 말을 들을 때마다 나는 기획자가 실제로 뭘 말하고 있는지 번역기를 켠다: 기획자가 말한 것: "간단하죠?" 기획자가 실제 의도한 것: "이 정도는 당신 같은 프로 개발자에겐 밥 먹는 것처럼 쉽겠네요?" 내가 듣는 것: "넌 이것도 못 하냐?" 내 코드가 들리는 것: "아니 이게 뭐라는 거야 이 미쳐버린 것 같은 요구사항을..." 문제는 이게 단순한 언어의 문제가 아니라는 거다. 그건 관점의 차이. 아니, 관점 이상의 뭔가다. 기획자에게 '실시간 데이터 대시보드 + 유저별 분석 리포트 PDF 생성'은 정말 간단해 보인다. 결과물만 보니까. 버튼을 누르면 깔끔한 UI가 나타나고, 그래프가 그려지고, PDF가 다운로드된다. 보기에는 그렇게 간단하다. 마치 스마트폰에서 카카오톡 앱을 켜는 것처럼. 그런데 나는 안다. 그 "간단해 보이는" 것 뒤에 숨겨진 것들을. 보이지 않는 빙산의 아래, 그곳에 내가 있다 기획자가 보는 것: 대시보드가 나타난다 → 그래프가 그려진다 → PDF가 생성된다. 내가 봐야 하는 것: 우선 현재 데이터 구조를 파악해야 한다. 유저 행동 데이터가 어디에 저장되어 있나? MySQL의 users_behavior 테이블인가? 아니면 로그 서버에서 실시간으로 들어오는 데이터인가? 아니면 여러 곳에서 산재되어 있나? 이미 데이터 웨어하우스 같은 게 있나? 없으면 만들어야 하나? 데이터 일관성은? 현재 수백만 건의 레코드가 있는데, 마이그레이션은 어떻게 할 건가? 다운타임이 생기면 안 되니까 이중 기록을 남겨야 한다. 기존 데이터와 새로운 데이터가 일치하는지 검증하는 로직도 필요하다. 검증 실패 시 롤백 시나리오는? 실시간 처리? "실시간"의 정의가 뭔가? 1초? 500ms? 100ms? 각각 다른 아키텍처가 필요하다. 그냥 쿼리하면 느리니까 캐싱이 필요하다. Redis? 메모리는 충분한가? TTL은 어떻게 설정할 건가? 캐시 무효화는? 스탬피드 문제는? 동시성? 몇 명이 동시에 대시보드를 볼 건가? 100명? 1000명? 1만 명? 데이터베이스 커넥션 풀은? 쿼리 최적화는? 인덱스 전략은? 슬로우 쿼리 로깅은? 세분화된 분석? 어느 정도 세분화인가? 성별, 연령, 지역? 기기 타입? 행동 경로? 시간대별? 각 조합마다 다른 쿼리가 필요하다. 프리컴퓨팅을 할 건가? 아니면 온더플라이로 계산할 건가? PDF 생성? 몇 MB짜리 PDF인가? 수백 페이지면 생성 시간이 몇 분이 될 수도 있다. 그럼 비동기 작업으로 처리해야 한다. 큐 시스템이 필요하다. Kafka? RabbitMQ? 실패 처리는? 재시도 로직은? 권한? 모든 유저의 데이터를 모두가 볼 수 있나? 아니면 자기 데이터만? 관리자는 모두 본다? 그럼 데이터 필터링 로직이 비즈니스 로직과 섞인다. 권한 검증이 매번 필요하다. 모니터링? 언제 터질지 모르는 시스템인데 모니터링은? 알러트는? 메모리 사용량, CPU, 데이터베이스 쿼리 성능, 캐시 히트율, PDF 생성 시간... 테스트? 단위 테스트는 물론이고, 통합 테스트는? 부하 테스트는? 1000명이 동시에 대시보드를 켜면? 10000명이면? 문서화? 새로운 팀원이 와도 이걸 유지보수해야 한다. 배포? 이게 다 되고 프로덕션에 나가면 롤백 시나리오는?이 모든 것들이 내 머리 안을 도는데, 기획자는 여전히 "이거 간단하죠?"라고 묻고 있다. 내가 대답하지 않자 그가 덧붙인다. "아, 시간 많이 안 걸릴 것 같긴 한데요? 3, 4일?" 3, 4일. 나는 웃었다. 하지만 웃음이 아니라 그냥 생리 반응이었다. 신체의 스트레스 반응 중 하나다. 피하고 싶지만 해야 하는 설명의 악순환 이 상황에서 나에게 두 가지 선택지가 있다. 첫 번째 선택: 현실을 설명한다 "아, 그게 사실은요... 데이터 마이그레이션, 캐시 전략, 동시성 제어, 권한 검증, 모니터링, 부하 테스트... 이런 게 다 들어가거든요. 최소 2주 정도는 필요할 것 같고..." 결과: 기획자의 표정이 굳는다. "아, 그렇군요. 근데 어떻게 이렇게 오래 걸려요? 다른 팀은 더 빨리 안 하던데?" 그리고 나는 또 설명해야 한다. "아, 다른 팀의 요구사항이 달라서..." 이 과정이 3, 4번 반복된다. 기획자는 여전히 이해하지 못한다. 그리고 나는 지친다. 두 번째 선택: 그냥 "네, 알겠습니다"라고 한다 결과: 회의는 빨리 끝난다. 하지만 다음 월요일, 화요일, 수요일, 목요일을 지옥으로 보낸다. 밤 11시까지 사무실에 남아있다. 아내한테 또 야근한다고 전한다. 아내는 "또?"라고만 한다. 그리고 금요일 오후, 여전히 완성 못 한 채로 "이번 스프린트엔 좀 더 필요할 것 같은데요"라고 말해야 한다. 그러면 기획자는 "어, 몇 일만 더 하면 안 돼?"라고 묻는다. 진짜 몇 일만 더 하면 된다. 근데 그건 이미 예측 불가능한 영역이다. 대부분의 경우, 나는 두 번째를 선택한다. 왜냐하면 첫 번째를 선택했을 때 오는 것들이 더 고통스럽기 때문이다. 기획자의 의심 어린 눈빛. "혹시 개발팀이 비효율적인 건 아닐까?" 같은 의구심. 그리고 그게 상사에게까지 전달될 가능성. 나는 이 회사에서 이미 7년을 왔다. 지금 "느리다"는 평판을 얻고 싶지는 않다. 그래서 나는 아무것도 설명하지 않는다. 그냥 한숨을 쉬며 "네, 알겠습니다"라고 한다. 간단하다는 착각의 원인: 눈에 보이는 것과 안 보이는 것 기획자를 탓하고 싶지는 않다. 정말이다. 박기획이는 나쁜 사람이 아니다. 그냥 안 봤을 뿐이다. 개발자의 일은 극도로 불가시적(invisible)이다. 사용자는 버튼을 누르고 결과를 본다. 아름다운 UI, 빠른 응답 속도, 안정적인 서비스. 그게 다다. 그 뒤에 있는 것들은 안 본다. 반면 기획자의 일은 가시적이다. 와이어프레임, 목업, 프로토타입. 보기만 해도 "아, 이런 기능이 들어가는구나"가 한눈에 들어온다. 그래서 기획자는 자연스럽게 생각한다. 저 와이어프레임 정도면 개발할 때 이 정도 난이도 아닐까? 데이터 몇 개 받아서 보여주면 되는 거 아닌가? 그리고 실제로 그 생각이 틀린 건 아니다. 만약 기획자가 요구한 기능이 정말로 그것만 있었다면 말이다. 하지만 그렇지 않다. "데이터를 받아서 보여주는 것"은 정말 간단하다. 5분이면 된다. 하지만 문제는 그 이전과 이후다. 이전: 그 데이터가 어디서 오는가? 데이터는 정확한가? 정확하지 않다면? 일관성이 있는가? 무결성은? 보안은? 이후: 그 데이터를 보여주고 나서? 매달 유저 수가 10배 늘어나면? 데이터가 100배 늘어나면? 여전히 빠를까? 내 마음이 쓰라린 이유들 이 문제가 나를 이렇게까지 자극하는 이유는, 사실 기획자 때문만은 아니다. 일부는 나 자신 때문이다. 7년을 이 회사에서 일하면서, 나는 스스로를 어떻게 정의해왔나? "그냥 일 잘하는 사람." 이 정도면 충분했다. 요구사항이 들어오면 한숨을 쉬지만, 결국 해낸다. 밤새가 필요하면 밤샌다. PR 리뷰는 잘한다. 버그를 찾는 능력도 좋다. 그래서 나는 사실상 이 팀의 버팀목이 되었다. 하지만 버팀목이 되는 것의 대가는 뭔가? 더 이상 '일 잘하는 사람'이 아니라 '일만 계속하는 사람'이 되는 것 아닌가? 기획자의 "간단하죠?"라는 말이 화나는 이유는, 그 말 자체 때문이 아니다. 그 말이 내게 계속 이렇게 살아도 괜찮은 건가 하는 회의감을 자극하기 때문이다. 연봉은 6500만원. 동기들은 7천 넘게 받는다더니. 직책은 없지만 사실상 테크 리드다. 사이드 프로젝트는 세 번 시작했다가 다 접었다. 이직을 생각해본 적 없나? 물론 있다. 하지만 이직 준비할 에너지가 없다. 왜? 일로 이미 죽어있으니까. 그리고 이 악순환 속에서 나는 계속 "간단하죠?"에 직면한다. 그 말이 내게 던지는 메시지는: "넌 충분히 많이 해. 이 정도는 쉽겠지?" 하지만 내 상태는: "나 이미 죽어있는데?"하지만 여전히 내가 해야 한다는 것 여기까지 읽으면, 그럼 난 뭘 원하나? 기획자가 나한테 존경심을 가지고 "이 기능을 구현하기 위해 정말 많은 복잡한 기술적 고려가 필요하군요. 개발자님의 전문성을 존경합니다"라고 말해주기를? 솔직하게 말하자면, 그것도 좋겠다. 하지만 그게 근본적인 해결책은 아니다. 근본적인 문제는 더 깊다. 그건 조직 문화의 문제다. 개발자의 시간과 노력이 제대로 평가받지 못하는 문화. 그리고 개발자 자신도 그걸 당연하게 받아들이는 문화. 나는 어쩌면 박기획보다 나 자신에게 더 화나있는 건지도 모른다. "간단하죠?"라는

PR 리뷰하다가 나는 언제 내 일을 하나요?

PR 리뷰하다가 나는 언제 내 일을 하나요?

PR 리뷰하다가 나는 언제 내 일을 하나요? 오늘도 오전 10시가 되기 전에 슬랙에 네 개의 PR 링크가 쌓였다. "개발님, 이거 좀 봐주실래요?" 심장이 철렁한다. 매번 이 문구를 볼 때마다 나는 내가 뭘 하고 있었는지 잊는다. 아, 그래. 나도 해야 할 일이 있었지. 릴리즈 전에 끝내야 할 API 최적화 작업. 어제도 못 했고, 그 앞날도 못 했고, 재작년 같은 계절에도 못 했던 그것. 테크 리드지만 직책은 없는 이상한 위치 사실 지금 이 상황이 되기까지는 논리가 명확했다. 7년을 이 회사에서 일했으니까, 후배들 PR은 내가 봐야지. 아키텍처 결정? 내가 한다. 신입 온보딩? 내가 한다. 레거시 코드 리팩토링 방향? 당연히 내가 한다. 어느 순간부터 나는 세미 테크 리드가 되어 있었다. 세미가 아니라 완전 테크 리드인데 직책은 없다. 연봉은 6500만원. 동기들은 이미 7000을 넘었다. 관리자가 면개 때 "개발 실력도 좋고 후배들도 잘 챙기시니까 기여도가 크신 거 같아요"라고 했을 때 나는 웃음이 나올 뻔했다. 기여도가 크다고? 기여는 자신의 일을 하는 건데, 나는 지난 3개월간 내 일을 얼마나 끝냈는가.아침 9시부터 체크인까지 5시간의 PR 리뷰 오늘 타임라인을 그려보자.09:30 - 첫 번째 커피 + 첫 번째 PR 리뷰 시작 09:45 - DB 쿼리 부분에서 N+1 이슈 발견, 코멘트 작성 10:15 - 두 번째 PR 도착, 인증 로직 검토 10:50 - 후배 A가 "개발님, 제 코멘트 봤어요?" 11:20 - 세 번째 커피 + 세 번째 PR (Redis 캐시 레이어) 12:30 - 점심 시간, 하지만 마음은 불안함 14:00 - 돌아와서 네 번째 PR 15:30 - "어? 벌써 이 시간?" (내 일은 여전히 0% 진행)12시간 근무 중 진짜 내 업무에 손을 댄 시간은 1시간 미만이다. 그 1시간도 불완전한 포커스다. 체크인 5분 전에 마지막 PR 코멘트를 남기는 나를 보면, 나는 이 회사의 미식축구 쿼터백처럼 느껴진다. 모든 플레이를 지휘하지만, 정작 터치다운은 못 하는 그런 역할. 기획자는 여전히 "간단하겠죠?" 어제 회의에서 기획자가 했던 말. "이거 캐시 레이어 한 번 쉬우신데 이주말까지 가능할까요?" 내가 그 시간에 뭘 할지는 이미 예정되어 있다. 토요일 오후 2시부터 6시까지 PR 리뷰. 왜냐하면 월요일 배포가 잡혀있으니까. 그리고 그 PR들은 당연히 내가 봐야 한다. 나는 "네, 되겠습니다"라고 했다. 뭐, 또 못할 건가. 못해본 게 어디 있나.슬랙 알림이 가져온 심리적 불안정 가장 힘든 건 타이밍이다. 내가 드디어 우리 서비스의 응답 속도 분석에 집중하려던 순간, 슬랙 알림음이 울린다. 후배A: @개발님 이거 어떻게 생각하세요? 후배B: 개발님 한 번 봐주시겠어요? 기획: 개발님 이거 기술적으로 문제 없나요?심장이 철렁한다. 그리고 나는 우리 서비스 응답 속도 문제를 다시 미룬다. 퇴근 후에도 슬랙을 켜지 못한다. 알림이 울릴까봐. 주말 오전 11시에 일어나려고 해도, 핸드폰을 보는 순간 미해결 PR들이 시야에 들어온다. "월요일에는 반드시 돌려야지"라는 의무감과 함께. 내가 원했던 건 이게 아니었다. 단지 좋은 개발자가 되고 싶었을 뿐이다. 그런데 좋은 개발자라는 평가가 내게 준 건 더 많은 시간 투자, 더 많은 책임감, 그리고 정작 성장할 기회의 박탈이었다.그래도 월요일 아침은 온다 내일은 또 어떤 PR들이 기다리고 있을까. 지금 생각해보니 내가 정말 해야 할 일 - 우리 시스템의 구조적 개선, 신입들을 진정한 시니어로 만드는 것, 내가 없어도 팀이 돌아가게 하는 것 - 이런 건 PR 리뷰 때문에 자꾸자꾸 뒤로 밀린다. 아이러니하게도, 내가 더 열심히 리뷰할수록 후배들이 성장할 기회도 줄어든다. 좋은 코드에 대해 "왜?"라고 물어보고 토론할 시간이 줄어들거든. 이번 주는 다르게 해보려고 한다. 월요일 아침에 내 일을 먼저 진행하고, PR들은... 음, 역시 못할 것 같다. 아, 그거요.테크 리드는 개발자인데, 개발하는 시간이 가장 적다는 게 아이러니다.