Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

Nonamed Develog

[TIL][240906] Troubleshooting 2: 중복된 코드의 냄새 본문

WHAT I LEARN/TIL

[TIL][240906] Troubleshooting 2: 중복된 코드의 냄새

노네임드개발자 2024. 9. 6. 20:25

1. 문제 인식: 중복된 코드의 냄새

처음에는 각각의 기능(회원가입, 로그인, 프로필 조회, 프로필 수정)에 맞춰 별도의 시리얼라이저를 만들었다. 아래는 그 첫 번째 코드이다.

class SignUpSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)
    
    class Meta:
        model = User
        fields = ['username', 'password', 'email', 'first_name', 'last_name', 'nickname', 'date_of_birth', 'gender', 'bio']

class SignInSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'email', 'first_name', 'last_name']

class ProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'email', 'first_name', 'last_name', 'nickname', 'date_of_birth', 'gender', 'bio']

class ProfileUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['email', 'first_name', 'last_name', 'nickname', 'date_of_birth', 'gender', 'bio']

 

처음 코드를 작성할 때는 필드 목록을 각각 정의하는 것이 문제가 없어 보였지만, 시간이 지남에 따라 공통된 필드가 반복적으로 정의되고 있다는 사실이 눈에 들어왔다. 특히 username, email, first_name, last_name과 같은 필드들이 여러 시리얼라이저에서 반복되면서 코드가 중복되고 있었다.

 

중복된 코드는 유지보수가 어려워지고, 버그가 발생할 가능성을 높이는 “코드 냄새”의 전형적인 예였다.


2. 리팩토링의 필요성: 효율성을 위한 상속 도입

코드를 개선하기 위한 다음 단계는, 공통된 부분을 하나의 부모 클래스에 모으고 필요한 시리얼라이저에서 이를 상속받는 구조로 바꾸는 것이었다. 여기서 등장한 것이 MyBaseSerializer이다. 이 시리얼라이저는 모든 시리얼라이저가 상속받는 기본 시리얼라이저로, 공통 필드를 한 곳에 정의해 중복을 줄였다.

class MyBaseSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'email', 'first_name', 'last_name']  # 공통 필드

class SignUpSerializer(MyBaseSerializer):
    password = serializers.CharField(write_only=True)

    class Meta(MyBaseSerializer.Meta):
        fields = MyBaseSerializer.Meta.fields + ['password', 'nickname', 'date_of_birth', 'gender', 'bio']

class SignInSerializer(MyBaseSerializer):
    class Meta(MyBaseSerializer.Meta):
        fields = MyBaseSerializer.Meta.fields

class ProfileSerializer(MyBaseSerializer):
    class Meta(MyBaseSerializer.Meta):
        fields = MyBaseSerializer.Meta.fields + ['nickname', 'date_of_birth', 'gender', 'bio']

class ProfileUpdateSerializer(MyBaseSerializer):
    class Meta(MyBaseSerializer.Meta):
        fields = ['email', 'first_name', 'last_name', 'nickname', 'date_of_birth', 'gender', 'bio']

 

 

MyBaseSerializer 도입: username, email, first_name, last_name과 같은 공통 필드를 MyBaseSerializer에 정의하고, 나머지 시리얼라이저는 필요한 필드를 추가하는 식으로 설계가 간소화되었다. 이로써 코드 중복이 눈에 띄게 줄어들었다.


3. to_representation 메서드 고민

리팩토링 과정에서, 시리얼라이저에서 반환할 때 특정 필드를 동적으로 수정할 필요가 있을지 고민이 있었다. 예를 들어, 프로필 조회 시 닉네임을 대문자로 변환하거나 데이터를 좀 더 동적으로 처리하는 방법으로 to_representation을 활용할 수 있다고 생각했다.

def to_representation(self, instance):
    representation = super().to_representation(instance)
    if 'nickname' in representation:
        representation['nickname'] = representation['nickname'].upper()
    return representation

 

 

아이디어: to_representation 메서드를 사용하면 반환되는 데이터를 조정할 수 있다는 점에서 유용해 보였다. 하지만, 이 메서드를 실제로 적용하려고 보니 필요 이상의 복잡성이 추가될 것 같았다. 단순한 필드 변환을 위해 메서드를 오버라이드하는 것보다는, 간단한 필드 추가와 수정으로도 충분히 문제를 해결할 수 있었다.


4. 결론: 상속으로 문제 해결, to_representation은 결국 사용하지 않음

결국, 상속을 통한 코드 중복 제거가 주요 개선점이 되었으며, to_representation을 사용하지 않아도 요구 사항을 충분히 충족할 수 있었다. MyBaseSerializer를 통해 공통 필드를 효율적으로 관리할 수 있었고, 추가적인 커스터마이징 없이도 필요한 데이터를 충분히 처리할 수 있었다.

  • 이전: 각 시리얼라이저에 중복된 필드들이 정의되어 유지보수와 관리가 어려웠다.
  • 이후: 공통 필드를 MyBaseSerializer로 묶어 중복을 제거하고, 복잡성을 추가하지 않으면서도 효율적인 설계를 할 수 있었다. to_representation은 결국 사용하지 않았다.

이 리팩토링 과정은 코드를 간결하고 효율적으로 유지하면서도, 불필요한 복잡성을 피하는 것이 얼마나 중요한지 깨닫는 과정이었다.