Progetto di Ingegneria del Software 1997-98

Ambiente di sviluppo software distribuito e multiutente

Questo progetto riguarda un ambiente distribuito di ingegneria del software, che include una serie strumenti per lo sviluppo cooperativo di componenti software Java. L'ambiente equipara l'utente finale di un'applicazione e l'utente di componenti.

Si vuole dare la possibilità ad ogni utente di presentare propri progetti di sviluppo e di partecipare a quelli esistenti.

Un progetto è associato ad una struttura organizzativa che attribuisce a degli utenti dei ruoli. Si riconosce però ad ogni utente il diritto di agire senza vincoli di ruolo. Un utente, limitatamente ai componenti cui ha accesso, può sviluppare l'applicazione come crede, e organizzarsi in gruppi con altri utenti. Eventualmente i componenti sviluppati possono essere accettati e può essere riconosciuto un ruolo ai gruppi e ai progetti autonomamente sviluppati.

Da una parte l'ambiente deve mettere gli utenti in condizione di non essere frenati dall'organizzazione che si danno e dall'altra deve favorire la convergenza delle varianti dei progetti e delle applicazioni rendendo vantaggioso il riuso dei componenti.

L'ambiente di sviluppo è scritto in Java e supporta componenti Java; tutto l'ambiente è visibile via Web.

Definizioni di base

Un utente è una persona. Un utente può creare progetti, gruppi e componenti.

Un gruppo è un insieme di utenti e gruppi definito dalle seguenti operazioni: addMember, removeMember, replaceMember, isMember.

Ad ogni operazione è associato un gruppo che può ridefinirla. Esistono alcuni gruppi predefiniti: tutti, nessuno, elenco utenti, ecc.

Una distribuzione è un gruppo assegnato ad almeno un'edizione di un componente.

Un ruolo è un gruppo (in genere è anche una distribuzione) definito nell'ambito di un progetto.

Un progetto è un insieme di ruoli che fanno riferimento ad un'applicazione. Più progetti possono avere per fine lo sviluppo di una stessa applicazione. Gli utenti che hanno dei ruoli in un progetto in genere cambiano nel tempo.

Gestione dei progetti

La gestione progetti include le seguenti funzioni:

· Presentazione di un progetto e richieste di partecipazione

· Visione dei progetti e offerte di partecipazione

· Definizione dei ruoli

· Gestione utenti (aggiunta, assegnazione ruoli)

· Pianificazione

Componenti

Un componente è un qualsiasi oggetto software manipolabile dall'ambiente. Esistono tre tipi di componenti: importati, derivati e astratti.

Un componente importato è un file gestito come tale dall'ambiente. Esempi: specifica formale, documentazione di un package (.html), documentazione di una applicazione (.html).

Un componente derivato è un file costruito a partire da altri componenti applicando un tool. Esempi: sorgente di una classe (.java), eseguibile di una classe (.class), eseguibile di una applicazione (.jar).

Un componente astratto è un componente cui corrisponde un'astrazione del linguaggio sorgente. Esempi: sorgente di un metodo, documentazione di un metodo, sorgente di una classe, documentazione di una classe, package, applicazione.

Una applicazione o sistema contiene l'eseguibile, i packages, la documentazione e altri componenti importati. Un eseguibile è un archivio (.jar) di eseguibili di classi (.class) e altri componenti importati; un package contiene delle classi; una classe contiene delle classi interne, dei metodi e delle definizioni di variabili; la documentazione contiene la documentazione dell'applicazione, dei packages, delle classi e dei metodi.

 

Gestione delle versioni e delle edizioni

Tutti i componenti possono evolvere e quindi hanno una storia. L'evoluzione di un componente è discreta - la granularità è data dalle operazioni di editing ­ è quindi possibile, in teoria, mantenere tutta la storia di un componente.

La modifica di un componente è finalizzata; si possono, ad esempio, aggiungere funzionalità, migliorare l'efficienza, correggere errori, ecc. Le singole operazioni di editing e le corrispondenti istanze partecipano alla realizzazione della modifica ma non sono rilevanti in termini del fine. Fanno parte della storia di un componente solo le istanze che realizzano compiutamente il fine di una modifica.

Una versione (version) è una istanza in sviluppo di un componente. Una versione è accessibile e modificabile solo dall'autore. La storia di una versione è ripercorribile passo per passo (undo/redo) per tutta la durata dello sviluppo.

Una edizione (release) è una versione finita e immutabile di un componente. Una versione diventa una edizione quando l'autore esegue l'operazione irreversibile di rilascio. Ad ogni edizione è associata una distribuzione che determina quali utenti possono accedere all'edizione.

Le varianti (variant) sono due o più versioni di un componente derivate da una stessa edizione. Poiché l'evoluzione di un componente non è lineare, da ogni edizione possono essere derivate in qualsiasi momento nuove varianti; più varianti possono eventualmente convergere in una nuova versione.

 

Le istanze di un componente sono identificate dall'ambiente in base alla loro storia (edizioni imparentate); inoltre hanno degli attributi associati: nome, nome variante, numero di edizione, stato di rilascio, data di creazione, data di rilascio, autore, compatibilità, descrizione modifiche, distribuzione.

Alcuni attributi vengono assegnati automaticamente quando viene creata una nuova versione (data di creazione, autore), altri vengono mantenuti aggiornati per tutta la durata dello sviluppo della versione (nome, data di rilascio, compatibilità).

Il nome variante viene ereditato dall'edizione di partenza ma può essere ridefinito dall'autore della versione.

Il numero di edizione (release number) è della forma x.y.z; prima o al momento del rilascio, l'autore decide quale indice incrementare in base al tipo di modifiche fatte: z (revision number) correzione di errori, y (minor release) piccoli cambiamenti, x (major release) grandi cambiamenti.

Lo stato di rilascio è pensato per assumere valori del tipo: alfa, beta, beta2, finale, ecc. Eventuali versioni di componenti che contengano componenti in uno stato diverso da finale non possono essere rilasciate come finali.

La distribuzione degli eseguibili è uguale alla distribuzione dell'applicazione. In questo modo, un utente che ha accesso all'applicazione può anche eseguirla e, se ha accesso anche ad altri componenti, può svilupparli e ricostruire l'intera applicazione.

Configurazione

I componenti partecipano alle relazioni fra componenti come istanze.

Esempio: l'edizione di un package contiene delle edizioni di classi che contengono edizioni di metodi.

La configurazione di un componente è definita dalle istanze dei componenti contenuti o referenziati.

L'unità di modifica è l'applicazione. Un utente sviluppa una propria versione dell'applicazione a partire da una precedente edizione. La configurazione iniziale è la stessa dell'edizione di partenza ed è modificabile durante lo sviluppo della versione, diventa immutabile al momento del rilascio.

E' possibile sviluppare e rilasciare singoli componenti della configurazione che possono eventualmente essere inclusi in altre configurazioni dell'applicazione in sviluppo. Simmetricamente, è possibile riassegnare singoli componenti a nuove edizioni degli stessi sviluppate da altri. Il rilascio di un componente implica il rilascio dei componenti contenuti non ancora rilasciati che per costruzione appartengono allo stesso autore. Possono esistere edizioni di componenti che non fanno parte di nessuna edizione dell'applicazione; tali componenti possono essere eliminati dall'autore.

Merge

A livello di configurazione di un componente, il merge è supportato da un meccanismo di notifica di nuove edizioni ed eventuale riassegnamento. A livello di componente, il merge fra varianti e in generale il confronto fra istanze è supportato evidenziando le differenze (aggiunte, tagli, spostamenti) all'interno dell'editor.

Delta

Una edizione di un componente viene mantenuta in singola copia indipendentemente dal numero di configurazioni di cui fa parte. Per costruzione, i componenti non rilasciati fanno parte di una sola configurazione.

A livello di componente, un sorgente Java viene rappresentato come albero sintattico; i nodi vengono mantenuti in singola copia indipendentemente dal numero di componenti di cui fanno parte.

Meccanismi di sicurezza e di riservatezza

Riservatezza

Ogni componente ha una storia fatta di edizioni e versioni. Una versione è accessibile solo all'utente (autore) che la sta sviluppando. Una edizione è accessibile e quindi sviluppabile solo dagli utenti che fanno parte della distribuzione associata. Ogni utente ha quindi una visione di parte, e in genere parziale, della storia di un componente.

Sicurezza

I meccanismi di sicurezza sono derivati da Java. Ogni componente è certificato dall'autore; ogni applicazione può inoltre contenere uno o più certificati di gruppi. Un utente può rilasciare certificati personali e dei gruppi di cui è membro diretto. I componenti vengono trasmessi crittografati.

Costruzione del sistema (System building)

Ogni componente può contenere o fare riferimento ad altri componenti. Il grafo di dipendenza dei componenti viene mantenuto automaticamente ed in base alle astrazioni del linguaggio (package, classe, metodo).

La costruzione di una versione del sistema è limitata alle versioni dei componenti non ancora costruiti.

Occorre fornire supporto a versioni multiple dei componenti e degli strumenti di costruzione; supporto alla migrazione e alla replicazione dei componenti finalizzati al supporto alla costruzione parallela e distribuita, agli utenti mobili, al ricambio degli utenti e alla tolleranza agli errori.

È necessario un meccanismo di propagazione degli aggiornamenti.

Architettura dell'ambiente

L'ambiente gestisce la memorizzazione, la migrazione, la replicazione e l'esecuzione di metodi dei componenti.

Gli utenti incidono sulle politiche di migrazione e di replicazione definendo vincoli di mobilità, sicurezza e disponibilità di risorse. I componenti di un sistema possono essere distribuiti su più macchine.

La trasmissione dei componenti è basata su invocazione remota di metodi (RMI) e non prevede scambio di file.

I componenti vengono resi visibili tramite associazione (binding) di riferimenti ad oggetti. La memorizzazione e la trasmissione dei componenti sono rese possibili da un processo di trasformazione (serialization) di componenti in sequenze di caratteri e viceversa.