목차
서론
하브루타란 친구와 함께 질문과 토론을 통해 사고를 확장하는 방식의 독서법이다. 이번엔 개발 관련 서적을 읽으며 질문과 토론을 통해 사고를 확장하는 친구로 LLM(ChatGPT 4o)을 선택해봤다. 방식은 다음과 같았다.
1. 한 챕터를 읽기전에 LLM에게 해당 챕터의 목차를 주고, 개발 관련 질문을 해달라고 했다.
2. 한 챕터를 읽은 후 해당 챕터에 대한 내 생각을 말하고, 처음 받은 질문에 대해 답변을 LLM에게 한다.
3. 마지막으로 내 답변에 대한 평가를 부탁하고, 더 깊게 얘기해볼만한 주제는 별도로 토론했다.
“’주니어 백엔드 개발자가 반드시 알아야 할 실무 지식'을 읽고 떠오른 내 생각들” 글에서는 책을 읽고 내 생각을 그대로 적어봤었다. 이번에 읽은 ‘육각형 개발자’는 사실 목차를 봤을 때, 다소 쉬워 보였기에, 책 내용만 따라가기 보다는 그 이상을 얻어보고 싶었다. 그래서 위와 같은 방식으로 LLM에게 질문 생성부터 시켰었다.
참고로 챕터를 읽기 전에 목차만 주고 질문을 먼저 받아둔 이유도 있다. LLM의 특성상 내가 책을 읽고 써준 내용에 기반해 질문을 생성할 확률이 높다. 따라서 내 생각이 반영되기 전에 질문을 받아야 LLM이 내 생각에 매몰되지 않고, 좀 더 다양한 시각에서 내 사고를 자극받을 수 있다고 판단했다.
이 방식으로 책을 읽어보니, 결과적으로 아주 맛있는 개발 책 독서가 되었다. 단순히 책 내용뿐 아니라 +@의 인사이트와 사고 확장의 경험까지 따라왔기 때문이다.
작년엔 스터디 위주로 개발서 독서를 많이 했었다. 물론 약간의 반강제성이 생겨 공부하긴 좋았지만, 오히려 관심이 높을 땐 매주 정해진 분량만 소화할 수 있다는게 아쉬울 때도 있다. 또한 좋은 스터디 팀원을 얻기 위한 노력도 필요하다. 이런 면에서, 언제나 평균 이상의 논리적인 답변이 가능한 LLM은 개발자식 하브루타 독서에 꽤 잘 어울리는 파트너라고 느꼈다.
아래부터는 위의 방식으로 읽은 ‘육각형 개발자’ 중, LLM에게 받은 질문과 그에 대한 내 답변 중 일부를 정리한 내용이다. 앞으로도 이런 방식으로 많이 읽어봐야겠다.
※ 참고로 이하의 질문은 LLM이 책의 목차만 보고 생성한 것으로, 실제 책의 내용과 다소 무관할 수 있습니다. 예를 들어 ‘기술 파기’ 목차는 실제론 기술을 파고드는 것에 대한 내용이었으나, LLM은 기술을 버리는 것으로 해석해 질문을 던졌습니다.
※ 제 생각을 적은 것으로, 사실이나 일반적인 생각과 다를 수 있습니다!
1장. 들어가며
실패, 3년 차, 개발이란, 개발에 필요한 것
“개발이란 무엇인가”라는 질문에 지금의 너는 어떻게 답할 수 있어?
개발이란 문제해결이라고 생각해. 기본적으로 내 가치관은, 모든 것은 문제해결이며, 모든 것은 확률이다야. 개발도 마찬가지야. 작게보면 함수단위가 되는거고. 알고리즘 문제 푸는 것도 문제해결인거고. 요구사항 캐치하는것도 문제해결이고. 트러블 슈팅도 문제해결이고. 크게보면 '고객을 만족시켜라'도 문제해결인거고. 그런거지. 그래서 나한테 묻는다면, 난 개발도 문제해결이라 생각해
너는 개발자에게 필요한 핵심 역량이 뭐라고 생각해? 기술 외에, 지금까지 중요하다고 느낀 ‘비기술적 능력’은 무엇이 있었어?
몇 가지 있어. 우선 자만하지 않기. 천외천이라고 하지. 언제나 하늘 위엔 하늘이 있어. 현재의 실력에 안주하지 말고, 나보다 더 잘하는 사람을 바라봐야 해. 겸손하게.
그리고 꾸준함으로 인해 무언가 성공해본 경험도 중요하다고 봐. 난 대학교 1학년 때 성적이 많이 나빴어. 그리고 이후 복학하고, 강의 잘하시는 것 같은 교수님께 가서 개발을 너무 모르는데 어떻게 하냐고 물어봤지. 그 교수님은 내게 그냥 수업 제외하고 하루에 10시간정도씩 3개월만 공부하라고 했어. 3개월이 뭐야, 1개월도 안되서 거의 따라잡았고, 올 A+도 받아보고 그랬지.
꾸준함으로 인해 무언가 성공해본 경험은 현재까지도 내게 큰 자산이라고 생각해. 구현력을 키운다고, 신입 초반 3개월 가량 동안 거의 800문제의 알고리즘 문제를 풀었어. 꾸준하게 무언가 했을 때 당장 눈에 안띄더라도 결국 내게 돌아온다는 경험이 내게 있기 때문에 믿고 한거지.
그리고 또.. 궁금한걸 못참아야 좋은 것 같아. 마지막으론 이건 후천적으로 고치기 힘든부분이라 조심스럽긴한데, 솔직히 말해서 논리력이 어느 정도 있어야 유리하다고 생각해. 물론 난 부족함.
2장. 구현 기술과 학습
구현 기술, 학습 대상, 기술 파기, 학습 전략, 유행에 상관없는 구현 기술, 구현 기술 적용, 주의할 점
구현 기술은 어디까지가 실력이고, 어디서부터 도구일까?
내가 절차지향의 대표주자인 C를 주로 하다가 자바로 넘어왔을 때, 객체지향 자체가 잘 이해되지 않았어. 그 때 내가 뭘 했냐면, 자바 언어 공부를 한게 아니고 객체지향 개념에 대해 공부했어. 여러 책에서 객체지향 설명한 부분 위주로만 보는거지. 다형성, 상속 이런 개념들 말이야. 이런게 실력이라고 봐.
내가 지금 C#을 갑자기 써야한다고할 때, 내가 많이 어려워하진 않을 것 같아. 함수명이 뭔지, 기본 CLASS 형태가 뭔진 궁금하겠지. 그건 도구야. 그냥 레퍼런스 찾아보면 돼. 근데 객체지향 개념은 이미 알고있어. 그건 실력이지. 즉, 해당 언어가 표현하고자하는 패러다임에 대한 이해는 실력이고, 응당 존재할 '화면에 문자열 출력하는 함수가 뭔지' 이런걸 익히는건 도구 사용법 익히는거라고 봐.
기억에 남는 가장 효율적인 학습법은?
이건 어떤걸 학습하는지에 따라 다르겠네. 난 언어 익힐 땐 그 언어 대충 문서 찾아보면서 그걸로 알고리즘 문제 풀어봐. 실제로 내 백준 제출내역은 물론 대부분이 자바지만 C, C++, C#, 코틀린 등 다양하게 제출되어 있어.
프레임워크 같은걸 익힐 땐, 난 무조건 따라서 코딩해. 내가 안다고 하더라도, 직접 코딩해봐야 손에 익는다고 생각하거든.
DDD 같은걸 익힐 땐, 여러 책을 구해두고 서로 다르게 표현하는 지점을 찾아보며 읽어봐.
반대로 실패한 학습 경험도 있어?
한 1바이트만큼 학습됬더라도 그걸 실패했다고 말할 수 있을까? 애초에 이전에 말했듯 난 꾸준함의 힘을 믿어. 그러다보니 뭐라도 쌓이면 학습이 되었다고 생각해. 물론 애초에 잘못된 자료로 학습한다면, 그건 실패라 볼 수 있겠지. 그래서 LLM도 학습 도구용이라기 보단, 내 생각 확장용으로 주로 사용하고 있어.
예전엔 열심히 배웠는데, 지금은 안 쓰는 기술이 있다면?
C랑 C++이야. 예전엔 LRU 알고리즘 개선, FTL 개선 이런 프로젝트들을 했었거든. 그래서 C랑 C++ 같이 성능 좋고 RAW한 녀석들로 했었지. 지금은 웹 개발자니까 사실 쓸 일이 없어.
웹개발에서의 얘기라면, JSP가 있겠네. 애초에 프론트쪽에 자바 코드 들어가는거 자체가 마음에 안들어서 사실 처음부터 관심이 없었어. 난 책임과 관심의 분리를 좋아하거든. 뭐 아무튼 초기 신입땐 쓰긴 했는데, 애초에 관심도 없었고, 나한테 어느정도 결정권이 주어지자마자 버리기 위해 노력했어. 자바 코드가 안들어간 JSP 혹은 타임리프 쓰다가, 그것도 얼마 안쓰고 리액트 도입했어. 현재는 백엔드 개발자니 리액트도 내가 안 쓰는 기술이네.
너는 트렌드에 어떻게 반응해? 빨리 따라가는 편? 검증될 때까지 기다리는 편?
난 사실 트렌드에 반응이 느린편이야. '흥미'에 따라 다르긴한데, 아무리 유행해도 내가 흥미를 못느끼면 별 관심 없고 그런거야. 평균적으로 봤을 땐 느린게 맞지. 어쨌든 내 입장은 기술은 도구일 뿐이다니깐. 뭔가 목표가 있고, 그걸 이루기 위해 어떤 기술이 필요하다면 쓰는거지. 뭐 개인 프로젝트야 관심 가는대로 하는거고, 회사에 도입하려면 검증 되야 쓰지. 이렇게 말하긴 하는데 사실 스프링부트 3.0 나오자마자 분석해서 스프링시큐리티 3.0 이상일 때 어떻게 쓰는지 변경점이랑 다 찾아서 블로그 글 적고, 초보자가 따라할 수 있게 글도 쓰고 그러긴 했어.
유행 안타고 계속 쓴다 싶은 기술/개념이 있다면?
대표적으로 디자인패턴이지. 프레임워크가 아무리 특정 디자인패턴을 적용시켜준다고 해도, 그 원리를 모르고 쓰면 안쓰는거야. 그리고 프레임워크가 적용하는건 아무래도 최대한 모든 경우를 만족시키는 방식이지. 결국 커스텀해서 써야만 하는 순간이 프로젝트마다 최소 1번이상은 있고, 그때마다 잘 쓰고 있네
기술에 너무 몰입해서 목표(문제 해결)를 놓쳤던 적?
코드 아키텍쳐로 헥사고날 아키텍쳐 도입했던 적이 있었어. 분명 신규 기능이 추가될거라는 요구사항을 들었어. 난 초기 개발 후 운영팀에 넘기고, 이후로 내가 추가 기능을 개발하지 않을 확률이 낮다고 생각해서 그렇게 했던건데, 아직 추가 안됬거든 ㅋㅋㅋ. 명분은 확실했으나, 현실적 문제로 가치가 없어지고 운영팀만 분석하기 어렵게 된 셈이지 뭐.
3장 소프트웨어 가치와 비용
소프트웨어 가치, 개발 비용, 유지보수 비용을 낮추려면
네가 만든 소프트웨어가 “가치를 발휘했다”고 느낀 순간은 언제야? “이걸로 누군가가 진짜 이득을 봤다” 같은 순간이 있었을까?
사실 내 사고방식도 그렇고 아직 높은 연차가 아니여서 그런지, '소프트웨어 가치'에 대해 고객을 많이 생각하진 않아. 현재까진 그것보다 '맡은 프로젝트를 어떻게 해결했는지'에 대해 더 가치를 느끼는 것 같아.
그런면에서, MSA가 맞다고 생각해서 그걸 기반으로 진행한 프로젝트가 있었어. 실제로 특정 서버의 경우 연동되는 외부 API의 문제로 몇 번 터졌는데, MSA 구조다보니 메인이 되는 결제 부분으로 장애가 전파되지 않았어. 결제관련 프로젝트라 더 잘 된 케이스라고 봐.
개발 ‘비용’이 실제로 무겁게 다가왔던 경험은 언제야? 일정 압박으로 구조를 포기해야 했던 적? "이거 리팩터링 해야 되는데 시간 없으니까 걍 쓰자" 한 적?
이건 뭐 모든 프로젝트 진행할때 모든 개발자가 겪는 경험일 것 같네. 결국 날 사용하는게 인건비가 드는거니깐. 경우에 따라 내 스탠스도 좀 바뀌는 것 같아. 불꺼줘야 하는 상황이라면, 구조나 효율성 좀 포기하고 우선 일정 맞추는 쪽을 택하는 경우도 있어.
보통의 경우라면 일정 압박이 있다면 내 경우 상사가 고를 수 있게 안건을 몇개 던져주는 편이야. A안으로 하면 이런 구조로 가능한데, 이 경우 시간이 더 필요합니다. 그렇더라도 이후 유지보수에서 이런 점이 좋아지니 이걸 추천드립니다. B안으로 하면 이후 리팩토링 기간 필요하긴 한데, 어쨌든 원래 일정 맞출 순 있습니다. 이런식이야. 사실 개발자의 인건비가 비싸다는 체감은 있으니까.. 무겁게 다가왔다기 보다는, 주어진 시간 내에서 조율하면서 진행하는거지 뭐.
“유지보수 비용을 줄이기 위해 평소에 가장 신경 쓰는 점”은 뭐야? 명확한 네이밍? 코드 단순화? 유연한 설계? 다른 사람 코드에 대비한 문서화?
우선은 명확한 코드 로직을 좋아해. 2depth 이상 들어가는걸 최대한 지양하고, 조건문에도 else 거는걸 지양해. 여러 케이스에 대해 고려한 뒤, 그걸 추상화해서 최대한 많은 케이스를 담은 조건으로 early return 하는 식이지. 막 if문 안에 100줄? 이런건 나도 이해 못하는데 운영하는 사람은 오죽하겠어?.
그리고 명령과 쿼리의 분리도 좋아하는 편이야. 네이밍에선 축약어를 좀 극혐해. 물론 많이 사용되는 축약어는 괜찮은데, 예상되지 않고 의미 전달이 어려운 축약어 쓰는걸 보면 엎고싶어. 예를들어 message -> msg 이런건 괜찮아. 근데 person -> prsn 이런건 절대 안써.
설계적으로 보면, OCP를 가장 중요하게 생각해. 기능 추가 시 기존 코드 수정을 최대한 안하는 방향으로 짜려고 항상 노력해. 그러다보니 전체적인 구조는 스프링부트의 일반적인 아키텍쳐를 따라가지만, 도메인 로직에 대해서는 디자인 패턴을 자주 사용하는 편이야.
문서화는 딱 하나만 생각하고 작성하는데, 이게 효율이 좋긴 하더라고? 뭐냐면 "나한테 질문이 최대한 안왔으면 좋겠다" 이거야 ㅋㅋㅋ
기술적으로 ‘이렇게 하면 완벽할텐데…’ 싶은 걸 포기한 적이 있어?
우선 '완벽할텐데'는 없어. 난 개발에 답은 없다고 생각하거든. 명분이 있을 뿐이지. 이건 많지. 보통은 일정 문제 때문이야. 내 개발 가치관은 코드엔 '명분과 팀의 합의'가 있어야 한다거든. 명분은 있더라도, 일정 문제가 조정되지 못했다면 팀의 합의 부분이 못 이뤄진거지. 그럼 이제 또다른 명분이 되는거야. '이번엔 일정 문제로 어쩔수 없이 이렇게 간다.'. 그래서 트랜잭션 스크립트 패턴으로 간 적도 많고 그렇네.
‘유지보수가 곧 가치’라고 보는 시각에 공감해?
회사 차원에서 대외적으론 이게 맞다고 생각해. 솔직히 말하면 소프트웨어 보다, 내 실력을 늘리는데에 더 관심이 있다보니, 유지보수를 위해 코드 품질을 더 늘리자! 이런 느낌은 아닌 것 같네. 그냥 내 실력 향상을 위해 코드를 설계하며 짜다보면, 결국 유지보수도 좋아지는거니 이것도 좋은 방법이라 생각해
4장 코드 이해
코드 변경, 코드 이해 도구, 이해하기 좋은 코드
지금까지 경험한 코드 변경 중 가장 힘들었던 경험은 뭐였어? 그게 코드 이해 때문인지, 아니면 기존 구조의 문제였는지도 함께 알려줘.
애초에 유지보수를 내가 개발한것만 했다보니, 힘든 코드 변경이 잘 없었어. 그래도 중간중간 타팀 도와주기 등으로 코드 변경을 해본적은 있으니 한번 얘기해볼께.
우선은 모든 비즈니스 로직이 DB 프로시져에 있던경우가 있었어. 애초에 싫어하는 구조기도 하고, 일단 디버깅이 힘드니까 코드 변경 해도 이게 맞나? 싶고 그랬지. 이건 구조의 문제였네.
코드 이해 때문으로 힘들었던건, 지나가다가 타팀이 유지보수 하던 코드를 봤는데 뭔 if문 안에 depth도 깊고, else도 많고 100줄 넘게 있는걸 해당 직원이 끙끙대면서 분석하고 있더라고. 지나가다가 갑자기 흥미가 들어서 "한 번 리팩토링 해봐도 될까요?" 라고 했고, 최종적으로 1/4 이하로 줄여줬어. 이건 코드 이해 때문에 어려웠긴한데, 애초에 목적이 리팩토링이라 너 질문이랑 맞게 대답했나 모르겠네.
이해를 돕기 위한 좋은 코드에 대해 어떤 항목을 가장 중요하게 생각하고, 어떤건 덜 중요하다고 생각해? 예를 들어 “중복 제거는 적당히만 해도 된다” 같은 너만의 기준이 있을지도?
depth가 늘어나지 않고, 분기를 빠르게 early return 하는게 가장 중요하다고 생각해. 결국 사람의 단기기억력엔 한계가 있어. if가 시작하면서 사람은 해당 조건을 머리에 malloc() 시키겠지. depth가 늘어나면 컨텍스트 스위칭 시키겠고. 그런식의 단기 기억을 최대한 빠르게 free() 시켜주는게 코드 이해를 돕는데 가장 중요하다고 생각해.
추상화 수준에 따른 메서드 추출을 덜 중요하게 생각해. 모든건 트레이드오프라고 생각해. 추상화 수준이 섞이더라도 5줄밖에 안되면? 차라리 하나의 함수로 처리하는것도 좋다고 봐. 5줄밖에 안되는데 함수 5개로 나누면 읽는 흐름이 오히려 분산된다고 느껴져. 물론 상황마다 다르긴 하겠지만.
트레이드오프와 관련된 다른 경험도 있는데, DB 설계 시 정규화를 하잖아? 근데 이걸 정말 다 지킨경우 오히려 코드 짜기가 엄청나게 어려워지기도 해. 난 단순한 게시물 리스트 하나 출력하는데 조인이 13개 필요하도록 설계된 경우도 봤어 ㅋㅋ. 심지어 인덱스 설계에 대한 고려는 부족해서 데이터도 많지 않은데 뭐 10초이상 걸리더라고.
‘코드는 결국 읽히기 위한 것’이라는 말에 개인적으로 얼마나 공감하는지, 그리고 그게 네 개발 습관에 어떤 영향을 주는지도 말해줘.
원래 누군가 뭔가를 엄청 쉽게한다면, 그 사람은 고수다 라는 밈이 있잖아? 코드도 마찬가지라고 봐. 아니 겨우 이거밖에 안짰어? -> 그만큼 쉽고 간결하게 코드를 짜는 고수야. 나도 지향하는 바이기도 해. 아 물론 에러도 많으면 고수 아니고 ㅋㅋㅋ 에러도 안나는데 요구사항을 모두 포함하는 간결한 코드라면 이라는 얘기야
5장 응집도와 결합도
응집도, 결합도
“응집도가 높다”는 걸 실제 코드에서는 어떻게 판단해? 클래스/모듈/패키지 단위에서 각기 다른 기준을 두고 있진 않아?
결국 응집도에 대한 판단 기준은, 책임이 얼마나 밀접하게 뭉쳐 있는가로 판단해. 직관적으로는, 뭔가 요구사항이 변경될 경우 얼마나 적은 수의 클래스를 손대야하냐로 판단 가능할 것 같아. 클래스, 모듈, 패키지 단위도 결국 마찬가지라고 봐. 그리고 어느 추상화 수준에서 응집도를 챙길지는 결국 변경하려는 요구사항이 어느 추상화 수준이냐에 따라 달라지겠네. 최초 개발 시 어느 수준까지 응집도를 챙기지는 프로젝트 사이즈에 따라 달라질 것 같고.
네가 생각하는 “결합도가 낮은 코드”는 어떤 상태야? 완전히 독립된 모듈처럼 동작하는 게 좋은 걸까, 아니면 어느 정도는 흐름이 있어야 한다고 봐?
동작에서의 결합도 보다는, 결국 이것도 응집도와 마찬가지로 이후 '수정'될 때를 봐야할 것 같아. 어떠한 요구사항에 의해 수정이 필요할 때, 한 기능을 수정하기 위해 연관된 클래스를 얼마나 건드려야하냐가 핵심같네. 이 경우에도 역시 따로 '결합도를 챙겨야되!' 라고 생각하면서 짠다기보다는, 기본적으로 OCP를 좋아해서 그걸 위주로 설계하다보니 결합도는 자동으로 챙겨진다고 봐야겠네. OCP를 기반으로 설계하면 굳이 의식하지 않아도 결합도는 자연스레 낮아진다고 생각해.
6장 리팩터링
수정 공포와 변경 비용, 리팩터링, 리팩터링 vs 새로 만들기
“수정 공포”를 느꼈던 구체적인 순간이 있었어? 그 공포의 원인은 비즈니스 로직 얽힘, 테스트 미비, 명확하지 않은 흐름, 복잡한 if-else 중 뭐였는지도 궁금해
우선 난 운영경험은 거의 없어. 대부분의 경험이 신규개발건 위주야. 비중이 그런거고, 아예 안해본건 아니니 몇가지 생각을 꺼내볼께.
우선 첫번째로는 DB 프로시져에 비즈니스 로직이 들어간 경우였어. 당연히 대부분 이런 코드를 짜는 사람들은 매직 넘버 등도 사용하게 되어있어. '... WHERE TYPE = '10'...' 이런거지. 난 프로시져에 비즈니스 로직이 있는걸 몇번 경험해보고 나니, 개인적으론 싫어해. 형상관리도 어렵고, 스케일아웃도 힘들고, 디버깅도 힘들지. 심지어 처음 개발자 시작할 때 "비즈니스 로직은 DB단에만 있어야 한다" 라고 가르침 받기도 했어. 물론 난 처음부터도 내 생각은 어느정도 있었어서 사실 무시했지 ㅋㅋ.
두번째로는 코드에서 나는 냄새가 너무 이상한 경우야. 즉, 코드 스타일이 일관되지 않고 복붙한 티가 너무 나는 경우 말야. 무슨말이냐면, 같은 사람이 짠건데 'if (a == b)' 이런 인덴테이션과, 'if(a==b)' 이런 인덴테이션 두 가지가 존재한다고 해보자. 본인이 직접 짜지 않고 복붙한 후에 확인조차 안했을 확률이 높아. 이런 프로젝트 코드를 받게되면, 단위 기능에 대한 리팩토링 문제가 아니라, 프로젝트 전체에 대한 신뢰도부터 확인해봐야되서 너무 공포스러워.
리팩터링을 ‘정기적으로 한다’거나 ‘작업 중 틈틈이 한다’는 습관이 있어?
내 기본 개념은 '명분과 팀의 합의'야. 만약 초기 개발에 기간이 부족해서 팀적으로 좀 놓고 가자고 했었다면, 이후 시간이 남을 때 기간을 잡고 진행해. 이 경우라면 정기적으로 한다에 해당하겠네. 시간이 충분하다면, 난 당시 내가 가진 배경지식과 경험을 바탕으로 그 순간에서 최선이라 판단되는 구조로 진행해. 물론 너무 과하진 않게. 그런데 이후 예상치 못한 요구사항이 발생했다면, 그 땐 리팩터링으로 구조를 조정해. 또는 내 배경지식이 증가했다면 역시 구조를 조정해. 그 경우라면 틈틈히 한다에 해당하겠네.
난 전체적인 설계 구조를 중요하게 봐. 이건 대학교때 담당 교수님도 같은 생각이시라, 연구실 프로젝트 기간이 얼마 안남더라도 더 좋은 구조가 생각난다면 갈아엎는식으로 진행했었어. 그 경험이 현재 나에게도 영향을 끼치는거라고 봐.
너한테 리팩터링은 ‘깨끗한 코드’가 목적이야? 아니면 ‘시스템 생존성 유지’가 목적이야? 미학적인 차원의 만족감인가, 아니면 유지보수 가능한 구조로 만드는 전략적 수단인가?
솔직히 말하면 자기만족이야. 난 "이 코드 이 부분 왜 이렇게 짠거에요?" 라고 누가 물어보면, 대답할 수 있어야 한다고 얘기해. 단순히 동작만하는 코드는 당연히 가능해야 하는거야. 개발자라면 그 이상으로 자신의 생각이 코드에 담겨야 한다고 생각해. 그러다보니 '미학적 차원의 만족감' 쪽이 가까워. 다만, 그걸 추구하다보면 '유지보수 가능한 구조'는 자연스레 따라오는거라고 봐.
7장 테스트
테스트 코드, 테스트 가능성, 리팩터링을 위한 테스트 작성하기
테스트 코드 작성에 있어 네가 가장 중요하게 여기는 원칙은 뭐야? (예: 가독성, 실행 속도, 독립성, 커버리지 등) 그리고 그 원칙을 선택하게 된 계기나 이유는?
커버리지이긴 한데, 좀 의미가 다른 커버리지야. 난 코드 전체에서 테스트가 얼마나 커버하는지에 대한 일반적인 커버리지는 크게 중요하게 보지 않아. 물론 일정 수준이상의 %는 넘겨야 하겠지만, 100%를 추구한다거나 그런거에 큰 의미를 두지 않아. 그보다 중요한 도메인 로직에 대해서, 해당 로직에 대한 예외 케이스를 최대한 생각해서 테스트 코드를 짜야 한다는 의미에서의 커버리지야. 굳이 sum() 함수를 테스트해야할까? 굳이 LinkedList<>에 대한 add()를 테스트해야할까? 굳이 DI가 잘됬는지 테스트해야할까? 이런 건 이미 검증된 기본 동작에 가까워. 난 그런걸로 힘빼다 흥미 잃지 말고, 제일 중요한 도메인 로직에 최대한 집중하는게 좋다고 생각해.
리팩터링 전 테스트 작성, 실제로 해본 적 있어? 없다면 왜 잘 안 하게 되었는지, 있다면 어떤 식으로 접근하는지 궁금해.
아직 운영중이 아닌 경우라면 안할때도 있어. 예를들어 내가 전체 구조를 바꾸고 싶어서 갈아엎는 경우지. 이 경우라면 테스트 코드가 오히려 방해되기도 하더라고.
실제 운영중인걸 리팩토링 한다면 항상 하는편이야. 다만 안한다기보단 못하는 경우가 있는데, 개발자 초창기에 다른 답변에서도 얘기했던 DB 프로시져에 로직이 있는 경우야. 또는 프론트쪽에 로직이 있는 경우에도 따로 테스트코드를 짤 생각은 안했어.
단위 테스트 vs 통합 테스트의 비중은 어떻게 두는 편이야? 팀 내 문화나 프로젝트 성격, 혹은 너만의 경험을 바탕으로 어떤 방식이 더 생산적이라고 느꼈는지.
난 단위 테스트를 더 가치있게 생각해. 애초에 내가 코드 뿐 아니라 전체적인 사고방식에서 결합도를 떨어뜨리는 방식을 선호해. 테스트도 마찬가지야. 개별 모듈에 메시지를 보냈고, 그 메시지가 해당 모듈 내에서 정상적으로 처리하는지만 보면 됬어. 이후로는 서로간의 메시지를 주고받는 인터페이스만 정상적이면 되. 통합 테스트와 같은 형태는 오히려 학습 테스트 시에 즐겨쓰는 편이야. 테스트코드 쪽에다가 학습하면서 전체 구조 짜서 돌려보는거지.
한편으로는, 전통적인 '테스트'에 위반하는 테스트더라도 도움이 된다면 서슴치않고 짜는편이야. 예를들어 매크로 형태로, 외부와 연결되어야 하는 부분이 현재 프로젝트의 모든 기능에 대해 모두 정상인지 확인하는 테스트 같은거지. 물론 이건 평소엔 돌지 않도록 Condition으로 막아뒀어. 실제 특정 이용기관이 우리 서비스를 도입하는 과정에서, 하나씩 API 연결 성공적인지 확인하기 귀찮으니깐, 전통적인 테스트에 부합하진 않지만 테스트코드로 만들어둔거지.
또, 이후 개발자가 실수하지 않도록 패키지 의존성에 대한 검증용 테스트도 만들어두는 편이야.
테스트 코드도 결국 유지보수 대상이야. 너는 테스트 코드를 어떤 기준으로 리팩터링하거나 삭제해야 할지 판단해?
결국 테스트 코드도 요구사항이 바뀌었을 때 의미 있는 대상만 리팩터링하는게 맞다고 봐. 사실 DDD와 같은 관점에서 설계해둘 경우, 내가 말한대로 도메인 로직 위주로 테스트를 진행할 경우 거의 테스트 코드를 손댈 일은 없다고 봐. 그것 때문에도 내가 도메인 로직만 집중해서 테스트하는걸 선호하는 것 같네.
테스트 코드는 진짜 코드일까, 아니면 일회성 스크립트일까? 즉, 테스트 코드에 어느 정도의 ‘아름다움’이나 ‘유지보수성’을 부여해야 할까?
다이어트 한다고 하면, 목표를 크게 잡는거보다 일단 당장 나가서 달리라고 하잖아? 그런거라고 봐. 굳이 테스트 코드까지 너무 완벽하게 짜려고 하다보면 오히려 중요한걸 놓치거나 흥미를 잃을 수 있다고 생각해. 그러니 난 초반엔 일회성 스크립트로 생각해. 나중에 필요에 따라 다듬어 나가는거지.
단, Display를 통해 어떤걸 테스트하려는 건지는 확실히 적어두는 편이야. 왜냐면 이후 신규 팀원이 생겼을 경우 테스트의 display 부분만 봐도 어느정도 도메인 지식을 습득할 수 있거든.
8장 아키텍처ㆍ패턴
아키텍처 고민하기, 패턴 익히기
아키텍처 선택에서 가장 크게 작용한 제약 조건. 실제 프로젝트에서 어떤 제약 조건이 아키텍처 방향을 정했는지?
결국 프로젝트의 생명주기에서 가장 긴건 유지보수 기간이야. 내가 아키텍처를 선택할 때 가장 크게 작용한 제약 조건은, 개발 시 이후 유지보수때 발생할 것으로 예상되는 문제점을 해결하기 가장 좋은걸 선택해야 한다는거였어.
예를들어 외부 시스템이 많이 붙고, 하나의 서비스 내에 사용자층이 갈리는 프로젝트가 있었어. 우리쪽의 관리자페이지, 하위 기관의 관리자페이지, 실제 고객이 결제하는 페이지, 하위 기관에서 실시간 API 처리하는 부분(결제 취소 등), 대규모로 매일 특정 시간에 폴링으로 진행되는 내역을 주고받는 파일 시스템. 여기서 난 사용자를 기준으로 시스템을 나누어서 MSA로 구성했고, 장애가 전파되지 않도록 했어. 외부와의 파일 송수신은 여러 번 외부 시스템의 문제로 장애가 났지만, 아키텍처 분리 덕분에 고객 결제 흐름은 영향을 받지 않았었어.
실제로 패턴 써먹은 경험 중 최고였던 건? 실전에서 강력했다고 느낀 패턴과 그 이유
옵저버 패턴쪽이라 생각해. 객체지향 설계의 역할, 책임, 협력의 관점에서 가장 쉽게 분리할 수 있도록 해주는 것 같아. 또한 중앙에서 메시지를 전파하고 각 모듈이 스스로 반응하게끔 설계할 수 있어서 OCP에 잘 어울려. 느슨하게 서로를 연결되도록 하기도 좋아. 각 모듈별로 각자가 어떻게 구현되었는지 몰라도 되고. 결국 요즘 많이 쓰는 카프카 같은 메시징 처리 방식이 옵저버 패턴의 확장이라 생각해.
패턴이 오히려 방해가 되었던 적은? 적용이 오히려 설계를 굳게 만들었던 경험이 있다면
사실 대부분의 디자인 패턴은 이미 프레임워크나 라이브러리에 적용되어 있어. 그렇다보니 일반적으로 라이브러리 종속성 없게 POJO로 짠 도메인 로직에 '꼭 필요하다고 생각될 때' 디자인 패턴을 넣는 편이야. 그래서 따로 그게 설계를 굳게 만든적은 없는거같아. 만약 설계를 굳게 만들었다고 판단되면, 애초에 내가 잘못넣은거니 빼버리거나 다른 패턴을 적용했었지.
“완벽한 아키텍처는 없다”는 말, 공감했는지? 차악을 선택한 경험과 그 결과
모든건 트레이드오프야. 만약 '완벽한' 무언가가 있다면, 애초에 개발자들은 논리적으로 판단할 필요가 없지. 그냥 그걸 그대로 외워서 그대로만 하면 되니까. 차악을 선택한 경험은 많지. 대부분의 경우 외부 요소 때문이야. 개발 기간의 제한이나, 이후 이걸 유지보수하게될 팀의 역량을 판단해서 차악을 선택하는거지. 예를들어 운영팀이 카프카를 아는사람이 없다고 해볼께. 여기서 필요하다고 갑자기 카프카를 넣는다면? 유지보수가 힘들어지겠지.
기술 스택 선택도 아키텍처 논의 대상인가? (도구 수준 vs 구조 수준) 경계를 어디서 두는지
도구라고 봐. 기술 선택은 최대한 늦춰야 맞아. 구현의 마지막 단계에서 실제 시스템 요구사항과 유지보수 환경을 고려해 결정해야 한다고 봐. 내 경우에도 주로 DB는 최초 개발시엔 그냥 map으로 두고 만들어. 인터페이스로 실제 사용하는곳과 연결해두지. MyBatis를 쓸지, JPA를 쓸지, JDBC를 직접 쓸지 이런건 도메인 로직과 관련 없어. 마지막에 현재 시스템에 가장 적절한 기술 스택을 고르면 돼.
같은 맥락에서 난 내가 DB 설계를 할 필요가 있을땐, DB 설계는 맨 마지막에 하는 편이야. 예를들어 DDD 관점에서 전체 시스템을 구성하고, DB는 현재 시스템에 필요한 최소한의 테이블로 설계해. 최대한 간단한 구조로.
물론 근데 외부 요인에 따라 설계 시 논의 대상이 될 순 있어. 예를들어 운영팀이 A라는 기술스택을 잘 모르고, 비슷한 B를 써봤다고 할께. 꼭 A를 써야만 하는 명분이 있지 않다면 최대한 B를 선택하겠지.
9장 업무 관리
처음부터 끝까지, 업무 나누기, 완료의 의미, 위험 관리, 요구 사항은 바뀐다, 일정, 점진적ㆍ반복적 개발, 안 된다고 말하기, 대안 제시하기, 수작업 줄이기, 이유와 목적 생각하기
"처음부터 끝까지" — 프로젝트 전체 생명주기를 어떻게 정의하고 있나?
플랫폼 서비스를 기반으로 생각해보면, 딱히 끝은 없어. 결국 해당 서비스에 사용자가 더 이상 존재하지 않게 되어 정식 종료되는 시점이 진정한 의미의 끝이겠지. 유지보수 기간은 ing이지 뭐. 단순히 운영팀에 전달하기 전까지를 프로젝트의 끝이라고만 본다면, 개발하는 곳에서 플랫폼 서비스를 1~2군데 정도는 붙인 후에 운영팀에 넘겨야 한다고 봐. 실제 이론으로 구현하는것과, 실제 하위 이용기관을 붙여보는건 또 다른얘기니깐.
"업무 나누기" — 네가 주도해서 업무를 쪼갠 경험이 있어? 어떤 기준으로 나눴는지? 단순히 기능 단위였는지, 담당자의 경험 수준까지 고려했는지? 결과적으로 나눔이 잘 된 경우 / 망한 경우 각각 있다면?
객체지향 설계에서의 역할, 책임, 협력 이 얘기를 좋아해. 업무 나누기도 이 개념에 따라 나눌때가 많아. 단순히 기능단위로 나누는건 싫어하는 부분이야. 오히려 각 업무를 캡슐화하고, 인터페이스를 설계해. 자바에서의 interface와 동일한 의미로 그렇게 해. 서로의 구체적인 구현 방식이나, 구현 시점은 몰라도 인터페이스에 맞게 서로 개발하게 하는거지.
기능 단위로 나누는걸 싫어하는건, 내가 개발자 초반에 많이 당해봤기 때문이야. 기능별로 코드 퀄리티도 너무 달라지고, 뭐 요구사항 들어오면 서로가 파악해서 하는 구조가 아니라 이 기능에 대한 요구사항이나 너가해. 이렇게 되는거지. 그럼 5개씩 기능별로 나눠가졌는데, 내가 잘해서 빨리 끝나서 남들이 못했던걸 추가로 처리해서 10개를 작업했어. 그럼 이후 요구사항이 누구한테 많이 들어올까?
"일정" — 네가 직접 일정 산정한 적 있어? 틀린 적은? 가장 크게 틀렸던 일정은 어떤 거였고, 왜 틀렸는지 회고적으로 보면 어떤 요인이 있었을까? 혹시 일정 문제로 인해 팀 내에서 신뢰가 흔들렸던 경험도 있었는지?
일정이 틀린 이유부터 생각해보면, 나랑 '완성'에 대한 기준자체가 달라서 그랬던거였어. 난 설계를 분석하고, 코드를 짜고, 본인이 검증해보고, 예상되는 예외케이스까지 처리한걸 해당 단위에 대한 완성으로 보거든. 근데 '코드를 짜고' 까지나, '본인이 검증해보고' 까지만 완성으로 생각하는 사람들도 꽤 있어. 이거에 대한 감각 없이 내 기준대로 생각하니까, '다 됬어요' 라는 말에 대해 서로 생각하는 바가 달랐던거지.
"안 된다고 말하기" — 너는 얼마나 잘 ‘거절’할 수 있어? 실제로 거절했던 사례, 혹은 말 못 해서 고생했던 적 있으면?
일단 전제로, 명분과 팀의 합의라는 관점에서 이미 팀에서 결정된 거라면 내 맘에 안들더라도 따르는 편이야. 반면 내가 주도권을 잡고 있는 경우라면, 난 일정 선을 설정해두는 편이야.
예를들어 내가 A라고 설계를 해뒀는데, 요구사항이 A' 이나 A'' 정도로 내가 수용할 수 있으면 괜찮은데, 갑자기 B를 원한다면 기본적으로 거부 의사를 표해. 물론 날 논리적으로 설득할 수 있다면 B로 변경도 가능해. 날 논리적으로 설득했더라도, B가 너무 과하다고 생각할 경우 B-1, B-2, B-3 이라는 절충안을 들고가서 고르게 하는 식이야.
일정에 관해서도 마찬가진데, 기본적으로 야근을 하지 않는 선에서 내가 할 수 있는 기간까지가 내 선이야. 그렇게 해야 예외 케이스가 발생했을 때 야근으로 처리가 되는거거든. 처음부터 야근을 상정한 일정을 본인이 받아들인다면, 정말 야근을 할 수 밖에 없는거지 뭐. 애초에 자기 객관화를 통해 본인이 할 수 없는 수준의 일은 조정하거나 받지 않는게 맞다고 봐. 물론 말은 이렇게 해도 실제론 자기 객관화는 어렵고, 어쩔수없이 받은적도 많긴하지.
10장 정리하고 공유하기
글로 정리해서 공유하기, 마인드맵 사용, 발표하기, 외래어 남용하지 않기, 글쓰기와 발표가 주는 효과
네가 글을 정리해 공유한 경험 중 가장 보람 있던 사례는? 단순 기술 정리일 수도 있고, 개인 회고일 수도 있고, 누군가에게 도움 되었다는 피드백을 받았던 경험이 있다면 공유해줘.
‘보람’이 남한테 도움이 되었다는 의미에서의 질문이겠지만, 그것보다 내가 기분 좋아서 보람 있었던걸 얘기해볼께. 개발쪽에 유명한 '토비'님이 인프런이라는 강의 사이트에 강의를 올리신걸 보고 리뷰글('[수강평] 토비의 스프링 부트 - 이해와 원리')을 적어 올렸거든. 그걸 누군가 보고 트위터에 "토비님은 이런 독자가 있다니 기쁘겠다." 라면서 내 리뷰를 링크걸었어. 그걸 또 토비님이 리트윗 하셨더라고. 이후로 토비님 계신 톡방에서 토비님이 "아.. nahwasa님이 여기에" 라고 알아봐주셔서 기뻤어 ㅋㅋ 강의 리뷰로 인해 존경하는 개발자님에게 언급된게 기뻤지.
남한테 도움이 된거라면, 스프링부트 3.0이 출시되었을 때 스프링 시큐리티쪽으로 변경점이 꽤 있었거든. 그거 정리해서 예제 만들고, 초보자용으로 따라하면 스프링부트 3.0 기반 스프링 시큐리티 구축할 수 있도록 글('스프링부트 3.0이상 Spring Security 기본 세팅 (스프링 시큐리티)')을 썼었어. 그거 예제 github repository도 거의 60개의 star를 받았고, 블로그 글도 많은 공감을 받았어. 근데 솔직히 그거보다 토비님 썰이 더 기쁘긴 했네 ㅋㅋ
생각을 정리할 때 어떤 도구나 방식(마인드맵, 표, 글, 그림 등)을 주로 쓰고, 왜 그 방식을 선호해? 실제로 문제 해결이나 발표 준비할 때 너만의 머릿속 구조화 방법이 있다면 그걸 알려줘.
제일 선호하는건 그냥 노트 펼쳐놓고 내 생각을 무작위로 적어보는 방식이야. 관련된 주제를 무작위로 적어본 후에, 큰 단위부터 추상위 수준을 낮추면서 점점 구체적으로 목차부터 만들어. 그다음 아까 적은 무작위로 적은게 각각 어느 항목에 들어가면 좋을지 매칭시켜. 사실 그 두가지에 순서가 있는건 아니고, 동시에 하는거라고 보면 되. 중간중간 관련 주제로 생각 나는걸 적어두고, 목차를 큰 분류부터 세분화하면서 점점 매칭시켜나가는 과정이지. 이건 대학교때에 영향을 많이 받은 부분인 것 같네. 논문이나 연구보고서 쓸 때 많이 이런식으로 했거든.
마인드맵을 공책에서 한다고 보면 될 것 같네. 뭔가 생각할땐 컴퓨터보단 직접 손으로 하는걸 선호해. 실제 마인드맵 양식은 생각 과정보다는, 내 생각과정을 남한테 보여줄 때 깔끔하게 정리하는 용도로 써.
세미나나 발표를 할 때 어떤 부분을 가장 중시해? 내용 자체보다 흐름, 전달 방식, 질문 유도 등 어떤 요소를 중요하게 보는지. 발표 준비할 때 너만의 팁이 있다면 그것도 같이 알려줘.
너무 딱딱하지 않게 하는 것과 중립을 지키는걸 중요하게 여겨. 중간중간 개그요소를 넣어서 주위를 환기시켜. 그리고 일반적으로 난 해당 주제에 대해 나만의 생각이 있지만, 남한테 내 생각을 피력하지 않도록 주의해. 꼭 하고싶은 말이라면 항상 주의문구를 넣어두는 편이야. "제 개인적인 생각이며, 사실과 다를 수 있습니다." 이런식으로.
내용 구성 측면에서 얘기해보자면, 흐름을 중요하게 여겨. A를 알아야 B를 이해할 수 있는 경우가 있잖아? 물론 이런 단순한거면 상관없는데, A를 알아야 B를 아는데, B를 알아야 C를 알고, C를 알아야 A를 알 수 있는 이런 경우도 있지. 이럴 때 흐름을 어떻게 잡냐가 제일 어려운거같고, 가장 많이 신경쓰는 부분이야.
실제로 글이나 발표에서 ‘외래어 남용’을 피하려 노력하는 편이야? 피하려 한다면 왜? 반대로 너는 기술적인 커뮤니케이션에서 외래어나 전문 용어가 어느 정도는 필요하다고 생각해?
이건 듣는 대상에 따라 달라져. 개발자끼리의 대화라면 굳이 대명사를 피하려 하지 않아. 예를들어 "어댑터 패턴" 느낌으로 가죠. 이런식으로만 말해도 개발자끼린 알아먹잖아? 근데 비개발자에게 얘기하려면, 이걸 구체적으로 설명하기도 뭐하고.. 좀 더 일상적인 내용을 가지고 비유로 설명해야겠지.
개발자끼리의 대화일 경우에도 뭐 일부러 외래어를 쓰진 않지만, 좀 모호한 표현은 항상 외래어 표현으로 오히려 쓰는 것 같네. 예를들어 composition 이런게 한글론 '합성', '조합' 등 많은 용어로 부르지만 대부분 와닿지 않아. 그냥 컴포지션이라 말해야 이해할 것 같네.
너는 글쓰기와 발표를 통해 어떤 식으로 ‘사고가 정제되거나 확장’된다고 느껴? 단순히 남을 위한 정리인가, 아니면 너 스스로의 ‘사고 확장 도구’인가?
기본적으로 남한테 내가 아는걸 알려주는 과정에서, 해당 주제에 대한 내 이해도가 확실히 높아진다고 생각해. 40 정도의 내용을 발표하려면, 못해도 80은 알아야 하거든. 남한테 알려줄 생각 없이 혼자 공부한다면 내가 아는게 80인지 알 방법이 없어. 남한테 알려주기 위해 발표자료를 만들다보면 내가 어느정도 이해하고 설명할 수 있는지 알 수 있지.
11장 리더와 팔로워
리터 연습하기, 팔로워, 겸손ㆍ존중ㆍ신뢰
누군가의 리더십 아래에서 일할 때, 네가 중요하게 여기는 점은 뭐야? 반대로, 리더가 너무 부족해서 힘들었던 경험이 있다면, 그때 너는 어떻게 대처했는지도 궁금해.
나는 리더십 아래에서 일할 때 항상 비슷한 태도를 가졌던 것 같아. 너무 맹목적으로 따르지 않고, 그렇다고 일부러 척을 지지도 않아. 내가 감당할 수 있는 책임의 범위를 정해두고 일을 진행해. 그게 힘들다고 "안된다"라고도 잘 하지 않아. 대신 절충안을 찾아 리더에게 들고가서 직접 리더가 선택하게 하는 편이야.
개발자 커리어에서 겸손, 존중, 신뢰가 필요하다고 느낀 순간은 언제였어?
겸손과 존중, 신뢰는 사실 비단 개발의 얘기가 아니지. 그냥 사람이라면 기본적으로 필요한거라고 봐. 겸손과 존중은 자기의 현재 위치를 인식하는 것에서부터 시작된다고 생각해. 난 개발자로써 겸손과 존중을 초기부터 가질 수밖에 없던 것 같아. 아무래도 개발자 초창기에 구현력 키운다고 알고리즘을 많이 풀었으니깐. 뭐 초등학생임에도 내가 생각도 못한 방법으로 문제를 해결하고 그러더라고. 천외천이라고, 내가 얼마나 실력이 늘던 항상 그 위가 항상 있다고 생각해.
신뢰도 마찬가지긴 하지만, 개발자에게 제일 중요한거라고 봐. 아무리 실력이 좋은 사람이더라도 신뢰가 깨지면 일단 같이 일하는게 힘들어져. 서로에 대한 신뢰를 전제로 하지 않으면 협업 자체가 무너질 수밖에 없어.
'Study > 책, 강의 생각 정리' 카테고리의 다른 글
'주니어 백엔드 개발자가 반드시 알아야 할 실무 지식'을 읽고 떠오른 내 생각들 (6) | 2025.05.19 |
---|
댓글