Django and domain driven design
Asked Answered
P

3

46

I am confused about Domain Driven Design Approaches. From the sources on net I understood it is way of segregating your Domain Objects and Database Objects but I don't understand the difference between two.

For an example lets take the code of Polls example in django tutorial, there are two models Polls and Choice.

Are these domain level objects or database level objects?

Is there a need for DDD with an ORM?

If yes, can you provide a good situation where you need to use DDD approach with an ORM

For example, this is the model

class Polls(models.Model):
    question = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

DDD approach code I have seen people writing

class PollService(object):
    def __init__(self, poll_repository):
        self.poll_respository = poll_respository

    def update(self, poll_id):
        poll = self.poll_respository.fetch_by_id(poll_id)
        poll.question += '?'
        self.poll_respository.update(poll)

#assume that the following code works?
class PollRepository():

    def __init__(self, db):
        self.db = db

    def update(self, poll):
        try:
            self.db.session().add(poll)
            self.db.session.commit()
        except Exception:
            self.db.session.rollback()

Is this a correct approach? I see a lot of redundant code here but people say that Polls is a domain level object and it should not directly talk to database?

Does DDD always comes with a DDD-reposiotry ? Why we need a DDD repository if we have an ORM

Another approach

views.py
def update_poll(poll_id):
    poll = models.Polls.objects.get(poll_id)
    poll.question += '?'
    poll.save()

What is wrong with this approach?

Phelips answered 4/2, 2017 at 7:11 Comment(2)
"Does DDD always comes with a DDD-reposiotry ? " - No. You could use CQRS with Event SourcingCapful
Check out github.com/dry-python project. It provides a set of tools to model your domain with ease!Monafo
F
44

Active Record Pattern

Django is tailored towards the use of the Active Record Pattern as described on this Django Design Philosophy page.

Your second example follows this pattern - the model itself has its properties, behaviour and data access contained within.

You can still use this pattern in a more DDD-like way, if you push more behaviour onto the model. e.g. in your example, a more effective use of the pattern would be to wrap the line

poll.question += '?'

in an intention revealing method on the poll object, so that the update_poll method is:

views.py
def update_poll(poll_id):
    poll = models.Polls.objects.get(poll_id)
    poll.add_question()
    poll.save()

This has the advantage of separating the business logic (pushed into the model) from the application flow logic (the update_poll method)

Although I'd suggest using a name that actually illustrates the intent or purpose of the method rather than just add_question.

But even if you do this, you are still using the Active Record pattern, not pure DDD.

You ask "Is there a need for DDD with ORM?"

DDD and an ORM are attempting to solve different problems. ORMs provide a convenient way of abstracting the set-like record-oriented world of databases in a more object oriented fashion.

DDD is an approach to assist with modelling complex real world situations in code.

Many DDD systems use ORMs to solve the infrastructure concerns of retrieving and persisting from the database (sometimes wrapping the ORM in a repository for a variety of reasons), but the DDD focus is on the domain models and how suitably they model the domain under consideration.

So - in your example, the benefits of DDD are difficult to see, as the business logic is so relatively simple.

I recommend reading the authoritive source on DDD - Domain Driven Design by Eric Evans for a language agnostic overview of the approach and the situations where it adds value.

Update

You ask:

Can you update me with one good example where using DDD with an ORM makes sense

and

If we use ORM I think there is no need for a DDD-repository

I think a better way to think about it is - when using an ORM, the ORM is the repository. You ask it for a model and it returns a model. That is the purpose of a repository. When people wrap it in a class called 'repository' it is usually because they want to do one of a few things:

  1. make it easier to inject a mock repository to simplify unit testing
  2. abstract the specific orm technology used to give flexibility to change the ORM later without having to touch the services or domain

This overview of the repository pattern provides another good writeup of the ddd repository pattern.

Foy answered 4/2, 2017 at 8:50 Comment(7)
Thanks Chris. Can you update me with one good example where using DDD with an ORM makes sense ?Phelips
do we need to use ddd-repositories with ORM ? If we use ORM I think there is no need for a DDD-repository ?Phelips
Please note 'model' in DDD is 'Domain Model' which consists of Entities, Value Objects, Services, Repositories, Aggregates, Aggregate Roots and whatever else is needed to represent the domain in question. Model in django models, are Entities. In other words, in DDD, model is a model of the domain.Burma
From Fowler's PoEAA book: "Active Record is a good choice for domain logic that isn’t too complex [CRUD]. [...] If your business logic is complex, you’ll soon want to use your object’s direct relationships, collections, inheritance, and so forth. These don’t map easily onto Active Record, and adding them piecemeal gets very messy. [...] Another argument against Active Record is the fact that it couples the object design to the database design. This makes it more difficult to refactor either design as a project goes forward."Jennajenne
If you take DDD serious, then Django Models are not Entities and the ORM is not the repository. A repository is just a plain python class providing an interface to query the domain data. The ORM is an implementation detail that does not belong to the domain model. The repository may use it to communicate with the database but it can't be the same thing. The same goes for models following the active record pattern. They can't be considered an entity.Deutsch
@Deutsch I agree but the repository have to communicate with the underlying storage layer, which in that case is Django ORM, there have to be a compromise to utilize both. The entity definition by Django is the tight coupling happening that is discouraged, which should be resolved if the same field mapping happened in a configuration file like xml/yaml and what not, but is that even possible? what is recommended to have both ?Penicillin
@Penicillin I honestly don't know what are you asking, can you rephrase a question?Comedy
G
19

Paul Hallett put it all together in his beautiful and complete article: https://phalt.github.io/post/django-api-domains

And the example here: https://github.com/phalt/django-api-domains

In brief:

Django’s style guide is old

The documentation, from the tutorials to the full docs, talk about a model-view-controller world in which Django renders HTML and delivers it to a web browser.

Something about this struck me as odd - I have worked with Django since 2012, and I only remember using it to render HTML once. Nearly all my time with Django, and all the time I have seen Django being talked about at conferences has been to provide an API (usually with Django REST Framework) to a frontend project. I would argue that this is actually the defacto standard for Django today. The documentation is out of date for the current popular use-cases. This is generally a trend I am seeing with Django - the project is trying to modernise how it is run and even how to handle async properly. Maybe it is time Django re-considered the design patterns it suggests for developers too?

Back to my immediate problem: in order to help the team organise their software better, I set out to find a good styleguide from the community. I read about Domain Driven Resign, the benefits of bounded contexts, and I found a nice styleguide by Hacksoft that we tried to use. This was great! The documentation here was very sound, and perfect for smaller projects or small companies.

But during our experimentation with it, we found it wasn’t fit for purpose for a few reasons. Namely, the fact that is encouraged business logic to live in the models. Django also recommends this and it is basically the active record pattern. In our experience with very large teams, keeping business logic tied to the models encouraged developers to fill up models.py with tonnes of code. This makes it very hard for developers to work on one file at the same time. Not to mention the fact that when a single file owns more than one problem in a domain (presentation, data, controller, etc) it tends to suck all other problems into the file too.

Gorizia answered 13/2, 2019 at 8:19 Comment(1)
you know you can use a folder for models with multiple files in it, right? You can even have one model per file, much like java.Airdrie
H
5

If you need some examples regarding DDD and Django then this https://github.com/dry-python/dry-python.github.io/tree/develop/slides slides using dry python tools could be useful.

Also, check the example project https://github.com/dry-python/bookshelf

Hermeneutics answered 2/11, 2019 at 19:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.