The story of returning to the front line for the first time in 5 years and refactoring Python Django

background

I've been involved in startups since last year and are developing with the Python framework Django. There was a development blank for nearly five years, so I decided opportunistically, "Is this the development of today?" But it was full of anti-patterns and ramblings.

The former former person in charge and the previous person in charge have stopped, and the attachment has been turned around. Looking at the remaining code, I can't help but think about it.

Under such circumstances, I would like to summarize the story of refactoring and the story of refactoring from now on.

The problem that was being blamed

It seems like it won't stop when I start talking, but there were two disappointing things from the architectural point of view.

View too smart

It seems that it was a simple app that the view only fetches the data originally created by batch processing. However, with the addition of functions, various calculations are now performed in the view.

Cluttered logic

It seems that the previous person tried to do something, but there was logic left in the view or logic in the model. You can create circular references in two different packages. I haven't confirmed the operation. It's been terrible.

The fundamental problem is ...

I put aside the fact that I didn't have enough time, ~~ the person in charge was stupid ~~, and it depends on the situation and people.

In the first place, Django expects a simple configuration with a 1: 1 table and model. It's a bit off the original meaning, but it's probably the Active Record pattern.

This configuration becomes problematic as the app becomes more complex.

As the functionality becomes more complex, the table changes. It may not match the model you originally expected.

I think Django tends to call the model directly from the view.

When you combine information from multiple tables, you tend to write logic in the view. If you do complicated calculations, it will be difficult to understand where the responsibility lies, asking "What? Is this model in charge?"

Model-View-Controller is a presentation layer pattern in the first place. It seems that the model is mixed with the architectural pattern of the data source, which is confusing. (I think I simply don't understand)

solution

I went back to the basics and started by layering. At that time, I referred to Domain Driven Design and the enterprise architecture pattern (although it has a bad reputation).

Personally, I was sick of the content of the enterprise architecture pattern.

http://www.amazon.co.jp/dp/4798121967 http://www.amazon.co.jp/dp/4798105538

Review: Basic application layer

There are some patterns, but it was easy to understand how to divide them into 4 layers.

Again, what made Django personally confusing was that it seemed like the presentation layer model, domain layer, and data layer were all in one. It became a key to divide this area.

Introduction of service layer

Changed to provide one service for one view. I don't like the complexity of the method parameters, so I let them handle the Data Transfer Object-like parameters.

The service is also divided into two types.

One is to handle basic CRUD. The naming convention is also XxxService.

The other is to combine multiple objects to perform complicated calculations and processing. The naming convention is also XxxEngine.

I didn't understand well even if I read various explanations, so I referred to the following code. http://www.infoq.com/jp/news/2015/04/ddd-trading-example https://github.com/archfirst/bullsfirst-server-java

Since it is inefficient to create an instance of the service each time, I made it a Singleton.

http://code.activestate.com/recipes/579090-yet-another-singleton-pattern-in-python-using-clas/

This is an issue for the future.

There were some similar things in XxxEngine. This is a haze that gives you a better view if you separate it with the Strategy pattern.

Model handling

I decided to think of Django's model as a data layer.

Introducing the domain layer

In the future, I am thinking of introducing a domain layer. Implement domain logic in a class that inherits from Django's model.

In the old days, when converting a table to an object, it was mapped to a POJO (Plain Old Java Object). To implement logic as a domain model, a class that inherited POJO was used. With that as a reference, I am thinking of inheriting POMO (my coined word w: Plain Old Model Object) and making it a domain model.

Summary

It's still subtle, but the current situation is like this.

When I saw the story of introducing the service layer in Rails, I thought "There are people who think the same thing", so I summarized what I thought / responded to in Django.

However, what I was worried about this time was the problem that was being talked about in the enterprise application pattern. Nowadays, there are many things that the framework hides and is not aware of. But when I was trying to push the boundaries of the framework, I thought it was important to know the basics.

Recommended Posts

The story of returning to the front line for the first time in 5 years and refactoring Python Django
Summary of stumbling blocks in Django for the first time
Check the processing time and the number of calls for each process in python (cProfile)
Google search for the last line of the file in Python
The story of Python and the story of NaN
The story of creating a "spirit and time chat room" exclusively for engineers in the company
Determine the date and time format in Python and convert to Unixtime
[Python] How to get the first and last days of the month
Put the process to sleep for a certain period of time (seconds) or more in Python
The story of releasing a Python text check tool on GitHub x CircleCI for the first time
[Python] The role of the asterisk in front of the variable. Divide the input value and assign it to a variable
A Python beginner first tried a quick and easy analysis of weather data for the last 10 years.
How to get the date and time difference in seconds with python
For the first time in Numpy, I will update it from time to time
A useful note when using Python for the first time in a while
The story of creating a store search BOT (AI LINE BOT) for Go To EAT in Chiba Prefecture (1)
A story about trying to improve the testing process of a system written in C language for 20 years
How to use MkDocs for the first time
The story of low learning costs for Python
I tried python programming for the first time.
Image processing? The story of starting Python for
The story of reading HSPICE data in Python
The story of viewing media files in Django
To represent date, time, time, and seconds in Python
Basic story of inheritance in Python (for beginners)
Try posting to Qiita for the first time
Various ways to read the last line of a csv file in Python
Data analysis in Python Summary of sources to look at first for beginners
How to count the number of elements in Django and output to a template
I want to get the file name, line number, and function name in Python 3.4
The story of creating a store search BOT (AI LINE BOT) for Go To EAT in Chiba Prefecture (2) [Overview]
[Super easy! ] How to display the contents of dictionaries and lists including Japanese in Python
[Tips] Problems and solutions in the development of python + kivy
The story of returning to the front line for the first time in 5 years and refactoring Python Django
Count the number of Thai and Arabic characters well in Python
Note: Get the first and last items of Python OrderedDict non-destructively
[Python] How to get the first and last days of the month
Get the title and delivery date of Yahoo! News in Python
Convert timezoned date and time to Unixtime in Python2.7
The wall of changing the Django service from Python 2.7 to Python 3
How to get the number of digits in Python
What I got into Python for the first time
I tried Python on Mac for the first time.
The story of Airflow's webserver and DAG, which takes a long time to load
The first step of machine learning ~ For those who want to implement with python ~
[Python] Measures and displays the time required for processing
Register a task in cron for the first time
Build API server for checking the operation of front implementation with python3 and Flask
I tried python on heroku for the first time
The story of FileNotFound in Python open () mode ='w'
[python] Calculation of months and years of difference in datetime
I want to create a lunch database [EP1-4] Django study for the first time
The first step for those who are amateurs of statistics but want to implement machine learning models in Python
Output the specified table of Oracle database in Python to Excel for each file
I just wanted to extract the data of the desired date and time with Django
A story about trying to introduce Linter in the middle of a Python (Flask) project
To do the equivalent of Ruby's ObjectSpace._id2ref in Python
[Jupyter] [Python] Correct the deviation between the x-axis scale and the center line of the bar with hist of matplotlib (for counting in 1 increments)
Now in Singapore The story of creating a LineBot and wanting to do a memorable job
Steps to change table and column names in your Django model at the same time
[Super easy! ] How to display the contents of dictionaries and lists including Japanese in Python
From zero knowledge of Python to making AI in the first grade of junior high school
What kind of environment should people who are learning Python for the first time build?
An easy way to view the time taken in Python and a smarter way to improve it
Tips for Python beginners to use the Scikit-image example for themselves 8 Processing time measurement and profiler
Check the operation of Python for .NET in each environment
The story of introducing jedi (python auto-completion package) to emacs