Perché nel mio caso ho bisogno dell'iniezione di dipendenza e del principio di inversione delle dipendenze?

7

Sono uno studente di buone pratiche, schemi architettonici e principi di progettazione. Ho studiato molto l'iniezione di dipendenza e l'inversione di controllo molto ultimamente, e ho "bevuto la koolade" abbastanza spesso con molti dei miei progetti nell'ultimo mezzo anno o giù di lì.

Recentemente, sono entrato in una discussione su questo con il mio capo. Mi ha chiesto di esporre le virtù dell'iniezione di dipendenza, in particolare per quanto riguarda il nostro ambiente specifico. Non è egli stesso uno sviluppatore, ma ha una spiccata capacità di comprendere linguaggi di programmazione e concetti correlati. In particolare, voleva che gli spiegassi perché usare l'iniezione di dipendenza era meglio che avere una libreria principale che funge da API. In altre parole, è così che tradizionalmente architettiamo un'applicazione, che ha al suo interno un modulo infrastruttura (accesso ai dati):

equestoècomepotrebbeapparireusandoDIP/DI

Lefreccediciascundiagrammarappresentanoovviamenteladirezionedelladipendenza.

Glihodettocheilcodiceconaccoppiamentolentoèsempremiglioreperchéconsentediscambiarecomponentisenzainfluenzarealtreareedell'applicazioneedoverriscrivereunsaccodicodiceperindirizzareinuovicomponenti.Hospiegatochelacodificasuun'astrazionepiuttostochesuun'APIconcretaerapreferibileperchéticostringeapensareinterminiditaleastrazioneequindiglielementispecificidiqualsiasiimplementazioneconcretasonomenoprobabiliafiltrareinaltrimoduli.Hoanchespiegatocheèpiùsemplicetestareicomponentiinisolamentoeutilizzareimockperisistemiesterni.

Impostandoilragionamentodiprovaaparteperilmomento,volevasapereperchénonpotevamosemplicementemodificareilmodulodell'infrastrutturasenzainfluiresullasuainterfacciapubblica.Adesempio,sedecidessimodipassaredaSQLServeraOraclecometecnologiadipersistenza,potremmosemplicementeapportaretalimodifichealmodulodiaccessoaidatieimodulisopradiessononsarebberopiùsaggi.

Nonavevounabuonarispostaperlui(oltreaivantaggiperitest).PoichéèimprobabilechepassiamodaSQLServeraOraclenelnostroambienteparticolare,tuttociòchepotevofareera"è solo la miglior pratica" e ribadire le ragioni che ho affermato prima.

Cos'altro avrei potuto dire per rafforzare la mia argomentazione?

    
posta rory.ap 18.11.2016 - 20:50
fonte

2 risposte

7

L'obiettivo principale del principio di inversione delle dipendenze è la direzione di cambiamento della dipendenza.

Nel tuo livello di interfaccia utente di esempio dipendono dal livello Presentazione e il livello Presentazione dipende dal livello della logica aziendale. Quindi, se apporti una modifica alla logica aziendale, devi ricompilare tutti i livelli, perché hanno dipendenza dal livello inferiore.

why can't we just modify the implementation in situ given that it won't affect the modules that depend on it because we only change internal aspects of the implementation and leave the public API alone

Perché vogliamo isolare i dettagli / le modifiche di implementazione dai livelli di livello superiore.
Quando apportiamo modifiche nel livello di livello inferiore, vogliamo ricompilare solo questo livello.

Ecco perché il livello più alto deve fornire un'interfaccia che si aspetta da livelli inferiori. Lo strato inferiore implementerà questa interfaccia.

Quindi nella tua applicazione finirai solo con un livello, entry point di applicazione, che avrà dipendenze su tutte le implementazioni. Il ruolo di questo livello per combinarli insieme.
Qui l'Iniezione delle Dipendenze aiuterà. La maggior parte dei framework di injection Dependency offrono la possibilità di caricare in modo dinamico tutte le dipendenze (implementazioni). Che danno come possibilità di aggiornare il nostro software senza reinstallarlo, fornirai all'utente solo la libreria di implementazione aggiornata.

