Refactoring Massive Python/Django App

Nicholas An
2 min readMay 17, 2021

--

So far, I have been working on the company’s backend application(Tradir.io) without paying much attention to how I am going to help other future developers inherit the codebase. However, since I know that I am not going to be working on this codebase forever, and the application is going to last a very long time, I felt a strong need to make the codebase more comprehensible.

Although, there is no need to refactor every single app in the whole project. The only apps that need to be refactored are the ones with huge files that are hard to read.

The best example would be a bloated serializer class that spans over 260 lines.

class SomeSerializer(serializers.ModelSerializer):
field1 = serializers.SerializerMethodField()
field2 = serializers.SerializerMethodField()
field3 = serializers.StringRelatedField(read_only=True)
field4 = serializers.CharField(required=False, allow_null=True)
.
.
.
get_field1(self, instance):
return OtherSerializer(instance.otherfield).data
get_field2(self, instance):
return OtherSerializer2(instance.otherfield2).data
.
.
.
def create(self, validated_data):
with transaction.atomic():
user = self.context['request'].user
car= Car.objects.create(owner=user, **validated_data)

car.add_access(user)
if self.context['others_allowed_to_drive']:
for id in self.context['other_user_ids']:
added_user = User.objects.get(id=id)
car.add_access(added_user)
car.save()
.
.
.

In the above example, you can see that the create() method, which is the most important method in SomeSerializer, has many lines of code. For now, it is now as big, but it certainly takes more than a few seconds to figure out what the last 6 lines of code do. We can create a separate method for those last 6 lines with appropriate naming.

def initialize_caraccess(self, car, user):
car.add_access(user)
if self.context['others_allowed_to_drive']:
for id in self.context['other_user_ids']:
added_user = User.objects.get(id=id)
car.add_access(added_user)
car.save()

Now, the create() method can be shorter and more semantic.

def initialize_caraccess(self, car, user):
.
.
.
car.save()
def create(self, validated_data):
with transaction.atomic():
user = self.context['request'].user
car= Car.objects.create(owner=user, **validated_data)

self.initialize_caraccess(self, car, user)

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Nicholas An
Nicholas An

Written by Nicholas An

Backend Server Developer in South Korea

Responses (1)

Write a response