Come ti avvicini ai conflitti di dipendenza transitiva conosciuti solo in fase di esecuzione? [chiuso]

9

In che modo affronterai normalmente i problemi di dipendenza transitoria che si verificano in fase di esecuzione in progetti software di grandi dimensioni?

Nelle ultime tre settimane, ho cercato di avviare un componente di un grosso pezzo di software all'interno di un altro componente del software, ma muore in modo intermittente a causa di problemi di dipendenza transitiva che sono noti solo in fase di esecuzione.

Per problemi di dipendenza transitiva, intendo che certe dipendenze delle dipendenze di un determinato progetto si scontrano con altre dipendenze in fase di esecuzione, causando instabilità o errore immediato.

Esistono centinaia e centinaia di dipendenze in uso e ci sono circa 50 sottoprogetti associati allo strumento su cui si lavora isolatamente da altri team, in cui tutti i moduli hanno dipendenze profondamente nidificate l'una dall'altra. Nessuno sa a cosa servono tutti i sottoprogetti, date le dimensioni e la complessità del progetto.

In questa situazione, proveresti a generare una rappresentazione visiva del DAG per ciascuna delle dipendenze del componente interessato e tentare di determinare dove potrebbero verificarsi collisioni durante l'esecuzione? Non ho alcun controllo su come le dipendenze sono gestite in altri sottoprogetti e non posso modificare alcun codice Java che sia stato scritto da altri sviluppatori

Le soluzioni che ho trovato funzionano solo per un'ora o due e poi smettono di funzionare a causa di cambiamenti nei componenti upstream. Un esempio di un componente upstream è un artefatto su cui il progetto a cui sto lavorando dipende da quale è stato costruito in una fase precedente nella pipeline CI.

Alle richieste di altri , includerò informazioni su quale tecnologia viene utilizzata, con il rischio di chiudere la domanda per fornire troppe informazioni o il corpo troppo lungo:

  • Maven è usato per la gestione delle dipendenze; e
  • Spring viene utilizzato come contenitore DI;
  • La maggior parte dei problemi di dipendenza coinvolge contesti di bean sovrapposti come risultato dei contesti di altri moduli caricati in fase di esecuzione
  • Il prodotto funziona correttamente e ci sono smorgasbords di unit test e test di integrazione per eludere alla correttezza funzionale del programma

In generale, sto cercando un approccio indipendente dalla lingua per identificare i modi di risolvere i conflitti di dipendenza senza enumerare tutte le possibili combinazioni delle dipendenze di un dato progetto.

Non riesco a riprogettare il progetto, aggiungere ulteriori gate di qualità, spingere per cambiamenti di paradigma in tutta l'azienda o cambiare lingua come risoluzione.

    
posta Tyler 24.08.2015 - 18:00
fonte

4 risposte

6

Potrebbe essere possibile risolvere il problema utilizzando i classloader personalizzati per assegnare a ciascun modulo nell'applicazione il proprio ambiente di esecuzione.

Fondamentalmente, definiresti un ambiente principale che consiste in un piccolo kernel dell'applicazione, insieme a tutte le dipendenze universalmente concordate e tutte le interfacce necessarie per i moduli per comunicare tra loro. Quindi, ogni modulo caricato riceve il proprio classloader che può accedere a (1) classi dall'ambiente di runtime, (2) classi dal nucleo dell'applicazione e (3) classi da quel modulo e le sue dipendenze dirette. Tutte le comunicazioni tra moduli passano attraverso interfacce definite nel core in modo che nessun modulo dipenda direttamente da un altro.

Questa tecnica viene utilizzata nei server delle applicazioni per consentire alle applicazioni di avere dipendenze che altrimenti si scontrano, quindi puoi vedere un'implementazione funzionante della tecnica, ad esempio, in Tomcat (e, se sei fortunato, potresti essere in grado utilizzare l'implementazione di Tomcat con pochi cambiamenti).

    
risposta data 25.08.2015 - 16:41
fonte
4

Non ho mai lavorato con Maven o Spring, ma per darti una risposta generica a una domanda generica: quando si tratta di problemi di dipendenza, il tuo sistema dovrebbe essere progettato per rilevarli nel più breve tempo possibile e quando tali problemi vengono rilevati, devono essere segnalati immediatamente, inclusa la loro possibile causa.

