Ce que je fais habituellement dans mes applications, c'est que je crée tous mes services/dao/repo/clients en utilisant des méthodes d'usine
class Service:
def init(self, db):
self._db = db
@classmethod
def from_env(cls):
return cls(db=PostgresDatabase.from_env())
Et quand je crée une application, je le fais
service = Service.from_env()
ce qui crée toutes les dépendances
et dans les tests quand je ne veux pas utiliser de vrai db je fais juste de la DI
service = Service(db=InMemoryDatabse())
Je suppose que c'est assez loin de l'architecture propre/hexadécimale car le service sait comment créer une base de données et sait quel type de base de données il crée (peut également être InMemoryDatabse ou MongoDatabase)
Je suppose que dans une architecture propre/hexadécimale, j'aurais
class DatabaseInterface(ABC):
@abstractmethod
def get_user(self, user_id: int) -> User:
pass
import inject
class Service:
@inject.autoparams()
def __init__(self, db: DatabaseInterface):
self._db = db
Et je mettrais en place un cadre d'injection pour faire
# in app
inject.clear_and_configure(lambda binder: binder
.bind(DatabaseInterface, PostgresDatabase()))
# in test
inject.clear_and_configure(lambda binder: binder
.bind(DatabaseInterface, InMemoryDatabse()))
Et mes questions sont:
vous voudrez peut-être utiliser une base de données différente et vous voulez avoir la flexibilité de le faire de manière simple, pour cette raison, je considère l'injection de dépendances comme une meilleure façon de configurer votre service
L'exemple initial est assez proche d'un clean/hex "correct". Ce qui manque, c'est l'idée d'une racine de composition, et vous pouvez faire clean/hex sans aucun framework d'injecteur. Sans cela, vous feriez quelque chose comme:
class Service:
def __init__(self, db):
self._db = db
# In your app entry point:
service = Service(PostGresDb(config.Host, config.port, config.dbname))
qui passe par Pure/Vanilla/Poor Man's DI, selon à qui vous parlez. Une interface abstraite n'est pas absolument nécessaire, car vous pouvez compter sur le typage canard ou le typage structurel.
Que vous souhaitiez ou non utiliser un framework DI est une question d'opinion et de goût, mais il existe d'autres alternatives plus simples à injecter comme punq que vous pourriez envisager, si vous choisissez de suivre cette voie.
https://www.cosmicpython.com/ est une bonne ressource qui examine ces problèmes en profondeur.