You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/domains.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,21 +15,21 @@ What this styleguide calls a `domain` is roughly an extension of what Django wou
15
15
16
16
This guide tries to keep the key benefits of Django's `app` pattern - namely Django's [models](https://docs.djangoproject.com/en/2.1/topics/db/models/) to represent tables in a datastore, but with an emphasis on **skinny models**.
17
17
18
-
This guide also retain Django's ability to *package apps as installable components in other applications*. This allows domains to be easily migrated to different codebases or completely different projects.
18
+
This guide also retains Django's ability to *package apps as installable components in other applications*. This allows domains to be easily migrated to different codebases or completely different projects.
19
19
20
20
## Domain rules
21
21
22
22
There are two major rules around domains:
23
23
24
24
1. You **should** split a domain if it becomes too big to work on.
25
25
26
-
A domain should allow between 4-6 developers (3 pairs) to comfortably work on it. If you find your developers being blocked by each other then it is time to consider splitting the domain or checking the software has not diverged too far from the styleguide.
26
+
A domain should allow between 4-6 developers (3 pairs) to comfortably work on it. If you find your developers being blocked by each other then it is time to consider splitting the domain or checking whether the software has not diverged too far from the styleguide.
27
27
28
28
---
29
29
30
30
2. You **should** adhere to the styleguide patterns in this document in order to maintain strong bounded contexts between your domains.
31
31
32
-
This applies even in situations where you extract one domain into two domains to increase velocity, but they still have to maintain a dependency between each other. We have found that if you relax the bounded context between domains, the boundary will erode and you will lose the ability to work on them independent of each other.
32
+
This applies even in situations where you extract one domain into two domains to increase velocity, but they still have to maintain a dependency between one another. We have found that if you relax the bounded context between domains, the boundary will erode and you will lose the ability to work on them independent of each other.
Copy file name to clipboardExpand all lines: docs/examples.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,9 +3,9 @@
3
3
Let's start with a basic example - a project that has two domains. They both expose APIs for a Frontend service, and they also communicate to each other.
4
4
Communicating to the Frontend service is simple - they have defined a REST API in their API layer and the Frontend calls it.
5
5
6
-
When talking to each other, they both _interface_ (hence the naming choice) with each other through the appropriate layers. Sometimes we call the this "API to interface path".
6
+
When talking to each other, they both _interface_ (hence the naming choice) with each other through the appropriate layers. Sometimes we call this the "API to interface path".
7
7
8
-
Let's imagine that the owners of Domain B decide they want to move their software into another web server on the other side of the world. The first thing they might do is make a copy of the software of Domain B. They might spin up that copy in the new world, and slowly port the data over from the old Domain B.
8
+
Let's imagine that the owners of Domain B decide they want to move their software into another web server on the other side of the world. The first thing they might do is make a copy of the software of Domain B. They might spin that copy up in the new world, and slowly port the data over from the old Domain B.
9
9
10
10
During this time, Domain A is still talking to the old Domain B. When the new Domain B is ready to go, they inform the team that owns Domain A. The Domain A team will then update their interfaces.py to point to the new Domain B instance. Because they have not leaked Domain B's logic throughout Domain A, the change is isolated to a single file (and hopefully a single git commit).
Copy file name to clipboardExpand all lines: docs/files.md
+14-14Lines changed: 14 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,13 +1,13 @@
1
1
2
2
### Examples on this page
3
3
4
-
In the examples below we imagine a service with two domains - one for books, and one for authors. The abstraction between books and authors is only present to demonstrate the concepts in the styleguide. You could argue that Books and Authors can live in one domain. In our example **we also assume a book can only have one author.** It's a strange world.
4
+
In the examples below we imagine a service with two domains - one for books, and one for authors. The abstraction between books and authors is only present to demonstrate the concepts in the styleguide. You could argue that Books and Authors can live in one domain. In our example **we also assume that a book can only have one author.** It's a strange world.
5
5
6
6
## Models
7
7
8
-
Models defines how a data model/ database table looks. This is a Django convention that remains mostly unchanged. The key difference here is that you use _skinny models_. No complex functional logic should live here.
8
+
_Models_ defines how a data model/ database table looks. This is a Django convention that remains mostly unchanged. The key difference here is that you use _skinny models_. No complex functional logic should live here.
9
9
10
-
In the past Django has recommended an [active record](https://docs.djangoproject.com/en/2.1/misc/design-philosophies/#models) style for it's models. In practice, we have found that this encourages developers to make`models.py` bloated and do too much - often binding the presentation and functional logic of a domain too tightly. This makes it very hard to have abstract presentations of the data in a domain. Putting all the logic in one place also makes it difficult to scale the number of developers working in this part of the codebase. See the [_"Which logic lives where?"_](/styleguide/#which-logic-lives-where) section for clarification.
10
+
In the past Django has recommended an [active record](https://docs.djangoproject.com/en/2.1/misc/design-philosophies/#models) style for its models. In practice, we have found that this encourages developers to bloat`models.py`, making it do too much and often binding the presentation and functional logic of a domain too tightly. This makes it very hard to have abstract presentations of the data in a domain. Putting all the logic in one place also makes it difficult to scale the number of developers working in this part of the codebase. See the [_"Which logic lives where?"_](/styleguide/#which-logic-lives-where) section for clarification.
11
11
12
12
A models.py file can look like:
13
13
@@ -39,9 +39,9 @@ class Book(models.Model):
39
39
40
40
## APIs
41
41
42
-
APIs defines the external API interface for your domain. Anyone using the APIs defined here is called a _consumer_. The API can be either an HTTP API using [GraphQL](https://github.com/graphql-python) or [REST](https://www.django-rest-framework.org/) for consumers over the web, or a software API for internal consumers. APIs is defined in `apis.py` which is agnostic to the implementation you choose, and you can even put more than one API in a domain. For example - you might want to wrap a GraphQL API _and_ a REST API around your domain for different consumers.
42
+
_APIs_ defines the external API interface for your domain. Anyone using the APIs defined here is called a _consumer_. The API can be either an HTTP API using [GraphQL](https://github.com/graphql-python) or [REST](https://www.django-rest-framework.org/) for consumers over the web, or a software API for internal consumers. APIs is defined in `apis.py` which is agnostic to the implementation you choose, you can even put more than one API in a domain. For example - you might want to wrap a GraphQL API _and_ a REST API around your domain for different consumers.
43
43
44
-
An apis.py file that defines a simple software API can look like:
44
+
An `apis.py` file that defines a simple software API can look like:
45
45
46
46
```python
47
47
import logging
@@ -79,13 +79,13 @@ class BookAPI:
79
79
80
80
## Interfaces
81
81
82
-
Your domain may need to communicate with another domain. That domain can be in another web server across the web, or it could be within the same server. It could even be a third-party service. When your domain needs to talk to other domains, you should define **all interactions with it in the `interfaces.py` file**. Combined with APIs (see above), this forms the bounded context of the domain, and prevents domain logic leaking in.
82
+
Your domain may need to communicate with another domain. That domain can be in another web server across the web, or it could be within the same server. It could even be a third-party service. When your domain needs to talk to other domains, you should define **all interactions to the other domain in the `interfaces.py` file**. Combined with APIs (see above), this forms the bounded context of the domain and prevents domain logic from leaking in.
83
83
84
-
Consider interfaces.py like a mini _Anti-Corruption Layer_. Most of the time it won't change and it'll just pass on arguments to an API function. But when the other domain moves - say you extract it into it's own web service, your domain only needs to update the code in `interfaces.py` to reflect the change. No complex refactoring needed, woohoo!
84
+
Consider `interfaces.py` like a mini _Anti-Corruption Layer_. Most of the time it won't change and it'll just pass on arguments to an API function. But when the other domain moves - say you extract it into its own web service, your domain only needs to update the code in `interfaces.py` to reflect the change. No complex refactoring needed, woohoo!
85
85
86
-
It's worth noting that some guides would consider this implementation a code smell because it has the potential for creating shallow methods or pass-through methods. This is somewhat true, and leads us back to the [pragmatism](/using/#be-pragmatic) point in our guide. If you find your `interfaces.py` is redundant, then you probably don't need it. That said: **we recommend starting with it and removing it later**.
86
+
It's worth noting that some guides would consider this implementation a 'code smell' because it has the potential for creating shallow methods or pass-through methods. This is somewhat true, and leads us back to the [pragmatism](/using/#be-pragmatic) point in our guide. If you find your `interfaces.py` is redundant, then you probably don't need it. That said: **we recommend starting with it and removing it later**.
87
87
88
-
An interfaces.py may look like:
88
+
An `interfaces.py` may look like:
89
89
90
90
```python
91
91
import uuid
@@ -133,15 +133,15 @@ class AuthorInterface:
133
133
134
134
Everything in a domain comes together in Services.
135
135
136
-
Services gather all the business value for this domain. What type of logic should live here? Here are a few examples:
136
+
_Services_ gather all the business value for this domain. What type of logic should live here? Here are a few examples:
137
137
138
138
- When creating a new instance of a model, we need to compute a field on it before saving.
139
139
- When querying some content, we need to collect it from a few different places and gather it together in a python object.
140
140
- When deleting an instance we need to send a signal to another domain so it can do it's own logic.
141
141
142
-
Anything that is specific to the domain problem and **not** basic informational logic should live in Services. As most API projects expose single functional actions such as Create, Read, Update, and Delete, Services has been designed specifically to compliment stateless, single-action functions.
142
+
Anything that is specific to the domain problem and **not** basic informational logic should live in Services. As most API projects expose single functional actions such as Create, Read, Update, and Delete, _Services_ has been designed specifically to compliment stateless, single-action functions.
Copy file name to clipboardExpand all lines: docs/plugins.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,4 +1,4 @@
1
-
We recommend the following plugins for use with this guide.
1
+
We recommend the following plugins for use with this guide:
2
2
3
3
## Django REST Framework
4
4
@@ -19,7 +19,7 @@ Additional ruling for DRF:
19
19
20
20
[Graphene-Django](https://docs.graphene-python.org/projects/django/en/latest/) is the recommended framework for creating [GraphQL](https://graphql.org/) APIs with Django.
21
21
22
-
When using Graphen-Django, we can organis the logic in a domain this way:
22
+
When using Graphen-Django, we can organise the logic in a domain this way:
Copy file name to clipboardExpand all lines: docs/using.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
3
3
In software we often specify a version of a project to use. For example - `requests==1.2` - this says _"we want to use requests version 1.2"_.
4
4
5
-
For this guide we recommend the following: picking a specific version and working against it. Just like software; future versions of this guide could change and that could cause conflicting issues with the styleguide in your project.
5
+
For this guide we recommend the following: picking a specific version and working against it. Just like software; future versions of this guide could change, potentially causing conflicts with the styleguide in your project.
6
6
7
7
You can see the released versions [here](https://github.com/phalt/django-api-domains/releases) and by clicking on the tag icon you can view historical versions. The published version at [https://phalt.github.io/django-api-domains](https://phalt.github.io/django-api-domains) will always be the latest version.
0 commit comments