Analiza interact ,iunilor echipei în procesul de dezvoltare software 17 iunie 2019 2 Cuprins 1 Introducere 5 1.1 Motivat ,ia . . . . . . . . . . . [626986]

PULL REQUEST ANALYZER:
Analiza interact ,iunilor echipei în procesul de
dezvoltare software
17 iunie 2019

2

Cuprins
1 Introducere 5
1.1 Motivat ,ia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Contextul problemei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3 Descrierea proiectului . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2 Fundamentare teoretică 11
2.1 Rolul comunicării în etapa de dezvoltare . . . . . . . . . . . . . . . . . . 11
2.2 Tehnologii folosite pe partea de backend . . . . . . . . . . . . . . . . . . 11
3 API-urile folosite pentru extract ,ia de date 13
3.1 GitHub Java API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2 Bitbucket REST API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4 Prezentarea întregului sistem 25
4.1 Arhitectura generală . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.2 DataLoader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.2.1 GitHubDataLoader . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.2.2 BitbucketDataLoader . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.3 Baza de date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.4 DataRegister . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.5 DataAnalyzer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.5.1 DeveloperAnalyzer . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.5.2 PullRequestAnalyzer . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.6 DataParser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5 Utilizarea aplicat ,iei 49
5.1 Configurarea aplicat ,iei . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.2 Exportarea rezultatelor analizelor . . . . . . . . . . . . . . . . . . . . . . 50
5.3 Interpretarea rezultatelor . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
6 Concluzii 59
6.1 Concluzii generale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.2 Direct ,ii de dezvoltare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3

4 CUPRINS

Capitolul 1
Introducere
1.1 Motivat ,ia
În ultimii ani, limbajele de programare au evoluat foarte mult, iar odată cu ele au evoluat
s,i sistemele software. De-asemenea, există proiecte software care sunt în dezvoltare de
foarte mult timp s ,i pe aceste proiecte s-a lucrat intens, au fost adăugate o grămadă de
noi funct ,ionalităt ,i, dar ce este s ,i mai important din punctul de vedere al acestei lucrări,
este faptul că au lucrat s ,i au interact ,ionat foarte mult ,i programatori. Aceste proiecte
au ajuns să aibă o dimensiune considerabil de mare s ,i este important să s ,tim în cadrul
unui asemenea proiect ce programatori au adus cele mai multe contribut ,ii, nivelul de
cunoas ,tere al sistemului pe care îl are fiecare dintre aces ,ti programatori s ,i în ce stadiu ne
aflăm cu proiectul până la momentul actual. Cu atât mai mult, esent ,ial este să putem
afla s ,i ce interact ,iuni au existat între programatori s ,i cât de mult au comunicat aces ,tia
în etapa de dezvoltare.
Având aceste informat ,ii, putem repara anumite gres ,eli s ,i astfel să îmbunătăt ,im pro-
cesul de dezvoltare software
Conform [1], legile lui Conway afirmă următoarele:
“Organizațiile ce produc sisteme software sunt constrânse să dezvolte sis-
teme ce reproduc structurile de comunicare din interiorul lor.”
“Înfiecareorganizațievaexistaîntotdeaunacinevacareștieceseîntâmplă.
Acea persoană trebuie concediată.”
În acest sens, software-ul care este descris în această lucrare încearcă să analizeze atât
procesul de dezvoltare al unui proiect, cât s ,i comunicarea dintre programatori în cadrul
acestuia. Această analiză se va realiza pe baza datelor extrase din pull request-urile
făcute de aces ,tia. Aceste date cont ,in pe lângă detaliile legate de programatori sau de pull
request-uri s ,i comentariile s ,i commit-urile asociate sau fis ,ierele modificate pe parcursul
etapei de dezvoltare.
1.2 Contextul problemei
Sistemele de versionare permit gestionarea versiunilor multiple ale unor fis ,iere, precum s ,i
asigurarea lucrului colaborativ asupra acestor fis ,iere. Fiecare modificare va fi înregistrată
5

6 CAPITOLUL 1. INTRODUCERE
cont ,inând atât diferent ,ele noii versiuni (revision), precum s ,i autorul acestei noi versiuni.
Acestesistemeaufostconceputepentruapermitemembrilormaimultorechipesăopereze
modificări pe acelas ,i proiect, aceste modificări urmând a fi reunite într-o nouă versiune a
proiectului.
În contextul unui sistem de versionare, putem întâlni mai mult ,i termeni specifici
precum:
repository : componentă server ce cont ,ine informat ,ii privind ierarhia de fis ,iere s ,i
reviziile unui proiect
checkout : preluarea în mediul local a unei anumite revizii publicate pe server
working copy : versiunea locală a proiectului
commit : publicare pe server a unor modificări
pull: act ,iunea de actualizare (update) a informat ,iilor locale cu cele de pe server
pull request (merge request) : este un mecanism de a adăuga contribut ,iile
personale la un proiect în dezvoltare pe un branch separat de cel principal
conflict : apare atunci când mai mult ,i utilizatori vor să publice modificări aplicate
aceloras ,i fis ,iere din proiect, însă sistemul de aplicare a versiunilor diferite nu poate
îmbina modificările
revert: revenirea la o versiune anterioară pe un anumit fir de dezvoltare (branch)
branch : ramură secundară de dezvoltare a proiectului
tag: branch “read-only” ce nu mai permite modificări ulterioare (folosit uneori
pentru versiunile stabile s ,i derivă dintr-un branch)
GIT este un exemplu de sistem de versionare distribuit ce rulează sub licent ,ă GNU pe
majoritatea sistemelor de operare existente: Linux, OSX, Windows. Este ideal pentru
cazul în care membrii unei echipe ce lucrează la un proiect act ,ionează într-un mod oare-
cum independent. As ,adar, sistemul oferă o flexibilitate foarte extinsă în ceea ce prives ,te
modurile de folosire.[2]
În figura 1.1 este detaliată diagrama de funct ,ionare GIT:
Figura 1.1: Diagramă de funct ,ionare GIT (sursă : [3])

1.2. CONTEXTUL PROBLEMEI 7
Lucrarea de fat ,ă se concentrează asupra analizării de pull request-uri din cadrul sis-
temelor de versionare Git s ,i anume GitHub s ,i Bitbucket.
GitHub s ,i Bitbucket sunt servicii de găzduire ale proiectelor git. Aceste servicii per-
mit păstrarea unei copii a proiectului online s ,i vizualizarea (tot online) tuturor fis ,ierelor
s,i a modificărilor aduse acestora. Ele sunt solut ,ii foarte bune pentru echipe, deoarece
facilitează o mare parte din lucrul cu proiecte mari s ,i mult ,i dezvoltatori care de cele mai
multe ori lucrează simultan pe acelas ,i proiect.
Printre avantajele folosirii sistemelor de versionare precum GitHub sau Bitbucket se
enumeră:
istoricul tuturor modificărilor este salvat, astfel că se poate reveni oricând la o
versiune mai veche dacă se descoperă introducerea unor defecte în ultima versiune
prin folosirea unui serviciu de găzduire (hosting), codul sursă are mereu o copie de
sigurant ,ă online
cea mai recentă versiune a codului sursă este mereu disponibilă tuturor dezvolta-
torilor, făcând astfel colaborarea s ,i sincronizarea mult mai us ,oară decât în cazul
trimiterii de fis ,iere cont ,inând cod sursă dezvoltatorilor interesat ,i de proiect.
Pull request-urile sau merge request-urile reprezintă un mecanism prin care un progra-
mator anunt ,ă echipa că el a realizat o nouă funct ,ionalitate (feature) pentru proiect si
dores ,te sa să comită acea nouă funct ,ionalitate pe ramura principală (numită de obicei
master). Pentru a nu afecta cu ceva proiectul deja existent, programatorul îs ,i face o copie
a proiectului într-un ramură (branch) secundară s ,i lucrează pe acea copie. În momentul
în care a realizat ce îs ,i propusese, creează un pull request s ,i prin acest pull request practic
cere celorlalt ,i membri ai echipei să ii verifice modificările s ,i în cazul în care totul este în
regulă să se accepte (merge) acel pull request, adică să aducă acele modificări din copia
proiectului s ,i pe ramura (branch-ul) principal.
Ceea ce este interesant la aceste pull request-uri, este faptul ca ele nu reprezintă doar
o notificare, ci prin intermediul lor se creează un forum de discut ,ii între programatori
pe acea nouă funct ,ionalitate, adică fiecare programator poate lăsa comentarii în legătură
cu modificările, iar responsabilul de pull request poate răspunde sau remedia ce nu este
în regulă conform feedback-ului primit. Toate comentariile, autorii lor, commit-urile s ,i
fis,ierele modificate asociate acestui noi feature sunt asociate cu pull request-ul făcut. În
cadrul acestei lucrări, cea mai mare parte din datele extrase s ,i analizeze realizate vor fi
bazate pe informat ,ii esent ,iale extrase din pull request-uri.
În figura 1.2 sunt exemplificate mai multe ramuri secundare dintr-un repository:
Figura 1.2: Diagramă exemplificare ramuri într-un repository (sursă : [4])

8 CAPITOLUL 1. INTRODUCERE
1.3 Descrierea proiectului
Pull Request Analyzer este un software de complexitate medie care analizează comuni-
carea dintre dezvoltatori în cadrul unui sistem software prin extragerea unor informat ,ii
utile legate de datele personale ale fiecărui programator împreună cu pull request-urile
pe care acesta le-a creat s ,i pull request-urile pe care acesta le-a acceptat (“merge-uit”).
Pentru fiecare pull request se vor extrage toate comentariile publicate, toate commit-urile
care s-au realizat în cadrul pull request-ului respectiv s ,i toate fis ,ierele modificate în aceste
commit-uri.
În momentul de fat ,ă, există multe solut ,ii pentru a analiza un sistem software din mai
multe puncte de vedere, dar aceste solut ,ii sunt dependente de limbajul de programare
s,i analizează sistemul fie dintr-un punct de vedere static fie dintr-un punct de vedere
dinamic.
Pull Request Analyzer are avantajul de a oferi o analiză a unui sistem dintr-o per-
spectivă diferită s ,i anume din perspectiva interact ,iunii dintre programatori atunci când
lucrează pe un proiect. As ,a cum a fost ment ,ionat s ,i mai sus, acest tip de analiză poate
oferi o privire de ansamblu asupra felului în care a fost proiectat sistemul s ,i se pot ob-
serva persoanele care au avut un impact mai mare asupra acestei dezvoltări s ,i care sunt
părt ,ile din sistem asupra cărora au lucrat mai mult. Astfel, mentenant ,a sistemului poate
fi mult îmbunătăt ,ită pe viitor s ,i poate fi facilitată prin asocierea fiecărei entităt ,i persoanei
responsabile.
Analizele pe care le realizează instrumentul de fat ,ă se împart în două categorii:
analize specifice întregului proiect
analize specifice fiecărui programatori în parte.
Toate aceste analize pot fi rulate pe întreaga durată de viat ,ă a proiectului până în mo-
mentul rulării sau doar pe o anumită perioadă recentă.
Analizele ce pot fi rulate pe proiect ne dau rezultate referitoare la:
1. Numărul de pull request-uri deschise / respinse / acceptate
2. Numărul de pull request-uri care au fost acceptate după o perioadă destul de lungă
de timp (> 7 zile)
3. Numărul de pull request-uri care sunt deschise de mult timp
4. Numărul de pull request-uri “fără activitate”
5. Numărul de pull request-uri complexe
6. Numărul mediu de pull request-uri deschise / acceptate pe zi / săptămână
7. Numărul mediu de comentarii pe pull request
8. Numărul comentariilor care se referă la o linie de cod s ,i numărul comentariilor
generale
9. Numărul mediu de commit-uri
10. Numărul mediu de fis ,iere schimbate pe pull request

1.3. DESCRIEREA PROIECTULUI 9
11. Numărul de pull request-uri deschise pe acelas ,i branch pe care sunt s ,i acceptate sau
închise
12. Timpul mediu de react ,ie la pull request-uri
13. Timpul mediu de răspuns la comentarii al det ,inătorilor de pull request-uri
14. Timpul mediu de acceptare al pull request-urilor
15. “Perioade aglomerate”
16. Cronologia fiecărui pull request
Analizele care sunt specifice fiecărui dezvoltator în parte produc rezultate cu privire la :
1. Numărul de pull request-uri deschise / respinse
2. Numărul de pull request-uri deschise de el s ,i acceptate de alt ,ii
3. Numărul de pull request-uri deschise de el s ,i acceptate tot de el
4. Numărul de pull request-uri acceptate ce apart ,in altor dezvoltatori
5. Numărul de pull request-uri acceptate după o perioadă destul de lungă de timp
6. Numărul de pull request-uri deschise de mult timp
7. Numărul de pull request-uri complexe create
8. Numărul mediu de comentarii al pull request-urilor lui
9. Numărul de comentarii pe pull request-urile create de el / pe alte pull request-uri
10. Numărul mediu de commit-uri si fis ,iere schimbate
11. Timpul mediu de react ,ie la pull request-urile colegilor
12. Timpul mediu de răspuns la comentariile de pe pull request-urile lui
13. Timpul mediu de acceptare al pull request-urilor lui
14. Cronologia fiecărui programator
15. Interact ,iunile cu ceilalt ,i programatori
Pull Request Analyzer nu este neapărat un instrument folosit pentru a evalua calita-
tea sistemelor analizate, el este mai degrabă un instrument auxiliar care aduce în plus
fat ,ă de alte instrumente mai complexe informat ,ii legate de felul în care dezvoltatorii
interact ,ionează, informat ,ii legate de progresul lor pe proiect s ,i le dă o privire de ansam-
bluasupraceeaceaufăcutpânăînmomentulrespectiv. Astfel, eipotîmbunătăt ,ianumite
aspecte ale procesului de dezvoltare pentru a deveni mai productivi s ,i mai eficient ,i. În
plus, rezultatele obt ,inute pot fi us ,or integrate cu instrumente de vizualizare ce facilitează
interpretarea lor s ,i ajută la formarea rapidă a unei opinii.
Acest instrument poate fi folosit atât într-o manieră retrospectivă, adică se poate
analiza un proiect în mod repetat, în timp, iar la final se compară rezultatele pentru a
vedea dacă măsurile luate au dus la o îmbunătăt ,ire, dar poate fi folosit s ,i personal, în
timpul etapei de dezvoltare pentru a vedea dacă programatorii interact ,ionează îndeajuns,
nu apar probleme sau situat ,ii de blocaj s ,i totul este conform planului.

