프로그래밍 언어와 서비스 형태에 상관없이 중요한 리팩터링 원칙
리팩터링은 단순히 코드를 짧게 만드는 작업이 아닙니다. 기존 기능은 유지하면서 코드의 구조를 더 이해하기 쉽고, 수정하기 쉽고, 확장하기 좋게 개선하는 작업입니다.
Java, Python, JavaScript 같은 프로그래밍 언어가 달라도, 웹 서비스나 데이터 분석 프로그램처럼 서비스 형태가 달라도 공통적으로 적용할 수 있는 중요한 원칙들이 있습니다.
대표적인 원칙이 SRP, DRY, Rule of Three, KISS, YAGNI, SoC, Meaningful Naming입니다.
● SRP (Single Responsibility Principle) - 단일 책임의 원칙
SRP는 하나의 함수, 클래스, 모듈이 하나의 책임에 집중하도록 만드는 원칙입니다.
예를 들어 하나의 함수가 데이터를 조회하고, 계산하고, 파일로 저장하고, 이메일까지 전송한다면 너무 많은 역할을 담당하고 있는 것입니다.
이런 경우에는 데이터 조회, 계산, 저장, 전송 기능을 적절하게 나누는 것이 좋습니다.
핵심은 하나의 코드가 너무 많은 일을 하지 않도록 한다는 것입니다.
● DRY (Don't Repeat Yourself) - 중복하지 말 것
DRY는 같은 코드나 같은 업무 규칙을 여러 곳에서 반복하지 않는다는 원칙입니다.
동일한 계산이나 검증 로직이 여러 파일에 복사되어 있으면, 나중에 규칙이 변경될 때 모든 부분을 찾아 수정해야 합니다.
따라서 정말 동일한 로직이 반복된다면 공통 함수나 모듈로 분리해서 재사용하는 것이 좋습니다.
핵심은 같은 지식이나 규칙이 여러 곳에 중복되지 않도록 한다는 것입니다.
● Rule of Three - 섣부른 추상화를 하지 말 것
DRY를 너무 적극적으로 적용하면 오히려 코드가 복잡해질 수 있습니다.
비슷한 코드가 두 번 등장했다고 바로 공통 함수나 복잡한 구조를 만드는 것이 항상 좋은 것은 아닙니다. 처음에는 비슷해 보여도 시간이 지나면서 서로 다른 기능으로 발전할 수도 있기 때문입니다.
Rule of Three는 비슷한 코드가 어느 정도 반복되는 것이 확인된 후에 공통화를 검토하자는 원칙입니다.
쉽게 말하면, 첫 번째는 작성하고, 두 번째는 관찰하고, 세 번째쯤 반복되면 추상화를 검토한다 정도로 이해하면 됩니다.
핵심은 “중복을 없애겠다고 너무 빨리 복잡한 구조를 만들지 않는다”는 것입니다.
● KISS (Keep It Simple, Stupid) - 단순하게 유지할 것
KISS는 같은 문제를 해결할 수 있다면 가능한 한 단순하고 이해하기 쉬운 방법을 선택하자는 원칙입니다.
단순한 조건문 몇 개로 해결할 수 있는 문제를 굳이 복잡한 디자인 패턴이나 여러 단계의 추상화로 만들 필요는 없습니다.
복잡한 코드는 처음에는 멋있어 보일 수 있지만, 나중에 다른 사람이 이해하고 수정하기 어려워질 수 있습니다.
핵심은 “필요 이상으로 복잡하게 만들지 않는다”는 것입니다.
● YAGNI (You Ain't Gonna Need It) - 당장 필요하지 않은 기능은 미리 만들지 말 것
개발하다 보면 다음과 같은 생각을 하기 쉽습니다.
“나중에 이런 기능이 필요할 수도 있으니까 미리 만들어 두자.”
하지만 실제로는 사용되지 않는 기능도 많고, 미래를 예상해서 만든 코드 때문에 현재 시스템이 더 복잡해지는 경우도 많습니다.
YAGNI는 지금 실제로 필요한 기능부터 구현하고, 새로운 요구사항이 생겼을 때 추가하자는 원칙입니다.
핵심은 “언젠가 필요할 것 같은 기능보다 지금 필요한 기능에 집중한다”는 것입니다.
● SoC (Separation of Concerns) - 관심사를 분리할 것
SoC는 서로 다른 목적이나 역할을 가진 기능을 적절하게 분리하는 원칙입니다.
예를 들어 하나의 프로그램에서 화면 표시, 업무 처리, 데이터 저장, 외부 API 통신을 모두 한곳에 작성하면 수정하기 어려워집니다.
각각의 관심사를 적절하게 나누면 특정 기능을 변경했을 때 다른 부분에 미치는 영향을 줄일 수 있습니다.
SRP와 비슷하지만, SRP가 하나의 함수나 클래스의 책임에 초점을 맞춘다면 SoC는 프로그램이나 시스템 전체에서 서로 다른 관심 영역을 분리하는 것에 더 가깝습니다.
핵심은 “성격이 다른 기능을 한곳에 섞지 않는다”는 것입니다.
● Meaningful Naming - 식별 가능한 이름 짓기
좋은 코드는 변수나 함수의 이름만 봐도 어느 정도 역할을 이해할 수 있어야 합니다.
예를 들어 다음과 같은 이름은 의미를 이해하기 어렵습니다.
a
data
temp
func1
반면 다음과 같은 이름은 역할을 쉽게 파악할 수 있습니다.
userCount
totalPrice
calculateTax
findUserById
Meaningful Naming은 변수, 함수, 클래스 등의 이름을 보고 무엇을 위한 코드인지 식별할 수 있도록 작성하는 것입니다.
핵심은 “이름만 보고도 코드의 역할을 어느 정도 이해할 수 있게 한다”는 것입니다.
● 7가지 원칙을 간단하게 정리하면
SRP → 하나의 코드에는 하나의 책임을 부여한다.
DRY → 같은 코드와 규칙을 반복하지 않는다.
Rule of Three → 중복을 없애겠다고 섣불리 추상화하지 않는다.
KISS → 가능한 한 단순하게 만든다.
YAGNI → 지금 필요하지 않은 기능은 미리 만들지 않는다.
SoC → 서로 다른 관심사와 역할을 분리한다.
Meaningful Naming → 이름만 보고도 역할을 식별할 수 있게 작성한다.
● 중요한 것은 원칙을 무조건 적용하는 것이 아니다
이 원칙들은 절대적인 규칙이라기보다 코드를 개선할 때 판단 기준으로 사용하는 원칙입니다.
예를 들어 DRY를 지나치게 강조하면 필요 이상으로 추상화될 수 있고, SRP를 너무 세밀하게 적용하면 클래스와 함수가 지나치게 많아질 수도 있습니다.
따라서 실제 리팩터링에서는 여러 원칙을 함께 고려해야 합니다.
중복인가? → DRY
공통화하기에는 아직 이른가? → Rule of Three
너무 복잡한가? → KISS
정말 필요한 기능인가? → YAGNI
책임이 너무 많은가? → SRP
서로 다른 기능이 섞여 있는가? → SoC
이름만 보고 역할을 알 수 있는가? → Meaningful Naming
이런 식으로 질문하면서 코드를 살펴보면 좋습니다.
● 한 문장으로 정리
좋은 리팩터링은 코드를 무조건 짧게 만들거나 복잡한 구조로 바꾸는 것이 아니라, 중복과 복잡성을 줄이고 책임과 역할을 명확하게 만들어 사람이 이해하고 수정하기 쉬운 코드로 개선하는 작업입니다. 그리고 SRP, DRY, Rule of Three, KISS, YAGNI, SoC, Meaningful Naming은 프로그래밍 언어나 서비스 형태에 관계없이 이러한 판단을 도와주는 중요한 기본 원칙입니다.