Modellazione dell'architettura di un sistema software
Per assicurarsi che il sistema software o l'applicazione soddisfi le necessità degli utenti, è possibile creare modelli in Visual Studio Ultimate durante la descrizione della struttura complessiva e del comportamento del sistema software o dell'applicazione. Utilizzando i modelli è inoltre possibile descrivere i criteri che vengono utilizzati in tutta la progettazione. Tramite i modelli è possibile comprendere l'architettura esistente, discutere le modifiche e comunicare chiaramente le intenzioni.
Lo scopo di un modello è quello di ridurre le ambiguità che si verificano nelle descrizioni del linguaggio naturale e consentire a tutti i colleghi di visualizzare la progettazione e discutere le progettazioni alternative. Un modello deve essere utilizzato insieme ad altri documenti o discussioni. Un modello da solo non rappresenta una specifica completa dell'architettura.
Nota
In questo argomento, per "sistema" si indica il software che si sta sviluppando. Potrebbe trattarsi di un insieme di grandi dimensioni di molti componenti software e hardware, di una singola applicazione o di una parte di un'applicazione.
L'architettura di un sistema può essere divisa in due aree:
Progettazione ad alto livello. Descrive i componenti principali e il modo in cui interagiscono per soddisfare ogni requisito. Se il sistema è di grandi dimensioni, ogni componente potrebbe disporre di una propria progettazione ad alto livello che indica come è costituito da componenti più piccoli.
Modelli di progettazione e convenzioni utilizzati in tutte le progettazioni dei componenti. Un modello descrive un particolare approccio per realizzare un obiettivo di programmazione. Utilizzando gli stessi modelli in tutta una progettazione, il team può ridurre il costo delle modifiche e lo sviluppo del nuovo software.
Progettazione ad alto livello
Una progettazione ad alto livello descrive i componenti principali del sistema e il modo in cui interagiscono per realizzare gli obiettivi della progettazione. Le attività nell'elenco seguente sono implicate nello sviluppo della progettazione ad alto livello, anche se non necessariamente in una particolare sequenza.
Se si aggiorna il codice esistente, è possibile iniziare descrivendo i componenti principali. Assicurarsi di individuare ogni modifica ai requisiti dell'utente, quindi aggiungere o modificare le interazioni tra i componenti. Se si sviluppa un nuovo sistema, è possibile iniziare individuando le funzionalità principali delle necessità degli utenti. È possibile esplorare le sequenze di interazioni per i casi di utilizzo principali, quindi consolidare le sequenze in una progettazione del componente.
In ogni caso, è utile sviluppare le diverse attività in parallelo e il codice e i test nella fase iniziale. Evitare di tentare di completare uno di questi aspetti prima di iniziarne un altro. In genere, i requisiti e l'individuazione della modalità più adatta a progettare il sistema cambiano mentre si scrive e si controlla il codice. Pertanto, è necessario iniziare individuando e codificando le funzionalità principali dei requisiti e della progettazione. Compilare i dettagli nelle successive iterazioni del progetto.
Individuazione dei requisiti. Il punto iniziale di qualsiasi progettazione è una chiara individuazione delle necessità degli utenti.
Modelli d'architettura. Le scelte effettuate sulle tecnologie principali e sugli elementi d'architettura del sistema.
Componenti e relative interfacce. È possibile disegnare diagrammi componente per mostrare le parti principali del sistema e le interfacce tramite le quali interagiscono. Le interfacce di ogni componente includono tutti i messaggi identificati nei diagrammi di sequenza.
Interazioni tra componenti. Per ogni caso di utilizzo, evento o messaggio in arrivo, è possibile disegnare un diagramma di sequenza che mostra come i componenti principali del sistema interagiscono per realizzare la risposta richiesta.
Modello di dati di componenti e interfacce. È possibile disegnare diagrammi classi per descrivere le informazioni passate tra componenti e archiviate nei componenti.
Individuazione dei requisiti
La progettazione ad alto livello di un'applicazione completa viene sviluppata più efficacemente insieme con un modello requisiti o altra descrizione delle necessità degli utenti. Per ulteriori informazioni sui modelli requisiti, vedere Modellazione dei requisiti utente.
Se il sistema da sviluppare è un componente di un sistema più grande, i requisiti potrebbero totalmente o parzialmente essere incorporati nelle interfacce di programmazione.
Il modello requisiti fornisce queste informazioni essenziali:
Interfacce fornite. Un'interfaccia fornita elenca i servizi o le operazioni che il sistema o il componente deve fornire agli utenti, ovvero persone o altri componenti software.
Interfacce richieste. Un'interfaccia richiesta elenca i servizi o le operazioni che il sistema o il componente può utilizzare. In alcuni casi, sarà possibile progettare tutti questi servizi come se facessero parte del sistema. In altri casi, specialmente se si progetta un componente che può essere combinato con altri componenti in molte configurazioni, l'interfaccia richiesta sarà impostata dalle considerazioni esterne.
Requisiti di qualità del servizio. Le prestazioni, la sicurezza, la robustezza e gli altri obiettivi e vincoli che il sistema deve soddisfare.
Il modello requisiti è scritto dal punto di vista degli utenti del sistema, siano essi persone o altri componenti software. che non conoscono i meccanismi interni del sistema. Al contrario, l'obiettivo di un modello d'architettura è quello di descrivere i meccanismi interni e mostrare come soddisfano le necessità degli utenti.
Tenere i requisiti e i modelli d'architettura separati è utile perché rende più semplice la discussione dei requisiti con gli utenti. Consente inoltre di effettuare il refactoring della progettazione e considerare architetture alternative mentre i requisiti restano invariati.
È possibile separare i requisiti e i modelli d'architettura in due modalità alternative:
Tenerli nella stessa soluzione ma in progetti diversi. Saranno visualizzati come modelli separati in Esplora modelli UML. Membri del team diversi possono operare in parallelo sui modelli. È possibile creare tipi limitati di traccia tra i modelli.
Inserirli nello stesso modello UML, ma in pacchetti diversi. In tal modo è più semplice tracciare le dipendenze tra i modelli, ma solo una persona per volta può lavorare sul modello. Inoltre, un modello molto grande impiegherà più tempo per essere caricato in Visual Studio. Questo approccio è pertanto meno adatto ai grandi progetti.
I dettagli che devono essere inseriti in un requisito o un modello d'architettura dipendono dalla scala del progetto e dalla dimensione e dalla distribuzione del team. Un piccolo team di un progetto contenuto potrebbe non andare oltre a un abbozzo di un diagramma classi dei concetti aziendali e alcuni modelli di progettazione, mentre un grande progetto distribuito su più di un paese avrebbe bisogno in modo significativo di più dettagli.
Modelli d'architettura
Nella fase iniziale di uno sviluppo, è necessario scegliere le tecnologie e gli elementi principali sulle quali dipende la progettazione. Le aree nelle quali devono essere fatte queste scelte includono gli elementi seguenti:
Scelte di tecnologia di base, quale la scelta tra un database e un file system e la scelta tra un'applicazione in rete e un client Web e così via.
Scelte dei framework, quale una scelta tra Windows Workflow Foundation o ADO.NET Entity Framework.
Scelte del metodo di integrazione, ad esempio tra un bus del servizio aziendale o un canale point-to-point.
Queste scelte vengono frequentemente determinate dai requisiti di qualità del servizio quale la scala e la flessibilità e possono essere effettuate prima che siano noti i requisiti dettagliati. In un grande sistema, la configurazione dell'hardware e del software è correlata fortemente.
Le selezioni effettuate interessano la modalità di utilizzo e interpretazione del modello d'architettura. Ad esempio, in un sistema che utilizza un database, le associazioni in un diagramma classi potrebbero rappresentare relazioni o chiavi esterne nel database, mentre in un sistema basato su file XML, le associazioni potrebbero indicare riferimenti incrociati che utilizzano XPath. In un sistema distribuito, i messaggi in un diagramma di sequenza possono rappresentare messaggi su una connessione, mentre in un'applicazione indipendente, possono rappresentare chiamate di funzione.
Componenti e relative interfacce
I principali consigli di questa sezione sono:
Creare diagrammi componente per mostrare le parti principali del sistema.
Disegnare le dipendenze tra i componenti o le interfacce per mostrare la struttura del sistema.
Utilizzare le interfacce sui componenti per mostrare i servizi che ogni componente fornisce o richiede.
In una progettazione di grandi dimensioni, è possibile disegnare diagrammi separati per scomporre ogni componente in parti più piccole.
Questi punti vengono trattati nella parte restante di questa sezione.
Componenti
Le viste centrali di un modello d'architettura sono i diagrammi componente che mostrano le parti principali del sistema e come dipendono l'uno dall'altro. Per ulteriori informazioni sui diagrammi componente, vedere Diagrammi dei componenti UML: riferimento.
Un diagramma componente tipico per un grande sistema potrebbe includere componenti come i seguenti:
Presentazione. Il componente che fornisce l'accesso all'utente, in genere in esecuzione su un browser Web.
Componenti del servizio Web. Fornisce la connessione tra client e server.
Controller del caso di utilizzo. Guida l'utente nei passaggi di ogni scenario.
Base aziendale. Contiene le classi basate sulle classi nel modello requisiti, implementa le operazioni principali e impone i vincoli aziendali.
Database. Archivia gli oggetti business.
Componenti di gestione degli errori e registrazione.
Dipendenze tra componenti
Oltre ai componenti, è possibile mostrare le dipendenze che intercorrono tra loro. Una freccia di dipendenza tra due componenti mostra che le modifiche nella progettazione di uno potrebbero influire sulla progettazione dell'altro. Di solito questo si verifica perché un componente utilizza i servizi o le funzioni forniti dall'altro componente, direttamente o indirettamente.
Un'architettura ben strutturata dispone di una disposizione chiara delle dipendenze nella quale sono vere queste condizioni:
Non ci sono cicli nel grafico delle dipendenze.
È possibile disporre i componenti in livelli nei quali ogni dipendenza va da un componente di un livello a un componente del livello successivo. Tutte le dipendenze tra due livelli vanno nella stessa direzione.
È possibile mostrare direttamente le dipendenze tra componenti o le dipendenze tra interfacce richieste e fornite che sono associate ai componenti. Tramite le interfacce è possibile definire le operazioni che vengono utilizzate in ogni dipendenza. In genere, le dipendenze vengono mostrate tra i componenti quando i diagrammi vengono disegnati per la prima volta e vengono sostituite quindi dalle dipendenze tra le interfacce quando vengono aggiunte ulteriori informazioni. Entrambe le versioni sono descrizioni corrette del software, ma la versione con le interfacce fornisce più dettagli della versione precedente.
La gestione di dipendenze è molto importante per la produzione di software gestibile. I diagrammi componente devono riflettere tutte le dipendenze nel codice. Se il codice esiste già, verificare che tutte le dipendenze vengano mostrate nei diagrammi. Se il codice deve essere sviluppato, verificare che non includa dipendenze non pianificate nel diagramma componente. Per semplificare l'individuazione delle dipendenze nel codice è possibile generare diagrammi livello. Per assicurarsi che vengano soddisfatti i vincoli di dipendenza pianificati, è possibile convalidare il codice rispetto ai diagrammi livello. Per ulteriori informazioni, vedere Diagrammi livello: riferimento.
Interfacce
Posizionando le interfacce sui componenti, è possibile separare e denominare i gruppi principali delle operazioni fornite da ogni componente. Ad esempio, i componenti di un sistema di vendite basato sul Web potrebbero disporre di un'interfaccia tramite la quale i clienti acquistano beni, un'interfaccia tramite la quale i fornitori aggiornano i cataloghi e una terza interfaccia tramite la quale viene gestito il sistema.
Un componente può disporre di un numero illimitato di interfacce fornite e richieste. Le interfacce fornite mostrano i servizi che il componente fornisce per altri componenti. Le interfacce richieste mostrano i servizi che il componente utilizza in altri componenti.
Se si definiscono le interfacce fornite e richieste, sarà possibile separare chiaramente il componente dal resto della progettazione, in modo da poter utilizzare le seguenti tecniche:
Posizionare il componente in un test harness nel quale i componenti circostanti sono simulati dal test harness.
Sviluppare il componente indipendentemente da altri componenti.
Riutilizzare il componente in altri contesti accoppiando le interfacce a componenti diversi.
Quando si desidera definire l'elenco delle operazioni in un'interfaccia, è possibile creare un'altra visualizzazione dell'interfaccia in un diagramma classi UML. A tale scopo, individuare l'interfaccia in Esplora modelli UML e trascinarla su un diagramma classi. È possibile aggiungere quindi operazioni all'interfaccia.
Un'operazione in un'interfaccia UML può rappresentare una modalità per richiamare un comportamento di un componente. Potrebbe rappresentare una richiesta del servizio Web, un segnale o un'interazione di altro tipo oppure una comune chiamata di funzione del programma.
Per determinare le operazioni da aggiungere, creare diagrammi di sequenza per mostrare il modo in cui i componenti interagiscono. Vedere Interazioni tra componenti. Ognuno di questi diagrammi di sequenza mostra le interazioni che si verificano in un caso di utilizzo diverso. In questo modo, è possibile gradualmente aggiungere all'elenco di operazioni nell'interfaccia di ogni componente, mentre si esplorano i casi di utilizzo.
Scomposizione di un componente in parti
È possibile applicare la procedura descritta nelle sezioni precedenti a ogni componente.
All'interno di ogni componente, è possibile mostrare i sottocomponenti come parti. Una parte è in realtà un attributo del componente padre che è un tipo di classe. Ogni parte dispone di tipo proprio che può essere un componente. È possibile posizionare questo componente su un diagramma e mostrare le parti. Per ulteriori informazioni, vedere Diagrammi dei componenti UML: linee guida.
È utile applicare questa tecnica all'intero sistema. Disegnarlo come solo componente e mostrarne i componenti principali come parti. Consente di identificare chiaramente le interfacce del sistema con il mondo esterno.
Quando la progettazione per un componente utilizza un altro componente, frequentemente è possibile scegliere se rappresentarlo come parte o come un componente separato al quale si accede tramite un'interfaccia richiesta.
Utilizzare le parti nelle situazioni seguenti:
La progettazione del componente padre deve utilizzare sempre il tipo di componente della parte. Di conseguenza, la progettazione della parte è integrale alla progettazione del componente padre.
Il componente padre non dispone di una propria esistenza concreta. Ad esempio, è possibile avere un componente concettuale chiamato Presentazione livello che rappresenta un insieme di componenti reali che gestiscono visualizzazioni e interazioni dell'utente.
Utilizzare componenti separati cui si accede tramite le interfacce richieste in queste situazioni:
Il componente richiedente può essere accoppiato tramite le relative interfacce a diversi componenti fornitori in fase di esecuzione.
La progettazione è tale che risulta facile sostituire un provider con un altro.
L'utilizzo delle interfacce richieste è di solito preferibile all'utilizzo delle parti. Anche se la progettazione può impiegare più tempo, il sistema risultante è più flessibile. È anche più semplice testare separatamente i componenti. Consente meno accoppiamento nei piani di sviluppo.
Interazioni tra componenti
I principali consigli di questa sezione sono:
Identificare i casi di utilizzo del sistema.
Per ogni caso di utilizzo, disegnare uno o più diagrammi per mostrare come i componenti del sistema realizzano il risultato richiesto collaborando l'un con l'altro e con gli utenti. Generalmente, questi sono diagrammi di sequenza o diagrammi di attività.
Utilizzare le interfacce per specificare i messaggi ricevuti da ogni componente.
Descrivere gli effetti delle operazioni nelle interfacce.
Ripetere la procedura per ogni componente, mostrando come interagiscono le parti.
Ad esempio, in un sistema di vendite basato sul Web, il modello requisiti potrebbe definire un acquisto del cliente come un caso di utilizzo. È possibile creare un diagramma di sequenza per mostrare le interazioni che il cliente ha con i componenti nel livello di presentazione e per mostrare le interazioni che hanno con i componenti di contabilità e warehouse.
Identificazione degli eventi di inizializzazione
Il lavoro eseguito dalla maggior parte dei sistemi software può essere convenientemente diviso in base alle risposte restituite a input o eventi diversi. L'evento di inizializzazione potrebbe essere uno dei seguenti:
La prima azione in un caso di utilizzo. Potrebbe essere visualizzato nel modello requisiti come passaggio di un caso di utilizzo o azione di un diagramma di attività. Per ulteriori informazioni, vedere Diagrammi casi di utilizzo UML: linee guida e Diagrammi di attività UML: linee guida.
Un messaggio di un'interfaccia di programmazione. Se il sistema che si sviluppa è un componente di un sistema più grande, deve essere descritto come un'operazione in una delle interfacce del componente. Vedere Componenti e relative interfacce.
Una particolare condizione controllata dal sistema o un evento normale, quale l'ora del giorno.
Descrivere i calcoli
Disegnare diagrammi di sequenza per mostrare come i componenti rispondono all'evento iniziale.
Disegnare una linea di vita per ogni istanza del componente che fa parte di una sequenza tipica. In alcuni casi, potrebbe essere presente più di un'istanza di ogni tipo. Se il sistema intero è stato descritto come componente singolo, deve essere disponibile una linea di vita per ogni parte contenuta.
Per ulteriori informazioni, vedere Diagrammi di sequenza UML: linee guida.
Anche i diagrammi di attività sono utili in alcuni casi. Ad esempio, se i componenti dispongono di un flusso di dati continuo, è possibile descriverlo come flusso oggetto. Se il componente dispone di un algoritmo complesso, è possibile descriverlo come flusso di controllo. Assicurarsi di esprimere chiaramente quale componente esegue ogni azione, ad esempio tramite i commenti. Per ulteriori informazioni, vedere Diagrammi di attività UML: linee guida.
Specificare le operazioni
I diagrammi mostrano le operazioni eseguite da ogni componente, rappresentate come messaggi su un diagramma di sequenza o azioni in un diagramma di attività.
Raccogliere insieme queste operazioni per ogni componente. Creare le interfacce fornite sul componente e aggiungere le operazioni alle interfacce. In genere, un'interfaccia separata viene utilizzata per ogni tipo di client. Le operazioni vengono aggiunte più facilmente alle interfacce in Esplora modelli UML. Allo stesso modo, raccogliere le operazioni che ogni componente utilizza da altri componenti e posizionarle nelle interfacce richieste associate al componente.
È utile aggiungere commenti ai diagrammi di attività o di sequenza, per indicare ciò che si ottiene dopo ogni operazione. È possibile inoltre scrivere l'effetto di ogni operazione nella proprietà Local Postcondition.
Modello di dati di componenti e interfacce
Definire i parametri e i valori restituiti di ogni operazione nelle interfacce del componente. Laddove le operazioni rappresentano chiamate quali le richieste di servizi Web, i parametri sono quelle informazioni che vengono inviate come parte della richiesta. Se un'operazione restituisce diversi valori, è possibile utilizzare i parametri con la proprietà Direction impostata su Out.
Ogni parametro e valore restituito dispone di un tipo. È possibile definire questi tipi utilizzando i diagrammi classi UML. Non è necessario rappresentare il dettaglio di implementazione in questi diagrammi. Ad esempio, se si intendono descrivere dati che vengono trasmessi come XML, è possibile utilizzare un'associazione per rappresentare qualsiasi tipo di riferimento incrociato tra i nodi dell'XML e utilizzare le classi per rappresentare i nodi.
Utilizzare i commenti per descrivere i vincoli aziendali sulle associazioni e sugli attributi. Ad esempio, per descrivere che tutti gli elementi sull'ordine di un cliente devono provenire dallo stesso fornitore, è possibile utilizzare un riferimento alle associazioni tra gli elementi dell'ordine e gli elementi sul catalogo del prodotto e tra l'elemento del catalogo e il fornitore.
Modelli di progettazione
Un modello di progettazione è una struttura che consente di progettare un particolare aspetto del software, specialmente nei casi in cui si ripeta in diverse parti del sistema. Adottando un approccio uniforme per tutto il progetto è possibile ridurre il costo di progettazione, assicurare la coerenza nell'interfaccia utente e ridurre il costo di individuazione e modifica del codice.
Alcuni modelli di progettazione generali, ad esempio Observer, sono ben conosciuti e ampiamente applicabili. Inoltre, sono disponibili modelli che sono applicabili solo al progetto specifico. Ad esempio, in un sistema di vendite Web saranno presenti diverse operazioni nel codice in cui si apportano modifiche all'ordine di un cliente. Per assicurarsi che lo stato dell'ordine venga correttamente visualizzato in ogni fase, tutte queste operazioni devono seguire un particolare protocollo per aggiornare il database.
Parte del lavoro dell'architettura software consiste nel determinare i modelli che devono essere adottati nella progettazione. Questa è generalmente un'attività continuativa perché durante l'avanzamento del progetto saranno individuati nuovi modelli e miglioramenti ai modelli esistenti. È utile organizzare il piano di sviluppo in modo da esercitarsi con ognuno dei modelli di progettazione principali nella fase iniziale.
La maggior parte dei modelli di progettazione possono essere parzialmente incorporati nel codice del framework. Il modello può essere parzialmente ridotto a una richiesta per lo sviluppatore di utilizzare particolari classi o componenti, quale un livello di accesso al database che assicura che il database venga gestito correttamente.
Un modello di progettazione viene descritto in un documento e in genere include le seguenti parti:
Nome.
Descrizione del contesto in cui è applicabile. Specificare i criteri che devono essere considerati dallo sviluppatore per l'applicazione del modello.
Breve spiegazione del problema che risolve.
Modello delle parti principali e relative relazioni. Possono essere classi o componenti e interfacce, con associazioni e dipendenze tra loro. Gli elementi di solito rientrano in due categorie:
Elementi che lo sviluppatore deve replicare in ogni parte del codice laddove viene utilizzato il modello. È possibile utilizzare tipi di modello per descrivere questi elementi. Per ulteriori informazioni, vedere Diagrammi casi di utilizzo UML: riferimento.
Elementi che descrivono classi del framework che lo sviluppatore deve utilizzare.
Modello delle interazioni tra le parti, utilizzando diagrammi di attività o sequenza.
Convenzioni di denominazione.
Descrizione della modalità di risoluzione del problema adottata dal modello.
Descrizione delle variazioni che gli sviluppatori potrebbero adottare.
Vedere anche
Concetti
Procedura: modificare un modello UML e i diagrammi
Visualizzazione del codice esistente
Modellazione dei requisiti utente