Showing Posts From

코드리뷰

팀원들이 자신을 리더로 보는 불편함과 책임감

팀원들이 자신을 리더로 보는 불편함과 책임감

아침부터 슬랙 멘션 출근하자마자 슬랙 멘션 5개. "개발님, 이거 어떻게 하면 될까요?" "DB 설계 리뷰 부탁드립니다." "이 라이브러리 써도 될까요?" 커피도 안 마셨다. 9시 2분. 다들 나한테 물어본다. 2년차 박신입부터 4년차 최선임까지. 정작 팀장은 회의 중이고, 나는 그냥 7년차다. 직책 없다. 월급도 제일 많이 받는 것도 아니다. 근데 왜 다들 나한테 물어보는 거지.점심시간 회피 식당 가는 길에 3년차 이주니어가 붙었다. "선배님, 아까 그 API 설계 괜찮을까요? 제가 생각한 건..." 밥 먹으면서도 기술 얘기. 김치찌개 식었다. 사실 이주니어 실력 괜찮다. 근데 확신이 없는 거다. 그래서 내 승인을 받으려고 한다. 마치 내가 리더인 것처럼. 근데 나는 리더가 아니다. 팀장은 따로 있다. 40대 중반. 개발은 안 한 지 5년 됐다. 회의만 한다. 기술적 결정은 "개발님이 잘 아시니까 알아서 하세요" 라고 한다. 알아서 하라고? 책임은? 월급은 똑같이 받으면서.PR 리뷰의 무게 오후 2시. PR 7개 쌓였다. 다들 내 리뷰 기다린다. 팀장 리뷰는 형식적이다. "수고하셨습니다" 도장만 찍는다. 실제로 코드 보는 건 나다. 어제 신입이 올린 PR. 200줄짜리 함수. "이렇게 하면 나중에 유지보수 힘들어요. 함수 분리하고 다시 올려주세요." Comment 달았다. Request changes. 10분 뒤 슬랙. "선배님 죄송한데 어떻게 분리하면 될까요?" 한숨 나온다. 근데 알려줘야 한다. 안 알려주면 계속 이렇게 짠다. 그럼 나중에 내가 고친다. 결국 화면 공유 켜고 30분 설명했다. 내 일은 언제 하지.기술 스택 선택의 부담 오후 4시. 기획 회의. 새 프로젝트다. 마이크로서비스로 갈지 모놀리식으로 갈지 정해야 한다. 팀장이 나를 본다. "개발님 의견이 어떠세요?" 5명 다 나를 본다. 내가 말하면 그게 결정이다. 팀장은 내 의견에 무조건 동의한다. "전문가가 그렇다는데 그렇게 하시죠." 책임은? 3개월 뒤 문제 생기면? "제 생각엔 일단 모놀리식으로 시작하는 게..." 말하는데 목소리 떨렸다. 근데 이게 맞나. 확신이 서지 않는다. 내가 틀리면 어쩌지. 팀원들 야근시키는 거 아닌가. 직책도 없는데 이런 결정을 내가 해야 하나. 월급은 6500이다. 책임과 권한의 불균형 퇴근길. 지하철에서 생각했다. 나는 사실상 테크 리드다. 팀원들도 그렇게 본다. 기술적 결정은 다 내가 한다. 근데 내 직함은 "책임연구원"이다. 팀장 밑에 그냥 팀원이다. 연봉 협상 때 팀장이 말했다. "회사 사정이 어려워서... 내년엔 올려드릴게요." 근데 후배 채용 공고 봤다. 신입 연봉 4500. 7년차 나는 6500. 3년 일해서 2천 올랐다. 동기 민수는 이직해서 8천 받는다. 리드 개발자 직함 달고. 나는 직함도 없이 리드 일만 한다. 권한은 없다. 팀 예산 결정권 없다. 인력 충원 요청해도 "검토해보겠습니다"만 6개월째다. 근데 책임은 진다. 배포 장애 나면 새벽에 전화 온다. 내가 설계한 거니까. 후배들의 기대 문제는 후배들이다. 진심으로 나를 믿는다. 기술적으로. 신입 박신입은 입사 첫날부터 내 자리 옆에 앉았다. "선배님한테 배우고 싶어요." 2년차 이주니어는 내가 추천한 책 다 읽었다. 클린 아키텍처, DDD, 리팩터링. 다 샀다. 4년차 최선임은 이직 고민 상담을 나한테 한다. 팀장한테는 안 한다. 이 기대가 무겁다. 내가 틀린 방향 알려주면 어쩌지. 내가 잘못된 결정 내리면 다들 따라온다. 근데 나도 확신 없을 때 많다. AWS 쓸지 GCP 쓸지. Redis 쓸지 Memcached 쓸지. 테스트 커버리지 몇 퍼센트까지 잡을지. 정답 없다. 트레이드오프다. 근데 선택은 해야 한다. 내가 선택하면 팀 전체가 3개월 그 방향으로 간다. 이게 리더의 무게구나. 근데 나는 리더가 아니다. 월급도 리더급이 아니다. 인정받지 못하는 역할 더 웃긴 건 윗선이다. 분기 회의 때 팀장이 발표한다. 우리 팀 성과. "저희 팀이 이번 분기에 마이크로서비스 전환 성공했습니다." 박수 나온다. 팀장 칭찬받는다. 근데 설계한 건 나다. 문서 작성도 나. 마이그레이션 계획도 나. 팀장은 회의만 했다. 인사 평가 때도 마찬가지다. "김 연구원은 기술적으로 우수하나, 리더십이 부족합니다." 리더십? 매일 후배 가르치고, PR 리뷰하고, 기술 결정하는 게 리더십 아닌가. 아. 리더십이 아니라 "보고 잘하기"를 말하는 거구나. 팀장한테 잘 보고하고, 임원진 앞에서 발표 잘하는 거. 나는 그냥 코드나 짜는 사람. 근데 실제로는 팀 기술 다 책임진다. 모순이다. 거절의 어려움 요즘 고민이 하나 더 생겼다. 거절을 못 하겠다. 후배가 물어보면 답해줘야 한다. 안 그러면 혼자 삽질한다. 그럼 나중에 내가 고친다. 차라리 지금 30분 쓰는 게 낫다. 근데 이게 매일이다. 하루에 2시간은 후배 도와준다. 내 개발 시간은 6시간에서 4시간으로 줄었다. 퇴근도 늦어진다. 내 일 못 끝내서. 팀장한테 말했다. "제가 후배들 가르치느라 제 일을 못 하겠어요." 팀장 답변. "그래도 팀워크가 중요하잖아요. 김 연구원이 잘 이끌어줘야죠." 이끌라고? 그럼 직책 달아줘. 월급 올려줘. 아무 말 안 했다. 해봤자 소용없다. 이직 고민 집에 와서 이력서 켰다. 6개월 전에도 켰다. 3개월 전에도 켰다. 매번 닫았다. 이유는 간단하다. 귀찮다. 면접 준비해야 한다. 알고리즘 공부. 시스템 설계. 포트폴리오 정리. 퇴근하면 기력이 없다. 넷플릭스 켜놓고 폰 본다. 주말엔 늦잠 자고 치킨 먹는다. 코딩 테스트 볼 에너지가 없다. 그래서 계속 미룬다. 근데 이러다가 10년차 되는 거 아닌가. 10년차에도 6500 받으면서 리더 일만 하는 거 아닌가. 생각하면 답답하다. 근데 뭐 어쩌겠나. 내일도 출근해야 한다. 애매한 위치 결국 내 위치가 애매한 거다. 리더도 아니고 평팀원도 아니다. 책임은 리더급. 권한은 팀원급. 월급도 팀원급. 가장 불편한 자리다. 올라가지도 못하고 내려가지도 못한다. 팀장은 내가 편하다. 기술 걱정 안 해도 되니까. 나한테 다 맡기면 되니까. 후배들도 내가 편하다. 물어보면 답해주니까. 고민 안 해도 되니까. 나만 불편하다. 근데 말 안 한다. 해봤자 바뀌는 게 없다. 그냥 하루하루 버틴다. 언젠가는 바뀌겠지. 승진하거나. 이직하거나. 아니면 그냥 익숙해지거나. 지금은 그냥 버틴다. 책임감의 무게 솔직히 말하면. 후배들 믿고 따르는 거 나쁘지 않다. 내 말 듣고 성장하는 거 보면 뿌듯하다. 6개월 전 아무것도 모르던 신입이 지금은 혼자 API 설계한다. 내가 가르쳤다. 근데 이 뿌듯함만으로는 안 된다. 책임감만 늘어난다. 월급은 그대로다. 회사는 이걸 안다. 그래서 안 올려준다. 어차피 일 하니까. 내가 바보같다. 거절해야 하는데. 내 일만 해야 하는데. 근데 못 한다. 후배들 보면. 이게 리더의 함정인가. 정식 리더는 아닌데 리더 역할을 하는. 가장 손해 보는 위치. 내일도 멘션 내일 출근하면 또 슬랙 멘션 5개 있을 거다. "개발님 이거 어떻게 해야 할까요?" 그럼 또 답할 거다. 30분 써서. 내 일은 점심 먹고 시작할 거다. 퇴근은 7시? 8시? 운 좋으면 6시. 이게 7년차 시니어 개발자의 일상이다. 리더 아닌 리더. 책임만 있고 권한 없는. 월급은 6500. 동기들은 8천. 그래도 출근한다. 어쩌겠나. 이게 내 선택이었으니까. 아니다. 선택이 아니라 흘러온 거다. 7년 일하다 보니 이렇게 됐다. 내일은 뭐가 달라질까. 아무것도. 그냥 하루가 지나간다. 멘션 5개 답하고. PR 7개 리뷰하고. 회의 2시간 하고. 그렇게 한 달 지나가고. 1년 지나가고. 10년차 되겠지. 그때도 이럴까.정식 리더도 아닌데 리더 대접받는 게 제일 애매하다. 책임은 지는데 돈은 안 받는다.

동기들은 7천대, 나는 6500만원: 합리화의 기술

동기들은 7천대, 나는 6500만원: 합리화의 기술

