Agile Architecture: partizionamento (modularità)

Nel precedente post dedicato all’Uso e al Riuso dei moduli e di come queste due caratteristiche sono in rapporto indiretto, abbiamo lasciato in sospeso il discorso relativo a come affrontare il problema del partizionamento del sistema in moduli (modularità).

Prima di approfondire tale aspetto, è opportuno spendere qualche parola di dettaglio sulla differenza tra modulo e componente, già introdotta sempre nel post precedente. Un Modulo è un’entità statica, che serve a decomporre un sistema complesso in componenti più semplici, possibilmente afferenti ad un determinato dominio, relazionati tra loro dalle seguenti associazioni fondati:

  • . Is part of: indica la relazione di appartenenza di un sotto modulo ad un modulo aggregatore;
  • . Depends of: indica la dipendenza diretta tra due moduli;
  • . Is a: definisce una generalizzazione/specializzazione tra moduli.

relazioni module styles

Figura 1: Le tre relazioni fondamentali nelle relazioni tra moduli

Un Componente è, invece, un entità dinamica, dotata di uno stato, le cui viste relative vengono tipicamente definite dopo quelle dei moduli, senza il vincolo che la relazione tra modulo e componente sia di 1:1.

Un’analogia abbastanza utile per comprendere la relazione tra Modulo e Componente è quella tra Classe e Oggetto nella programmazione Object Oriented: è possibile pensare al Modulo come ad una Classe e al Componente come ad un Oggetto.

Riprendiamo ora l’argomento oggetto del post, introducendo la definizione di Tensione Modulare (Modular Tension), ovvero la necessità di bilanciare opportunamente proprio Uso e Riuso.

Chiaramente il partizionamento dota il sistema di alcune caratteristiche fondamentali, che caratterizzano direttamente la tensione:

  • . Cohesion (Coesioni): ogni modulo ha uno scope ben definito e concentra in esso le relative funzionalità. Ciò favorisce un disaccoppiamento (o basso accoppiamento, loose coupling) dei moduli;
  • . Maintance (Manutenibilità): comunque si effettuata la scomposizione, un modulo è sicuramente meno complesso dell’intero sistema a cui afferisce. E’ quindi più semplice da manutenere;
  • . Extensibility (Estensibilità): i moduli sono caratterizzati da un’interfaccia d’uso ben definita. Ciò permette di modificare internamente il modulo e addirittura di sostituirlo senza impattare sull’aspetto funzionale del sistema. Attenzione: ciò può non essere vero per gli aspetti qualitativi.

modularitymaintenance

Un sistema estremamente modulare, quindi composto da molti moduli a grana fine (Fine-grained) e poco legato all’ambiente operativo (Lightweight), è sicuramente più facile da manutenere ed estendere e quindi da Riusare, ma ha complessità intrinseche come la comunicazione (orchestrazione) tra i moduli e la difficoltà di valutare l’impatto generale della una modifica di uno di essi se il numero dei moduli è relativamente alto (context dependencies).

Al contrario, un sistema poco modulare, quindi composto da moduli a grana spessa (Coarse-grained) e legati all’ambiente di esecuzione (Heavyweight), è più difficile da manutenere perché più complesso, ma è più semplice da Usare e sostituire perché la specifica macro-funzionalità è svolta interamente dal modulo stesso.

Il tutto si riassume nell’enunciato già presentato nel post precedente: Maximizing reuse complicates use, e, graficamente, nella relativa immagine dove la Tensione Modulare è rappresentata dalla line difforme di colore verde nella figura 2. 

use vs reuse

Figura 2 - in verde la Tensione Modulare

A questo punto una domanda è d’obbligo: come scegliere il giusto livello di modularità del sistema? Appare quantomeno scontato che non esista una formula magica che possa risolvere il problema, ma è possibile ricorrere a delle “best practice” note come module styles. 

use vs reuse modules styles

Figura 3 - Module Styles

Si tratta di una serie di soluzioni architetturali (attenzione, Architetturali e non di Design), tra le quali troviamo:

  • . Decomposition Style, focalizzato sulla relazione “is-part-of”;
  • Uses Style, focalizzato sulla relazione “depends-on”;
  • Generalization Style, focalizzato sulla relazione “is-a”;
  • Layered Style, focalizzato sulla relazione “allowed-to-use”;
  • Aspect Style, focalizzato su quelli che vengono definiti “Aspetti”, ovvero; caratteristiche/elementi trasversali che attraversano i vari moduli (esempio: il logging);
  • Data Model Style, focalizzato sulla rappresentazione delle relazioni tra i dati (entità).

Questi stili permettono di organizzare in modo efficace i moduli, preparando la relativa vista ad essere poi di supporto alla creazione della vista Component & Connector (C&C), di cui parleremo nei prossimi post. 

layered style

Figura 4 - Layerd Style

agileiot logo  ac2 logodac dac dacdac dac psmii psmii safesafe cal1 less certazure fundamentals
mvp reconnect