10 CAPITOLUL 1. INTRODUCERE

Capitolul 2
Fundamentare teoretică
În acest capitol vor fi prezentate idei dintr-un studiu de caz despre comunicarea într-o
echipă s ,i cum poate influent ,a aceasta procesul de dezvoltare software s ,i câteva informat ,ii
despre tehnologiile folosite pentru partea de backend.
2.1 Rolul comunicării în etapa de dezvoltare
Deseori, sistemele software sunt dezvoltate de organizat ,ii care constau din multe echipe
de persoane care lucrează împreună. Brooks afirmă în cartea ”Myth Man Month” că,
calitatea produsului este puternic afectată de structura organizatorică. Din păcate, nu
prea au existat dovezi până în prezent pentru a sust ,ine această afirmat ,ie.[5]
În lucrarea intitulată ” The Influence of Organizational Structure on Software
Quality: An Empirical Case Study ” se prezintă o metrică pentru a cuantifica com-
plexitatea organizatorică, în relat ,ie cu procesul de dezvoltare al produsului pentru a
identifica dacă această structură organizatorică are sau nu un impact asupra succesului
produsului . În studiul ment ,ionat, metricile organizat ,ionale au fost aplicate datelor din
Windows Vista, iar rezultatele obt ,inute au fost semnificative, prezicând es ,ecul la care era
predispus sistemul. Metricile folosite prezintă avantajul de a avea o precizie mult mai
bună decât cea a metricilor tradit ,ionale de detect ,ie a ratei de es ,ec a unui sistem. Ast-
fel, rezultatele obt ,inute sunt empirice s ,i dovedesc faptul că aceste metrici care măsoară
relat ,iile dintr-o organizat ,ie sunt în strânsă legătură cu, s ,i pot prezice es ,ecul unui sistem
în dezvoltare.
Autorii propun măsurători care cuantifică complexitatea organizatorică s ,i care oferă
o privire de ansamblu asupra întregului proces din punctul e vedere al codului scris.
Metricile organizat ,ionale surprind diferite probleme ce t ,in de organizarea programatorilor
cum ar fi distant ,a dintre aces ,tia, numărul de dezvoltatori care lucrează pe o componentă,
cât ,i dintre aces ,tia lucrează la mai multe proiecte sau câte schimbări apar de-a lungul
timpului.
2.2 Tehnologii folosite pe partea de backend
Java: este un limbaj de programare orientat pe obiecte, dezvoltat de Sun Microsystems
s,i lansat în anul 1995. Java este o platformă independentă, acest lucru înseamnă că
un cod compilat poate rula fără modificări sau cu mici modificări pe orice platformă,
unde există o mas ,ină virtuală instalată(JVM), spre deosebire de alte limbaje cum ar fi
11

12 CAPITOLUL 2. FUNDAMENTARE TEORETICĂ
C, C++. Acest lucru este posibil deoarece sursele Java sunt compilate într-un format
standardnumitbyte-code(coddeoctet ,i). AcestcodesteinterpretatdeJVM(JavaVirtual
Machine). Codul de octet ,i este un intermediar între codul mas ,ină(dependent de tipul
calculatorului) s ,i codul sursă.[6]
Spring: este un framework „open source”, des ,i t ,inta lui nu este niciun limbaj de
programare, a devenit popular în rândul comunităt ,ii Java. A fost creat de RodJohnson
s,i descris în cartea sa „Expert One-on-One: J2EE Design and Development”. Spring-ul a
fost creat pentru a aborda dezvoltarea aplicat ,iilor enterprise complexe s ,i a face posibilă
folosirea „plain-vanilla” JavaBeans pentru a obt ,ine lucruri, care anterior erau posibile
doar folosind EJB (Enterprise JavaBeans). Folosirea lui nu este limitată doar la partea
de server-side, ci orice aplicat ,ie Java poate beneficia de simplicitatea, testabilitatea s ,i
cuplajul slab (loose coupling) oferit de acesta.[7]
Spring Boot : oferă posibilitatea de a crea cu us ,urint ,ă aplicat ,ii „stand-alone”(de sine
stătătoare) bazate pe framework-ul Spring. Printre caracteristicile oferite se număra: în-
corporează Tomcat (nu este necesară instalarea unui server container), configurează auto-
mat Spring oriunde este posibil, nu este necesară nicio configurat ,ie XML, oferă „starter
POM”(Project Object Model) pentru a simplifica configurat ,ia Maven.
JPA(Java Persistence API) : reprezintă o colect ,ie de clase (în limbajul de programare
Java), oferind funct ,ionalităt ,i legate de interogarea eficientă a informat ,iilor stocate în baze
dedaterelat ,ionale, maialesînsituat ,iaîncarevolumulacestoraesteconsiderabil. Această
interfat ,ă de programare implementează un nivel de abstractizare, toate informat ,iile fiind
stocate la nivel de obiecte, astfel încât programatorul nu este obligat să cunoască detaliile
specifice unui sistem de gestiune al bazelor de date.”[8]

Capitolul 3
API-urile folosite pentru extract ,ia de
date
În acest capitol se vor discuta detalii legate de ce oferă API-ul (Application Interface) de
la GitHub s ,i ce oferă cel de la Bitbucket. Se va arăta cum anume s-au extras toate datele
necesare analizelor s ,i ce informat ,ii au fost oferite prin aceste API-uri.
Cele două sect ,iuni din acest capitol vor pune mai mult accentul pe metodele apelate
din API s ,i tipul de date returnat de acestea. De-asemenea, vor fi prezentate s ,i anumite
entităt ,i specifice fiecărui sistem de versionare, des ,i ele sunt foarte asemănătoare între ele
când vine vorba de GitHub s ,i Bitbucket.
3.1 GitHub Java API
Întrucât proiectul pe partea de backend este scris în Java cu Spring Boot, s-a ales o
bibliotecă Java pentru a facilita extract ,ia de date s ,i pentru o înt ,elegere mai bună a
implementării s ,i a ceea ce se întâmplă acolo în spate. În mod normal, lucrul cu API-ul
de la GitHub se face prin request-uri de tip HTTP, iar datele sunt trimise s ,i primite în
format JSON. Avantajul folosirii acestei biblioteci este că se pot obt ,ine datele lucrând
numai cu obiecte, iar toate informat ,iile sunt încapsulate în aceste obiecte ca atribute.
Biblioteca se numes ,te GitHub Java API, este creată de Eclipse s ,i urmăres ,te să suporte
toată funct ,ionalitatea API-ului original, adică orice date se obt ,in folosind un apel la API-
ul de la GitHub, se pot obt ,ine aceleas ,i date într-o manieră orientată pe obiecte s ,i folosind
această bibliotecă.
Această bibliotecă este împărt ,ită în trei pachete principale :
Core: este pachetul care cont ,ine tot modelul de clase cu metode de tip get s ,i set
pentru resursele disponibile prin API cum ar fi repositories, commit-uri, utilizatori
sau echipe
Client: acest pachet se ocupă de comunicarea cu serverul de la GitHub API prin
request-uri de tip HTTPS s ,i este responsabil de transformarea răspunsurilor din
format JSON în clasele din model potrivite
Service : este pachetul care se ocupă de crearea, actualizarea, citirea sau s ,tergerea
datelor dintr-un repository GitHub.
Pentruaputeautilizaserviciilepuseladispozit ,iedeGitHubJavaAPI,utilizatorultrebuie
să fie autentificat folosind contul personal de GitHub :
13

14 CAPITOLUL 3. API-URILE FOLOSITE PENTRU EXTRACT ,IA DE DATE
GitHubClient client = new GitHubClient();
client.setCredentials(username,password);
Codul 3.1 Autentificarea utilizatorului
Pentru a putea încărca date dintr-un repository, este nevoie de mai multe servicii care să
fie instant ,iate folosind clientul care tocmai s-a creat. Aceste servicii sunt următoarele :
UserService pentru a putea obt ,ine un anumit programator, un RepositoryService pentru
a putea avea acces la un repository s ,i un PullRequestService pentru a se putea obt ,ine
toate pull request-urile dintr-un repository:
RepositoryService repositoryService =
new RepositoryService(client);
UserService userService =
new UserService(client);
PullRequestService pullRequestService =
new PullRequestService(client);
Codul 3.2 Obt ,inerea serviciilor pentru încărcarea datelor
După ce s-au creat serviciile necesare, se poate crea un obiect Repository care o să fie
repository-ulsupusanalizeis ,idinelsepotextragetot ,iprogramatoriis ,itoatepullrequest-
urile:
Repository gitHubRepository = repositoryService
.getRepository(owner, repository);
List<PullRequest> allPullRequests = pullRequestService
.getPullRequests(gitHubRepository,"all");
List<Contributor> contributors = repositoryService
.getContributors(gitHubRepository, false );
Codul 3.3 Obt ,inerea repository-ului, a pull request-urilor s ,i a
programatorilor
Deja se pot observa avantajele folosirii unei biblioteci Java pentru obt ,inerea datelor ca s ,i
obiecte din care se pot obt ,ine mai departe informat ,ii. Repository-ul este un obiect Repo-
sitory, pull request-urile sunt obiecte de tip PullRequest, iar contribuitorii sunt obiecte de
tip Contributor. În metoda getPullRequests() există un parametru “all”, asta înseamnă
că se obt ,in toate pull request-urile. Se poate da ca s ,i parametru s ,irul de caractere “open”
sau “merged” pentru a obt ,ine doar acele pull request-uri care sunt nerezolvate încă, res-
pectiv cele care au fost deja rezolvate, dar pentru ca analiza să fie cât mai completă s ,i
corectă se vor lua toate pull request-urile.
După ce s-au obt ,inut două liste cu tot ,i programatorii s ,i toate pull request-urile, se
continuă prin obt ,inerea informat ,iilor pentru fiecare în parte. Pentru fiecare programator
pot obt ,ine informat ,ii legate de id, username, numele real s ,i e-mail. Aceste date se obt ,in
us,or apelând nis ,te metode de tip get pe o instant ,ă a clasei User:

3.1. GITHUB JAVA API 15
Long id = user.getId();
String username = user.getLogin();
String name = user.getName();
String email = user.getEmail();
Codul 3.4 Metode de tip get pentru informat ,ii legate de programatori
În cazul pull request-urilor se pot obt ,ine atât informat ,ii legate de pull request în sine, cât
s,i informat ,ii legate de comentariile care există pe acel pull request, commit-urile care s-au
făcut s ,i fis ,ierele modificate. Pentru detalii legate de pull request se extrage id-ul, titlul,
starea (deschis, respins sau acceptat), data creării, data închiderii sau acceptării (dacă
este cazul), programatorul care a creat pull request-ul, cel care l-a închis sau acceptat
(merged) precum s ,i branch-ul de pe care s-a lucrat s ,i branch-ul pe care se dores ,te să se
facă merge. La fel ca s ,i în cazul programatorilor, datele se obt ,in tot apelând metode
getter pe un obiect de tip PullRequest :
Long id = pullRequest.getId();
String title = pullRequest.getTitle();
String status = pullRequest.getState();
Date creationDate = pullRequest.getCreatedAt();
Date mergeDate = pullRequest.getMergedAt();
Date closeDate = pullRequest.getClosedAt();
User creator = pullRequest.getUser();
User merger = pullRequest.getMergedBy();
String initialBranch = pullRequest.getHead();
String finalBranch = pullRequest.getBase();
Codul 3.5 Metode de tip get pentru informat ,ii legate de pull request-uri
După ce s-au obt ,inut detaliile legate de pull request se poate obt ,ine câte o listă cu
comentarii, commit-uri s ,i fis ,iere modificate pentru pull request-ul respectiv :
List<CommitComment> comments =
pullRequestService.getComments(gitHubRepository,
pr.getNumber());
List<RepositoryCommit> commits =
pullRequestService.getCommits(gitHubRepository,
pr.getNumber());
List<CommitFile> files =
pullRequestService.getFiles(gitHubRepository,
pr.getNumber());
Codul 3.6 Obt ,inerea comentariilor, commit-urilor s ,i a fis ,ierelor
modificate pentru un anumit pull request
Pentru fiecare comentariu se vor extrage date referitoare la id, autor, timestamp, fis ,ierul
la care face referire comentariul, linia de cod din fis ,ier, cont ,inutul comentariului s ,i co-
mentariul părinte (dacă acest comentariu este un răspuns la un altul). Aceste date se
obt ,in folosind următoarele metode pe un obiect de tipul CommitComment:

16 CAPITOLUL 3. API-URILE FOLOSITE PENTRU EXTRACT ,IA DE DATE
Long id = comment.getId();
User author = comment.getUser();
Date timestamp = comment.getCreatedAt();
String file = comment.getPath();
int lineOfCode = comment.getPosition();
Long parentId = comment.getInReplyToId();
String content = comment.getBody();
Codul 3.7 Metode de tip get pentru informat ,ii legate de un comentariu
Pentru fiecare commit se vor extrage informat ,ii legate de autor, mesaj s ,i timestamp.
Pentru acestea se folosesc următoarele metode pe un obiect de tip Commit:
User author = commit.getAuthor();
String message = commit.getMessage();
Date timestamp = commit.getDate();
Codul 3.8 Metode de tip get pentru informat ,ii legate de un commit
Pentru fiecare fis ,ier modificat se vor extrage informat ,ii legate de numele fis ,ierului, numă-
rul de linii adăugate, numărul de linii modificate s ,i numărul de linii s ,terse. Metodele vor
fi apelate pe un obiect de tip CommitFile :
String fileName = file.getFilename();
int additions = file.getAdditions();
int changes = file.getChanges();
int deletions = file.getDeletions();
Codul 3.9 Metode de tip get pentru informat ,ii legate de un fis ,ier
modificat
3.2 Bitbucket REST API
Pentru extract ,ia de date din repository-urile de tip Bitbucket se foloses ,te un REST API.
Există s ,i un Java API pentru Bitbucket, dar este put ,in prea complicat s ,i complex pentru
ceea ce este nevoie privind această lucrare. API-urile REST pentru Bitbucket oferă acces
la resurse (entităt ,i de date) prin căi URI (Uniform Resource Identifier). Pentru a utiliza
un API REST, aplicat ,ia va face o cerere HTTP s ,i va analiza răspunsul. Bitbucket REST
API utilizează JSON ca format de comunicare s ,i metode standard HTTP precum GET,
PUT, POST s ,i DELETE.
Bitbucket foloses ,te paginarea pentru a conserva resursele serverului s ,i pentru a limita
dimensiunea răspunsului atunci când resursele returnează colect ,ii de date foarte mari.
O cerere către un API paginat va avea ca rezultat un vector (array) de valori înfăs ,urat
într-un obiect JSON, iar pe lângă valori apar s ,i unele metadate de paginare, cum ar fi:

3.2. BITBUCKET REST API 17
{
"size": 3,
"limit": 3,
"isLastPage": false,
"values": [
{ /*result 0 */ },
{ /*result 1 */ },
{ /*result 2 */ }
],
"start": 0,
"filter": null,
"nextPageStart": 3
}
Exemplul 3.1 Exemplu de răspuns de la un API paginat (sursă : [9])
Client ,ii pot utiliza parametrii de interogare limits,istartpentru a obt ,ine numărul dorit
de rezultate. Parametrul limit indică câte rezultate să apară pe pagină. De obicei, daca
limit nu este specificat, acesta este 25 implicit. Acest parametru poate fi specificat cu o
valoare mai mare in request, dar tot se va aplica o limită specifică pentru resurse, limită
ce este configurată de administratorii server-ului. Solicitarea de a obt ,ine o pagină mai
mare ar trebui să arate astfel:
https: //api.bitbucket.org/2.0/repositories/" + owner + "/" +
repository + "/pullrequests?limit=1000"
Exemplul 3.2 Exemplu de request în care se specifică o limită mai mare
pentru răspuns
Parametrul start indică ce element trebuie folosit ca primul element din pagina de re-
zultate. Toate răspunsurile paginate cont ,in un atribut isLastPage care indică dacă
există altă pagină de elemente. Dacă există mai mult de o pagină (adică răspunsul
cont ,ine "isLastPage": false), obiectul de răspuns va cont ,ine de asemenea un atribut nex-
tPageStart care trebuie utilizat de client ca parametru de pornire pentru următoarea
solicitare.
https: //api.bitbucket.org/2.0/repositories/" + owner + "/" +
repository + "/pullrequests?start=25"
Exemplul 3.3 Exemplu de request în care se specifică un element de
start pentru pagina de răspuns
În ceea ce prives ,te această lucrare, pentru partea de autentificare atunci când se fac
request-uri de tip HTTP către serverul Bitbucket se foloses ,te Basic Authentication, adică
se creează un antet de autorizare care va cont ,ine datele de autentificare la Bitbucket ale
utilizatorului (username-ul s ,i parola). Astfel, în toate request-urile, se va crea acest antet
s,i va fi transmis către server în vederea autentificării:

18 CAPITOLUL 3. API-URILE FOLOSITE PENTRU EXTRACT ,IA DE DATE
HttpHeaders createHeaders (String username, String password){
return new HttpHeaders() {{
String auth = username + ":" + password;
byte [] encodedAuth = Base64.encodeBase64(auth.getBytes(
Charset.forName("US-ASCII")));
String authHeader = "Basic " + new String(encodedAuth);
set("Authorization", authHeader);
}};
}
Codul 3.10 Crearea unui antet (header) de autorizare pentru
request-uri de tip HTTP (sursă: [10])
Pentru preluarea entităt ,ilor de date de la serverul Bitbucket, se foloses ,te solut ,ia oferită
de Spring s ,i anume RestTemplate care oferă o metodă de a deserializa obiecte din format
JSON. În acest context, se creează o clasă DTO (Data Transfer Object) care are rolul de
a încapsula valorile dorite din răspunsul JSON ca s ,i atribute, iar în momentul în care se
face request-ul, RestTemplate creează un obiect de tipul clasei DTO din care pot obt ,ine
acele date.
În exemplul următor, se dă o clasă declarată împreună cu atributele dorite din răs-
punsul JSON. Folosind metoda exchange() pe un obiect de tip RestTemplate, se face un
request către server s ,i se obt ,ine un răspuns care este mai apoi deserializat într-un obiect
de tipul clasei declarate:
ResponseEntity<BitbucketPullRequestValuesURL> responseObject;
responseObject = restTemplate.exchange(URL,
HttpMethod.GET,
new HttpEntity<BitbucketPullRequestValuesURL>
(createHeaders(username, password)),
new ParameterizedTypeReference
<BitbucketPullRequestValuesURL>() {});
BitbucketPullRequestValuesURL response =
responseObject.getBody();
@Data
@NoArgsConstructor
class BitbucketPullRequestValuesURL {
BitbucketPullRequestURL values[];
private String next;
}
Codul 3.11 Exemplu de deserializare a unui obiect dintr-un răspuns de
tip JSON
După cum s-a ment ,ionat s ,i mai sus, răspunsurile oferite de server sunt paginate. Astfel,
pentru a putea lua toate datele, în obiectul care se obt ,ine ca răspuns trebuie preluat s ,i
parametrul care cont ,ine numărul paginii următoare, iar pentru fiecare pagină se verifică
dacă acesta există. Dacă există, se face din nou apelul cu URL-ul modificat, adică se dă
ca s ,i parametru pagina următoare, dacă nu, se iese din buclă :

3.2. BITBUCKET REST API 19
String URL;
ResponseEntity<BitbucketPullRequestValuesURL> responseObject;
int page = 1;
do{
URL = "https://api.bitbucket.org/2.0/repositories/" +
owner + "/" + repository +
"/pullrequests?state=OPEN" + "&page=" + page++;
responseObject = getPullRequests
(restTemplate, allPullRequests, URL);
}while (responseObject.getBody().getNext() != null );
Codul 3.12 Exemplu de iterare a tuturor paginilor unui răspuns de la
serverul Bitbucket
Încontinuare, sevaarătacumaufostextrasetoatedatelenecesarepentruanalizăfolosind
acest REST API. În acest sens, se vor exemplifica doar clasele DTO pentru deserializarea
răspunsurilor de tip JSON s ,i ce request-uri au fost făcute către server. A se observa că în
exemplele următoare clasele au fost adnotate cu @Data s ,i @NoArgsConstructor. Aceste
adnotărireprezintăofacilitateoferitădeSpringBootprincaresecreeazăautomatmetode
detipgets ,iset, constructori, metodatoString()s ,imetodaEqualsAndHashCode()înclasa
respectivă, deci nu trebuie să mai fie ele implementate explicit.
Pentru a obt ,ine tot ,i programatorii implicat ,i în aceste pull request-uri se face un requ-
est prin care se obt ,ine un obiect de tipul BitbucketSinglePullRequestURL. Acest obiect
cont ,ine o listă cu participant ,i, adică persoane care au creat pull request-ul, au comentat
pe acel pull request sau au modificat fis ,iere în cadrul acelui pull request. Pe urmă, fiecare
participant cont ,ine un atribut “user” care reprezintă programatorul de la care se pot lua
date necesare cum ar fi id-ul, username-ul s ,i numele.
"https://api.bitbucket.org/2.0/repositories/" + owner +
"/" + repository + "/pullrequests/" + currentPullRequest
.getId();
Exemplul 3.5 Request-ul către server pentru obt ,inerea unui pull request

20 CAPITOLUL 3. API-URILE FOLOSITE PENTRU EXTRACT ,IA DE DATE
@Data
@NoArgsConstructor
class BitbucketSinglePullRequestURL {
private BitbucketPullRequestParticipantURL
participants[];
}
@Data
@NoArgsConstructor
class BitbucketPullRequestParticipantURL {
private BitbucketAuthorURL user;
}
@Data
@NoArgsConstructor
class BitbucketAuthorURL {
private String uuid;
private String username;
private String display_name;
}
Codul 3.13 Clasele s ,i request-ul pentru obt ,inerea informat ,iilor legate de
programatori
Pentru a se obt ,ine date legate de pull request-uri se va obt ,ine câte o listă cu toate pull
request-urile deschise (open), închise (declined) s ,i cele acceptate (merged). Acest lucru se
face prin transmiterea unui parametru în request prin care se specifica ce pull request-uri
se doresc. Desigur, pentru a se obt ,ine toate pull request-urile este nevoie de o iterare a
tuturor paginilor, întrucât serverul oferă doar zece pull request-uri pe pagină.
"https://api.bitbucket.org/2.0/repositories/" + owner +
"/" + repository + "/pullrequests?state=OPEN" + "&page="
+ pageNo;
"https://api.bitbucket.org/2.0/repositories/" + owner +
"/" + repository + "/pullrequests?state=MERGED" + "&page="
+ pageNo;
"https://api.bitbucket.org/2.0/repositories/" + owner +
"/" + repository + "/pullrequests?state=DECLINED" + "&page="
+ pageNo;
Exemplul 3.6 Request-uri pentru a obt ,ine toate pull request-urile
(deschise, acceptate s ,i închise)
Fiecare listă obt ,inută cont ,ine obiecte de tipul BitbucketPullRequestValuesURL care au
un vector cu valori (values) ce reprezintă pull request-urile din acea pagină s ,i un atribut
“next” carereprezintăpaginaurmătoare(dacăexistă). Fiecarepullrequestdinacelvector
cont ,ine date precum id, titlu, autor, data creării, data închiderii sau acceptării, starea,
branch-ul init ,ial, branch-ul final s ,i autorul care a închis/acceptat pull request-ul.

3.2. BITBUCKET REST API 21
@Data
@NoArgsConstructor
class BitbucketPullRequestValuesURL {
private BitbucketPullRequestURL values[];
private String next;
}
@Data
@NoArgsConstructor
class BitbucketPullRequestURL {
private String title;
private Long id;
private BitbucketAuthorURL author;
private String created_on;
private String updated_on;
private String state;
private BitbucketPullRequestSourceURL source;
private BitbucketPullRequestDestinationURL
destination;
private BitbucketAuthorURL closed_by;
}
Codul 3.14 Clasele declarate pentru obt ,inerea informat ,iilor legate de
pull request-uri
Pentru obt ,inerea comentariilor, se iterează fiecare pull request s ,i se face câte un apel
pentru a obt ,ine comentariile asociate. La fel ca s ,i în cazul pull request-urilor, se va
obt ,ine câte un obiect de tipul BitbucketCommentValuesURL care are un vector de valori
(comentariile propriu-zise) s ,i un atribut “next” pentru paginare. Fiecare comentariu din
vectorcont ,ineid-ul, autorul, timestamp-ul, cont ,inutulcomentariului, comentariulpărinte
(dacă există) s ,i linia din fis ,ier la care se referă comentariul.
"https://api.bitbucket.org/2.0/repositories/" + owner +
"/" + repository + "/pullrequests/" + currentPullRequest
.getId() + "/comments/" + "?page=" + pageNo;
Exemplul 3.7 Request-ul către server pentru a obt ,ine comentariile unui
pull request

22 CAPITOLUL 3. API-URILE FOLOSITE PENTRU EXTRACT ,IA DE DATE
@Data
@NoArgsConstructor
class BitbucketCommentValuesURL {
private BitbucketCommentURL values[];
private String next;
}
@Data
@NoArgsConstructor
class BitbucketCommentURL {
private Long id;
private BitbucketAuthorURL user;
private String updated_on;
private BitbucketCommentContentURL content;
private BitbucketCommentInlineURL inline;
private BitbucketParentURL parent;
}
Codul 3.15 Clasele declarate pentru obt ,inerea informat ,iilor legate de
comentarii
La fel ca s ,i în cazul comentariilor, pentru obt ,inerea commit-urilor se iterează fiecare pull
request s ,i se obt ,in commit-urile asociate. De data aceasta, se va obt ,ine un obiect de tipul
BitbucketCommitValuesURL care va avea un vector de valori reprezentând commit-urile
propriu-zises ,iatributulpentrupaginare. Pentrufiecarecommitseiamesajul, timestamp-
ul s ,i autorul.
"https://api.bitbucket.org/2.0/repositories/" + owner +
"/" + repository + "/pullrequests/" + currentPullRequest
.getId() + "/commits" + "?pagelen=100";
Exemplul 3.8 Request-ul către server pentru a obt ,ine commit-urile
unui pull request
@Data
@NoArgsConstructor
class BitbucketCommitValuesURL {
private BitbucketCommitURL values[];
private String next;
}
@Data
@NoArgsConstructor
class BitbucketCommitURL {
private String message;
private String date;
private BitbucketCommitAuthorURL author;
}
Codul 3.16 Clasele declarate pentru obt ,inerea informat ,iilor legate de
commit-uri

3.2. BITBUCKET REST API 23
În ceea ce prives ,te fis ,ierele modificate, pentru fiecare pull request se obt ,ine un obiect
String care reprezintă toate modificările care au avut loc în cadrul acelui pull request.
Acest s ,ir de caractere este de fapt cont ,inutul unui fis ,ier de diferent ,e numit diff. S ,irul se
împarte după numele de fis ,iere modificate, iar apoi se numără liniile de cod adăugate sau
s,terse. În fis ,ierul diff numele de fis ,iere sunt precedate întotdeauna de construct ,ia “diff
–git”, iar după acestea urmează linii de cod care încep fie cu “+” fie cu “-” reprezentând
linii adăugate sau s ,terse.
"https://api.bitbucket.org/2.0/repositories/" + owner +
"/" + repository + "/pullrequests/" + currentPullRequest
.getId() + "/diff";
Exemplul 3.9 Request-ul către server pentru a obt ,ine fis ,ierul diff

24 CAPITOLUL 3. API-URILE FOLOSITE PENTRU EXTRACT ,IA DE DATE

Capitolul 4
Prezentarea întregului sistem
GitHub Repository Bitbucket Repository
Persist data to a databaseExtract information
Register data to a model
Run analysis
Export results
Figura 4.1: Diagrama de funct ,ionare a Pull Request Analyzer
25