술자리에서 들은 숫자대학 동기 모임이었다. 1년 만이었다. 고기 굽다가 준호가 말했다. "나 이번에 연봉 협상했는데." 7200만원이란다. 작년보다 500 올랐다고. 민수가 거들었다. "나도 비슷해. 7100?" 나는 고기를 뒤집었다. 입에서 "오 좋네" 같은 소리가 나왔다. 속으로는 계산기가 돌아갔다. 6500만원. 내 연봉. 700만원 차이. 한 달에 60만원. 세후로 치면... 계산 그만. "개발아, 너는?" 준호가 물었다. "비슷해." 거짓말이었다. "우리 회사 연봉 체계가 좀 달라서." 또 거짓말. 집에 오는 택시 안에서 계속 생각했다. 700만원. 700만원. 창밖을 봤다. 아무것도 안 보였다. 월요일 아침의 합리화 출근했다. 자리에 앉았다. 모니터를 켰다. 슬랙이 떴다. 읽지 않은 메시지 37개. 주말에 쌓인 거다. '준호네 회사는 더 크니까.' 첫 번째 합리화가 시작됐다. 직원 3000명. 우리는 300명. 10배 차이. 근데 3000명이면 더 바쁜 거 아닌가? 아닐 수도. 분업이 잘 돼 있을 수도. '민수는 금융권이잖아.' 두 번째. 금융권은 원래 연봉이 높다. 대신 야근이 심하다고 들었다. 들었다. 확인은 안 해봤다. 커피를 마셨다. 첫 번째 아아. 9시 17분이었다. 영수가 슬랙에 멘션을 날렸다. "형 이거 봐주실 수 있으세요?" PR 링크. 또 시작이다. 코드를 봤다. 변수명이 'data1', 'data2'. 한숨이 나왔다. "여기 네이밍 다시 해봐." 댓글을 달았다. 친절하게. '우리 회사는 여유롭잖아.' 세 번째 합리화. 9시 출근 6시 퇴근. 칼퇴 가능. 가끔. 배포일만 아니면. 그리고 버그만 안 터지면. 그리고 기획 변경만 안 들어오면. 점심시간의 계산김치찌개집에 갔다. 혼자. 사장님이 "어서오세요 김 과장님~" 하셨다. 과장 아닌데. 뭐 됐다. 밥을 먹으면서 폰으로 계산했다. 700만원 차이. 12개월로 나누면 월 58만원. 세후로 치면 43만원 정도? 43만원이면 뭐가 가능한가. 치킨 10번. 넷플릭스 프리미엄 3년 치. 아니면 월세를 좀 더 좋은 데로. 근데 나는 치킨을 월 10번이나 안 먹는다. 넷플릭스는 이미 있다. 이사는 귀찮다. '그럼 연봉이 똑같아도 별 차이 없는 거 아냐?' 이상한 논리였다. 나도 알았다. 하지만 국물을 떠먹으면서 고개를 끄덕였다. 혼자서. "잘 먹었습니다." 카드를 내밀었다. 7500원. 43만원이면 이 밥을 57번 더 먹을 수 있다는 계산이 또 돌았다. 오후 회의에서 3시 회의. 기획팀과. 수진 매니저가 말했다. "이 기능 추가 간단하죠?" 간단하지 않았다. DB 스키마 변경. API 3개 수정. 테스트 케이스 전부 다시. "한 2주 정도 걸릴 것 같은데요." 내가 말했다. "에이~ 생각보다 오래 걸리네요." 생각보다? 누구 생각? '준호는 이런 거 안 당할 텐데.' 갑자기 든 생각. 큰 회사는 기획자가 더 전문적일 거다. 개발 공수를 이해할 거다. 아마도. 또 합리화가 시작됐다. '우리 회사는 작아서 소통이 편하잖아.' 편한가? 지금 이 회의가 편한가? 기획자는 내 표정을 보고 말을 바꿨다. "그럼 3주 드릴게요." 1주 더 받았다. 작은 승리였다. 기분이 나아지진 않았다. 회의가 끝났다. 자리로 돌아왔다. 슬랙 알림 12개. '민수네는 이것보단 체계적이겠지.' 또 합리화. 확인해본 적 없는데. 퇴근길의 자문자답6시 45분에 나왔다. 오늘은 일찍 나온 거다. 지하철을 탔다. 자리가 없었다. 손잡이를 잡았다. '나는 만족하고 있나?' 질문이 떠올랐다. 대답이 안 나왔다. 만족은 아니다. 그렇다고 불만도 아니다. 그 중간 어디쯤. '그럼 이직해야 하나?' 이력서 쓰기. 포트폴리오 정리. 코딩 테스트 준비. 면접. 피곤하다. 상상만으로. '지금 회사가 나쁜 건 아니잖아.' 동료들은 괜찮다. 영수는 귀찮지만 배우려고 한다. 기획팀도 나쁜 사람들은 아니다. 그냥 일이 그런 거다. 출퇴근 시간도 나쁘지 않다. 1시간. 딱 봐줄 만. '그럼 이대로 계속?' 대답이 또 안 나왔다. 집 앞 편의점에 들렀다. 맥주 2캔을 샀다. 4600원. 700만원 차이로 살 수 있는 맥주는 몇 캔일까. 또 이런 계산. 웃겼다. 나 자신이. 집에서 아내와 문을 열었다. "다녀왔어." 아내가 소파에 있었다. 노트북을 보고 있었다. "저녁 뭐 먹어?" 아내가 물었다. "라면?" 내가 말했다. "좋아." 라면을 끓였다. 물이 끓는 동안 멍하니 냄비를 봤다. '아내한테 말해볼까?' 연봉 차이 얘기. 합리화하는 내 모습. 근데 말하면 뭐가 달라지나. 아내가 "이직해" 할 수도. "괜찮아" 할 수도. 둘 다 듣고 싶지 않았다. 라면이 끓었다. 계란을 넣었다. "오늘 일 어땠어?" 아내가 물었다. "그냥. 평범했어." 거짓말은 아니었다. 진짜 평범한 하루였다. 머릿속만 복잡했을 뿐. 라면을 먹었다. 아내는 디자인 시안 얘기를 했다. 나는 고개를 끄덕였다. 집중은 안 됐다. 머릿속에선 여전히 계산기가 돌았다. 700만원. 58만원. 43만원. 자기 전 침대에서 침대에 누웠다. 폰을 켰다. 유튜브를 봤다. 개발자 이직 브이로그. 추천 영상에 떴다. "연봉 3000 올렸습니다" 제목. 클릭했다. 5분 보다가 껐다. 부러웠다. 동시에 짜증났다. '나도 할 수 있다.' 생각했다. '하기 싫을 뿐.' 차이가 뭔가. 할 수 있는데 안 하는 거랑 못 하는 거. 나는 어느 쪽인가. 모르겠다. 솔직히. '지금도 괜찮은데.' 다시 합리화. 월급은 밀린 적 없다. 야근은 견딜 만하다. 사수 없이 혼자 일하는 거보단 낫다. 근데 그게 만족인가? 아니면 그냥 귀찮은 건가? 폰을 내려놓았다. 천장을 봤다. '동기들이 7천대라는 걸 몰랐으면.' 이 생각이 제일 솔직했다. 모르면 비교 안 했을 거다. 비교 안 하면 만족했을 거다. 아마도. 근데 알아버렸다. 이제 모를 수 없다. 눈을 감았다. 잠이 안 왔다. 내일도 출근이다. 9시. 슬랙 알림. PR 리뷰. 회의. 평범한 하루. 머릿속에선 계산기가 계속 돌았다. 결국 남은 건 아침이 왔다. 알람이 울렸다. 7시. 씻고 나갔다. 출근했다. 자리에 앉았다. 모니터를 켰다. 슬랙. 읽지 않은 메시지 23개. '오늘도 똑같네.' 근데 다른 게 하나 있었다. 어제까지는 이게 당연했다. 오늘부터는 선택처럼 느껴진다. 이직할 수도 있다. 안 할 수도 있다. 연봉을 올릴 수도 있다. 이대로 갈 수도 있다. 근데 나는 아직 아무것도 안 한다. 합리화만 한다. "지금도 괜찮아." "이직은 귀찮아." "동기들은 환경이 달라." 다 맞는 말이다. 동시에 다 핑계다. 진짜 문제는 뭔가. 만족도 불만도 아닌 이 어정쩡한 상태에서, 움직이기엔 에너지가 부족하고, 참기엔 자존심이 걸린다는 것. 그리고 그걸 인정하기 싫어서 계속 이유를 만든다는 것. 영수가 슬랙에 멘션을 날렸다. "형 이거 봐주세요." 또 PR이다. "어 본다." 답장을 보냈다. 코드를 열었다. 리뷰를 시작했다. 700만원 차이 생각은 잠시 멈췄다. 일은 계속됐다. 합리화도.결국 나는 아직 아무것도 바꾸지 않았다. 내일도 똑같을 거다. 모레도. 언젠가 바뀔까? 모르겠다. 오늘은 일단 커피나 한 잔 더 마셔야겠다.

주말 문자: '혹시 확인 가능하신가요?'의 무서움

주말 문자: '혹시 확인 가능하신가요?'의 무서움

