08-GestioneProgetti

Transcript

08-GestioneProgetti
Gestione progetti
software
Michelangelo Diligenti
Ingegneria Informatica e
dell'Informazione
[email protected]
Sommario
●
●
Cosa fare quando il progetto software diviene
grande?

Dividere bene le classi in .cc e .h

Makefiles per gestire la compilazione
Gestione di progetti in un gruppo di programmatori

svn e programmazione condivisa
.cc e .h
●
Importante separare l'interfaccia ed
implementazione

Interfaccia in .h, ricordatevi la seguente struttura del .h
per evitare che il file possa venire incluso più volte
#ifndef NOME_FILE_H
#define NOME_FILE_H
// codice …
#endif // NOME_FILE_H

Implementazione in .cc, VANTAGGI


Interfaccia chiara e leggibile
Tempi di compilazione ridotti
Forward Declarations
●
●
●
●
Non includere un file da un file .h se possibile
evitarlo con forward declaration
Forward declaration dichiara l'esistenza di un tipo
senza specificarne le caratteristiche
Velocizza la compilazione ed aiuta ad evitare
dipendenze cicliche
Usare forward declaration quando non serve sapere
la dimensione del tipo per compilare

Possibile ogni volta che nel .h ci si riferisce al tipo per
indirizzo o riferimento
Forward Declaration: esempio
class RefParam;
class ValParam;
class PtrParam;
class User{
PtrParam* dato; // ok non devo sapere dimensione per definire puntatore
public:
void Do(const RefParam &inParam ); // ok, riferimento
void Do(ValParam inParam); // strano ma ok, purché senza implementazione,
// ma solo definizione del metodo
void Do(PtrParam* inParam); // ok, puntatore
void Do(ValParam& inParam); // ok, riferimento
};
Forward Declaration: esempio
class ValMember;
class PtrMember;
class User{
public:
User();
ValMember valmember; // no! serve sapere dimensione
PtrMember* ptrmember; // ok! non serve dimensione
};
Makefiles
●
●
Dato un progetto formato da un insieme di sorgenti
Definiscono come la compilazione deve avvenire
per creare i binari
●
Definiscono un insieme di direttive di compilazione
●
Permettono di definire le dipendenze tra sorgenti

Solo cosa cambia e ciò che dipende da quello che è
cambiato va ricompilato

Velocizzazione dei tempi di compilazione durante lo
sviluppo
Makefiles
●
Strumenti di sviluppo comuni come Eclipse o
Netbeans costruiscono Makefile per noi

Tuttavia bene capire il funzionamento dei Makefile

Quando si crea pacchetto software non opportuno
assumere che lo strumento di sviluppo sia installato

Si esporta solo il codice ed il makefile (con eventuali
librerie)

Il processo di istallazione usa il makefile per
ricompilare il codice sulla macchina target
Makefiles: invocazione
●
Come lo si invoca

Per costruire i binari di default usando un makefile
chiamato “makefile” nella directory corrente


Per costruire il binario programma usando il makefile
di default


digitare: “make”
digitare: “make programma”
Per costruire il binario programma usando il makefile
“makefile”

digitare: “make -f makefile programma”
Makefiles: struttura
●
Righe che iniziano per # sono commenti
●
Makefile è una sequenza di comandi nella forma:
●
target: lista_dipendenze_di_target
tab
comando

Target: nome del risultato del comando, in genere è od
un binario od un file oggetto .o

lista_dipendenze_di_target: i target da cui target dipende


Target costruito se una delle dipendenze è cambiata
comando: regola da eseguire usando il terminale

