코드 품질 향상을 위한 필수 리팩토링 전략: 중복 지식과 긴 매개변수 목록 해결법


요약

이 글은 코드 품질 향상을 위한 필수적인 리팩토링 전략에 대해 다루고 있으며, 특히 중복 지식과 긴 매개변수 목록 문제에 대한 효과적인 해결책을 제공합니다. 핵심 요약:

  • **AI 기반 중복 코드 탐지 및 자동 리팩토링:** 최신 머신러닝 도구를 활용하여 지식 중복 문제를 효율적으로 해결할 수 있습니다. 예를 들어, 클라우드 환경에서 대규모 코드베이스의 중복 코드를 자동으로 찾아내고 리팩토링을 제안하는 시스템이 이미 활용되고 있습니다.
  • **함수형 프로그래밍 기법을 통한 긴 매개변수 목록 개선:** 람다 표현식과 고차 함수를 사용하여 함수의 책임을 명확히 하고, 매개변수 수를 줄여 코드 가독성을 높일 수 있습니다. 저도 이러한 접근 방식을 통해 코드 유지보수가 한결 쉬워진 경험이 있습니다.
  • **소프트웨어 메트릭을 이용한 자동화된 코드 품질 검증:** 사이클로매틱 복잡도와 같은 메트릭을 통해 코드를 객관적으로 분석하고 조기에 문제를 발견할 수 있는 시스템 구축이 가능합니다. 실제로 이를 통해 많은 `코드 냄새` 문제들을 사전에 예방할 수 있었습니다.
본 기사를 통해 독자들은 최신 기술을 활용한 리팩토링 전략으로 소프트웨어 품질 향상의 길잡이를 얻을 것입니다.

지식 중복이 발생하는 이유와 해결책

## 🏗 ️ 5. 코드 냄새: 지식 중복 ## 동일한 로직이 코드베이스에 흩어져 있는 경우 ## 🧠 문제: 지식 중복 지식 중복은 **같은 로직, 알고리즘 또는 규칙**이 코드베이스의 여러 곳에 나타날 때 발생합니다. 이는 단순히 **중복된 코드**에 관한 것이 아니라, **중복된 지식**에 대한 문제입니다. 🚨 **왜 위험한가요?** - 🔍 **흩어진 로직** → 한 인스턴스를 업데이트한다고 해서 다른 곳도 반드시 업데이트되는 것은 아닙니다. - 📉 **다양화된 행동** → 시간이 지나면서 서로 다른 장소의 유사한 로직이 지역적인 수정으로 인해 **서로 다르게 발전할 수 있습니다**. - 🔄 **유지보수 악몽** → 변경 사항을 여러 파일이나 모듈에서 추적해야 하므로 어려움이 커집니다. 모든 유사 코드를 병합할 필요는 없습니다. 두 섹션의 코드가 서로 다른 지식을 나타낸다면 분리되어 있어야 합니다. 그러나 만약 **동일한 비즈니스 로직이 여러 파일에 흩어져 있다면**, 리팩토링이 필수적입니다. ---## 🎭 NLP 모델에서의 토큰화 자연어 처리(NLP) 파이프라인을 상상해 보세요. 이곳에서는 여러 구성 요소가 텍스트를 처리하기 전에 반드시 **토큰화 작업을 수행해야 합니다**. 만약 각 구성 요소가 각각의 토큰화 로직을 구현한다면, 불일치와 유지보수 문제들이 발생하게 됩니다.

긴 매개변수 목록의 문제점과 해결 방법

코드에서 여러 곳에 중복된 토큰화 로직이 존재합니다. 예를 들어, 감정 분석기 클래스의 전처리 메서드는 텍스트를 소문자로 변환한 후 공백으로 나누고 구두점을 제거하는 과정을 포함하고 있습니다. 이러한 접근 방식은 몇 가지 문제를 야기할 수 있습니다.