주말 문자: '혹시 확인 가능하신가요?'의 무서움 토요일 오후 3시 27분 침대에 누워 있었다. 넷플릭스 틀어놓고 폰으로 커뮤니티 보는 중. 딱 이 타이밍에 진동이 왔다. 슬랙 알림. "김개발님, 혹시 주말인데 죄송하지만 확인 가능하신가요?" 심장이 쿵 내려앉는다. 토요일이 끝났다. 정확히는 3시 27분에.메시지 내용은 안 봐도 안다. "급한 건 아닌데" 로 시작하는 글은 100% 급하다. "시간 되실 때" 라고 쓴 건 "지금 당장" 이란 뜻이다. 물음표 하나가 주말을 파괴한다. 확인하지 말까, 확인할까 5초간 고민한다. 안 본 척? 불가능하다. 이미 슬랙이 '읽음' 표시를 띄웠을 수도 있다. 설령 안 읽어도, 내일 출근하면 "어제 메시지 못 보셨어요?" 가 기다린다. 확인하면? 주말이 증발한다. "네 확인해볼게요" 라고 답장하는 순간, 나는 출근 상태가 된다. 침대는 책상이 되고, 휴식은 업무가 된다. 결국 확인한다. 안 할 수가 없다.내용을 본다. "고객사에서 데이터 조회가 안 된다고 하는데, 혹시 서버 확인 부탁드려요. 급하진 않은데 월요일 전에 해결되면 좋을 것 같아서요." 급하지 않다고? 월요일 전이면 오늘 아니면 내일이다. 이게 급하지 않은 거면 뭐가 급한 건데. 노트북을 켠다 한숨이 나온다. 침대에서 일어난다. 거실로 간다. 노트북 가방을 집는다. 무겁다. 마음이 더 무겁다. 전원을 켠다. 부팅 소리가 주말 종료 알람처럼 들린다. VPN 접속. 비밀번호 치는 손가락이 무겁다. 아내가 거실로 나온다. "왜? 뭐 일 있어?" "응... 좀 급한 거래." 미안하다는 말은 안 한다. 이미 몇 번을 겪었으니까. 아내는 한숨만 쉬고 들어간다.모니터링 툴을 연다. 그라파나, 키바나, 센트리. 로그를 본다. 에러는 없다. 데이터베이스 접속한다. 쿼리 날린다. 결과는 정상이다. 10분 지났다. 문제가 없다. 슬랙에 답장한다. "확인했는데 서버는 정상입니다. 혹시 어떤 화면에서 어떻게 조회하셨는지 알 수 있을까요?" 답장이 온다. 20분 후에. "아 고객사가 캐시 문제였나봐요. 새로고침하니까 되네요. 감사합니다!" 캐시. F5 한 번이면 되는 걸로 내 토요일 오후가 날아갔다. 그래도 끌 수가 없다 노트북을 닫아야 한다. 알고 있다. 근데 안 닫힌다. "혹시 또 문자 오면?" 이라는 생각이 든다. 이미 노트북 켜놨으니까, 그냥 좀 더 보는 게 낫지 않나. 슬랙 채널을 훑는다. 어제 올라온 메시지들. 지라 티켓도 확인한다. 새로 등록된 버그 3건. PR도 하나 올라와 있다. 후배가 올린 거. "주말엔 안 봐도 되는데..." 라고 생각하면서 클릭한다. 코드를 본다. 리뷰를 단다. "이 부분 null 체크 필요할 것 같아요." 댓글 남기고 나서 후회한다. 주말에 왜 리뷰를 달았지. 후배가 주말에 수정하면 어떡하지. 너무 늦었다. 이미 후배가 답글을 달았다. "오 감사합니다! 수정했어요." 주말 근무가 전염된다. 저녁이 되어도 시계를 본다. 6시 반. 아내가 저녁 먹자고 한다. "응, 곧 갈게." 노트북은 아직 켜져 있다. 슬랙 알림은 여전히 켜져 있다. 치킨을 시켰다. 아내랑 같이 먹는다. 근데 폰은 식탁 위에 있다. 화면이 보이는 각도로. 진동이 올 때마다 시선이 간다. "업무 채널 아니겠지?" 확인한다. 다행히 스팸 문자다. 치킨 먹으면서도 긴장한다. 주말인데 주말이 아니다. 아내가 말한다. "너 맨날 주말에도 폰 보더라. 그냥 알림 끄면 안 돼?" 끌 수 있으면 진작 껐다. 문제는 알림이 아니다. 내 머릿속이 문제다. 알림 꺼도 "혹시 급한 거 왔으면?" 이라는 생각이 든다. 30분마다 슬랙 확인한다. 아무 메시지 없으면 다행이다. 근데 또 30분 후에 확인한다. 이게 주말 근무보다 피곤하다. 차라리 일하는 게 나을 것 같다는 생각이 든다. 일요일도 마찬가지 일어나자마자 폰을 본다. 슬랙 확인. 다행히 메시지 없다. 근데 안심이 안 된다. "아직" 없는 것뿐이다. 샤워하면서도 폰을 가까이 둔다. 혹시 진동 소리 못 들을까봐. 점심 먹고 카페 간다. 아내랑. 노트북은 안 가져왔다. 의지의 한국인. 근데 폰은 있다. 핫스팟 켜면 된다. 만약 급한 일 생기면 노트북 가지러 집 갔다 오면 된다. 왕복 30분. 충분히 가능하다. 카페에서 2시간 있었다. 슬랙 17번 확인했다. 메시지는 없었다. 돌아오는 길에 생각한다. "오늘은 조용하네. 내일 월요일이 걱정이다." 주말이 끝나가는데 안도감이 든다. 이상하다. 주말이 끝나는 게 다행이라니. 월요일 출근 9시에 출근한다. 컴퓨터 켠다. 슬랙 연다. 주말 메시지 쭉 확인한다. 토요일 메시지: 캐시 문제 해결. 일요일 메시지: 없음. 결국 토요일 그 한 건이었다. 그 한 건 때문에 주말 이틀을 긴장하며 보냈다. 치킨 먹을 때도, 카페 갈 때도, 자기 전에도. 동료가 말한다. "주말 잘 쉬었어?" "응, 뭐 그럭저럭." 거짓말이다. 하나도 안 쉬었다. 그 문자의 정체 "혹시 확인 가능하신가요?" 이 문장이 무서운 이유를 안다. 급하다는 뜻이다. 근데 급하다고 안 쓴다. 완곡하게 물어본다. 선택권이 있는 것처럼. 실제로는 선택권이 없다. "아니요, 확인 불가능합니다" 라고 답할 수 있나? 못 한다. 절대로. 그래서 더 무섭다. 거절 불가능한 부탁. 그게 물음표로 포장되어 온다. "죄송하지만" 이라는 말도 들어간다. 미안해하면서 부탁한다. 거절하기 더 어렵다. "주말인데" 라고 명시한다. 본인도 알고 있다. 주말이란 걸. 근데 보낸다. 그만큼 급하다는 뜻이다. 결국 이 문장은 명령이다. 물음표로 끝나는 명령문. 경력이 쌓일수록 신입 때는 달랐다. 주말 메시지 오면 선배가 처리했다. "내가 볼게, 넌 쉬어" 라고 했다. 지금은 내가 제일 시니어다. 주말 메시지는 내게 온다. 후배들한테 떠넘길 수도 있다. 근데 안 한다. 왜냐하면 나도 당했으니까. "김개발님이 봐주시면 빠를 것 같아서요." 이 말의 뜻: 다른 사람은 못 한다. 너만 가능하다. 책임감이 주말을 잡아먹는다. 연봉이 오를수록 주말은 짧아진다. 시니어라는 타이틀의 대가. 신입 때는 주말에 연락 없었다. "경력 쌓으면 편해지겠지" 라고 생각했다. 틀렸다. 반대였다. 대응 방법들 방법을 찾아봤다. 커뮤니티에. "알림 끄세요." 끄면 불안하다. 이미 답했다. "회사 핸드폰 따로 쓰세요." 회사가 안 준다. 개인 폰에 슬랙 깔아야 한다. "퇴근하면 슬랙 로그아웃하세요." 해봤다. 30분 버티다가 다시 로그인했다. "업무 시간 외 연락 금지 문화 만드세요." 어떻게? 나부터 지키질 못한다. 해외 사례도 봤다. 프랑스는 '연결되지 않을 권리' 가 법으로 있다. 부럽다. 한국은 '확인 가능하신가요' 가 문화다. 결국 답은 없다. 회사를 옮겨도 마찬가지다. 어디를 가도 '혹시 확인 가능하신가요' 는 있다. IT 업계의 숙명. 24시간 운영, 24시간 대기. 진짜 무서운 건 적응한다는 거다. 처음엔 화났다. 주말인데 왜 연락하냐고. 지금은 그냥 확인한다. 당연하다는 듯이. 주말에 메시지 안 오면 이상하다. "오늘은 조용하네?" 라고 생각한다. 평화로운 주말이 불안하다. "월요일에 터지는 거 아니야?" 걱정한다. 이게 무섭다. 주말 근무를 당연하게 받아들이는 나. 동기들이랑 술 마셨다. 한 친구가 말했다. "너 주말에도 폰 계속 보더라. 슬랙이야?" "응, 습관이야." "끄면 안 돼?" "끄면 불안해." 친구가 웃었다. "너 중독됐다." 맞다. 중독이다. 일 중독이 아니라 불안 중독. 그래도 안 볼 수는 없다. 현실적으로 생각한다. 무시하면 월요일이 지옥이다. 처리 안 된 이슈가 쌓인다. 주말에 30분 일하면 월요일 3시간 아낀다. 그게 더 낫다. 효율적이다. 이렇게 합리화한다. 아내한테 설명했다. "지금 안 하면 월요일에 더 힘들어." 아내가 말했다. "그럼 월요일은 언제 또 힘드냐?" 대답 못 했다. 맞는 말이다. 월요일 처리하면 화요일 급한 게 온다. 화요일 처리하면 수요일 급한 게 온다. 끝이 없다. 주말에 미리 처리하는 건 해결이 아니다. 그냥 이슈를 당겨오는 것뿐이다. 이상과 현실 이상: 주말엔 완전히 쉰다. 현실: 주말엔 반쯤 쉰다. 노트북은 안 켜도 폰은 확인한다. 긴급한 것만 처리한다. 근데 모든 게 긴급하다. 타협한다. "토요일엔 확인만, 일요일엔 아예 안 봐." 지켜진 적 없다. "오전엔 확인 안 해, 오후에만." 이것도 안 된다. 오전 10시에 확인한다. "자기 전엔 절대 확인 안 해." 누워서 확인한다. 마지막으로. 결국 다 확인한다. 규칙은 깨지라고 있는 거다. 내 규칙은. 다른 직군은 디자이너인 아내는 주말에 연락 없다. "너희는 급한 거 없어?" "있지. 근데 주말엔 안 해." "그럼 월요일에 늦는 거 아니야?" "늦으면 늦는 거지. 주말인데." 부럽다. 개발자는 다르다. 서버가 죽으면 매출이 죽는다. 버그가 터지면 고객이 떠난다. "월요일까지 기다려주세요" 가 안 통한다. 그래서 주말에도 대기한다. 소방관처럼. 경찰관처럼. 근데 우리는 수당도 없다. 마케터 친구도 비슷하다. "주말엔 캠페인 안 돌려. 평일에만." 기획자 친구는 더하다. "주말? 당연히 쉬지. 왜?" 우리만 이렇게 사는 건가. 아니다. 다른 개발자들한테 물어봤다. 똑같다. 다들 주말에도 확인한다. 이게 정상인가, 비정상인가. 업계 전체가 이러면 정상인 건가. 언제까지 10년 차 선배한테 물었다. "선배도 주말에 확인해요?" "당연하지." "언제까지 해야 돼요?" "나도 모르겠다. 아직도 하고 있으니까." 희망이 없다. 은퇴할 때까지? 이직해도? 프리랜서 돼도? 서버가 돌아가는 한, 우리는 대기한다. 365일, 24시간. 실제로 일하는 건 아니어도, 대기는 한다. 이게 개발자의 숙명이다. 코드는 자면서도 돌아간다. 그래서 우리도 자면서 깬다. 폰 진동 소리에. 토요일 오후 3시 27분의 공포 다시 그 순간으로 돌아간다. 침대에 누워 있다. 평화롭다. 진동이 온다. 슬랙이다. "혹시 확인 가능하신가요?" 이 문장이 눈에 들어오는 순간, 주말이 끝난다. 정확히 3시 27분에. 앞으로 몇 시간이 남았는지는 중요하지 않다. 이미 출근 모드로 전환됐다. 뇌가 깨어난다. 휴식 모드 종료. 어떤 이슈일까. 심각한 건가. 빨리 처리 가능한가. 생각이 돌아가기 시작한다. 주말은 시간으로 측정되지 않는다. 메시지 하나로 시작되고 끝난다. "혹시 확인 가능하신가요?" 이게 주말 종료 알람이다.다음 주말도 똑같을 것이다. 그다음 주말도. 근데 확인은 할 거다. 안 볼 수가 없으니까.

야근 문화와 싸우는 개발자의 딜레마

야근 문화와 싸우는 개발자의 딜레마