nota la direzione delle frecce di dipendenza

     Run-time dependencies                Compile-time dependencies
-------------------------------        -------------------------------
|                             |        |                             |
|          UI Layer           |        |          UI Layer           |
|                             |        |                             |
----INeededBehvaiorInterface---        ----INeededBehvaiorInterface---
               |                                     ^
               v                                     |
 ------------------------------         ------------------------------
|                             |        |                             |
|        Business logic       |        |        Business logic       |
|                             |        |                             |
-----IDataServiceInterface-----        -----IDataServiceInterface-----
               |                                     ^
               v                                     |
 ------------------------------         ------------------------------
|                             |        |                             |
|          Data layer         |        |          Data layer         |
|                             |        |                             |
-------------------------------        -------------------------------
    
risposta data 18.11.2016 - 23:02
fonte
3

Il modo in cui imposti l'esempio e la domanda rende la risposta davvero difficile in quanto ciò che presenti qui è una generalizzazione; quindi, le tue risposte al tuo capo sono argomenti generali (che, a proposito, sono perfettamente corretti). Sento che si può fare un caso strong se si guardano esempi specifici e si mostrano i benefici.

In generale, ecco alcune note / idee:

  1. Non penso che i tuoi secondi grafici mostrino correttamente il concetto DI. La risposta di Fabio cerca di mostrare meglio i confini e in che modo DI può andare bene

  2. Robert ha cercato di sollevare un altro punto importante quando ti ha chiesto di chiarire a quale astrazione ti riferisci quando scrivi "la codifica su un'astrazione piuttosto che su un'API concreta era preferibile". Penso che il giusto significato sia codificare contro l'astrazione e non contro IMPLEMENTATION poiché le API sono un'espressione di astrazione per definizione

  3. Basandosi su (2), ciò che si ottiene anche con l'approccio DI e, di conseguenza, con l'uso delle interfacce, è l'espandibilità (il principio "Apri / Chiudi" nella progettazione SOLID). Ecco un esempio:

Say YouBusinessLayer accetta IDataRepository e quest'ultimo fornisce l'accesso a SQL Server.

Come dici correttamente, se si passa a Oracle è possibile sviluppare un nuovo IDataRepository (OracleDataRepo) discendente e collegarlo a YourBusinessLayer (OracleDataRepo) anziché a YourBusinessLayer (SQLDataRepo).

Quindi, ora hai questa gerarchia:

IDataRepository - > OracleDataRepo e IDataRepository - > SQLDataRepo

In questa fase, il tuo capo ha un punto perché puoi modificare l'implementazione.

Ma che ne dici se vuoi fornire funzionalità aggiuntive al livello dati esistente. Non conosco i dettagli del tuo caso quindi spero di scegliere un caso pertinente: ad esempio, vuoi utilizzare un servizio di registrazione da un fornitore terzo che ha caricato i dati su un server.

Se si utilizza la progettazione corrente, è necessario utilizzare l'ereditarietà e il polimorfismo e se si dispone delle classi Oracle e SQL è necessario aggiornarle entrambe. Usando DI e interfacce, si guarda al repository IData e si modifica solo in un punto del codice.

Quindi, che ne pensi se hai un altro team responsabile dello sviluppo di parte del tuo livello di accesso ai dati (di nuovo, non conosci i dettagli effettivi del tour). Dì, il logger è sviluppato da qualcun altro. Come lavoreranno nella tua classe? Devi smettere di lavorare e dare loro l'accesso al tuo codice.

Con interfacce e DI, le cose funzionano bene favorendo la composizione invece dell'ereditarietà. Ciò significa che si utilizza l'iniezione della dipendenza per ricevere il registratore tramite un'interfaccia.

E un ultimo esempio a cui posso pensare è questo: che ne dici se i tuoi clienti (o gli utenti del livello di accesso ai dati) hanno esigenze diverse in termini di funzionalità e non vuoi esporre tutte le funzionalità a tutti. Con DI e interfacce, si eredita IDataRepository, si applicano le regole di conseguenza e quindi la vecchia dichiarazione YourBusinessLayer (SQLDataRepo) consumerà la nuova interfaccia in modo gradevole.

    
risposta data 19.11.2016 - 23:52
fonte