첫째, 지식의 중복입니다. 여러 클래스에서 동일한 토큰화 로직이 반복되면 관리하기가 어려워질 수 있습니다. 둘째, 기능 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` 클래스는 각자의 필요에 따라 이 클래스를 재사용합니다. 이렇게 함으로써 코드 중복 없이 필요한 기능들을 손쉽게 확장할 수 있게 됩니다.

명확하지 않은 이름 짓기의 문제점과 개선 방안

다양한 구성 요소들이 **공유된 논리를 재사용하면서도** **토큰화 동작을 맞춤 설정할 수 있습니다**. ---## 🔍 지식 중복을 피하기 위한 모범 사례📌 **공통 논리 추출 → 자주 사용되는 논리를 도우미 함수나 유틸리티 클래스로 이동시키세요. 📌 **구성 및 상수 중앙 집중화 → 매직 넘버와 설정 값을 코드베이스에 흩어지게 하지 마세요. 📌 **상속보다 조합 사용 → 관련 없는 클래스 간의 행동을 공유하기 위해 조합을 선호하세요. 📌 **조기 리팩토링 → 같은 논리를 두 번 복사 붙여넣기 했다면, 즉시 리팩토링하는 것을 고려해보세요. ---## 🏁 최종 생각코드를 작성하는 것은 두 개의 다른 책에서 **같은 이야기를 쓰는 것과 같습니다**. 지식이 중복되면 불필요한 복잡성과 일관성 결여, 유지 보수 부담이 발생합니다. 이러한 중복이 증가하지 않도록, 코드를 DRY(중복 금지) 원칙에 따라 리팩토링하여 지식을 중앙 집중화하고 유지 관리하기 쉽게 하세요. ## 🏗️ 6.코드 냄새: 긴 매개변수 목록## 너무 많은 매개변수가 함수를 사용하기 어렵게 만들 때## ⚖️ 문제: 긴 매개변수 목록매개변수가 너무 많은 메서드는 읽기, 유지 관리 및 올바르게 사용하는 데 어려움을 겪습니다. 함수는 **단순하고 직관적이어야 하지만**, 긴 매개변수 목록은 **복잡성과 혼란을 초래합니다**.


명확하지 않은 이름 짓기의 문제점과 개선 방안 Free Images


NLP 모델에서 토큰화 로직 중앙 집중화하기

이 문제는 여러 측면에서 고려할 수 있습니다. 첫째, 매개변수가 변화할 경우, 여러 함수 호출에 걸쳐 업데이트해야 하므로 유지 관리가 어려워집니다. 둘째, 매개변수를 잘못된 순서로 전달하면 기능이 쉽게 고장날 수 있어 오류의 원인이 됩니다. 셋째, 중간 매개변수를 선택 사항으로 만들기란 많은 프로그래밍 언어에서 복잡한 작업이 될 수 있습니다. 넷째, 불리언 플래그에 따라 다르게 작동하는 함수는 명확성이 떨어지므로 별도의 함수로 분리하는 것이 좋습니다. 예를 들어, **30가지 재료를 특정 순서로 조합해야 하는 레시피**를 생각해보세요. 한 가지 실수라도 요리를 망칠 수 있습니다. 따라서 함수는 **논리적으로 그룹화된 모든 재료들이 잘 정리된 레시피처럼 설계되어야 합니다.**

## 🎭 기계 학습 모델 구성

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 자격증명 같은 항목들 또는 하이퍼파라미터 튜닝을 위해서는 설정 파일을 활용하여 하드코딩된 값을 없앨 수 있습니다.

모델 구성 시 긴 매개변수 목록 관리하기

모델 설정을 JSON 파일에서 로드하는 방법에 대한 예시입니다. 이 코드는 매개변수를 중앙 집중화하여 코드 수정 없이도 업데이트할 수 있게 합니다.

🔍 긴 매개변수 목록을 피하기 위한 최선의 방법들:
📌 **매개변수 캡슐화** → 긴 목록 대신 데이터 객체를 사용하세요.
📌 **기본값 사용** → 합리적인 기본값을 설정해 명시적 값을 줄이세요.
📌 **중복 매개변수 제거** → 다른 변수로부터 유추할 수 있는 매개변수는 제거하세요.
📌 **플래그 매개변수 피하기** → `use_batch_norm=True`와 같은 플래그 대신, 서로 다른 동작을 위한 별도의 함수를 만드세요.
📌 **외부 구성 파일 사용** → 환경 설정은 JSON, YAML 또는 .env 파일에 저장하세요.

🏁 마지막 생각: 함수는 과도하게 복잡한 양식을 채우는 느낌이 들어선 안 됩니다. 매개변수가 너무 길어지면 함수 설계를 다시 고민해봐야 할 때입니다. 관련 값들을 의미 있는 객체로 그룹화함으로써 코드를 더 깔끔하고 안전하며 확장 가능하게 만들 수 있습니다.

🏗️ 7. 코드 냄새: 데이터 뭉치
관련된 데이터가 함께 이동해야 하는 경우

🎒 문제: 데이터 뭉치
데이터 뭉치는 여러 개의 관련 변수가 항상 함께 사용되지만 구조화된 형식으로 캡슐화되어 있지 않을 때 발생합니다. 이는 종종 코드가 어지럽고, 긴 매개변수 목록이 생기며, 캡슐화 원칙을 위반하는 분산된 논리를 초래합니다.

🚨 왜 문제가 되는가?
- 📌 **분산된 지식** → 하나의 변수가 누락되거나 수정될 경우 모든 참조를 수동으로 업데이트해야 합니다.
- 📊 **긴 매개변수 목록** → 동일한 관련 데이터를 처리하는 함수들이 파라미터로 bloated(비대해짐)됩니다.
- 🚧 **캡슐화 위반** → 객체가 자신의 내부 데이터를 관리하는 대신 그 구조가 여러 함수 호출에 노출됩니다.

사용자 세션 데이터를 캡슐화하는 방법

사용자 정보를 캡슐화하여 AI 기반 추천 시스템의 효율성을 높일 수 있습니다. 예를 들어, 사용자의 ID, 위치 및 브라우징 기록과 같은 정보는 여러 기능에서 필요합니다. 이전 방식에서는 이러한 관련 데이터를 각각 처리하는 방법이었으나, 이로 인해 여러 가지 문제가 발생할 수 있습니다.

예를 들어, 로그 활동을 기록하거나 추천을 생성하는 함수마다 동일한 매개변수를 반복해서 요구하게 되며, 이 과정에서 필요한 필드를 놓치는 경우가 생길 수 있습니다. 또한 사용자의 속성이 추가되면 각 함수의 시그니처를 계속 업데이트해야 하는 확장성 문제도 존재합니다.

따라서 이러한 문제를 해결하기 위해 사용자 세션 데이터를 하나의 객체로 묶어 관리하는 것이 좋습니다. 이렇게 하면 관련된 매개변수를 단일 클래스에 그룹화하여 전달함으로써 코드의 일관성과 가독성을 높이고, 나중에 새로운 속성이 추가되더라도 유연하게 대처할 수 있는 구조로 만들 수 있습니다. 이를 통해 전체적인 코드 품질과 유지보수성을 향상시킬 수 있을 것입니다.

이해하기 쉬운 변수 및 함수 이름 만들기

사용자 세션 객체를 활용한 개선된 코드 예시입니다.

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 클래스가 자신의 데이터와 동작을 소유하게 되어 더 명확해졌습니다.
- **간결한 메서드 시그니처**: 여러 개의 매개변수를 사용하는 대신 하나의 객체를 전달하여 더욱 깔끔해졌습니다.
- **유지보수 용이성**: 새로운 사용자 속성을 추가하는 경우, 모든 함수를 수정할 필요 없이 클래스만 조정하면 됩니다.

이러한 점들이 코드의 가독성과 유지보수성을 높이는 데 도움을 줍니다.
이해하기 쉬운 변수 및 함수 이름 만들기

리팩토링을 통한 중복 코드 제거 필요성

경량 데이터를 다루기 위해, Python의 `namedtuple`을 사용하여 더 깔끔하고 불변적인 대안을 제공할 수 있습니다. 예를 들어, 아래와 같이 사용할 수 있습니다.

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를 사용하는 것이 좋습니다.

## 마지막 생각

모든 필수품을 따로 들고 다니지 않는 것처럼, 우리는 그것들을 정리하고 접근하기 쉽게 만들기 위해 배낭을 사용합니다. 코드에서도 마찬가지입니다: 관련 데이터를 함께 그룹화하여 복잡하고 유지보수가 어려운 함수 시그니처를 피해야 합니다.

## 코드 냄새: 불명확한 이름

### 이름이 목적을 설명하지 못할 때

### 문제: 잘못된 명명 규칙

명명은 깨끗한 코딩에서 가장 중요하지만 종종 간과되는 요소 중 하나입니다. 변수, 함수 또는 클래스의 이름이 그 목적을 명확히 표현하지 않으면 개발자는 코드를 파악하기 위해 많은 시간을 소모해야 합니다.

클린 코드 작성을 위한 최선의 실천 사항

🚨 **문제의 원인** - 🔎 **코드가 불명확해짐** → 만약 이름이 그 기능을 설명하지 않으면, 매번 **추가적인 정신적 노력**이 필요합니다. - 🏗️ **유지보수가 어려워짐** → 코드 가독성이 떨어져 디버깅과 리팩토링이 **더 힘들어집니다**. - 🕵️ **맥락 상실** → 변수가 선언된 곳과 멀리 사용될 경우 그 의미가 **흐려집니다**. > _**예시:** 파일명을 `"Stuff_1"`와 `"Stuff_2"`로 짓는 대신 `"Invoices"`와 `"Receipts"`로 지으면, 내부에 무엇이 있는지 아무도 모릅니다!_---## 🎭 머신러닝 모델에서의 나쁜 네이밍 예제AI 모델이 고객 정보를 처리하여 **고객 이탈률 예측**을 하는 상황을 상상해 보세요. 잘못된 변수 이름은 코드에서 실제로 무슨 일이 일어나고 있는지를 감추게 됩니다. ## ❌ 이전: ML 처리에서 불명확한 변수 이름
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의 네이버 블로그 포스트 목록

보드게임 거래는 주로 신뢰로 이뤄진다. 하지만 내가 판매한 게임에서 일부 컴포넌트 누락이 발생한다면? 택배 거래라 다시 돌려받기도 어렵다면?? 그런 상황이 싫기에 ...

출처: 키자드

칼럼니스트

전문가

관련 논의