Eseguito per creare il target
Makefiles: esempio
# Compiling source files (uno per ogni file .cc)
main.o : main.cc mydefs.h
g++ -c main.cc
file1.o : file1.cc file1.h mydefs.h
g++ -c file1.cc
file2.o : file2.cc command.h
g++ -c file2.cc
display.o : display.cc command.h
g++ -c display.cc
se file1.cc o file1.h o mydef.h
sono cambiati, genera target
file1.o eseguendo il comando
“g++ -c file1.cc”
# Alla fine, linking file oggetto
programma : main.o file1.o file2.o display.o
g++ -o programma main.o file1.o file2.o display.o
clean :
rm -f programma *.o
genera target clean: ripulisce il disco e
reinizia la compilazione da zero: esegue
il comando “rm -f programma *.o”
Makefiles: esempio più binari
main.o : main.cc mydefs.h
g++ -c main.cc
main1.o : main1.cc mydefs.h
g++ -c main1.cc
file1.o : file1.cc file1.h mydefs.h
g++ -c file1.cc
display.o : display.cc command.h
g++ -c display.cc
programma : main.o file1.o
g++ -o programma main.o file1.o display.o
ogni binario ha linking
separato
programma1 : main1.o file1.o file2.o display.o
g++ -o programma1 main1.o file1.o file2.o display.o
all: programma programma1
clean :
rm -f programma programma1 *.o
target all costruisce tutti i
binari, si chiama con “make all”
Make: esercizio
●
Costruire il makefile per la compilazione di 2-3 eseguibili
a vostra scelta, meglio se su piu' sorgenti, costruiti
durante il corso
Phony targets
●
●
Sono targets che specificano azioni, non creano
targets e non hanno dipendenze
Usati per ripulire lo stato della compilazione o
creare archivi
ripulisce i file generati dal
makefile stesso, si chiama con:
make clean
clean:
rm -f *.o lista_binary
tgz:
crea archivio del pacchetto
dei sorgenti, si chiama con:
make tgz
tar cvfz pacchetto.tar.gz *.cc *.h Makefile
Targets e dipendenze
●
Le dipendenze possono essere aggiunte in modo
incrementale
–
Possibile aggiungere targets che specificano solo
dipendenze ma non azioni, vedremo come usarlo
–
Esempio
#Regola di compilazione, per ora .o dipende solo da .cc corrispondente
file1.o : file1.cc
g++ -c file1.cc
# Regola che specifica dipendenze aggiuntive
# gfile1.o ora dipende sia da file1.cc che da file1.h e mydef.h
file1.o: file1.h mydef.h
Makefiles: variabili
●
Possibile definire variabili
NOME_VAR = VALORE

Per accedere al valore della variabile (equivalenti):
${NOME_VAR} o $(NOME_VAR)
Makefiles: esempio con variabili
LD=g++ # linker
CC=g++ # compilatore
programma : main.o file1.o file2.o display.o
${LD} -o prog1 main.o file1.o file2.o display.o
# Compiling source files
main.o : main.cc mydefs.h
${CC} -c main.cc
file1.o : file1.cc mydefs.h
${CC} -c file1.cc
file2.o : file2.cc command.h
${CC} -c file2.cc
display.o : display.cc command.h
${CC} -c display.cc
...
Variabili speciali
●
$@: il target per la regola corrente
●
$< : il nome della prima dipendenza
●
●
●
$?: il nome di tutte le dipendenze che sono
cambiate
$^: il nome di tutte le dipendenze separate da uno
spazio
$+ : come $^ ma eventuali dipendenze ripetute sono
rimosse
Regole implicite
●
●
Usando la seguente sintassi, possibile specificare
target generici
Per fornire una regola generale di come passare da
ogni file .cc al corrispondente .o
%.o:%.cc
${CC} -c $<
Makefile: esempio generale
CC=g++
CFLAGS=-O6 -Wall
LDFLAGS=-O6
objs = file1.o file2.o display.o
# Linking, più binari possono essere generati
programma : programma.o $(objs)
${CC} ${LDFLAGS} -o $@ $+
programma1 : programma1.o $(objs)
${CC} ${LDFLAGS} -o $@ $+
# Compilazione
%.o:%.cc
${CC} ${CFLAGS} -c $<
# Aggiunta dipendenze ulteriori
programma.o : mydefs.h programma.h
programma1.o : mydefs.h
...
all: programma programma1
clean:
rm -f programma programma1 $(objs)
primo binario, costruito se:
make programma
secondo binario, costruito se
make programma1
make all costruisce tutto
Make depend
●
●
Permette di non aggiungere le dipendenze a
mano
Analizza i files, esegue il preprocessore e
controlla #include

Infine aggiunge al makefile le dipendenze

Si esegue con comando (cerca file Makefile):
makedepend *.cc *.h

Oppure makedepend -f makefile_specifico
Make depend
●
Spesso si mette direttamente come phony target
nel makefile
SRCS = file1.cc file2.cc …
CFLAGS = …
depend:
makedepend -- $(CFLAGS) -- $(SRCS)
oppure
depend:
makedepend -- $(CFLAGS) -- *.cc

