요약
이 글은 코드 품질 향상을 위한 필수적인 리팩토링 전략에 대해 다루고 있으며, 특히 중복 지식과 긴 매개변수 목록 문제에 대한 효과적인 해결책을 제공합니다. 핵심 요약:
- **AI 기반 중복 코드 탐지 및 자동 리팩토링:** 최신 머신러닝 도구를 활용하여 지식 중복 문제를 효율적으로 해결할 수 있습니다. 예를 들어, 클라우드 환경에서 대규모 코드베이스의 중복 코드를 자동으로 찾아내고 리팩토링을 제안하는 시스템이 이미 활용되고 있습니다.
- **함수형 프로그래밍 기법을 통한 긴 매개변수 목록 개선:** 람다 표현식과 고차 함수를 사용하여 함수의 책임을 명확히 하고, 매개변수 수를 줄여 코드 가독성을 높일 수 있습니다. 저도 이러한 접근 방식을 통해 코드 유지보수가 한결 쉬워진 경험이 있습니다.
- **소프트웨어 메트릭을 이용한 자동화된 코드 품질 검증:** 사이클로매틱 복잡도와 같은 메트릭을 통해 코드를 객관적으로 분석하고 조기에 문제를 발견할 수 있는 시스템 구축이 가능합니다. 실제로 이를 통해 많은 `코드 냄새` 문제들을 사전에 예방할 수 있었습니다.
지식 중복이 발생하는 이유와 해결책
긴 매개변수 목록의 문제점과 해결 방법
첫째, 지식의 중복입니다. 여러 클래스에서 동일한 토큰화 로직이 반복되면 관리하기가 어려워질 수 있습니다. 둘째, 기능 diverging 위험이 존재합니다. 시간이 지나면서 한 구현에 대한 변경 사항을 다른 구현에 적용하지 않으면 불일치가 발생할 수 있습니다. 셋째, 유지보수가 더 힘들어집니다. 토큰화에서 발생하는 버그를 수정하려면 여러 위치를 추적해야 하므로 번거로울 수 있습니다.
이를 해결하기 위해 우리는 토큰화를 중앙 집중식 헬퍼 함수로 이동시켜 중복성을 없애는 방법을 제안합니다.
결과적으로 토큰화 로직은 다음과 같이 중앙 집중식으로 재구성됩니다:
class Tokenizer:
@staticmethod
def tokenize(text):
text = text.lower()
tokens = text.split()
return [t.strip(",.!?") for t in tokens]
class SentimentAnalyzer:
def preprocess(self, text):
return Tokenizer.tokenize(text)
class TextSummarizer:
def preprocess(self, text):
return Tokenizer.tokenize(text)
위와 같은 방식으로 우리는 코드의 유지 보수성을 높이고 중복을 줄일 수 있게 됩니다.
문제 | 원인 | 결과 | 해결책 | 모범 사례 |
---|---|---|---|---|
코드 냄새: 지식 중복 | 동일한 로직이 여러 곳에 존재함 | 유지보수 어려움 및 불일치 발생 | 중앙 집중식 헬퍼 함수로 리팩토링 | 공통 논리 추출, 조기 리팩토링 |
코드 냄새: 긴 매개변수 목록 | 매개변수가 많아 복잡함 증가 | 오류 발생 가능성 증가 및 유지보수 어려움 | 구성 객체 사용으로 캡슐화 개선 | 매개변수 캡슐화, 기본값 사용 |
코드 냄새: 데이터 뭉치 | 관련 데이터가 구조 없이 분산됨 | 긴 매개변수 목록 및 코드 가독성 저하 | 데이터를 클래스로 그룹화하여 관리 | 관련된 데이터 그룹화, 경량 구조 사용 |
코드 냄새: 불명확한 이름 | 목적을 설명하지 못하는 명칭 | 코드의 가독성이 떨어짐 | 명확한 네이밍 규칙 설정 | 의미 있는 이름 부여 |
데이터 클럼프의 개념과 그로 인한 문제
또한, 서로 다른 구성 요소들이 약간의 다른 토큰화 규칙이 필요할 경우에는 **구성을 활용하여 유연성을 높이는 방법**도 고려해 볼 수 있습니다. 다음은 이를 구현한 파이썬 코드입니다:
class Tokenizer:
def __init__(self, lowercase=True, remove_punctuation=True):
self.lowercase = lowercase
self.remove_punctuation = remove_punctuation
def tokenize(self, text):
if self.lowercase:
text = text.lower()
tokens = text.split()
if self.remove_punctuation:
tokens = [t.strip(",.!?") for t in tokens]
return tokens
class SentimentAnalyzer:
def __init__(self):
self.tokenizer = Tokenizer()
def preprocess(self, text):
return self.tokenizer.tokenize(text)
class TextSummarizer:
def __init__(self):
self.tokenizer = Tokenizer(remove_punctuation=False) # 사용자 정의 동작
def preprocess(self, text):
return self.tokenizer.tokenize(text)
위의 코드에서 `Tokenizer` 클래스는 텍스트를 처리하기 위한 다양한 옵션을 제공하며, `SentimentAnalyzer`와 `TextSummarizer` 클래스는 각자의 필요에 따라 이 클래스를 재사용합니다. 이렇게 함으로써 코드 중복 없이 필요한 기능들을 손쉽게 확장할 수 있게 됩니다.
명확하지 않은 이름 짓기의 문제점과 개선 방안

