web-dev-qa-db-fra.com

Méthodes d'usine vs infrastructure d'injection dans Python - qu'est-ce que le plus propre?

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:

  • Mon chemin est-il vraiment mauvais? N'est-ce plus une architecture propre?
  • Quels sont les avantages de l'utilisation d'inject?
  • Vaut-il la peine de s'embêter et d'utiliser le framework inject?
  • Existe-t-il d'autres meilleures façons de séparer le domaine de l'extérieur?
9
Ala Głowacka

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

0
kederrac

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.

0
ejung