Django Business logic separation from framework.

In our Django project we decided to start separating business logic of product features to separate - let’s call it layer.
The idea is to encapsulate business logic flow into one place, lets say class FooFeatureManager, and not put pure feature business flow code into Views/Serializers/Models/Forms/Commands etc…

The question is it good idea to move to that class business logic code event if it one simple line : for example line that defines the next available date for feature activation by customer.
Code:

 class FooFeatureManager:
     @staticmethod
     def min_activation_date():
         return timezone.now().date() + timedelta(days=23)
    
     ... more business logic code


 class FooSerializer(serializers.ModelSerializer):
    min_activation_date = serializers.SerializerMethodField()
    class Meta:
        model = FooConfig
        fields = ( 'min_activation_date', )

    def get_min_activation_date(self, obj):                     --------------------------> This is better ?
        return timezone.now().date() + timedelta(days=23)

    def get_min_activation_date(self, obj):
        return FooFeatureManager.min_activation_date()          --------------------------> Or this is better ?

Serializers are already designed in a way to handle your business logic with a consistent pattern and in a very testable way. In your small example, I would not move the code anywhere else, I would keep it in the serializer.

In a real world use case, you may need to reuse code outside of a serializer. In that case, you probably do want to decouple your logic from your serializer.

My common path would be keep logic primarily in serializers and only abstract when needed.

1 Like

Thank you for the answer.

Following your answer, what will happen if the same logic will be executed in another places ? Serializer serves API, but there are in addition admin actions on the same feature, and possibly commands that as well can require to use same business logic.

Should we use rest framework serializer in Django admin and/or commands?

@massover Another question.

When you decide not to decouple business logic until it will really be needed in more places, how do you ensure not to miss the timing.

In the project I am working on, remote team of multiple engineers working intensive on a lot of different features at the same time.

And most of the time the code is duplicated when another place need to reuse business logic because people missing that need to be DRY, and the business logic becomes scattered around the code base…

WDYT?

There is a reason why you see Django projects organized the way you do. This is not Java Spring or some other framework where you need to introduce layers to work around limitations in the language or the framework.
Logic belonging to (or effectively based on) a single model belongs with that model, or its manager.
Truly multi-model logic can go in the view or a utility module in the application. This does not mean that the logic exists in the view itself. That logic can be defined in functions in your view module.

Keep in mind that models, views, and forms do not need to be single files. You can create them as modules, with the functionality divided among multiple files.

Regarding your other question, that’s a management and planning issue.

Regardless of your exact development practices (waterfall, some flavor of agile, whatever), code reviews should be some part of your development cycle. If you can’t identify these types of situations in the planning process, you can resolve them during the code review.

If it’s multiple teams working in multiple locations on the same logic, then it’s the responsibility of local management to resolve these as quickly as possible. Yes, that means that the managers have to become familiar with the code base and logic of what their developers are working on. Frequent commits and pushes are useful with this. But the key is to make some one person responsible for identifying when this occurs, and to address it quickly.

2 Likes

@KenWhitesell
Thank you for your response.
WDYT?

  1. Sometimes feature from business point of view does not fits into single model, but the logic is spread between a few. Let’s say enabling some feature for customer requires to update some config models and the customer model, and for example send email upon activation. Does it makes sense to put that flow into specific model?

  2. How the concern of Clean architecture lives with that Django approach ? Robert C. Martin tells us that no any framework should be the architecture, but only the utility that you plug where it belongs?

Thank you for the response.

@massover Thank you for the answer

Addressing each question in turn:

  1. The “flow”? (I’m interpreting that as being the sequence of code determining which functions or methods should be called, in what sequence, and with which parameters.) No, that would be in the view module, probably as a function being called by the view.
    However, if there is a close relationship between the config models being updated and the customer model upon which they depend, I would consider placing the code that updates those config models in the customer model.
    For example, let’s say that this config model tracks whether or not the customer wants weekly emails sent to them. I would make the initial assumption that the only time this setting would be changed would be in the context of updating the customer object - you would not be changing this setting without knowing who the customer was. So in this case, I’d be very comfortable with adding a model function to the customer model to update that config setting.

  2. Absolutely agree with Mr Martin here - with the understanding that “System Architecture” != “Where files are located in directory structures” and “Which files contain what functions”. Rather, it’s addressing what functionality is present in functions and objects, and the relationships between them.
    This question regarding physical code organization is a separate topic, and does properly reside in the realm of framework patterns and expectations. Sure, you can build a system that completely ignores the common patterns and practices of Django and even PEP-8 for that matter, and you can do it in such a way that adheres to every other applicable architectural principle. What you would end up with is a system that creates “friction” with experienced Django developers coming on board to maintain and enhance your system.

1 Like

@KenWhitesell

Regarding the second answer, i want to be sure i get it.

Can i say that what you are saying is :
Mr Martin’s point of view on relationships between frameworks and architecture is something you agree with, but in the reality, Django oriented developers does not usually address “Clean architecture principles” or any other architecture principles, but using Django’s way of doing things. Consequently the attempt to break that status quo will lead to “frictions” with Django oriented developers/community and will not be beneficial, mainly because of “people” and not because of Django and Clean Arch or any other arch ?

That’s not quite an accurate restatement, no.

I’m saying the two concepts (“Clean architectural principles” and “Django’s way of organizing code”) are two different and non-overlapping issues. The architectural principles will identify what functionality will be provided by which objects or functions. The organizing code identifies physically where those functions exist within your source directory tree.

Now, while that’s the basic and direct response, the reality is a little more subtle than that. Django does have an architecture, with its associated principles - one that has been proven to work extremely well under a variety of circumstances. To say that:

is ignoring the architecture that does exist. The friction that gets created when a developer ignores Django’s architecture is the “mental disconnect” created when someone who is familiar with Django’s architecture has to bridge the gap between their understanding of how Django works and how your application works caused by the mixture of architectural patterns.

Keep in mind that “Architectural Principles” are just that - principles. They’re not rules or requirements. They form a basis for making decisions.
Never lose sight of the fact that the overall objective of adopting a set of principles is to enhance reliability, maintainability, and extensibility of a system - in other words, minimizing the cost of that system over its entire life cycle.
The skill of an architect is understanding these decision points, and how those decisions may affect and be affected by future environmental changes - and what the cost may be to implement those changes later.

(I’ve seen way too-many over-engineered systems designed to handle situations with < 1% probability of occurrence over a 20-year lifespan of that system - such as a mainframe system developed in 1990 with a separate “data access layer” because “we might want to change databases” as if IBM DB2 was going to go away in an environment where it was responsible for 95+% of all corporate data.)

So yes, if you’re building your system around Django, your architectural decisions should reflect that. Otherwise, you’re wasting time, money, and “mental effort” trying to achieve some “ivory tower” architecture that may or may not be suited for the environment in which the real system is being built - or worse, trying to replicate an architecture built for a different framework. Django is not Spring, .NET, or Symfony - there is no value in trying to replicate application architecture among the four.

(All this comes from working as an Enterprise Architect for a little more than 5 years in a large multi-national corporation. I was formally trained in the application of TOGAF 7/8 as an enterprise architectural framework, and was a member of the team that developed the corporate IT architectural principles for the US division.)

1 Like

@KenWhitesell
Again thanks for investing time here.

So if i want to ask myself should i take into account “Clean architecture” when working with Django or totally ignore that and go the “Django way” ?

If yes use “Clean architecture” together with Django - how in your opinion the combination can be achieved in optimal manner ?

By applying the Clean Architecture principles within the Django architecture.

1 Like