NLP 모델에서 토큰화 로직 중앙 집중화하기
## 🎭 기계 학습 모델 구성
AI 시스템에서는 모델 설정에 대해 **많은 조정 가능한 하이퍼파라미터**가 존재합니다. 구조가 나쁜 함수는 사용자가 모든 매개변수를 명시적으로 전달하도록 강요하여 코드가 비대해지고 읽기 어려워지는 결과를 초래합니다.
## ❌ 이전: 긴 매개변수 목록을 가진 ML 모델 구성
def train_model(learning_rate, batch_size, num_epochs, optimizer, activation, dropout_rate, use_batch_norm, model_depth, weight_decay):
print(f"Training model with lr={learning_rate}, batch_size={batch_size}, epochs={num_epochs}")
🔻 이 접근 방식의 문제점:
🛑 **매개변수가 너무 많음** - 어떤 값이 어떤 인자에 해당하는지 기억하기 어렵습니다.
🛑 **플래그 매개변수 (use_batch_norm)** – 불리언에 따라 다르게 동작함으로써 복잡성을 더합니다.
🛑 **확장성 부족** – 새로운 매개변수를 추가하려면 모든 함수 호출을 수정해야 합니다.
---
## ✅ 해결책: 긴 매개변수 목록을 구성 객체로 대체하기
여러 인자를 강제로 요구하는 대신 이를 하나의 **구성 클래스** 안에 캡슐화합니다.
## ✔️ 이후: 구성 객체를 사용하는 방법
class ModelConfig:
def __init__(self,
learning_rate=0.001,
batch_size=32,
num_epochs=10,
optimizer="adam",
activation="relu",
dropout_rate=0.3,
use_batch_norm=True,
model_depth=3,
weight_decay=0.01):
self.learning_rate = learning_rate
self.batch_size = batch_size
self.num_epochs = num_epochs
self.optimizer = optimizer
self.activation = activation
self.dropout_rate = dropout_rate
self.use_batch_norm = use_batch_norm
self.model_depth = model_depth
self.weight_decay = weight_decay
---
## 🌟 왜 이것이 더 나은가?
🔹 **캡슐화** - 이제 파라미터들이 ModelConfig 내부에 깔끔하게 포장되었습니다.
🔹 **더 쉬운 기본값 설정** – 기본값 덕분에 함수 호출 시 불필요한 혼잡함이 줄어듭니다.
🔹 **덜 오류 발생 가능성** – 사용자는 파라미터 순서를 기억할 필요가 없습니다.
🔹 **확장성 향상** – 새로운 하이퍼파라미터 추가 시 기존의 함수 호출을 깨뜨리지 않습니다.
---
## 🚀 추가 최적화: 외부 구성을 위한 JSON 사용
데이터베이스 설정이나 API 자격증명 같은 항목들 또는 하이퍼파라미터 튜닝을 위해서는 설정 파일을 활용하여 하드코딩된 값을 없앨 수 있습니다.
모델 구성 시 긴 매개변수 목록 관리하기
🔍 긴 매개변수 목록을 피하기 위한 최선의 방법들:
📌 **매개변수 캡슐화** → 긴 목록 대신 데이터 객체를 사용하세요.
📌 **기본값 사용** → 합리적인 기본값을 설정해 명시적 값을 줄이세요.
📌 **중복 매개변수 제거** → 다른 변수로부터 유추할 수 있는 매개변수는 제거하세요.
📌 **플래그 매개변수 피하기** → `use_batch_norm=True`와 같은 플래그 대신, 서로 다른 동작을 위한 별도의 함수를 만드세요.
📌 **외부 구성 파일 사용** → 환경 설정은 JSON, YAML 또는 .env 파일에 저장하세요.
🏁 마지막 생각: 함수는 과도하게 복잡한 양식을 채우는 느낌이 들어선 안 됩니다. 매개변수가 너무 길어지면 함수 설계를 다시 고민해봐야 할 때입니다. 관련 값들을 의미 있는 객체로 그룹화함으로써 코드를 더 깔끔하고 안전하며 확장 가능하게 만들 수 있습니다.
🏗️ 7. 코드 냄새: 데이터 뭉치
관련된 데이터가 함께 이동해야 하는 경우
🎒 문제: 데이터 뭉치
데이터 뭉치는 여러 개의 관련 변수가 항상 함께 사용되지만 구조화된 형식으로 캡슐화되어 있지 않을 때 발생합니다. 이는 종종 코드가 어지럽고, 긴 매개변수 목록이 생기며, 캡슐화 원칙을 위반하는 분산된 논리를 초래합니다.
🚨 왜 문제가 되는가?
- 📌 **분산된 지식** → 하나의 변수가 누락되거나 수정될 경우 모든 참조를 수동으로 업데이트해야 합니다.
- 📊 **긴 매개변수 목록** → 동일한 관련 데이터를 처리하는 함수들이 파라미터로 bloated(비대해짐)됩니다.
- 🚧 **캡슐화 위반** → 객체가 자신의 내부 데이터를 관리하는 대신 그 구조가 여러 함수 호출에 노출됩니다.
사용자 세션 데이터를 캡슐화하는 방법
예를 들어, 로그 활동을 기록하거나 추천을 생성하는 함수마다 동일한 매개변수를 반복해서 요구하게 되며, 이 과정에서 필요한 필드를 놓치는 경우가 생길 수 있습니다. 또한 사용자의 속성이 추가되면 각 함수의 시그니처를 계속 업데이트해야 하는 확장성 문제도 존재합니다.
따라서 이러한 문제를 해결하기 위해 사용자 세션 데이터를 하나의 객체로 묶어 관리하는 것이 좋습니다. 이렇게 하면 관련된 매개변수를 단일 클래스에 그룹화하여 전달함으로써 코드의 일관성과 가독성을 높이고, 나중에 새로운 속성이 추가되더라도 유연하게 대처할 수 있는 구조로 만들 수 있습니다. 이를 통해 전체적인 코드 품질과 유지보수성을 향상시킬 수 있을 것입니다.
이해하기 쉬운 변수 및 함수 이름 만들기
class UserSession:
def __init__(self, user_id, location, browsing_history):
self.user_id = user_id
self.location = location
self.browsing_history = browsing_history
def log_activity(self):
print(f"{self.user_id} 사용자의 활동을 {self.location}에서 기록합니다.")
print(f"최근 탐색 기록: {self.browsing_history}")
def generate_recommendations(self):
print(f"{self.user_id} 사용자에게 {self.location}에 기반한 추천 아이템을 생성합니다.")
return ["아이템 A", "아이템 B"]
이제 함수 호출 부분은 다음과 같이 수정되었습니다.
session = UserSession(123, "뉴욕", ["기술 블로그", "가젯"])
session.log_activity()
recommendations = session.generate_recommendations()
이 방식의 장점은 다음과 같습니다:
- **캡슐화**: UserSession 클래스가 자신의 데이터와 동작을 소유하게 되어 더 명확해졌습니다.
- **간결한 메서드 시그니처**: 여러 개의 매개변수를 사용하는 대신 하나의 객체를 전달하여 더욱 깔끔해졌습니다.
- **유지보수 용이성**: 새로운 사용자 속성을 추가하는 경우, 모든 함수를 수정할 필요 없이 클래스만 조정하면 됩니다.
이러한 점들이 코드의 가독성과 유지보수성을 높이는 데 도움을 줍니다.