Modifica Makefile aggiungendo una linea
# DO NOT DELETE THIS LINE -- make depend depends on it.

Dopo questa linea vengono messe le dipendenze
Make: esercizio
●
Modificare il makefile costruito usando il template
generale precedentemente fornito
Programmazione condivisa
●
Source Managment Control (SMC)

Software che permette di sviluppare software in team

Tracciano i cambiamenti e chi li ha fatti

Permettono di tornare indietro nel tempo con il codice

Agevolano la risoluzione di cambiamenti conflittuali
allo stesso codice

FONDAMENTALI per lo sviluppo in azienda
Programmazione condivisa
●
Source Managment Control (SMC)

CVS: il primo ed il classico



oggi un po antiquato
ma ha imposto un modello che tutti conoscono
Subversion (SVN), quello che studieremo

Utilizzo simile al CVS

Ma riscritto completamente

Perforce: ottimo ma non gratuito

e molti altri
SMC centrealizzati e non
●
SMC centralizzati hanno un repository centralizzato

Ogni client ha sua copia decentralizzata

Un server centrale tiene la copia di riferimento
(master)

SVN è centralizzato
Working Copy
●
Repository/Master
Working Copy
Working Copy
SMC decentralizati non hanno repository centrale

Spesso basati su Peer-to-peer, i client tengono le
copie ed il repository in modo distribuito
SVN, client e server
●
SVN server tiene il repository master

Riferimento per tutte le altre copie

Le working copy sono inizializzate dal master

Cambiamenti su working copy sottomessi al master

Server contiene database ed altri tools come


Web server per controllare lo stato del master
SSH per sottomettere sul o leggere i dati dal master
Repository/Master
Clients
Working Copy
Working Copy
Server
Working Copy
SVN: architettura
Libreria per
accesso e
modifica
working copy
Accesso da
linea di comando
o interfaccia
grafica
Files che
formano la
working copy
Metodi per
accesso alla
working copy
(http, apache,...)
Libreria per
accesso e
modifica del
master
Database che
Memorizza
Repository
Working
Copy Files
SVN e comandi
●
Vedremo la gestione da linea di comando

●
Effettuata tramite il binario svn ed svnadmin

●
Possibile anche gestire via Web
Necessario installare i pacchetti corrispondenti
Help generico digitando
svn help
●
Per avere help specifico di un comando
svn help comando

Esempio “svn help import”

Tutti i comandi sono relativi ad una directory di lavoro
SVN creazione del master
# Creo directory sul server
mkdir -p /var/svn/repos
# creazione del master repository chiamato pps
sudo svnadmin create /var/svn/repos/pps
SVN importazione codice
●
●
Per iniziare un repository è possibile importare
un'intera directory con tutto il codice in essa
contenuto
Tale comando viene chiamato import

Necessario solo una volta e nel caso di progetti già
avviati

Se il progetto parte da zero tale comando non è
necessario

