A quale complessità si aggiungono i quadri DI?

8

La risposta attualmente più votata a una domanda molto recente afferma che

DI containers are an "enterprise software" pattern, used when the object graph is very large and complex. I suspect that 95% of applications do not require it.

che è qualcosa con cui non sono assolutamente d'accordo. Forse ho sbagliato la terminologia, ma per me DI framework significa solo "qualcosa che collega i miei oggetti insieme". Mi manca qualcosa?

Sto utilizzando Guice anche per progetti molto piccoli (come 10 classi) al fine di semplificarli . Certo, è un file JAR da 400 kB, ma non è quello che mi interessa. Per un piccolo progetto non ho quasi mai bisogno di alcuna configurazione e l'unico "overhead" è l'aggiunta dell'annotazione @Inject .

Quindi mi chiedo davvero, quale maggiore complessità fanno i quadri DI?

Aggiornamento che indirizza le risposte

In un progetto di classe 82, ho

  • 32 @Inject annotazioni
  • 15 @Singleton e 1 @ProvidedBy annotazioni
  • 4 provider (tutti di cui avrei bisogno anche senza DI poiché sono le mie fabbriche)
  • 1 modulo contenente una singola riga
  • 0 righe XML !!!

Questo è tutto. Certo, è un piccolo progetto, ma esattamente questo era il mio punto. Il lavoro aggiuntivo era composto da poche parole piuttosto che da linee .

Uso esclusivamente l'iniezione del costruttore per ottenere oggetti "facili" immutabili. Ogni volta che appare una nuova dipendenza, aggiungo un campo finale, lascio che Lombok RequiredArgsConstructor si occupi della dichiarazione e lasci che Guice si prenda cura di di chiamarlo correttamente.

    
posta maaartinus 16.06.2014 - 00:23
fonte

4 risposte

6

Ci sono un paio di compromessi che devono essere fatti quando si usano i framework DI per quanto posso vedere.

La cosa più preoccupante per me è che il codice dell'applicazione di solito è diffuso tra un linguaggio di programmazione principale (come Java) e il codice di configurazione XML / JSON (è è codice). Ciò significa che in caso di problemi con l'applicazione è necessario cercare in due punti. Spesso il codice di configurazione non è facilmente correlato al codice dell'applicazione principale.