Idealmente, questo punto nel tempo non è al "tempo di esecuzione della produzione". Il momento migliore è "tempo di costruzione", ma nel tuo caso sembra impossibile. Quindi la seconda opzione migliore sono i test di funzionamento. Ci hai detto che ci sono "test di integrazione", ma poiché non rilevano i problemi di dipendenza, sembrano incompleti o non testano le collisioni di dipendenza in generale. Ecco dove dovresti iniziare a provare a risolvere il problema.

Inoltre, per rendere i test più efficaci, i tuoi componenti devono "fail-fail" quando si verifica un problema di dipendenza. Ciò significa che non appena una dipendenza viene risolta e un componente viene caricato, le potenziali collisioni di dipendenza devono essere verificate e segnalate immediatamente. Se il sistema funziona per un'ora prima che venga rilevata una collisione, diventa molto difficile individuare la causa del problema. Non so se Maven / Spring ti fornisce già una strategia "fail fast" integrata, ma se non è così, prova a pensare in quella direzione.

Per mitigare i problemi nella produzione, il tuo sistema dovrebbe essere progettato per non morire completamente quando si verifica una collisione di dipendenza con un sottocomponente meno importante coinvolto. L'errore non dovrebbe essere mascherato, ovviamente, ma il sistema dovrebbe idealmente rifiutare il caricamento di quel componente, registrare e / o segnalare il problema e rimanere in uno stato stabile. Quando il componente viene caricato per primo, il sistema diventa instabile e si rileva il problema solo in seguito, quindi probabilmente sarà necessario arrestare e riavviare il sistema completamente, il che credo sia qualcosa che è meglio evitare.

Ad esempio, se il tuo sistema è un negozio Web e il tuo sottomodulo per "iscrizione alla newsletter" non può essere caricato per alcune ore, è qualcosa che potrebbe essere più facilmente tollerato come se l'intero negozio non funzionasse più.

Infine, questa potrebbe non essere un'opzione nel tuo caso, ma se i componenti possono essere eseguiti in un isolamento migliore l'uno contro l'altro e se ciò può evitare le collisioni di dipendenza, potrebbe essere un approccio che vale la pena di pensare.

    
risposta data 25.08.2015 - 16:27
fonte
2

Considera questo solo pensando a voce alta qui. A seconda dei requisiti / limiti di tempo, potrei considerare questo:

1) crea un elenco di interfacce e le relative implementazioni (utilizzando la reflection, se disponibile)

2) crea una sorta di wrapper attorno al tuo DI. Quando viene chiesto a un DI di fornire un'implementazione concreta, verifica se esiste già una regola DI; se la regola esiste, basta restituire ciò che fornisce la DI; altrimenti se c'è una singola implementazione di un'interfaccia e sei in grado di creare un'istanza - registra e restituisci un'istanza; altrimenti registra e fallisce.

Dipende da quanto vuoi ottenere, suppongo, ma alla fine vuoi solo avere una lista completa di ciò che richiede cosa - questa soluzione alla fine genererà quella lista.

Tuttavia, probabilmente questo è un sacco di lavoro e non è affidabile - cosa succede se hai una strana condizione che richiede una certa dipendenza una volta in una luna blu?

Che cosa intendi quando dici "cambiamenti nei componenti upstream"?

    
risposta data 24.08.2015 - 22:52
fonte
2

Se ti seguo correttamente, il problema è che il codice che devi usare ha dipendenze di run-time sui moduli espresse in XML Spring, ma a Maven non viene detto nulla. Quindi quando li usi le cose di cui hanno bisogno (le dipendenze transitive) non sono sul tuo classpath, e non fanno quello che dovrebbero.

Sto indovinando quando chiedi ai tuoi colleghi 'come faccio a far funzionare tutto questo?', dicono 'ovviamente hai bisogno di questa lista di 35 moduli e versioni , come potresti non sapere che ? '

Presumibilmente al termine dei test di integrazione, i moduli richiesti vengono dichiarati come dipendenze di test. Pertanto, la soluzione sistematica consiste nell'impostare le ispezioni dei test di integrazione per assicurarsi che non abbiano altro che strumenti di test di terze parti dichiarati come dipendenze di test. Questo potrebbe anche essere automatizzato dal plug-in per maven enforcer .

Apparentemente non puoi farlo, quindi la tua migliore opzione è probabilmente trovata qui .

    
risposta data 26.08.2015 - 02:15
fonte

Leggi altre domande sui tag