Domain Driven Design with Django and GraphQL | Patrick Arminio

This video features Patrick Arminio at DjangoCon Europe 2021 in Online.

Domain Driven Design with Django and GraphQL | Patrick Arminio
0:46:04
Published June 27, 2021
3,142 views

Domain driven design is starting getting traction in the Python world, probably also thanks to Architecture Patterns with Python (https://www.cosmicpython.com/).

In this talk we will learn some basics of Domain Driven Design and how to apply the pattern when using Django and GraphQL. We will see different approaches of modelling the domain, and discuss the tradeoffs. We will discuss why this approach makes a lot of sense with GraphQL and finally we will see a complex approach where we leverage the domain driven architecture to have an easy way to abstract how we store and cache our data in order to build a performant GraphQL API.

This talk is aimed at people with knowledge of web-development. GraphQL knowledge won’t be necessary as I’ll do a quick introduction of that. Experience with Django, Flask or similar framework might be useful but not required.
The audience will learn basic concepts of domain driven design and how to apply them to build a scalable GraphQL API.

Summary

GraphQL provides a typed, declarative API with queries, mutations, and subscriptions, while tools such as Strawberry let Python developers define schemas from typed Python code. Patrick Arminio argues that GraphQL works well with domain-driven design when the domain remains independent of Django, GraphQL, and the database: entities represent business concepts, repositories abstract persistence, and services contain logic spanning multiple entities. In Django, this means using GraphQL as an application layer and translating between domain entities, Django models, and GraphQL types; the separation improves testing and keeps business rules reusable, though it adds code and is best adopted gradually for complex domains rather than simple CRUD.

Key takeaways

  • GraphQL uses a typed schema and lets clients request exactly the fields they need through queries, mutations, and subscriptions.
  • Code-first libraries such as Strawberry generate GraphQL schemas from typed Python definitions and provide useful editor and type-checking support.
  • Domain-driven design starts with the business domain and a shared vocabulary rather than with database models or framework structures.
  • Entities model business concepts, repositories abstract storage, and services hold logic that involves multiple entities.
  • A Django application can use GraphQL as its application layer while adapters translate between Django models and domain entities.
  • The approach improves isolation and testing but requires extra mapping code, careful domain modelling, and gradual migration; it is not worthwhile for every simple CRUD application.

Summarised automatically from the transcript.

Chapters

  1. 0:08 Introduction Patrick introduces himself and previews the talk on Domain-Driven Design, Django, and GraphQL.
  2. 0:54 GraphQL Foundations An overview of GraphQL queries, mutations, subscriptions, schemas, and the benefits of declarative data fetching.
  3. 4:00 GraphQL Tools and Python Libraries A live GraphQL API demonstration leads into GraphQL tooling and the Python ecosystem, including Strawberry and Graphene.
  4. 10:14 Domain-Driven Design Motivation The talk shifts to why Domain-Driven Design helps teams focus on business problems, shared language, and maintainable systems.
  5. 13:18 Layered Architecture Patrick explains the presentation, application, domain, and database layers and GraphQL’s role as an API adapter.
  6. 14:54 Entities, Repositories, and Services The core Domain-Driven Design patterns are introduced through Python examples for events, repositories, and domain services.
  7. 17:18 Domain-Driven Design in Django The talk examines the tension between Django’s conventions and Domain-Driven Design, then outlines a Django-compatible architecture.
  8. 20:38 GraphQL and Django Implementation A live walkthrough shows the project structure, GraphQL queries and mutations, domain conversion, and repository-backed data access.
  9. 24:20 Testing and Repository Abstractions Patrick demonstrates abstract and fake repositories, service tests, and the benefits of keeping domain logic independent of the database.
  10. 30:31 Architecture Lessons and Resources The talk concludes with guidance on separating domain and API types, Domain-Driven Design resources, and project takeaways.
  11. 33:17 Questions Audience questions cover adoption challenges, use cases, gradual migration, generated types, and when Domain-Driven Design is appropriate.

Transcript

7,347 words · auto-generated Show

Automatically transcribed, so expect mistakes in names and technical terms.

0:08

Speaker 1: Everyone, my name is Patrick, as mentioned. I work at Poland in London, which is a startup that does uh things around events. Um and I'm also a the president on Python Italia. I was just mentioning this because I wanted to to share something that we're doing in a couple of weeks on the 16th of June. We're doing a remote festival which is going to be dedicated to Python and the Python community as As we know, we were not able to organize a conference in person last year, so we decided to do something to bring the community together. uh just bringing maybe like the most fun part of it so just socializing and doing things fun so it's gonna be live coding performances um and games as well. So if you're interested in doing something fun in a couple of weeks,

0:54

Speaker 1: feel free to check out the website. It's going to be Pythas done online. Cool. So today I wanted to introduce you to domain-driven design and GraphQL and how they fit together. But first I wanted to do a quick introduction to GraphQL because it's still a Quite new technology, especially in the Python world. So I think it's worth just going back to to the roots, I guess, of the actual So GirQL is defined as a query language, basically allows you to fetch data in a declarative way. So you can send a document and then the server is going to do all the artwork for you. You can see it's kind of like REST, but instead of having multiple endpoints, you only have one where you send a document that looks like this. For example, here

1:39

Speaker 1: we are saying I want to query something and I want to get a blog post with ide of one and then for the blog post you want to fetch the title the content and the full name of the author and then the server is going to do all the work for you um and i'm gonna show a demo this in in a second Also worth mentioning that Gartel supports multiple operation. So what we've seen here, this is just a query. So a query basically allows you to fetch data without any side effects. It's like get in in the Rust world, I guess. And then you have mutations. Mutations are basically a way to do anything that has side effects. So for example, creating a user, deleting a user uh or even sending an emails, things like that. And finally, I think these are very, very cool.

2:25

Speaker 1: It's subscription. They're very similar to queries, but they allow you to subscribe to events and get the data in real time. So for example, I can subscribe to a new comment event and then every time there is a new comment, I'm gonna receive a uh the data bug it usually works with web sockets or server site server send events um yeah this is quite cool as well so GraphQL as a tight schema. So I think this is also one of the big selling points of GraphQL is having the schema. which is basically gives you guarantees of what the API is going to return and what's in the API. So for example, for our previous query, we can see that we could have a schema that looks like this. So we have a type user

3:11

Speaker 1: where there's a full name and the full name is a string, then it's also required. The examination mark means that the string is required. Then we have a blog post which has an ID of type ID, title of type string, contentless type string, and auto type user Finally, we have this special type. It's only special because of the name, the query type, where that defines a blog post. and also defines here some arguments, only one in this case, which is the ID and it's required. And it might return a blog post. Let's see an example of GraphQL. So this is the ID that comes with usually any any GraphQL server that you can use in any languages pretty much. So basically this is a very very good tool that allows you to just run operations on GraphQL

4:00

Speaker 1: and also see the documentation. For example, this is the uh Star Wars API GraphQL implementation. You can see here that on the right we have documentation where we can see all the types that we have. So for example, here we have only a query. So there is no mutation subscription for this API But here we can see that we can query for a film with an ID, we can query for a person, we can query for plants, and then we can go and try this here. So for example, I want to do a query And I want to fetch, let's say, person with ID one, maybe. I don't know if that exists. And then I don't really know this API, so you can see that this tool is helping me a lot.

4:47

Speaker 1: Uh we're trying to discover one. So yeah, in this case the ID is not valid, but maybe let's do old person. we don't have old people. Let's see how that works. Um so you can see I this is It's telling me also if there is any error. For example, the field name doesn't exist on people connection because this is returning a paginated result. So there's going to be edges. And then name. And you can see here it's returning all the data that I'm fetching. And also what's powerful, it's just returning the data I'm asking for. So if for example, if I'm asking for birth year, it's gonna return that as well.

5:32

Speaker 1: So I think this is also another reason why people say that this is much better than Rust because it actually allows you to fetch only the data that you need and no nothing more than that. And for me, I think it's just like the user experience. It's really good. Like making Kafka APIs, it's quite easy, I would say , when you know some of the basics and some of the uh quirks around it and then on the front end there is a lot of tools for example a pollo that I think it was mentioned in another talk uh which makes using GraphQL APIs much much easier Cool. Um until a few years ago we had a bit of um not great um I guess a situation we got curling Python, we only

6:20

Speaker 1: have one library which was graphene. And I think it was not also non-mantane at that point But now luckily things have changed. So we have two, well, we have four, or probably even more now, uh libraries. So there is the first two. is Trobre and Graffini which are code first. So code first means that you're basically writing Python code and then the um the framework is going to convert the Python code to be this the graphical schema that you you're seeing here which is this one. Meanwhile the schema first uh which allows you to to write this uh the schema first and then you attach um the resolvers which are basically the way you fetch data um python um we we use strawberry and graphene at work

7:06

Speaker 1: graphina is mostly used for our legacy apis strawberry is used is being used for all the new apis Also wanted to mention that the surveys like the library I've been working on for I think two years now at this point. And it's becoming quite popular these days. And we also have I think it's five core developer, so it's becoming a very very solid project, even if it's not yet stable I would say like we use we use it in production but we still haven't released version one mostly because we are doing some internal refactoring and we are also uh finishing writing the docs Just gonna show an example on how to implement the previous schema that we've seen with Surbery. So the syntax

7:52

Speaker 1: that we have is basically a I guess a copy of data classes if you use that. Basically we have a decorator called Subrary Type. And then we can use that to come to basically convert a class to a graphical type. So what we're gonna do here is like we're gonna see all the fields that declared using the type annotation syntax You're gonna get the type and then we're gonna create a GraphQL type for you. So this is gonna look exactly the same as this one at the top when you convert it to GraphQL. And one of the reasons why I we we prefer code first is that this code can be reused in Python, obviously, but also it can be like uh if you use my pi or any any other type checker you get auto completion and also type checking

8:38

Speaker 1: which is uh really really nice And this is how you create the query. So as you can see here, there's a couple of things that are different. The first thing is that we're using uh this submarine field decorator um to to basically define the field instead of setting it as a field like this so just the name and the type we are creating a function or a method in this case um That's called blog post. So this is doing two things. One is is basically declaring the field. So we have a blog post field, but it's also um adding something that's called resolver. Resolver and GraphCard are basically fun functions that get called when you request for data So for example, if I'm requesting for this field in GraphQL

9:26

Speaker 1: , the GraphQL server is gonna call this method on the query class. That's what we're doing. We are extracting the the argument from uh from this method and we are passing them to the garfial type as well. And the last thing we have to do is that we have to create the schema using subray. schema and passing the root type, which is the green. Yeah, this is basically it's not very, very difficult to basically create a very simple example of this. And I'll show you a I guess better example later in a few minutes. Yeah, as I mentioned, GraphQL is very powerful and flexible. And I think a lot of the advantages come from the fact that it's typed and also it's

10:14

Speaker 1: declarative. And with that, there is a lot of tools that have been created by the community. So for example, just saying Apollo has a client that you can easily use to uh to fetch data in in a React application either in VJS or just anywhere. It's really, really powerful. It basically removes a lot of complexity, especially on the front end. Maybe things are be more complicated on the back end, but I think once the we go over that initial barrier, it gets much much better. But yeah, this talk is about doing domain-driven design and GraphQL together. So I guess one other question that you might have is do we need domain-driven design for doing GraphQL? Well

11:00

Speaker 1: We don't need to do that. So we can just use GraphQL and maybe work with the Django models directly. I think it's it's a good idea to do domain-driven design. Domain-driven design is something that we're doing upon and uh I think we started a couple of months ago. Obviously, we're trying to convert the whole code base to be domain-driven design Which is just a tough challenge and I'll show you why in a moment. So domain-driven design is an approach to software that focuses on domain and the processes around that domain. So basically instead of writing the code first, you or like just thinking of what kind of data structure you want to use.

11:46

Speaker 1: Basically domain dreaming design forces you to think about what kind of problems you you are trying to solve. And with that, it also forces you to use an ubiquitous language. So when you try to define a software as um as the main driven, I guess. You're trying to basically find all the domain you're working with. So you go and talk with stakeholders, product owner, developers and trying to find a common ground, a common language. for the problem you're trying to describe. And this is um this is actually really good because it helps a lot with the communication between different departments. I've seen this a lot of work where like I was using a a different name for something

12:31

Speaker 1: that it was actually a user. And so this like if we had like this ubiquitous language from the start, it would be much easier. Like we would have a lot or less confusion. And as I mentioned, like you are trying to find solution first. You should not be focusing on the technology. Because again, like our focus is to solve real-world problems. We're not trying to, okay, let's use Django directly. Let's try to find the like our domain, and let's try to find the solutions for that domain. Something that's also very um, I guess, prominent in the domain-driven world is this uh layer architecture.

13:18

Speaker 1: Which basically promotes an architecture that looks like this. So we have a presentation layer, we have an application layer or API layer, then we have a domain layer, and finally we have a database layer. This is basically saying from presentation layer is what the user is gonna look like, it's gonna see, and it should not contain any business logic code Sorry, the business logic should be should be as small as possible. Um and then we have the API layer, which is basically kind of the glue between the presentation layer domain layer is it's what's gonna get the data from domain layer send it back to the presentation layer the domain layer is where we implement all our logic And finally we have the database layer, which is uh what we use for for storing the data.

14:08

Speaker 1: Uh and you can see here that we're using GraphQL as our API layer, but If we need to add an a REST API or even a command line interface, it's really easy to do because like all the logic is inside the domain layer. So the REST API is only gonna be like an adapter or like an interface for to our domain. Cool. How can we implement domain-driven design? So domain-driven design is quite new in Python, I guess, mostly because uh I don't know, it was mostly popular in uh enterprise languages, so languages we um You get static typing, but we can still do this in in Python. And I'm going to show you a basic domain-driven design structure that we are actually using a

14:54

Speaker 1: pollen. And just want to mention that this is very basic. Domain-Grimming design is something that's quite new for us. So we're trying to basically do a migration step by step, trying to understand what kind of pattern works for us. So we chose to implement these three patterns, entities, repository, and services. Entities are basically the objects inside your data. So they represent something in the domain. So for example here we since we do events we could have an entity that's event and you can see we can define it as a data class and then we can define so much input on this entity And it kind of looks like a Django model. But again, we want to be abstracted

15:41

Speaker 1: from the actual framework or from the actual uh um storage layer basically. The entities basically represent business concepts, not database ones. Then we have repositories. Repositories are basically, I guess you can think as them as like an ORM. So basically they allow you to fetch data and save data. and update. So you can have a repository that looks like this for for example for our event. So we have a get function that returns an event and then we have a save function that saves an event and also returns the updated version. Finally, we have services. Services are basically

16:26

Speaker 1: it's where you put logic that's not circulated to one single entity. For example, here we have a function, it's it what we can we call service uh that basically uses two entities one is the event and one is the new manager uh and it does some logic on that and then finally saves the um the event with the updating manager And you also can do some some side effects. There's actually more like if you if you go and read anything ready to dominate design, you're gonna see things like bonded context. um aggregates and so on. But I think this is a really good starting point for for us or anyone in general. Doing this already helps quite a bit with the communication and just the structuring the code.

17:18

Speaker 1: So let's see how we can use domain during design in a Django view. So this is a very silly example of a view where which returns an event detail. So you can see here we are creating an event repository, using the event repository to get the event by ID, and then if there's an event, we render the page. Otherwise we do a 404. So as you can see, this example is not really doing things the Django. We're not using models. I don't know, like it's domain-driven design doesn't really work well with Django, I would say. Like Django is quite opinionated, even though I don't think that's a bad thing. Like it gives you a very good structure for um for just doing any any kind of project, but then it doesn't really scale well

18:06

Speaker 1: for for big projects. At least I haven't seen that working really well for a project I've been working on. So maybe if you're starting with a new project, you could try to do to use a linear framework, something like Flask or Fast API, which are quite popular this day, and we are actually using them for um for some of our side projects, uh sorry, for some of our services. I still think that Django is really good and it's like you can still do domain driven design with Django. So let's see how we're doing DDD with Django Poland. So we come up with this kind of, I guess, architecture where we have a GraphQL layer, which is our application layer. Then we have entities, repositories, and we also sell

18:53

Speaker 1: services, but for like for showing the example they are not necessary So we have two fun two things here. So we have this from domain function on the graphical types, which gets an entity that converts it to the graphical type. And then we have convert instance function on the uh just near the entities that I'll basically get a Django model and convert them to to be an entity. I'll show you the code in a bit because I feel like this explanation is not the best. I guess one question you might have is, can now we use Django models as entities directly? You could, but the problem is if you use Django modus, you're gonna tie

19:39

Speaker 1: your entities to the database. So for example, if you're using a JSON field or just in general, you're gonna it's gonna be super easy to just keep the the repository and just use the Django object uh the Django or um which is something that we're trying to avoid here so let's see a small example So since I'm doing this live, I actually can show you the code, which is probably gonna be best. So I have this junk application here and I share the domain at the repository later on in the Slab. And we have two applications here. So we have an API one, which is going to contain everything related to the API. We have one which is up, which is the uh it's basically our domain, or our domains.

20:26

Speaker 1: In this case we only have events, and then we have a db application, uh which might be a bit strange. So This was a one suggestion for one of my previous coworkers. They said it might be best to just try to put all the models inside the P so it's easier to Just understand that they're separated from the actual domain. But yeah, I'm not sure this works well. It doesn't bother me too much, but yeah, not everyone might like it. So let's go and see what we've done here. Let's go. So the first thing is we have a URL, so you can see that there is a GraphQL view here that we use to go and fetch the information on the domain So you can see here, which is this one.

21:12

Speaker 1: And our domain is pretty simple. So you have one query, so you can fetch an event by D Oh, I need to start the server. So as I was mentioning, we have only one one query. So you can vet you this event by ID. Which I so we're using UIDs now, so I this this was wrong. But you can also create one, so maybe you can do that. Create event, start date 2021 I think okay, so in in this example I'm just saying okay, let's create an event with the start date and I forgot the temple.

22:01

Speaker 1: There you go. So we did start dating this title and then I want to get the ID and the title bug. As you can see here, we get any um we get the event bug. And all of this is using Django, Django models and domain design all the ones. And yeah, you can see that we also fetching the data here. So that works as well. So let's see how the um how we implemented the the query. So this is the API that we have. So the first thing I wanted to mention is that we have a custom graphical view. So this is based on Shrewberry which provides a general integration but we want to return a custom context. This is basically an object that's gonna be it can be reused everywhere in in the

22:47

Speaker 1: in in the Garfell API. Let's see that in a second. So let's go here. So the schema looks like this. So we have a query limitation. The query is defined like this. So this is the event field. accepts an ID, both accept this special info parameter. So the info parameter is basically a similar to the Django request object. It has everything related to the GraphQL query in this case. And it also holds the context that we were passing before. So what are we doing here? We're using the context. I'm using the event repository, just this. to to fetch the event event by D. If we don't have an event, uh we return on otherwise we return the

23:33

Speaker 1: uh the event and we convert the event from the domain. The domain event is the the entity from the domain while the event type is the graphical event type So you can see here we have this utility function that converts the entity to be a graphical type. Okay, hopefully this is not too complex. There is also the typings which might be uh quite new as well. So server uses mostly type-ins to make to make things work with um with the implementation. Cool. So if you see here we have defined the context using a lab search repository

24:20

Speaker 1: As we mentioned before, like we want to make sure that we like that our implementation is not tied to to the database structure. So this is how we define a basic repository. So we define on the only operation that we want to do. And then if we need We can extend that we can create a like a specific implementation, for example, for Django, for maybe SQL outcome if you're using dot. And this is this is actually really powerful because it allows you to do uh tests really easily. So for example, here we have a test where we're defining a fake repository, which in this case it just example returns always none. So we can test for example this case where like

25:05

Speaker 1: the Gavskare layer is returning none if the event doesn't exist. Then we can do the same, for example, for returning an event here. This is already a very big benefit for uh just implementing this kind of domain-driven design structure. Um Cool, let's see if I can um show you. Yeah, I wanted to show you also like the tests for the service. So this is um So ah yeah this is the entity that we have here for our domain. It's similar to the GraphQL one, but again, that should be separated because for example you might have a lot of data here that you don't want to expose on GraphQL, for example or even on graphical

25:50

Speaker 1: you may have some competit fields or fields that come from other places. So you you want to keep things separated. Let's see a service now. So this is very similar to what we had before. There's only one logic thing, which is just checking that the start date is after today. So we only create events in the future. So we do that, we create an event, we create an ID. So we're doing your ID here, and then we pass in the title. And finally we're using the save function only repository to save the event and again here that we pass in the typing for the app document repository but then when we actually use it we're gonna use the Django and one and I'll show you that in a second. Just wanted to show you again the test. Example here we have a event test

26:37

Speaker 1: repository that's not doing anything for the gallon because we're not using that But then for the save, it's just returning the save. And you can see that we can easily test the logic. So we can check, for example, when we get an event that we use the ID, that we return an ICA prefer ID. And then for example, we can also test the logic. And also like if we if we did everything like this, we would have a very fast test where we're not using the database. And we only need to test the database once. We need when we test the repository. So we can test the implementation. So let's go and see that how it looks. I think this is probably the hugless part of the code base because there's a quite a few things happening. So let's see die in a second Um so for example

27:23

Speaker 1: for getting we are using the event, the model, the Django model, and we're using the up the orm to filter and getting the first one by the if we have one we do a conversion so we convert the database instance to be an entity Which in this case is very simple. But yeah, this is probably gonna get tedious when you have a lot of models and then it is because you have to do this work quite a few times. We do the same thing here for um for update or create the event. I really don't like this to be honest, but I haven't really found a way for doing this in a much nicer way with the Django. I know that you can use SQL alchemy, you can mop uh

28:08

Speaker 1: you can map a class to a database table which might look much nicer. But again you write this only once and then then it's basically gone for you Um yeah, I think that should be it for the example. So I've done all this slide. Let's see if I missed something. Oh yeah, as I mentioned, we are passing here the repository as abstract. I guess we now know why we've done that, but also we're passing it as a dependency here to just make it test easier. uh we should it's quite useful. Cool. Yeah this is the mutation that we've seen so we can go and create an event and then we have the front domain uh class method that basically converts an entity to a

28:56

Speaker 1: graphical type. And again, maybe I should have come up with a better example to just making sure that like the reason why we have like different types for different parts of the code base. But again we we want to keep things separated. So like the domain should not know about how it's being used, so it should not know anything about GraphQL. So this is why we this is the place where we're doing the conversion. So the Garfell layer, the apply layer knows about the domain, but the domain doesn't know about the the Garfkell layer And this is limitation. Again, we're using the service function to convert to create the event. We're also using the context to get the repository. And these are

29:41

Speaker 1: the tests. Um yeah, as I mentioned like Dita Mosano I think is like having things that are named uh the same in different places. But again, this is this is this is the domain, the ubiquitous languages. So we we had things that have the same name because they are basically the same thing. They're just used in different contexts. I guess one, yeah, I guess the entity and maybe the database that could be merged together, but it's it's best to just keep them separated. And this is how it looks. So we have the application layer which is Garkel and Efficiation may be REST, example. And then we have the domain layer which is represented by the entities and the repositories. And finally, we have the database layer, which is used by a specific implementation of the repository.

30:31

Speaker 1: But that comes later. Like the first thing it would be to just implement this bit, have an abstract repository, and then implement the precision. the persisting budget. Um Surry supports uh creating graphical types from graphical models. But again, we want to avoid that. We don't want to make a copy one-to-one of what we have on the domain. We want to make sure that the GraphQL layer is still for the use case that we are working with. And again, um that was just code. So domain given design is much more than that. It's mostly um like a way of doing code so the focus with domain driven design it should be on the on the domain so the code comes comes later

31:17

Speaker 1: um Yeah, um have some resources here. Hopefully I have still a bit of time. Or maybe I went too fast, I'm not sure. So the first resource is Cosmic Python. I think this is the book that basically prompted us to try to manage human design. This is a very good book by Harry Prestival and Bob Gregory. You can read it for free on the website. Yeah, it has a lot of concept. Like some of the ideas that we had are basically coming from this book. And there's also more things which are even more interesting, but I don't think we have time to go into that. Then if you really want to know about domain-driven design, there is this really good talk by Robert Smallshari from your Python a couple of years ago, or two

32:03

Speaker 1: years ago. This is really good. It goes a lot into details of domain driven design. So if you're really interested in that, definitely go and check uh this. this talk and I'll share the links on on uh on Slack otherwise this is not really easy to copy. Also I wanted to mention like we are hiring so if you go to Pollen. co you can see all the openings and if you want to work with domain-driven design or if you're really good with domain-driven design and want to help us with the transition. Um yeah just Maybe you can also speak with me if you're interested in that. And again, if you if you want to check out our festival, it's PyFest. online. It's gonna be, I think it's gonna be really fun.

32:49

Speaker 1: Again, yeah, thanks everyone for your attention, especially now that's the last session. And you can find me online at Spotify 91 and there's my website and I'll share the uh slides and the links on Slack in a few seconds. Hello everyone

33:17

Speaker 2: Okay, maybe I can ask the first question.

33:23

Speaker 3: No, go on. No, go on.

33:26

Speaker 2: Uh yeah I was curious uh uh uh what made you to do the uh change uh from your current architecture to domain-driven uh version

33:40

Speaker 1: Um yeah, we I think this is was uh was an idea from our principal uh engineer, just just basically making sure that um that we have a better structure of of our code base because like oh well I I guess you know because like our stop startups has gone through faces so we changed the basic our focus quite a few times. And one of the things that we have a lot of legacy code and basic legacy Django models, so we're trying to use um without basically writing everything. But then now it's getting a bit messy. So we're trying to improve things. And like the domain-driven design approach is basically helping us to okay. Now we really have to understand what we're doing, especially in the code.

34:26

Speaker 1: And so this is like we're doing some processes here. Like for example, there's a technique called event storming. We just try to define all the things we can do in the domain. Um and this is something that's helping us, also the stakeholders, because there's a lot of uncertainty of what we're actually doing and what the process that we have and Yeah, so basically just basically clean cleaning up things and making sure that everyone is on the same page.

34:58

Speaker 3: Hi, uh so two questions. First, uh did you f uh find much resistance in the team to adopting such a uh uh architecture because Uh like most Pythonists and Django developers that don't like that kind of approach that like drifts away from the from the framework and adds like more layers into into things. So uh and uh I I careers uh use don't seem to be using use cases and like that's one of the domain driven design uh concepts that I find like

35:43

Speaker 3: pretty interesting. So like did did you have any reason to not use that or like do you use another approach? So

35:52

Speaker 1: um yeah another question. So for the first question in terms of like fiction from other teams um Yeah, yeah, there there's definitely there is a bit like uh especially since we haven't really figured out the best way of doing things yet. Like we're still trying to to know what domain driven design looks like for us because it like the implementation is always a bit different. And I think one of the, I guess, mistakes that we did, um, or like non-proper way of approaching this is to actually go and doing the code first, like structuring the code, say oh this is how we can use domain driven design but actually what we had to do first was the um all the processes around trying to define what the domain looks like uh and how you um basically making sure make

36:38

Speaker 1: sure that all the code uh respect subdomain. That's something I will actually start doing now. And I'm not sure how it's going because I'm involved in another team at the moment. But yeah, uh there's there's definitely a few people that are really into it. Like they they like Deadlio, this like they know that this I mean definitely looks much better than we what we had before. I guess also maybe they were struck by the fact that we have a lot of legacy And there's a lot of times that things are hard to understand. So that helps a bit, I guess. But yeah, there's definitely people that do things the the old way, especially uh when when they aren't under pressure of deadlines. Uh because that's one of the enemies of this as well. Because if when we when you want to do domain-driven design, you have to focus on the domain and that takes quite a bit of time and yeah

37:25

Speaker 1: deadlines are not helping Um in terms of use cases, um yeah again this is probably like a an artifact of house going through the code first and not just trying to understand like the domain the domain part bit or just display the processes around that. Um what we have now we have a I mean given design score the work. So we have a team of eight people where we meet every few weeks and we talk about how we can improve our process around that with what kind of um um process we can adopt that. So for example, like there's a few people reading books that they're gonna share ideas on that. And there's people in some teams that try and even storming just

38:10

Speaker 1: to find the domain pattern and not really familiar with use cases so I'm not sure why we haven't shown but You know, I think I'm going to be able to do that. Oh there's a message here. Oh, um someone that's no name, so not sure. Uh but yeah, someone's mentioning the yeah, the wind given design. Um Yeah, it's not really really well suited for crowd, I guess.

38:55

Speaker 1: Like if you're doing crowd or something simple, domain driven design is not the place, like it's not the technology they want to use or not like the the patterns uh methodology. That's definitely definitely true. So yeah. So like our application nowadays is becoming quite complex. we don't really have crowd crowd anymore. We're not using the Java anymore. Well I mean we're using it because we have some legacies but we're trying to go away from from the Java building and a new one. Um so yeah definitely and the talk uh which I'm gonna share there in mentions that so like command human design is not for everything or everyone

39:55

Speaker 4: Can you hear me a pipe, uh Patrick?

39:58

Speaker 1: Uh yes.

39:59

Speaker 4: Okay, fine. So um I want to speak about uh the problem uh of uh creating models entities and the strawberry types You have to write three things that sometimes could be uh something more uh something similar So, uh, do you think that the the next step in a domain -driven approach could be the creation on the fly? of strawberry types or serializers or Django models. And do you think this is could be the best approach or the best approach could be uh

40:46

Speaker 4: the creation of the entity uh starting from the server type or salizers or the models.

40:54

Speaker 1: Um so yeah the Don't know what this noise is. Um but yeah the source of through should always be the domain. So if you want to auto-generate types, that should be this should be the the graphical ones, not the the domain type. The domain should be always it should not Uh sorry this There we go. Sorry, there was a tab playing the sponsor. Yeah, so the domain should be the source of truth. So you don't want to how to generate domain entities because that's something that you want to define clearly. For the graphical text, yeah, I would say uh it's an approach of doing it. Like we we are avoiding auto-creating types

41:39

Speaker 1: um graphical types mostly because we don't want to expose everything. Um but again it I I'm not really against that. It's definitely something you can do. And I don't really have a song preference on that personally. Again, we are doing in survey we are doing We are doing a Django integration so you can convert models to subway types and in future are we also doing Pythonic, so if you're using Pythantic for your entities, you can convert that to graphical types quite easily But um yeah it's sometimes like especially for example I guess you've seen in Django's framework you have to declare out the fields especially Because you like you want to grind people to exp uh um basically

42:25

Speaker 1: exposing everything even by mistake. Because for example, let's say that you have Uh this is simply an example where you have a user and you have also the user uh the the password in the in the entity for some reason. You definitely don't want to expose that in any way. Or if you want to expose it, you want to add permissions on top of it. So yeah, definitely, I mean for simple use cases it might be fine, but then when you get to more complex ones, it's not no ideal. There's also the thing is when when you want to merge things together, like in GraphQL, you can easily have one type that contains multiple things. That's also not easy to auto-generate as well, because you you're doing correlations between things and you're not using Django and using domain-driven design, so you cannot do uh

43:12

Speaker 1: generation based on the following keys and things like that

43:19

Speaker 4: Okay, thank you. Great talk.

43:29

Speaker 1: Thank you.

43:33

Speaker 3: Um so when you started implementing uh it did you do like it gradually? So for example starting from creating the repositories first or the entities first or like or or did you just like implement it all the way like to the whole application and

43:52

Speaker 1: Uh so we haven't done it. We haven't finished. So it's it's gonna be it is a gradual process process for so we're implementing new services that are separately from our Django and those are domain-driven first, I guess But the rest, let's look at the code base, it's a bit tricky because we also don't want to convert things that we don't use anymore. So every time we implement a new feature, we go and try to define, okay, this is a domain But it also depends on who's working on it. Like it's someone that's really into the window and design, like if like one of my colleagues really into that every time it's working on a feature try to do some a bit a bit of conversion to domain-driven design so that like gradually we we go for the domain-driven design. But it's a long process. It's definitely a long process because it takes

44:38

Speaker 1: Um like takes takes a lot of time, yeah. There is one question related to I think it's Paul Halhalet using Django API domains. I don't really know about this, so cannot really answer. But I'm gonna get I'm reading the introduction, it seems that some of the concepts are basically similar, at least the not the architecture like the code ones, but just having um bunding context. Yeah. So that that might be similar. Like a lot of a lot of the concepts are like

45:23

Speaker 1: can be shared between lot implementations, but Like I guess everyone does it a bit differently. So I think definitely if you if you check the cosmic Python book, that's gonna give you a good starting point.

Questions this talk answers

What is GraphQL, and how is it different from REST?

GraphQL lets clients send declarative queries to a single endpoint and receive only the fields they request, rather than working with multiple REST endpoints that may return more data than needed.

Discussed at 0:54

What are GraphQL queries, mutations, and subscriptions used for?

Queries fetch data without side effects, mutations perform changes such as creating or deleting records, and subscriptions deliver updates in real time when events occur.

Discussed at 1:39

Why use domain-driven design with GraphQL instead of exposing Django models directly?

DDD keeps the application focused on the business domain rather than on framework or database structures. GraphQL can then act as an application-layer interface while the domain logic remains reusable by REST APIs or other interfaces.

Discussed at 11:00

What does a layered domain-driven architecture look like in a Django application?

The presentation layer contains the user-facing interface, GraphQL serves as the application/API layer, the domain layer contains business logic, and the database layer handles persistence. The API layer connects to the domain through adapters rather than implementing the business rules itself.

Discussed at 13:18

How do entities, repositories, and services work in domain-driven design?

Entities represent business concepts, repositories provide operations for loading and saving those entities, and services contain logic that spans more than one entity. The entities are deliberately kept independent of Django and the database.

Discussed at 14:54

How can domain-driven design be integrated with Django and GraphQL?

The GraphQL layer uses repositories to retrieve domain entities, converts those entities into GraphQL types, and keeps the domain unaware of GraphQL. Django model instances are converted into domain entities inside the repository implementation.

Discussed at 18:53

Why shouldn’t Django models be used directly as domain entities?

Using Django models as entities ties the domain to the database and makes it tempting to bypass the repository abstraction. Separate domain entities allow the business logic to remain independent of storage details such as Django-specific fields.

Discussed at 19:39

How does using repository interfaces make a Django GraphQL application easier to test?

The application depends on an abstract repository, so tests can provide a fake in-memory implementation instead of using the database. This allows GraphQL behavior and domain services to be tested quickly, while database-specific behavior is tested separately.

Discussed at 24:20

How should a legacy Django application migrate gradually to domain-driven design?

The migration is incremental: new services can be built with the domain-driven structure, and existing features can be converted as they are changed instead of rewriting the whole application. The team also needs to define the domain and its processes before merely reorganizing the code.

Discussed at 33:52

Is domain-driven design a good fit for every Django project?

No. It is generally not worthwhile for simple CRUD applications, but it becomes more useful as the domain and processes grow complex and the codebase becomes difficult to understand.

Discussed at 38:55

Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.

More videos by Patrick Arminio

More videos from DjangoCon Europe