Da quanto descritto, sembra che il sistema generale non abbia confini ben definiti, probabilmente non del tutto ben progettati. Se possibile, fare un passo indietro, riflettere, ridisegnare i confini (suppongo che più di una squadra stia sviluppando il sistema, quindi i rappresentanti di ciascuno devono essere presenti, anche ops, se separati).
L'idea generale è di stabilire API minimalistiche tra i componenti. Probabilmente hai già una buona comprensione dei cambiamenti più frequenti, quindi conosci approssimativamente la stabilità relativa dei componenti. Una buona pratica è quella di rendere i componenti instabili dipendenti da quelli stabili e le dipendenze inverse con tutti quei bei modelli di design.
I sistemi problematici / legacy / che cambiano rapidamente potrebbero dover essere racchiusi in ciò che DDD (Domain-Design Design) chiama Anti-Corruption Layer. Aggiungi questo ai luoghi, che causano la maggior parte del dolore. In realtà, gli elementi del DDD possono aiutarti ad affrontare esattamente il tuo problema, anche se non segui la filosofia in ogni sua parte. Puoi iniziare ad esempio con la comprensione di contesti limitati e modi diversi per la loro integrazione, vedi ad esempio link . L'idea principale è rendere il sistema meno complesso, meglio allineato con le esigenze aziendali. I modelli tattici del DDD sono materia secondaria.
Un altro approccio utile è quello di mantenere le API (i tuoi contratti dati) con versione e mantenere un grafico della compatibilità della versione dei componenti . (qualcosa di simile a qualsiasi sistema di packaging, come quello di Debian). Ciò richiede una certa disciplina, ad esempio, essere parte della definizione di fatto per ogni rilascio di componente. So che sia Java che Elixir hanno sistemi eccellenti per gestire pacchetti dipendenti. Utensili? Tocca a voi. Personalmente trovo quelli semantici web: RDF / OWL e il motore di inferenza per essere all'altezza di tale compito, dichiarativo, facile da configurare e mantenere, anche se con la necessità di imparare alcuni principi del database grafico e linguaggio di interrogazione. Naturalmente, è necessario mantenere gli stati di stage / produzione in modo da poter dedurre la compatibilità del risultato, quindi è meglio essere collegati a qualche tipo di sistema di Continuous Delivery (difficile dire dove si è ora sulla scala del CD, ma automatizzare è la chiave).
Inoltre, le informazioni di pacchettizzazione / rilascio hanno un "master data" migliore nel sistema di orchestrazione / coreografia di distribuzione dei moduli, non nella parola MS. Certamente, gli strumenti multipiattaforma possono essere trovati per quello (forse, ci saranno risposte con le raccomandazioni degli strumenti). E memorizzare il grafico delle versioni del sistema può essere benissimo. Probabilmente, sarà necessario utilizzare versioni di rilascio anziché revisioni git per semplificare la manutenzione.
Per quanto riguarda il middleware, Elixir consente di comprendere il codice di scambio a caldo, il che significa che il middleware non deve fermarsi nemmeno per gestire lo switchover. In combinazione con il controllo delle versioni, significa che in molti casi è possibile utilizzare diverse versioni simultaneamente (il middleware non è legato allo schema del database rigido, vero?)
Questi contratti di dati, se si escogitano alcuni modi dichiarativi per descriverli a Swagger, possono essere la base per la documentazione, i test e anche la generazione automatica del codice per gli adattatori, che si può desiderare sui bordi di componenti.
Questa risposta non pretende di essere troppo specifica o onnicomprensiva. Prova a pensare fuori dagli schemi: sei il miglior esperto del tuo sistema.