야근 문화와 싸우는 개발자의 딜레마 또 8시 오늘도 6시가 됐다. 퇴근 시간이다. 근데 아무도 안 일어난다. 팀장이 자리에 앉아있다. 모니터를 보고 있다. 뭘 하는지는 모르겠다. 아마 메일 보는 중일 거다. 근데 그게 중요한 게 아니다. 그가 있다는 게 중요하다. 옆자리 박주임도 앉아있다. 헤드폰 끼고 코드 치는 척한다. 실제로 치고는 있는데, 급한 건 아닌 거 안다. 오전에 그 작업 끝났다고 했으니까. 나도 앉아있다. PR 리뷰를 한다. 급한 건 아니다. 내일 봐도 된다. 근데 지금 보고 있다. 이상하다. 다들 일이 있어서 남는 게 아니다. 남아야 해서 남는다.효율성이라는 허상 작년에 책을 읽었다. '실리콘밸리 어쩌구' 그런 제목이었다. 내용은 간단했다. 야근하지 마라. 쉬어라. 그게 효율적이다. 맞는 말이다. 실제로 그렇다. 피곤하면 코드 품질 떨어진다. 버그 만든다. 다음날 그거 고치느라 시간 쓴다. 악순환이다. 데이터도 있다. 주 40시간 이상 일하면 생산성 감소한다고. 그래프도 봤다. 50시간 넘으면 오히려 마이너스라고. 알고 있다. 다들 알고 있다. 근데 7시 반이다. 아직도 다들 앉아있다. 효율성? 그런 거 여기선 통하지 않는다. 적어도 우리 팀에선. 회사는 말한다. "워라밸 중요합니다." 복지 페이지에 써있다. 채용공고에도 있다. 근데 실제로는 다르다. 6시에 나가는 사람? "일 별로 없나보네." 이런 소리 들린다. 직접 듣진 않았다. 근데 분위기로 안다. 작년에 신입이 왔었다. 매일 6시 10분에 퇴근했다. 3개월 만에 팀 바뀌었다. 공식적인 이유는 '업무 적합성' 문제였다. 그 뒤로 아무도 6시에 안 나간다.야근의 구조 야근은 전염된다. 팀장이 남으면 주임이 남는다. 주임이 남으면 대리가 남는다. 대리가 남으면 사원이 남는다. 피라미드다. 역삼각형 피라미드. 가끔 팀장이 먼저 간다. "오늘은 약속 있어서." 이럴 땐 다들 7시쯤 나간다. 그래도 6시는 아니다. 너무 빨리 나가면 이상하니까. 근데 그런 날은 한 달에 한두 번이다. 배포일엔 더하다. 배포는 보통 오후 6시에 시작한다. 왜 6시냐고? 그게 규칙이니까. 배포 준비하느라 4시부터 긴장한다. 5시엔 테스트 서버 확인한다. 6시에 프로덕션 배포한다. 7시까지 모니터링한다. 문제 없으면 8시쯤 퇴근한다. 문제 생기면? 10시다. 운 좋으면. 작년엔 새벽 2시까지 있었다. 롤백하고, 원인 찾고, 다시 배포하고. 퇴근할 때 편의점에서 삼각김밥 샀다. 아침인지 저녁인지 모르겠더라. 다음날은? 9시 출근이다. 당연하다. 야근은 자발적인 거니까. 공식적으로는. 싸워봤다 한번 시도했다. 6개월 전쯤. 팀 회의에서 말했다. "야근 줄였으면 좋겠습니다. 효율성 측면에서도 그렇고요." 팀장이 고개 끄덕였다. "그러게. 다들 일찍 퇴근했으면 좋겠어." 끝이다. 대화는 거기까지였다. 다음날? 똑같다. 아무것도 안 바뀌었다. 일주일 뒤 다시 말했다. "지난번에 말씀드린 야근 건인데요." "아, 그거? 근데 지금 프로젝트 일정이 좀 빡빡해서. 마무리되면 그때 다시 얘기하자." 프로젝트는 끝났다. 다음 프로젝트가 시작됐다. 여전히 빡빡했다. 항상 빡빡하다. 2주 동안 나 혼자 6시에 퇴근했다. 실험이었다. 결과? 소외감. 팀원들이 저녁에 얘기한다. 슬랙에. "아 이 부분 김대리님 의견 필요한데." 나는 없다. 집에 있다. 다음날 아침. "어제 그 건 결정 났어요. 김대리님 의견 못 들어서 아쉬웠는데." 미안하다는 말투는 아니었다. 결국 다시 남게 됐다. 7시 반까지는.숫자로 보는 야근 계산해봤다. 하루 1.5시간 야근. 주 5일이면 7.5시간. 한 달이면 30시간. 30시간이면 거의 4일이다. 한 달에 4일을 공짜로 일하는 셈이다. 1년이면? 360시간. 45일. 두 달이다. 연봉 6500만원. 12개월로 나누면 월 541만원. 거기에 두 달 치면... 1082만원. 1년에 천만 원 어치를 공짜로 일한다. 물론 포괄임금제다. 계약서에 '월 20시간 야근 포함'이라고 써있다. 근데 실제론 30시간 넘게 한다. 초과 10시간. 시급으로 환산하면... 계산하기 싫다. 동기가 이직했다. 작년에. 연봉 7200 받는다고 했다. 야근? 거의 없다고. 배포 자동화 되어있고, 온콜도 돌아가면서 한다고. 700만 원 더 받으면서 야근도 안 한다. 나는? 여기서 야근한다. 왜? 이직이 귀찮아서. 면접 준비해야 한다. 알고리즘 문제 풀어야 한다. 이력서 써야 한다. 회사 찾아봐야 한다. 근데 야근하느라 시간이 없다. 야근 때문에 이직 못 하고, 이직 못 해서 야근한다. 순환논리다. 문화라는 이름의 감옥 야근은 문화다. 명문화되지 않은 규칙이다. 아무도 강요하지 않는다. 공식적으로는. 근데 다들 한다. 안 하면 이상한 사람 된다. 신기한 건 다들 싫어한다는 거다. 야근. 점심시간에 불평한다. "진짜 야근 지긋지긋해." 커피 마시면서 한숨 쉰다. "오늘도 늦게 가겠네." 근데 저녁 6시 되면? 다들 앉아있다. 변화를 원하지만 누구도 시작하지 않는다. 시작하면 손해니까. 먼저 나가면 찍히니까. 죄수의 딜레마다. 경제학 시간에 배웠던 거. 다들 협력하면 최선인데, 배신이 두려워서 결국 최악을 선택한다. 우리가 그렇다. 다 같이 6시에 퇴근하면 좋다. 근데 아무도 먼저 안 나간다. 결국 다 같이 8시까지 남는다. 최악의 균형이다. 근데 안정적이다. 아무도 깨지 않는다. 합리화의 기술 사람은 자기 행동을 합리화한다. 나도 그렇다. 야근하면서 생각한다. "뭐 그래도 요즘 10시까진 안 남잖아." "다른 회사는 더 심하대." "원래 개발자가 이런 거지." 거짓말은 아니다. 다 사실이다. 근데 위안이 되진 않는다. 가끔 반성한다. '내가 왜 이러고 있지?' 답은 알고 있다. 편해서. 익숙해서. 변화가 무서워서. 이직하면 새로운 사람들. 새로운 코드베이스. 새로운 규칙. 적응해야 한다. 증명해야 한다. 피곤하다. 차라리 여기서 야근하는 게 편하다. 적어도 익숙하다. 이직 준비할 시간에 넷플릭스 본다. 주말엔 늦잠 잔다. '다음 주부터 해야지.' 다음 주는 오지 않는다. 의지의 문제가 아니다. 시스템의 문제다. 근데 시스템은 안 바뀐다. 그럼? 내가 바뀌어야 한다. 근데 안 바뀐다. 그냥 야근한다. 해답은 없다 결론은 뭐냐고? 없다. 야근 문화는 당장 안 바뀐다. 내가 바꿀 수도 없다. 회사 전체의 문제니까. 할 수 있는 건 개인적 대응뿐이다. 이직할까? 진지하게 고민은 한다. 근데 실행은 안 한다. 아직은. 효율을 올릴까? 낮에 집중해서 일 끝내고 6시에 나갈까? 시도는 해본다. 근데 결국 남는다. 분위기 때문에. 타협한다. 7시 반까지만. 8시 넘기지 말자. 스스로 선 긋는다. 근데 배포일엔 어차피 넘긴다. 모순이다. 알면서 한다. 비효율적인 걸 알면서 반복한다. 왜? 그게 여기 문화니까. 나 혼자 바꿀 수 없으니까. 결국 적응이다. 불편하지만 참을 만하다. 최악은 아니다. 그냥 그렇다. 언젠가는 바뀔까? 모르겠다. 아마 안 바뀔 거다. 근데 희망은 버리지 않는다. 그게 버티는 방법이니까.오늘도 8시에 퇴근했다. 내일도 그럴 거다. 모레도.

API 문서화를 미뤘다가 생기는 혼란

API 문서화를 미뤘다가 생기는 혼란

