Add a Why not? section

This commit is contained in:
Radoslav Georgiev 2022-01-21 14:01:53 +02:00
parent f4d1a33c69
commit 0983eb9eae
No known key found for this signature in database
GPG Key ID: 0B7753A4DFCE646D

View File

@ -21,6 +21,7 @@ Django styleguide that we use in [HackSoft](https://hacksoft.io).
<!-- toc -->
- [Overview](#overview)
- [Why not?](#why-not)
- [Cookie Cutter](#cookie-cutter)
- [Models](#models)
* [Base model](#base-model)
@ -77,12 +78,14 @@ Django styleguide that we use in [HackSoft](https://hacksoft.io).
## Overview
The core of the Django Styleguide can be summarized as follows:
**In Django, business logic should live in:**
* Model properties (with some exceptions).
* Model `clean` method for additional validations (with some exceptions).
* Services - functions, that mostly take care of writing things to the database.
* Selectors - functions, that mostly take care of fetching things from the database.
* Model properties (with some exceptions).
* Model `clean` method for additional validations (with some exceptions).
**In Django, business logic should not live in:**
@ -90,12 +93,69 @@ Django styleguide that we use in [HackSoft](https://hacksoft.io).
* Serializers and Forms.
* Form tags.
* Model `save` method.
* Custom managers or querysets.
* Signals.
**Model properties vs selectors:**
* If the property spans multiple relations, it should better be a selector.
* If the property is non-trivial & can easily cause `N + 1` queries problem, when serialized, it should better be a selector.
The general idea is to "separate concerns" so those concerns can be maintainable / testable.
## Why not?
> Why not put your business logic in APIs / Views / Serializers / Forms?
Relying on generic APIs / Views, with the combination of serializers & forms does 2 major things:
1. Fragments the business logic in multiple places, making it really hard to trace the data flow.
2. Hides things from you. In order to change something, you need to know the inner-workings of the abstraction that you are using.
Generic APIs & Views, in combination with serializers & forms is really great for the straight-forward "CRUD over a model" case.
From our experience so far, this straightforwad case rarely happens. And once you leave the happy CRUD path, things start to get messy.
And once things start to get messy, you need more "boxes", to organize your code in a better way.
This styleguide aims to:
1. Give you those "boxes".
1. Help you figure out your own "boxes", for your own specific context & needs.
---
> Why not put your business logic in custom managers and/or querysets?
This is actually a good idea & you might introduce custom managers & querysets, that can expose better API, tailored to your domain.
But trying to place all of your business logic in a custom manager is not a great idea, because of the following:
1. Business logic has it's own domain, which is not always directly mapped to your data model (models)
1. Business logic most often spans across multiple models, so it's really hard to choose where to place something.
- Lets say you have a custom piece of logic that touches models `A`, `B`, `C` and `D`. Where do you put it?
1. There can be additional calls to 3rd party systems. You don't want those in your custom manager methods.
**The idea is to let your domain live separately, from your data model & API layer.**
If we take the idea for having custom managers and combine that with the idea of letting the domain live saparetely, we'll end up with what we call a "service layer".
Services can be functions, classes, modules or whatever makes sense for your particular case.
With all that in mind, custom managers & querysets are very powerful tool and should be used.
---
> Why not put your business logic in signals?
From all of the available options, perhaps, this one will lead you to a very bad place very quickly:
1. Signals are a great tool for **connecting things that should not know about each other, yet, you want them to be connected.**
1. Signals are also a great tool **for handling cache invalidation** outside your business logic layer.
1. If we start using signals for things that are heavily connected, we are just making the connection more implicit and making it harder to trace the data flow.
That's why we recommend using signals for very particular use cases, but generally, **we don't recommend using them for structuring the domain / business layer.**
## Cookie Cutter
We recommend starting every new project with some kind of cookiecutter. Having the proper structure from the start pays off.