본문 바로가기
Study/객체지향 시스템 디자인 원칙

[객체지향 시스템 디자인 원칙] 내 생각 Q&A - 8장. 실용적인 접근법

by Nahwasa 2025. 7. 16.

목차

     

      이 글은 ['객체지향 시스템 디자인 원칙'을 읽으며 정리한 내 생각 - LLM과의 Q&A 기반 사고 확장] 글을 챕터별로 나눈 시리즈 중 하나 입니다. 전체 흐름을 보고 싶거나, 다른 챕터를 확인하고 싶으시다면 위 통합글을 참고해주세요.

     

      이 글은 책 내용을 요약하거나 정리한 글이 아닙니다. 책을 읽고 난 뒤 제 생각을 중심으로 정리한 글 입니다. '객체지향 시스템 디자인 원칙'을 읽으며, 느낀점이나 좋았던 점 및 책에 제시된 연습문제를 LLM에게 알려줬습니다. 이를 바탕으로 제 생각을 기반으로 책의 연습문제를 변형하거나, 새로운 질문을 생성하게 했습니다. 그 후 제가 그 질문에 답하고, LLM과 토론하는 방식을 사용해 사고를 확장해봤습니다. 이 글은 그 질문과 답변을 모아둔 글 입니다. 자세한 작성 배경은 통합글에서 확인하실 수 있습니다.

     

     Q1, Q2와 같은 질문 외의 모든 답변은 LLM을 쓰지 않고 제가 직접 답변한 내용입니다. 이후 LLM과 토론하며 생각이 조금씩 바뀐 부분들도 있으나, 최대한 초안 답변으로 올렸습니다.

     제 생각을 적은 것으로, 일반적인 개발자들의 생각이나 사실과 다소 다를 수 있습니다.

     

     


     

    8장. 실용적인 접근법

    Q1. 리팩터링은 ‘수익률 높은 투자’다. 이 말에 너는 얼마나 동의해?

    • 실무에서 리팩터링을 자주 하는 편이야? 아니면 일정에 쫓겨 잘 못 하는 경우가 많아?
    • 지금까지 리팩터링을 해서 ‘진짜 잘했다’ 싶었던 경험과, 오히려 ‘괜히 건드렸다’ 싶은 경험이 있다면?
    • 리팩터링 타이밍은 어떤 기준으로 판단해?
    • (예: 커밋 수 기준? 기능 분기점? 코드 읽기 난이도?)

     

    내 답변

      사실 내 업무 특성 때문에 많이 하진 못해. 다른 답변에서도 말했지만, 보통 플랫폼 서비스 초기 개발 후 1~2군데의 하위 이용기관 도입까진 내가 운영해. 그 후 서비스 크기에 따라 운영팀 혹은 별도팀으로 넘어가는 식이야.

     

      그래서 초기 개발 시의 리팩터링이 대부분이야. 보통 일정이 그리 널널한 편은 아니야. 그러다보니 초기 개발하면서 우선은 ‘이정도면 괜찮지’ 수준으로 우선 만들면서, 이후 여유 있을 때 리팩터링 할만한 부분은 따로 적어둬. 물론 여유 있다면 바로바로 처리하지. 즉 내가 주로 해본건 장기적인 리팩터링보다는, 기술 부채를 내 현재 수준에서 최대한 관리 가능한 수준으로 유지시키는거였어. 예를들어 최근 프로젝트에서 적어두고 리팩터링했던 부분 중 일부를 적어보면 다음과 같아.

    • 로그 부분 전부 람다식으로 변경 (참고 : 메모리 최적화 - 필요할때만 String 생성됨)
    • 이후 서비스 커질 가능성 높음. 현재 모놀리식 기반이나, 기능 추가 시 멀티모듈도 가능하게 확장지점 마련
    • 테스트 커버리지 높히기
    • 외부 API 호출부에 들어간 암호화모듈때문에 checked exception 추가된 부분 상위 모듈로 전파안되게 처리
    • 외부 API 호출부 병목구간 확인을 위해 시간 로그 다양화.
    • 로그 저장 실패 시 파일로라도 내리기

      이제보니 객체지향 설계적인 리팩터링은 없네. 애초에 코드 구조 설계부터 하고 실제 코딩은 마지막에 하는편이라 그런 것 같긴 해.

     

      리팩터링 해서 잘했다고 생각한 부분은 외부 API 호출부 시간 로그를 다양하게 바꾼 부분이었어. API별로 실제 외부 API를 호출하기 이전까지 내부의 로직 시간, API 호출 후 응답이 오기까지의 시간, 응답을 받고 내부에서 처리에 걸린 시간 등 다양하게 로깅되도록 했어. 그리고 API 별로 N개의 하위 로그 형태로 외부 API 더라도 개별로도 확인할 수 있게 했지. 어느 부분이 병목지점인지 파악하기 정말 편했어.

     

      괜히 건드렸다 싶은건 내 입장에선 딱히 없는 것 같네. 이후 운영팀에선 이걸 왜 건드려놨어 했을수도 있지만 ㅋㅋ

     

     

    Q2. 더 우아한 디자인 해법으로 옮겨갈 타이밍은 어떻게 결정해?

    • 단순히 “돌아가니까 OK”보다는 “좀 더 구조적으로 리팩터링할 타이밍이다”라고 느끼는 기준은?
    • 어떤 상황에서 “이건 더 이상 이렇게 가면 안 된다”고 판단해?
    • 직관적으로 판단하는 편이야, 아니면 로그/성능/구조 등 어떤 지표를 가지고 판단해?

     

    내 답변

      다른 리팩터링 말고 구조적 리팩터리만 생각해볼께. 타이밍은 다음처럼 판단해볼 수 있을 것 같아. 이후 바뀔 수 있다고 예상되는 지점, 이후 제어권이 내게서 벗어났을 때 휴먼에러 발생 시 문제가 클 수 있는 지점. 그 외에도 직관적으로 깔끔하지 못하다고 생각되는 부분인 것 같네. 뭐 이론적으로 기준을 들자면 더 들 수 있겠지만, 대부분은 초기 설계 때 이미 고려되어 있어. 그러니 이후 리팩터링 대상은 개발하다보니 요구사항이 자주 변경되는 부분에 대한 리팩터링, 개발하다보니 이후 여긴 기능 더 추가되거나 변경 가능하겠는데? 싶은 부분이 주로 내가 리팩터링 하는 부분인 것 같아.

     

      제어권이 내게서 벗어났을 때 휴먼에러 발생 시 문제가 클 수 있는 지점도 마찬가지로, 실제 동작 자체엔 문제가 안돼. 다만 이후 운영팀으로 이관되었을 때, 잘못 손대면 안될만한 부분에 대한 안전장치를 말한거야. 예를들어 최근 프로젝트에서 고객의 정보를 담고 있는 Payload가 있었어. 백엔드 내부에서는 암호화가 풀린 상태로 쓰고 있지만, 네트워크 상에 나갈땐 무조건 암호화된 EncryptedPayload 형태로 나가야해. 우선 암호화에 대한 생성 책임을 Factory로 만들고, 패키지 형태나 접근 제어자를 적절히 사용해서 내가 원하지 않는 곳에서 사용하지 못하게 했어. 근데도 패키지 구조에 안맞게, 굳이 쓰겠다고 public으로 풀어버리거나 동일한 패키지 내에 클래스를 만들어서 억지로 사용할수도 있겠지. 그래서 ARCUnit으로 생성이 특정 클래스에서만 이루어질 수 있다는 제약을 테스트코드로 뒀어. 테스트코드까지 갈아엎을정도로 쓰고싶었다면, 이제 내 책임은 아닌거 같다고 생각했어 ㅋㅋ

     

      ‘이건 더 이상 이렇게 가면 안된다’ 이 부분은 항상 어려워. 코드 구조를 설계할 때 항상 생각하는 지점이야. 실제로도 일부러 타협해둔 부분도 많아. 예를들어 서비스 코드가 한 100개 있는데, 그 중에 하나만 길어. 근데 서비스 코드들 전부 비슷비슷하게 생겼는데, 얘만 길다고 구조를 바꿨을 때 이후 유지보수 하는 사람이 보기 더 편할까? 아니면 하나정돈 좀 길어도 코드 형태의 일관성을 맞춰두는게 좋을까? 이런 문제도 있지. 나 처음으로 개발자 관련 스터디할 때 스터디원이 “야그니”라는 말을 썼거든. 그게 뭔지 궁금해서 찾아보니 You Ain’t Gonna Need It 이더라고. 저 용어를 처음 들었다보니 기억에 많이 남아. 자연스레 짜면서 항상 되묻는편이야. 굳이 이거까지 해야할까? 정말 바뀔만한 부분이 맞을까? 가독성 너무 떨어지는거 아닐까? 오히려 싫어하지 않을까? 그런거지. 그래서 명확한 판단 기준은 없어. 그냥 현재 내가 가진 개발 지식 또는 현재 프로젝트에 대한 예상되는 상황에서 이 정도면 양심의 가책은 없겠는데? 싶은 정도까지만 처리하는 편이야.

     

      직전 답변에서도 말했듯이, 보통 플랫폼 서비스 초기 개발 후 1~2군데의 하위 이용기관 도입까지만 내가 운영하고 운영팀에 넘기는 식이야. 그러다보니 로그, 성능을 가지고 리팩토링하긴 힘들어. 오히려 이후 로그나 성능으로 문제가 될 시 이런식으로 처리하라는 식으로 문서화는 가끔씩 해두는 편이야. 예를들어 최근 통계관련 로직에서 이후 인덱스 걸만한 지점 써뒀어. 그러니 내 기준은 주로 ‘구조’적으로 직관적으로 판단한다가 더 맞겠네. 이후 예상되는 서비스의 크기를 가지고, 어느정도 수준 까지만 해두는 편인거지. 참고로 아까 말한 통계 부분은, 운영팀에 넘기기 전에 이미 사용량이 많아져서 3초 이상 걸려서, 넘기기 전에 리팩토링해서 1초 이내로 줄여뒀었어. 더 최적화도 가능하지만, 사실 하위 이용기관 담당자들이 가끔씩 보는거라 굳이 더 줄일 필요는 없다고 생각했어.

     

     

    Q3. ‘임시 해결책만큼 영구적인 것은 없다’ — 너도 그런 사례 많이 봤어?

    • 실제 경험한 임시방편 코드가 영구 구조물처럼 자리잡은 경우는?
    • 왜 그렇게 굳어졌다고 생각해?
    • 그런 사태를 미리 방지하거나 나중에라도 해결하기 위해 어떤 노력을 하고 있어?

     

    내 답변

      처음 개발자 시작했을 땐 파견 업체에서 시작했어. 즉 첫 프로젝트는 '프리'로 나간 셈이야. 거긴 전부 프리인 프로젝트인거지. 나도 웹쪽 지식 자체가 없고, 특히 프론트쪽은 아예 처음 해봤었거든. 그러다보니 PL급의 말을 철썩처럼 따랐지. 공통 라이브러리 형태의 js 함수들을 하나의 파일안에 전부 몰아두는 구조였어. 물론 js가 뭐 객체지향 언어라고 보긴 힘들지만, 그래도 결합도 얘기는 패러다임과 상관없는 얘기라 생각하니 계속 얘기해볼께.

     

      공통 함수가 자주 추가된건 아니지만, 아무튼 여러 개발자가 추가하다보니 꽤 파일 크기가 커지지. 결론적으로 몇만줄 이상의 거대한 무언가가 되었어. 너가 말한 ‘영구 구조물’이라 볼 수 있겠네. 짠 사람도 다 다르고, 특히나 객체지향 언어도 아니니깐 이게 어디까지 영향이 퍼져있는지도 모르지. 게다가 나나 대부분은 (대외적으론 대리인데 실제론) 신입 수준이고, 애초에 그 구조를 PL이 제시한거였잖아. 그러니 아무도 리팩토링 할 생각자체를 안한거지. 물론 나도 변명이긴한데, 솔직히 프론트 자체를 거의 처음해본거라, 감히 손 댈 생각 못했어 ㅋㅋ. 깨진 창문 이론에 따라, 이미 남들이 그렇게 짜고 있는 코드에서 혼자만 바꿔보는건 용기가 많이 필요하다고 생각해.

     

      얼마전에 본 MSA 관련 책에 이런 내용이 나와. ‘MSA 도입을 위해서는 팀원 전체의 상향 평준화가 필요하다’. 물론 PL 역할의 개발자가 충분한 설계 지식이 있다면, 팀이나 프로젝트의 규칙으로 정해서 미리 방지가 가능할꺼야. 그럼에도 해당 개발자도 놓치는 부분이 언제나 있을 수 있지. 결국 팀이나 사내의 문화 자체가 리팩토링에 열려있는 자세가 되는게 제일 중요할 것 같아. 일종의 문화처럼 서로 토론하면서 재밌게 할 수 있도록 말이야. 물론 초기부터 잘 잡는게 제일 좋겠지. 그러려면 PL 급도 중요하지만 팀원이나 사내의 문화 자체가 중요한 것 같아.

     

      물론 일정 압박 같은 외부적 요인도 영구 구조물을 만드는데 기여할 수 있어. 그치만 ‘어느정도의 선’ 까지는 솔직히 역량의 차이라고 봐. 일정같은 외부 요인이 변명이 될 순 없다고 봐. 예를들어 어느정도 역량이 있는 사람이 일정이 급하다고 if, else 루프가 한 100개 있는 함수를 짤까? 본인이 이해하기 힘들어서라도 그렇게 안하겠지. 오히려 그렇게 짜는게 더 시간이 많이 걸린다는걸 이미 알고 있는 사람일테니까. 로버트 C 마틴의 클린코드 책에서 나온 내용을 인용해볼께. “요구사항이 변했다고 불평, 일정이 촉박해 제대로 할 시간이 없었다고 한탄, 멍청한 관리자와 조급한 고객과 쓸모없는 마케팅 부서 탓이라 떠벌인다. 하지만 잘못은 전적으로 우리 프로그래머에게 있다. 우리가 전문가 답지 못했기 때문이다. 인정하기 어려울 것이다.”

     

      어떤 노력을 하고있냐고 하면 그건 대답이 좀 어렵네. 그냥 사내 세미나를 많이 해보려고 노력하고 있어. 예를들어 가장 최근에 진행한 세미나는 ‘왜 이렇게 코드를 짰을까? 제 코드의 선택과 이유들’ 라는 세미나였어. 내가 개발자 초기부터 짰던 코드 예시를 두고, 왜 그땐 그렇게 생각했고, 이런 부분은 반성한다. 또는 최근엔 이렇게 짰는데 이런 생각을 가지고 짜봤다. 이런 세미나였어. 그리고 하나 더 들어보자면 PR 올라온거에 대한 코드 리뷰를 단순 동작보다는 구조를 위주로 평가하는 편이야. 잘못된 동작은 의외로 빠르게 파악 가능한데, 구조적인 문제는 이후 알 수 없는 문제를 만들거든.

     

      최근 코드 리뷰 단 것 중 몇개 보면 다음과 같아. “postFiles() 과 중복된 역할 같습니다. 테스트용으로 쓰고 삭제 안하신 것 같슴다.”, “위에 적은 내용과 동일합니다. 리터럴이 바로 나와서 이후 운영할 때 헷갈릴 것 같습니다.”, “토큰 발행의 책임을 여기에서 가지는게 맞을지 생각해볼 필요가 있슴다.”

     

     

    Q4. 너도 이제 주니어 개발자에게 영향을 주는 위치에 있는 것 같아. ‘이 챕터를 주니어에게 어떻게 설명할래?’

    • 예를 들어, 신입 개발자가뭐라고 설명할 것 같아?
    • “리팩터링이 중요한 건 알겠는데, 뭐가 좋은 리팩터링이에요?”라고 물으면
    • 혹은 누군가가 실용성을 지나치게 강조하며너는 어떤 식으로 반론을 펼쳐?
    • “어차피 잘 돌아가잖아요”라고 말할 때,

     

    내 답변

      뭐가 좋은 리팩터링인진 오히려 내가 묻고싶네. 그냥 내 현재 지식 수준에 따라 매번 바뀌는 것 같아. 그러니 어떤게 좋은 리팩터링인가? 보다는 어떻게 리팩터링하는게 좋은가를 먼저 말해줄 것 같아. 보이스카우트 규칙이 기억하기도 좋고, 아주 좋은 규칙이라 생각해. 캠핑장에 처음 왔을 때보다 더 깨끗하게 하고 떠나라는 원칙이야. 코드에 접목해보자면, 코드를 처음 봤을 때보다 조금이라도 더 나은 상태로 남겨두라는 거지.

     

      뭐 이론적으로 따지면 뭐가 좋은 리팩터링인진 어느정도 나와 있긴 하지. 근데 그보다는 마인드가 중요하다고 생각해. 관심을 가지고 지식을 쌓아나간다면 리팩터링 실력은 오를꺼야. 하지만 리팩터링을 할 마음 자체가 없다면, 그건 방법이 없잖아? 그러니 우선 보이스카우트 법칙을 설명해주고, 사소한거 부터 지속적으로 해보라고 말할 것 같아. 뭐 변수명이 이게 더 낫지 않나요?, 인덴테이션 이거 한줄 더 띄우는게 보기 좋아보여요도 하나의 리팩터링이니까.

     

      ‘어차피 잘 돌아가잖아요’는 프로젝트의 생명주기에 대해 몰라서 하는 얘기라고 생각해. 초기 개발보다 유지보수 기간이 훨씬 길지. 물론 단건으로 돈받고 원하는걸 짜주는 프리거나, SI만 해왔다면 정말 모를수도 있다고 봐. 그치만 서비스를 만들고 본인 회사에서 계속 운영하는 형태라면, 이후 유지보수팀도 계속 봐야할꺼잖아. 얼굴 들고 다니는데 부끄러움은 없어야지 ㅋㅋ.

     

      뭐 이건 감성적인 측면이고, 반대로 생각해보면 사실 좀 애매하긴 해. 언제나 생각은 상대적인거잖아? 극단적으로 들어가보면 누군간 프레임워크를 쓰는 것 조차 실용성만 강조한거라고 할 수 있어. 모든 결합도는 무조건 인터페이스가 있어야 한다고 할 수 있어. 모든 프로젝트는 MSA로 구성되어야 한다고 할 수 있어. 프로젝트의 테스트 커버리지는 항상 100%를 유지해야 한다고도 할 수 있지.

    Q3의 답변에 있던 내 초기 개발자 생활에서, 난 “비즈니스 로직은 DB 프로시져에 있어야 한다” 라는 가르침을 받았어. 그게 배포 없이 프로시져만 갈아끼워도 로직을 바꿀 수 있다고 하면서. 어쨌든 대학교때 배운게 있어서, 아닐꺼라곤 생각했지만 뭐 Q3에서도 말했듯 내가 막 대놓고 반대하긴 쉽지 않았지. 아무튼 거기서 난 어느정도 비즈니스 로직을 프레임워크 안으로 가져왔어. 그들이 보았을 때 난 ‘실용성을 지나치게 강조하며 어차피 잘 돌아가잖아요’ 라고 말하는 사람이었을 수 있어.

     

      결국 답은 없어. 누군가에겐 내가 이전에 나한테 “비즈니스 로직이 프로시져에 있어야한다”라고 했던 사람처럼 보일 수 있다고 생각해. 애초에 내 지식이 완벽한게 아니고, 그건 모두가 마찬가지니까. 그러니 난 적극적으로 내 생각을 피력하는 타입은 아니야. 반대로 그럼 “이 부분에 기능 추가하려면 어떻게 해야할까요?” 이런식으로 역으로 생각하게 할 것 같아. 결국 중요한건 의견이 다르더라도, 명분과 팀의 합의라는 입장에서 그 실용성 논리가 팀 내에서 납득할 수 있느냐야. 여기서 단순히 ‘편하니까요’가 나오면 안되겠지. ‘이게 사실 이후에 A 기능 추가시엔 더 유리해요.’ 이런 설명이 가능하다면 얼마든지 수용 가능해.

    댓글