26 CAPITOLUL 4. PREZENTAREA ÎNTREGULUI SISTEM
Înacestcapitolvorfiprezentatearhitecturageneralăaproiectului,principaleleentităt ,i
ale sistemului, fluxul logic al programului, dar s ,i arhitectura s ,i implementarea mai detali-
ată a unora dintre cele mai importante analize de care dispune acest instrument software.
În sect ,iunea 3.1 este prezentată arhitectura generală a proiectului, modul de proiec-
tare, precum s ,i pe scurt fiecare entitate importantă din sistem. În sect ,iunea 3.2 este
prezentată în detaliu partea de extract ,ie de informat ,ii împreună cu salvarea lor în baza
de date. În sect ,iunea 3.3 se arată cum aceste date sunt apoi încărcate din baza de date
într-un model în memorie pentru a le putea accesa mult mai rapid. În sect ,iunea 3.4 se
vor prezenta în detaliu implementarea analizelor s ,i salvarea lor pentru a putea fi expor-
tate, iar în ultima sect ,iune se discută exportarea rezultatelor obt ,inute s ,i accesarea lor din
browser.
4.1 Arhitectura generală
Arhitectura generală a sistemului este prezentată în figura 4.2. Clasa Main care pornes ,te
sistemul are ca dependente cele mai importante entităt ,i ale sistemului :
DataLoader : este o clasă abstractă care este mos ,tenită de doua subclase specifice
fiecărui tip de repository. Pentru repository-uri de tip GitHub se foloses ,te clasa
GitHubDataLoader , iar pentru repository-uri de tip Bitbucket se foloses ,te clasa
BitBucketDataLoader . Ambele clase implementează metoda loadData() prin
care se extrag toate informat ,iile necesare s ,i se salvează în baza de date într-un
model comun ambelor tipuri de repository.
DataRegister : este clasa care încarcă toate datele din baza de date într-un model
pentru a putea mai apoi obt ,ine aceste date mult mai rapid fără a suprasolicita baza
de date.
DataAnalyzer : esteceamaiimportantăclasăcarecont ,ineomarepartedinlogica
aplicat ,iei. Această clasă implementează s ,i rulează toate analizele pe datele adunate
din repository. Clasa foloses ,te doua entităt ,iDeveloperAnalyzer s,iPullRequ-
estAnalyzer pentru a implementa cele doua categorii de analize: cele referitoare
la fiecare dezvoltator în parte, respectiv cele referitoare la întreg proiectul analizat.
Aceste clase au ca dependent ,ă o clasăStatistics care este folosită pentru a calcula
diferite valori cum ar fi media aritmetică sau mediana dintr-o listă. O mare parte
din analizele realizate apelează metode din această clasă pentru a obt ,ine rezultatele
dorite. Pe lângă implementarea s ,i rularea analizelor, clasa se ocupă s ,i de salvarea
rezultatelor obt ,inute s ,i exportarea acestora în fis ,iere de tip Excel pentru a putea fi
rapid citite s ,i comparate.
DataParser : este clasa care se ocupă de exportarea tuturor datelor extrase s ,i
a rezultatelor obt ,inute din analize pentru a fi ulterior integrate în instrumente de
vizualizare. Clasa exportă toate aceste informat ,ii in format JSON.
Importantdement ,ionatestefaptulcăaceastăaplicat ,ieafostimplementatăînas ,afelîncât
se pot extrage date de pe server pentru un anumit repository, dar în acelas ,i timp se pot
rula analize pe un alt repository care există deja în baza de date. Această funct ,ionalitate
este implementată folosind mecanismul de multithreading (mai multe fire de execut ,ie)
oferit de Spring Boot prin care se lansează partea de extract ,ie de date pe un fir de

4.1. ARHITECTURA GENERALĂ 27
execut ,ie separat, iar aplicat ,ia îs ,i continuă fluxul pe firul principal. Acest lucru a fost
gândit pentru a nu face utilizatorul să as ,tepte după extract ,ia de informat ,ii care poate
dura chiar s ,i 20 de ore în cazul proiectelor foarte mari. Astfel, el poate lăsa aplicat ,ia să
încarce un proiect mare, iar în acelas ,i timp să analizeze un alt proiect.
Starter
DataParser DataAnalyzer DataRegister{abstract}
Data Loader
GitHubDataLoader BitbucketDataLoaderDeveloperAnalyzer Statistics PullRequestAnalyzer
Figura 4.2: Arhitectura generală a sistemului

28 CAPITOLUL 4. PREZENTAREA ÎNTREGULUI SISTEM
4.2 DataLoader
Clasa DataLoader este clasa care se ocupă de primii doi pas ,i din fluxul acestei aplicat ,ii
s,i anume extract ,ia de informat ,ii de pe serverele de GitHub sau Bitbucket urmat de sal-
varea acestor informat ,ii în baza de date. După cum s-a ment ,ionat s ,i mai sus, această
clasă este o clasă abstractă care este mos ,tenită de alte doua clase concrete GitHubDa-
taLoader, respectiv BitbucketDataLoader. Instant ,ierea clasei potrivite se face polimorfic
în clasa Main folosind mecanismul de injectare a dependint ,elor specific framework-ului
Spring. În acea clasă există două obiecte gitHubDataLoader, respectiv bitBucketData-
Loader care sunt injectate în constructor, iar în funct ,ie de tipul repository-ului pe care
clientul dores ,te să-l încarce, atributul dataLoader primes ,te fie o referint ,ă către un obiect
de tipul GitHubDataLoader fie către unul de tip BitbucketDataLoader.
Înainte de a începe extract ,ia de date, clasei DataLoader i se setează atributele ne-
cesare, atribuite care sunt mos ,tenite de fiecare subclasă. Aceste atribute sunt datele de
conectare ale clientului la serviciul GitHub sau Bitbucket împreună cu datele referitoare
la repository-ul care se dores ,te a fi analizat (det ,inătorul s ,i numele repository-ului). Pe
lângă atributele necesare pentru a extrage informat ,ii, clasa mai are injectate entităt ,ile
folosite pentru a salva informat ,iile în baza de date, dar acestea împreună cu baza de date
vor fi discutate mai pe larg în subsect ,iunea 3.2.3. După ce aceste date au fost setate, se
apelează metoda abstractă loadData() care este implementată de fiecare subclasă. Me-
toda este adnotată cu @Async pentru a anunt ,a aplicat ,ia că ea va fi rulată pe un fir de
execut ,ie separat de cel principal din motive discutate mai sus.
public abstract class DataLoader {
protected String username;
protected String password;
protected String owner;
protected String repository;
protected DeveloperRepository developerRepository;
protected PullRequestRepository pullRequestRepository;
protected CommentRepository commentRepository;
protected CommitRepository commitRepository;
protected FileRepository fileRepository;
protected ProjectRepository projectRepository;
@Autowired
public DataLoader () {

//setting repositories for persisting data

}
@Async
public abstract void loadData() throws …
}
Codul 4.1 Clasa DataLoader
O altă funct ,ionalitate importantă când vine vorba de extract ,ia de date s ,i salvarea lor
în baza de date atât pentru GitHub, cât s ,i pentru Bitbucket este posibilitatea de a face
update la date. În momentul în care se apelează metoda loadData() pentru un repository,
aceasta verifică dacă nu cumva în baza de date există deja acest repository, iar dacă da,

4.2. DATALOADER 29
vor fi încărcate doar informat ,iile noi. Acest lucru este folositor, deoarece un utilizator
poate actualiza informat ,iile din baza de date la intervale repetate de timp fără a mai
încărca întreg proiectul de la început.
În următoarele două subsect ,iuni se vor prezenta detalii legate de implementarea cla-
selor GitHubDataLoader s ,i BitbucketDataLoader fără a mai arăta cum anume au fost
extrase datele, întrucât aceste informat ,ii au fost deja prezentate în sect ,iunile 2.2 s ,i 2.3.
4.2.1 GitHubDataLoader
Subclasa GitHubDataLoader este clasa care se ocupă de extragerea informat ,iilor referi-
toare la repository-uri de pe GitHub folosind API-ul. După ce se autentifică clientul s ,i se
obt ,in de la serverul de GitHub toate serviciile necesare pentru obt ,inerea de date (vezi Co-
dul 3.1 s ,i Codul 3.2 din sect ,iunea 3), se verifică dacă proiectul există deja în baza de date
sau nu, urmând apoi să facă încărcare de date sau actualizare de date. Informat ,iile des-
pre proiect se vor extrage apelând metoda loadProjectData(), datele programatorilor for
fi obt ,inute apelând metoda loadDeveloperData(), iar în metoda loadPullRequestData()
se obt ,in pentru fiecare pull request atât detaliile ce t ,in de pull request în sine, cât s ,i
detalii legate de comentariile, commit-urile s ,i fis ,ierele schimbate asociate fiecărui pull
request. Aceste date se obt ,in apelând metodele loadCommentData(), loadCommitData
s,i loadFileData().

if(projectRepository.findByProjectId(gitHubRepository
.getId())!= null ) {
updateDeveloperData(orderedDevelopers,
userService, gitHubRepository);
updatePullRequestData(pullRequestService,
issueService, allPullRequests,
gitHubRepository);
}
else {
loadProjectData(gitHubRepository);
loadDeveloperData(userService, orderedDevelopers,
gitHubRepository, "");
loadPullRequestData(pullRequestService,
issueService,allPullRequests,
gitHubRepository, 0, start);
}
Codul 4.2 Secvent ,a de cod care extrage informat ,iile sau le actualizează
pentru GitHub
Atunci când se dores ,te extragerea informat ,iilor dintr-un repository de GitHub, apare o
constrângere legată de numărul de request-uri către server pe care un utilizator le poate
face folosind API-ul. Des ,i utilizatorul este autentificat, acestuia îi sunt permise doar 5000
de request-uri pe oră. Acest număr este unul destul de mic având în vedere faptul că
există proiecte pe GitHub care au peste 10.000 de pull request-uri s ,i 100 de dezvoltatori
care lucrează pe proiect.
Pentruaînlăturaacestinconvenients ,ipentruaputeaextrageîntotalitateinformat ,iile
despre un repository, Pull Request Analyzer abordează problema în felul următor: el

30 CAPITOLUL 4. PREZENTAREA ÎNTREGULUI SISTEM
ret ,ine de fiecare dată id-ul ultimului programator sau pull request extras, iar în cazul în
care API-ul aruncă o except ,ie legată de limita de request-uri, opres ,te firul din execut ,ie
pentru o perioadă de timp, iar apoi reia execut ,ia de unde a rămas. Perioada de timp în
care firul este pe pus pe pauză este calculată ca fiind o oră minus durata de timp în care
a rulat până la aruncarea except ,iei. De-asemenea, există situat ,ii în care serverul poate să
dea eroare sau să nu poată returna unele date, dar s ,i acestea sunt tratate corespunzător,
reluând încărcarea.
private void loadPullRequestData(…, int startingIndex,
Date startTime){
allPullRequests = allPullRequests.subList
(startingIndex, allPullRequests.size());
try {
for (PullRequest pr : allPullRequests){
startingIndex = allPullRequests.indexOf(pr);
//loading pull requests…
}
}catch (RequestException | HttpClientErrorException
limitException){
sleep(startingIndex, startTime);
loadPullRequestData(…, startingIndex,
new Date());
}…
}
private void sleep( int startingIndex, Date startTime) {
long time = 1000 *60*60 –
(now.getTime() – startTime.getTime());
Thread.sleep(time);
}
Codul 4.3 Secvent ,ă de cod care tratează toate except ,iile la încărcarea
datelor
4.2.2 BitbucketDataLoader
Asemănătoare cu GitHubDataLoader, clasa BitbucketDataLoader extrage informat ,ii des-
pre repository-uri de tip Bitbucket folosind un REST API. Se foloses ,te aceeas ,i idee, se
verifică dacă există deja proiectul în baza de date, caz în care se face încărcare, iar dacă
nu există, se face actualizare. Metodele sunt aceleas ,i ca s ,i în cazul repository-urilor de
GitHub: loadProjectData(), loadloadDeveloperData(), loadPullRequestData(), loadCo-
mmentData() s ,i loadCommitData(). Diferent ,a dintre cele două clase constă în felul în
care se obt ,in datele de pe server. Dacă în cazul clasei GitHubDataLoader se foloses ,te un
Java API, în cazul acestei clase se foloses ,te REST API (vezi sect ,iunea 2.3).
Avantajul care apare atunci când extragem date de pe serverul de Bitbucket este că
nu mai avem acea constrângere legată de numărul de request-uri, deci tratarea acelor
except ,ii nu mai este necesară.

4.3. BAZA DE DATE 31
4.3 Baza de date
Aplicat ,ia prezentă foloses ,te baza de date H2 ca solut ,ie oferită de Spring Boot pentru
persistarea datelor în memorie. Această bază de date este o variantă open source bazată
pe Java care poate fi us ,or încorporată într-o aplicat ,ie de tip Spring s ,i nu numai. În
mod normal, Spring Boot configurează această bază de date să funct ,ioneze ca bază de
date în memorie, ceea ce înseamnă că datele nu vor fi salvate pe disc, ci se vor pierde
după repornirea aplicat ,ie, dar acest lucru poate fi modificat cu us ,urint ,ă din fis ,ierul de
proprietăt ,i al aplicat ,iei Spring (vezi ultima linie din exemplul 4.1). Tot de acolo putem
modifica username-ul s ,i parola de conectare la baza de date. Bineînt ,eles, această aplicat ,ie
va fi configurată pentru a păstra în baza de date toate informat ,iile extrase chiar s ,i după
terminare.
În exemplul 4.1 sunt exemplificate câteva din proprietăt ,ile setate pentru această
aplicat ,ie în ceea ce prives ,te baza de date:
spring.datasource.username=test
spring.datasource.password=test
spring.h2.console.enabled= true
spring.jpa.hibernate.ddl-auto=update
Exemplul 4.1 Câteva Proprietăt ,i ale bazei de date
Baza de date H2 vine cu o consolă GUI (interfat ,ă) pentru a putea vizualiza cont ,inutul
bazei de date s ,i pentru a rula comenzi SQL dacă este nevoie. Astfel, după pornirea
aplicat ,iei putem accesa linkul http://localhost:8080/h2 pentru a avea acces în consolă
unde ne autentificăm folosind username-ul s ,i parola setate:
Figura 4.3: Interfat ,a bazei de date H2
Modelul bazei de date utilizat pentru această aplicat ,ie este prezentat în figura 4.4 de
pe pagina următoare. Există câte o tabelă pentru fiecare entitate extrasă de pe serverele
de GitHub sau Bitbucket.
TabelaProject cont ,ine informat ,iile despre repository-ul analizat, iar între această
tabelă s ,i tabelele Developer s ,i Pull_Request există o relat ,ie de 1 la n, adică un proiect
poate avea mai mult ,i programatori s ,i mai multe pull request-uri.
TabelaDeveloper cont ,ine date despre programatori cum ar fi numele, email-ul,
username-ul s ,i id-ul.
TabelaPull_Request cont ,ine informat ,iile despre pull request-uri împreună cu id-ul
proiectuluidecareapart ,ines ,iid-urilecreatorului, respectivprogramatoruluicareaaccep-
tat pull request-ul (dacă există). În consecint ,ă, între tabela Developer s ,i Pull_Request