문서화는 나중에 API 개발 끝났다. 배포도 했다. 근데 문서는 안 썼다. "나중에 쓰지 뭐." 그게 3주 전이다. 이제 슬랙이 난리다. "김개발님 이 API 파라미터가 뭐예요?" "응답 형식이 어떻게 되죠?" "에러코드 정리된 거 있어요?" 코드 보면 되는데. 근데 그것도 민망하다.처음엔 괜찮았다 처음 2주는 괜찮았다. 나만 쓰는 API였으니까. 인증 토큰은 헤더에 Authorization: Bearer {token}. 페이징은 page랑 size. 정렬은 sort. 당연한 거 아닌가. 근데 프론트팀 신입이 들어왔다. 김신입. "김개발님, API 명세서 어디 있어요?" "아... 그게... 코드 보면 돼요." "네? 코드요?" 말하면서도 개같다는 걸 알았다. 질문이 쌓인다 김신입은 착하다. 슬랙으로 물어본다. 하나씩. "User API의 role 필드 값이 뭐가 올 수 있나요?" "ADMIN, USER, GUEST 세 개요." 10분 후. "null일 수도 있나요?" "아뇨. 필수값이에요." 또 10분. "그럼 기본값은 뭐예요?" "기본값 없어요. 회원가입 때 지정해야 해요." 한 필드에 세 번 물었다. 나는 코드 짜다 말고 세 번 답했다.그냥 코드 보라고 할까 "코드 보면 다 나와요." 이렇게 말하고 싶다. 근데 그게 개발자 오만이라는 걸 안다. 코드가 문서는 아니니까. 프론트 개발자가 스프링 코드 뒤적이면서 @RequestBody가 뭔지 찾아보고, @Valid 어노테이션 의미 파악하고, 유효성 검증 로직 추적하고... 그건 폭력이다. 근데 문서 쓰는 것도 폭력이다. 나한테. 회의에서 터졌다 기획자 박기획이 말했다. "이번 기능, API 호출 시나리오 정리 좀 해주세요." "시나리오요?" "네. 어떤 순서로 어떤 API 호출하는지요. 플로우차트 같은 거." "그건... QA팀이 테스트하면서 보면 되는 거 아닌가요?" "QA도 모르는데요. 문서가 없어서." 회의실이 조용해졌다. 다들 나를 봤다. 나는 모니터 보면서 펜 돌렸다. "...알겠습니다."일단 미뤘던 이유 문서화를 안 한 게 게을러서만은 아니다. 변명이긴 한데, 진짜다. API가 계속 바뀌었다. 초기 개발 단계라서. 처음엔 User 조회가 GET /user/{id}. 근데 기획 바뀌어서 GET /users/{id}로 수정. 복수형. 응답 형식도 바뀌었다. 처음엔 유저 객체 그대로 내려줬는데, 나중에 래핑해서 { data: {...}, meta: {...} } 형태로. 에러 코드는 3번 바뀌었다. USER_NOT_FOUND가 USER_001이 됐다가 다시 ERR_USER_NOT_FOUND로. 그때마다 문서 고치려면 개빡친다. 그래서 "일단 완성되면 쓰지" 했는데. 완성은 안 된다. 계속 수정된다. 코드로 자동 생성? "Swagger 쓰세요." 후배 이후배가 말했다. "Swagger요?" "네. 어노테이션 달면 문서 자동 생성돼요." 알긴 아는데. 도입이 귀찮다. 어노테이션 달려면 컨트롤러마다 @ApiOperation, @ApiParam 다 붙여야 한다. 우리 API 엔드포인트가 47개다. 기존 코드 47개 파일 열어서 어노테이션 추가. 그것도 일이다. "시간 나면 해볼게요." 이후배는 더 안 물었다. "시간 나면"이 뭔 뜻인지 아니까. 문서 쓰기 시작했다 결국 썼다. Notion 페이지 만들었다. "API 문서" 제목 달고. 목차 만들고.인증 User API Post API Comment API ...47개 엔드포인트를 정리하기 시작했다. 각 API마다:메서드, URL 요청 파라미터 요청 바디 예시 응답 예시 에러 케이스첫 번째 API 정리하는 데 30분 걸렸다. "30분 곱하기 47... 2350분... 39시간?" 계산기 두드리다가 한숨 나왔다. 누가 봐주긴 할까 4시간 정도 쓰고 12개 API 문서화했다. 진도는 25%. 슬랙에 공유했다. "API 문서 작성 시작했습니다. 피드백 주세요." 5분 후 김신입이 답장했다. "오오 감사합니다!" 그게 끝이다. 다른 반응은 없다. "이거 진짜 다 쓸 가치가 있나?" 혼잣말이 나왔다. 근데 김신입이 질문이 확 줄었다. 슬랙 알림이 조용하다. 그거면 됐다. 유지보수가 문제다 이틀 뒤 기획 변경됐다. User API에 nickname 필드 추가. 필수값. 2~10자. 코드는 10분 만에 고쳤다. 근데 문서는? Notion 열어서 User API 섹션 찾아서. 요청 바디 예시 수정하고. 응답 예시 수정하고. 유효성 검증 규칙 추가하고. 15분 걸렸다. "이래서 안 쓰는 건데." 또 혼잣말. 그리고 1주일 뒤 또 기획 변경. 이번엔 문서 업데이트 안 했다. "나중에 몰아서 하지." 3주 전 그 마인드가 돌아왔다. 문서가 틀렸다 김신입이 또 물었다. "문서랑 실제 API 응답이 달라요." "어디요?" "nickname 필드가 안 내려와요." "아, 그거 선택값으로 바뀌었어요." "문서에는 필수라고 돼있는데..." "...업데이트 깜빡했네요." 이게 더 최악이다. 문서가 없는 것보다 틀린 문서가 더 위험하다. 김신입은 틀린 문서 믿고 개발했다. 필수값이니까 예외처리 안 했다. 버그 났다. 내 잘못이다. Swagger를 결국 도입했다 주말에 했다. 집에서. Spring REST Docs도 고민했는데, 테스트 코드 짜야 해서 패스. Swagger가 빠르다. 의존성 추가. 설정 파일 작성. 컨트롤러에 어노테이션 추가. @ApiOperation(value = "유저 조회", notes = "ID로 유저 조회") @ApiResponses({ @ApiResponse(code = 200, message = "성공"), @ApiResponse(code = 404, message = "유저 없음") }) @GetMapping("/users/{id}") public UserResponse getUser(@PathVariable Long id) { ... }이런 식으로 47개 엔드포인트 다 달았다. 토요일 오후 내내. 근데 뭔가 뿌듯하다. 코드 정리하니까 보기 좋다. /swagger-ui.html 접속해봤다. 문서가 예쁘게 나온다. "이거 괜찮네." 팀원들 반응 월요일에 공유했다. "Swagger 도입했습니다. /swagger-ui.html 확인해보세요." 김신입 답장이 빨랐다. "헐 대박이에요!" 이후배도 반응했다. "오 형 주말에 이거 하신 거예요?" "그냥 심심해서요." 사실 김신입이 계속 물어볼까봐 불안해서 한 거다. 기획자 박기획도 봤다. "이거 좋네요. 이제 기획 전달할 때 이거 보여드리면 되겠어요." 개발 안 하는 사람도 보기 쉽다는 게 Swagger 장점이다. 그래도 완벽하진 않다 Swagger도 한계는 있다. 복잡한 비즈니스 로직 설명은 어렵다. 어노테이션만으로는. "결제 API는 먼저 주문 생성하고, 그 다음 결제 요청하고..." 이런 플로우 설명은 못한다. 에러 케이스 설명도 부족하다. 400 에러가 나는 이유가 10가지인데, 그걸 다 @ApiResponse에 못 쓴다. 인증 토큰 발급 과정, 리프레시 토큰 로직... 이런 건 별도 문서 필요하다. 결국 Swagger + Notion 병행하게 됐다. Swagger는 API 레퍼런스. Notion은 가이드 문서. 둘 다 관리하는 건 귀찮은데. 그래도 없는 것보단 낫다. 유지보수는 여전히 숙제 한 달 지났다. Swagger 문서도 낡아간다. 신규 API 추가할 때 어노테이션 빼먹는다. 급하니까. "나중에 추가하지." 그러고 까먹는다. 김신입이 또 물어본다. "새로 추가된 알림 API 문서는 어디 있어요?" "아... 어노테이션 추가 안 했네요. 코드 보면..." 또 "코드 보면"이 나왔다. 문서화는 일회성이 아니다. 계속 관리해야 한다. 그게 어렵다. PR 체크리스트에 추가 이후배가 제안했다. "PR 템플릿에 문서 업데이트 항목 추가하는 거 어때요?" "PR 템플릿에요?" "네. API 변경 시 Swagger 어노테이션 업데이트했는지 체크하는 거요." ## Checklist - [ ] 테스트 코드 작성 - [ ] API 변경 시 Swagger 문서 업데이트 - [ ] 코드 리뷰 반영괜찮은 아이디어다. 실제로 추가했다. 다들 체크는 한다. 안 하면 내가 코멘트 달아준다. "Swagger 문서 업데이트 부탁드려요." 처음엔 귀찮아했는데, 한 달 지나니 습관 됐다. 신규 API 만들 때 자동으로 어노테이션 단다. 이제는. 문서화 문화 결국 문화 문제다. "문서화는 나중에" 이 마인드가 문제였다. 개발하면서 동시에 문서 작성. 이게 기본이 돼야 한다. 근데 그게 쉽지 않다. 특히 일정 촉박할 때. "기능 개발이 먼저고 문서는 나중에" 이 생각이 자동으로 나온다. 팀장이 "문서화도 개발의 일부"라고 강조한다. 맞는 말인데. 실천이 어렵다. 지금도 완벽하진 않다. 그래도 3달 전보단 낫다. 배운 것들 API 개발하고 문서 안 쓰면:팀원이 계속 물어본다. 슬랙 알림 지옥. 신입이 헤맨다. 온보딩 시간 3배. 기획/QA가 답답해한다. "이거 어떻게 테스트해요?" 나도 까먹는다. 3개월 전 API 뭐였는지 기억 안 남.문서화 방법:Swagger/OpenAPI: API 레퍼런스용, 자동 생성 가능 Notion/Wiki: 가이드, 플로우, 비즈니스 로직 설명 README: 빠른 시작 가이드 코드 주석: 복잡한 로직만중요한 건 도구가 아니라 습관이다. 개발 끝나고 "나중에 쓰지"가 아니라, 개발하면서 바로 쓰기. PR 체크리스트에 넣기. 리뷰 때 확인하기. 완벽하지 않아도 된다. 없는 것보단 낫다. 3개월 후 효과 문서화 시작하고 3개월 지났다. 김신입 질문이 80% 줄었다. 슬랙 조용하다. 신규 입사자 온보딩 시간 절반 됐다. Swagger 보고 바로 개발 시작. QA팀이 좋아한다. "이제 테스트 케이스 짜기 쉬워요." 나도 편하다. "코드 보면 돼요" 안 해도 된다. 시간 투자는 했다. 주말 하루, 그 뒤로 일주일에 1시간씩. 근데 그거 하고 절약되는 시간이 더 크다. 질문 답하는 시간, 설명하는 시간, 디버깅 도와주는 시간. "진작 할 걸" 이 생각 든다. 여전히 귀찮다 그래도 솔직히 말하면. 여전히 귀찮다. API 하나 추가할 때마다 Swagger 어노테이션 5줄 쓰는 거. 귀찮다. Notion 가이드 문서 업데이트하는 거. 귀찮다. 기획 변경될 때마다 문서 수정하는 거. 귀찮다. 근데 한다. 안 하면 더 귀찮아지니까. 김신입이 또 물어보는 게 더 귀찮다. 틀린 문서 때문에 버그 나는 게 더 귀찮다. 문서화는 미래의 나를 위한 투자다. 그리고 팀을 위한 배려다. 개발자가 코드만 짜면 된다는 생각. 학생 때 끝났어야 했다. 실무에서는 커뮤니케이션도 개발이다. 문서도 개발이다."나중에"는 영원히 안 온다. 지금 쓰거나, 계속 물어봐 주거나.

테크 리드인데 직책이 없는 개발자의 슬픈 현실

테크 리드인데 직책이 없는 개발자의 슬픈 현실

