Operazione: Identificazione elemento progettazione |
|
 |
Questo compito descrive come identificare sottosistemi, classi, interfacce, eventi e segnali. |
Discipline: Analisi e progettazione |
|
Scopo
-
Analisi delle iterazioni delle classi di analisi per
identificare gli elementi del modello di progettazione
|
Relazioni
Ruoli | Esecutore primario:
| Esecutori aggiuntivi:
|
Input | Obbligatorio:
| Facoltativo:
|
Output |
|
Utilizzo del processo |
|
Descrizione principale
IL Compito: Analisi del caso d'uso si traduce in classi di
analisi, che rappresentano cose concettuali che possono eseguire comportamenti. In progettazione, le
classi di analisi evolvono in svariati tipi di elementi di progettazione:
-
classi, per rappresentare una serie di responsabilità piuttosto dettagliate;
-
sottosistemi, per rappresentare una serie meno dettagliata di responsabilità, composti da un'ulteriore serie di
sottosistemi, ma in ultima analisi anche da una serie di classi;
-
classi attive, che rappresentano thread nel sistema;
-
interfacce, che rappresentano dichiarazioni astratte di responsabilità fornite da una classe o sottosistema.
In oltre nella progettazione si devono identificare:
-
eventi, che sono specifiche di ricorrenze interessanti in spazio e tempo che solitamente (se sono ragguardevoli)
richiedono una risposta dal sistema; e
-
segnali, per rappresentare meccanismi asincroni utilizzati per comunicare con determinati tipi di eventi
all'interno del sistema.
Questa sottile distinzione ci permette di esaminare aspetti diversi della progettazione:
-
Gli eventi ed i segnali utilizzati per comunicarli, ci permettono di descrivere i trigger asincroni di
comportamento a cui il sistema deve rispondere.
-
Le classi ed i sottosistemi consentono di raggruppare responsabilità collegate in unità che si potranno sviluppare
in modo relativamente indipendente; le classi adempiono ad un insieme atomico di responsabilità correlate, mentre i
sottosistemi sono blocchi di costruzione compositi che vengono rispettivamente composti di classi o altri
sottosistemi. I sottosistemi sono utilizzati per rappresentare i prodotti del lavoro di un team di sviluppo come
una singola unità integrale di funzionalità, e come tale vengono usati sia come unità di controllo e gestione
configurazione che come elementi di progettazione logica.
-
Le classi attive vengono utilizzate per rappresentare thread di controllo nel sistema, consentendo di modellare la
simultaneità. Le classi attive sono spesso utilizzate insieme ad altre classi solitamente, ma non necessariamente,
passive: tale composizione di classi può quindi essere utilizzata - alla stregua di una collaborazione - per
modellare comportamenti complessi.
Nei sistemi in tempo reale, vengono utilizzate le capsule al posto delle classi attive. Queste offrono una
semantica più solida per semplificare la progettazione ed aumentare l'affidabilità delle applicazioni
simultanee. Le capsule condividono alcuni aspetti sia delle classi che dei sottosistemi: sono infatti
collaborazioni incapsulate di classi che insieme rappresentano un thread di controllo nel sistema. Si
differenziano dai sottosistemi perché una capsula è di responsabilità di un singolo sviluppatore, mentre un
sottosistema è di responsabilità (solitamente) di un team di sviluppatori; un sottosistema può tuttavia
contenere capsule.
-
Le interfacce consentono di esaminare e catturare i 'punti di giunzione' del sistema, definendo in modo preciso
come interagiscono le parti che lo costituiscono.
-
Nei sistemi in tempo reale si devono utilizzare i Protocolli per definire in modo preciso i messaggi che potranno
essere inviati e ricevuti su una porta di una capsula.
Separando le preoccupazioni e gestendo ciascun problema rappresentato da questi concetti in modo separato, si
semplifica il processo di progettazione e si chiarificano le soluzioni.
Se è necessario mantenere la tracciabilità tra modelli di sistema, lo si deve documentare durante questo
compito. Per maggiori informazioni sulla documentazione della tracciabilità tra modelli di progettazione e altri
modelli di sistema, consultare Guida: Modelli di
progettazione.
Rappresentazione UML 1.x
In UML 1.5, un sottosistema è un tipo particolare di pacchetto che contiene unicamente interfacce come elementi
pubblici. Le interfacce contengono un livello di incapsulamento che consente al progetto interno del sottosistema di
restare nascosto agli altri elementi del modello. Il sottosistema di concetto è utilizzato per distinguerlo dai
pacchetti "ordinari", che sono contenitori di elementi di modello senza semantica; il sottosistema rappresenta un
utilizzo particolare con proprietà simili alle classi (dal punto di vista comportamentale).
Nel RUP, le capsule sono rappresentate utilizzando la notazione UML 1.5. Molte di queste possono essere rappresentate
in UML 2.0 utilizzando Concetto: Classi
strutturate.
Fare riferimento a Differenze tra UML 1.x ed UML 2.0 per ulteriori informazioni.
|
Passi
Identificazione di eventi e segnali
Scopo
|
Identificare eventi e segnali interni ed esterni a cui il sistema deve rispondere.
|
Gli eventi sono delle ricorrenze interne ed esterne che causano delle azioni nel sistema. Gli eventi e le loro
caratteristiche possono aiutare nell'identificazione di elementi di progettazione chiave, quali le classi attive.
Un elenco iniziale di eventi esterni può essere ottenuto dal modello caso d'uso, dalle interazioni dell'esecutore
con i casi d'uso. Gli eventi interni possono essere ottenuti dal testo contenuto nel flusso del caso d'uso, o
possono essere identificati durante l'evolversi del progetto.
Le caratteristiche fondamentali degli eventi sono:
-
interno o esterno - l'evento è interno o esterno?
-
priorità - l'evento necessita dell'arresto di altri processi per essere gestito?
-
frequenza - quanto spesso si verifica l'evento?
-
distribuzione della frequenza - l'evento si verifica ad intervalli regolari o ci sono dei picchi?
-
requisiti di risposta - la velocità con cui il sistema deve rispondere all'evento (potrebbe essere necessario
distinguere tra la media ed il caso peggiore).
-
tipo - si tratta di un evento di chiamata, evento di tempo, evento di segnale, o evento di modifica (consultare
Concetto: Eventi e segnali per le definizioni)?
Le caratteristiche degli eventi devono essere catturate per portare all'identificazione degli elementi di
progettazione che li gestiscono. La cattura degli eventi è fondamentale nei sistemi reattivi (basato sugli eventi),
ma può essere utile anche in altri sistemi, quali quelli con messaggistica simultanea e/o asincrona.
Gli eventi di comunicazione asincroni in generale, possono essere modellati come segnali per esprimere i dati che
trasportano, o per esprimere le relazioni tra segnali. In alcuni sistemi, quali quelli reattivi è importante
collegare i segnali ricevuti da unità esterne a determinati meccanismi, come interrupt o messaggi di polling
specifici.
|
Identificazione di classi, classi attive e sottosistemi
Scopo
|
Affinare le classi di analisi negli appropriati elementi di modello di progettazione
|
Identificazione delle classi. Quando la classe di analisi è semplice e rappresenta già un astrazione logica
singola, può essere associata in modo diretto, 1:1, in una classe di progettazione. Solitamente, le classi
entità restano relativamente intatte all'interno di un progetto. Siccome le classi entità sono persistenti, determinare
se la classe di progettazione deve essere persistente ed annotarlo nella sua descrizione.
Quando si identificano le classi queste devono essere raggruppate in Prodotto
di lavoro: Pacchetti di progettazione, per scopi organizzativi e di gestione configurazione. Consultare Linea guida del prodotto di lavoro: Pacchetto di progettazione per ulteriori
informazioni su come effettuare le scelte di impacchettamento.
Identificazione delle classi attive. Considerare i requisiti di simultaneità del sistema nel contesto
dell'oggetto di analisi identificato: è necessario che il sistema risponda agli eventi generati dall'esterno? e se sì,
quali classi di analisi sono 'attive' quando si verifica l'evento? Gli eventi esterni in un modello del caso d'uso sono
rappresentati da emissioni provenienti da esecutori che interagiscono con il caso d'uso. Studiare le realizzazioni del
caso d'uso corrispondenti per controllare quali oggetti interagiscono quando si verifica l'evento. Iniziare
raggruppando gli oggetti in insiemi autonomi che collaborano - questi raggruppamenti rappresentano una selezione
iniziale ad un gruppo che potrà in seguito andare a formare una classe attiva composita.
Se gli eventi hanno attributi importanti che devono essere catturati, considerare la possibilità di modellarli in
classi, <<segnali>> stereotipati. Nei sistemi in tempo reale, questi insiemi di oggetti identificati devono
essere raggruppati in capsule, che hanno una forte semantica di incapsulamento.
Le istanze di classi attive rappresentano thread 'logici' indipendenti di esecuzione. Questi thread 'logici' di
esecuzione non devono essere confusi o associati con i thread di esecuzione del sistema operativo (per quanto ad un
certo punto verranno associati con essi). Al contrario, essi rappresentano thread di esecuzione concettualmente
indipendenti nell'ambito delle soluzioni. Lo scopo di identificarli in questa fase della progettazione è quello di
poter separare la soluzione in unità indipendenti basate sui 'punti di giunzione di simultaneità' naturali nel sistema.
Questo modo di dividere il lavoro rende la gestione della simultaneità concettualmente più semplice, poiché i thread
indipendenti di esecuzione potranno essere considerati separatamente tranne che per il fatto che condividono le
sottostanti classi passive.
In generale si dovrebbe prendere in considerazione l'utilizzo di una classe attiva ogni volta vi siano simultaneità e
conflitti di simultaneità nel dominio del problema. Una classe attiva deve essere utilizzata per rappresentare oggetti
simultanei esterni o attività simultanee interne al computer. Questo consente il controllo delle attività simultanee.
Un'altra possibilità è quella di utilizzare le classi attive come rappresentazione interna di periferiche fisiche
esterne connesse al computer, siccome queste entità fisiche sono simultanee in modo inerente. Queste classi, che
fungono da "driver di periferica", non servono unicamente per controllare la periferica corrispondente, ma anche per
isolare il sistema dalle sue specifiche. Ciò significa che il sistema potrebbe non essere influenzato anche se la
tecnologia della periferica dovesse evolvere.
Un altro esempio classico di utilizzo delle classi attive consiste nella rappresentazione di attività simultanee
logiche. Un'attività logica rappresenta un "oggetto" simultaneo concettuale, quale, una transazione finanziaria o una
telefonata. Per quanto esse non si manifestino direttamente come entità fisiche (anche se si verificano in un mondo
fisico), vi sono spesso ragioni per gestirle come tali. Ad esempio potremmo dover trattenere una determinata
transazione finanziaria per evitare un conflitto di simultaneità oppure potrebbe essere necessario interromperla a
causa di errori nel sistema. Siccome questi oggetti concettuali devono essere gestiti come unità, è utile
rappresentarli come oggetti con interfacce proprie che forniscono le funzionalità appropriate.
Un esempio particolare di tale tipo di oggetto concettuale è l'unità di controllo dell'oggetto attivo. Il suo
ruolo è quello di gestire in modo continuo uno o più oggetti attivi. Questo compito normalmente consiste nel portare un
oggetto ad un determinato stato operativo e nel mantenerlo in tale stato anche in presenza di errori parziali, e
sincronizzando le sue operazioni con quelle di altri oggetti. Queste unità di controllo degli oggetti attivi spesso
evolvono partendo da oggetti di controllo identificati durante Compito: Analisi
del caso d'uso.
Grazie alla loro capacità di risolvere semplicemente i conflitti di simultaneità, le classi attive tornano utili anche
come guardiani delle risorse condivise. In questo caso, una o più risorse richieste da più compiti concorrenti
vengono incapsulate in una classe attiva. In virtù della loro semantica di esclusione reciproca incorporata, tali
guardiani proteggono automaticamente queste risorse dai conflitti di simultaneità.
Nei sistemi in tempo reale, si devono utilizzare le capsule al posto delle classi attive: ovunque si richieda una
classe attiva, come mostrato nelle simulazioni precedenti, è necessario sostituirle con le capsule.
Identificazione dei sottosistemi. Quando la classe di analisi è più complessa, al punto da contenere
comportamenti che non possono essere responsabilità di una classe che agisca da sola, deve essere associata ad un
sottosistema di progettazione. Il sottosistema di progettazione viene utilizzato per incapsulare queste collaborazioni
in modo che i clienti del sottosistema possano rimane allo scuro della sua progettazione interna.
Un sottosistema viene modellato come un componente UML, che ha come elementi pubblici le sole interfacce. Le interfacce
contengono un livello di incapsulamento che consente al progetto interno del sottosistema di restare nascosto agli
altri elementi del modello. Il sottosistema di concetto è utilizzato per distinguerlo dai pacchetti, che sono
contenitori di elementi di modello senza semantica.
La decisione di creare un sottosistema da una serie di classi di analisi che collaborano, viene basata sulla
possibilità che la collaborazione possa o venga sviluppata in modo indipendente da un team di progettazione separato.
Se la collaborazione può essere completamente contenuta in un pacchetto assieme alle classi di collaborazione, un
sottosistema fornisce una maggiore forma di incapsulamento rispetto a quella fornita da un semplice pacchetto. I
contenuti e le collaborazioni interne ad un sottosistema sono completamente isolate dietro una o più interfacce, così
che il cliente del sottosistema dipende solo dalle interfacce. Il progettista del sottosistema non dovrà quindi
preoccuparsi delle dipendenze esterne; egli (o il team di progettazione) deve definire come viene realizzata
l'interfaccia, ma sarà libero di modificare la progettazione del sottosistema interno senza influenzare le dipendenze
esterne. Nei grandi sistemi con team largamente indipendenti, questo grado di separazione combinato con le migliorie
architetturali fornite dalle normali interfacce, rappresenta un solido argomento per la scelta dei sottosistemi
rispetto ai semplici pacchetti. Consultare Linea guida del
prodotto di lavoro: Sottosistema di progettazione per ulteriori informazioni sui fattori che influenzano la scelta
di utilizzare i sottosistemi come elementi di progettazione.
|
Identificazione delle interfacce di sottosistema
Scopo
|
Identificazione degli elementi di progettazione che formano i punti di giunzione nel sistema.
|
Le interfacce definiscono una serie di operazioni che vengono realizzate da alcuni programmi di classificazione. Nel
modello di progettazione le interfacce sono utilizzate principalmente per definire le interfacce per i sottosistemi.
Questo non significa che non possono essere utilizzate anche per le classi, ma per le classi singole è solitamente
sufficiente definire delle operazioni pubbliche sulla classe che definisce l'interfaccia. Le interfacce sono importanti
per i sottosistemi poiché consentono la separazione delle dichiarazioni di comportamento (l'interfaccia) dalla sua
realizzazione (le classi specifiche interne al sottosistema che realizzano l'interfaccia). Questa separazione consente
di incrementare l'indipendenza dei team di sviluppo che lavorano su parti diverse del sistema, mantenendo però
definizioni precise dei 'contratti' tra le diverse parti.
Per ciascun sottosistema identificare una serie di possibili interfacce. Utilizzando le collaborazioni
raggruppate create nel passo precedente, identificare la responsabilità che viene 'attivata' quando si avvia la
collaborazione. Questa viene quindi raffinata determinando quali informazioni devono essere fornite dal 'cliente' e
quali devono essere restituite al termine della collaborazione; questa serie di informazioni diventano il prototipo dei
parametri di input, output e dei valori restituiti per l'operazione che il sistema realizzerà. Definire il nome di
questa operazione, utilizzando le convenzioni di denominazione definite in Prodotto di lavoro: Linee guida specifiche del progetto. Ripetere
finché tutte le operazioni realizzate dal sottosistema non saranno definite.
Raggruppare poi tutte le operazioni sulla base delle loro responsabilità. Sono preferibili gruppi piccoli, siccome è
più probabile ottenere una serie aderente di responsabilità comuni se le operazioni nel gruppo sono minori. Tenere
sempre presente il riutilizzo - creare delle similitudini che possano rendere più semplice l'identificazione di
funzionalità riutilizzabili collegate tra loro. Allo stesso tempo, però, è bene non dedicare troppo tempo alla ricerca
del raggruppamento di responsabilità ideale; ricordarsi che si tratta di un primo raggruppamento e che il raffinamento
proseguirà in modo iterativo durante tutta la fase di elaborazione.
Ricerca delle similitudini tra le interfacce. Nell'insieme di interfacce candidate, cercare nomi simili,
responsabilità simili ed operazioni simili. Nel caso vi siano operazioni uguali in più interfacce, riorganizzarle,
estraendo le operazioni comuni ed inserendole in una nuova interfaccia. Considerare anche le interfacce esistenti,
riutilizzandole dove possibile. Lo scopo è quello di mantenere la coesione delle interfacce rimuovendo le operazioni
ridondanti. Ciò le renderà più semplici da comprendere e ne faciliterà l'evoluzione nel tempo.
Definizione delle dipendenze dell'interfaccia. I parametri ed i valori restituiti da ciascuna operazione
dell'interfaccia sono di diversi tipi: essi devono realizzare una particolare interfaccia, oppure devono essere istanze
di un semplice tipo di dati. Nel caso in cui i parametri siano oggetti che realizzano una determinata interfaccia, si
devono definire le relazioni di dipendenza tra di essa e l'interfaccia da cui essa dipende. La definizione delle
dipendenze fornisce delle informazioni utili per l'accoppiamento all'Architetto del software, siccome le dipendenze tra
le interfacce determinano le dipendenze primarie tra gli elementi del modello di progettazione.
Associazione delle interfacce ai sottosistemi. Una volta identificate le interfacce, creare delle associazioni
di realizzazione tra il sottosistema e l'interfaccia che esso realizza. Una realizzazione da un sottosistema ad
un interfaccia indica che esistono uno o più elementi all'interno del sottosistema che realizzano le operazioni
dell'interfaccia. Successivamente, quando il sottosistema verrà progettato, verrà raffinata la realizzazione
dell'interfaccia di sottosistema, il progettista del sottosistema definirà quali elementi specifici realizzeranno le
operazioni dell'interfaccia. Queste realizzazioni raffinate sono visibili solo al progettista del sottosistema; al
cliente del sottosistema saranno visibili unicamente le realizzazioni delle sue interfacce.
Definizione dei comportamenti specificati dalle interfacce. Le interfacce spesso definiscono una macchina a
stati implicita per gli elementi che le realizzano. Se le operazioni devono essere richiamate in un ordine specifico
(ad esempio, è necessario avviare una connessione al database prima di utilizzarlo), si deve definire una macchina a
stati che illustri gli stati visibili (o intuibili) pubblicamente che ciascun elemento di progettazione che realizza
l'interfaccia deve supportare. Questa macchina a stati aiuta l'utente di un interfaccia a comprenderla con più
semplicità, ed aiuterà il progettista degli elementi che realizzano l'interfaccia a fornire loro il comportamento
corretto.
Impacchettamento delle interfacce. Le interfacce sono in possesso dell'Architetto del software; la loro modifica
è sempre rilevante dal punto di vista architetturale. Per gestire questa eventualità, esse devono essere raggruppate in
uno o più pacchetti in possesso dell'Architetto del software. Se ciascuna interfaccia è realizzata da un singolo
sottosistema, la si può impacchettare assieme ad esso. Se invece è realizzata da più sottosistemi, deve essere
impacchettata in pacchetti separati in possesso dell'Architetto del software. Ciò consente di gestirla e controllarla
indipendentemente dal sottosistema.
Scopo
|
Identificazione degli elementi di progettazione che formano i punti di giunzione nel sistema (solo per
la progettazione del RT).
|
I protocolli sono simili alle interfacce nei sistemi basati sugli eventi: identificano il 'contratto' tra le capsule
definendo una serie corrispondente di segnali utilizzati per le comunicazioni tra thread di controllo indipendenti.
Mentre le interfacce sono utilizzate principalmente per la definizione di una messaggistica sincrona utilizzando un
modello di richiamo a chiamata di funzione, i protocolli sono utilizzati per la definizione di comunicazioni asincrone
utilizzando una messaggistica basata su segnali. Questi consentono una separazione tra la dichiarazione di
comportamento (l'insieme dei segnali) e la sua realizzazione (gli elementi del sottosistema che realizzano
l'interfaccia). Questa separazione consente di incrementare l'indipendenza dei team di sviluppo che lavorano su parti
diverse del sistema, mantenendo però definizioni precise dei 'contratti' tra le diverse parti.
Per ciascuna capsula identificare una serie di segnali in ingresso ed uscita. Utilizzando le collaborazioni
raggruppate create nei precedenti passi, identificare la responsabilità che viene 'attivata' quando si avvia la
collaborazione. Questa viene quindi raffinata determinando quali informazioni devono essere fornite dal 'cliente' e
quali devono essere restituite al termine della collaborazione; questa serie di informazioni diventano il prototipo dei
parametri di input per un segnale che la capsula realizzerà tramite una delle sue porte. Definire il nome di questo
segnale, utilizzando le convenzioni di denominazione definite in Prodotto di lavoro: Linee guida specifiche del progetto. Ripetere
finché tutti i segnali realizzati dalla capsula non saranno definiti.
Raggruppare poi tutti i segnali sulla base delle loro responsabilità. Sono preferibili gruppi piccoli, siccome è più
probabile ottenere una serie aderente di responsabilità comuni se i segnali nel gruppo sono minori. Tenere sempre
presente il riutilizzo - creare delle similitudini che possano rendere più semplice l'identificazione di funzionalità
riutilizzabili collegate tra loro. Allo stesso tempo, però, è bene non dedicare troppo tempo alla ricerca del
raggruppamento di responsabilità ideale; ricordarsi che si tratta di un primo raggruppamento e che il raffinamento
proseguirà in modo iterativo durante tutta la fase di elaborazione. Assegnare al protocollo un nome significativo che
descriva il suo ruolo nella collaborazione della capsula.
Ricerca delle similitudini tra i protocolli. Nell'insieme di protocolli candidati, cercare nomi simili,
responsabilità simili e segnali simili. Nel caso vi siano segnali uguali in più protocolli, riorganizzarli, estraendo i
segnali comuni ed inserendoli in una nuova interfaccia. Considerare anche i protocolli esistenti, riutilizzandoli dove
possibile. Lo scopo è quello di mantenere la coesione dei protocolli rimuovendo le operazioni ridondanti. Ciò li
renderà più semplici da comprendere e ne faciliterà l'evoluzione nel tempo.
Associazione dei protocolli alle capsule. Una volta identificati i protocolli, creare le porte sulle
capsule che li realizzano. Le porte delle capsule ne definiscono le 'interfacce', il comportamento che può essere
richiesto dalla capsula. Successivamente, una volta progettata la capsula, il comportamento specificato dalle porte
verrà descritto dalla sua macchina a stati.
Definizione dei comportamenti specificati dai protocolli. I protocolli spesso definiscono una macchina a stati
implicita per gli elementi che le realizzano. Se i segnali di input devono essere ricevuti in un ordine specifico (ad
esempio, un segnale 'sistema-pronto' deve essere ricevuto prima di un determinato segnale di errore), si deve definire
una macchina a stati che illustri gli stati visibili (o intuibili) pubblicamente che ciascun elemento di progettazione
che realizza il protocollo deve supportare. Questa macchina a stati aiuta l'utente della capsula che realizza il
protocollo a comprenderne meglio il comportamento, ed aiuterà il progettista delle capsule a fornire loro il
comportamento corretto.
Impacchettamento dei protocolli. I protocolli sono in possesso dell'Architetto del software; la loro modifica è
sempre rilevante dal punto di vista architetturale. Per gestire questa eventualità, essi devono essere raggruppati in
uno o più pacchetti in possesso dell'Architetto del software. In questo modo sarà possibile gestire e controllare i
protocolli indipendentemente dalle capsule che li realizzano.
|
|
Ulteriori informazioni
© Copyright IBM Corp. 1987, 2006. Tutti i diritti riservati.
|
|