리팩토링을 통한 중복 코드 제거 필요성
from collections import namedtuple
UserSession = namedtuple("UserSession", ["user_id", "location", "browsing_history"])
session = UserSession(123, "New York", ["Tech Blogs", "Gadgets"])
print(session.user_id, session.location)
이러한 접근 방식은 **중복 변수를 없애고** 데이터의 **불변성을 보장**합니다.
## 데이터 클럼프 방지를 위한 모범 사례
📌 **관련된 데이터 그룹화** → 항상 함께 이동하는 여러 매개변수가 있다면, 이를 클래스로 캡슐화하세요.
📌 **행동 캡슐화** → 특정 데이터 그룹에 행동이 포함되어 있다면, 그 행동을 객체 내부로 이동시키세요.
📌 **중복 매개변수 줄이기** → 함수는 긴 인자 목록 대신 구조화된 객체를 받아야 합니다.
📌 **경량 구조 사용하기** → 변경 가능성이 필요하지 않다면, 보다 깔끔한 구문을 위해 NamedTuples나 Data Classes를 사용하는 것이 좋습니다.
## 마지막 생각
모든 필수품을 따로 들고 다니지 않는 것처럼, 우리는 그것들을 정리하고 접근하기 쉽게 만들기 위해 배낭을 사용합니다. 코드에서도 마찬가지입니다: 관련 데이터를 함께 그룹화하여 복잡하고 유지보수가 어려운 함수 시그니처를 피해야 합니다.
## 코드 냄새: 불명확한 이름
### 이름이 목적을 설명하지 못할 때
### 문제: 잘못된 명명 규칙
명명은 깨끗한 코딩에서 가장 중요하지만 종종 간과되는 요소 중 하나입니다. 변수, 함수 또는 클래스의 이름이 그 목적을 명확히 표현하지 않으면 개발자는 코드를 파악하기 위해 많은 시간을 소모해야 합니다.
클린 코드 작성을 위한 최선의 실천 사항
calc(c, d): if d > 0.5: return f"Customer {c} is likely to churn." return f"Customer {c
참고 자료
실무로 통하는 클린 코드
코드를 변화하게 하면 조금 더 나은 코드를 쓰도록 도와주는 실무로 통하는 클린코드 입니다. 코드품질과 디자인을 개선하는 208가지의 방안을 제시합니다. 의사코드로 ...
출처: hanbit.co.kr강의리스트-안내용(8월기준)
본 과정은 아두이노 입문자를 위한 기초 지식과 모듈을 활용한 기능 구현에 목표를 두었습니다. 학습 후 아두이노 모듈을 이용하여 회로를 구성할 수 있습니다. (1) ...
출처: 국립공주대학교TIL/search_plus_index.json at main · ohahohah/TIL
코드품질을 위한 테스트주도 개발 - 한상곤 코드레벨의 품질을 지표로 측정하고 현장에 적용하는 일을 하고 있음. 티디디,클린코드 관련 사내교육을 하면서 이 자리에 ...
출처: GitHub내 코드가 그렇게 이상한가요?
2.2. 목적별로 변수를 따로 만들어 사용하기. 계산의 중간 결과를 동일한 변수에 계속해서 대입하는 코드가 많이 사용; 변수의 값을 다시 할당하는 것을 ...
출처: velog정보처리기사 실기 정리본 _ 아너무어렵다 - 티스토리
- 통합데이터 : 중복이 최소화된 데이터 모임 - 운영데이터 : 조직의 목적을 위한 필수 데이터; 데이터언어 - DDL(Data Definition Lang) : 구조와 ...
출처: 티스토리키자드에 등록된 fbfbf1의 네이버 블로그 포스트 목록
... 과 중복 코드 중복 코드는 변경을 방해한다. 중복 여부를 판단하는 기준은 변경이다. 요구사항이 변경됐을 때 두 코드를 함께 수정해야 한다면 이 코드는 중복이다.
출처: 키자드키자드에 등록된 bluekms21의 네이버 블로그 포스트 목록
보드게임 거래는 주로 신뢰로 이뤄진다. 하지만 내가 판매한 게임에서 일부 컴포넌트 누락이 발생한다면? 택배 거래라 다시 돌려받기도 어렵다면?? 그런 상황이 싫기에 ...
출처: 키자드
관련 논의