32 CAPITOLUL 4. PREZENTAREA ÎNTREGULUI SISTEM
există de-asemenea o relat ,ie de 1 la n. Tabela Pull_Request este folosită pentru a stoca
titlul pull request-ului, statusul (deschis, acceptat sau respins), data creării, data acceptă-
rii sau data închiderii, ramura proiectului pe care a fost deschis pull request-ul s ,i ramura
pe care a fost acceptat.
Între tabela Pull_Request s ,i tabelele Comment, File, Commit există de-asemenea
o relat ,ie de 1 la n, întrucât un pull request are asociate mai multe fis ,iere schimbate,
comentarii s ,i commit-uri. La fel există s ,i între tabela Developer s ,i tabelele Comment sau
Commit, deoarece orice comentariu sau commit are un autor.
TabelaComment cont ,ine informat ,ii legate de cont ,inutul unui comentariu, fis ,ierul
la care se referă, linia de cod (în cazul comentariilor pe linii de cod), id-u comentariului
”părinte” (dacă comentariul este răspuns la un altul) s ,i timestamp-ul.
TabelaCommit cont ,ine mesajele commit-urilor pe un anumit pull request s ,i data s ,i
ora la care au fost făcute.
TabelaFilecont ,ine toate informat ,iile referitoare la fis ,ierele schimbate în cadrul unui
pull request. Aceste informat ,ii sunt de numele fis ,ierului, numărul de linii modificate,
numărul de linii adăugate s ,i numărul de linii s ,terse.
Din punct de vedere al implementării, pentru fiecare tabelă există câte un Repository
de tip CrudRepository care stochează toate aceste date. Datorită framework-ului Spring,
aceste repository-uri au deja definite toate metodele pentru a putea obt ,ine datele din
baza de date. În acest context, aplicat ,ia va avea 6 repository-uri: ProjectRepository,
DeveloperRepository, PullRequestRepository, CommentRepository, CommitRepository
s,i FileRepository.
Figura 4.4: Diagrama cu tabele ale bazei de date

4.4. DATAREGISTER 33
4.4 DataRegister
Clasa DataRegister este clasa care realizează al treilea pas din fluxul aplicat ,iei de fat ,ă.
Ea se ocupă cu obt ,inerea tuturor datelor din baza de date s ,i popularea unui model cu
aceste date. Se implementează, cu alte cuvinte, un mecanism de cacheing pentru date (o
memorie cache).
Memoria cache este o colect ,ie de date ce reprezintă o copie a datelor originale, acestea
fiind aduse, de obicei, o singură dată în memorie. Citirea datelor din baza de date la
fiecare iterat ,ie este costisitoare din punct de vedere al timpului s ,i nu se pretează. Pentru
că majoritatea datelor necesare în analize se află în baza de date, la fiecare calcul sau
verificare ar fi nevoie de numeroase citiri costisitoare. Aceste citiri ar încetini procesul, iar
performant ,a întregului proces de analiză ar fi scăzută. Datele sunt aduse în memorie de
fiecare dată când se dores ,te analizarea unui repository, urmând ca mai apoi informat ,iile
necesare să fie preluate din cache.
Modelulfolositpentrumemoriacacheesteasemănătorcucelalbazeidedate,diferent ,a
fiind că în memoria cache se păstrează doar proiectul care va fi supus analizelor.
Înceeaceprives ,teimplementarea, sevorfolosidouaregistre, unulcarememoreazătot ,i
programatorii numit DeveloperRegistry , iar celălalt pentru memorarea pull request-
urilor numit PullRequestRegistry . Registrul cu programatori va fi format dintr-o listă
de obiecte Developer ce vor cont ,ine pe lângă datele personale s ,i o listă cu pull request-
uri create sau acceptate de acesta, o listă ce cont ,ine comentariile făcute s ,i o listă cu
commit-urile efectuate. Asemănător, registrul cu pull request-uri va fi o listă de obiecte
PullRequest care vor cont ,ine pe lângă datele legate de pull request s ,i o listă cu comentarii
asociate, fis ,iere modificate, commit-uri s ,i doua atribute de tip Developer ce corespund
creatorului pull request-ului, respectiv celui care a acceptat pull request-ul (dacă este
cazul). Obiectele de tip Comment, Commit sau File vor avea de-asemenea câte un autor
de tip Developer s ,i un pull request asociat de tip PullRequest.
Modelul memoriei cache va fi populat cu aceste date conform informat ,iilor din baza
de date după cum se poate vedea s ,i în figura 4.5 :

34 CAPITOLUL 4. PREZENTAREA ÎNTREGULUI SISTEM
Figura 4.5: Diagrama de clase a memoriei cache

4.5. DATAANALYZER 35
În momentul în care se dores ,te analizarea unui proiect din baza de date, se setează
atributul ce cont ,ine numele proiectului de analizat din clasa DataRegister s ,i se apelează
metoda registerData() care aduce toate datele din baza de date s ,i le stochează în cele
doua registre :
public class DataRegister {

private DeveloperRegistry developerRegistry;
private PullRequestRegistry pullRequestRegistry;
private ProjectData projectToAnalyze;

public void registerData() {
registerDevelopersDetails();
registerPullRequestsDetails();
registerCommentsDetails();
registerCommitsDetails();
registerFilesDetails();
registerCommentsForPullRequests();
registerCommentsForDevelopers();
registerCommitsForPullRequests();
registerCommitsForDevelopers();
registerFilesForPullRequests();
registerCreatedPRsForDeveloper();
registerMergedPRsForDeveloper();
}
}
Codul 4.4 Secvent ,ă de cod cu metodele apelate pentru înregistrarea
datelor în memoria cache
4.5 DataAnalyzer
Clasa DataAnalyzer este clasa care se ocupă de penultimul pas din fluxul aplicat ,iei,
adică implementează s ,i rulează analizele pe datele extrase s ,i memorate. După cum s-a
ment ,ionat s ,i în introducere, această clasă det ,ine cea mai mare parte din logica acestei
aplicat ,ii. Pe lângă faptul că implementează analizele, ea salvează rezultatele obt ,inute
într-un model pentru a putea fi us ,or accesate pe urmă s ,i le exportă în fis ,iere de tip Excel
pentru a putea fi rapid citite s ,i interpretate.
Clasa are ca dependent ,e doua clase DeveloperAnalyzer, respectiv PullRequestAnaly-
zercaresuntfolositepentruproducereacelordouacategoriideanalizes ,ioaltădependent ,ă
către proiectul ce trebuie analizat. Tot în component ,a clasei se regăsesc s ,i două referint ,e
către clasele folosite pentru memorarea rezultatelor. Una dintre ele este developerA-
nalyses care este o listă ce cuprinde rezultatele obt ,inute pentru fiecare programator în
parte, iar cealaltă este pullRequestAnalysis care este un obiect ce memorează rezulta-
tele obt ,inute pentru întreg proiectul analizat.
Atunci când se analizează proiecte foarte mari cu multe date, ideal este ca întregul
proces să fie unul performant, rapid, cu rezultate bune s ,i dacă se poate cât mai simplu de
implementat. În acest context, această lucrare profită de noua funct ,ionalitate introdusă
în Java 8 s ,i anumeStreams . Folosind acest concept, analizele merg mult mai repede,

36 CAPITOLUL 4. PREZENTAREA ÎNTREGULUI SISTEM
mult mai us ,or s ,i totul se poate face în câteva linii de cod. Nu mai sunt necesare multe
bucle de tip for s ,i o grămadă de teste de tip if, întrucât API-ul de Streams oferă avantajul
de a trata colect ,iile de date ca pe nis ,te fluxuri de date pe care le putem filtra, ordona,
număra sau colecta în alte liste foarte us ,or. Utilitatea folosirii API-ului de Streams va fi
vizibilă în următoarele subsect ,iuni.
Clasa Main apelează metoda analyzeData() care va rula pe rând analizele ment ,ionate
:
public class DataAnalyzer {
private DeveloperAnalyzer developerAnalyzer;
private PullRequestAnalyzer pullRequestAnalyzer;
private ProjectData projectToAnalyze;
private List<DeveloperAnalysis> developerAnalyses;
private PullRequestAnalysis pullRequestAnalysis;
@Autowired
public DataAnalyzer
(DeveloperAnalyzer developerAnalyzer,
PullRequestAnalyzer pullRequestAnalyzer) {
//setters…
}
public void analyzeData() throws IOException {
developerAnalyses = developerAnalyzer
.run(projectToAnalyze);
pullRequestAnalysis = pullRequestAnalyzer
.run(projectToAnalyze);
}
}
Codul 4.5 Clasa DataAnalyzer
În următoarele subsect ,iuni vor fi prezentate mai în detaliu analizele implementate din
clasele DeveloperAnalyzer s ,i PullReqeustAnalyzer, iar exportarea rezultatelor s ,i inter-
pretarea lor vor fi discutate în capitolul 4.
4.5.1 DeveloperAnalyzer
DeveloperAnalyzer este clasa care se va ocupa de analizele referitoare la fiecare progra-
mator implicat pe proiect. Ea va genera o listă de obiecte de tip DeveloperAnalysis care
cont ,in rezultatele obt ,inute pentru analizele prezentate în sect ,iunea 1.3. Această clasă are
ca s ,i dependint ,e injectate cele doua registre cu programatori s ,i pull request-uri de unde
va lua datele s ,i un obiect al clasei Statistics cu care se vor calcula medii sau mediane.
Modelul clasei DeveloperAnalysis care memorează rezultatele este prezentat în figura
4.6 :

4.5. DATAANALYZER 37
DeveloperAnalysis
developer Developer
openedPR int
mergedPRByCreator long
mergedPRByOthers long
mergedPROfOthers long
closedWithoutMergePR long
longTimeToMergePR long
openForALongTimePR long
noOfComplexPR long
noOfCommentsOfCreatedPR List<Integer>
commentsOnCreatedPR long
commentsOnOtherPR long
noOfCommits List<Integer>
noOfChangedFiles List<Integer>
reactionTimesOnPR List<Long>
mergeTimesOfCreatedPR List<Long>
responseTimesOnComments List<Double>
timeline List<DeveloperActivity>
interactions Map<String,Integer>
Figura 4.6: Modelul clasei DeveloperAnalysis
A se observa că pentru unele din rezultate nu s-au memorat valori, ci liste de valori,
asta pentru că aplicat ,ia pentru exportarea rezultatelor va lua în considerare atât media
valorilor, dar s ,i mediana acelor valori, întrucât aceasta din urmă poate să fie cu mult
diferită fat ,ă de medie. Pentru toate analizele ce urmează a fi prezentate, media sau
mediana se vor calcula apelând metode specifice din clasa Statistics.
În continuare se vor discuta analizele implementate pentru această clasă. Fiecărei
analize îi corespunde o metodă care extrage tot ,i programatorii din DeveloperRegisrtry s ,i
îi supune unor verificări:
Pentru calculul numărului de pull request-uri deschise se verifică dimensiunea listei
de pull request-uri create pe care o are fiecare programator.
Pentru calcului numărului de pull request-uri ale lui acceptate de el însus ,i, ale lui
acceptate de alt ,ii sau pull request-uri acceptate de el ale altor programatori se
verifică lista de pull request-uri acceptate s ,i se filtrează după autorul pull request-
ului s ,i autorul care a acceptat pull request-ul. Pentru exemplificare, se va arăta
cum anume s-au extras numărul pull request-urilor lui acceptate de alt ,ii:

38 CAPITOLUL 4. PREZENTAREA ÎNTREGULUI SISTEM
public long getMergedPullRequestsByOthers() {
return createdPullRequests.stream()
.filter(x -> x.getMergeDate() != null &&
!x.getMergeDev().getDeveloperId()
.equals( this .getDeveloperId()))
.count();
}
Codul 4.6 Metoda pentru a obt ,ine numărul pull request-urilor
acceptate de alt ,ii
Pentrucalculuinumăruluidepullrequest-urideschisedemulttimpsaupullrequest-
uri care au fost acceptate după o perioadă destul de lungă se timpul se calculează
timpul de la deschidere până în prezent, respectiv până la acceptare a pull request-
urilor create . Dacă această durată depăs ,es,te 7 zile, se iau în calcul. În exemplul
următor, se va arăta cum se calculează numărul pull request-urilor deschis de mult
timp:
public Long getLongTimePR() {
return createdPullRequests.stream()
.filter(x -> x.getStatus()
.equals("open") &&
x -> x.isOpenForALongTime())
.count();
}
public boolean isOpenForALongTime() {
Date today = new Date();
long time = today.getTime()
– creationDate.getTime();
long days = time / (1000 *60*60*24);
if(days > 7)
return true ;
return false ;
}
Codul 4.7 Metode pentru obt ,inerea numărului de pull request-uri
deschise de mult timp
Pentru calcului numărului de pull request-uri respinse se calculează numărul pull
request-urilor create, dar care nu au nicio dată de acceptare. Asta înseamnă că
au fost deschise pentru a aduce nis ,te modificări, dar acele modificări nu au fost
acceptate pe proiect
Pentru calcului numărului de pull request-uri ”complexe” se iau în considerare acele
pull request-uri care au următoarele caracteristici:
1. Pull request-urile sunt încă deschise sau au fost acceptate.
2. Au mult ,i programatori implicat ,i prin comentarii.

