좋음은 상대적이다.

‘좋다’라는 말은 흔히 쓰이지만, 막상 그 의미를 정의하려 하면 쉽지 않다. 무엇이 좋은지를 묻는 순간, 우리는 왜 그렇게 느끼는지, 그 판단의 이유를 고민하게 된다. 좋음은 절대적인 가치가 아니라, 상황과 맥락, 개인의 관점에 따라 달라지는 상대적 감정이기 때문이다.

예를 들어 커피 한 잔, 음식, 운동 같은 일상적인 선택을 떠올려보자. 어떤 사람에게는 최상의 선택이 될 수 있지만, 다른 사람에게는 불편하거나 부담스러운 선택일 수 있다.

결국 ‘좋다’는 판단은 개인의 경험, 목적, 환경에 따라 달라지며, 모두에게 좋은 것은 존재하지 않는다. 좋음은 특정한 맥락 안에서만 의미를 갖는, 감정적 판단인 셈이다.

이런 사고를 코드에 적용해보면 어떨까? 좋은 코드란 무엇인가라는 질문은, 좋은 커피나 음식이 무엇인가를 묻는 것과 다를 바 없다. 상황과 목적에 따라 달라질 수밖에 없다는 것이다.

좋은 코드란 무엇인가?

우리는 흔히 가독성, 일관성, 유지보수 용이성 같은 기준을 좋은 코드의 핵심으로 꼽는다. SOLID, 높은 응집도·낮은 결합도, 추상화 등도 대표적인 기법이다. 물론 유효한 원칙들이다. 하지만 “항상” 좋은가? 맥락을 벗어나면 원칙은 종종 비용이 된다.

예를 들어, 팀의 의사결정을 돕기 위한 게임 MVP를 빠르게 만들어야 한다고 하자. 이때 좋은 코드는 “지금 목적에 가장 빨리 도달하게 하는 코드”다. 동작하는 결과가 최우선이며, 과도한 설계나 레이어 분리는 ROI가 낮다. 일관성·응집도·결합도 같은 품질 기준은 장기 운영을 전제로 가치를 갖는다. 반면 단발성 실험에서는 구현 집중이 더 합리적일 수 있다.

반대로 간단한 페이지라도 로직이 다양하다면 어떨까? API 호출, 응답 변환 유틸, 파싱 함수, UI 마크업, A/B 테스트 분기가 뒤섞여 있다면, 다음과 같은 레이어링이 유지보수에 도움이 된다:

e.g) API Layer ← Model Layer ← Business Component Layer ← UI Component Layer

역할을 분리하면 변경 영향 범위가 좁아지고, 응집도는 올라가며 결합도는 내려간다. 하지만 항상 장점만 있는 것은 아니다.

  1. 비용: 추상화는 공짜가 아니다. 구현이 숨겨지면 추적 난이도가 올라가고, 구조를 모르는 사람에게는 학습 비용이 크다.

  2. 오버 엔지니어링: 네 단계로 쪼갰지만, 실제로는 하나로 합쳐도 충분히 단순할 수 있다. 작은 기능에 과도한 레이어링은 유지보수 시간을 오히려 늘린다.

  3. 경계 모호성: 경계가 모호한 요소(예: 상수 같은 함수)에서 어디에 두어야 할지 결정 비용이 생긴다.

이런 선택은 사고 자원을 소모한다. 간단한 페이지처럼 복잡도가 낮은 기능이라면 한 파일에 모으는 편이 개발·파악 모두 더 빠를 수 있다. 결합도가 높아지고 길이가 늘어날 위험은 있지만, 복잡도가 낮은 맥락에서는 “한눈에 파악되는 코드"가 오히려 가독성 이점이 된다.

좋은 코드는 ‘형태’가 아니다.

그렇다면 좋은 코드란 무엇일까? 결론적으로, 좋은 코드는 고정된 ‘형태’가 아니다. 멘탈 모델이다. 애초에 ‘좋다’라는 개념이 들어간 이상, 그것을 구체적인 형태로 규정할 수는 없다. ‘좋음’은 고정된 사실이 아니라 상대적인 영역이기 때문이다.

따라서 특정 특징을 몇 가지 갖췄다고 해서 좋은 코드로 합격·불합격을 판정할 수 없다. 좋은 코드는 현재 목적과 맥락 속에서 자연스럽게 만들어진다. 어떤 순간엔 가독성이, 다른 순간엔 성능이, 또 다른 순간엔 낮은 결합도가 최선이다. 때로는 명시적 의존성이 의도를 더 분명히 드러낸다.

핵심은 “일반적으로 좋은 패턴”을 기계적으로 따르지 않는 것이다. 유연한 판단 능력이 바로 좋은 코드를 만드는 힘이다. 다음 코드를 작성할 때 “이 상황에 적합한가?“를 스스로에게 물어보자.