Post

소프트웨어 3대 원칙(DRY · KISS · YAGNI)

중복 제거(DRY), 단순성(KISS), 필요하지 않으면 만들지 말라(YAGNI). 실무 예시와 안티패턴, 체크리스트까지.

소프트웨어 3대 원칙(DRY · KISS · YAGNI)

요약

  • DRY (Don’t Repeat Yourself) — 중복을 제거하라. 같은 지식(비즈니스 규칙, 로직, 상수 등)이 여러 곳에 퍼지지 않게 하라.
  • KISS (Keep It Simple, Stupid) — 단순하게 설계하라. 불필요한 복잡성은 피하라.
  • YAGNI (You Aren’t Gonna Need It) — 필요하지 않은 기능은 미리 만들지 마라. “혹시 쓰일까”는 대부분 시간 낭비다.

1) DRY — Don’t Repeat Yourself (중복 금지)

핵심

같은 정보를 여러 곳에 두지 말자. 변경 지점이 하나여야 유지보수가 쉽다.

예시 (안티패턴)

1
2
3
4
5
6
7
// 중복된 처리: 수정 시 모든 곳을 바꿔야 함
function priceWithTaxA(price) {
  return price + price * 0.1;
}
function priceWithTaxB(price) {
  return price + price * 0.1;
}

개선

1
2
3
4
const TAX_RATE = 0.1;
function priceWithTax(price) {
  return price + price * TAX_RATE;
}

주의할 점

  • 너무 작은 중복까지 무조건 합치면 오히려 추상화가 과해짐. 의미적으로 같은 중복인지(의도와 규칙이 동일한지)를 판단하자.
  • 공통 모듈을 만들 때 결합도가 높아지지 않도록 신경쓰기.

2) KISS — Keep It Simple, Stupid (단순하게)

핵심

설계와 코드에서 불필요한 복잡성을 제거하자. 단순한 것이 버그가 적고 이해하기 쉽다.

예시 (안티패턴)

  • 복잡한 한 함수가 여러 역할(입력 검증, 비즈니스 로직, DB처리)을 모두 수행하는 경우
  • 지나치게 일반화된 추상화로 인해 오히려 사용이 어려워진 API

개선 원칙

  • 함수는 한 가지 일만 하게 설계(FSR — single responsibility).
  • 명확한 이름과 작은 함수.
  • 복잡한 로직은 단계별로 나누고 주석으로 의도 설명.

실무 팁

  • 리팩터링 후 테스트를 작성해 단순화가 기능을 깨지 않았는지 확인하라.
  • 코드 리뷰에서 “이걸 더 간단히 못하나?”라는 질문을 자주 던져라.

3) YAGNI — You Aren’t Gonna Need It (미래는 미리 만들지 마라)

핵심

미래에 필요할 것 같다는 이유만으로 기능을 미리 만들지 마라. 실제 요구가 생겼을 때 그때 구현하는 것이 비용 대비 효율적이다.

예시 (안티패턴)

  • “나중에 멀티테넌시가 필요할지도 모르니”라며 지금부터 모든 코드에 테넌트 추상화 적용
  • 미리 만든 복잡한 설정 파서나 플러그인 시스템 (실제로는 단일 설정으로 충분)

개선

  • 실제 요구(요청 수, 클라이언트 요청 등)가 확인되기 전까지 단순하게 유지.
  • 확장 포인트는 남기되(확장 가능하게), 구체적 구현은 요구가 왔을 때 추가.

주의

  • YAGNI를 남용하면 반복적으로 비슷한 코드가 여러 곳에 생길 수 있음 → DRY와 균형 필요.
  • 도메인 규칙이 불변으로 보이면 미리 정리해 둘 필요가 있다(예: 결제 규칙).

실무에서 세 원칙의 균형 잡기

이 세 원칙은 서로 보완적이지만 때론 충돌하기도 합니다.

  • DRY vs YAGNI: 중복 제거를 위해 추상화하면, 그 추상화가 ‘미래 요구’를 위한 과잉설계가 될 수 있다. → 기준: 추상화는 현재의 여러 중복 지점을 해결할 때만 도입하라. “혹시 나중에”를 위해 추상화하지 마라.

  • KISS vs DRY: 단순성을 위해 중복을 허용할 수도 있다(특히 아주 작은 스코프일 때). → 기준: 중복이 버그 위험을 높이거나 변경 비용을 키우면 DRY 적용.


체크리스트 (코드 리뷰용)

  • 이 변경이 중복을 야기하나? → DRY 적용 고려
  • 더 단순하게 만들 수 없나? → KISS 우선
  • 지금 당장 필요한가? → YAGNI 적용 가능성 검토
  • 테스트가 충분한가? 리팩토링 후 테스트로 보호되는가?

짧은 예시 플로우 (의사결정)

  1. 새로운 요구가 왔다.
  2. 기존 코드와 겹치는가? → 겹치면 재사용/공통 함수로 모아라(DRY).
  3. 추상화할 경우 복잡도가 급증하는가? → 그렇다면 단순하게 먼저 구현(KISS).
  4. 기능을 예측해서 미리 설계할 필요가 있는가? → 아니면 YAGNI로 보류.

마무리

  • DRY, KISS, YAGNI는 서로 보완하면서도 상황에 따라 트레이드오프가 필요합니다.
  • 규칙을 경전처럼 맹목적으로 따르기보단 “왜”라는 질문을 던지면서 균형 있게 적용하는 것이 핵심입니다.
This post is licensed under CC BY 4.0 by the author.