4.5. DATAANALYZER 39
3. Au multe comentarii
4. Pull request-urile respective au o durată de viat ,ă destul de lungă.
5. Există multe commit-uri după deschidere (follow up commits) pe acestea
6. Numărul fis ,ierelor modificate nu este foarte mare astfel încât să fie vreo problemă.
public long getNoOfComplexPRs() {
return createdPullRequests.stream()
.filter(x -> x.isOpenForALongTime() ||
(x.getMergeDate() != null &&
(x.getTimeForMerging() /
(1000 *60*60*24)) > 7))
.filter(x -> x.getFilesModified().size() < 4)
.filter(x -> x.getNoOfFollowUpCommits() >= 2)
.filter(x -> x.getComments().size() >= 8)
.count();
}
Codul 4.8 Metoda de obt ,inere a pull request-urilor complexe
Numărulmediudecomentarii, commit-uris ,ifis ,iereschimbatepentrufiecareprogra-
mator se calculează apelând o metodă pentru calcularea mediei din clasa Statistics.
Această metodă primes ,te o listă de valori s ,i returnează media lor:
public double calculateLongsAverage(List<Long> values) {
return values.stream()
.collect(Collectors.averagingLong(Long::longValue));
}
Codul 4.9 Metoda pentru calcularea mediei unei liste de valori
Numărul de comentarii pe pull request-urile create se calculează însumând comen-
tariilecareaucas ,iautorprogramatorulrespectiv, iarnumăruldecomentariipealte
pull request-uri se calculează verificând toate comentariile programatorului care nu
sunt pe pull request-urile create de el.
Timpul mediu de react ,ie la pull request-urile colegilor se calculează ca fiind media
timpilor în care programatorul respectiv a comentat primul pe un pull request de-al
unui coleg. Aces ,ti timpi sunt calculat ,i în ore:
1. Se verifică toate pull request-urile care nu sunt create de el s ,i care au cel put ,in un
comentariu de-al lui
2. Se calculează timpul scurs de la crearea pull request-ului până la primul comentariu.

40 CAPITOLUL 4. PREZENTAREA ÎNTREGULUI SISTEM
public List<Long> getReactionTime(List<PullRequest>
allPullRequests) {
return allPullRequests.stream()
.filter(x -> !x.getCreatorDev()
.getDeveloperId()
.equals( this .getDeveloperId()))
.filter(x ->
x.hasAtLeastOneCommentFromDeveloper( this ))
.map(x ->
x.getReactionTimeFromDeveloper( this ))
.sorted(Comparator.comparing(Long::longValue))
.collect(Collectors.toList());
}
public long getReactionTimeFromDeveloper(Developer developer) {
Comment firstComment = comments.stream()
.filter(x -> x.getAuthor() != null &&
x.getAuthor().getDeveloperId()
.equals(developer.getDeveloperId()))
.min(Comparator.comparing(Comment::getTimestamp))
.orElse( null );
if(firstComment != null ){
return firstComment.getTimeSincePRCreation();
}
return 0L;
}
Codul 4.10 Metode pentru calcularea timpului mediu de react ,ie
Pentru timpul mediu de acceptare al pull request-urilor, se iau toate pull request-
urile acceptate s ,i se face media duratelor de la creare până la acceptare. Aceste
durate se măsoară de obicei în zile.
Pentru timpul mediu de răspuns la comentarii se aplică următorul algoritm:
1. Se împart toate comentariile în comentarii pe un anumit fis ,ier s ,i comentarii generale
care nu sunt pe un anumit fis ,ier.
2. Pentru comentariile generale se va calcula un timp, iar pentru comentariile pe un
anumit fis ,ier se va calcula un timp pentru fiecare fis ,ier, întrucât discut ,iile au loc pe
fiecare fis ,ier în parte.
3. Pentruambelecategoriidecomentariisedistingdouăsituat ,ii. Vorexistacomentarii
caresuntrăspunslaaltecomentarii,cazîncaresecalculeazătimpulrăspunsuluifat ,ă
de comentariul ”părinte” s ,i vor exista comentarii care nu sunt neapărat un răspuns
la alte comentarii, caz în care se va lua în considerare timpul fiecărui comentariu
de-al programatorului fat ,ă de ultimul comentariu care nu este al lui.
4. Se calculează câte o medie pe fiecare fis ,ier s ,i pe comentarii generale, iar rezultatul
va fi media acestor medii calculate anterior.
O analiză foarte importantă din punctul de vedere al acestei lucrări este calcularea
interact ,iunilor dintre programatori.
Din punct de vedere teoretic, se consideră o interact ,iune între doi programa-
tori dacă pe un anumit pull request au existat cel put ,in doua comentarii de
la amândoi.

4.5. DATAANALYZER 41
Din punct de vedere al implementării, se creează o matrice de n programatori
* n programatori unde o valoare reprezintă numărul de interact ,iuni, se verifică
pentru fiecare pull request ce programatori au avut minim două comentarii s ,i
se completează matricea.
Pentru memorarea rezultatelor, se foloses ,te pentru fiecare programator un
dict ,ionar unde cheia este numele programatorului, iar valoarea este reprezen-
tată de un alt dict ,ionar format din perechi nume – număr de interact ,iuni,
reprezentând tot ,i ceilalt ,i colegi s ,i câte interact ,iuni au avut pe proiect.
public void calculateInteractions(List<String> developers,
int[][] interactions) {
Set<String> authors = comments.stream()
.filter(x -> x.getAuthor() != null )
.map(x -> x.getAuthor().getUsername())
.collect(Collectors.toSet());
List<String> developersWhoCommunicate
= authors.stream()
.filter(x ->
this .hasTwoCommentsFromDeveloper(x))
.collect(Collectors.toList());
if(developersWhoCommunicate.size() > 1) {
String[] devs = new String[developersWhoCommunicate
.size()];
devs = developersWhoCommunicate.toArray(devs);
for (int i = 0 ; i < devs.length – 1; i++) {
for (int j= i+1; j < devs.length; j++) {
int devA = developers
.indexOf(devs[i]);
int devB = developers
.indexOf(devs[j]);
interactions[devA][devB]++;
interactions[devB][devA]++;
}
}
}
}
Codul 4.11 Calcularea interact ,iunilor dintre programatori
Ultima dintre analize nu este chiar o analiză, ci este mai degrabă crearea unei
cronologii pentru fiecare programator în parte. Această cronologie va cont ,ine toate
activităt ,ile pe care programatorul le-a avut pe proiect de-a lungul timpului.
Aceste activităt ,i vor fi reprezentate prin clase ce mos ,tenesc superclasa Deve-
loperActivity s ,i vor putea fi următoarele: OpenPRActivity, ClosePRActivity,
MergePRActivity, CommitActivity s ,i CommentActivity.
Ca s ,i implementare, pentru fiecare programator se vor extrage toate pull
request-urile create, acceptate sau închise, se vor extrage toate comentari-
ile s ,i commit-urile s ,i se vor crea obiecte de tipul DeveloperActivity ce vor fi
salvate într-o listă în ordinea timestamp-ului fiecărei activităt ,i

42 CAPITOLUL 4. PREZENTAREA ÎNTREGULUI SISTEM
Figura 4.7: Diagrama de clase a activităt ,ilor unui programator
4.5.2 PullRequestAnalyzer
PullRequestAnalyzeresteclasacaresevaocupadeanalizelereferitoarelaîntregproiectul.
Această clasă are aceeas ,i structură ca s ,i DeveloperAnalyzer, iar logica este asemănătoare.
De data aceasta, nu se va mai produce o listă de rezultate, ci se va genera un singur obiect
de tipul PullRequestAnalysis care va îngloba rezultatele obt ,inute. Asemănător, clasa are
referint ,e către registrul cu programatori, registrul cu pull request-uri s ,i o referint ,ă către
clasa Statistics.
Modelul clasei PullRequestAnalysis care memorează rezultatele este prezentat în fi-
gura 4.8 :

4.5. DATAANALYZER 43
PullRequestAnalysis
owner String
projectName String
openPRs List<PullRequest>
closedPRs List<PullRequest>
mergedPRs List<PullRequest>
longTimeToMergePRs List<PullRequest>
openForALongTimePRs List<PullRequest>
prsWithoutActivity List<PullRequest>
complexPRs List<PullRequest>
dailyOpenedPRs List<Date>
dailyMergedPRs List<Date>
noOfCommentsPerPR List<Integer>
noOfCommentsOnCodePerPR List<Long>
noOfSimpleCommentsPerPR List<Long>
noOfCommitsPerPR List<Integer>
noOfFollowUpCommitsPerPR List<Long>
noOfChangedFilesPerPR List<Integer>
branchBranchPRs List<PullRequest>
reactionTimesOnPRs List<Double>
responseTimesOfPROwner List<Double>
mergeTimesOfPRs List<Long>
crowdedDays TreeMap<Date,Long>
crowdedTwoDays TreeMap<Date,Long>
crowdedThreeDays TreeMap<Date,Long>
PRTimeline Map<Long,List<PullRequestActivity>>
Figura 4.8: Modelul clasei PullRequestAnalysis
La fel ca s ,i în cazul modelului DeveloperAnalysis, unele date nu au fost salvate ca
valori, ci ca liste de valori sau chiar liste de pull request-uri. Când vrem să analizăm un
proiect, s-ar putea să nu fie de ajuns doar salvarea numărului de anumite pull request-
uri, ci se dores ,te salvarea pull request-urilor în sine pentru a le putea identifica s ,i studia
ulterior. De-asemenea, acest lucru s-ar putea să fie util s ,i pentru a vizualiza rezultatele.
Astfel, putem să vizualizăm s ,i care sunt acele pull request-uri care au o anumită problemă
s,i ce informat ,ii mai cont ,in ele.
O parte din analizele ce apar în DeveloperAnalyzer apar s ,i în PullRequestAnalyzer,
ideea este aceeas ,i, doar că cele din cadrul DeveloperAnalyzer se referă la fiecare pro-
gramator în parte, iar aici rezultatele se referă la întreg proiectul, net ,inându-se cont de
programator. În consecint ,ă, pentru a nu se repeta, vor fi discutate în continuare doar
analizele mai importante s ,i analizele care nu au fost ment ,ionate deja s ,i în subsect ,iunea

44 CAPITOLUL 4. PREZENTAREA ÎNTREGULUI SISTEM
anterioară:
Pullrequest-urilefărăactivitatesuntpullrequest-uricareaufostdeschises ,iulterior
acceptate fără niciun comentariu. Se numără astfel toate pull request-urile unui
proiect care au fost acceptate, dar nu au niciun comentariu:
private List<PullRequest> getApprovedWithoutActivityPRs() {
return pullRequestRegistry.getPullRequests().stream()
.filter(x -> x.getMergeDate() != null )
.filter(x -> x.getComments().size() == 0)
.collect(Collectors.toList());
}
Codul 4.12 Metodă care returnează pull request-urile fără activitate
Pentru numărul mediu de pull request-uri create / acceptate pe zi / săptămână se
extrag pull request-urile create sau acceptate în fiecare zi, iar apoi se apelează o
metodă de calcul din clasa Statistics care face o medie pe zi sau pe săptămână.
În exemplul următor se vor prezenta metodele pentru a obt ,ine numărul mediu
de pull request-uri create pe săptămână, restul făcându-se asemănător.
Prima metodă este folosită pentru a obt ,ine pull request-urile create în fie-
care zi, iar a doua este metoda din clasa Statistics care calculează media pe
săptămână:
private List<Date> getDailyOpenedPRs() {
return pullRequestRegistry.getPullRequests().stream()
.sorted(Comparator.comparing
(PullRequest::getCreationDate))
.map(x -> x.getCreationDate())
.collect(Collectors.toList());
}
public double calculateWeeklyAverage(List<Date> dates) {
Date firstDate = dates.get(0);
Date lastDate = dates.get(dates.size() – 1);
long noOfWeeks = (lastDate.getTime() –
firstDate.getTime()) / (1000 *60*60*24*7);
Map<Long, Long> weeks = dates.stream()
.collect(Collectors.groupingBy(x ->
x.getTime() / (1000 *60*60*24*7),
Collectors.counting()));
return (double ) weeks.values().stream()
.collect(Collectors.summingLong
(Long::longValue)) / noOfWeeks;
}
Codul 4.13 Metode folosite pentru a obt ,ine numărul mediu de pull
request-uri create pe săptămână

4.5. DATAANALYZER 45
În ceea ce prives ,te numărul de mediu de commit-uri, pentru un proiect se iau în
calcul s ,i numărul mediu de commit-uri făcute după deschiderea unui pull request.
Acestea poartă denumirea de follow up commits. Ele se iau în considerare s ,i pentru
calculul numărului de pull request-uri complexe. Pentru obt ,inerea lor, se verifică
toate commit-urile s ,i se iau doar acelea care au data creării după data creării pull
request-ului:
public long getNoOfFollowUpCommits() {
return commits.stream()
.filter(x -> x.getTimestamp().getTime() >
x.getPullRequest().getCreationDate()
.getTime())
.count();
}
Codul 4.14 Metodă folosită pentru a obt ,ine numărul de follow up
commits
O altă analiză importantă este numărul de pull request-uri care au fost deschise s ,i
acceptate pe aceeas ,i ramură (branch):
private List<PullRequest> getNoOfBranchBranchPRs() {
return pullRequestRegistry.getPullRequests()
.stream()
.filter(x -> x.getInitBranch().
equals(x.getFinalBranch()))
.collect(Collectors.toList());
}
Codul 4.15 Metodă folosită pentru a obt ,ine numărul de pull request-uri
deschise s ,i închise pe acelas ,i branch
Important de s ,tiut pentru un proiect sunt s ,i perioadele ”aglomerate”, adică perioade
în care s-au creat mai multe pull request-uri decât de obicei. Aceste perioade se
calculează ca fiind trei zile consecutive, iar pentru determinarea lor s-a aplicat
următorul algoritm:
1. Se extrage numărul de pull request-uri create în fiecare zi.
2. Se stabilesc nis ,te praguri (thresholds) pentru numărul minim de pull request-uri
create într-o zi, două sau trei zile. De exemplu, dacă s-au creat minim 5 pull
request-uri într-o zi, acea zi este considerată o zi aglomerată, dacă s-au creat 12
pullrequest-uriîntotalîndouăzile, aceledouăzileformeazăoperioadăaglomerată,
iar pragul pentru trei zile este de 20 de pull request-uri.
3. Se verifică pragul pentru perioade de o zi, două sau trei zile consecutive s ,i pune
acele zile într-un dict ,ionar de forma zi – număr pull request-uri create.
4. Dacă o anumită zi apare în dict ,ionarul cu 3 zile aglomerate de exemplu, acea zi nu
va mai fi pusă s ,i în celelalte dict ,ionare, deoarece a fost deja luată în considerare.