Vedremo come aggiungere singoli files al repository
SVN importazione codice
# Creo directory di lavoro sul client e ci copio codice
mkdir $HOME/Documents/Corsi/ProgrammazioneProgettazioneSoftware2011/src/svn/pps
# Vado su directory di lavoro, da ora in poi assumerò di essere qui
cd $HOME/Documents/Corsi/ProgrammazioneProgettazioneSoftware2011/src/svn
cp $CODICE/costruttori/* pps
# Importo il codice nel repository pps
svn import pps svn+ssh://michi@localhost//var/svn/repos/pps -m 'inital import'
Binario che
implementa
il client
Operazione
di
importazione
Opzionale:
descrizione
dell'operazione
Utente
che accede
Directory
che viene
importata
Metodo
di
accesso
URL
del master
Path di
accesso
al master
SVN creazione working copies
●
●
In qualsiasi momento è possibile creare una nuova
working copy
Comando detto checkout
# Creo una nuova working copy a partire dal repository
svn checkout svn+ssh://michi@localhost//var/svn/repos/pps pps1
URL
Repository che
viene preso
Path dove viene
fatto checkout
rispetto alla
directory corrente
SVN aggiunta files
●
●
●
●
Aggiunta files sulla working copy
Attenzione non basta avere file nella directory che si
è checked out perché siano tracciati
Solo i nuovi file aggiunti esplicitamente saranno
tracciati
Tale comando di aggiunta è detto add
# Aggiungo file da tracciare (in path su cui è stato fatto un checkout)
svn add path/file
SVN edit files
●
I files nella working copy che sono tracciati possono
essere editati da un normale editor
SVN rimozione files
●
Rimozione files sulla working copy
●
Comando detto delete o rm
# Rimuovo file da tracciare (in path su cui è stato fatto un checkout)
svn delete path/file
SVN sincronizzazione
●
●
Sincronizzazione da client a master per
sottomettere i cambiamenti fatti viene detto commit
Sottomette i cambimenti relativi all'aggiunta,
rimozione e cambiamenti sui files tracciati
svn commit -m “commento opzionale su cosa si sottomette”
SVN sincronizzazione
●
●
Sincronizzazione da master a client per ricevere i
cambiamenti fatti su altre working copy viene detta
sync o update
Sincronizza i cambimenti relativi all'aggiunta,
rimozione e cambiamenti sui files fatti da altri client
svn update
SVN iterazione di lavoro
●
A parte le inizializzazioni, le iterazioni di lavoro con
SVN sono semplici

Il 95% del tempo si digitano i seguenti comandi
svn update
svn commit -m “commento”
●
Se i cambiamenti sono su stesso file da parte di
diversi client, svn cercherà di fare l'unione (merge)
SVN e conflitti
●
●
●
Tutto è semplice tranne in un caso
Cosa succede se due persone modificano lo stesso
file nello stesso punto?
In tal caso SVN non permette a chi fa il commit per
secondo di effettuarlo

Siamo in presenza di uno o più conflitti

Possibile vedere files con conflitti con comando
svn status

Mostra files con estensione .mine e .rNumero

Necessario effettuare risoluzione dei conflitti
SVN e risoluzione conflitti
Il file con conflitto (riportato da svn status) ha linee
con conflitti evidenziate con dei markers speciali
<<<<<<< .mine
●
CODICE INSERITO SULLA WORKING COPY
===========
CODICE INSERITO SUL MASTER DOPO NOSTRO UPDATE
>>>>>>> .r23
●
Markers evidenziano codice introdotto in working
copy (.mine) e dall'altro client (.r$VERSIONE)

Markers devono essere eliminati, finché non si è
risolto il conflitto: il codice compila e funziona
correttamente
SVN e risoluzione conflitti
●
●
Dopo aver editato il file, risolto il conflitto ed
eliminato i markers, il conflitto è risolto
Per dire a SVN che il conflitto è risolto
svn resolved path/file
●
Adesso possibile effettuare il commit

Se ci sono conflitti, svn blocca i commit
SVN e backups
●
SVN usa un semplice database open-source
chiamato Berkley DB

Possibile fare backups del database con il comando
svnadmin dump /var/svn/repos/pps > backup_file

Consigliabile effettuare backups attraverso cron ogni
poche ore/minuti

Possibile ricaricare un backup precedente sul
repository master con il comando
svnadmin load /var/svn/repos/pps < backup_file
SVN ed export
●
Se volete rilasciare il codice a terze parti (non
sviluppatori)

Potete fargli fare un checkout ma questo è pesante
visto che SVN si porta dietro meta-data

Meglio semplicemente dargli i files

Possibile esportare l'albero di files (tutti i files
ricorsivamente nel repository) con il comando export
svn export svn+ssh://michi@localhost//var/svn/repos/pps output
Repository esportato
Directory dove si
esporta
SVN: uso avanzato
●
●
La trattazione fatta sulle slide di SVN copre solo una
piccola parte di cosa può fare SVN
Cose rilevanti non trattate

Branching: quando si vuole avere più copie del codice


Esempio per la versione stabile e quella sperimentale
dello stesso
Script automatici da eseguire quando si effettuano
operazioni

Esempio: per controllare che il codice rispetti un certo stile
o compili correttamente quando viene fatto il commit
SVN: uso avanzato
●
Manuale completo ed ufficiale è ben 405 pagne!
●
Scaricabile gratuitamente da
http://svnbook.red-bean.com/
●
Copre tutti gli utilizzi più avanzati anche se è
dispersivo