L'unico anti-pattern di iniezione di dipendenza legittimo di cui sono a conoscenza è il pattern Service Locator , che è un anti-pattern quando viene utilizzato un framework DI per esso.
Tutti gli altri cosiddetti anti-pattern DI di cui ho sentito parlare, qui o altrove, sono solo casi leggermente più specifici di anti-pattern generali di progettazione OO / software. Per esempio:
L'iniezione eccessiva da parte del costruttore costituisce una violazione del principio della responsabilità singola . Troppi argomenti del costruttore indicano troppe dipendenze; troppe dipendenze indicano che la classe sta provando a fare troppo. Di solito questo errore è correlato ad altri odori di codice, come nomi di classi insolitamente lunghi o ambigui ("manager"). Gli strumenti di analisi statica sono in grado di rilevare facilmente un eccessivo accoppiamento afferente / efferente.
L'iniezione di dati, al contrario del comportamento, è un sottotipo dell'anti-pattern poltergeist , con il 'geist in questo caso il contenitore. Se una classe deve essere a conoscenza della data e dell'ora correnti, non iniettare a DateTime
, che sono dati; invece, si inietta un'astrazione sull'orologio di sistema (di solito chiamo il mio ISystemClock
, anche se penso che ce ne sia uno più generale nel progetto SystemWrappers ). Questo non è corretto solo per DI; è assolutamente essenziale per la testabilità, in modo da poter testare le funzioni che variano nel tempo senza doverle effettivamente attendere.
Dichiarare ogni ciclo di vita come Singleton è, per me, un perfetto esempio di programmazione di culto del carico e, in misura minore, il " pozzo nero " colloquialmente chiamato . Ho visto più abusi singleton di quanto non mi ricordi, e molto poco riguarda DI.
Un altro errore comune sono i tipi di interfaccia specifici dell'implementazione (con nomi strani come IOracleRepository
) fatti proprio per essere in grado di registrarlo nel contenitore. Questo è di per sé una violazione del principio di inversione di dipendenza (solo perché è un'interfaccia, non significa che sia veramente astratto) e spesso include anche un gonfiamento di interfaccia che viola il principio di segregazione dell'interfaccia .
L'ultimo errore che di solito vedo è la "dipendenza opzionale", che hanno fatto in NerdDinner . In altre parole, esiste un costruttore che accetta l'iniezione di dipendenza, ma anche un altro costruttore che utilizza un'implementazione "predefinita". Ciò viola anche il DIP e tende a portare anche a violazioni di LSP , poiché gli sviluppatori, nel tempo, iniziano a fare ipotesi sull'implementazione predefinita e / o avviano nuove istanze utilizzando il costruttore predefinito.
Come dice il vecchio proverbio, puoi scrivere FORTRAN in qualsiasi lingua . Dependency Injection non è una pallottola d'argento che impedirà agli sviluppatori da avvitare la loro gestione delle dipendenze, ma non prevenire una serie di errori comuni / anti-pattern:
...e così via.
Ovviamente non si vuole progettare un quadro di dipendere da una specifica contenitore CIO realizzazione , come l'Unità o autofac. Ciò sta, ancora una volta, violando il DIP. Ma se ti ritrovi a pensare anche a fare qualcosa del genere, allora devi aver già commesso diversi errori di progettazione, perché l'iniezione di dipendenza è una tecnica di gestione delle dipendenze per scopi generali e non è legata al concetto di contenitore IoC.
Tutto può costruire un albero delle dipendenze; forse è un contenitore IoC, forse è un test unitario con un sacco di beffe, forse è un test driver che fornisce dati fittizi. Al tuo framework non dovrebbe interessare e alla maggior parte dei framework che ho visto non importa, ma fanno ancora un uso pesante dell'iniezione di dipendenza in modo che possa essere facilmente integrato nel contenitore IoC preferito dell'utente finale.
DI non è scienza missilistica. Cerca solo di evitare new
e static
tranne quando c'è un motivo convincente per usarli, come un metodo di utilità che non ha dipendenze esterne o una classe di utilità che non potrebbe avere alcuno scopo al di fuori del framework (wrapper di interoperabilità e chiavi del dizionario sono esempi comuni di Questo).
Molti dei problemi con i framework IoC emergono quando gli sviluppatori stanno imparando come usarli e invece di cambiare effettivamente il modo in cui gestiscono le dipendenze e le astrazioni per adattarsi al modello IoC, cercano invece di manipolare il contenitore IoC per soddisfare le aspettative dei loro vecchio stile di codifica, che comporta spesso un elevato accoppiamento e una bassa coesione. Il codice errato è un codice errato, che utilizzi o meno tecniche DI.