46 CAPITOLUL 4. PREZENTAREA ÎNTREGULUI SISTEM
Algoritmul face s ,i verificări pentru detectarea unor perioade aglomerate false,
adică perioade de două zile sau trei zile în care într-o zi să fie multe pull
request-uri create, iar în cealaltă să fie doar unul sau două, dar luate împreună
să depăs ,ească pragul.
El s ,tie să detecteze aceste perioade prin verificarea că niciuna din zile din
perioadă nu depăs ,es,te mai mult de 70% din totalul de pull request-uri (pentru
perioadededouăzile)s ,iprinverificareacăfiecarezidinperioadăareunminim
de 25% din total (pentru perioade de trei zile).
Fiind un algoritm destul de lung, se va exemplifica doar port ,iunea pentru
perioade de doua zile:

for (int i = 1; i < dates.size(); i++) {
Long first = dailyPRs.get(dates.get(i-1));
Long second = dailyPRs.get(dates.get(i));
double proportion = 0.7 *(first + second);
if(first + second > twoDaysThreshold &&
first < proportion &&
second < proportion) {
if(getDayNo(dates.get(i)) ==
getDayNo(dates.get(i-1)) + 1) {
manyPRsTwoDays.put(dates.get(i – 1), first);
manyPRsTwoDays.put(dates.get(i), second);
}
}
}

Codul 4.16 Port ,iune de cod pentru detectarea perioadelor aglomerate
de două zile
La fel ca s ,i în cazul programatorilor, se realizează o cronologie s ,i pentru fiecare pull
request în parte. Această cronologie va cont ,ine toate evenimentele care au avut loc
pe un pull request de la creare până la acceptare sau respingere.
Evenimentele vor subclase ale clasei PullRequestActivity: OpenPRActivity,
ClosePRActivity, MergePRActivity, CommentOnPRActivity s ,i FollowUpCo-
mmitActivity.
Asemănător clasei DeveloperAnalyzer, se vor extrage toate comentariile s ,i
commit-urile de pe pull request s ,i datele de deschidere, respectiv închidere
sau acceptare s ,i se vor crea obiectele specifice ce vor fi puse într-o listă pentru
fiecare pull request.
Figura 4.9: Diagrama de clase a evenimentelor unui pull request

4.6. DATAPARSER 47
4.6 DataParser
Clasa DataParser este clasa care realizează ultimul pas al fluxului acestei aplicat ,ii. Ea
se ocupă de adunarea tuturor datelor încărcate în registre referitoare la dezvoltatori, pull
request-uri, comentarii, commit-uri s ,i fis ,iere modificate s ,i a rezultatelor obt ,inute prin
analize s ,i realizează un export al tuturor acestor informat ,ii în format JSON pentru a
putea fi apoi integrate în instrumente de vizualizare. Lucrarea de fat ,ă nu se ocupă s ,i de
implementarea acestor instrumente, dar este gândită ca pe viitor să fie o aplicat ,ie web în
care partea de analiză să fie integrată cu instrumentele de vizualizare.
Exportul datelor se realizează folosind pentru fiecare entitate ment ,ionată mai sus câte
un obiect de transfer DTO (Data Transfer Object). Clasele folosite pentru instant ,ierea
acestor obiecte sunt asemănătoare cu cele din model, dar sunt concepute pentru a fi
serializate în format JSON. Acestea sunt DeveloperDTO ,PullRequestDTO ,Com-
mentDTO ,CommitDTO ,FileDTO ,DeveloperAnalysisDTO s,iPullRequestA-
nalysisDTO . Pentru a facilita accesul s ,i serializarea acestora, după ce sunt instant ,iate
obiectele, acestea sunt salvate în liste într-un registru DTORegistry :
@Data
@Service
public class DTORegistry {
private List<DeveloperDTO> developerDTOS;
private List<PullRequestDTO> pullRequestDTOS;
private List<CommentDTO> commentDTOS;
private List<CommitDTO> commitDTOS;
private List<FileDTO> fileDTOS;
private List<DeveloperAnalysisDTO>
developerAnalysisDTOS;
private PullRequestAnalysisDTO
pullRequestAnalysisDTO;
}
Codul 4.17 Clasa DTORegistry pentru memorarea datelor ce trebuie
serializate
Clasa DataParser are ca s ,i dependent ,e cele două registre cu programatori s ,i pull request-
uri, un obiect al clasei Statistics pentru calcule, o instant ,ă a clasei DataAnalyzer pentru
a obt ,ine rezultatele analizelor s ,i registrul DTO pentru transfer. În momentul în care
aplicat ,ia face exportul, se apelează metoda parseData() care ia pe rând toate datele s ,i le
salvează în registrul DTO:
public void parseData() {
parseDevelopers();
parsePullRequests();
parseComments();
parseCommits();
parseFiles();
parseDevAnalysis();
parsePRAnalysis();
}
Codul 4.18 Metoda parseData() din clasa DataParser

48 CAPITOLUL 4. PREZENTAREA ÎNTREGULUI SISTEM
Întrucât s-a ment ,ionat faptul că această aplicat ,ie va avea integrată pe viitor s ,i partea de
vizualizare a datelor s ,i va fi o aplicat ,ie web, toate informat ,iile păstrate în registrul DTO
vor fi exportate atât în fis ,iere de tip json separate, dar vor fi accesibile s ,i prin cereri de
tip HTTP din browser.
În Spring, cererile (request-urile) HTTP sunt gestionate de un Controller. Această
aplicat ,iearedefinitcâteuncontrollercaregestioneazăocereredetipGET(GETrequest)
pentru fiecare entitate exportată, iar prin acest request de tip GET s ,i datorită framework-
ului Spring, toate datele cerute sunt returnate în format JSON automat. Controller-ul
este o clasă us ,or de identificat fiind adnotată cu @RestController. Folosind această ad-
notare, clasa va fi înregistrată ca un bean în container-ul Spring. Un bean este un obiect
care este instant ,iat, asamblat s ,i administrat de container-ul Ioc Spring (Ioc – Inversion
of Control). Pentru fiecare controller se foloses ,te adnotarea @RequestMapping care ma-
pează implicit operat ,iile de tip HTTP, cum ar fi GET, POST, DELETE s ,i UPDATE.
În cazul lucrării de fat ,ă, se foloses ,te o singura metodă în fiecare controller adnotată cu
@GetMapping pentru obt ,inerea de date.
În acest context, toate datele sunt accesibile din browser la următoarele adrese:
http://localhost:8080/developers : pentruaobt ,inetot ,iprogramatoriiimplicat ,i
pe proiect
http://localhost:8080/pullrequests : pentru a obt ,ine toate pull request-
urile
http://localhost:8080/comments : pentru a obt ,ine toate comentariile
http://localhost:8080/commits : pentru a obt ,ine toate commit-urile
http://localhost:8080/files : pentru a obt ,ine toate fis ,ierele modificate
http://localhost:8080/dev_analysis : pentruaobt ,inerezultateleanalizelor
pe programatori
http://localhost:8080/pr_analysis : pentru a obt ,ine rezultatele analizelor
pe întreg proiectul

Capitolul 5
Utilizarea aplicat ,iei
În acest capitol se va descrie cum poate fi utilizată aplicat ,ia, cum sunt exportate rezul-
tatele analizelor s ,i se vor studia câteva rezultate obt ,inute pentru a putea vedea utilitatea
acestui instrument.
5.1 Configurarea aplicat ,iei
Pentru a putea folosi aplicat ,ia, aceasta trebuie configurată corespunzător, iar acest lucru
este posibil folosind aplicat ,ia desktop s ,i dialogurile de configurare. Se disting trei opt ,iuni
pentru un utilizator care foloses ,te aplicat ,ia:
Acesta poate selecta să încarce un proiect în baza de date, caz în care se va realiza
doar partea de extract ,ie de informat ,ii s ,i încărcare în baza de date.
Utilizatorul va fi întrebat ce tip de repository vrea să încarce (GitHub sau Bi-
tbucket), i se vor cere username-ul s ,i parola de conectare la serviciul respectiv
s,i det ,inătorul s ,i numele repository-ului:
Figura 5.1: Dialogul cu prima opt ,iune a utilizatorului
49

50 CAPITOLUL 5. UTILIZAREA APLICAT ,IEI
A doua opt ,iune disponibilă este să încarce un proiect s ,i să îl s ,i analizeze după
încărcare,cazîncaresevorrealizatot ,ipas ,iidinfluxulaplicat ,iei(extract ,ie,încărcare
în baza de date, încărcare în memoria cache, analizare s ,i generare rezultate).
Dateleceruteutilizatoruluis ,idialogulsuntaceleas ,icas ,ipentruprimaopt ,iune.
Ultima opt ,iune este să analizeze un proiect existent deja în baza de date, caz în
care se va realiza doar partea de încărcare a datelor în memoria cache, analizarea
lor s ,i producerea rezultatelor.
Utilizatorului i se va cere doar numele proiectului pe care dores ,te să-l anali-
zeze:
Figura 5.2: Dialogul cu a treia opt ,iune a utilizatorului
5.2 Exportarea rezultatelor analizelor
Analizele obt ,inute rulând această aplicat ,ie sunt exportate în fis ,iere de tip Excel folosind
biblioteca Apache POI care este un Java API pentru a facilita lucrul cu documente
Microsoft Office. Am ales să export rezultatele în acest format, deoarece fis ,ierele Excel
sunt folosite pentru date tabelare, pentru analize s ,i reprezintă o solut ,ie rapidă s ,i us ,or de
citit.
Folosirea bibliotecii Apache POI este simplă s ,i intuitivă. Din punct de vedere al
implementării, documentul Excel este un obiect de tip Workbook , foaia de calcul este
un obiect de tip Sheet, rândurile din tabel sunt obiecte Row, iar celulele sunt obiecte
de tipCell:

5.3. INTERPRETAREA REZULTATELOR 51
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("sheetName");

CellStyle headerCellStyle =
workbook.createCellStyle();
headerCellStyle.setFont(headerFont);
headerCellStyle.setAlignment
(HorizontalAlignment.CENTER);

Row row = sheet.createRow(0);
Cell cell = row.createCell(i);
cell.setCellValue(someValue);
cell.setCellStyle(headerCellStyle);
Codul 5.1 Crearea obiectelor pentru fis ,ierul Excel
În clasele DeveloperAnalyzer s ,i PullRequestAnalyzer este implementată metoda expor-
tAnalysis() care exportă rezultatele analizelor în doua fis ,iere de tip Excel. În continuare
este prezentată metoda exportAnalysis() din clasa DeveloperAnalyzer, cea din clasa Pul-
lRequestAnlayzer fiind exact la fel, doar că se exportă rezultatele pe proiect:
private void exportAnalysis(List<DeveloperAnalysis>
developerAnalyses,…) throws IOException {
Workbook workbook = new XSSFWorkbook();
exportAnalysisValues(developerAnalyses, workbook);
exportTimeline(developerAnalyses, workbook);
exportInteractions(developerAnalyses, workbook);
FileOutputStream file =
new FileOutputStream("fileName.xlsx");
workbook.write(file);
file.close();
workbook.close();
}
Codul 5.2 Metoda exportAnalysis() din clasa DeveloperAnalyzer
5.3 Interpretarea rezultatelor
După cum s-a ment ,ionat în capitolul precedent, această aplicat ,ie nu are încă integrată
partea de vizualizare a datelor s ,i a rezultatelor, dar pentru interpretarea lor se vor folosi
s,abloane html cu cod JavaScript care creează diagrame s ,i grafice cu rezultatele obt ,inute.
Cu ajutorul acestora, se pot forma păreri s ,i opinii asupra comunicării s ,i lucrului în echipă
al programatorilor s ,i se pot trage concluzii valide cu ceea ce se întâmplă în întregul sistem.
În continuare vor fi prezentate s ,i interpretate rezultate obt ,inute prin analizarea pro-
iectuluiKafkade pe GitHub al celor de la Apache.
Diagramele s ,i graficele au fost generate folosind s ,abloane din biblioteca D3.js [11].
Pentru o privire de ansamblu asupra pull request-urilor create ale unui proiect se
foloses ,te următoarea diagramă din figura 5.3:

52 CAPITOLUL 5. UTILIZAREA APLICAT ,IEI
Figura 5.3: Diagramă cu pull request-urile create ale proiectului
Interesantdeobservatpeaceastădiagramăestefaptulcăomarepartedinpullrequest-
urile create nu au fost acceptate. Asta înseamnă că un volum mare de muncă a fost irosit,
iar pe lângă asta există s ,i mult timp pierdut, timp care ar fi putut fi folosit mai eficient.
Bineînt ,eles, acest lucru este cauzat s ,i de faptul că proiectul Kafka este un proiect open
source, iar oricine poate cere anumite modificări, de aici s ,i numărul mare de pull request-
uri respinse.
De-asemenea, o mare parte din pull request-urile care sunt deschise sunt deschise de
mult timp, ceea ce înseamnă că lucrurile nu evoluează as ,a cum ar trebui. Numărul pull
request-urilor complexe este s ,i el într-o proport ,ie destul de mare, iar asta înseamnă că
au existat anumite probleme până la rezolvarea lor.
Aceste date pot fi confirmate s ,i verificând informat ,iile din fis ,ierul cu rezultate al
proiectului analizat:
Figura 5.4: Valorile analizelor obt ,inute pentru proiectul Kafka

