Skip to content
Snippets Groups Projects
Verified Commit 1a0759df authored by Marco Aceti's avatar Marco Aceti
Browse files

Add 'Lezione 06'

parent 0982c21f
No related branches found
No related tags found
No related merge requests found
# Git workflow e strumenti
In git, l'utilizzo dei branch è fortemente incentivato dal suo design e dalle sue funzionalità, rendendo praticamente impossibile lavorare senza utilizzarli. I branch consentono di creare versioni separate del codice, permettendo di lavorare su diverse funzionalità o correzioni di bug in modo indipendente e senza interferire con il codice principale.
C'è __libertà completa__ sul loro utilizzo: tutti i branch hanno pari importanza, chiunque può crearli e nominarli in qualunque modo.
Lavorando in un team, è quindi necessario stabilire delle politiche sui tipi e i nomi di branch, in modo da organizzare il lavoro al meglio.
- [**GitFlow**](./01_gitflow.md): organizzazione branch
- [**Hosting centralizzato**](./02_hosting-centralizzato.md): repository centrali git
- [**Gerrit**](./03_gerrit.md): meccanismo di review in team
- [**Strumenti dell'opensource**](./04_strumenti-opensource/00_index.md): strumenti opensource per build automation e bug tracking
---
layout: post
title: "[06] Git workflow"
date: 2022-10-19 14:45:00 +0200
toc: true
---
# Git Workflow
In Git, l'utilizzo dei branch è fortemente incentivato dal suo design e dalle sue funzionalità, rendendo praticamente impossibile lavorare senza utilizzarli. I branch consentono di creare versioni separate del codice, permettendo di lavorare su diverse funzionalità o correzioni di bug in modo indipendente e senza interferire con il codice principale.
C'è __libertà completa__ sul loro utilizzo: tutti i branch hanno pari importanza, chiunque può crearli e nominarli in qualunque modo.
Lavorando in un team, è quindi necessario stabilire delle politiche sui tipi e i nomi di branch, in modo da organizzare il lavoro al meglio.
## GitFlow
# GitFlow
GitFlow è una tecnica di organizzazione dei branch e delle repository che prevede la creazione sia di diversi tipi di branch a vita limitata che il loro _merge_ guidato.
......@@ -26,9 +12,9 @@ I branch e i tipi di branch previsti da GitFlow sono:
- release branches;
- hotfix branches.
### `develop` e `master`
## `develop` e `master`
{% responsive_image path: 'assets/06_gitflow-develop-master.png' %}
![GitFlow develop e master](/assets/06_gitflow-develop-master.png)
In GitFlow, ci sono due branch che hanno una durata più lunga rispetto ai branch temporanei utilizzati per lavorare su specifiche funzionalità o correzioni di bug:
- __`master`__: contiene le versioni stabili del codice sorgente, pronte per essere consegnate o rilasciate al cliente o al pubblico. Queste versioni sono considerate _affidabili_ e _testate_, quindi possono essere utilizzate in produzione;
......@@ -36,9 +22,9 @@ In GitFlow, ci sono due branch che hanno una durata più lunga rispetto ai branc
Al termine di ogni rilascio, il contenuto del branch `develop` viene integrato nel branch `master`, che rappresenta la versione stabile del codice. Le _versioni notturne_, invece, sono versioni di sviluppo che vengono rilasciate periodicamente e contengono le ultime modifiche apportate al codice. Esse vengono create partendo dal branch `develop`, che rappresenta il punto di integrazione di tutti i contributi dei gruppi di lavoro.
### Feature
## Feature
{% responsive_image path: 'assets/06_gitflow-feature.png' width: "400" %}
![GitFlow feature](/assets/06_gitflow-feature.png)
I __*feature branch*__ sono branch temporanei utilizzati per sviluppare nuove funzionalità o per correggere bug. __Possono essere creati solo a partire dal branch `develop`__ e vengono utilizzati per isolare il lavoro su una specifica funzionalità o problema dal resto del codice.
Quando il lavoro è completato, il feature branch viene integrato di nuovo nel `develop` tramite un merge.
......@@ -63,27 +49,27 @@ $ git checkout develop # entra nel branch develop
$ git merge --no-ff feature/myFeature # mergia il branch di feature
$ git branch -d feature/myFeature # elimina il branch di feature
```
#### `--no-fast-forward`
### `--no-fast-forward`
{% responsive_image path: 'assets/06_gitflow-feature-ff.png' %}
![GitFlow fast forward](/assets/06_gitflow-feature-ff.png)
Di default, Git risolve il merge di due branch con la stessa storia banalmente eseguendo il _fast forward_, ovvero spostando il puntatore del branch di destinazione all'ultimo commit del branch entrante.
Di default, git risolve il merge di due branch con la stessa storia banalmente eseguendo il _fast forward_, ovvero spostando il puntatore del branch di destinazione all'ultimo commit del branch entrante.
In GitFlow è preferibile esplicitamente __disabilitare il fast forward__ (con l'opzione `--no-ff`) durante il merge in `develop` in quanto è più facile distinguere il punto di inizio e il punto di fine di una feature.
### Squashing
## Squashing
Usando Git è anche possibile eseguire in fase di merge lo _squashing_ dei commit, ovvero la fusione di tutti i commit del branch entrante in uno solo.
Usando git è anche possibile eseguire in fase di merge lo _squashing_ dei commit, ovvero la fusione di tutti i commit del branch entrante in uno solo.
Questa operazione è utile per migliorare la leggibilità della history dei commit su branch grossi (come `develop` o `master`) ma il suo uso in GitFlow è opinabile: il prof. Bellettini consiglia di non utilizzarlo, in modo da mantenere i commit originali.
### Release
## Release
{% responsive_image path: 'assets/06_gitflow-release.png' %}
![GitFlow release](/assets/06_gitflow-release.png)
Lo scopo di creare una release è __cristalizzare l'insieme delle funzionalità__ presente sul branch `develop` all'inizio di essa dedicandosi solo alla sistemazione degli errori o alle attività necessarie per il deploy (modifica del numero di versione, ...).
L'insieme delle funzionalità rilasciate è quello presente sul branch `develop` al momento di inizio di una release.
I bug fix possono essere ri-mergiati in `develop`, anche utilizzando la funzionalità __cherry-pick__ di Git; essa permette di selezionare un commit specifico da un ramo e applicarlo in un altro ramo.
I bug fix possono essere ri-mergiati in `develop`, anche utilizzando la funzionalità __cherry-pick__ di git; essa permette di selezionare un commit specifico da un ramo e applicarlo in un altro ramo.
Ad esempio, se si ha un ramo di sviluppo ("`develop`") e un ramo di release ("`release`"), è possibile utilizzare il cherry-pick per selezionare solo i commit che contengono bugfix e applicarli al ramo di release, senza dover fare un merge di tutto il ramo di sviluppo.
Ciò può essere utile in casi in cui si vuole mantenere la stabilità del ramo di release, includendo solo i bugfix considerati essenziali per la release.
......@@ -105,14 +91,14 @@ $ git merge --no-ff release/v1.2.3 # mergia la feature
$ git branch -d release/v1.2.3 # elimina il branch della feature
```
In Git, i tag sono etichette che possono essere applicate a un commit per segnalarne l'importanza o per marcare un punto specifico dello storico del repository. Un __tag è un puntatore costante al commit__ a cui è stato applicato, quindi non cambia mai e permette di fare riferimento in modo stabile a una versione specifica del codice. Al contrario, i branch sono puntatori dinamici che vanno avanti nel tempo, seguendo l'evoluzione del codice attraverso i nuovi commit
In git, i tag sono etichette che possono essere applicate a un commit per segnalarne l'importanza o per marcare un punto specifico dello storico del repository. Un __tag è un puntatore costante al commit__ a cui è stato applicato, quindi non cambia mai e permette di fare riferimento in modo stabile a una versione specifica del codice. Al contrario, i branch sono puntatori dinamici che vanno avanti nel tempo, seguendo l'evoluzione del codice attraverso i nuovi commit
In GitFlow, le release sono versioni stabili del codice che vengono rilasciate al pubblico o al cliente.
Ogni release viene creata partendo dal branch `develop` e viene gestita come un branch a sé stante, che viene chiuso una volta che tutte le modifiche previste sono state integrate.
Al contrario, le feature sono branch temporanei utilizzati per sviluppare nuove funzionalità o per correggere bug.
È possibile avere più feature aperte contemporaneamente, ma solo una release rimanere aperta in un dato istante.
### Hotfix
## Hotfix
Un _hotfix_ è una riparazione veloce di difetti urgenti senza dover aspettare la prossima release.
È l'unico caso per cui non si parte da `develop`, ma dall'ultima - o una particolare - versione rilasciata su `master`.
......@@ -131,17 +117,17 @@ $ git merge --no-ff hotfix/CVE-123 # mergia l'hotfix
$ git branch -d hotfix/CVE-123 # elimina il branch di hotfix
```
## Limiti
# Limiti
Quali sono i limiti di git presentato così?
Git e GitFlow come sono stati esposti presentano numerosi vincoli, tra cui:
git e GitFlow come sono stati esposti presentano numerosi vincoli, tra cui:
- la __mancanza di un sistema di autorizzazione granulare__, ovvero la possibilità di assegnare permessi in modo specifico e mirato a diverse funzionalità o risorse. Inoltre, non esiste una distinzione tra diversi livelli di accesso, quindi o si ha accesso completo a tutte le funzionalità o non si ha accesso a niente;
- l'__assenza di code review__, ovvero il processo di revisione del codice sorgente da parte di altri sviluppatori prima che venga integrato nel codice base.
### git request-pull - generates a summary of pending changes
## `git request-pull` — _generates a summary of pending changes_
Il tool `git request-pull` è un comando di Git che serve per formattare e inviare una proposta di modifiche a un repository tramite una mailing list.
Il tool `git request-pull` è un comando di git che serve per formattare e inviare una proposta di modifiche a un repository tramite una mailing list.
Il comando crea un messaggio di posta elettronica che chiede al maintainer del repository di "pullare" le modifiche, ovvero di integrarle nel codice base.
Oggi, questa pratica è stata in molti progetti sostituita dalle pull request, che sono richieste di integrazione delle modifiche presentate attraverso un'interfaccia web.
Le pull request offrono una serie di vantaggi rispetto alle richieste via email, come una maggiore trasparenza del processo di integrazione, una maggiore efficienza e una maggiore facilità di utilizzo.
......@@ -159,7 +145,7 @@ The following changes since commit a16f3a0488c062d7b61dc4af15c2ba8081166040:
Handle '/sweng' path (2022-11-25 19:14:40 +0100)
are available in the Git repository at:
are available in the git repository at:
git@gitlab.di.unimi.it:silab-gang/sweng.git lezioni/09
......@@ -185,7 +171,7 @@ Marco Aceti (14):
Merge branch 'master' into lezioni/09
Replace hook UMLs images with PlantUML
Merge branch 'master' into lezioni/09
Fix GitLab CI (take 2)
Fix gitLab CI (take 2)
Refactor diagrams until 'Strategy'
Refactor all remaining diagrams
Merge remote-tracking branch 'gitlab/master' into lezioni/09
......@@ -228,228 +214,3 @@ Matteo Mangioni (18):
```
Questo modello è molto più _peer to peer_ delle pull request proposte dai sistemi semi-centralizzati spiegati in seguito.
# Hosting centralizzato
Un hosting centralizzato Git è un servizio che fornisce una repository centrale per i progetti Git dove i contributi vengono integrati e gestiti, garantendo una maggiore trasparenza e controllo del processo di sviluppo e mantenendo molti vantaggi della decentralizzazione, come la possibilità di lavorare in modo asincrono e autonomo.
Gli hosting centralizzati come GitHub e GitLab, nella loro costante evoluzione, spesso inventano nuovi meccanismi e provano a imporre nuovi workflow, come il GitHub Flow o il GitLab Flow, per semplificare e ottimizzare il processo di sviluppo. Tuttavia, è importante valutare attentamente questi nuovi approcci e verificare se si adattano alle esigenze specifiche del progetto e della squadra di sviluppo.
Inoltre, molti servizi di hosting centralizzati offrono funzionalità aggiuntive, come la possibilità di eseguire il "fork" di un repository, inviare _pull request_ per le modifiche e di utilizzare strumenti di continuous integration (CI) per testare automaticamente le modifiche apportate al codice.
## Fork
Il "fork" di un repository Git è una __copia del repository originale__ che viene creata su un account di hosting diverso dal proprietario originale.
Questo permette a un altro sviluppatore di creare una copia del repository e di lavorare su di essa senza influire sul lavoro del proprietario originale e __senza la sua autorizzazione__.
È possibile quindi mantenere una _connessione_ tra i due repository e condividere facilmente le modifiche apportate.
La maggioranza delle piattaforme di hosting centralizzato __ottimizza la condivisione dello spazio degli oggetti__, utilizzando un'unica _repository fisica_ per tutti i fork.
Tuttavia, questo può comportare alcune problematiche di sicurezza, come ad esempio la difficoltà per la piattaforma di stabilire in quale fork si trova un determinato oggetto in caso di conflitto o la possibilità che un utente malintenzionato possa modificare o eliminare accidentalmente oggetti di altri fork.
Per questo motivo, è importante che le piattaforme implementino __misure di sicurezza adeguate__ per proteggere i dati dei fork e garantire la tracciabilità delle modifiche ([esempio sul kernel Linux](https://github.com/torvalds/linux/commit/b4061a10fc29010a610ff2b5b20160d7335e69bf)).
## Review / Pull request
Tra la creazione di una pull request e il suo _merge_, specialmente nei progetti open source (dove chiunque può proporre qualsiasi patch) è fondamentale prevedere un processo di __review__.
{% responsive_image path: 'assets/06_pull-request.png' %}
La funzionalità di _review/pull request_ permette di facilitare le interazioni tra gli sviluppatori utilizzando il sito di hosting come luogo comune per la discussione informale e la revisione delle modifiche.
## Continous integration (CI)
Come accennato in precedenza, molti servizi di hosting centralizzati offrono strumenti di __continuous integration__ (CI) che possono essere utilizzati per testare automaticamente le modifiche proposte nella pull request.
Questi strumenti consentono di verificare che le modifiche non introducano errori o vulnerabilità e di garantire che il codice sia pronto per essere integrato nel repository principale.
Possono essere utilizzati anche per eseguire automaticamente la _suite di test_ o automatizzare il deployment.
{% responsive_image path: 'assets/06_ci-cd.png' %}
# Gerrit
Gerrit è un __sistema di review__ del codice sviluppato internamente da Google per gestire i progetti interni; si basa sul concetto di "peer review": tutti gli sviluppatori sono autorizzati a fare review delle proposte di modifica di qualsiasi zona di codice.
Nel processo di review di Gerrit, i __developer__ possono sottoporre proposte di cambiamento utilizzando un sistema di "patch" che descrive le modifiche apportate al codice.
I __reviewer__, ovvero gli altri sviluppatori del progetto, possono quindi esaminare le patch e decidere se accettarle o rifiutarle.
Una volta che una patch ha ricevuto un numero sufficiente di review positivi, viene automaticamente integrata nel __repository principale autoritativo__ in cui tutti hanno accesso in sola lettura.
Gerrit obbliga a strutturare le modifiche (_changeset_) in un unico commit (tecnica _squash_) al momento dell'accettazione.
Ciò significa che tutte le modifiche apportate devono essere fuse in un unico commit, in modo da rendere più facile la gestione del repository.
Al momento della review, invece, le modifiche rimangono separate in versioni singole, ovvero ogni modifica viene presentata come un commit separato, in modo che i reviewer possano esaminarle più facilmente.
## Verifier
Il verifier è uno strumento o un processo che viene utilizzato in Gerrit per verificare che le modifiche proposte siano corrette e funzionino come dovrebbero.
In particolare, il verifier scarica la patch, la compila, esegue i test e controlla che ci siano tutte le funzioni necessarie.
Se il verifier rileva dei problemi, può segnalarli al team di sviluppo perché vengano corretti prima che la patch venga accettata.
Una volta terminato il proprio processo, approva le modifiche votandole positivamente.
Solitamente sono necessari 1 o 2 voti per procedere.
## Approver
Una volta verificata, una proposta di modifiche deve essere anche approvata.
L'approvatore deve determinare la risposta alle seguenti domande riguardo la proposta di modifiche:
- _è valida per lo scopo del progetto?_
- _è valida per l'architettura del progetto?_
- _introduce nuove falle nel design che potrebbero causare problemi in futuro?_
- _segue le best practices stabilite dal progetto?_
- _è un buon modo per implementare la propria funzione?_
- _introduce rischi per la sicurezza o la stabilità?_
Se l'approver ritiene che la proposta di modifiche sia valida, può approvarla scrivendo "LGTM" (acronimo di _"Looks Good To Me"_) nei commenti della pull request.
# Strumenti dell'open source
Gli strumenti dell'open source sono una serie di programmi, librerie e servizi che vengono utilizzati per sviluppare progetti open source.
Questi strumenti sono pensati per semplificare il processo di sviluppo e gestione di progetti open source, rendendoli accessibili a una comunità di sviluppatori e contribuenti.
## Build automation
La build automation è un processo fondamentale nello sviluppo di software open source, che consiste nel creare un sistema automatizzato per compilare il codice sorgente in un eseguibile.
Questo processo è importante perché consente di risparmiare tempo e risorse, evitando di dover compilare manualmente il codice ogni volta che si apportano modifiche.
Inoltre, la build automation garantisce una maggiore qualità e coerenza del software, poiché il processo di compilazione viene eseguito in modo uniforme ogni volta.
### make
`make` è uno strumento di build automation che viene utilizzato per automatizzare il processo di compilazione di un progetto.
In particolare, `make` viene utilizzato per specificare come ottenere determinati _targets_ (obiettivi), ovvero file o azioni che devono essere eseguite, partendo dal codice sorgente.
Ad esempio, in un progetto di sviluppo software, un _target_ potrebbe essere il file eseguibile del programma, che viene ottenuto compilando il codice sorgente.
`make` segue la filosofia _pipeline_, ovvero prevede l'utilizzo di singoli comandi semplici concatenati per svolgere compiti più complessi.
È supportata la _compilazione incrementale_, ovvero il fatto di compilare solo le parti del progetto che sono state modificate dall'ultima volta, al fine di velocizzare il processo.
Inoltre, vengono gestite le _dipendenze_ tra file, ovvero le relazioni tra i diversi file che compongono il progetto: se un file sorgente dipende da un altro file, make assicura che il file dipendente venga compilato solo dopo che il file da cui dipende è stato compilato.
Ciò garantisce che il progetto venga compilato in modo coerente e che le modifiche apportate a un file siano considerate correttamente nella compilazione dei file dipendenti.
```make
CC=gcc
CFLAGS=-I.
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: hellomake.c hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o $< $(CFLAGS)
```
Nell'esempio, se il _target_ hellomake (definito dai file `hellomake.c` e `hellofunc.o`) è stato aggiornato, occorre ricompilarlo utilizzando i comandi sotto.
Tuttavia, make lavora a un livello molto basso, il che può rendere facile commettere errori durante la sua configurazione e utilizzo.
Non c'è portabilità tra macchine (ambienti) diverse.
#### Makefile
Un _Makefile_ è un file di testo che contiene le istruzioni per il programma make su come compilare e linkare i file sorgente di un progetto.
Ogni riga del Makefile definisce un obiettivo o una dipendenza, insieme ai comandi che devono essere eseguiti per raggiungerlo.
L'utilizzo del Makefile permette di automatizzare la compilazione e il linkaggio dei file sorgente, semplificando il processo di sviluppo di un progetto.
Nell'esempio menzionato, il Makefile definisce il target `hellomake`, che dipende dai file `hellomake.c` e `hellofunc.o`, e fornisce i comandi per compilarli e linkarli insieme.
#### Generazione automatica
Sono stati creati dei tool (`automake`, `autoconf`, `imake`, ...) che _generano_ `Makefile` ad-hoc per l'ambiente attuale.
Il _mantra_:
```bash
$ ./configure
$ make all
$ sudo make install
```
era largamente utilizzato per generare un Makefile ad-hoc per l'ambiente attuale e installare il software sulla macchina in modo automatico.
`automake`, `autoconf`, e `imake` sono strumenti che aiutano a questo scopo, generando Makefile che possono essere utilizzati per compilare e installare il software in modo automatico.
### Ant
Ant nasce in Apache per supportare il progetto Tomcat.
Data una __definizione in XML__ della struttura del progetto e delle dipendenze invocava comandi programmati tramite classi Java per compilare il progetto.
Il vantaggio è che Java offre un livello d'astrazione sufficiente a rendere il sistema di build portabile su tutte le piattaforme.
Nella versione base supporta integrazioni con altri tool come CVS, Junit, FTP, JavaDOCS, JAR, ecc...
Non solo compila, ma fa anche deployment.
Il deployment consiste nell'installare e configurare un'applicazione o un sistema su uno o più server o ambienti di esecuzione.
Nel contesto di Ant, il deployment può includere l'invocazione di comandi per copiare i file del progetto sui server di destinazione, configurare le impostazioni di sistema o dell'applicazione, avviare o fermare servizi o processi, e così via.
In questo modo, Ant può essere utilizzato non solo per compilare il progetto, ma anche per distribuirlo e rendere disponibile l'applicazione o il sistema ai suoi utenti.
I target possono avere dipendenze da altri target.
I target contengono task che fanno effettivamente il lavoro; si possono aggiungere nuovi tipi di task definendo nuove classi Java.
Esempio di un build file:
```xml
<?xml version="1.0"?>
<project name="Hello" default="compile">
<target name="clean" description="remove intermediate files">
<delete dir="classes" />
</target>
<target name="clobber" depends="clean" description="remove all artifact files">
<delete file="hello.jar">
</target>
<target name="compile" description="compile the Java source code to class files">
<mkdir dir="classes" />
<javac srcdir="." destdir="classes" />
</target>
<target name="jar" depends="compile" description="create a Jar file for the application">
<jar destfile="hello.jar">
<fileset dir="classes" includes="**/*.class" />
<manifest>
<attribute name="Main-Class" value="HelloProgram" />
</manifest>
</jar>
</target>
</project>
```
### Gradle
Gradle è uno strumento di build automation che utilizza le repository Maven come punto di accesso alle librerie di terze parti.
Maven è una piattaforma di gestione delle dipendenze e della build automation per il linguaggio di programmazione Java.
Le repository Maven sono archivi online che contengono librerie Java, plugin e altri componenti utilizzati nella build di progetti Java.
Gradle utilizza queste repository per cercare e scaricare le librerie di cui ha bisogno per eseguire la build del progetto.
Gradle, che supporta Groovy o Kotlin come linguaggi di scripting, adotta un approccio dichiarativo e fortemente basato su convenzioni.
Ciò significa che tutto ciò che è già stato definito come standard non deve essere ridichiarato.
Inoltre, Gradle definisce un linguaggio specifico per la gestione delle dipendenze e permette di creare build multi-progetto.
Gradle scala bene in complessità: permette di fare cose semplici senza usare le funzioni complesse.
È estendibile tramite plugin che servono per trattare tool, situazioni, linguaggi legati solitamente al mondo Java.
#### Plugin
I plugin servono per trattare tool, situazioni, linguaggi definendo task e regole per lavorare più facilmente.
Il plugin _Java_ definisce:
- una serie di __sourceSet__, ovvero dove è presente il codice e le risorse. Principalmente sono:
- `src/main/java`: sorgenti Java di produzione;
- `src/main/resources`: risorse di produzione;
- `src/test/java`: sorgenti Java di test;
- `src/test/resources`: risorse di test.
- dei __task__, anche con dipendenze tra loro.
{% responsive_image path: 'assets/06_gradle-tasks.png' %}
#### Altri plugin
- application, per l'esecuzione;
- FindBugs, jacoco: per la verifica e la convalida;
- eclipse, idea: per integrazione con gli IDE;
## Bug tracking
Il bug tracking è stato reso necessario nel mondo open source per via della numerosità dei contributi e della alta probabilità di avere segnalazioni duplicate.
Inoltre, per gestire le segnalazioni di bug nell'ambito dello sviluppo open source, esistono diversi strumenti come git-bug, BugZilla, Scarab, GNATS, BugManager e Mantis.
### Bug workflow
{% responsive_image path: 'assets/06_bug-workflow.png' %}
L'obiettivo del bug tracking è avere più informazioni possibili su ogni bug per saperli riprodurre e quindi arrivare a una soluzione.
È importante verificare i bug una volta che l'_issue_ è stato aperto, in modo da poter confermare la sua esistenza e la completezza delle informazioni fornite.
Un _issue_ è un problema o una richiesta di funzionalità segnalata all'interno di un progetto di software.
Gli issue vengono solitamente utilizzati per tenere traccia dei problemi noti o delle richieste di nuove funzionalità all'interno di un progetto, e possono essere gestiti attraverso un sistema di bug tracking o gestione delle richieste.
Gli issue possono essere aperti da qualsiasi membro del team o dalla comunità, e possono essere risolti o chiusi da un membro del team responsabile.
Ci sono diversi modi per cui può essere chiuso un bug:
- __duplicate__: quando è stato già segnalato in precedenza e quindi non rappresenta un problema nuovo. In questo caso, viene solitamente fatto riferimento al numero del bug originale che ha già ricevuto una risoluzione;
- __wontfix__: il bug viene chiuso come "non risolvibile" perché o rappresenta una funzionalità voluta dal progetto o è troppo complesso da risolvere per essere considerato conveniente farlo dal punto di vista dei progettisti;
- __can't reproduce__: non è stato possibile riprodurre il bug, ovvero che non è stato possibile ottenere lo stesso risultato o il comportamento segnalato dal bug. Ciò può essere dovuto a una mancanza di dettagli o a un errore nella segnalazione del bug stesso;
- __fixed__: il bug è stato fixato;
vs __fix verified__: il fix è stato integrato in una release passando tutti gli step di verifica.
# Hosting centralizzato
Un hosting centralizzato Git è un servizio che fornisce una repository centrale per i progetti Git dove i contributi vengono integrati e gestiti, garantendo una maggiore trasparenza e controllo del processo di sviluppo e mantenendo molti vantaggi della decentralizzazione, come la possibilità di lavorare in modo asincrono e autonomo.
Gli hosting centralizzati come GitHub e GitLab, nella loro costante evoluzione, spesso inventano nuovi meccanismi e provano a imporre nuovi workflow, come il GitHub Flow o il GitLab Flow, per semplificare e ottimizzare il processo di sviluppo. Tuttavia, è importante valutare attentamente questi nuovi approcci e verificare se si adattano alle esigenze specifiche del progetto e della squadra di sviluppo.
Inoltre, molti servizi di hosting centralizzati offrono funzionalità aggiuntive, come la possibilità di eseguire il "fork" di un repository, inviare _pull request_ per le modifiche e di utilizzare strumenti di continuous integration (CI) per testare automaticamente le modifiche apportate al codice.
## Fork
Il "fork" di un repository Git è una __copia del repository originale__ che viene creata su un account di hosting diverso dal proprietario originale.
Questo permette a un altro sviluppatore di creare una copia del repository e di lavorare su di essa senza influire sul lavoro del proprietario originale e __senza la sua autorizzazione__.
È possibile quindi mantenere una _connessione_ tra i due repository e condividere facilmente le modifiche apportate.
La maggioranza delle piattaforme di hosting centralizzato __ottimizza la condivisione dello spazio degli oggetti__, utilizzando un'unica _repository fisica_ per tutti i fork.
Tuttavia, questo può comportare alcune problematiche di sicurezza, come ad esempio la difficoltà per la piattaforma di stabilire in quale fork si trova un determinato oggetto in caso di conflitto o la possibilità che un utente malintenzionato possa modificare o eliminare accidentalmente oggetti di altri fork.
Per questo motivo, è importante che le piattaforme implementino __misure di sicurezza adeguate__ per proteggere i dati dei fork e garantire la tracciabilità delle modifiche ([esempio sul kernel Linux](https://github.com/torvalds/linux/commit/b4061a10fc29010a610ff2b5b20160d7335e69bf)).
## Review / Pull request
Tra la creazione di una pull request e il suo _merge_, specialmente nei progetti open source (dove chiunque può proporre qualsiasi patch) è fondamentale prevedere un processo di __review__.
![Pull request](/assets/06_pull-request.png)
La funzionalità di _review/pull request_ permette di facilitare le interazioni tra gli sviluppatori utilizzando il sito di hosting come luogo comune per la discussione informale e la revisione delle modifiche.
## Continous integration (CI)
Come accennato in precedenza, molti servizi di hosting centralizzati offrono strumenti di __continuous integration__ (CI) che possono essere utilizzati per testare automaticamente le modifiche proposte nella pull request.
Questi strumenti consentono di verificare che le modifiche non introducano errori o vulnerabilità e di garantire che il codice sia pronto per essere integrato nel repository principale.
Possono essere utilizzati anche per eseguire automaticamente la _suite di test_ o automatizzare il deployment.
![CI/CD](/assets/06_ci-cd.png)
# Gerrit
Gerrit è un __sistema di review__ del codice sviluppato internamente da Google per gestire i progetti interni; si basa sul concetto di "peer review": tutti gli sviluppatori sono autorizzati a fare review delle proposte di modifica di qualsiasi zona di codice.
Nel processo di review di Gerrit, i __developer__ possono sottoporre proposte di cambiamento utilizzando un sistema di "patch" che descrive le modifiche apportate al codice.
I __reviewer__, ovvero gli altri sviluppatori del progetto, possono quindi esaminare le patch e decidere se accettarle o rifiutarle.
Una volta che una patch ha ricevuto un numero sufficiente di review positivi, viene automaticamente integrata nel __repository principale autoritativo__ in cui tutti hanno accesso in sola lettura.
Gerrit obbliga a strutturare le modifiche (_changeset_) in un unico commit (tecnica _squash_) al momento dell'accettazione.
Ciò significa che tutte le modifiche apportate devono essere fuse in un unico commit, in modo da rendere più facile la gestione del repository.
Al momento della review, invece, le modifiche rimangono separate in versioni singole, ovvero ogni modifica viene presentata come un commit separato, in modo che i reviewer possano esaminarle più facilmente.
## Verifier
Il verifier è uno strumento o un processo che viene utilizzato in Gerrit per verificare che le modifiche proposte siano corrette e funzionino come dovrebbero.
In particolare, il verifier scarica la patch, la compila, esegue i test e controlla che ci siano tutte le funzioni necessarie.
Se il verifier rileva dei problemi, può segnalarli al team di sviluppo perché vengano corretti prima che la patch venga accettata.
Una volta terminato il proprio processo, approva le modifiche votandole positivamente.
Solitamente sono necessari 1 o 2 voti per procedere.
## Approver
Una volta verificata, una proposta di modifiche deve essere anche approvata.
L'approvatore deve determinare la risposta alle seguenti domande riguardo la proposta di modifiche:
- _è valida per lo scopo del progetto?_
- _è valida per l'architettura del progetto?_
- _introduce nuove falle nel design che potrebbero causare problemi in futuro?_
- _segue le best practices stabilite dal progetto?_
- _è un buon modo per implementare la propria funzione?_
- _introduce rischi per la sicurezza o la stabilità?_
Se l'approver ritiene che la proposta di modifiche sia valida, può approvarla scrivendo "LGTM" (acronimo di _"Looks Good To Me"_) nei commenti della pull request.
# Strumenti dell'open source
Gli strumenti dell'open source sono una serie di programmi, librerie e servizi che vengono utilizzati per sviluppare progetti open source.
Questi strumenti sono pensati per semplificare il processo di sviluppo e gestione di progetti open source, rendendoli accessibili a una comunità di sviluppatori e contribuenti.
- [**Build automation**](./01_build-automation.md): `make`, Ant e Gradle
- [**Bug tracking**](./02_bug-tracking.md): tecniche di bug workflow
# Build automation
La build automation è un processo fondamentale nello sviluppo di software open source, che consiste nel creare un sistema automatizzato per compilare il codice sorgente in un eseguibile.
Questo processo è importante perché consente di risparmiare tempo e risorse, evitando di dover compilare manualmente il codice ogni volta che si apportano modifiche.
Inoltre, la build automation garantisce una maggiore qualità e coerenza del software, poiché il processo di compilazione viene eseguito in modo uniforme ogni volta.
## `make`
`make` è uno strumento di build automation che viene utilizzato per automatizzare il processo di compilazione di un progetto.
In particolare, `make` viene utilizzato per specificare come ottenere determinati _targets_ (obiettivi), ovvero file o azioni che devono essere eseguite, partendo dal codice sorgente.
Ad esempio, in un progetto di sviluppo software, un _target_ potrebbe essere il file eseguibile del programma, che viene ottenuto compilando il codice sorgente.
`make` segue la filosofia _pipeline_, ovvero prevede l'utilizzo di singoli comandi semplici concatenati per svolgere compiti più complessi.
È supportata la _compilazione incrementale_, ovvero il fatto di compilare solo le parti del progetto che sono state modificate dall'ultima volta, al fine di velocizzare il processo.
Inoltre, vengono gestite le _dipendenze_ tra file, ovvero le relazioni tra i diversi file che compongono il progetto: se un file sorgente dipende da un altro file, make assicura che il file dipendente venga compilato solo dopo che il file da cui dipende è stato compilato.
Ciò garantisce che il progetto venga compilato in modo coerente e che le modifiche apportate a un file siano considerate correttamente nella compilazione dei file dipendenti.
```make
CC=gcc
CFLAGS=-I.
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: hellomake.c hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o $< $(CFLAGS)
```
Nell'esempio, se il _target_ hellomake (definito dai file `hellomake.c` e `hellofunc.o`) è stato aggiornato, occorre ricompilarlo utilizzando i comandi sotto.
Tuttavia, make lavora a un livello molto basso, il che può rendere facile commettere errori durante la sua configurazione e utilizzo.
Non c'è portabilità tra macchine (ambienti) diverse.
### `Makefile`
Un _Makefile_ è un file di testo che contiene le istruzioni per il programma make su come compilare e linkare i file sorgente di un progetto.
Ogni riga del Makefile definisce un obiettivo o una dipendenza, insieme ai comandi che devono essere eseguiti per raggiungerlo.
L'utilizzo del Makefile permette di automatizzare la compilazione e il linkaggio dei file sorgente, semplificando il processo di sviluppo di un progetto.
Nell'esempio menzionato, il Makefile definisce il target `hellomake`, che dipende dai file `hellomake.c` e `hellofunc.o`, e fornisce i comandi per compilarli e linkarli insieme.
### Generazione automatica
Sono stati creati dei tool (`automake`, `autoconf`, `imake`, ...) che _generano_ `Makefile` ad-hoc per l'ambiente attuale.
Il _mantra_:
```bash
$ ./configure
$ make all
$ sudo make install
```
era largamente utilizzato per generare un Makefile ad-hoc per l'ambiente attuale e installare il software sulla macchina in modo automatico.
`automake`, `autoconf`, e `imake` sono strumenti che aiutano a questo scopo, generando Makefile che possono essere utilizzati per compilare e installare il software in modo automatico.
## Ant
Ant nasce in Apache per supportare il progetto Tomcat.
Data una __definizione in XML__ della struttura del progetto e delle dipendenze invocava comandi programmati tramite classi Java per compilare il progetto.
Il vantaggio è che Java offre un livello d'astrazione sufficiente a rendere il sistema di build portabile su tutte le piattaforme.
Nella versione base supporta integrazioni con altri tool come CVS, Junit, FTP, JavaDOCS, JAR, ecc...
Non solo compila, ma fa anche deployment.
Il deployment consiste nell'installare e configurare un'applicazione o un sistema su uno o più server o ambienti di esecuzione.
Nel contesto di Ant, il deployment può includere l'invocazione di comandi per copiare i file del progetto sui server di destinazione, configurare le impostazioni di sistema o dell'applicazione, avviare o fermare servizi o processi, e così via.
In questo modo, Ant può essere utilizzato non solo per compilare il progetto, ma anche per distribuirlo e rendere disponibile l'applicazione o il sistema ai suoi utenti.
I target possono avere dipendenze da altri target.
I target contengono task che fanno effettivamente il lavoro; si possono aggiungere nuovi tipi di task definendo nuove classi Java.
Esempio di un build file:
```xml
<?xml version="1.0"?>
<project name="Hello" default="compile">
<target name="clean" description="remove intermediate files">
<delete dir="classes" />
</target>
<target name="clobber" depends="clean" description="remove all artifact files">
<delete file="hello.jar">
</target>
<target name="compile" description="compile the Java source code to class files">
<mkdir dir="classes" />
<javac srcdir="." destdir="classes" />
</target>
<target name="jar" depends="compile" description="create a Jar file for the application">
<jar destfile="hello.jar">
<fileset dir="classes" includes="**/*.class" />
<manifest>
<attribute name="Main-Class" value="HelloProgram" />
</manifest>
</jar>
</target>
</project>
```
## Gradle
Gradle è uno strumento di build automation che utilizza le repository Maven come punto di accesso alle librerie di terze parti.
Maven è una piattaforma di gestione delle dipendenze e della build automation per il linguaggio di programmazione Java.
Le repository Maven sono archivi online che contengono librerie Java, plugin e altri componenti utilizzati nella build di progetti Java.
Gradle utilizza queste repository per cercare e scaricare le librerie di cui ha bisogno per eseguire la build del progetto.
Gradle, che supporta Groovy o Kotlin come linguaggi di scripting, adotta un approccio dichiarativo e fortemente basato su convenzioni.
Ciò significa che tutto ciò che è già stato definito come standard non deve essere ridichiarato.
Inoltre, Gradle definisce un linguaggio specifico per la gestione delle dipendenze e permette di creare build multi-progetto.
Gradle scala bene in complessità: permette di fare cose semplici senza usare le funzioni complesse.
È estendibile tramite plugin che servono per trattare tool, situazioni, linguaggi legati solitamente al mondo Java.
### Plugin
I plugin servono per trattare tool, situazioni, linguaggi definendo task e regole per lavorare più facilmente.
Il plugin _Java_ definisce:
- una serie di __sourceSet__, ovvero dove è presente il codice e le risorse. Principalmente sono:
- `src/main/java`: sorgenti Java di produzione;
- `src/main/resources`: risorse di produzione;
- `src/test/java`: sorgenti Java di test;
- `src/test/resources`: risorse di test.
- dei __task__, anche con dipendenze tra loro.
![Task gradle](/assets/06_gradle-tasks.png)
### Altri plugin
- application, per l'esecuzione;
- FindBugs, jacoco: per la verifica e la convalida;
- eclipse, idea: per integrazione con gli IDE;
\ No newline at end of file
# Bug tracking
Il bug tracking è stato reso necessario nel mondo open source per via della numerosità dei contributi e della alta probabilità di avere segnalazioni duplicate.
Inoltre, per gestire le segnalazioni di bug nell'ambito dello sviluppo open source, esistono diversi strumenti come git-bug, BugZilla, Scarab, GNATS, BugManager e Mantis.
## Bug workflow
![Bug workflow](/assets/06_bug-workflow.png)
L'obiettivo del bug tracking è avere più informazioni possibili su ogni bug per saperli riprodurre e quindi arrivare a una soluzione.
È importante verificare i bug una volta che l'_issue_ è stato aperto, in modo da poter confermare la sua esistenza e la completezza delle informazioni fornite.
Un _issue_ è un problema o una richiesta di funzionalità segnalata all'interno di un progetto di software.
Gli issue vengono solitamente utilizzati per tenere traccia dei problemi noti o delle richieste di nuove funzionalità all'interno di un progetto, e possono essere gestiti attraverso un sistema di bug tracking o gestione delle richieste.
Gli issue possono essere aperti da qualsiasi membro del team o dalla comunità, e possono essere risolti o chiusi da un membro del team responsabile.
Ci sono diversi modi per cui può essere chiuso un bug:
- __duplicate__: quando è stato già segnalato in precedenza e quindi non rappresenta un problema nuovo. In questo caso, viene solitamente fatto riferimento al numero del bug originale che ha già ricevuto una risoluzione;
- __wontfix__: il bug viene chiuso come "non risolvibile" perché o rappresenta una funzionalità voluta dal progetto o è troppo complesso da risolvere per essere considerato conveniente farlo dal punto di vista dei progettisti;
- __can't reproduce__: non è stato possibile riprodurre il bug, ovvero che non è stato possibile ottenere lo stesso risultato o il comportamento segnalato dal bug. Ciò può essere dovuto a una mancanza di dettagli o a un errore nella segnalazione del bug stesso;
- __fixed__: il bug è stato fixato;
vs __fix verified__: il fix è stato integrato in una release passando tutti gli step di verifica.
......@@ -48,6 +48,14 @@
- [Meccanismo di base](./05_scm/02_meccanismo.md)
- [git](./05_scm/03_git.md)
- [Git workflow e strumenti](./06_git-workflow/00_index.md)
- [GitFlow](./06_git-workflow/01_gitflow.md)
- [Hosting centralizzato](./06_git-workflow/02_hosting-centralizzato.md)
- [Gerrit](./06_git-workflow/03_gerrit.md)
- [Strumenti dell'opensource](./06_git-workflow/04_strumenti-opensource/00_index.md)
- [Build automation](./06_git-workflow/04_strumenti-opensource/01_build-automation.md)
- [Bug tracking](./06_git-workflow/04_strumenti-opensource/02_bug-tracking.md)
# 2. Progettazione e implementazione
# 3. Verifica e convalida
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment