Introduzione
Ingegneria del software significa avere un approccio sistematico e rigoroso allo sviluppo, alla messa in opera e alla manutenzione del software, secondo criteri ingegneristici. Metodi tecnici e manageriali per prevedere e tenere sotto controllo i costi per tutta la vita (lifecycle) dei prodotti software. Come tutte le ingegnerie, fornisce una guida per applicare la conoscenza scientifica allo sviluppo di soluzioni cost-effectively per risolvere i problemi.
- Processo: come avviene lo sviluppo industriale del software
- Prodotto: che cosa viene effettivamente prodotto. Studiare i metodi da usare perché il processo porti allo sviluppo di prodotti di qualità.
Software: insieme di artefatti legati ad un particolare prodotto software.
- Progetto standard: soluzione ad un problema noto e ricorrente, in cui ri-utilizzo soluzioni note.
- Progetto innovativo: soluzioni radicalmente nuove a problemi non noti.
Ingegneria tradizionale
Prevale il progetto standard, in cui vengono seguite procedure standard per lo sviluppo. Si pone una estrema attenzione alla fase di progetto, in modo da poter poi creare dei modelli matematici sui quali svolgere test preliminari.
Ingegneria del software
Spesso il software viene trattato come progetto innovativo. Congelare le caratteristiche e le specifiche di prodotto e di progetto non è realistico, in quanto il software è e deve essere in continua evoluzione e aggiornamento.
Progettazione vs programmazione
Un programmatore è una figura professionale che sviluppa un programma completo, partendo da specifiche fornite da altri.
Un ingegnere del software:
- Analizza problemi e domini applicativi.
- Coglie i requisiti e sviluppa specifiche.
- Progetta componenti, potenzialmente ri-utilizzati.
Progettazione: scomposizione di un sistema in moduli, ovvero scomporre un problema grande in sottoproblemi che possono essere risolti indipendentemente (divide et impera).
Processo di sviluppo software
Modello a cascata
- Studio di fattibilità
- Analisi di costi e beneficio, analisi di eventuali alternative, costi associati e risorse necessarie.
- Produce il documento "studio di fattibilità".
- Descrizione preliminare del problema.
- Scenari che descrivono le possibili soluzioni.
- Analisi e specifica dei requisiti
- Analizza il dominio in cui l'applicazione si colloca.
- Identifica i requisiti.
- Deriva una specifica del software.
- Produce il documento "analisi e specifica dei requisiti".
- Progettazione
- Definisce l'architettura del software.
- Componenti.
- Relazioni tra componenti.
- Obiettivo: supportare lo sviluppo concorrente, definendo le diverse responsabilità per le diverse parti.
- Produce il documento "progetto del sistema".
- Definisce l'architettura del software.
- Implementazione e test di unità
- Ogni modulo elementare viene implementato mediante il linguaggio di programmazione scelto e viene testato dallo sviluppatore mentre viene sviluppato.
- Integrazione e test di sistema
- I moduli sono integrati in sottosistemi e ciascun sottosistema viene testato.
- Il sistema completo viene testato alla fine per verificare proprietà complessive che non avrebbero senso sui singoli componenti.
- Messa in opera
- Obiettivo: distribuire l'applicazione e gestire le diverse installazioni e configurazioni presso i clienti.
- Manutenzione
- Copre i cambiamenti successivi alla fine del processo di sviluppo.
- Correttiva: correggere i difetti.
- Adattativa: adattare i cambiamenti dell'ambiente operativo.
- Perfettiva: estensione di requisiti funzionali.
- Copre i cambiamenti successivi alla fine del processo di sviluppo.
Cicli di vita "agili"
- SCRUM
È una metodologia iterativa e incrementale. Parte del riconoscimento che i committenti possono cambiare idea e che il processo a cascata non è in grado di reggere a questa "turbolenza". Il progetto viene organizzato in "sprint", ovvero in periodi da 4 a 7 settimane nei quali si crea un incremento del prodotto rilasciabile.
- Extreme Programming
Come SCRUM, rivendica la centralità del codice rispetto ad altri artefatti, con il conseguente pericolo di ricadere nel code-and-fix. Integra il testing nel processo come attività centrale; prima di iniziare a codificare, si definiscono i casi di test che dovranno essere superati intanto che si scrive il codice. Avviene un refactoring continuo, ovvero il software è sempre in evoluzione, e il mio obiettivo è quello di sistemarlo di volta in volta. Talvolta nel processo di sviluppo del software si possono realizzare dei prototipi, con lo scopo di capire meglio ciò che si dovrà poi realizzare.
Caratteristiche
- Correttezza: un software è corretto se soddisfa le specifiche.
- Affidabilità: solidità dell'applicazione, assenza di un malfunzionamento.
- Robustezza: anche se qualcosa va storto, il software si comporta comunque in maniera accettabile.
- Prestazioni: uso efficiente delle risorse (memoria, processori, banda di rete).
- Usabilità: semplicità d'utilizzo del software.
- Manutenibilità
- Riusabilità: ri-utilizzo dei componenti interni.
- Portabilità: adattamenti a diversi ambienti.
- Inter-operabilità: il software si collega bene con le altre applicazioni del contesto in cui lavora.
Programmazione orientata agli oggetti
Riuso
Al fine di non perdere tempo e soldi, è essenziale riuscire a riutilizzare parti di progetti (idee e componenti) già sviluppati in precedenza.
- Riduzione dei tempi di sviluppo.
- Minore manutenzione.
- Maggiore robustezza ed affidabilità.
- Possibilità di sfruttare al massimo la conoscenza sviluppata da una azienda specifica in un determinato campo.
Possono però sorgere dei problemi, principalmente di due nature:
- Problemi tecnici: i moduli devono essere adattabili, ovvero la soluzione deve essere abbastanza generale.
- Problemi non tecnici:
- Paura di affidarsi al codice scritto da altri.
- Possibilità di perdita di efficienza, in quanto una soluzione generale potrebbe essere meno efficiente di una soluzione su misura.
Modularizzazione
Un sistema è modulare se è diviso in parti che hanno una sostanziale autonomia individuale ed una ridotta interazione con le altre parti. Si definisce modulo un fornitore di risorse computazionali (funzioni, strutture dati, tipi...)
Per un modulo è importante distinguere:
- Cosa fa: insieme dei servizi forniti, o interfaccia (costituisce il contratto tra il modulo e i suoi utilizzatori).
- Come è fatto: particolarità interne al modulo, implementazione.
Una buona modularizzazione è necessaria per poter riutilizzare il codice ed inoltre influisce positivamente su altre qualità del software quali verificabilità, manutenibilità e comprensibilità.
Approccio top-down
Seguendo l’approccio top-down, si scompone ricorsivamente la funzionalità principale del sistema in funzionalità più semplici, fino a quando le funzionalità individuate sono abbastanza semplici da permettere una diretta implementazione. A questo punto si può dividere il lavoro di implementazione sulla base delle funzionalità individuate.
Questo metodo di lavoro risulta particolarmente adatto a progettare algoritmi, ma non sistemi di grosse dimensioni, in quanto:
- Spesso un sistema non è caratterizzato da una sola funzionalità principale.
- Le funzionalità di un sistema sono soggette a frequenti cambiamenti.
- Si decidono troppo presto i vincoli tra i diversi moduli.
- Difficoltà di aggiornamento e di gestione delle modifiche all'interno del codice.
Approccio object-oriented
Tipo: insieme di valori (dominio) + insieme di operazioni. Il vantaggio principale è che gli errori di tipo sono rilevati dal compilatore, perciò per individuarli non è necessario eseguire il programma.
Programmazione orientata agli oggetti
Incapsulamento
Per poter gestire al meglio i moduli è necessario il coordinamento tra sviluppatore e utilizzatore. È necessario che lo sviluppatore fornisca delle strutture dati assieme a delle operazioni che operano su di essa, in modo che l'utilizzatore non debba modificare il proprio comportamento a fronte di modifiche nel codice eseguibile da parte dello sviluppatore.
Es. se in una struttura dati "data", cambio il campo int mese con char mese[4], l'utilizzatore che vuole stampare una determinata data non deve cambiare nulla, sono io che devo fornire la “stampa_data” funzione e provvedere ad aggiornarla.
Tipo di dato astratto
Astrazione sui dati: non classifica i dati in base alla loro rappresentazione (implementazione), ma in base al loro comportamento atteso (specifica). Il comportamento dei dati è espresso in termini di un insieme di operazioni applicabili a quei dati (interfaccia). Le operazioni dell'interfaccia sono le sole cose che si possono utilizzare per creare, modificare e accedere agli oggetti; l'implementazione della struttura dati non può essere utilizzata al di fuori della specifica.
Un dato astratto (ADT) è definito dallo sviluppatore e incapsula tutte le operazioni necessarie a manipolare i valori.
- Offre in maniera visibile:
- Il nome del tipo.
- Interfaccia: tutte e sole le operazioni per manipolare i dati del tipo e la loro specifica.
- Nasconde l'implementazione del tipo e delle operazioni necessarie.
Un utilizzatore può creare istanze del tipo specificato e manipolarle tramite le operazioni definite. Lo scopo dell'astrazione non è quello di essere vago, ma di creare un nuovo livello semantico in cui si può essere assolutamente precisi.
Linguaggi orientati agli oggetti
Esiste un certo numero di linguaggi di programmazione orientati agli oggetti, che hanno le seguenti caratteristiche:
- Obbligano ad incapsulare le strutture dati all'interno di opportune dichiarazioni (classi).
- Consentono facilmente di impedire l'accesso all'implementazione.
- Rendono possibile creare istanze concrete (oggetti) da una astrazione per parametrizzazione.
Oggetti
Un oggetto è un concetto, un'astrazione, o in generale un'entità avente un significato ben preciso per l'applicazione in esame; può essere composto da altri oggetti (anche dello stesso tipo).
- Identità: ogni oggetto è dotato di identità univoca (nome della variabile, locazione di memoria per il linguaggio C).
- Comportamento (metodi, operazioni): determina come agisce un oggetto
- Cambiamenti di stato e reazioni ad azioni di altri oggetti.
- È definito dall'insieme di operazioni che l'oggetto può compiere.
- Stato: è la condizione in cui si trova l'oggetto, ed è definito dai valori delle proprietà. Due oggetti possono essere uguali, se hanno lo stesso valore dello stato, oppure identici se sono lo stesso oggetto, ovvero se hanno la stessa identità.
Classe
Una classe è un gruppo di entità identificato da un insieme di caratteristiche comuni; è un'astrazione della realtà, in quanto enfatizza alcune caratteristiche e tralascia alcune proprietà. È un modello per creare oggetti con proprietà simili; ogni oggetto è istanza di una particolare classe.
Formalmente, una classe è un costrutto che consente la definizione di tipi di dato astratto: definiscono la struttura e il comportamento degli oggetti (istanze) che appartengono alla classe.
Le proprietà di una classe si dividono in:
- Pubbliche (metodi)
- Private (attributi): sono visibili e modificabili solo attraverso apposite proprietà pubbliche.
Relazioni tra classi
- Aggregazione (part of): es. volante part-of automobile.
- Uso (message passing): es. persone usa automobile.
- Ereditarietà (is a): es. automobile elettrica is a automobile.
- Una classe è sottoclasse di una sopraclasse se condivide/eredita la struttura e i comportamenti della sopraclasse.
Polimorfismo
Il polimorfismo è la capacità di un'entità di assumere forme diverse nel corso della propria esistenza. Una variabile polimorfica può mutare il proprio tipo:
- Tipo statico: noto a "compile-time", definisce le caratteristiche generali degli oggetti della classe.
- Tipo dinamico: noto solo a "run-time", definisce il tipo specifico dell'oggetto a cui la variabile si riferisce in un certo istante.
Binding
- Static binding: il legame fra il nome di una funzione (metodo) ed il codice da eseguire avviene in fase di compilazione.
- Late binding: il legame fra il nome di una funzione (metodo) ed il codice da eseguire avviene in fase di esecuzione, all'atto della chiamata.
Terminologia
- Tipo di dato astratto: insieme di valori con operazioni per accedere/modificare istanze.
- Modulo: collezione di definizioni di dati e codice tra loro collegati.
- Tipizzazione statica: informazioni di tipo associate agli identificatori.
- Tipizzazione dinamica: informazioni di tipo associate agli oggetti.
Esecuzione in un contesto object-oriented
Un programma in esecuzione consiste di un insieme di oggetti, che comunicano tra loro inviando e ricevendo messaggi, ed eventualmente eseguendo un metodo (alla ricezione). Gli oggetti appartengono a classi (definizioni di tipi di dato astratto) e consistono di attributi (dati) e metodi (comportamento). Le classi definiscono staticamente dati e comportamento di un insieme di oggetti dello stesso tipo.
Unified Modeling Language (UML)
Modellazione
Un modello è una descrizione astratta del sistema, in cui è inclusa anche una descrizione dell’ambiente in cui il sistema dovrà operare. Modellare un sistema aiuta gli analisti a capire le funzionalità del sistema e favorisce la comunicazione con i committenti. Sono astrazioni, non hanno lo stesso rigore che può avere l’implementazione stessa.
- Ignorano dettagli che possono distrarre dall’essenza del problema (aumento focus sui dettagli che rimangono).
- Occorre rendersi conto dell’approssimazione introdotta nel trarre conclusioni.
UML
UML è un tentativo di standardizzazione diversi modelli disponibili per il software, in quanto il software non dispone ancora di tecniche standard efficaci per descriverne la struttura, le funzionalità e le prestazioni.
Diagrammi
- Diagrammi di struttura: mostrano la struttura interna (statica) del programma, sotto qualche punto di vista.
- Diagramma di comportamento: enfatizza gli aspetti dinamici del programma, ovvero come si comporta.
- Diagrammi di intersezione: mostrano sequenze di interazioni tra i diversi moduli.
Un tipo di dato astratto mi fornisce una visione astratta di un concetto nel mio dominio applicazione. Un tipo di dato astratto si mappa 1 a 1 con il concetto di “classe”. Per questo ci concentriamo sul diagramma di struttura delle classi, e sulle interazioni tra di esse.
Casi di utilizzo
Scopo: sono diagrammi comportamentali che descrivono i requisiti del sistema e le funzionalità di alto livello che devono essere offerte, senza affrontare in alcun modo la descrizione di come le funzionalità sono realizzate.
Unified Modeling Language (UML)
Diagramma delle classi
UML consente di esprimere graficamente livelli crescenti di dettaglio nella descrizione delle entità. Un grande livello di dettaglio può essere inadeguato o controproducente nella specifica dei requisiti; diventa invece essenziale nella descrizione dell’architettura della soluzione, dove le classi corrispondono esattamente alle classi della soluzione in Java.
- Descrizione statica (come è fatto, non come agisce).
- Rappresenta una classe (una entità del mio dominio):
- Nome.
- Attributi (stato).
- Metodi/operazioni (comportamento).
Visibilità (information hiding): quali rappresentazioni interne voglio far vedere dall’esterno.
- Public (+): tutti.
- Private (-): nessuno.
- Protected (#): stessa “cartella” e sottotipi.
- Friendly (~): stessa “cartella”.
Associazioni di classi
Un’associazione indica una relazione tra classi (anche all’interno della stessa classe), e può avere:
- Nome: solitamente un verbo, “una persona vive in una casa”.
- Ruoli svolti dalle classi: in un’azienda lavorano persone, ovvero è come se avessi un attributo “array di riferimenti” da 0 a n all’interno del tipo Azienda. Una persona lavora in un’azienda, ovvero è come se avessi un attributo “azienda” in Persona.
Al posto delle linee, possiamo avere delle frecce; significa che teniamo il riferimento solo in uno dei due “tipi” (quello da cui parte la freccia).
Aggregazioni
Le aggregazioni sono una forma particolare di associazione; una parte è in relazione con un oggetto (part of).
Composizioni
Una relazione di composizione è un’aggregazione forte, ovvero un’aggregazione in cui le parti componenti non esistono senza il contenitore.
Unified Modeling Language (UML)
Diagrammi di intersezione
Sono diagrammi che descrivono il comportamento dinamico di un gruppo di oggetti che “interagiscono” per risolvere un problema; quali sono le sequenze...
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
-
Programmazione java
-
Programmazione - programmazione Java 2
-
Programmazione - programmazione Java 1
-
Programmazione JAVA