Naturalmente la configurazione è anche al di fuori dei limiti di ciò che il compilatore (e spesso l'IDE) può controllare per te, il che significa che è molto più facile fare errori in questa configurazione che se stessi scrivendo una classe principale che gestiva il cablaggio. In effetti questo significa che i problemi di cablaggio sono spinti da problemi di compilazione a problemi di runtime.

Oltre a dividere l'applicazione, l'uso di DI Frameworks significa spesso che si utilizza @Inject o simile all'interno del codice, invece delle tradizionali tecniche DI (iniezione di interfaccia CTOR in Java / C ++, modello di iniezione in C ++). Lo svantaggio di questo è che deve quindi utilizzare un framework DI con l'applicazione. Un'alternativa sarebbe quella di progettare l'applicazione senza prevedere un framework DI e quindi consentire al framework DI di riutilizzare l'iniezione tradizionale CTOR / setter delle classi.

Lo svantaggio del meccanismo di iniezione tradizionale arriva quando una classe complessa e correttamente incapsulata richiede una serie di altre iniezioni relativamente complesse al momento del CTOR. Solitamente questo è risolto incorporando un Builder , ma può essere un dolore.

Modifica :

I ragazzi di seguito hanno menzionato che Guice non ha bisogno di una configurazione XML / JSON separata. La mia risposta vale davvero per il mio utilizzo di Spring.

    
risposta data 16.06.2014 - 16:42
fonte
4

Penso che il principale svantaggio dell'uso di un contenitore IoC sia tutta la magia che fa dietro le quinte. (Questo è anche un problema con gli ORM, un altro strumento magico comune.) Il debug dei problemi IoC non è divertente, perché diventa più difficile vedere come e quando vengono soddisfatte le dipendenze. Non puoi passare attraverso la risoluzione delle dipendenze nel debugger.

I contenitori spesso rendono difficile configurare "classe A con una versione di una dipendenza e classe B con una versione diversa" o scenari simili in cui le astrazioni vengono riutilizzate. Puoi finire in situazioni in cui ogni classe ha la sua interfaccia, anche quando significano la stessa cosa. Questo ti blocca dal potere di astrazione di riutilizzare le interfacce.

Secondo me, la grande vittoria che ottieni da IoC è la gestione automatica dello stile di vita. Puoi dichiarare componenti come singletons, singleton per richiesta, istanze transitorie e così via - e il contenitore si prenderà cura di tutto per te. È molto più difficile impostarlo usando new -expressions. D'altra parte, è ancora facile causare perdite di risorse per mismatching degli stili di vita.

Alcuni progetti usano IoC per costruire tutto nel sistema - anche classi che rappresentano dati aziendali - senza parole chiave new . Penso che questo sia generalmente un errore perché ti incoraggia a scrivere classi scarsamente incapsulate e troppe interfacce. Il tuo codice diventa dipendente da IoC. Sembra anche essere co-morboso con i test eccessivi.

Personalmente, generalmente preferisco andare senza un contenitore. Invece, compongo oggetti usando new -espressioni incapsulate in una composizione root. È facile vedere le dipendenze concrete di una data classe, e quando cambio un costruttore ottengo degli errori in fase di compilazione, entrambi sono vinti da una grande manutenzione. È anche semplice configurare istanze separate con componenti diversi.

Il mio consiglio, se si desidera utilizzare un contenitore IoC, è soddisfare le proprie dipendenze alla voce  point al sistema e usarlo solo per le dipendenze attuali (repositories et al). E ricorda che puoi ancora utilizzare l'integrazione delle dipendenze e persino mantenere la configurazione in un singolo file, senza usare un contenitore.

    
risposta data 18.06.2014 - 00:56
fonte
1

Alcuni sviluppatori sostengono che qualsiasi framework che usi nel tuo codice è un potenziale problema in un secondo momento, perché in genere richiede di scrivere il codice in un certo modo per interagire correttamente con esso, e questo può causare problemi in un secondo momento data se risulta che tali modi sono in conflitto con altri requisiti di progettazione. Un esempio di questa preoccupazione è espresso da Bob Martin qui . Non sono personalmente d'accordo, ma posso vedere il suo punto.

    
risposta data 16.06.2014 - 22:28
fonte
1

Riassumendo: sembra che l'unica complessità derivi dall'uso di metodi di configurazione impropri (sì, XML non è sicuro per il tipo) e probabilmente anche da framework che fanno molto più lavoro (Spring gestisce il ciclo di vita dell'oggetto, che va ben oltre il DI) .

Per un progetto semplice, DI fare bene è estremamente utile:

  • consente di scrivere servizi come minuscole classi immutabili con il minimo sforzo
  • assicura singletonness nel giusto ambito pur rimanendo testabile
  • richiede pochissima configurazione (circa 1 riga per 20 classi DI)

È anche abbastanza innocuo, in quanto potrebbe essere fatto manualmente. Sta solo creando le istanze, passandole ai costruttori per creare più istanze e così via. Noioso e lungo, ma semplice.

Un tipico servizio che usa Guice e Lombok è simile a questo

@Singleton
@RequiredArgsConstructor(onConstructor=@__(@Inject))
public class TotalCostsComputer {
    public CostsResult getCosts(Goods goods, Shippment shippment) {
        return taxComputer.applyTax(composeResult(
                    goodsCostComputer.getCosts(goods),
                    shippmentCostComputer.getCosts(shippment));
    }
    ...

    private final GoodsCostComputer goodsCostComputer;
    private final ShippmentCostComputer shippmentCostComputer;
    private final TaxComputer taxComputer;
}

Ora, aggiungere una dipendenza significa semplicemente aggiungere un nuovo campo finale privato . Non può essere nullo (Guice garantisce questo anche senza @NonNull ).

Test significa creare le proprie istanze o recuperarle dal Injector (possibilmente configurato per restituire alcuni stub). Entrambi sono piuttosto semplici.

    
risposta data 13.09.2014 - 06:49
fonte

Leggi altre domande sui tag