5.3. INTERPRETAREA REZULTATELOR 53
Se poate observa în figura 5.5 numărul de pull request-uri create zilnic folosind un
calendar în care fiecare zi e colorată în funct ,ie de cât de mare este numărul:
Figura 5.5: Calendarul cu numărul de pull request-uri create
Mai mult, din rezultatele obt ,inute se pot reprezenta perioadele aglomerate în care
s-au făcut multe pull request-uri. În figura 5.6 sunt reprezentate aceste perioade:
Figura 5.6: Grafic ce prezintă perioadele aglomerate ale unui proiect
Din acest grafic se poate observa că numărul mare de pull request-uri a fost realizat
săptămânal în apropierea weekend-ului. Asta poate însemna faptul că programatorii
obis ,nuiesc să deschidă pull request-uri la sfârs ,itul unui sprint de o săptămână.

54 CAPITOLUL 5. UTILIZAREA APLICAT ,IEI
Un alt aspect interesant de observat asupra unui proiect, este ce proport ,ie din
comentarii sunt comentarii simple sau comentarii pe cod. Comentariile pe cod
arată faptul că ceva nu este în regulă s ,i mai trebuie modificat înainte de acceptare.
Câte dintre commit-uri sunt commit-uri făcute după deschiderea pull request-
urilor s ,i câte sunt cele init ,iale. La fel ca s ,i în cazul comentariilor, commit-urile
făcute după deschiderea pull request-urilor exprimă faptul că au mai apărut
modificări.
Se pot observa ce fel de modificări au apărut în fis ,iere (adăugări sau s ,tergeri).
Toate aceste date ment ,ionate mai sus pot fi observate folosind diagramele din
figura 5.7:
Figura 5.7: Diagrame cu numărul de comentarii, commit-uri s ,i modificări din fis ,iere pe
tot proiectul
În ceea ce prives ,te rezultatele analizelor realizate pe datele despre programatori se pot
trage următoarele concluzii:
Care sunt cei mai activi programatori. În acest sens se vor reprezenta în figura 5.8
numărul de comentarii, numărul de commit-uri s ,i numărul de fis ,iere modificate al
celor care sunt cei mai activi.

5.3. INTERPRETAREA REZULTATELOR 55
Figura 5.8: Diagramă cu numărul de comentarii, commit-uri s ,i fis ,iere modificate ale celor
mai activi programatori
Care sunt programatorii care au deschis cele mai multe pull request-uri, care sunt
cei care au acceptat cele mai multe pull request-uri s ,i care sunt cei care au cele mai
multe pull request-uri respinse.
Având aceste date, putem vedea care sunt programatorii care lucrează mult
pe proiect, care sunt cei care au cele mai multe cunos ,tint ,e s ,i cea mai multă
experient ,ă, respectiv care sunt cei care lucrează dar ceea ce fac ei nu este chiar
corect.
Tot ,i aces ,ti programatori pot fi observat ,i în figurile 5.9, 5.10 s ,i 5.11:

56 CAPITOLUL 5. UTILIZAREA APLICAT ,IEI
Figura 5.9: Diagramă cu programatorii care au deschis cele mai multe pull request-uri
Figura 5.10: Diagramă cu programatorii care au acceptat cele mai multe pull request-uri
Figura 5.11: Diagramă cu programatorii care au cele mai multe pull request-uri respinse

5.3. INTERPRETAREA REZULTATELOR 57
Putem evalua cât de implicat ,i, ”săritori” s ,i cât de repede răspund programatorii
atunci când apar pull request-uri noi sau comentarii pe pull request-urile lor.
În acest context, se vor prezenta doua diagrame în figurile 5.12 s ,i 5.13. Una
dintre diagrame va cont ,ine timpul mediu de react ,ie la pull request-urile cole-
gilor măsurat în ore s ,i numărul pull request-urilor la care au react ,ionat, iar
cealaltăvacont ,inetimpulmediuderăspunslacomentariipepullrequest-urile
lor măsurat în minute s ,i numărul de comentarii.
Pentru simplitate se vor exemplifica doar cei care sunt cei mai rapizi în
act ,iunile lor:
Figura 5.12: Diagramă cu timpul de react ,ie la pull request-urile colegilor măsurat în ore
Figura 5.13: Diagramă cu timpul de răspuns la comentarii măsurat în minute
Una dintre cele mai importante analize este evaluarea interact ,iunilor dintre pro-
gramatori. Aceste interact ,iuni arată cât de mult comunică programatorii între ei
s,i care sunt programatorii care interact ,ionează mai mult s ,i care sunt cei care nu
interact ,ionează.
Pentru claritate, în figura 5.14 vor fi reprezentate interact ,iunile dintre pro-
gramatorii care au lucrat pe un alt proiect mai mic de Bitbucket. Diagrama
interact ,iunilor celor de pe proiectul Kafka ar fi fost prea mare pentru a fi
reprezentată în acest exemplu.

58 CAPITOLUL 5. UTILIZAREA APLICAT ,IEI
Figura 5.14: Diagrama interact ,iunilor dintre programatori

Capitolul 6
Concluzii
Acest capitol este destinat concluziilor. Se vor sumariza informat ,iile prezentate s ,i se vor
discuta următoarele direct ,ii pe care le va lua aplicat ,ia.
6.1 Concluzii generale
Consider că Pull Request Analyzer este un instrument important în domeniul asigurării
calităt ,ii software s ,i al procesului de dezvoltare, deoarece chiar dacă nu aduce o contribut ,ie
majoră domeniului, impresionează prin simplitate s ,i important ,a rezultatelor.
Des ,i rezultatele acestor analize nu sunt suficiente pentru a evalua calitatea unui sis-
tem sau modul în care acesta evoluează, ele ne oferă un punct de vedere diferit asupra
sistemului, un punct de vedere care aduce ceva în plus fat ,ă de analizele tradit ,ionale.
Aceste analize reprezintă un set de funct ,ionalităt ,i auxiliare care integrate cu alte analize
pot aduce informat ,ii importante despre un sistem s ,i ceea ce se întâmplă în procesul de
dezvoltare al acestuia.
Pull Request Analyzer este în opinia mea, un instrument care poate anticipa soarta
unui sistem fără a avea nevoie de analizarea codului, dar în acelas ,i timp o poate schimba
oferind nis ,te rezultate importante. Prin analizarea s ,i studierea acestor rezultate, se pot
formula concluzii valide referitoare la ce ar trebui modificat pe viitor pentru ca întreg
procesul de dezvoltare să fie îmbunătăt ,it, iar evolut ,ia acestuia să fie una progresivă.
Ba chiar mai mult, dezvoltatorii care lucrează pe proiect s ,i folosesc această aplicat ,ie îs ,i
pot evalua munca s ,i progresul până la momentul curent pentru a deveni pe viitor mai
productivi s ,i mai eficient ,i.
Instrumentul de fat ,ă oferă informat ,ii legate de volumul de muncă care este depus pe
un anumit proiect, cat de eficient se lucrează, câte modificări apar pe un proiect, care
sunt programatorii cei mai activi, care sunt cei care nu aduc niciun aport, care sunt
programatorii care interact ,ionează s ,i care sunt cei care cunosc cel mai bine sistemul.
Având la îndemână aceste date, această aplicat ,ie poate fi folosită atât într-o manieră
retrospectivă, adică se poate analiza un proiect în mod repetat, în timp, iar la final
se compară rezultatele pentru a vedea dacă măsurile luate au dus la o îmbunătăt ,ire,
dar poate fi folosită s ,i personal, în timpul etapei de dezvoltare pentru a vedea dacă
programatorii interact ,ionează îndeajuns, nu apar probleme sau situat ,ii de blocaj s ,i totul
este conform planului.
59

60 CAPITOLUL 6. CONCLUZII
6.2 Direct ,ii de dezvoltare
În primul rând, această aplicat ,ie a fost gândită pentru a fi folosită tot mai mult de tot ,i
membriiuneiorganizat ,ii,începânddelaprogramatoriicarelucreazăpeunanumitproiect,
liderii echipelor, administratori s ,i până la directori. Astfel, aplicat ,ia trebuie să poată
oferi informat ,ii utile pentru fiecare categorie de utilizatori. În consecint ,ă, dezvoltarea
analizelor s ,i integrarea lor cu alte instrumente sunt inevitabile în viitorul apropiat.
În vederea dezvoltării, ca prim pas pentru Pull Request Analyzer este implementarea
s,i integrarea unor instrumente de vizualizare a datelor pe care aplicat ,ia le extrage s ,i a
rezultatelor obt ,inute. Se dores ,te astfel ca această aplicat ,ie să fie o aplicat ,ie web în care
serverul, implementat folosind Spring Boot , să se ocupe de extract ,ia de date, imple-
mentarea analizelor s ,i rularea acestora, iar interfat ,a, implementată folosind Angular , să
poată reda prin vizualizări rezultatele analizelor s ,i datele extrase. Astfel, orice utilizator
va putea să-s ,i selecteze proiectul pe care dores ,te să-l analizeze, iar pe urmă să poată vizu-
aliza direct în browser rezultatele obt ,inute. După cum s-a ment ,ionat, partea de backend
este deja implementată s ,i pregătită pentru a fi conectată cu frontend-ul, dar urmează
implementarea părt ,ii de frontend.
Al doilea pas se referă la rafinarea s ,i extinderea analizelor existente. Fiind vorba de
sisteme de versionare, pot fi extrase mult mai multe informat ,ii decât cele extrase deja sau
pot fi dezvoltate s ,i mai mult pentru a analiza în întregime un sistem. Lucrarea de fat ,ă
analizează un sistem pe baza informat ,iilor extrase din pull request-uri de pe proiecte de
GitHub sauBitbucket . Pe viitor, vor putea fi analizate s ,i proiecte de pe GitLab. De-
asemenea, analizele vor cuprinde s ,i informat ,ii extrase din alte entităt ,i decât pull requests
cum ar fiissuessauactivity events .
Un al treilea pas pentru dezvoltarea proiectului este integrarea acestuia într-un in-
strument de analiză numit DX-Platform. Instrument este dezvoltat de colegii mei de
facultate s ,i este folosit pentru a evalua calitatea sistemelor software. Acest pas are o
important ,ă deosebită, deoarece toate analizele din Pull Request Analyzer, dar s ,i din alte
instrumente de analiză vor putea fi rulate din acelas ,i loc, iar rezultatele ar fi de asemenea
păstrate în mod centralizat.
Bineînt ,eles, sunt convins că pe viitor vor apărea noi direct ,ii de dezvoltare s ,i noi idei
inovatoare care vor îmbunătăt ,i această aplicat ,ie, iar ea va fi în continuare dezvoltată în
as,a fel încât să facă fat ,ă noilor cerint ,e s ,i să se ridice la as ,teptările utilizatorilor.

Listă de figuri
1.1 Diagramă de funct ,ionare GIT (sursă : [3]) . . . . . . . . . . . . . . . . . 6
1.2 Diagramă exemplificare ramuri într-un repository (sursă : [4]) . . . . . . 7
4.1 Diagrama de funct ,ionare a Pull Request Analyzer . . . . . . . . . . . . . 25
4.2 Arhitectura generală a sistemului . . . . . . . . . . . . . . . . . . . . . . 27
4.3 Interfat ,a bazei de date H2 . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.4 Diagrama cu tabele ale bazei de date . . . . . . . . . . . . . . . . . . . . 32
4.5 Diagrama de clase a memoriei cache . . . . . . . . . . . . . . . . . . . . . 34
4.6 Modelul clasei DeveloperAnalysis . . . . . . . . . . . . . . . . . . . . . . 37
4.7 Diagrama de clase a activităt ,ilor unui programator . . . . . . . . . . . . 42
4.8 Modelul clasei PullRequestAnalysis . . . . . . . . . . . . . . . . . . . . . 43
4.9 Diagrama de clase a evenimentelor unui pull request . . . . . . . . . . . . 46
5.1 Dialogul cu prima opt ,iune a utilizatorului . . . . . . . . . . . . . . . . . 49
5.2 Dialogul cu a treia opt ,iune a utilizatorului . . . . . . . . . . . . . . . . . 50
5.3 Diagramă cu pull request-urile create ale proiectului . . . . . . . . . . . . 52
5.4 Valorile analizelor obt ,inute pentru proiectul Kafka . . . . . . . . . . . . . 52
5.5 Calendarul cu numărul de pull request-uri create . . . . . . . . . . . . . . 53
5.6 Grafic ce prezintă perioadele aglomerate ale unui proiect . . . . . . . . . 53
5.7 Diagrame cu numărul de comentarii, commit-uri s ,i modificări din fis ,iere
pe tot proiectul . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.8 Diagramă cu numărul de comentarii, commit-uri s ,i fis ,iere modificate ale
celor mai activi programatori . . . . . . . . . . . . . . . . . . . . . . . . 55
5.9 Diagramă cu programatorii care au deschis cele mai multe pull request-uri 56
5.10 Diagramă cu programatorii care au acceptat cele mai multe pull request-uri 56
5.11 Diagramă cu programatorii care au cele mai multe pull request-uri respinse 56
5.12 Diagramă cu timpul de react ,ie la pull request-urile colegilor măsurat în ore 57
5.13 Diagramă cu timpul de răspuns la comentarii măsurat în minute . . . . . 57
5.14 Diagrama interact ,iunilor dintre programatori . . . . . . . . . . . . . . . . 58
61

62 LISTĂ DE FIGURI

Bibliografie
[1] http://labs.cs.upt.ro/~oose/uploads/SQA/CES-CodeAsCrimeScene.pdf
[2] http://acs.ase.ro/Media/Default/documents/cts/SeminarZamfiroiu/GIT.pdf
[3] https://www.atlassian.com/git/tutorials/learn-git-with-bitbucket-cloud
[4] https://www.atlassian.com/git/tutorials/using-branches
[5] https://www.cs.umd.edu/~basili/publications/proceedings/P125.pdf
[6] https://www.tutorialspoint.com/java/index.htm
[7] https://spring.io/projects/spring-framework
[8] http://aipi2015.andreirosucojocaru.ro/laboratoare/laborator02
[9] https://docs.atlassian.com/bitbucket-server/rest/6.1.2/bitbucket-rest.html
[10] https://www.baeldung.com/how-to-use-resttemplate-with-basic-authentication-in-
spring
[11] https://www.d3-graph-gallery.com/index.html
63

Similar Posts