테크 리드인데 직책이 없는 개발자의 슬픈 현실 월요일 아침 9시. 출근해서 첫 번째 할 일은 슬랙 확인이다. 주말에 올라온 PR이 3개. 후배들이 기다리고 있다. 내가 안 보면 머지가 안 된다. 그들은 나를 기술 리드라고 부르고, 난 그렇게 행동한다. 근데 직책은? 개발자. 그냥. 개발자. 커피를 마신다. 첫 번째다. 아 그거요, 하면서 PR을 본다. 주니어가 짠 코드다. 구조가 이상하다. 리팩토링이 필요하다. 근데 내가 코드를 다시 짜줄 수는 없으니까 "이 부분에서 의존성이 뭔지 생각해봐요"라고 댓글을 단다. 그게 메멘토링이다. 멘토링이 아니라 메멘토링. 내 시간을 쪼개서 하는. 3년 다음에 이직한 친구는 시니어 개발자다. 직책도 있고 연봉도 7천대라고 했다. 나? 6500만원. 올해도 200만원 인상되고 끝.업무 현황: 나는 누구인가 사실 나는 테크 리드다. 팀의 기술 방향을 정한다. 새 프레임워크 도입할 때 나한테 물어본다. 레거시 코드 얘기 나올 때 다들 날 쳐다본다. 마이그레이션 프로젝트? 내가 계획 짠다. 아키텍처 리뷰? 내 책임이다. 그런데 직책은 개발자다. 팀 회의에서 내 발언이 '의견'이 아니라 '지시'로 들린다는 걸 안다. 근데 공식적으로는 선임이 아니니까 누가 책임질 건 애매하다. "그렇게 했어요"라고 하면 "그거 누가 결정했어?"라고 물어본다. 나다. 내가 했다. 근데 나는 개발자고 선임은 아니고. 후배 성과평가? 내가 쓴다. 근데 평가 논의할 때 나는 반영만 된다. 경영진은 직급이 뭐라고 물어본다. 아, 개발자다. 그럼 의견만 듣겠습니다. 라고 한다. 의견만. 페이 밴드는? 개발자 페이 밴드다. 시니어 밴드까지 가려면 1년이 더 필요하다고 HR이 말했다. 그 1년 동안 나는 테크 리드고 지금과 같이 일한다. 이게 3년이다. 커피를 마신다. 두 번째다. 토요일의 업무 "김개발님, 이거 어떻게 생각해요?" 토요일 오후 2시. 쉬는 날인데 슬랙이 울린다. 선임 개발자다. 새 프로젝트 기획이 나왔대. 아키텍처 검토 해달래. 내가 봐야 한다. 안 보면 월요일에 틀린 방향으로 간다. 3명이 틀린 길을 1주일 간다. 그럼 사이클 터진다. 그럼 내 일이 거기서 끝나지 않는다. 주말 오후 2시에 설계 문서를 본다. 칠판을 꺼낸다. 아니 모니터 앞에 앉는다. 생각한다. 펜을 돌린다. 1시간 후 슬랙에 장문의 메시지를 쓴다. "데이터베이스 스키마는 이렇게 가고, 캐시 레이어는 Redis로..." 장황하게 쓴다. 근데 꼭 필요한 내용이다. 없으면 틀린다. 선임: "역시 김개발님이네요. 감사합니다." 감사합니다. 그 말이다. 월급에 포함되지 않는 일이 한 번씩 감사합니다로 끝난다. 그래도 필요하니까 한다. 아내는 뭐해, 라고 묻지 않는다. 나도 답하지 않는다. 토요일이라는 걸 둘 다 잊는다.면접 준비할 마음 이직할 거야? 하는 질문 많다. 동기들 톡방에도 올라온다. "요즘 대기업 시니어 연봉 9천대라던데?" 나도 봤다. 2달마다 본다. 그리고 다시 슬랙을 켠다. 이직할 마음이 있다. 진짜 있다. 그런데 마음이 없다. 면접을 봐야 한다. 포트폴리오를 정리해야 한다. 깃허브를 봐야 한다. 사이드 프로젝트를 하나 띄워야 한다. 혹은 과거 프로젝트를 정리해야 한다. 그걸 할 에너지가 없다. 일과가 끝나면 넷플릭스를 킨다. 뭘 보든 상관없다. 그냥 킨다. 생각을 안 하려고. 주말에 일어나서 면접을 준비할까, 할 생각을 하다가 라면을 끓인다. 라면을 먹으면서 자기 전까지 폰을 본다. 페이스북에서 동기들 사진을 본다. 근데 게시물에 좋아요는 안 누른다. 그리고 월요일 오전 9시가 된다. 아 그거요. 후배를 가르친다는 게 "이 부분에서 왜 싱글톤 패턴을 썼어요?" 새로 온 후배다. 2년차. 내가 물어본다. 그러면 그 질문이 시작이다. 그 질문 하나로 30분이 간다. 나는 가르쳐야 한다. 안 가르치면 내일 다시 틀린다. 모레도 틀린다. 그럼 내가 고친다. 시간이 2배가 된다. 그래서 가르친다. 설명한다. 왜 싱글톤이 문제인지. 스레드 안전성이 뭔지. 테스트 불가능성이 뭔지. 그럼 대안이 뭔지. 후배가 이해했다. "아, 그렇군요. 감사합니다." 30분이 사라졌다. 내 일은 30분 밀렸다. 그 30분은 퇴근 후에 한다. 근데 이게 계속 반복되니까 하루에 2시간이 간다. 5일이니까 10시간이 간다. 한 주에 10시간. 한 달이면 40시간. 그게 내 시간이다. "선임 개발자니까 이 정도는 당연하지" 라고 누구도 말하지 않는다. 근데 그렇게 생각한다. 월급에 후배 교육비가 포함되나? 아니다. 근데 포함된다. 매달 40시간. 월급을 시급으로 나누면 얼마지. 계산은 안 해도 알 수 있다. 담배 피는 척하고 베란다에 나간다. 생각한다. 뭘? 아무것도. 그냥 5분을 버린다.'간단하죠?'의 무게 기획자가 온다. 회의실에 10명이 앉아 있다. 나를 포함해서. "이거 사실 간단하니까 한 3일이면 되겠죠?" 간단하면 너가 해. 내가 말하진 않는다. 그냥 생각한다. 입으로는 "어, 알겠습니다"라고 한다. 간단하다. 정말 간단하다. 단순하게 따지면. 버튼을 누르면 데이터가 저장되게 하면 된다. 그게 간단한 거다. 기획자 입장에선. 그런데 데이터 검증은? 권한 체크는? 동시성 문제는? 롤백은? 로깅은? 모니터링은? 테스트는? 3일이 10일이 된다. 10일이 끝나면 QA에서 버그를 찾는다. 3일치 버그를. 왜냐면 3일에 되게 하려고 했으니까. 야간에 고친다. 기획자는 "역시 세밀하네요"라고 한다. 세밀해서가 아니라 기본을 했을 뿐인데. 근데 이게 반복되니까 의심한다. 내가 느린 걸까? 다른 회사의 개발자들은 3일에 하나? 아니다. 나는 안다. 다들 이렇다. 근데 말 안 할 뿐이다. 그래서 회의실에서 "네, 간단하겠습니다"라고 한다. 나오면서 한숨 쉬고, 책상에 앉아서 모니터를 봐도 계획서가 눈에 안 들어온다. 펜을 돌린다. 회의가 끝난 지 1시간이 지났는데도 펜을 돌린다. 레거시와의 전쟁 "이거 왜 이렇게 짜놨어?" 3년 전 코드다. 내가 짠 게 아니다. 그 전 선임이 짠 거다. 그런데 그 선임은 회사에 없다. 구조가 이상하다. 디자인 패턴이라고 할 수 없다. 그냥... 동작한다. 그게 전부다. 고쳐야 한다. 근데 안 고친다. 왜? 시간이 없다. 새 기능을 해야 하고, PR 리뷰를 해야 하고, 후배를 봐야 하고, 토요일 오후의 아키텍처 설계를 해야 한다. 레거시는 여기에 있다. 계속 동작한다. 버그는 가끔 난다. 그럼 패치한다. 근본은 못 본다. 3년 후배가 와서 묻는다. "이거 왜 이렇게 짜놨어요?" 내가 답한다. "아, 그거요..." 나도 모른다고 할 수도 있다. 근데 말하지 않는다. 왜냐면 나는 시니어 개발자처럼 일하니까 알아야 한다고 생각한다. 그래서 "비즈니스 요구사항이 이랬거든요"라고 말한다. 거짓이 아니다. 근데 전부도 아니다. 밤 11시. 배포 전 마지막 체크다. 레거시 코드를 본다. 여전히 이상하다. 근데 동작한다. 배포한다. 집에 가는 길에 "언젠가 고쳐야지"라고 생각한다. 근데 그 날은 안 온다. 슬랙 알림, 나의 적 알림 음소거. 늘 켜져 있다. 주말인데도. 저녁 8시인데도. 밤 11시인데도. 음소거 상태로. 빨간 숫자가 쌓인다. 1, 5, 12, 27. 27개의 알림. 다 나한테다. 아니 일부는 전사 공지다. 그래도 20개 이상은 내 책임이다. 기획이 변했다. 리뷰 요청이 3개 왔다. 후배가 막혔다고 한다. 선임이 의견을 물었다. 그리고 또 뭔가. 이게 밤 11시 30분의 내 상황이다. 주말 오후라고 생각할 때도 그렇다. 슬랙이 울릴까봐 음소거에서 볼륨을 내렸다가 다시 음소거로 한다. 확인할까봐. 확인하면 일한다. 일하고 싶지 않다. 근데 일 생각이 나 이상하게 괜찮다. 자는 것보다. 그래서 음소거를 푼다. 알림을 본다. 30분이 일로 간다. 그리고 또 음소거를 한다. 근데 마음은 음소거가 안 된다. 아내와의 저녁 "오늘 뭐했어?" 8시 반. 저녁 시간이다. "일했어. 후배 코드 리뷰하고." "토요일인데?" "응." 대화가 끝난다. 아내도 야근한 날이 많다. UI 디자이너. 리뷰가 많다. 근데 코드 리뷰는 내 몫이다. 내가 아니면 못 본다. "내일은 쉴 거야?" "배포일인데..." "또?" 네. 또다. 라면을 끓인다. 아내는 회사 일로 정신없다. 나도 회사 일로 정신없다. 근데 라면은 끓인다. 어제도 라면이었나? 모르겠다. 기억이 안 난다. 아내가 소파에 누웠다. 노트북 위에. 나도 소파에 누웠다. 폰 위에. 같은 공간에 있는데 다른 세상에 있다. 이게 저녁이다. 밤 10시가 되면 자야 한다. 내일 아침은 7시 반에 일어난다. 그리고 또 커피. 동기들과의 거리 "너 시니어 됐어?" 카톡에서 묻는다. 3년 전 후배다. 지금은 내 동료가 아니다. 다른 회사다. "아직." "3년인데?" "응." 뭐라고 설명할까? 테크 리드인데 직책이 없다고? 그럼 왜 안 옮기냐고 물을 게 뻔하다. 나도 그 대답을 못 한다. "연봉도 못 올렸어?" "200만원." "어? 나는 1년에 600만원 올랐는데?" 모르겠다. 그 친구는 이직했다. 시니어로. 6개월 만에 연봉이 8천대가 됐다고 했다. 근데 야근이 많댔다. 번아웃 위험이라고도 했다. 그리고 3개월 후에는 연락이 없었다. 근데 내가 덜 바쁜 건가? 아니다. 내가 더 바쁘다. 근데 시니어로 안 불린다. 후배들 앞에서는 테크 리드처럼 행동하고 경영진 앞에서는 개발자다. 둘 다 아니고 둘 다다. 연락을 받은 지 3시간 후에 답한다. "화이팅." 그게 다다. 오늘도 커피 세 번째 커피를 마신다. 오후 3시. 어제 아침에 일어난 지 24시간도 안 됐는데 벌써 세 번째다. 첫 번째는 출근 직후. 깨어나기 위해. 두 번째는 회의 전. 정신 차리기 위해. 세 번째는 지금. 이유는 없다. 그냥 마신다. 커피가 없으면 이 업무가 안 된다. 근데 커피가 있어도 된다. 모순이다. 근데 마신다. 펜을 돌린다. 모니터를 본다. 코드를 본다. 문제가 있다. 해결해야 한다. 내일도 같은 일을 한다. 모레도. 그 다음날도. 그리고 어느 날 슬랙에서 "김개발님 시니어 됐대요"라는 말이 나올 거다. 근데 그때도 일은 같다.내일은 좀 나아지겠지. 아마도.

사이드 프로젝트 3번 접은 개발자가 배운 것

사이드 프로젝트 3번 접은 개발자가 배운 것

사이드 프로젝트 3번 접은 개발자가 배운 것 출근했다. 월요일이다. 슬랙을 켰다. 금요일부터 쌓인 메시지 47개. 레거시 시스템 버그, 배포 관련 문의, 후배 코드 리뷰. 일단 무시하고 커피를 마신다. 첫 번째다. 어제 밤, 침대에서 다시 생각했다. 사이드 프로젝트 얘기다. 정확히는 사이드 프로젝트 '접은 걸' 생각했다. 3번 접었다. 3번 다. 회사 일 외에 뭔가 만들고 싶은 게 없는 게 아니다. 문제는 그게 아니다. 시작하고 2주 뒤 현실이 와서 꺾여버린다. 아내가 "너 또 안 할 거다"라고 할 때, 그게 가장 싫다. 왜냐하면 맞으니까.프로젝트 1번: 주식 앱 (1주일 반 버틴 것) 작년 2월이었다. 회사에서 Redis 사용 경험이 필요했다. 그러면 사이드로 만들면서 배우자고 생각했다. 주제는 주식이었다. 실시간 시세를 캐싱하고, 사용자 포트폴리오를 추적하고, 매매 알림을 주는 앱. "이번엔 다르다"고 다짐했다. 첫 주말은 열정이었다. ERD를 그렸다. API 설계했다. Redis 아키텍처도 다 구상했다. GitHub에 저장소까지 만들었다. 커밋 메시지는 "initial commit: stock tracking app with real-time cache strategy". 멋있었다. 월요일이 왔다. 회사에서 Redis 관련 긴급 버그가 터졌다. 프로덕션 캐시 일관성 문제. 밤 10시까지 붙들었다. 화요일은 출근해서 그 문제를 추적했다. 수요일엔 후배가 물어봤다. "시니어, 이 쿼리 왜 느려요?" 30분을 설명했다. 목요일에 사이드 프로젝트를 다시 봤다. 코드가 낡아 보였다. 뭔가 잘못된 느낌. Redis 설정을 다시 봤다. 생각을 정리하려고 또 다른 설계를 했다. 금요일엔 아무것도 못 했다. 주말엔 침대. 월요일에 GitHub에 들어갔다가 나왔다. 더 이상 하기 싫었다.프로젝트 2번: 개인 블로그 플랫폼 (10일) 4월이었다. 트위터에서 개발자들이 개인 블로그 갖는 게 중요하다고 했다. 그러면 플랫폼을 만들자고 생각했다. Medium 같은 서비스. 마크다운 에디터, 태그 시스템, 댓글, SEO 최적화. 대단했다. "이번엔 정말 다르다"고 했다. 진짜 다를 줄 알았다. 첫 3일은 정말 빨랐다. Spring Boot 프로젝트 세팅, JPA 엔티티 설계, 마크다운 파싱 라이브러리 통합. 생각보다 쉬웠다. "아, 이게 진짜 가능하겠네"라고 생각했다. 그 생각이 문제였다. 4일차: 마크다운 렌더링에서 보안 이슈가 보였다. XSS 방지. 10가지 경우의 수를 고민했다. 하나 구현했다. 나머지 9개는 다음에 하기로. 5일차: 데이터베이스 마이그레이션을 생각했다. 유저가 블로그 이동할 때 데이터를 어떻게 옮길까. 너무 복잡했다. 다음 버전에 미뤘다. 6일차: 아내가 물어봤다. "블로그 만들어?" "응, 만들고 있어." "언제 오픈?" 그 순간 마음이 내려앉았다. 언제냐고. 모르잖아. 7일차: 코드를 다시 봤다. 마크다운 파싱 로직이 마음에 안 들었다. 전부 다시 짰다. 사실 필요 없었다. 8일차: 8일차에 뭘 했는지 모른다. GitHub 커밋 기록도 없다. 9일차: GitHub에 들어갔다가 나왔다. 10일차: 프로젝트를 삭제했다. 아니, 삭제 안 했고 그냥 방치했다. 지금도 있다. Private 저장소로. 패배의 증거.프로젝트 3번: 자동화 도구 (2주) 7월이었다. 회사에서 매번 배포할 때마다 같은 작업을 반복했다. 체크리스트 확인, 데이터베이스 마이그레이션 스크립트 검증, 알림 전송. 3번 접은 개발자가 배웠어야 할 것: 작은 게 최고다. 근데 이번엔 작게 시작했다. 진짜. 배포 자동화 도구. CLI 하나면 끝. 아무것도 웹 없이. 아무것도 복잡하게 없이. 단순함. 첫 주: 전부 다 했다. Python으로 CLI 도구. 8시간 안에 뼈대 완성. 회사에서 써봤다. 먹혔다. 동료들이 물어봤다. "이거 언제 만들었어?" "어제 밤." "진짜?" 뿌듯했다. 둘째 주: 추가 기능을 생각했다. 롤백 기능, 배포 로그 기록, 실패했을 때 자동 알림. 한 가지씩 추가하다 보니까 복잡해졌다. 코드가 길어졌다. 테스트 케이스도 많아야 했다. 처음 간단함은 어디갔나. 그러던 와중에, 회사에서 새로운 배포 시스템 도입 공지가 났다. 외부 솔루션. 3개월 뒤면 우리 도구 필요 없어진다. 그걸 봤을 때, 손에서 힘이 빠졌다. 왜 하고 있지. 이 느낌 또 왔다. GitHub에 들어갔다가 나왔다. 3번 다다.배운 것들 (솔직하게) 교훈 같은 건 안 가르칠 거다. 인터넷에 넘쳐난다. "작게 시작하세요", "꾸준함이 중요합니다" 같은 거. 그런 건 다 알고 있었다. 근데 못 했다. 첫 번째: 완성 중독이 있다는 것. 프로젝트를 시작하면 '다 만들어서 공개해야지'가 머릿속 기본값이 된다. 그렇게 되면 나머지 모든 것들은 완성도가 낮으면 공개 못 한다고 생각한다. 주식 앱도 그랬다. "아직 알고리즘이 부족하니까", "UI가 못생겼으니까". 이유는 많다. 근데 공개 안 하면 뭐가 다른가. 그냥 개인 폴더에서 썩는 거다. 그게 낫나. 두 번째: 번아웃이 일찍 온다는 것. 회사에서 7시간 일하고, 퇴근 후 2시간을 사이드 프로젝트에 쓴다고 하자. 그럼 뇌는 코딩만 12시간 한다는 거다. 주말엔? 더 하고 싶은 마음이 안 생긴다. 그냥 침대가 끌린다. 근데 계속 자책한다. "왜 못 하지. 다들 하는데." 다들 안 한다. 그냥 SNS에서 자랑하는 사람들만 보인다. 세 번째: 공동작업이 없으면 쉽게 포기한다는 것. 회사 프로젝트는 스팩 변경되면 짜증나도 한다. 왜냐면 누군가 기다리니까. 근데 사이드 프로젝트는? 오직 자기만을 위한 거. 오직 자기만이 유일한 스테이크홀더다. 자기 마음만 중요하면 사실 중요한 게 아니다. 스스로에겐 자비롭기 쉽다. 네 번째: 진짜 만들고 싶은 건 따로 있다는 것. 3개 프로젝트 다 "이거 배우고 싶어서" 또는 "포트폴리오 될 것 같아서" 시작했다. 정말 그 앱이 필요해서가 아니었다. 내가 주식을 몰라서가 아니라 Redis를 배우고 싶어서. 블로깅이 하고 싶어서가 아니라 마크다운 파싱이 하고 싶어서. 이건 말이 안 된다. 뭔가를 잘 만들려면 그걸 정말 원해야 한다.지금 지금은 뭘 하고 있나. 사이드 프로젝트? 안 한다. 필요 없다고 생각했나. 아니다. 밤 10시에 누워 있으면서 생각한다. 앱 만드는 거. 블로그 쓰는 거. 뭔가를 만드는 거. 근데 아침이 되면 출근한다. 회사에선 할 게 많다. 퇴근하면 피곤하다. 주말엔 쉰다. 이게 계획된 결과인가. 아니다. 그냥 그런 거다. 에너지 관리의 실패. 혹은 진짜 필요 없는 걸 만들려고 했던 거고, 그래서 자연스럽게 포기된 거다. 그럼 이제 뭘 해야 하나. 아내가 말했다. "넌 회사 일로 충분히 바빠. 왜 더 해." 맞다고 생각했다. 근데 자책은 계속 된다. 왜인지는 모르겠다. 아마도 개발자라는 직업이 계속 뭔가 배우고 빌드해야 한다고 강요하는 것 같다. 그게 나쁜 건 아니다. 근데 그게 회사에서 충분하다면, 사이드는 뭐 하는 거지. 최근에 생각을 바꿨다. 사이드 프로젝트는 재미 없으면 버린다. 배우기 위해서가 아니라, 그냥 만드는 게 재미있어야 한다. 근데 일단 3번 실패한 개발자 입장에선, 4번째를 어떻게 믿고 시작하나. 그게 문제다.근데 뭔가 배운 건 있다 프로젝트를 접으면서 배운 코드들은 남았다. Redis 아키텍처 방식, 마크다운 파싱 로직, Python CLI 도구 구조. 그건 버려진 게 아니다. 회사에서 쓸 때 나온다. "아, 저 방식 어디서 봤는데" 하면서. 아, 그렇구나. 사이드 프로젝트가 완성돼야 의미 있는 게 아니다. 배운 것들이 다른 데서 쓰일 때 의미가 있는 거다. 그럼 3번 접은 게 완전 손해는 아니네. 다만, 시간이 아까운 건 사실이다. 4개월이 그냥 사라졌다. 대신 뭘 배웠나면, 배웠다는 것 자체를 증명하기 힘들다. 코드도 없고, 완성된 앱도 없다. 그냥 "배웠어"라고 말할 수밖에. 근데 그게 현실이다. 개발자의 삶은 많은 부분이 그렇다. 배웠는지 모르고, 못 했는지 안 했는지도 모른다. 그냥 계속한다. 정해진 시간에 출근해서, 정해진 일을 하고, 퇴근한다. 사이드 프로젝트는 그걸 벗어나려는 시도다. 하지만 결국 마찬가지다. 번아웃이 올 때까지 한다. 그리고 멈춘다. 다음 번엔 다를 거라고 생각하면서. 이건 교훈이 아니다. 그냥 현실이다.커피를 마신다. 두 번째다. 회사에선 지금 배포 준비 중이다. 우리 팀이 만든 기능이 나간다. 후배가 물어봤다. "프로덕션에서 Redis 캐시 문제 없을까요?" 내가 답했다. "몰라. 나가고 봐." 아, 그거 사이드에서 배웠던 거다. 문제는 나가야 본다.[IMAGE_4] [IMAGE_5]결국 다음 사이드 프로젝트도 접할 것 같다.

Redis 캐시 전략으로 밤새 디버깅한 날

Redis 캐시 전략으로 밤새 디버깅한 날

