Skip to content

Commit 4348316

Browse files
committed
* Rename common to bootstrap (meaningful naming)
* Move storage initialisation from `gateways` to `bootstrap` * Update documentation Signed-off-by: Federico Busetti <[email protected]>
1 parent fc54306 commit 4348316

24 files changed

+65
-47
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ COPY --chown=nonroot:nonroot poetry.lock .
6868
COPY --chown=nonroot:nonroot src/alembic ./alembic
6969
COPY --chown=nonroot:nonroot src/domains ./domains
7070
COPY --chown=nonroot:nonroot src/gateways ./gateways
71-
COPY --chown=nonroot:nonroot src/common ./common
71+
COPY --chown=nonroot:nonroot src/bootstrap ./bootstrap
7272
COPY --chown=nonroot:nonroot src/alembic.ini .
7373
COPY --chown=nonroot:nonroot Makefile .
7474

docs/api-documentation.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ The example `books` domain provides 2 endpoints to demonstrate this approach
1414
* `/api/books/v2` (POST)
1515

1616
/// note | Media type versioning
17+
1718
An improvement could be moving to [media type versioning](https://opensource.zalando.com/restful-api-guidelines/#114)
1819
///

docs/inversion-of-control.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class BookService:
5858
) -> None:
5959
self.book_repository = book_repository
6060

61-
# file `common/di_container.py`
61+
# file `bootstrap/di_container.py`
6262
from sqlalchemy_bind_manager._repository import SQLAlchemyAsyncRepository
6363
from dependency_injector.containers import DeclarativeContainer
6464
from dependency_injector.providers import Factory
@@ -196,18 +196,20 @@ the life cycle of the concrete classes is handled in the correct order
196196
and we don't end up in circular dependencies.
197197
///
198198

199-
200199
```python
201-
# file `common/factories.py`
200+
# file `bootstrap/factories.py`
202201
from domains.books._data_access_interfaces import BookRepositoryInterface
203202

203+
204204
def book_repository_factory() -> BookRepositoryInterface:
205205
from sqlalchemy_bind_manager._repository import SQLAlchemyAsyncRepository
206206
return SQLAlchemyAsyncRepository()
207207

208+
208209
# file `domains/books/service.py`
209210
from domains.books._data_access_interfaces import BookRepositoryInterface
210-
from common.factories import book_repository_factory
211+
from bootstrap.factories import book_repository_factory
212+
211213

212214
class BookService:
213215
book_repository: BookRepositoryInterface
@@ -258,13 +260,13 @@ We would need to implement the functionalities a dependency injection container
258260
///
259261

260262
```python
261-
# file `common/injectors.py` (Theoretical)
263+
# file `bootstrap/injectors.py` (Theoretical)
262264
def inject_book_repository(f):
263265
@functools.wraps(f)
264266
def wrapper(*args, **kwds):
265267
# This allows overriding the decorator
266268
if "book_repository" not in kwds.keys():
267-
from gateways.storage import BookRepository
269+
from bootstrap.storage import BookRepository
268270
kwds["book_repository"] = BookRepository()
269271
elif not isinstance(kwds["book_repository"], BookRepositoryInterface):
270272
import warnings

docs/packages/bootstrap.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Bootstrap
2+
3+
The `bootstrap` module contains logic that is shared among the external layer
4+
(i.e. `http_app`, `celery_worker`, etc.).
5+
6+
It contains 3 submodules (and related responsibilities):
7+
8+
* `bootstrap.bootstrap`: The application initialisation logic (database, logging,
9+
celery tasks) necessary to run the domain logic. It uses `bootstrap.config` and
10+
`bootstrap.di_container` subpackages. It does not contain the specific HTTP
11+
framework initialisation (or other frameworks such as GRPC).
12+
* `bootstrap.config`: The application config models, based on `BaseSettings`
13+
and `BaseModel` from `pydantic` package to get the values from
14+
environment variables.
15+
* `bootstrap.di_container`: The dependency injection container configuration.
16+
* `bootstrap.storage`: The storage configuration (SQLAlchemy). This setup uses
17+
[Imperative Mapping](https://docs.sqlalchemy.org/en/20/orm/mapping_styles.html#imperative-mapping)
18+
so that our models remains simple classes.
19+
20+
/// warning | Note about SQLAlchemy ORM Imperative Mapping
21+
22+
Even if the code for models appears to remain simple classes, imperative mapping
23+
transforms them behind the scenes. However, the code in our application should not
24+
rely on such specific capabilities otherwise we would bind our code to SQLAlchemy.
25+
26+
To handle database operations we use a repository class that is aware of SQLAlchemy.
27+
In this way, should we need to change our storage implementation (e.g. switch to MongoDB),
28+
we'll only need to change the repository class, without having to change anything in
29+
our application logic.
30+
///

docs/packages/common.md

Lines changed: 0 additions & 15 deletions
This file was deleted.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ branch = true
7979
source = ["src"]
8080
omit = [
8181
"src/alembic/*",
82-
"src/common/config.py",
82+
"src/bootstrap/config.py",
8383
]
8484
# It's not necessary to configure concurrency here
8585
# because pytest-cov takes care of that

src/alembic/env.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import logging
22
from asyncio import get_event_loop
33

4-
from common.bootstrap import application_init
5-
from common.config import AppConfig
4+
from bootstrap.bootstrap import application_init
5+
from bootstrap.config import AppConfig
66
from sqlalchemy.ext.asyncio import AsyncEngine
77

88
from alembic import context

src/bootstrap/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .bootstrap import application_init
2+
from .config import AppConfig

src/common/bootstrap.py renamed to src/bootstrap/bootstrap.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
from dependency_injector.containers import DynamicContainer
33
from dependency_injector.providers import Object
44
from domains import init_celery, init_domains
5-
from gateways.storage import init_storage
65
from pydantic import BaseModel, ConfigDict
76

87
from .config import AppConfig, init_logger
98
from .di_container import Container
9+
from .storage import init_storage
1010

1111

1212
class InitReference(BaseModel):
File renamed without changes.

0 commit comments

Comments
 (0)