mirror of
https://github.com/HackSoftware/Django-Styleguide.git
synced 2025-02-06 22:50:53 +03:00
Merge pull request #91 from HackSoftware/improve-overview
Improve overview
This commit is contained in:
commit
007e187238
64
README.md
64
README.md
|
@ -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 straightforward "CRUD for a model" case.
|
||||
|
||||
From our experience, so far, this straightforward 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 its 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.
|
||||
- Let's 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 of having custom queryset/managers and combine that with the idea of letting the domain live separately, 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 tools and should be used to expose better interfaces for your models.
|
||||
|
||||
---
|
||||
|
||||
> 🤔 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.
|
||||
|
|
Loading…
Reference in New Issue
Block a user