Redis 캐시 전략으로 밤새 디버깅한 날 그건 화요일 저녁 6시의 일이었다 일반적으로 배포는 금요일 오후 3시에 한다. 근데 이번엔 달랐다. 기획팀이 수요일 자정까지 급하게 처리해야 할 기능이 있다고 했고, 우리 팀은 당연히 전쟁 준비를 했다. 사실 나는 지난주부터 Redis 캐시 도입을 준비하고 있었다. 회사 서비스가 요즘 느리다는 컴플레인이 계속 들어오고 있었다. 사용자가 늘어나면서 데이터베이스 쿼리가 답답해 지기 시작한 거다. 데이터는 자주 바뀌지 않는데 매번 디비에서 갱신하고 있었으니까 말이다. 그래서 내가 제안했다. "Redis 캐시 레이어 추가하면 어때요?" 팀장은 "좋지, 김개발이가 해봐" 라고 했다. 요즘 팀장은 항상 그렇다. 뭔가 새로운 기술이 나오면 나한테 건넨다. 직책도 없으면서. 아무튼. 나는 지난주 내내 Redis 연결, TTL 설정, 캐시 무효화 로직을 짰다. 로컬에서는 완벽했다. DB 응답 시간이 200ms에서 20ms로 뚝 떨어졌다. 이거야말로 진짜 최적화다. 나는 자신감에 차 있었다. 화요일 저녁 6시, 배포가 시작되었다. 테스트 서버부터. 로그를 봤다. 모든 게 정상이었다. 프로덕션 배포. 여전히 정상. "좋네. 이제 집 갈까" 라고 생각했다. 아내한테 카톡했다. "늦게 먹을 거 같아" 라고. 아내는 "알겠어 조심해" 라고 했다. 근데 밤 10시. 슬랙에서 핑이 울렸다. 안 좋은 예감이 들었다. 모니터가 시커먼 밤 10시의 공포 [Alert] User ID 12345 - 잘못된 데이터 제공 반복 이 메시지가 모니터에 떴을 때, 나는 한숨을 쉬면서 생각했다. "또 시작이네." 기획팀에서 온 리포트였다. 몇몇 사용자가 캐시된 데이터가 맞지 않는다는 피드백을 주었다는 거다. 사용자 A의 정보를 조회할 때 사용자 B의 정보가 나온다는 식. 이건 내가 가장 싫어하는 케이스였다. "대체 뭐가 문제지?" 하고 한참 고민해야 하는 상황 말이다. 로컬에선 진짜 문제가 없었는데. 나는 일단 프로덕션 서버의 로그부터 뒤지기 시작했다. CloudWatch 대시보드를 열었다. 레이턴시는 확실히 내려갔다. 그건 좋은 신호였다. 그럼 캐시 정책이 작동한다는 뜻인데... 오류 로그를 보니 패턴이 보였다. 2024-01-17 22:10:45 - Cache HIT for user:12345 - result from Redis 2024-01-17 22:10:50 - user:12345 updated in DB 2024-01-17 22:11:02 - Cache HIT for user:12345 - result from Redis (STALE DATA)아. 이거다. 내가 짠 캐시 무효화 로직이 DB 업데이트를 감지하지 못하고 있었다.나는 잠깐, 내가 뭘 놨더라 하면서 코드를 다시 봤다. 캐시 무효화 로직은 이렇게 짜여 있었다: @Transactional public void updateUser(User user) { userRepository.save(user); redisTemplate.delete("user:" + user.getId()); }당연하지. 이렇게 간단할 리가 없다. 문제는 우리 시스템이 마이크로서비스 아키텍처로 되어 있다는 거였다. 사용자 정보는 User Service에서 관리하지만, 프로필 이미지 같은 건 Content Service에서 관리했다. 그리고 두 서비스는 다른 데이터베이스를 쓰고 있었다. 즉, 내 무효화 로직은 User Service의 캐시만 날리고 있었다. Content Service에서 업데이트된 데이터는 Redis에 남아있었던 거다. "아 그거요" 라고 중얼거렸다. 이제 문제를 알았으니까 고칠 수 있다. 근데 문제는... 10시가 넘었다. 새벽 3시, 커피가 식어가는 시간 나는 일단 핫픽스를 생각했다. Redis의 모든 관련 캐시를 무조건 날려버리는 방식으로. 그럼 성능이 또 떨어질 텐데, 일단 버그는 없을 거다. @Transactional public void updateUser(User user) { userRepository.save(user); // 일단 관련된 모든 캐시 다 날려버림 redisTemplate.delete("user:" + user.getId()); redisTemplate.delete("profile:" + user.getId()); redisTemplate.delete("content:" + user.getId()); // ... 기타등등 }팀 슬랙에 메시지를 띄웠다. "일단 핫픽스 할게요. 내일 제대로 리팩토링합시다." 배포는 밤 11시에 끝났다. 버그는 사라졌다. 근데 나는 계속 앉아 있었다. 뭔가 불안했다. "이게 진짜 완벽한 해결책인가?" 밤 12시, 커피를 또 마셨다. 셋째 잔. 나는 비즈니스 로직을 다시 생각했다. 지금 우리 시스템은 여러 마이크로서비스가 동일한 사용자 정보를 캐시하고 있었다. 어느 한 서비스에서 업데이트되면, 다른 서비스도 알아야 한다. 근데 어떻게? 메시지 큐? Kafka? 그건 복잡할 것 같은데. 아니면 그냥 캐시 TTL을 짧게 가져가? 그럼 매번 다 조회해야 하는데 결국 성능 개선이 없는 거잖아. 나는 다시 생각했다. "근본적인 문제가 뭐지?" 아. 여러 서비스가 같은 데이터를 각각 캐시하고 있다는 게 문제다. 그럼 캐시를 중앙화해야 한다. 모든 데이터 조회는 하나의 서비스를 거쳐서, 그 서비스가 Redis를 관리하도록. 밤 2시. 나는 구조를 다시 그렸다. 손으로 노트에다가. 종이와 펜이 제일 빠르다. User Service → [Redis Cache Manager Service] → Redis Content Service ↓ Profile Service ↓이렇게 하면 어떻게 되지? 음... 네트워크 호출이 하나 더 늘어난다. 하지만 모든 캐시가 일관성 있게 유지된다. 밤 3시, 슬랙에 긴 스레드를 남겼다.팀장님, 내일 아침에 얘기하고 싶은데, 현재 캐시 설계에 근본적인 문제가 있는 것 같습니다. 마이크로서비스 간 캐시 무효화가 제대로 안 되고 있어요. 긴급 핫픽스는 했는데, 장기적으로는 아래처럼 개선이 필요할 것 같습니다:Redis Cache Manager 서비스 신설 모든 캐시 쓰기/삭제 요청을 여기로 집중 TTL 정책 중앙화 ...그리고 나는 커피를 마셨다. 넷째 잔. (셋째가 아니라) 컴퓨터는 여전히 켜져 있었고, 모니터에는 코드가 떠 있었다. 나는 다시 생각했다. 혹시 내가 놓친 게 있나? 아. 하나 더 있었다. Cache Invalidation Pattern이었다. 우리는 지금 TTL-based invalidation을 쓰고 있었는데, 이건 보장되지 않는다. 업데이트가 되고 나서 TTL이 끝날 때까지의 그 시간 동안, 잘못된 데이터가 나간다는 뜻이다. 그럼 Event-driven invalidation은? 업데이트가 발생하면 즉시 이벤트를 발행하고, 그걸 듣는 모든 캐시 레이어가 반응한다. Kafka 같은 메시지 큐를 쓰면 돼. 근데 이건 더 복잡하다. 그리고 비용도 는다. 나는 한숨을 쉬었다. 개발이 정말 쉬워 보이기만 하지, 실제로는 이렇게 트레이드오프를 계속 해야 한다. 밤 4시, 나는 침대로 갔다. 결국 아내 옆에 누웠다. 아내는 자고 있었다. 새벽 5시, 깨어나면서 든 생각 꿈을 봤는데, 뭔지는 모르겠다. 그냥 코드를 계속 보고 있는 느낌이었다. 눈을 떴을 때 시간이 5시였다. 휴... 밤 11시에서 4시까지 거의 5시간을 일한 거다. 그런데 뭔가 좋은 느낌이 들었다. 문제를 찾았으니까. 그리고 해결 방법도 여러 개 생각했으니까. 근데 동시에 깨달았다. 이 문제는 사실 처음부터 예측할 수 있었어야 했다는 거다. 마이크로서비스 아키텍처에서 캐시를 도입할 때는 항상 무효화 전략을 먼저 생각해야 한다. 성능 개선은 나중이다. 나는 다시 한 번 생각했다. "내가 면접 준비를 해야 하나? 다른 회사에서는 이런 실수가 안 나나?" 아니다. 어디든 있다. 다만 시간에 여유가 있는 회사는 이런 문제를 천천히 해결한다. 우리처럼 급하게 배포하는 회사에서는 항상 이런 문제가 터진다. 아내가 깨어났다. "뭐 해?" "일." "밤에?" "응. 어제 배포에서 버그가 났어." 아내는 한숨을 쉬었다. "내일 출근 안 하면 되지?" "그럼 누가 고칠?" 아내는 다시 누웠다. 우리 부부는 서로의 일에 대해 깊이 있게 물어보지 않는다. 그냥 있다는 걸 알고 있을 뿐이다.아침 8시, 회의실에서의 대화 나는 2시간 반을 더 잤다. 당연히 피곤했다. 사무실 도착 시간은 오전 8시 30분. 평소보다 30분 빨랐다. 팀장에게 내가 쓴 스레드를 보여주고 싶었다. 팀장은 커피를 마시고 있었다. "팀장, 어제 그 버그 이야기 들으셨어요?" "응. 잘 고쳤네. 고마워." "네, 근데 이건 임시방편이고요. 우리 캐시 아키텍처에 근본적인 문제가..." 팀장이 손을 들었다. "알겠어. 문서화해서 보여줘. 그 다음에 우리 얘기할 거 있고." 나는 알았다. 진짜 얘기는 나중에 나온다는 뜻이다. 퀵스탠드업 미팅이 끝나고, 팀장이 나를 불렀다. "어제 밤을 새웠네." "...네. 문제를 찾아야 해서." "잘 했어. 근데 이런 식으로 일하면 안 돼. 네가 팀에서 가장 시니어인데, 뭔가 도움이 필요하면 후배들한테 물어봐. 너 혼자 다 해야 하는 건 아니야." 나는 대답을 못 했다. 팀장 말이 맞는데, 내 일의 성격상 그게 쉽지 않거든. 후배들한테 "이거 이상한데 뭐 같아?" 라고 물어보면, 결국 내가 다시 다 설명해야 한다. 그럼 시간이 더 든다. 하지만 입으로는 "알겠습니다" 라고만 했다. 이제는 무엇을 배울 것인가 지금 오후 2시다. 나는 캐시 무효화 로직을 다시 작성하고 있다. 이번엔 다르다. Event-driven 방식은 아니지만, 최소한 여러 서비스 간의 캐시 일관성을 보장하도록 했다. 간단한 로직이다: // User Service에서 업데이트 발생 @Transactional public void updateUser(User user) { userRepository.save(user); // 자신의 캐시만 날리지 말고, 다른 서비스에도 알려주기 cacheInvalidationService.invalidateUserCache(user.getId()); }// CacheInvalidationService public void invalidateUserCache(Long userId) { // 모든 관련 캐시 패턴을 한 곳에서 관리 List<String> patterns = getCachePatterns(userId); redisTemplate.delete(patterns); // 나중에는 메시지 큐로 다른 서비스에도 전파 }사실 이것도 완벽한 해결책은 아니다. 하지만 나는 이제 알았다. 완벽한 해결책은 없다. 있는 건 상황에 맞는 적절한 트레이드오프일 뿐이다. 귀가 길에, 나는 커피숍에 들어갔다. 커피 한 잔 더. 다섯째 잔. 바리스타가 내 얼굴을 봤다. 아마도 피곤해 보였을 거다. "힘든 하루였어요?" "네. 밤을 새웠어요." "또 배포 날씸?" "아뇨. 버그 때문에요." 바리스타는 웃었다. "개발자는 항상 뭔가 때문에 밤을 새네요." 나도 웃었다. "그래서 정신이 올빠르지." 집에 도착했을 때, 아내가 있었다. 보통 이 시간엔 없는데. "조금 일찍 나왔어?" "응. 넌 뭐해? 피곤해 보여." 나는 아내에게 어제 밤 일을 설명했다. Redis, 캐시 무효화, 마이크로서비스... 아내는 대부분 못 알아듣겠지만, 그냥 들어주는 것만으로도 충분했다. "고생했네. 밥 먹고 쉬자. 내가 뭐 사 올까?" "김치찌개." "또?" "점심으로 먹었어도 저녁으로 먹고 싶어." 아내는 한숨을 쉬고 나갔다. 나는 소파에 누웠다. 모니터는 꺼졌다. 슬랙도 무음. 일단 이 순간은 나의 것이다. 이제 깨달았다. 완벽한 코드를 짜려다 밤을 새는 것보다, 괜찮은 코드를 짜고 시간을 자기는 게 훨씬 나낫다는 걸. 적어도 내 정신 건강을 위해선. 내일부터는 어떻게 할까? 유사한 문제가 또 나오면? 나는 아마 또 밤을 새우겠지. 왜냐하면 내가 팀의 일인당 전문가니까. 근데 적어도 이번엔 알았다. 혼자 다 하려고 하지 말고, 처음부터 아키텍처를 제대로 생각해야 한다는 걸. 그리고 또 하나. 우리 팀은 이제 Redis 캐시 가이드 문서가 필요하다. 마이크로서비스 환경에서의 캐시 무효화 패턴, TTL 설정 기준, 모니터링 방법 등등. 나는 내일부터 그걸 작성해야 한다. 그럼 또 다른 후배가 같은 실수를 하지 않겠지. 아내가 돌아왔다. 김치찌개 냄새가 풍겼다. "먹자."결국 버그는 나를 성장시켰고, 밤샘은 나를 피로하게 했지만, 그 둘의 조합이 내를 개발자로 만들었다.