Definiamo l’accoppiamento software come il numero di connessioni inter-modulo nei sistemi software, ed è spesso considerato la chiave di lettura per identificare la difficoltà nel mantenere, scalare, e spesso anche migliorare, l’applicativo stesso.
Più l’accoppiamento è elevato, maggiore sarà il costo necessario per implementare nuove funzioanlità, perchè il rischio di rompere ciò che già esiste e funziona, è altissimo. Ma siamo sicuri che esista un solo tipo di coupling? Siamo certi che tutto l’accoppiamento sia da rimuovere per avere una codebase pulita, testabile, scalabile, etc? Vediamo di capire quali tipi di coupling esistono, e quali sono quelli da considerare dannosi
Static vs Dynamic
Prima di definire cos’è statico e cos’è dinamico abbiamo bisogno di definire cosa intendiamo per modulo software. Un modulo è un insieme di componenti altamenti coesi fra loro, che concorrono a risolvere un problema di business. Può essere composto da diverse classi, sia astratte che concrete, interfacce, etc. Ogni modulo è poi disaccopiato dagli altri, per garantirne l’indipendenza logica.
Ciò detto, si definisce dipendenza statica una dipendenza interna al modulo, fra i componenti del modulo stesso, ed estendo il concetto, una dipendenza è statica se è indispensabile all’avvio del modulo stesso, o del microservizio stesso se estendiamo il concetto di modulo.
Si definisce dipendenza dinamica una dipendenza esterna al modulo, che serve al modulo, oppure al microservizio, quando questo è stato avviato.
Nel caso di microservizi che dialogano fra loro utilizzando un service bus, la dipendenza verso il service bus è una dipendenza statica, in quanto è indispensabile, al momento dell’avvio del microservizio, caricare questa dipendenza per poter pubblicare messaggi. Nel momento in cui un microservizio pubblica un messaggio, diventa una dipendenza dinamica.
Afferent vs Efferent
L’accoppiamento di tipo afferent misura il numero di connessioni in ingresso ad un componente, o modulo. Ossia, quanto un componente dipende dagli altri.
L’accoppiamento di tipo effrent misura le connnessioni in uscita verso altri componenti, o moduli.
Nel 1990, Robert Martin, in occasione di un libro sul linguaggio C++, ha creato alcume metriche, che sono applicabili ad ogni linguaggio object-oriented, che servono a misurare l’equilibrio interno di una codebase, abstractness e instability.
Abstractness è il rapporto fra la somma di tutti i componenti astratti (classi astratte, interfacce, etc) e i componenti concreti. Rappresenta la misura di astrazione verso l’implementazione degli oggetti che compongono il nostro modulo. Una codebase con un singolo metodo main() e migliaia di righe di codice avrà un indice di astrazione molto vicino allo 0, ma risulterà alquanto difficile da comprendere. La formula per ottenere questo indice è
A = {\sum m^a} \over {\sum m^a + \sum m^c}
Dove m^a rappresenta un componente astratto, e m^c un componente concreto.
Instability è inceve il rapporto fra l’accoppiamento efferente e la somma fra l’accoppiamento afferente e quello efferente
I = {C^e} \over {C^e + C^c}
L’instabilità rappresenta la volatilità della nostra codebase. Più questo indice si avvicina ad 1 più il nostro codice sarà instabile, ma è altrettanto vero che un valore tendente a 0 indica una codebase molto stabile ed al contempo molto rigida, in quanto priva di astrazione.
In generale è importante non soffermarsi solo su uno di questi due indici, ma piuttosto valutarli nel loro insieme.
In conclusione
Dopo aver definito maggiormente cosa intendiamo per accoppiamento possiamo cominciare a trarre qualche conslusione un pò più sensata su quanto pesa il couplingall’interno della nostra codebase. Sicuramente se l’accoppiamento è di tipo statico, all’interno di un modulo, non ci deve preoccupare più di tanto, perchè questo modulo, o addirittura questo microservizio, verrà sempre distribuito come un’unica unità. Viceversa, se l’accoppiamento statico è fra moduli diversi, o peggio, fra microservizi diversi, allora ci dovremo preoccupare, perchè sarà impossibile rilasciare l’uno senza interferire sulle funzionalità dell’altro.
Anche il tipo di accoppiamento efferente o afferente ci aiuta a capire quanto siamo liberi di rilasciare il nostro modulo con tranquillità. Se il numero di connessioni in uscita è elevato, avremo le mani legati in fase di rilascio, perchè molti altri moduli dipendono dal nostro, e non possiamo rilasciare qualcosa che compromette il funzionamento del sistema stesso.
Questa è solo una piccola panoramica del mondo del coupling e delle sue ripercussioni sul nostro codice, se avete commenti in merito, fatemi sapere.