software engineering

198
Ingineria sistemelor de programe Note de curs Florin Ostafi

Upload: igor-dologan

Post on 29-Jun-2015

246 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: software engineering

Ingineria sistemelor de programe

Note de curs

Florin Ostafi

Page 2: software engineering

INTRODUCERE

Ingineria software a parcurs o cale lungă începând cu 1968, an în care acest termen a fost utilizat pentru prima oară la o conferinţă NATO. Iar de atunci software-ul a pătruns în viaţa fiecăruia dintre noi în diverse moduri, aşa cum puţini anticipaseră chiar cu un deceniu în urmă. Aşadar cunoaşterea noţiunilor de bază legate de teoria şi practica ingineriei software este esenţială pentru înţelegerea tehnicilor de construire a unui software performant şi de asemenea a metodelor de evaluare a riscurilor şi oportunităţilor pe care software-ul le oferă vieţii noastre de zi cu zi.

În anul 1946 Goldstine şi von Neumann apreciau că 1000 de instrucţiuni reprezintă o limită superioară rezonabilă pentru complexitatea problemelor ce pot fi concepute ca rezolvabile cu ajutorul calculatorului. După ce a prevăzut că nici un program pentru calculatoare personale nu va necesita vreodată mai mult de 64 KB de memorie RAM, Bill Gates a admis în 1995 că lucrurile s-au schimbat în ultimele două decenii.

Următoarele exemple oferă o imagine asupra gradului de complexitate la care au ajuns programele:

• Sistemul de rezervare a biletelor pentru compania aeriană KLM conţinea, în anul 1992, două milioane de linii de cod în limbaj de asamblare;

• Sistemul de operare System V versiunea 4.0 (UNIX) a fost obţinut prin compilarea a 3700000 linii de cod;

• Programele scrise pentru naveta spaţială NASA au circa 40 de milioane de linii de cod obiect;

• Pentru realizarea sistemului de operare IBM OS360 au fost necesari 5000 de ani-om. Pentru a contracara ceea ce se prefigura ca fiind o criză a programării, a fost propus în anul

1968 termenul de “ingineria software” (software engineering), într-un mod oarecum provocator. Se dorea ca arta programării să împrumute din rigoarea stiinţelor inginereşti pentru a putea livra programe la timp şi în mod economic. Definiţii: IEEE Standard Glossary of Software Engineering Terminology (1990, 1991)

Aplicarea unei abordări sistematice, disciplinate, cuantificabile la realizarea, operarea şi întreţinerea software-ului.

Fritz Bauer (1968) Stabilirea şi utilizarea unor principii inginereşti în scopul realizării în mod economic

produse software fiabile care funcţionează eficient pe maşini reale.

Morven Gentlemen (1990) Utilizarea metodologiilor , instrumentelor şi tehnicilor de rezolvare a problemelor practice

care apar în construcţia , instalarea , întreţinerea şi evoluţia produselor software.

Stephen Schach (1990) O disciplină având drept obiectiv producţia unui software de calitate, livrat la termen, cu

respectarea bugetului şi care satisface cerinţele stabilite.

Boehm (1979) Aplicarea practică a cunoştinţelor ştiinţifice în proiectarea şi construcţia programelor şi a

documentaţiei asociate necesare pentru dezvoltarea, operarea şi întreţinerii acestora.

Dennis (1975) Ingineria software este aplicarea principiilor, aptitudinilor şi arta proiectării si construcţiei

programelor şi sistemelor de programe.

Page 3: software engineering

Fairley (1985) Ingineria software este disciplina tehnică şi managerială având ca obiect producţia

sistematică şi întreţinerea produselor informatice care sunt realizate şi modificate în timp în condiţii economice.

O definiţie cuprinzătoare a fost prezentată de Bruegge şi Dutoit în Object-Oriented Software Engineering [2000] conform căreia Ingineria software este:

activitate de modelare - probleme complexe sunt tratate prin modelare, atenţia fiind concentrată asupra detaliilor semnificative si ignorând restul.

• modelul - o abstractizare a realităţii

• analiza - construcţia unui model al domeniului problemei

• proiectarea - construirea unui model pentru domeniul soluţiei

În metodele OO, modelul domeniului soluţiei este o extensie a modelului domeniului problemei, astfel încât structura software-ului reflectă structura problemei.

activitate de rezolvare a problemelor - modelele folosite pentru a căuta o soluţie acceptabilă sunt:

• efectuarea de experimente

• reutilizarea unor soluţii model (reuses pattern solutions)

• evoluţia incrementală a sistemului spre o variantă acceptată de client

• revizuirea răspunsului la schimbări

activitate de achiziţionare de informaţie-în modelare aplicaţiei şi a domeniului soluţiei, se colectează datele, se organizează in informaţii şi se formalizează în cunoştinţe. Această activitate este neliniară în sensul că achiziţia de noi informaţii poate invalida cunoştinţele precedente şi se caracterizează prin:

• dezvoltare bazata pe risc - identificarea componentelor cu risc mare pentru a evita surprizele ulterioare

• dezvoltare pe probleme (issue-based development) - execuţia in paralel a activităţilor de dezvoltare, organizarea făcându-se ţinând cont de problemele care sunt încă nerezolvate

• dezvoltare iterativa – proiectarea si implementarea la început a părţilor cu risc ridicat (dificile)

activitate raţională-logică – realizatorii de software trebuie să înţeleagă contextul în care au

fost luate deciziile şi logica ce stă in spatele lor pentru a înţelege implicaţiile unei schimbări propuse atunci când decizia este reanalizată; utilă în cazul unor sisteme care să schimbă în mod frecvent precum şi utilă in etapa de întreţinere

Clasificarea aplicaţiilor software

• Sisteme de operare şi software de sistem • Software timp real – restricţii timp de răspuns • Sisteme informatice – baze de date • Software ştiinţific • Software inclus (ascensoare, telefoane, aparatură casnică)

Page 4: software engineering

Anthony Wasserman identifică opt noţiuni fundamentale ce formează baza operativă a disciplinei Ingineria sistemelor software: 1. Abstractizarea – o descriere a problemei la un anumit nivel de generalizare ce ne permite să ne concentrăm atenţia asupra aspectelor cheie ale problemei fără a ne pierde în detalii.

2. Metode şi Notaţii în proiectare şi analiză - când se lucrează în echipă, comunicarea între membrii echipei şi documentarea în procesul de dezvoltare face necesară stabilirea unui sistem de notaţie comun.

3. Prototipizare - construirea unei versiuni miniaturale a sistemului, de obicei cu funcţionalitate limitată, care ajută utilizatorul să identifice cerinţele esenţiale ale sistemului şi demonstrează fezabilitatea unui anumit mod de abordare/proiectare; utilizată în special pentru proiectarea interfeţelor utilizator.

4. Arhitectura sistemului (software) - descrierea sistemului ca o mulţime de unităţi arhitecturale şi stabilirea legăturilor între unităţi.

5. Procesul software – organizarea şi disciplina în activităţile ce se desfăşoară în timpul procesului de dezvoltarea software-ului contribuie la calitatea software-ului şi rapiditatea cu care este dezvoltat.

6. Refolosirea - evidenţierea părţilor comune cu alte aplicaţii şi refolosirea unor componente dezvoltate anterior.

7. Măsurători - descrierea cantitativă a îmbunătăţirii proceselor, resurselor şi metodelor permite compararea progresului intre proiecte disparate şi ajută la analiza şi luarea deciziilor.

8. Instrumente şi Mediu integrat (Tools and Integrated Environment) –instrumentele CASE (computer-aided software engineering) sunt proiectate pentru a spori dezvoltarea soft-ului dar rareori se adresează unui ciclu întreg de dezvoltare a software-ului Complexitatea sistemelor software derivă din 4 elemente: 1) complexitatea domeniului problemei.

Problemele care cer o rezolvare software sunt deosebit de complexe, începând chiar cu specificaţiile care pot fi contradictorii (ex: specificaţiile pentru construirea unui robot). Funcţionalitatea acestor sisteme este suficient de greu de înţeles şi la aceasta se mai adaugă şi cerinţele nefuncţionale pe care trebuie să le îndeplinească sistemul: performanţă, utilitate, fiabilitate, cost, etc.

Această complexitate provine şi din neînţelegerile care există între proiectanţii sistemului şi utilizatorii săi: utilizatorii, de obicei, nu-şi pot exprima clar cerinţele într-o formă pe care proiectanţii să o înţeleagă. Uneori, ei au doar o vagă idee despre ceea ce doresc de la un sistem. Practic, aceste probleme apar deoarece fiecărui grup îi lipsesc cunoştinţele despre domeniul celuilalt grup.

Utilizatorii şi proiectanţii au perspective diferite de a vedea soluţia problemei. Chiar şi atunci când utilizatorii ştiu ceea ce doresc, lipsesc instrumentele pentru extragerea precisă a cerinţelor lor. Calea obişnuită prin care aceste specificaţii sunt exprimate constă în a scrie mult text, incluzând ocazional şi diverse figuri. Dar aceste documente sunt greu de înţeles, sunt deschise la diverse interpretări, şi deseori, conţin elemente care sunt mai degrabă de proiectare decât de specificaţiile esenţiale ale problemei.

Complicaţii mai mari apar atunci când specificaţiile sistemului se modifică în timpul dezvoltării lui. Sistemele mari tind să evolueze de-a lungul timpului, o condiţie ce impropriu este denumită “întreţinere”. Mai precis, întreţinerea înseamnă corectarea erorilor. Evoluţia înseamnă

Page 5: software engineering

modificarea cerinţelor şi menţinerea înseamnă folosirea unor mijloace extraordinare de a păstra în utilizare un sistem vechi şi depăşit. 2) dificultatea de a administra procesul de dezvoltare

Scopul principal al echipei de software e de a construi iluzia simplităţii, de a feri utilizatorul de vasta complexitate a problemei. Volumul mare de muncă determină folosirea unei echipe de dezvoltare a softului. Mai mulţi membri în echipă înseamnă o mai complexă comunicare între ei, deci o coordonare mai dificilă, mai ales atunci când echipa este dispersată geografic. Într-o echipă de dezvoltare, cheia coordonării e de a menţine mereu unitatea şi integritatea proiectului. 3) flexibilitatea sistemului

Sistemul software va trebui să fie flexibil. Acest lucru îl forţează pe proiectant de a dezvolta

blocurile primitive din care va construi apoi abstractizările de la nivelele superioare. În timp ce domeniul construcţiilor industriale oferă standarde pentru calitatea materialelor, puţine astfel de standarde există în software-ul industrial. Ca urmare, dezvoltarea softului rămâne o muncă intens laborioasă. 4) problemele de caracterizare a comportării sistemelor discrete

În aplicaţiile foarte mari, pot exista sute sau mii de variabile. Colecţia de variabile, valorile lor, adresele lor şi stiva de apeluri ale fiecărui proces din sistem, reprezintă starea curentă a sistemului la un moment dat. Sistemele discrete (care nu pot fi descrise prin funcţii continue), prin natura lor, au un număr finit de stări posibile. În marile sisteme, acest număr este imens. De aceea, se încearcă proiectarea părţilor de sistem astfel încât comportarea uneia să aibă impact minim asupra celorlalte. Totuşi, orice eveniment extern sistemului soft îl poate plasa într-o nouă stare, şi, mai mult, maparea de la o stare la alta nu e întotdeauna deterministă. În cele mai rele cazuri, un eveniment extern poate corupe starea sistemului pentru că proiectanţii au uitat să considere anumite interacţiuni dintre evenimente (ex: sistemul computerizat, comun pentru cabina de comandă şi cabina pasagerilor, într-un avion ).

Deoarece nu avem nici instrumentele matematice şi nici capacitatea intelectuală de a modela complet comportarea marilor sisteme discrete, trebuie să ne rezumăm la acceptarea unui nivel acceptabil de încredere în corectitudinea lor, dovedită în timpul testărilor atente.

Referitor la factorul uman în procesul de dezvoltare a softului, acesta trebuie să ia în consideraţie foarte multe detalii în acelaşi timp. Experienţe psihologice au arătat că un individ poate înţelege simultan 7 ± 2 unităţi de informaţii şi că există o limitare a vitezei de procesare a creierului la 5 secunde pentru acceptarea unei noi informaţii. Şi atunci apare următoarea problemă: complexitatea softului ce ni se cere să-l proiectăm creşte dar factorul uman prezintă incapacităţi serioase de a face faţă acestei probleme. Sugestia lui Dijkstra este: “Tehnica de a stăpâni complexitatea este ştiută din antichitate: divide şi cucereşte ”. În proiectarea unui sistem, este esenţială descompunerea lui în subsisteme din ce în ce mai mici, fiecare din ele putând fi construit independent. În felul acesta este rezolvată şi constrângerea impusă de capacitatea umană de cunoaştere: pentru a înţelege un anumit nivel al unui sistem e nevoie de a înţelege numai câteva părţi în acelaşi timp.

Page 6: software engineering

Ciclul de viată al unui produs software

Produsul software este un produs similar oricărui alt produs. El are atribute fizice ca orice alt produs fizic, şi deci, el are o "viaţă" similară cu cea a altor produse. De aceea, produsul software poate fi privit din punctul de vedere al unui ciclu de viaţă, acesta reprezentând toate fazele din cursul procesului de dezvoltare a unui sistem software, începând de la conceperea sistemului şi până la retragerea sa din folosinţă.

Fazele clasice în procesul de dezvoltare sunt: • definirea cerinţelor utilizatorilor

• definirea specificaţiilor software

• programarea sistemului

• implementarea

• testarea

• documentarea

Problemele ingineriei software Satisfacerea cerinţelor clienţilor. Problema fundamentală a ingineriei software este îndeplinirea cerinţelor clientului. Aceasta trebuie realizată nu punctual, nu în acest moment, ci într-un mod flexibil şi pe termen lung. Ingineria software se ocupă cu toate etapele dezvoltării programelor, de la extragerea cerinţelor de la client până la întreţinerea şi retragerea din folosinţă a produsului livrat. Pe lângă cerinţele funcţionale, clientul doreşte (de obicei) ca produsul final să fie realizat cu costuri de producţie cât mai mici. De asemenea, este dezirabil ca aceasta să aibă performanţa cât mai bună (uneori direct evaluabilă), un cost de întreţinere cât mai mic, să fie livrat la timp, şi să fie sigur.

Prezentăm în continuare o statistică privind gradul de satisfacere a cerinţelor pentru proiecte software mari. Aceasta pare să justifice orice disciplină a muncii care să îmbunătăţească aceste cifre.

Figura 1. Gradul de satisfacere a cerinţelor pentru proiecte software mari

45%

25%

20%

5%5%

livrate dar nefolosite

plătite dar nelivrate

abandonate sau refăcute

folosite după modif icări

folosite aşa cum au fost livrate

Nerespectarea cerinţelor poate avea efecte serioase. Un sistem de livrare a insulinei pentru

diabetici poate provoca moartea pacientului dacă nu funcţionează corect. Funcţionarea incorectă a unui sistem de control al unui satelit poate provoca pagube de milioane de dolari.

Un program este sigur dacă funcţionează şi continuă să funcţioneze fără întreruperi şi fără a efectua operaţii nedorite. Un program are o greşeală (bug) dacă nu se comportă corect. Se presupune că dezvoltatorul ştia ce ar fi trebuit programul să facă, iar comportamentul greşit nu este intenţionat.

Page 7: software engineering

Costul produsului. Cheltuielile pentru producerea sistemelor software sunt imense. Se apreciază că ele au depăşit suma de 140 bilioane $ la nivelul anului 1985 şi urmau să crească de atunci cu 12% pe an. Costul este influenţat de cerinţele impuse pentru funcţionarea acestuia (exemplu: necesitatea de a se executa în timp real - timpul tipic de răspuns este de ordinul microsecundelor). De asemenea, timpul mare de viaţă şi frecventele modificări cerute pentru menţinerea sistemului sau pentru adăugarea unor noi facilităţi vor mări costurile generale. Se estimează că cel mai mare volum al cheltuielilor (60%-80%) se înregistrează în cazul întreţinerii softului. Totodată, cu cât produsul soft este mai complex, mai mare, cu atât costurile totale vor creşte.

Figura 2 se bazează pe un număr de studii care demonstrează distribuţia tipică a timpului consumat pentru crearea unui sistem software.

Figura 2: Distribuţia efortului pentru obţinerea produsului soft

40%

5%35%

20%

Testare

Analiză

Proiectare

Implementare

După cum se vede, cel mai mult timp e dedicat proiectării şi implementării sistemului.

Figura 3: Erori tipice în produsul soft

36%

64%

erori de implemetare

erori de specif icare şi analiză

Alte studii au arătat că cerinţele, specificaţiile şi analiza produsului determină cele mai

multe erori în sistem (64% faţă de 36%) (Figura 3). Mai mult, aceste erori nu sunt descoperite de către cei care dezvoltă sistemul ci de către cei care le testează şi/sau de către utilizatori. Cu cât aceste erori sunt evidenţiate mai târziu, cu atât ele implică un mai mare volum de muncă şi cost. Cel mai mare efort este concentrat în faza de dezvoltare a ciclului de viaţă al produsului deşi cea mai mare rată de întoarcere o prezintă fazele anterioare acestui punct (cerinţele, specificaţiile sistemului, analiza).

Page 8: software engineering

Varietatea din practică se referă la faptul că există multe tehnici pentru producerea sistemelor software. Ca rezultat, ele sunt dificil de coordonat, variază mult în ceea ce priveşte costul, flexibilitatea şi întreţinerea lor. Şi totuşi există sute de tehnici, automate sau nu, menite să ajute la coordonarea, dezvoltarea sau întreţinerea sistemelor software. O firească întrebare care se pune este dacă vreuna din aceste tehnici chiar merge. Studiile realizate au arătat că aplicarea acestor tehnici au determinat scăderea costurilor şi obţinerea unor sisteme mai flexibile. În realitate, problema este că prea puţini le folosesc. Este uimitor cât de puţin este folosită tehnologia ingineriei software în realitate. Se pare că ori nimeni nu citeşte aceste studii, ori nu există interes de a le folosi acolo unde ele ar putea aduce cele mai mari beneficii. În primul rând, nimeni nu crede că aplicarea unor tehnici de ingineria programării, şi în special a celor automate, ar salva într-adevăr nişte bani În al doilea rând, eforturile pentru cercetarea, dezvoltarea şi aplicarea acestor tehnici sunt fragmentare. Există multe tehnici, dar ele sunt unice în general, nu pot fi folosite împreună cu alte tehnici, sau nu merg pentru probleme reale. O altă problemă este lipsa de consistenţă: nu există un vocabular general acceptat în domeniul ingineriei programării. Nu există nici un proces sau model unic, general acceptat, de dezvoltare a sistemelor software. Fiecare companie are modul său propriu de a produce sisteme software. Lipsa productivităţii. În domeniul ingineriei software, termenul de productivitate este încă nebulos. Ea ar putea însemna:

• un volum mai mare de cod scris de către o persoană

• micşorarea costului produsului soft

• creşterea calităţii produsului Probabil, productivitatea ar trebui văzută ca o sumă a tuturor acestor factori. Studiile efectuate asupra acestui subiect au arătat că productivitatea depinde de 30 variabile (pregătirea personalului, complexitatea produsului, cerinţele produsului, timpul de predare, utilitarele folosite pentru producerea softului, calitatea managementului, limbajul de programare utilizat ). În general, există o slabă productivitate în producerea sistemelor software datorită lipsei de personal pregătit pentru aceasta şi datorită cererii crescânde de produse soft.

Un alt motiv pentru care problema productivităţii nu e uşor de rezolvat e “pluralitatea scopurilor”. Nu există nici un beneficiu dacă personalul a fost suficient de pregătit ca să predea produsul la timp dar acesta este atât de slab ca performanţă încât e inutilizabil sau dacă va fi nevoie de mult mai mulţi bani pentru a-l putea face să meargă. Un proiect software îşi propune de multe ori scopuri contradictorii: este dificil de a realiza un produs flexibil, eficient, utilizabil, extensibil, modificabil, etc. simultan (in unele sisteme, o mai mare siguranţă a acestuia înseamnă mai multe verificări care determină un timp mai mare de execuţie sau poate însemna o proiectare mai flexibilă a sistemului. Acestea pot mări costul produsului, timpul de producere şi pot face sistemul mai greu de întreţinut.) O notă finală: un studiu interesant efectuat de Bell Laboratories a arătat că doar aproximativ 13% din timpul unui programator este investit în programare. S-a estimat că 33% din timpul său e dedicat scrierii documentaţiei. Dacă se pune deci problema creşterii productivităţii, acesta ar putea fi un punct demn de luat in consideraţie. In capitolele următoare se va examina o abordare a problemelor cu care se confruntă azi domeniul ingineriei programării, prin utilizarea mediilor de dezvoltare a sistemelor software. Se speră ca prin aceasta să se reducă varietatea practicilor, să se crească productivitatea şi, în final, să se micşoreze costul produsului. Până în prezent s-au făcut paşi importanţi în tehnologia ingineriei software pe toate fronturile: analiza cerinţelor produsului, strategiile de implementare, modelele de cost, etc. Fiecare

Page 9: software engineering

din acestea urmăreşte să reducă din: costul ridicat al softului, variaţia din practică şi lipsa productivităţii.

Totuşi, după mai bine de 20 ani “criza softului” nu este rezolvată. Cererea pentru producerea sistemelor software creşte mai repede decât productivitatea realizării lui. Greşeli care se făceau în anii 70’ se repetă în continuare. Incapacitatea noastră de a stăpâni complexitatea unui sistem rezultă în întârzierea proiectului, depăşirea cheltuielilor şi deficienţe în ceea ce priveşte îndeplinirea specificaţiilor sistemului. E nevoie de utilitare mai bune, de tehnici şi metode mai bune, şi, ceea ce este cel mai important, e nevoie de educaţie şi antrenare în acest scop.

Principalele soluţii abordate pentru rezolvarea “crizei software-ului”

S-au pus în evidenţă câteva probleme majore privind dezvoltarea ingineriei programării: costul ridicat al softului, varietatea din practică şi lipsa de productivitate. De asemenea, prăpastia dintre potenţialul echipamentelor hardware şi performanţele sistemelor software devine din ce în ce mai mare. Acest potenţial pierdut afectează cel mai mult marile organizaţii care sunt dependente de sisteme software foarte complexe. Mai rău decât atât, aceste sisteme sunt defectuoase şi structurate atât de rigid încât nu permit modificări majore ulterioare fără reproiectarea lor. Câteva din neajunsurile practicilor curente în procesul de dezvoltare a sistemelor software sunt:

• realizarea unor specificaţii inconsistente, incoerente şi incomplete

• realizarea unor sisteme nereutilizabile

• responsabilităţi şi îndatoriri slab definite şi controlate

• slabe performanţe ale produsului final

• inexistenţa unei metrici pentru testarea calităţii sistemului

• nici un mijloc pentru a coordona complexitatea

• documentaţie care nu oferă nici un ajutor efectiv

• etc.

Rezumăm în continuare principalele eforturi care s-au făcut în direcţia obţinerii unui sistem software robust, care îndeplineşte toate cerinţele utilizatorilor. 1. Programarea monolitică. Programele mici pot fi construite în stil monolitic, ca o singură procedură sau un set de instrucţiuni. De obicei, ele sunt scrise de un singur programator, care poate cuprinde mental întreaga imagine a procedurii. Sistemele mari, însă, nu pot fi realizate în acest fel. Cu cât sistemul e mai complex, cu atât vor fi necesare echipe mai mari iar volumul de comunicări între membrii echipei va creşte corespunzător. 2. Programarea modulară. Principiul pe care se bazează este de a împărţi programele în componente mai mici, ce pot fi construite independent. Acesta e modul de lucru folosit în ultimii 40 ani. Suportul elementar pentru programarea modulară îl reprezintă subrutina, concept introdus în 1950. 3. Programarea structurată. În anii ’60 s-au făcut eforturi mari în direcţia dezvoltării unui stil de programare mai disciplinat, mai consistent, concretizându-se într-o manieră “top-down” de proiectare a programelor. Ea se bazează pe principiul descompunerii funcţionale, în virtutea căreia sistemul e văzut ca un set de sub-sisteme, fiecare sub-sistem fiind la rândul său descompus după acelaşi principiu. Programarea structurată a adus îmbunătăţiri semnificative în calitatea software-

Page 10: software engineering

ului în ultimii 20 de ani. O problemă serioasă însă este că nu întotdeauna este posibilă anticiparea proiectului sistemului complet, înainte de implementare, şi în cazul unei erori, întregul proiect trebuie revizuit în aceeaşi manieră top-down. 4. CASE- Computer-Aided Software Engineering

Ultima inovaţie în programarea structurată este ingineria software asistată de calculator. Cu ajutorul mediilor CASE se coordonează procesul de descompunere funcţională, definind grafic diagrame înlănţuite şi verificând că toate interacţiunile sistemului reflectă regulile impuse.

Sistemele avansate CASE pot realiza un sistem complet din diagramele proiectate şi din toate informaţiile asociate lor. Totuşi, acest proces nu e chiar atât de automatizat cum pare la prima vedere. Practic, CASE traduce proiectul unui sistem din formă grafică într-o formă textuală. Experienţa de până azi arătat că dezvoltarea unui proiect complet, grafic, poate fi la fel de costisitor din punct de vedere al timpului ca şi programarea lui. 5. Limbajele de generaţia a IV-a (4GL) reprezintă o altă abordare a programării automate. Ele includ o gamă largă de utilitare pentru automatizarea unor aplicaţii de rutină (crearea de menuri, generarea de rapoarte, etc.). Au avantajul că pot fi folosite şi de ne-programatori. Nu pot fi folosite pentru sisteme mari şi pentru menţinerea programelor modificate 6. Abordarea orientată-obiect

Analiza orientată obiect este o metodă relativ nouă, de analiză bazată pe obiecte şi clase. Un obiect este o entitate, o încapsulare a unor valori de atribute şi a unui set de operaţii acţionând asupra acestora. O clasă este o descriere a unui set de obiecte cu atribuţii şi servicii comune. Medii pentru dezvoltarea sistemelor software (Software Development Environments)

Un mediu pentru dezvoltarea sistemelor software este o colecţie de utilitare software şi hardware pentru producţia de sisteme software într-un domeniu specific. Există trei tipuri de astfel de medii:

• medii de programare - pentru programare, testare, depanarea programelor;

• medii CASE - orientate spre fazele de definire a specificaţiilor software şi a proiectării sistemelor;

• medii de inginerie software - dedicate producţiei de sisteme software complexe, cu un ciclu îndelungat de viaţă, a căror întreţinere costă mai mult decât dezvoltarea lor şi care sunt produse de echipe şi nu de programatori individuali;

Acestea furnizează suportul pentru toate activităţile de dezvoltare şi de management. În

practică, graniţele dintre aceste tipuri nu sunt bine delimitate. Mediile CASE - sunt destinate diferitelor fazelor din dezvoltarea sistemelor. Aceste medii sunt orientate spre un suport grafic care e folosit în diverse metode de proiectare. Ele pot suporta fie o singură metodă, fie o gamă de câteva din cele mai cunoscute metode. Componentele tipice într-un mediu CASE sunt:

• un sistem de editare a diagramelor pentru crearea diagramelor fluxurilor de date, a hărţilor de structură, a diagramelor de tip entitate-relaţie (entity-relationship), a dicţionarelor de date, a arborilor de decizie, etc.; informaţiile despre aceste identităţi sunt înregistrate într-o bază de date centrală (enciclopedie);

Page 11: software engineering

• facilităţi de analiză şi verificare în timpul creării diagramelor;

• facilităţi ce permit utilizatorului de a regăsi informaţiile;

• dicţionarul de date, conţinând informaţii despre entităţile folosite în proiectul sistemului;

• facilităţi de generare a rapoartelor care folosesc informaţiile din baza centrală de date şi generează documentaţia sistemului;

• utilitare de generare a formatelor ecran şi document;

• facilităţi import-export pentru schimbul de informaţii dintre baza centrală de date şi alte utilitare de dezvoltare;

• unele medii CASE suportă generatoare de cod pe baza informaţiilor de proiectare înregistrate în dicţionarul de date.

Unele din criticile care au fost aduse acestor medii sunt următoarele:

• nu există o standardizare care să facă informaţia interschimbabilă dintre diverse medii CASE;

• nu există facilităţi care să permită utilizatorului să modifice regulile implicite ale metodei pe care mediul o suportă, şi să o adapteze problemei sale specifice;

• nu sunt facilităţi suficiente pentru crearea unei documentaţii de calitate;

• facilităţile oferite pentru realizarea diagramelor determină o greoaie creare a acestora (diagrame nu foarte complicate pot necesita câteva ore de lucru); este necesar un mod automatizat de creare şi aranjare a diagramelor, dat fiind un text de intrare;

• suportul pentru specificaţiile formale este sărac;

• suportul pentru proiectarea orientată-obiect este sărac; de aceea, avantajele productivităţii şi scăderii costului sistemelor soft prin folosirea unor tehnici ca analiza orientată obiect sunt negate cel puţin datorită unor utilitare inadecvate.

Unele din aceste deficienţe au fost deja remediate. În prezent, mediile CASE sunt valabile

pentru IBM-PC sau pentru sisteme UNIX Unele medii permit transferul de date de la şi spre alte aplicaţii şi pot genera documente de

calitate PostScript. În continuare e dificilă transferarea informaţiilor din baza centrală de date a unui mediu CASE către altul, ceea ce obligă păstrarea mediului cu care a fost construit un sistem pentru a putea continua întreţinerea acestuia.

O deficienţă serioasă a mediilor CASE, din punct de vedere al ingineriei sistemelor software pe scară largă, este dificultatea integrării lor cu sistemele de coordonare al configuraţiei (“configuration management system”). Sistemele foarte mari au un ciclu de viaţă îndelungat, ca urmare ele se pot modifica mereu, existând în versiuni diferite. Sistemul pentru coordonarea configuraţiei permite regăsirea unei anumite versiuni, permite construirea unui sistem din componente şi menţine legăturile dintre aceste componente şi documentaţia lor. Mediile CASE furnizează facilităţi pentru proiectarea sistemului software dar aceste proiecte nu sunt automat legate de codul sursă rezultat şi documentaţia utilizatorului. Ca urmare, multiplele versiuni ale unui sistem nu pot fi uşor coordonate.

Avantajele mediilor CASE: • cu toate că experienţa în folosirea acestor medii nu e foarte îndelungată, unii utilizatori

au declarat o reducere a timpului necesar în dezvoltarea sistemului şi o creştere a productivităţii;

• documentaţia este actualizată după orice modificare în proiectul şi codul sistemului;

Page 12: software engineering

• modificările sunt mai uşor de realizat; o modificare a cerinţelor utilizatorilor determină o modificare simplă în codul sursă, prin folosirea acestor medii;

• activitatea de întreţinere este mult simplificată, deoarece documentaţia este realizată odată cu dezvoltarea sistemului şi datorită unei abordări disciplinate pentru dezvoltarea sistemului;

• oferă un limbaj comun tuturor celor implicaţi în proiect.

Pe măsură ce standardele pentru construirea acestor medii sunt definitivate şi publicate, mediile CASE vor evolua spre mediile ingineriei software. Mediile de inginerie software - sunt colecţii de utilitare software care acţionează într-un mod integrat. Caracteristicile mediului de inginerie software:

• Facilităţile mediului sunt integrate. Toate utilitarele sunt interfaţate cu un sistem de management al obiectelor (OMS), astfel încât ieşirea unui utilitar reprezintă intrarea în altul.

• Posibilitatea coordonării mai multor versiuni ale aceluiaşi sistem software. Toate produsele rezultate în cursul procesului de dezvoltare pot face subiectul managementului de configuraţie (care asigură asocierea corectă a tuturor documentelor-specificaţii, proiect, cod, documentaţia utilizatorului, etc. - corespunzătoare unei versiuni, completitudinea şi consistenţa lor).

• Furnizează facilităţi pentru suportarea tuturor activităţilor de dezvoltare software (specificarea, proiectarea, implementarea, testarea, documentarea, depanarea, etc.).

Concluzii Se pare că un mediu pentru dezvoltarea sistemelor este mai util în perioada următoare finalizării şi predării sistemului, perioadă care reprezintă 80% din cheltuielile totale ale sistemului şi 90% din ciclul de viaţă al acestuia.

Folosirea mediilor de dezvoltare a sistemelor software pot ajuta în mare măsură la rezolvarea problemelor cu care se confruntă procesul de realizare a produselor software. După o perioadă de timp, cheltuielile pentru producerea sistemelor vor scădea iar calitatea produselor software va fi îmbunătăţită.

Ele nu reprezintă totuşi un panaceu pentru această problemă. Mediile de dezvoltare nu pot înlocui gândirea, nu pot garanta o coordonare eficientă a proiectului, nu pot înlocui fireştile erori umane, nu pot garanta că ştim ceea ce dorim să facem, etc.

Page 13: software engineering

Cap. 1

Modele de dezvoltare a programelor

Pentru dezvoltarea unui program avem nevoie de:

• înţelegerea clară a cerinţelor;

• un set de metode şi instrumente de lucru;

• un plan de acţiune.

Planul de acţiune se numeşte model de dezvoltare. Dezvoltarea unui anumit program constă într-un set de paşi ce se fac pentru a-l realiza. Luând în considerare tipul paşilor ce se efectuează se creează un model de lucru, ce poate fi aplicat unei serii mai largi de proiecte. Acesta este motivul pentru care planul de acţiune este numit model: el poate fi privit ca un şablon al dezvoltării de programe.

Există o serie largă de modele de dezvoltare:

• ad-hoc (do-it-yourself)

• cascadă (waterfall)

• prototipizare

• metode formale

• spirală

• RUP (Rational Unified Process)

• XP (Extreme Programming)

1.1 Etapele dezvoltării programelor

În timpul dezvoltării programelor s-a constatat că există anumite tipuri de activităţi care trebuie făcute la un moment dat:

• analiza cerinţelor

• proiectarea arhitecturală

• proiectarea detaliată

• scrierea codului

• integrarea componentelor

• validare

• verificare

• întreţinere

Page 14: software engineering

Analiza cerinţelor. Se stabileşte ce anume vrea clientul ca programul să facă. Scopul este înregistrarea cerinţelor într-o manieră cât mai clară şi mai fidelă. Claritatea se referă la lipsa ambiguităţii iar fidelitatea la înregistrarea cât mai exactă (posibil cuvânt cu cuvânt).

Proiectarea arhitecturală. Din motive de complexitate, programele mari nu pot fi

concepute şi implementate ca o singură bucată. Programul va trebui construit aşadar din module sau componente. Proiectarea arhitecturală împarte sistemul într-un număr de module mai mici şi mai simple, care pot fi abordate individual.

Proiectarea detaliată. Se realizează proiectarea fiecărui modul al aplicaţiei, în cele mai

mici detalii.

Scrierea codului. Proiectul detaliat este transpus într-un limbaj de programare. În mod tipic, aceasta se realizează modular, pe structura rezultată la proiectarea arhitecturală.

Integrarea componentelor. Modulele programului sunt combinate în produsul final.

Rezultatul este sistemul complet.

Modelul big-bang. În acest model, componentele sunt dezvoltate şi testate individual. Apoi ele sunt integrate în sistemul final. Având în vedere că funcţionarea corectă a componentelor individuale a fost testată, integrarea ar trebui să fie o formalitate. Din păcate, componentele nu pot fi testate exhaustiv, iar când acestea lucrează împreună pot să apară situaţii pe care o anumită componentă nu le-a întâlnit în procesul de testare sau conflicte între anumite componente (de exemplu, conflicte de partajare a resurselor). S-a constatat că atunci când se aplică acest model, timpul de testare explodează, proiectul devenind greu de controlat. Aceasta justifică denumirea de ’big-bang’.

Modelul incremental. Acest model propune crearea unui nucleu al aplicaţiei şi integrarea a câte o componentă la un moment dat, urmată imediat de testarea sistemului obţinut. Astfel, se poate determina mai uşor unde anume apare o problema în sistem. Acest tip de integrare oferă de obicei rezultate mai bune decât modelul big-bang.

Validare. În procesul de validare ne asigurăm că programul îndeplineşte cerinţele

utilizatorului. Întrebarea la care răspundem este: construim produsul corect (Are we building the right product)? Un exemplu de validare este testul de acceptare, în care produsul este prezentat clientului. Clientul spune dacă este mulţumit cu produsul sau dacă mai trebuie efectuate modificări.

Verificare. În procesul de verificare ne asigurăm că programul este stabil şi că

funcţionează corect din punctul de vedere al dezvoltatorilor. Întrebarea la care răspundem este: construim corect produsul (Are we building the product right)?

Întreţinere. După ce programul este livrat clientului, mai devreme sau mai târziu sunt

descoperite defecte sau erori ce trebuie reparate. De asemenea, pot apărea schimbări în specificaţiile utilizatorilor, care vor diverse îmbunătăţiri. Întreţinerea constă în gestionarea acestor probleme.

Page 15: software engineering

1.2 Modelul cascadă (waterfall)

Modelul cascadă defineşte următorii paşi în dezvoltarea unui program:

• Specificarea cerinţelor

• Proiectarea arhitecturală

• Proiectarea detaliată

• Scrierea codului

• Testarea componentelor

• Testarea sistemului

• Acceptarea proiectului

Nu se stipulează cum se fac aceşti paşi (metodologie, notaţii), ci doar ordinea efectuării lor. Avantajul metodei de dezvoltare în cascadă este acela că o sarcină complexă este împărţită în mai mulţi paşi mici, ce sunt mai uşor de administrat. Fiecare pas are ca rezultat un produs bine definit (documente de specificaţie, model, etc.)

Figura 1.1: Modelul de dezvoltare în cascadă

Ingineria cerinţelor

Proiectarea arhitecturală

Proiectarea detaliată

Implementare

Testarea unităţilor

Testarea sistemului

Acceptarea proiectului

Page 16: software engineering

1.3 Modelul cascadă cu întoarcere

Unul din dezavantajele modelului cascadă este că într-un anume stadiu al dezvoltării nu se

poate influenţa rezultatul obţinut într-un stadiu precedent pentru a se remedia o problema găsită. De exemplu, la testare se poate descoperi o eroare de proiectare.

Modelul cascadă cu feedback propune remedierea problemelor descoperite în pasul precedent. Problemele la pasul i care sunt descoperite la pasul i+3 rămân însă neremediabile. Un model realist ar trebui să ofere posibilitatea ca de la un anumit nivel să se poată reveni la oricare dintre nivelele anterioare.

Dezavantajul principal al modelului în cascadă este acela că un client obţine o viziune practică asupra produsului doar în momentul terminării procesului de dezvoltare.

Figura 1.2: Modelul de dezvoltare în cascadă cu întoarcere

Ingineria cerinţelor

Proiectarea arhitecturală

Proiectarea detaliată

Implementare

Testarea unităţilor

Testarea sistemului

Acceptarea proiectului

Page 17: software engineering

1.4 Prototipizarea

O problemă generală care apare la dezvoltarea unui program este să ne asigurăm că utilizatorul obţine exact ceea ce vrea. Prototipizarea vine în sprijinul rezolvării acestei probleme. Încă din primele faze ale dezvoltării, clientului i se prezintă o versiune funcţionala a sistemului. Această versiune nu este întregul sistem, însă este o parte a sistemului care cel puţin funcţionează.

Prototipul ajută clientul în a-şi defini mai bine cerinţele şi priorităţile. Prin intermediul unui prototip el poate înţelege ce este posibil şi ce nu din punct de vedere tehnologic. Prototipul, este de obicei produs cât mai repede; pe cale de consecinţă, stilul de programare este de obicei (cel puţin) neglijent. Însă scopul principal al prototipului este de a ajuta în fazele de analiză şi proiectare şi nu folosirea unui stil elegant.

Se disting două feluri de prototipuri:

• de aruncat (throwaway)

• evoluţionar

În cazul realizării unui prototip de aruncat, scopul este exclusiv obţinerea unei specificaţii. De aceea nu se acordă nici o importanţă stilului de programare şi de lucru, punându-se accent pe viteza de dezvoltare. Odată stabilite cerinţele, codul prototipului este ’aruncat’, sistemul final fiind rescris de la început, în mod tipic chiar în alt limbaj de programare.

În cazul realizării unui prototip evoluţionar, scopul este de a crea un schelet al aplicaţiei care să poată implementa în primă fază o parte a cerinţelor sistemului. Pe măsură ce aplicaţia este dezvoltată, noi caracteristici sunt adăugate scheletului existent. În contrast cu prototipul de aruncat, aici se investeşte un efort considerabil într-un design modular şi extensibil, precum şi în adoptarea unui stil elegant de programare.

Avantaje:

• permite dezvoltatorilor să elimine lipsa de claritate a specificaţiilor;

• oferă utilizatorilor şansa de a schimba specificaţiile într-un mod ce nu afectează drastic durata de dezvoltare;

• întreţinerea este redusă, deoarece validarea se face pe parcursul dezvoltării;

• se poate facilita instruirea utilizatorilor finali înainte de terminarea produsului.

Dezavantaje:

• deoarece prototipul rulează într-un mediu artificial, anumite dezavantaje ale produsului final pot fi scăpate din vedere de clienţi;

• clientul nu înţelege de ce produsul necesită timp suplimentar pentru dezvoltare, având în vedere că prototipul a fost realizat atât de repede;

• deoarece au în fiecare moment şansa de a face acest lucru, clienţii schimbă foarte des specificaţiile;

• poate fi nepopulară printre dezvoltatori, deoarece implică renunţarea la propria muncă.

Page 18: software engineering

1.5 Metode formale

În acest model de dezvoltare, sunt folosite formalismul şi rigoarea matematicii. În prima fază este construită o specificaţie în limbaj matematic. Apoi, această specificaţie este transformată în programe, de obicei într-un proces incremental.

Avantaje:

• precizia obţinută prin specificarea formală;

• păstrarea corectitudinii în timpul transformării specificaţiei în cod executabil;

• oferă posibilitatea generării automate de cod;

• potrivite pentru sisteme cu cerinţe critice.

Dezavantaje:

• specificarea formală este de obicei o barieră de comunicare între client şi analist;

• necesită personal foarte calificat (deci mai scump);

• folosirea impecabilă a tehnicilor specificării formale nu implică neapărat obţinerea de programe sigure, deoarece anumite aspecte critice pot fi omise din specificaţiile iniţiale.

1.6 Modelul în spirală

Modelul în spirală încearcă să rezolve problemele modelului în cascadă, păstrând avantajele acestuia: planificare, faze bine definite, produse intermediare. De asemenea, se poate folosi prototipizarea dacă se consideră necesar.

Modelul în spirală defineşte următorii paşi în dezvoltarea unui produs:

• studiul de fezabilitate

• analiza cerinţelor

• proiectarea arhitecturii software

• implementarea

Modelul în spirală recunoaşte că problema principală a dezvoltării programelor este riscul. Riscul nu mai este eliminat prin aserţiuni de genul: “în urma proiectării am obţinut un model corect al sistemului”, ca şi în modelul cascadă. Aici riscul este acceptat, evaluat şi se iau măsuri pentru contracararea efectelor sale negative.

Exemple de riscuri:

• în timpul unui proces îndelungat de dezvoltare, cerinţele (noi) ale clientului sunt ignorate;

• firma concurentă lansează un program rival pe piaţă;

• un dezvoltator / arhitect părăseşte echipa de dezvoltare;

Page 19: software engineering

• echipa nu respectă un termen de livrare pentru o anumită componentă

• clientul schimbă cerinţele.

În modelul spirală (figura 1.3) se consideră că fiecare pas din dezvoltare conţine o serie de activităţi comune:

• pregătirea: se identifică obiectivele, alternativele, constrângerile;

• gestionarea riscului: analiza şi rezolvarea situaţiilor de risc;

• activităţi de dezvoltare specifice pasului curent (de ex. analiza specificaţiilor sau scrierea de cod)

• planificarea următorului stadiu: termenele limita, resurse umane, revizuirea stării proiectului.

Figura 1.3: Modelul de dezvoltare în spirală

1.7 Rational Unified Process (RUP)

Rational Unified Process (Procesul unificat [de dezvoltare al firmei] Rational) defineşte următoarele activităţi fundamentale:

• Ingineria funcţionalităţii. Sunt sintetizate necesităţile funcţionale.

• Cerinţe. Se translatează necesităţile funcţionale în comportament de sisteme automate.

• Analiza şi Proiectare. Se translatează cerinţele în arhitectura programului.

• Implementare. Se creează programul conform cu arhitectura astfel încât comportamentul acestuia sa fie apropiat de cel dorit.

2: gestiunea riscului [dealing with risk]

1: pregătirea [take stock]

4: planificarea următorului stadiu

[planning]

3: dezvoltarea [development]

Page 20: software engineering

• Testare. Se asigură că comportamentele cerute sunt corecte şi că toate comportamentele necesare sunt prezente în program.

• Administrarea configuraţiei şi a schimbărilor. Se gestionează versiunile tuturor entităţilor din care este compus programul.

• Administrarea proiectului. Sunt administrate planificările şi resursele.

• Administrarea mediului. Se instalează şi se menţine mediul de lucru necesar dezvoltării programului.

• Plasament. Se efectuează activităţile necesare punerii în funcţiune a programului.

Figura 1.4: Activităţile în cadrul RUP

Aceste activităţi nu sunt separate în timp (cum se presupune, de exemplu, în cazul modelului

în cascadă). Aici, ele sunt executate în paralel, pe parcursul întregului proiect. După cum reiese din figura 1.4 cantitatea de cod scrisă la începutul proiectului este mică, însă nu zero. Pe măsură ce proiectul evoluează, cele mai multe dintre cerinţe devin cunoscute, însă noi cerinţe sunt identificate: aceasta înseamnă că activitatea cerinţe se regăseşte pe întreaga durată de viaţă a procesului, însă apare cu pregnanţă la începutul acestuia.

Aşadar, pe măsură ce procesul de dezvoltare evoluează, importanţa anumitor activităţi scade sau creşte, însă este permis ca aceste activităţi să se execute la orice moment al dezvoltării.

Un proiect bazat pe RUP evoluează în paşi numiţi iteraţii. Scopul unei iteraţii este să dezvolte un program funcţional care să poată fi prezentat clientului, iar clientul să îl poată evalua. Programul obţinut la sfârşitul unei iteraţii ar trebui să conţină elemente din toate compartimentele programului, chiar dacă aceste compartimente nu sunt implementate complet.

Întinderea în timp a unei iteraţii depinde de tipul de proiect la care se lucrează, de experienţa echipei etc. Este însă de preferat ca iteraţiile să fie cât mai scurte. Dacă o iteraţie este scurtă, echipa de dezvoltare are oportunitatea de a primi mai repede reacţii din partea clientului. Iteraţiile care durează o săptămână sau două sunt considerate acceptabile ca întindere în timp. Iteraţiile pot fi folosite pentru a estima timpul necesar dezvoltării proiectului. Dacă, de exemplu, mai sunt de

Page 21: software engineering

proiectat încă 20 de iteraţii, iar până în momentul la care se face estimarea timpul de dezvoltare a fost de 2 săptămâni pe iteraţie, putem să apreciem că proiectul va mai dura aproximativ 40 de săptămâni. Acest tip de informaţie poate fi de mare folos administratorilor şi clienţilor. Iniţial estimările sunt nesigure, însă pe măsura ce proiectul avansează, ele devin din ce în ce mai precise. Se disting patru faze în RUP:

• Pornire

• Rafinare

• Construire

• Tranziţie Pornire. În faza de pornire, scopul principal al iteraţiilor este să ajute echipa de dezvoltare

să stabilească obiectivele esenţiale ale proiectului. Se vor explora arhitecturi alternative şi soluţii tehnice posibile. În urma acestei activităţi, se obţin următoarele:

• enumerare a cerinţelor principale, posibil în formă de cazuri de utilizare;

• imagine de ansamblu asupra arhitecturii programului;

• descriere a obiectivelor proiectului;

• un plan preliminar de dezvoltare.

Rafinare. În faza de rafinare se stabileşte o înţelegere detaliată a problemei care trebuie rezolvată, se hotărăşte arhitectura programului, se stabileşte echipa de lucru, se elimină situaţiile cu risc mare.

Această activitate produce următoarele:

• un prototip evoluţionar al arhitecturii programului;

• teste care verifică funcţionarea programului;

• cazuri de utilizare care descriu majoritatea funcţionalităţilor sistemului;

• un plan de proiect detaliat pentru iteraţiile următoare.

Construire. Iteraţiile din faza de construire au ca rol adăugarea se diverse caracteristici programului dezvoltat. În această fază se aşteaptă ca utilizarile oferite de client să se stabilizeze în mare măsură, deşi în unele aplicaţii este posibil ca ele să sufere oarecare modificări.

Cazurile de utilizare sunt adăugate unul câte unul, iteraţie cu iteraţie la program, până când clienţii pot utiliza programul într-un mod apropiat de cel aşteptat.

Activitatea de construire produce următoarele:

• Programul propriu-zis

• Teste

• Manuale de utilizare

Tranziţie. În cadrul acestei activităţi programul este îmbogăţit mai departe cu caracteristici, însă accentul se pune pe îmbunătăţirea şi rafinarea celor existente. Sfârşitul acestei activităţi şi a întregului proces de dezvoltare are loc atunci când:

• Obiectivele propuse în cadrul fazei de pornire sunt îndeplinite;

Page 22: software engineering

• Clientul este satisfăcut.

De remarcat că a doua situaţie nu se suprapune peste prima. Adesea pot să apară cerinţe ce nu au fost propuse iniţial.

1.8 Extreme Programming

Extreme Programming (XP, programare extremă) este o metodologie nouă de dezvoltare, inspirată din RUP, dar care propune rezolvări originale problemelor care apar în dezvoltarea de programe. Fiind o tehnologie nouă (şi extremistă) are adepţi şi detractori.

XP consideră că dezvoltarea programelor nu înseamnă ierarhii, responsabilităţi şi termene limită aşa cum se află acestea pe masa administratorului, ci înseamnă colaborarea oamenilor din care este formată echipa. Aceştia sunt încurajaţi să îşi afirme personalitatea, să ofere şi să primească cunoaştere şi să devină programatori străluciţi.

De asemenea, XP consideră că dezvoltarea de programe înseamnă în primul rând scrierea de programe. Această sintagmă banală se pare că este uitată de multe companii care se ascund în spatele proceselor de dezvoltare stufoase, a şedinţelor şi a rapoartelor de activitate (XP ne aminteşte cu respect ca fişierele PowerPoint nu se pot compila).

De altfel, inspirarea proceselor de dezvoltare a programelor din ingineria construcţiilor se pare că nu este cea mai fericită alegere. Este adevărat că un inginer care vrea să construiască un pod peste un râu face întâi măsurători, realizează un proiect şi abia apoi trece la execuţie, toate acestea într-un mod secvenţial şi previzibil. Dar dezvoltarea de programe nu seamănă cu aşa ceva, oricât am vrea să ne păcălim să credem asta. Dacă inginerului constructor respectiv i s-ar schimba cerinţele de rezistentă, i s-ar muta malurile şi i s-ar schimba râul din Siret în Amazon, pentru frumuseţe chiar când a terminat de construit jumătate de pod, putem fi siguri că acel inginer şi-ar schimba modul de lucru. Din păcate însă, nu ştim (încă) cum.

Iniţiatorii XP, Jon Jeffries şi Kent Beck definesc următoarele două carte, ca bază filozofică pentru această metodologie.

Carta drepturilor dezvoltatorului

• Ai dreptul să ştii ceea ce se cere, prin cerinţe clare, cu declaraţii clare de prioritate.

• Ai dreptul să spui cât îţi va lua să implementezi fiecare cerinţă, şi să îţi revizuieşti estimările în funcţie de experienţă.

• Ai dreptul să îţi accepţi responsabilităţile, în loc ca acestea să-ţi fie asignate.

• Ai dreptul să produci treabă de calitate în orice moment.

• Ai dreptul la linişte, distracţie şi la muncă productivă şi plăcută.

Carta drepturilor clientului

• Ai dreptul la un plan general, să ştii ce poate fi făcut, când, şi la ce preţ.

• Ai dreptul să vezi progresul într-un sistem care rulează şi care se dovedeşte că funcţionează trecând teste repetabile pe care tu le specifici.

• Ai dreptul să te răzgândeşti, să înlocuieşti funcţionalităţi şi să schimbi priorităţile.

• Ai dreptul să fii informat de schimbările în estimări, suficient de devreme pentru a putea reduce cerinţele astfel ca munca să se termine la data prestabilită. Poţi chiar să te opreşti

Page 23: software engineering

la un moment dat şi să rămâi cu un sistem folositor care să reflecte investiţia până la acea dată.

Aceste afirmaţii, deşi par înţelese de la sine, conţin semnificaţii profunde. Multe din

problemele apărute în dezvoltarea programelor pornesc de la încălcarea acestor principii. Enumerăm pe scurt câteva dintre caracteristicile XP.

• Echipa de dezvoltare nu are o structură ierarhică. Fiecare contribuie la proiect folosind maximul din cunoştinţele sale.

• Scrierea de cod este activitatea cea mai importantă.

• Proiectul este în mintea tuturor programatorilor din echipa, nu în documentaţii, modele sau rapoarte.

• La orice moment, un reprezentant al clientului este disponibil pentru clarificarea cerinţelor.

• Codul se scrie cât mai simplu.

• Se scrie întâi cod de test.

• Dacă apare necesitatea rescrierii sau aruncării de cod, aceasta se face fără milă.

• Modificările aduse codului sunt integrate continuu (de câteva ori pe zi).

• Se programează în echipă (programare în perechi). Echipele se schimbă la sfârşitul unei iteraţii (1-2 săptămâni).

• Se lucrează 40 de ore pe săptămână, fără lucru suplimentar.

Page 24: software engineering

Cap. 2

Ingineria cerinţelor Primul pas logic în dezvoltarea unui program este stabilirea precisă a cerinţelor clientului

(ceea ce clientul vrea ca programul să facă). Partea ce mai importantă a acestui proces o reprezintă comunicarea dintre client şi echipa de dezvoltare. Când un inginer de programe lucrează la stabilirea cerinţelor, el este numit inginer de cerinţe, analist de sistem sau analist.

Dezvoltarea unui program începe de obicei cu o idee a clientului despre un nou sistem sau pentru îmbunătăţirea unui sistem existent. Clientul angajează un analist cu care va lucra împreună pentru specificarea mai exactă a cerinţelor. Ideea iniţială a clientului poate fi vagă şi prost definită, după cum poate fi clară şi bine definită.

Stabilirea cerinţelor este probabil cea mai importantă activitate în dezvoltarea produselor program. Dacă un client nu ştie sau nu poate să stabilească în urma unei discuţii cu echipa de dezvoltare în mod exact ce vrea ca produsul să facă, este inutil să angajeze o echipă care să programeze. O echipă de programatori poate să scrie cel mai estetic program din punct de vedere al tehnicilor de programare folosite, dar dacă nimeni nu va dori să-l folosească, proiectul va fi un eşec.

Multe programe nu se potrivesc cu cerinţele clientului nu din motive de implementare defectuoasă, ci din cauză că cerinţele nu au fost specificate corect de la început

Programatorii nu pot şi nu au cum să cunoască necesităţile clienţilor, mai ales dacă nu cunosc domeniul pentru care o anumită aplicaţie este scrisă. Este responsabilitatea clientului de a veni cu cereri exacte şi pertinente. Este obligaţia inginerului de cerinţe de a discuta cu clientul pentru a clarifica cerinţele şi a ajuta clientul să-şi fixeze priorităţile.

Stabilirea precisa a cerinţelor este primul pas în obţinerea unui program care satisface cerinţele clientului. O specificaţie bună este folosită şi în fazele de validare şi verificare.

De ce sunt cerinţele utilizatorilor atât de importante? În 1994 compania Standish Group a supravegheat peste 350 de companii care au produs

peste 8000 de proiecte software şi a observat că 31 de procente dintre proiecte au fost abandonate înainte de a fi terminate. Mai mult, în marile companii, doar 9% au fost livrate la timp şi la costul la care au fost contractate, iar în companiile mici procentul s-a ridicat doar la 16%. În urma cercetărilor efectuate s-a stabilit următorul clasament al factorilor care au dus la această situaţie:

1. cerinţe incomplete (13.1%) 2. lipsa implicării utilizatorilor (12.4%) 3. lipsa resurselor (10.6%) 4. aşteptări nerealiste (9.9%) 5. lipsa suportului executivului (9.3%) 6. schimbarea cerinţelor şi a specificaţiilor (8.7%) 7. lipsa planificării (8.1%) 8. sistemele nu au mai fost cerute în întregime (7.5%) Lipsa prevederii în înţelegerea , documentarea şi managementul cerinţelor duce la o

multitudine de probleme: construirea unui sistem care rezolvă o problemă pusă greşit, care nu funcţionează după aşteptări, sau care este greu de înţeles şi de utilizat de către clienţi. Mai mult, un proces de extragere a cerinţelor nesatisfăcător poate fi scump. Boehm şi Papaccio (1988) au arătat că dacă găsirea şi rezolvarea problemelor referitoare la cerinţe în faza de definire a cerinţelor costă 1$ , aceeaşi operaţie costă 5$ dacă are loc în faza proiectării, 10$ în faza scrierii codului, 20$ în faza de testare şi mai mult de 200$ după livrarea sistemului.

Page 25: software engineering

1. Cerinţa

Noţiunea de cerinţă este mai veche decât dezvoltarea programelor. De exemplu, o cerinţă pentru o locomotivă ar putea arăta astfel: Pe o cale ferată uscată, locomotiva trebuie să fie capabilă să pornească un tren de 100 tone pe o pantă de maxim 5% cu o acceleraţie de cel puţin 30km/h. De remarcat că această cerinţă spune ce vrea clientul. Nu spune nimic despre cum ar putea fi realizată. Nu se specifică tipul motorului (cu aburi, diesel, electric) sau materialul din care să se confecţioneze roţile.

Controversă: este bine să facem specificarea luând în considerare felul în care sistemul va fi implementat?

1. Nu folosim detalii de implementare. Motivaţia: nu ne aşteptăm ca un client să ştie lucruri specifice dezvoltării programelor, şi deci nu poate să fie de acord în cunoştinţă de cauză cu stipulările din specificaţii. Secretarele care folosesc Excel ştiu COM? E necesar să facem constrângeri asupra programului încă din faza de concepere?

2. Folosim detalii de implementare. Câteodată nu este posibil să ignoram o implementare existentă. Dacă facem un program pentru o bibliotecă, studiem implementarea existentă (tipul fişelor ce trebuie completate, fluxul de lucru, modul de organizare al mediilor de stocare a informaţiilor) şi o „copiem” în program. Putem verifica dacă o cerinţă este sau nu rezonabilă din punct de vedere tehnic. Pentru a putea estima timpul de dezvoltare şi preţul, trebuie luată în considerare implementarea. Este o diferenţă între a programa în Visual Basic şi a programa în C++. Costurile iniţiale la programarea în Visual Basic vor fi mai mici (timp de dezvoltare mai mic, programatori mai ieftini), însă odată ce produsul necesită dezvoltarea peste o anumită limită a complexităţii, este posibil ca respectivele costuri să crească (întreţinere greoaie, probleme de performanţă).

În legătură cu specificaţia pentru locomotivă, remarcăm că indică cerinţe, nu mod de implementare. Cerinţele sunt testabile (cu instrumente de măsură specifice) şi sunt clare (neambigue). Remarcăm însă că este incompletă: nu specifică nimic despre costul sau termenul limită de realizare.

Ca să vedem dacă o specificaţie este bună ar trebui să ne întrebam dacă: • spune ce şi nu cum

• este clară

• este suficient de detaliată

• este completă Pentru comparaţie, considerăm următorul exemplu de specificaţie: Scrieţi un program

Pascal care oferă funcţionalitatea unei agende telefonice personale. Ar trebui să implementeze funcţii pentru căutarea unui număr şi pentru introducerea unui nou număr de telefon. Programul ar trebui să ofere o interfaţă utilizator prietenoasă.

2. Extragerea cerinţelor

Presupunem că analistul şi clientul lucrează împreună, fiecare încercând să înţeleagă pe celalalt. Esenţa procesului de obţinere a cerinţelor este comunicarea. Se disting trei activităţi majore care conduc la obţinerea unei specificări a cerinţelor:

• Ascultare. în această fază analistul înregistrează cerinţele clientului

• Gândire. în această fază analistul încearcă să traducă cerinţele clientului în limbaj tehnic şi să se asigure de pertinenţa cerinţelor în acest context.

Page 26: software engineering

• Scriere. Analistul şi clientul cad de acord asupra unor formulări ale cerinţelor pe care analistul le considera pertinente.

Aceste activităţi sunt parte a unui proces iterativ, lung şi complicat. Negocierea este foarte

importantă. Diferenţa culturală dintre client şi analist este câteodată foarte mare. Există situaţii când există diferenţe semnificative între aşteptările utilizatorilor finali şi ale clientului.

Un exemplu concret al acestui tip de conflict este când un patron care comandă un program care să fie utilizat de către angajaţii săi doreşte ca acesta să conţină module de monitorizare a muncii angajaţilor.

O altă problema o reprezintă literatura studiată de client, înainte de angajarea echipei de dezvoltare. Clientul aşteaptă mult prea mult de la program şi de la echipa de dezvoltare.

Analistul trebuie: • să extragă şi să clarifice cerinţele clientului

• să ajute la rezolvarea diferenţelor de opinie între clienţi şi utilizatori.

• să sfătuiască clientul despre ce este tehnic posibil sau imposibil

• să documenteze cerinţele

• să negocieze şi să obţină o înţelegere cu clientul.

3. Specificarea cerinţelor

Produsul extragerii cerinţelor şi a analizei este un document de specificare a cerinţelor (specificaţii). Specificaţiile sunt de o importanţă crucială în dezvoltarea cu succes a unui produs. Specificaţiile sunt documente de referinţă cu ajutorul cărora se evaluează dezvoltarea programului.

Trebuie avute în vedere: • nivelul de detaliu

• cui îi este adresat documentul

• notaţia folosită

Este de preferat ca specificaţiile să se restrângă cât mai mult în preajma a ce, nu a cum trebuie făcut. Ar trebui să surprindă viziunea clientului asupra sistemului. Specificaţiile trebuie înţelese de două grupuri distincte de persoane: clienţi şi dezvoltatori. Fiecare dintre aceste grupuri tind să aibă jargoane, domenii de expertiză diferite. Membrii acestor grupuri vor ca specificaţiile să enunţe exact cea ce trebuie făcut, însă preferinţele pentru limbajul în care se exprimă aceste lucruri sunt diferite. Clienţii preferă de obicei limbajul natural, în timp ce analiştii tind să folosească o notaţie precisă (limbaj de modelare).

Notaţiile folosite sunt de mai multe tipuri: informale, formale, semiformale. În abordarea modernă se fac două seturi de documente. Un set este pentru clienţi, iar un set

pentru dezvoltatori. Problema care apare este actualizarea acestor documente şi menţinerea lor consistentă.

Un document de specificaţii bun ar trebui să împartă pe categorii în mod explicit cerinţele în una din următoarele clase:

Cerinţele de capabilitate - definesc o operaţie sau o secvenţă de operaţii corelate, pe care

sistemul trebuie să le îndeplinească. În faza definirii cerinţelor software, cerinţele de capabilitate vor fi analizate pentru a

produce setul de cerinţe funcţionale. Cerinţele de capabilitate au următoarele atribute:

Page 27: software engineering

• capacitatea - se referă la cât de mult din capabilitatea respectivă e necesar la orice moment de timp.

Exemple: numărul de terminale, numărul de utilizatori, volumul de date ce va trebui stocat

• viteza - arată cât de rapid trebuie să se execute o operaţie sau secvenţă de operaţii, măsurat în număr de operaţii pe unitatea de timp.

Exemplu: “95% din tranzacţii se vor executa în mai puţin de o secundă”

• acurateţea unei operaţii - este măsurată prin diferenţa dintre ceea ce se intenţionează să execute o operaţie şi ceea ce execută ea în realitate.

Exemplu: “Programul va prezice altitudinea satelitului în limitele (cu o eroare de ) a 10m cu şapte zile înainte.”

Cerinţe privind datele - se referă la datele de intrare / ieşire din sistem (format, dimensiuni) şi la datele stocate în interiorul sistemului.

Cerinţele restrictive - impun restricţii asupra îndeplinirii cerinţelor de capabilitate. Utilizatorul poate impune constrângeri asupra interfeţelor privind comunicarea cu alte sisteme (interfeţe hardware sau software) sau cu factorul uman (interfaţa utilizator). El poate impune modul în care trebuie realizate interacţiunile cu alte sisteme dar ar trebui să lase echipei de dezvoltare libertatea de a le defini pe cele interne (privind interacţiunile dintre componentele software).

Cerinţele pentru interfaţa utilizator pot impune aspecte privind stilul acesteia (limbaj de comandă, sistemul de menuri, icons), formatul (conţinutul rapoartelor şi afişajelor ecran).

Utilizatorul poate impune constrângeri privind calitatea produsului software, prin următoarele caracteristici:

• adaptabilitate (flexibilitate) - posibilitatea unui sistem de a fi uşor modificat.

Exemplu: “Trebuie să fie posibil de a adăuga noi comenzi fără a le mai testa pe cele vechi”.

Observaţie: În ceea ce priveşte adaptabilitatea, orice schimbare presupune un risc şi modificări ale părţilor sigure ale sistemului ar putea fi inacceptabile.

• disponibilitatea - se referă la posibilitatea sistemului de a fi utilizat în timpul perioadei sale de operare. Cerinţele de disponibilitate ar putea specifica: - capacitatea minimă disponibilă (exemplu: “toate terminalele”)

- timpul de început şi de sfârşit al disponibilităţii (exemplu: “de la 9.00 până la 17:30, zilnic”)

- în medie, perioada disponibilităţii.

Exemplu: “toate capabilităţile esenţiale ale sistemului vor fi disponibile în măsură de cel puţin 98% în orice 48 ore şi în măsură de cel puţin 75% în orice perioadă de 3 ore ”

Dacă un sistem nu este disponibil (nu poate fi folosit), acest fapt se datorează pierderii cel puţin a uneia din capabilităţile sale, pierdere numită cădere, fiind cauzată de erori. Timpul mediu între apariţiile erorilor interne sistemului software (“bugs”) măsoară siguranţa sistemului. Timpul mediu necesar pentru a fixa erorile sistemului măsoară posibilitatea sistemului de a fi întreţinut.

Page 28: software engineering

• portabilitatea - reprezintă posibilitatea unui sistem de a fi mutat dintr-un mediu în altul.

Exemplu: “Software-ul va fi portabil între mediile X şi Y”

Portabilitatea poate fi măsurată în număr de linii de cod şi/sau numărul de module care nu trebuie să se modifice în momentul portării de pe un computer pe altul

• securitatea - sistemul trebuie să fie protejat împotriva propriilor erori ale utilizatorilor, sau împotriva unor activităţi ilegale, sau împotriva accesului unor utilizatori neautorizaţi.

• siguranţa - consecinţele “căderilor” sistemului trebuie semnalate clar echipei de dezvoltare. Informaţiile manipulate de sistem trebuie protejate împotriva unor erori ale sistemului (software sau hardware).

Exemplu: “Sistemul trebuie să asigure faptul că nici una din date nu se va pierde în eventualitatea unei căderi de tensiune”

• standarde - specifică documentele care definesc standarde: - ale procesului (exemplu: standardele pentru asigurarea produsului)

- ale produsului (exemple: formate ale fişierelor pentru export, sau formate ale rapoartelor)

• resurse - reprezintă resursele valabile pentru producerea şi operarea sistemului, în termeni financiari, de limitări materiale sau de resurse calculator (exemplu: memorie).

Probleme ce pot apare în legătura cu cerinţele:

• Cerinţe vagi: sistemul trebuie să fie prietenos

• Cerinţe contradictorii: toate datele trebuie scrise pe disc; timpul de răspuns 1 s

Succesul unui proces de dezvoltare a unui program se bazează pe extragerea în mod profesionist a cerinţelor de la client.

4. Metode pentru specificarea cerinţelor utilizatorilor Limbajul natural

Modul evident de specificare a unei cerinţe este limbajul natural. Limbajul natural este foarte accesibil dar inconsistent şi ambiguu. De exemplu, afirmaţia: Baza de date va conţine o adresă poate fi interpretată după cum urmează: Va fi doar o singură adresă

O parte din Baza de date va fi desemnată ca o adresă.

Va fi cel puţin o adresă în baza de date. Formalisme matematice

Formule matematice ar trebui folosite sau referite în DCU, pentru a clarifica o cerinţă. Toate

simbolurile folosite într-o expresie trebuie să fie definite sau referite. Engleza structurată - limbaj de specificare care foloseşte un vocabular şi o sintaxă foarte limitate. Vocabularul constă doar din:

Page 29: software engineering

• verbe imperative ale limbii engleze

• termeni definiţi într-un glosar

• cuvinte rezervate

Sintaxa e limitată la următoarele posibilităţi: • simple construcţii declarative

• construcţii decizionale

• construcţii repetitive

Engleza structurată este, în mod normal, folosită pentru a descrie procesele de bază ale sistemului şi e potrivită pentru exprimarea cerinţelor de capabilitate.

Exemple:

• construcţii declarative GET RAW DATA REMOVE INSTRUMENT EFFECTS CALIBRATE CORRECTED DATA

• construcţii decizionale IF SAMPLE IS OF NOMINAL QUALITY THEN CALIBRATE SAMPLE ELSE STORE BAD SAMPLE

• construcţii repetitive FOR EACH SAMPLE GET POINTING DIRECTION AT TIME OF SAMPLE STORE POINTING DIRECTION WITH SAMPLE

Formalizând engleza structurată, se poate automatiza procesarea cerinţelor (verificarea automată, o analiză automată, transformări şi afişări) şi se poate simplifica definirea testelor pentru faza de verificare şi validare a sistemelor. Tabele

Tabelele reprezintă o metodă efectivă pentru descrierea concisă şi completă a cerinţelor. Această metodă poate rezuma anumite relaţii, interacţiuni între cerinţe mai eficient decât o prezentare textuală. Diagrame bloc ale sistemului

Diagramele bloc reprezintă modul tradiţional de prezentare a proceselor dorite. Ele pot, de

asemenea, demonstra contextul în care sistemul va opera atunci când este o parte dintr-un sistem mai mare. Diagrame de context

Diagramele de context prezintă intefeţele externe ale sistemului, intrările şi ieşirile sale.

Page 30: software engineering

5. Utilitare pentru identificarea cerinţelor utilizatorilor Chestionarul este principalul utilitar pentru un interviu. Pentru a obţine informaţii utile, trebuie să se acorde o atenţie deosebită conţinutului şi prezentării sale. Mediile CASE pot fi utilizate pentru analiză şi proiectare, considerând studiul de fezabilitate. Similar, prototipul sistemului poate fi realizat folosind utilitare pentru o proiectare mai detaliată. Capturarea cerinţelor utilizatorului pe baza unui sistem software existent ar putea implica determinarea unor modele care descriu acest sistem (analiza structurată, SSADM). Utilitarele CASE sunt potrivite pentru construirea acestor modele.

6. Utilitare pentru specificarea cerinţelor utilizatorilor Utilitarele pentru manipularea informaţiilor - reprezintă cerinţele utilizatorului ar trebui să suporte una sau mai multe din funcţiile următoare:

- inserarea unor noi cerinţe

- modificarea unei cerinţe

- ştergerea unei cerinţe

- cross-referenţierea

- căutări

- afişări în diverse formate Pentru sistemele complexe, un sistem de manipulare a bazelor de date devine esenţial în

coordonarea informaţiilor. Utilitare pentru crearea Documentului Cerinţelor Utilizatorului (DCU) - sunt necesare utilitare care permit crearea paragrafelor, secţiunilor, tabelelor, cuprinsurilor, etc.

Sunt utile următoarele facilităţi: - un spell-checker

- afişarea documentului la diferite nivele de detaliu

- programe pentru compararea documentelor, care pot marca automat textele modificate (foarte necesare în revizuirea documentelor)

7. Documentul Cerinţelor Utilizatorului (DCU)

Acesta este documentul obligatoriu, produs în faza definirii cerinţelor şi trebuie să fie finalizat înainte de proiectarea sistemului. DCU trebuie:

• să furnizeze o descriere generală a ceea ce utilizatorul doreşte să execute sistemul.

• să conţină toate cerinţele cunoscute, ale utilizatorilor

• să descrie toate operaţiile pe care le va executa sistemul

• să descrie toate constrângerile impuse sistemului

• să definească toate interfeţele externe sistemului sau să conţină referinţe despre ele în alte documente.

Page 31: software engineering

Costul modificării cerinţelor creşte cu atât mai mult cu cât proiectul înaintează în fazele următoare. În faza de testare a sistemului, verificarea se va face pe baza DCU. Standardele Software Engineering recomandă următoarele caracteristici ale stilului de prezentare a unui DCU:

• DCU trebuie scris folosind un limbaj , vocabular şi stil uşor de înţeles de către toţi utilizatorii.

• DCU trebuie să fie clar, consistent, modificabil. - un DCU este clar dacă orice cerinţă este neambiguă (are o singură interpretare) şi este înţeleasă de toţi participanţii la proiect; o cerinţă trebuie scrisă într-o singură propoziţie iar justificările trebuie separate de aceasta; se recomandă ca cerinţele corelate între ele să fie grupate. Structurarea cerinţelor în document este foarte importantă.

- un DCU este consistent dacă nu există conflicte între cerinţe. Folosirea mai multor termeni pentru a specifica acelaşi lucru este un exemplu de inconsistenţă.

- un DCU este modificabil dacă orice modificare a cerinţelor poate fi documentată uşor, complet şi consistent.

Evoluţia DCU

Modificările inevitabile ale DCU sunt responsabilitatea utilizatorului. E necesară păstrarea

unei istorii a modificărilor efectuate. Problema actualizării întregii documentaţii va fi rezolvată când va fi stabilită o arhitectură

electronică standard pentru documente. Dacă schimbările cerinţelor sunt rezolvate direct în faza de implementare, fără a mai fi

prinse în documentaţie, aceasta poate provoca serioase probleme în faza de întreţinere a sistemului. Iniţiatorul proiectului ar trebui să monitorizeze tendinţa în apariţia unor noi cerinţe ale

utilizatorului. O tendinţă crescătoare va periclita succesul proiectului. Responsabilităţi

Se pun în evidenţă următoarele recomandări: • definirea clară a tuturor responsabilităţilor înainte de începerea DCU.

• utilizatorii reali ai sistemului sunt responsabili pentru determinarea cerinţelor de capabilitate.

• inginerii software trebuie să ia parte la formarea DCU pentru a-i ajuta pe utilizatori.

• indiferent de organizare, utilizatorii nu trebuie să dicteze soluţii iar echipa de dezvoltare nu trebuie să dicteze cerinţe.

Conţinutul DCU

Structura generală a unui DCU, recomandată de Standardul Ingineriei Software, este prezentată în continuare:

1. Introducere 2. Descriere generală 3. Cerinţe specifice

Page 32: software engineering

Secţiunea 1 trebuie să prezinte pe scurt scopul sistemului software, listele de definiţii pentru termeni utilizaţi în document, lista de referinţe bibliografice identificate prin autor, titlu şi date, şi o trecere în revistă a restului documentului.

Secţiunea 2 prezintă: • capabilităţile generale ale sistemului şi de ce sunt ele necesare

• constrângerile generale şi motivul pentru care au fost impuse

• caracteristicile generale ale utilizatorilor sistemului (nivelul educaţiei lor, limbajul, experienţa lor tehnică pot impune importante constrângeri asupra software-ului) din fazele de operare şi întreţinere ale sistemului. Este important a clasifica aceşti utilizatori şi de a estima numărul lor, în fiecare categorie.

• mediul extern în care sistemul va opera, prin diagrame de context pentru a evidenţia interfeţele externe şi prin diagrame bloc pentru a evidenţia activităţile din întregul sistem.

• situaţiile de risc evidenţiate în urma analizei riscurilor

Secţiunea 3 reprezintă partea principală a DCU, prezentând toate cerinţele de capabilitate şi cerinţele restrictive ale sistemului.

Validitatea sistemului software se va face pe baza acestor cerinţe. Fiecare cerinţă trebuie unic identificată. Fiecare cerinţă trebuie marcată funcţie de importanţa sa (unele pot fi extrem de importante,

altele inacceptabile, altele suspendate până la obţinerea unor resurse necesare, altele sunt prioritare, instabile).

Fiecare cerinţă trebuie să fie verificabilă. O afirmaţie trebuie să conţină o singură cerinţă. O cerinţă e verificabilă dacă există o metodă ce demonstrează obiectiv că ea este asigurată de sistem. (Afirmaţii ca: “interfaţa utilizator va fi prietenoasă”, ”sistemul va merge bine”, nu sunt verificabile deoarece termenii “bine”, “prietenos” nu au interpretări obiective). Dacă nu există o metodă pentru verificarea acestei cerinţe, aceasta este invalidă.

Page 33: software engineering

1

Definirea specificaţiilor software 1. Faza definirii cerinţelor software Introducere

Specificarea cerinţelor reprezintă definirea cerinţelor în termeni tehnici necesari dezvoltării unui sistem software şi alcătuieşte Documentul Cerinţelor Software (DCS). Documentul cerinţelor utilizatorilor este echivalentul tehnic al documentului cerinţelor software. Există situaţii în care există un document unic care serveşte ambelor scopuri, document realizat împreună de către client, inginerul de cerinţe şi programatori. În cele mai multe cazuri însă sunt necesare ambele documente. Trebuie o atenţie specială în a nu se pierde informaţii sau a se schimba cerinţe la interpretarea acestora ca specificaţii software.

Evident, ar trebui să existe o corespondenţă între fiecare cerinţă din DCU şi fiecare specificaţie din DCS. DCS reprezintă punctul de vedere al echipei de dezvoltare şi nu al utilizatorului. Definirea cerinţelor software reprezintă răspunderea echipei de dezvoltare. La această fază participă şi utilizatori, ingineri de sistem software sau hardware, personal de operare. Activitatea de management va trebui să asigure că acest document va fi revizuit de către toţi participanţii la această fază.

Managementul configuraţiei este alcătuit dintr-un set de proceduri care

urmăresc: - cerinţele care definesc ce trebuie să facă sistemul; - modulele de proiectare care sunt generate de aceste cerinţe; - codul programului ce implementează modulele de proiectare; - teste care verifică funcţionalitatea sistemului; - documente care descriu sistemul. În particular, în timpul fazei de definire şi de specificare a cerinţelor software,

managementul configuraţiei detaliază corespondenţa dintre elementele din DCU şi specificaţiile software. Dacă nu se definesc aceste legături, nu se pot defini cazuri de testare a codului pentru a verifica dacă respectă cerinţele impuse. In continuare, se va prezenta foarte sumar un ghid pentru producerea cerinţelor software, bazat pe recomandările standardelor Software Engineering.

Setul cerinţelor soft va fi alcătuit pe baza DCU şi pe baza modelului logic al sistemului (care este o descriere abstractă a ceea ce ar trebui să execute sistemul şi nu trebuie să conţină detalii de implementare).

Cerinţele software şi modelul logic al sistemului vor fi documentate în DCS, documentul obligatoriu al acestei faze.

Page 34: software engineering

2

1.1 Construirea modelului logic al sistemului Un model logic al sistemului este:

• o descriere simplificată a sistemului • ierarhic, conform unor criterii consistente de descompunere • compus din simboluri alese conform unor convenţii • construit pe baza unor anumite metode şi utilitare • folosit în analiza sistemelor

Modelul logic al sistemului determină o mai bună înţelegere a cerinţelor software,

considerate ca întreg. El trebuie construit iterativ: revizuiri ale fiecărui nivel al sistemului trebuie realizate înainte de a trece la următorul nivel de detaliu. Utilitarele CASE se recomandă pentru obţinerea unor modele clare şi consistente, uşor de construit şi de modificat. Tipul modelului logic depinde de metoda folosită. Se vor prezenta pe scurt metodele potrivite pentru construirea unui model logic. În cele ce urmează, prezentăm conceptele şi terminologia descompunerii funcţionale, pentru a arăta cum se construieşte un model logic.

Descompunerea funcţională Pentru a construi un model logic, sistemul este descompus într-un set de funcţiuni

de bază, cu doar câteva intrări şi ieşiri simple. Descompunerea funcţională este numită şi metoda “top-down” pentru că începe descompunerea sistemului de la o singură funcţie, rezultând apoi funcţii la nivele de detaliu mai mare. Fiecare nivel modelează sistemul la diferite trepte de abstractizare. Standardele SE definesc următoarele recomandări privind construirea unui model logic:

1. funcţiile trebuie să aibă un singur obiectiv, bine definit; 2. funcţiile trebuie să fie potrivite nivelului la care apar (exemplu: “Calculează …”

să nu apară cu “Verifică ….”); 3. interfeţele trebuie minimizate; 4. orice funcţie se descompune în cel mult 7 sub-funcţii; 5. nu se foloseşte terminologia specifică implementării (fişier, înregistrare, modul,

staţie de lucru, etc.); 6. atributele de performanţă ale oricărei funcţii (capacitate, viteză, acurateţe) ar

trebui specificate, dacă e posibil; 7. trebuie identificate funcţiile critice; 8. numele funcţiilor trebuie să reflecte scopul lor; 9. numele funcţiilor trebuie să aibă o structură declarativă (“Calculează suma”,

“Caută identificator ”, etc.). Se consideră că descompunerea funcţională a atins un nivel suficient de detalii dacă:

• modelul furnizează toate capabilităţile cerute • respectă cele nouă recomandări

Page 35: software engineering

3

Analiza performanţei

Cerinţele utilizatorului pot conţine atribute de performanţă (capacitate, viteză,

acurateţe). Acestea definesc performanţele pentru o funcţie sau un grup de funcţii. Modelul logic trebuie verificat din punct de vedere al conflictelor performanţelor

prin studierea tuturor căilor de-a lungul fluxurilor de date.

Analiza funcţiilor critice

Uneori, cerinţele de capabilitate sunt definite în termeni privind categoria severităţii consecinţelor hazardului (CSCH). Aceste categorii pot varia de la “catastrofic” la ”critic” şi de la ”marginal” la ”neglijabil”.

Dacă asemenea termeni sunt specificaţi, modelul logic trebuie analizat pentru a propaga CSCH către toate cerinţele corelate cu cerinţa iniţială, având ataşată această categorie (pentru aceasta există tehnici speciale).

Prototipul

Uneori, este util de a verifica anumite părţi ale modelului. Tehnica executării unui prototip ar putea clarifica cerinţele.

Echipa de dezvoltare poate identifica cerinţe cu un grad oarecare de risc (adică nu e sigur că aceste cerinţe ar putea fi satisfăcute). Prototipul poate decide dacă asemenea cerinţe trebuie sau nu incluse în DCS. 1.2 Specificarea cerinţelor software Standardele SE definesc următoarele tipuri de cerinţe software:

• cerinţele funcţionale (provenite din cerinţele de capabilitate) • cerinţele nefuncţionale sau de performanţă (provenite din constrângerile

asupra cerinţelor de capabilitate)

Cerinţele funcţionale

Acestea specifică funcţiile pe care sistemul trebuie să le execute. Există o corespondenţă de la 1 la 1 între cerinţele funcţionale şi nodurile

sistemului logic. Cerinţele funcţionale trebuie organizate în aceeaşi manieră top-down, funcţie de

structura modelului logic. O cerinţă funcţională: • defineşte ce execută sistemul • defineşte transformarea ce trebuie executată pe intrările specificate pentru a

genera ieşirile • are ataşate cerinţe de performanţă (capacitate, viteză, acurateţe)

Page 36: software engineering

4

• trebuie exprimate prin fraze concise, simple (de exemplu, utilizând engleza structurată)

Cerinţele nefuncţionale (de performanţă)

Acestea provin din cerinţele restrictive. Ele ar trebui ataşate cerinţelor

funcţionale, putând apărea deci pe orice nivel, aplicându-se tuturor cerinţelor funcţionale de pe nivelul următor.

De obicei, sunt exprimate în limbaj natural, deoarece notaţiile formale nu sunt destul de expresive. 2. Metode pentru definirea cerinţelor software Introducere

Faza definirii cerinţelor software poate fi numită şi faza analizei, conform standardelor SE.

Analiza se realizează folosind o metodă sau o combinaţie de metode pentru: • construirea modelului logic • specificarea cerinţelor software Se rezumă în continuare câteva bine-cunoscute metode, fără a recomanda o

metodă standard şi fără a defini un set complet de metode. Funcţie de fiecare proiect, se alege metoda cea mai potrivită. E recomandabil a se

studia sisteme concrete, care au fost dezvoltate cu diverse metode, pentru a alege metoda cea mai potrivită.

Metodele posibile sunt: • descompunerea funcţională • analiza structurată • analiza orientată-obiect • metode formale • dezvoltarea sistemelor Jackson • prototipul

2.1 Descompunerea funcţională

Aceasta este metoda tradiţională de analiză şi a fost încorporată în metoda analizei structurate. 2.2 Analiza structurată

Este numele unei clase de metode de analiză a sistemelor prin construirea unor modele ale fluxurilor de date.

Fac parte din această clasă următoarele metode: • metodele Yourdon (DeMarco şi Ward-Mellor)

Page 37: software engineering

5

• SSADM (Structured System Analysis and Design Methodology) • SADT (Structured Analysis and Design Techniques) Analiza structurată include toate conceptele descompunerii funcţionale dar

produce specificaţii funcţionale de o mai mare calitate, prin definirea riguroasă a interfeţelor între procese şi anume, fluxurile de date şi control.

Diagramele fluxurilor de date (DFD) sunt caracteristice metodelor de analiză structurată.

Conform definiţiei propusă de DeMarco, analiza structurată înseamnă folosirea următoarelor tehnici pentru a produce specificaţiile sistemului:

• DFD • Dicţionarul de Date • engleza structurată • tabele de decizie • arbori de decizie Ultimele 3 sunt utilizate pentru a specifica detalii de procesare algoritmică.

Dezvoltarea analizei structurate pentru sistemele de timp real, a suplimentat

această listă cu: • Schema Transformărilor • Lista evenimentelor • Diagrame stare-tranziţie • Schema de Date • Specificaţii pre- şi post- condiţie

SSADM, care pune accent pe modelarea datelor, mai include: • Diagramele Entitate-Relaţie (E-R “entity-relationship”) sau Modelele Entităţii • Istoriile vieţii entităţii (Entity Life Histories) Analiza structurată produce specificaţii structurate, conţinând o descriere

sistematică şi riguroasă a sistemului. Analiza şi proiectarea sistemului reprezintă procesul realizării unui model al sistemului.

Analiza structurată (“Structured Analysis”)- versiunea DeMarco (78)

SA este o metodă generală de analiză a sistemelor. Există 2 versiuni similare: - Gane, Sarson (79) - DeMarco (78)

Ne vom referi în continuare la versiunea DeMarco. SA DeMarco utilizează Diagramele Fluxurilor de Date (DFD). DFD evidenţiază

transformarea datelor de intrare în date de ieşire printr-o secvenţă de transformări funcţionale. Ele reprezintă un mod intuitiv de descriere a sistemelor şi pot fi înţelese fără o antrenare specială.

În mod normal, aceste diagrame nu trebuie să includă informaţii de control, dar trebuie să documenteze transformările datelor.

Page 38: software engineering

6

DFD sunt grafice adnotate, folosind următoarele simboluri:

• Primul simbol reprezintă fluxul de date, unic etichetate textual. • Simbolul 2 reprezintă procesul care transformă datele de intrare în date de

ieşire. • Simbolul 3, o linie dreaptă, reprezintă un fişier sau o bază de date. • Simbolul 4 reprezintă sursa sau destinaţia datelor. Ele sunt exterioare

sistemului care trebuie analizat.

Ultimele simboluri au înţelesul cunoscut al operatorilor expresiilor booleene. Sunt folosite când mai multe fluxuri de date intră sau ies dintr-un proces.

Toate aceste simboluri pot fi combinate pentru a forma o DFD. Exemplul 1:

Figura 1: Diagramă a fluxurilor de date

Sursa S1 creează data A care urmează să fie transformată de procesul P1 în două

pachete de date B şi C. Procesul P2, folosind informaţii din baza de date DB , transformă datele B şi C în D, procesul P3 transformă data D în data E, care ajunge la destinaţia S2.

Fiecare proces poate fi expandat într-o manieră ierarhică, pentru a prezenta un nivel de detaliu mai mare. Un proces poate reprezenta un număr de alte procese şi fluxuri de date, deci o DFD, ca în figura 2. Acest lucru e numit organizare pe nivele (leveling), un proces fiind considerat părintele altor procese descendente. Conceptul de echilibrare (balancing) se referă la faptul că intrările şi ieşirile procesului părinte sunt, de asemenea, reprezentate în diagrama descendentă. Şi acest lucru este pus în evidenţă în figura 2.

P1 P3 P2

S1 A

B

C D ES2

DB

flux de date

fişier

proces

surse sau destinaţii

and, or conectori logici

Page 39: software engineering

7

Toate datele care apar în DFD sunt documentate într-un dicţionar de date.

Figura 2: Organizarea pe nivele. Echilibrarea intrărilor şi ieşirilor Celelalte elemente ale analizei structurate: Engleza structurată, Tabele de decizie

şi Arborii de decizie sunt utilizate pentru a specifica detalii ale procesării. DFD reprezintă o parte integrală a unui număr de metode iar mediile (utilitarele)

CASE, de obicei, suportă crearea DFD. Notaţiile folosite în diverse metode sunt asemănătoare.

Metoda E-R

Cele mai multe sisteme software complexe folosesc mari baze de date. O parte din activitatea de modelare a sistemelor este dedicată definirii logice a datelor manipulate de sistem. Metode obişnuite pentru modelarea logică a datelor sunt:

• modelul entitate-relaţie (“entity-relationship”) sau E-R , Chen-1976 • SDM – Structured Data Modeling (Hammer, McLeod-81) • modelul relaţional (“Relational Model”) În principiu, modelul E-R stabileşte entităţi de date (care în termenii limbajelor de

programare ar corespunde tipurilor de structuri de date) şi relaţii între aceste entităţi (corespunzătoare operaţiilor asupra tipurilor de entităţi). Entităţile pot avea atribute (analog câmpurilor din structuri), la fel şi relaţiile (“private data values”). În general, atributele sunt atomice (nu se descompun mai departe). Tipurile pot avea subtipuri astfel încât un tip special de relaţii numit relaţie de moştenire (inheritance relation) a fost introdus pentru extinderea modelului E-R. Subtipurile moştenesc atributele supertipurilor. Atribute adiţionale proprii pot fi adăugate entităţii subtip.

În general, modelul E-R este suportat de mediile CASE.

P1 P2

P3

P4

A B

C

E

D

F

P21

P23

P22

P24

P25B

C

E

Page 40: software engineering

8

Modelul utilizat aici reprezintă extensia modelului E-R, a lui Chen. Notaţiile grafice utilizate sunt prezentate în figura 3.

entitate

atribut pentru entitate sau relaţii

<cardinalitate de intrare> relaţie <cardinalitate de ieşire>

relaţie de moştenire

Figura 3: Notaţiile folosite în modelul E-R extins

Există variante pentru aceste notaţii.

Cardinalitatea de intrare reprezintă numărul entităţilor de intrare. Cardinalitatea de ieşire reprezintă numărul entităţilor de ieşire.

O relaţie de moştenire arată că o entitate moşteneşte atributele entităţii părinte. Subtipul este indicat printr-o săgeată.

Relaţiile între entităţi pot fi: • 1:1 ceea ce înseamnă că o instanţă a unei entităţi participă în relaţie cu o instanţă a altei

entităţi. • 1:M - o instanţă a unei entităţi participă în relaţie cu mai multe instanţe ale altei entităţi. • M:N - mai multe instanţe ale unei entităţi participă în relaţie cu mai multe instanţe ale altei

entităţi. În acest model, relaţia M:1 nu este suportată. Exemplul 1: Ca o simplă ilustrare a modelului E-R, considerăm un simbol utilizat de sistemele de editare a diagramelor:

Simbolurile reprezentând tipuri particulare sunt compuse din simbolurile

primitive ca: linii, elipse, dreptunghiuri.

<nume>

<nume

Page 41: software engineering

9

Modelul datelor pentru simbolul compus din figura anterioară, este prezentat în figura 4. Acest model arată că simbolul compus considerat are un atribut care indică dacă simbolul are dimensiuni variabile sau fixe şi este realizat dintr-un număr de primitive, toate având atributul de “culoare”. Primitivele pot fi dreptunghiuri, linii sau elipse, fiecare din aceste subtipuri având propriile lor atribute.

Figura 4: Modelul simbolului compus

Modelele E-R au fost utilizate foarte mult în proiectarea bazelor de date. Datorită existenţei tipurilor, subtipurilor şi a supertipurilor, este uşor de a mapa aceste modele în baze de date orientate obiect. Deşi bazele de date orientate obiect nu au atins un stadiu matur, se pare că vor fi folosite pe scară largă în viitor în aplicaţii ca medii CASE.

Dicţionarul de date

Pe măsură ce un model al sistemului este dezvoltat, apar foarte multe entităţi a

căror identificare prin nume trebuie să fie unică. Menţinerea unicităţii este dificilă mai ales dacă mai multe persoane sunt implicate în procesul de dezvoltare . Este absolut necesară o metodă automatizată şi, în acest scop, se foloseşte un utilitar pentru coordonarea numelor: dicţionarul de date. Dicţionarul de date (DD) documentează riguros diagramele sistemelor. Practic, dicţionarul de date este o listă de nume ale entităţilor, însoţite de descrieri ale acestora.

Dicţionarele de date sunt utile în toate fazele procesului de dezvoltare, începând de la modelarea iniţială şi până la întreţinerea sistemului.

tip dimensiune Simbol compus

are

primitive culoare

dreptunghi linie elipsă

lungime lăţime lungime unghi diam x diam y

Page 42: software engineering

10

Toate numele entităţilor, tipurilor, relaţiilor, atributelor, etc., trebuie introduse în DD. Există posibilitatea, prin suportul software existent, de a crea , a menţine şi a interoga DD. Exemplul 1: Un model logic posibil al datelor pentru un DD este arătat în figura5.

Figura 5: Model al dicţionarului de date

Acesta arată că DD este compus dintr-un număr de intrări, fiecare intrare având ca

atribute: nume, reprezentare, descriere, data creării şi o stare (care permite unei intrări să devină inactivă). Fiecare intrare participă în 3 relaţii cu alte intrări. Acestea arată:

• ce entităţi vor folosi această entitate • ce entităţi sunt folosite de această entitate • ce entităţi sunt incluse în această entitate (de exemplu, entităţile operaţii sunt

incluse în entităţile tipurilor de date abstracte) Exemple de intrări în DD sunt prezentate în figura 6. Informaţiile privind relaţiile

dintre entităţi nu au fost cuprinse aici. Într-un DD automat, aceste informaţii sunt accesibile dintr-un meniu asociat fiecărei intrări.

tip dimensiune DD

defineşte

intrare

def

desc

data

nume

tip

1

N

folosită de

foloseşte include

intrare intrare intrare

Page 43: software engineering

11

Nume_entitate Tip Descriere Definiţie Data design name data numele diagramei ce trebuie procesată …. … Get design name proces diagrama se găseşte în baza de date a

sistemului ca o entitate cu un nume. Acest proces comunică cu utilizatorul pentru a prelua acest nume.

… …

Get entity name proces Folosind numele diagramei, acest proces găseşte în baza de date a diagramei şi extrage numele entităţilor.

… …

Figura 6: O parte a înregistrărilor din DD pentru un generator de rapoarte a diagramelor

Modelul Ward-Mellor

Acesta descrie un proces iterativ de modelare a sistemului care defineşte întâi primele nivele ale modelului esenţial, care este un model logic al sistemului. În loc de a construi imediat nivelele următoare ale modelului, Ward şi Mellor recomandă construirea primelor nivele ale modelului de implementare. Ciclul continuă cu definirea următorului nivel al modelului esenţial. Acest mod evită îndepărtarea prea mare a modelului de realitate şi previne o implementare lipsită de coerenţă şi structură. Totuşi, nu se intenţionează în acest fel construirea modelului definitiv de implementare. Acesta ar trebui să aibă loc în faza proiectării sistemului. Această metodă este considerată în faza definirii specificaţiilor software a sistemelor de timp real.

Modelul SADT (D.Ross-1977)

Acest model consideră două etape în faza definirii cerinţelor software: - analiza contextului sistemului, a interacţiunii sale cu exteriorul

- specificarea funcţională care presupune construirea unei arhitecturi funcţionale, exprimată prin diagrame SADT.

Arhitectura funcţională reprezintă un model logic al sistemului, derivat dintr-o descompunere funcţională, top-down, a sistemului, începând cu diagrama de context, care prezintă toate interfeţele sistemului, după acelaşi principiu ca şi SA. Ca şi în SA, fluxurile de date ale sistemului sunt transformate de o funcţie sau de o activitate. Diagramele obţinute în acest fel se numesc diagrame de activităţi.

Diagramele de activităţi SADT sunt formate din dreptunghiuri, săgeţi şi diagrame, ca în figura 7:

Figura 7: Diagrama SADT

Funcţie sau activitate

Date de control

Date de intrare Date de ieşire

Mecanism

Page 44: software engineering

12

Un dreptunghi e o funcţie sau activitate care transformă datele. Datele de intrare pătrund prin partea stângă şi ies, transformate, prin partea dreaptă.

Pe latura superioară a dreptunghiului sunt evidenţiate constrângerile sau datele de control pentru activitatea respectivă. Acestea constrâng modul de transformare a intrării în ieşire sau controlează modul în care o activitate poate fi folosită pentru a produce o ieşire.

În partea inferioară a dreptunghiului, se prezintă mecanismul folosit de funcţia sau activitatea respectivă, dar mecanismele nu sunt esenţiale modelului SADT.

Dreptunghiul este etichetat cu un verb sau o expresie declarativă care să exprime clar o acţiune de transformare a datelor.

Fiecare săgeată este etichetată cu un substantiv. O diagramă constă dintr-un set de astfel de simboluri din figura anterioară şi

fiecare element al diagramei poate fi descompus mai departe, prin acelaşi tip de relaţie părinte-descendent, întâlnit la diagramele SA. Pentru a menţine consistenţa şi completitudinea nivelelor, intrările, ieşirile şi datele de control ale unei diagrame părinte trebuie să apară şi în diagrama descendent. Fiecare descompunere trece astfel prin nivele din ce în ce mai detaliate.

2.3 Metode formale

Scopul acestui capitol este de a introduce tehnicile formale de specificaţii pentru a

îndepărta unele păreri preconcepute privind acest subiect şi pentru a-i convinge pe ingineri că aceste tehnici pot fi folosite în procesul de dezvoltare a sistemelor software.

Metodele formale trebuie folosite când e necesar a demonstra riguros că sistemul îndeplineşte anumite acţiuni. Aceste metode se recomandă pentru sistemele critice din punct de vedere al siguranţei, sau pentru cele cu severe constrângeri de securitate.

Metodele formale au fost criticate pentru că determină specificaţii neinteligibile pentru utilizator. Conform standardelor ingineriei programării, DCU furnizează specificaţiile din punctul de vedere al utilizatorului. DCS este destinat în primul rând echipei de dezvoltare dar i se pot adăuga note explicatorii care să-l facă înţeles şi de alţi cititori. Metodele şi specificaţiile formale n-au fost folosite pe scară largă în dezvoltarea sistemelor. Există, în general, tendinţa de a respinge folosirea acestora deoarece efortul implicat în însuşirea, asimilarea lor, nu pare a fi justificat de avantajele pe care le oferă. Totuşi, în momentul de faţă, metodele formale au atins un nivel suficient de matur, nivel la care ele pot fi utilizate în sisteme reale. Experienţele de până acum au arătat că utilizarea acestor metode: - măresc calitatea sistemului - reduc costurile totale de dezvoltare Avantaje • Pe măsură ce o specificaţie e rafinată, sunt detectate erorile şi omisiunile. Detectarea

erorilor este argumentul cel mai puternic pentru dezvoltarea unor specificaţii formale. • Specificaţiile formale sunt entităţi matematice care pot fi analizate din punct de

vedere matematic. E posibil de a se demonstra consistenţa şi completitudinea specificaţiilor sau de a demonstra că o implementare se conformează specificaţiilor sale. Astfel, poate fi demonstrată absenţa unor clase de erori.

Page 45: software engineering

13

• Specificaţiile formale pot fi folosite ca un ghid pentru identificarea seturilor de test potrivite la verificarea sistemului. În acest sens, au fost deja iniţiate acţiuni de cercetare privind tehnicile specificaţiilor formale în scopul verificării formale a programelor. Totuşi, e recomandabil a se folosi tehnicile specificaţiilor formale chiar dacă încă nu există posibilitatea verificărilor formale a programelor.

Tehnicile specificaţiilor formale nu sunt folosite pe scară industrială deoarece:

• Managerii sunt conservatori şi nu adoptă noi tehnici dacă avantajele nu sunt evidente. E greu de a demonstra că un cost relativ mare pentru dezvoltarea unei specificaţii formale va reduce costurile totale pentru dezvoltarea sistemelor.

• Cei mai mulţi ingineri nu sunt antrenaţi în a folosi aceste tehnici. Dezvoltarea specificaţiilor formale cere o familiarizare cu noţiuni de matematică şi logică matematică, ceea ce face ca aceste tehnici să pară dificile.

• Există o largă ignoranţă privind cunoaşterea tehnicilor curente de specificare şi aplicabilitatea lor. Există deja aproximativ câteva sute de sisteme relativ mari, specificate formal.

• Cele mai multe eforturi s-au concentrat spre dezvoltarea de notaţii şi tehnici. Puţin efort s-a îndreptat spre producerea suporturilor software pentru aceste tehnici, deşi acesta este esenţial.

O specificaţie formală este o specificaţie exprimată într-un vocabular, sintaxă şi semantică formal definite.

După cum am mai precizat, un model al procesului îl reprezintă cel al transformărilor formale. Specificaţiile formale reprezintă o premisă obligatorie pentru acest proces care implică transformarea acelei specificaţii într-un program, printr-o serie de transformări ce păstrează corectitudinea. (figura 8).

Figura 8: Dezvoltarea transformaţională a sistemelor Ti = transformări formale Pi = demonstrarea corectitudinii transformărilor

Fiecare transformare este suficient de aproape de cea anterioară astfel încât efortul de a o verifica nu este excesiv. Avantajul abordării transformaţionale comparat cu

Specificare formală R2 R3

P1 P2 P4P3

Program executabil R1

T1 T2 T3 T4

Page 46: software engineering

14

a demonstra că programul îşi îndeplineşte specificaţiile este că distanţa dintre transformări este mai mică decât distanţa dintre specificaţii şi program. Demonstraţiile pentru program sunt foarte lungi şi nepractice pentru sistemele pe scară largă, dar abordarea transformaţională realizată din paşi mici poate fi mai bună. Totuşi, procesul nu e simplu. Alegerea transformării şi demonstrarea corespondenţei dintre transformări presupun anumite abilităţi.

Se pare însă că dezvoltări recente ale metodelor formale (limbajul de specificare Z) vor face acest proces mai practic. Cele mai comune metode formale sunt:

Metoda Rezumat Z Metodă de specificaţie pentru programe secvenţiale VDM (Vienna Development Method)

Metodă de specificaţie pentru programe secvenţiale

LOTOS (Language of Temporal Ordering Specification )

Metodă formală, singura care are un standard internaţional. Este o combinaţie între CSP, şi tipurile de date abstracte din limbajul de specificaţii algebrice, ACT ONE. Este dedicată sistemelor distribuite. Sunt valabile utilitare.

CSP (Communicating Sequential Processes)

Limbaj de proiectare pentru paralelism asincron şi comunicaţii sincrone.

OBJ (OBJects) Limbaj de specificare funcţională şi utilitar pentru prototip. Utilizat pentru programe secvenţiale. Obiectele sunt principalele componente ale specificaţiilor

CCS (Calculus for Communicating Systems)

Specificare şi proiectare a sistemelor concurente. Calcul pentru paralelism asincron şi comunicaţii sincrone.

Reţele Petri Modelarea comportării sistemelor concurente. Specificaţii algebrice Metodă de specificaţie pentru programe secvenţiale 2.4 Dezvoltarea sistemelor Jackson - metodă dedicată mai ales dezvoltării sistemelor de

timp real. 2.5 Prototipizarea rapidă

Un prototip este un model executabil al unor aspecte selectate ale sistemului. Dacă cerinţele sunt neclare sau incomplete, e util a se dezvolta un prototip pentru a determina cerinţele reale. Prototipul poate ajuta la definirea cerinţelor pentru interfaţa utilizatorului. Prototipizarea rapidă este procesul de a construi şi a evalua foarte rapid o serie de prototipuri, în următoarea manieră: repeat until utilizatorul semnează DCS begin analizează cerinţele creează baza de date

Page 47: software engineering

15

creează interfaţa utilizator adaugă noi funcţii revede execuţia prototipului împreună cu utilizatorul end

Cerinţele trebuie analizate utilizând o metodă ca SA, de exemplu. Prototipizarea rapidă necesită un suport (utilitare) software, altfel nu e suficient

de rapidă pentru a fi efectiv utilă. Rezultatele prototipizării rapide se folosesc la formularea cerinţelor software în DCS. Pentru a permite o implementare rapidă a unui prototip, constrângerile şi regulile impuse de standardele de proiectare şi implementare pot fi relaxate. Deoarece produsul software final trebuie să respecte anumite cerinţe de calitate, softul scris pentru implementarea prototipului nu trebuie folosit în etapele ulterioare. Este utilă, bineînţeles, utilizarea ideilor care a determinat construirea prototipului.

Page 48: software engineering

1

2. Metode pentru definirea cerinţelor software (continuare)

2.6 Analiza orientată-obiect (AOO) Introducere

Analiza orientată obiect este numele unei clase de metode de analiză a unei probleme prin studiul obiectelor domeniului problemei respective. Obiectul reprezintă o încapsulare a valorilor unor atribute şi a serviciilor lor exclusive.

O clasă descrie un set de obiecte cu atribute şi servicii comune. Un obiect este o instanţă a unei clase si crearea unui obiect se numeşte instanţiere. Clasa poate fi descompusă în subclase. Subclasele au în comun atributele caracteristice unei familii de clase, moştenind operaţiile şi atributele claselor-părinţi.

Analiza orientată obiect (AAO) diferă de analiza structurată (AS) prin: • construirea unui model al obiectelor în locul modelului funcţional

• integrarea obiectelor, atributelor şi operaţiilor în loc de separarea lor prin modelul datelor şi cel funcţional.

AAO a fost utilizată cu succes în problemele greu abordate cu AS, ca de exemplu realizarea interfeţelor utilizator. AAO determină o tranziţie către proiectarea orientată obiect (POO) şi limbaje de programare ca ADA, C++ etc. Iniţiatorii acestei metode argumentează că modul de a privi un sistem din perspectiva obiectelor este mult mai natural decât analiza sistemelor din punct de vedere funcţional. Specificaţiile bazate pe obiecte vor fi mai adaptabile decât cele bazate pe funcţii. Cele mai importante şi recunoscute metode AOO sunt:

• metoda Coad-Yourdon

• Rumbaugh-Object Modelling Technique (OMT)

• Shlaer-Mellor

• Booch

În momentul de faţă, AAO evoluează iar analiştii, de obicei, combină tehnicile diferitelor metode în faza de analiză a problemei.

AAO nu se utilizează pentru sisteme care au foarte puţine funcţiuni sau pentru sisteme cu 1-2 clase şi obiecte.

Principiile utilizate de OOA sunt principiile utilizate pentru coordonarea complexităţii: 1. Abstractizarea (procedurală şi de date)

2. Încapsularea

3. Moştenirea

4. Asocierea

5. Comunicarea prin mesaje

6. Utilizarea metodelor de organizare

Page 49: software engineering

2

• obiecte şi atribute

• obiecte şi părţile sale

• clase şi membri 1. Abstractizarea. Principiul abstractizării presupune ignorarea acelor aspecte ale unui subiect care nu sunt relevante pentru obiectivul curent (aceasta este o tehnică importantă pentru a coordona complexitatea).

• Abstractizarea procedurală este principiul conform căruia orice operaţie poate fi tratată ca o singură entitate în ciuda faptului că ea presupune realizarea mai multor operaţii de pe nivelul următor de detaliu (vezi diagramele DFD unde primul nivel reprezintă sistemul urmând celelalte nivele de detaliu). Această formă de abstractizare joacă un rol foarte important în definirea Serviciilor sistemului.

• Abstractizarea datelor reprezintă un mecanism mai puternic de abstractizare conform căruia tipurile de date sunt definite în termenii operaţiilor ce se aplică obiectelor de acel tip, cu restricţia că valorile acelor obiecte pot fi observate şi modificate doar prin intermediul operaţiilor menţionate. Prin aplicarea acestui principiu, un analist defineşte Atributele şi Serviciile care manipulează aceste atribute. Singurul mod de a accesa un atribut este prin intermediul serviciilor. Atributele şi serviciile pot fi văzute ca formând un întreg.

2. Încapsularea. Conform acestui principiu, fiecare componentă a unui program ar trebui să încapsuleze sau să ascundă o singură decizie de proiectare. Interfaţa fiecărui modul e definită astfel încât să releve cât mai puţin din funcţionarea sa internă. Se minimizează astfel efortul modificărilor ulterioare. 3. Moştenirea - mecanismul prin care se exprimă similarităţile dintre clase, simplificând definirea claselor prin utilizarea unor clase anterior definite. Acest principiu pune în evidenţă generalizarea şi specializarea, făcând explicite Atributele şi Serviciile comune, printr-o ierarhie de clase. Principiul moştenirii permite analistului de a specifica Atributele şi Serviciile comune doar o dată , dar şi de a specializa şi a extinde anumite Atribute şi Servicii. 4. Asocierea - reprezintă reuniunea sau conexiunea ideilor (presupune alăturarea, legarea acelor lucruri care au loc la un moment dat în circumstanţe similare). 5. Comunicarea prin mesaje - se referă la interacţiunea prin mesaje între obiecte, interacţiune care corespunde modului imperativ al limbajelor (comandă, cerere).

6. Înglobarea metodelor de organizare. Strategia analizei poate fi construită pe baza a trei metode de organizare:

• diferenţierea între obiecte şi atributele lor (ex: a distinge între un copac şi înălţimea sa)

• diferenţierea dintre obiectul ca întreg şi părţile sale componente (ex: a distinge între un copac şi ramurile sale)

• diferenţierea diverselor clase de obiecte (ex: clasa pietrelor şi clasa arborilor)

Page 50: software engineering

3

Metoda de analiză orientată obiect Coad - Yourdon

Coad şi Yourdon descriu o metodă OOA bazată pe 5 activităţi majore: • identificarea claselor şi obiectelor

• identificarea structurilor

• identificarea subiecţilor

• identificarea atributelor

• identificarea serviciilor

Aceste activităţi (care nu reprezintă neapărat paşi secvenţiali) sunt folosite pentru a construi fiecare din cele cinci nivele ale modelului obiect. Obiectele există în domeniul problemei. Clasele sunt abstractizări ale obiectelor. Obiectele sunt instanţe ale claselor.

Primul obiectiv al metodei e de a identifica clasele şi obiectele.

Al doilea obiectiv e de a identifica structurile. Există 2 tipuri de structuri: • structuri generalizare-specializare (generalization-specialization); moştenirea este

posibilă intre membrii structurii.

• structuri parte-întreg (“whole-parts”); modelează relaţiile între entităţi.

Modelele mari, complexe, sunt organizate în subiecţi, fiecare subiect reprezentând un anumit punct de vedere al problemei. De exemplu, modelul obiect al unui motor ar putea prezenta un punct de vedere al mecanicului şi unul al electricianului. Atributele caracterizează fiecare clasă. De exemplu, un atribut al motorului unui vehicul este numărul de cilindri. Fiecare obiect va avea o valoare a atributului respectiv. Serviciile definesc funcţiunile sistemului.

Aceste activităţi conduc analistul de la nivele mari de abstractizare (clasele şi obiectele) spre nivele din ce în ce mai detaliate ale abstractizării (Structurile, Atributele şi Serviciile):

• Unii analişti preferă ordinea: Clase-Obiecte, Atribute, Structuri, Servicii.

• Alţii preferă ordinea: Clase-Obiecte, Servicii, Structuri, Atribute. Pentru proiectele mai complexe analiştii pot utiliza a 5-a activitate - cea a subiecţilor. Puterea metodei constă în descrierea scurtă, concisă şi folosirea unor texte generale ca surse

de definiţii. Principalul dezavantaj al metodei constă în notaţia complicată, dificil de folosit fără utilitare.

Modelul AOO este prezentat în 5 straturi: • stratul subiecţilor

• stratul claselor şi obiectelor

• stratul structurilor

• stratul atributelor

• stratul serviciilor

Page 51: software engineering

4

Activitatea I a metodei Coad-Yourdon: Identificarea claselor-obiectelor

O clasă poate fi privită ca o colecţie de obiecte care pot fi descrise prin aceleaşi Atribute şi Servicii. Obiectul (sinonim cu instanţa) reprezintă încapsularea Atributelor şi Serviciilor. Prin clasă&obiect vom înţelege un termen desemnând o clasă şi obiectele din acea clasă.

Motivele principale pentru care trebuie identificate clasele şi obiectele: • găsirea unei reprezentări tehnice a sistemului mai aproape de modul în care concepem

lumea înconjurătoare.

• se creează astfel o bază stabilă pentru analiză şi specificaţii: clasele şi obiectele pentru un sistem de control al traficului aerian pot fi aceleaşi şi peste 5 ani, doar serviciile şi atributele se pot modifica radical. Clasele şi obiectele sunt relativ stabile de-a lungul timpului, urmând ca, la apariţia modificărilor ulterioare, ele să constituie o bază pentru reutilizare.

• evitarea schimbării reprezentării de bază în momentul trecerii de la faza de analiză la cea de proiectare (această trecere este dificilă de la DFD ale analizei structurate la hărţile de structură specifice proiectării, sau de la DFD la o reprezentare obiect în faza de proiectare). Această problemă se rezolvă prin utilizarea unei reprezentări orientată-obiect atât în faza de analiză cât şi în fazele de proiectare şi implementare.

Notaţii

O clasă de bază, fără obiecte instanţiate, va fi reprezentată astfel:

O clasă cu obiecte instanţiate va fi reprezentată astfel:

Numele clasei:

• este un singur substantiv sau substantiv şi adjectiv

• se alege ţinând cont de vocabularul standard al domeniului problemei. Folosirea unei terminologii nefamiliare clientului îl frustrează şi-l face pe acesta să nu se simtă confortabil.

• se referă doar la un singur obiect al clasei

• trebuie să fie sugestiv

• se recomandă să se scrie folosind litere mari şi mici pentru a face uşoară citirea lor. Numărul de clase în modelul OOA depinde de complexitatea domeniului problemei: 35 este media; 110 clase deja sunt prea multe; pentru domenii ale problemei care conţin câteva sub-domenii (ex: controlul traficului aerian), ar putea exista 4-5 sub-domenii cu câte 50-100 clase pentru fiecare.

Nume clasă

Atribute (proprietăţi)

Servicii (metode)

Nume clasă&obiect

Atribute (proprietăţi)

Servicii (metode)

Page 52: software engineering

5

Unde cautăm ? Se recomandă investigarea domeniului problemei prin: • observare (ex: controlul traficului aerian - staţi un schimb întreg în locul unde se

desfăşoară activităţile ce au legătură cu sistemul, puneţi-vă în locul clientului, încercaţi să intuiţi problemele sale şi modul în care sunt sau ar trebui soluţionate)

• ascultare atentă - luaţi contact cu experţii în domeniu, ascultaţi cu atenţie, reveniţi pentru întrebări şi clarificări ale problemelor, puneţi-le întrebări despre domeniul problemei, de ce sunt mai importante unele aspecte decât altele, ce scenarii sunt semnificative şi de ce. Analiştii trebuie să aibă acces la informaţii din domeniu problemei. Ei trebuie să recurgă neapărat la ajutorul unui expert în domeniu. Ideal, echipa iniţială de analişti este formată din 3 super-analişti şi 3 experţi în domeniul problemei.

• verificarea rezultatelor anterioare ale OOA, pentru domenii similare ale problemei în ideea refolosirii unor clase şi obiecte deja identificate.

• documentaţie permanentă . Cereţi clientului un rezumat concis al domeniului problemei de 25, 50 sau 100 pagini. Consultaţi o documentaţie profesionistă, un excelent mod de a asimila terminologia şi conceptele fundamentale. Colectaţi orice diagramă, grafic, schemă bloc, etc. Construiţi diagrame, punând în evidenţă componentele ce vor interacţiona. În felul acesta veţi căpăta rapid o perspectivă asupra domeniului problemei.

• prototipul este esenţial pentru o analiză efectivă mai ales în cazul sistemelor care presupun o interacţiune om - computer. Clientul va trebui mereu temperat atrăgându-i mereu atenţia că nu prototipul este produsul final.

Ce căutăm ?

Pentru identificarea claselor şi obiectelor căutăm: • structuri - acestea sunt atât de importante încât există o activitate separată pentru

identificarea lor (Structurile Generalizare-Specializare şi structurile Whole-Parts, prezentate în detaliu în secţiunile următoare)

• alte sisteme - evidenţierea sistemelor (“terminatorilor externi”) care interacţionează cu sistemul în cauză.

• dispozitivele cu care sistemul va interacţiona

• evenimente/lucruri ce trebuie memorate - identificarea evenimentelor care trebuie înregistrate de sistem

• rolul factorului uman privind sistemul. Clasele şi obiectele reprezentând factorul uman se referă la:

- utilizatorii sistemului (funcţionarul care va interacţiona cu sistemul)

- persoanele care nu interacţionează direct cu sistemul dar informaţii despre aceste persoane sunt păstrate de sistem

Investigarea ulterioară a Serviciilor şi Atributelor va diferenţia în detaliu cele 2 categorii. • proceduri operaţionale pe care sistemul trebuie să le execute pentru a conduce

interacţiunile umane

Page 53: software engineering

6

• amplasamentul fizic - dacă e necesar ca sistemul să aibă informaţii despre acest lucru (pot fi sisteme care trebuie configurate la o anumită altitudine, longitudine, latitudine şi tip de relief. Ar putea deci exista o Clasă&Obiect de tip Amplasament)

• unităţi organizaţionale cărora aparţin factorii umani (de exemplu, în cazul unui funcţionar, acesta poate lucra într-un district, şi se poate deci lua în consideraţie o Clasă&Obiect DiviziuneRegională, dacă sistemul necesită informaţii despre acel district)

Odată identificaţi candidaţii pentru Clase&Obiect, aceştia trebuie examinaţi pentru a decide dacă vor fi în final incluşi în modelul OO. Criterii pentru această decizie pot fi:

• Sunt toate aspectele identificate relevante pentru sistem? Poate fi orice obiect al unei clase descris? Care sunt atributele lui potenţiale? (De exemplu, atributele potenţiale pentru un funcţionar sunt: nume, parolă, autorizaţie. Altele cum ar fi: înălţimea, semne particulare, greutate nu sunt relevante pentru sistem).

• Trebuie un obiect să execute anumite activităţi ?

• Este caracterizată o clasă prin mai multe Atribute? (o clasă cu un singur atribut este considerată suspectă)

• Este caracterizată o clasă prin mai multe Obiecte? (o clasă cu un singur obiect este considerată suspectă)

• Se poate identifica un set de Atribute aplicabile întotdeauna, tuturor obiectelor clasei ? De exemplu, setul de Atribute pentru Clasa&Obiect Clădire va conţine: adresa, preţul, mărimea. Dar NumărulDormitoare sau NumărulBăi se aplică doar anumitor clădiri. Acest lucru indică faptul că ar fi necesară o structură Generalizare - Specializare.

• se poate identifica un set de Servicii aplicabile întotdeauna, tuturor obiectelor clasei ? Dacă nu, atunci e necesară o structură Generalizare - Specializare.

• Toate clasele obiectele identificate trebuie să se concentreze asupra informaţiilor şi serviciilor cerute de sistem (nu se fac referiri la detalii de proiectare, deşi e bine ca acestea să fie reţinute, notate, încă din această fază. E posibil ca echipa de proiectare să adauge noi clase şi obiecte care să realizeze procesarea cerută de proiectare.) Se recomandă realizarea analizei şi specificaţiilor fără a ţine cont de o arhitectură specifică software sau hardware a sistemului, chiar dacă clientul garantează că ea nu se schimbă niciodată.

• Trebuie evitată reţinerea unor informaţii care rezultă din altele (Exemplu: nu are rost de a se reţine vârsta_persoanei dacă sistemul deja a înregistrat data_naşterii). Luaţi în consideraţie acele Atribute şi Servicii din care apoi se pot obţine rezultate derivate.

Exemplu - Sistemul senzor

Acest sistem monitorizează senzorii şi senzorii critici. Fiecare senzor este descris de: • modelul său (producătorul şi numărul)

• secvenţa de iniţializare (trimisă către senzor)

• conversie

• intervalul datelor

• stare (on, off, standby)

• valoare curentă

Page 54: software engineering

7

• valoare de prag În plus, senzorii critici sunt descrişi de toleranţă privind intervalul datelor. Sistemul

semnalează alarma când pragul senzorului este depăşit. Observaţii

Clasele&obiect potenţiale includ: - două dispozitive (Senzor şi SenzorCritic)

- un eveniment memorat (EvenimentAlarmă)

- rolul factorului uman (Funcţionar) pentru controlul senzorilor

Presupunem că pentru acest exemplu clientul doreşte omiterea memorării evenimentului şi al rolului factorului uman. Deci, modelul constă în două obiecte: Senzor şi SenzorCritic. Mai multe detalii vor fi puse în evidenţă prin următoarele activităţi OOA. Activitatea a II-a a metodei Coad-Yourdon: Identificarea structurilor

Această secţiune se referă la evidenţierea structurilor Generalization-Specialization (Gen-Spec) şi Whole-Parts (Întreg - Părţi).

Structura Gen-Spec poate fi văzută ca fiind aspectul de diferenţiere între clase, aspect al uneia din cele trei metode de organizare, utilizate de gândirea umană.

Exemplu: generalizarea vehicul şi specializarea camion. Mai puţin formal, din punct de vedere al specializării, Gen-Spec poate fi gândită în sensul de

este un fel de sau este o (Camion “este un” Vehicul). În cadrul structurii Gen-Spec se aplică principiul moştenirii.

Structura Whole-parts este una din cele trei metode de bază de organizare. Exemplu: Întregul vehicul şi partea motor. Mai puţin formal, din perspectiva întregului, structura Whole-Parts poate fi gândită ca o

structură are un sau are o. Exemplu: Vehicul are un motor. Cum identificăm structurile ?

Pentru fiecare Clasă&Obiect se examinează fiecare clasă pentru a pune în evidenţă structurile Gen-Spec, şi fiecare obiect pentru a identifica structurile Whole-Parts. Structurile Gen-Spec Notaţii

Senzor

SenzorCritic

Page 55: software engineering

8

În vârf se află o clasă de generalizare, iar pe nivelele următoare clase de specializare. (Liniile unesc clasele şi nu obiectele). Punctul de ramificare a liniilor spre specializări se reprezintă printr-un semicerc. Fiecare clasă-specializare este denumită astfel încât să aibă un înţeles de sine stătător. Numele cel mai potrivit este format din numele clasei generalizatoare urmat de numele naturii specializării.

Exemplu: Pentru generalizarea Senzor sunt preferate specializările SenzorCritic şi SenzorStandard faţă de numele Critic şi Standard.

Simbolurile Clasă&Obiect apar pentru toate specializările aflate pe nivelele cele mai de jos. Pe celelalte nivele, apar fie simbolurile Clasă&Obiect fie Clasă.

Folosirea unei Clase ca generalizare

Aici, un senzor este fie un senzor critic, fie un senzor standard. Senzor este o clasă fără obiecte corespunzătoare directe, dar cu obiecte corespunzătoare în clasele specializate. Deoarece nici un nou Atribut şi mici un nou Serviciu nu au fost adăugate senzorului standard, structura anterioară poate fi rescrisă astfel încât un senzor este fie un senzor critic, fie doar un senzor:

Generalizare

Specializare1

Specializare2

Senzor

Model SecvenţaIniţializar

e Conversie Interval Adresă Prag Stare

Initializează Monitorizează

SenzorCritic Toleranţă

Monitorizează

SenzorStandard

Page 56: software engineering

9

Folosirea unei Clase&Obiect ca generalizare Se recomandă ca structurile identificate: • să facă parte din domeniul problemei

• să facă parte din responsabilităţile sistemului

• să existe efectiv moşteniri între clase

De asemenea, se recomandă să se studieze rezultate anterioare (dacă există) ale analizei OO pentru probleme similare şi să se reutilizeze structuri Gen-Spec evidenţiate. Dacă sunt posibile multe specializări este util de a se considera întâi cea mai simplă specializare şi cea mai complicată, apoi de a considera diverse variante între cele două.

Unul din criteriile construirii unei structuri Gen-Spec este de a reflecta o generalizare-specializare în domeniul problemei. Aceste structuri nu trebuie construite doar pentru a extrage Atribute comune. Un exemplu de structură Gen-Spec eronată este următorul:

În acest exemplu chiar numele claselor nu reflectă o generalizare şi apoi o specializare.

Senzor

Model SecvenţaIniţială

Conversie Interval Adresă Prag Stare

ValoareInitializează

Monitorizează

SenzorCritic Toleranţă

Monitorizează

Localizare

Avion

Aeroport

Page 57: software engineering

10

Fiecare Structură Gen-Spec formează fie o ierarhie fie o latice. În practică, cea mai

obişnuită formă este de ierarhie. Exemplu:

Structură Gen-Spec ierarhie În acest exemplu, o persoană este fie posesor, fie funcţionar, fie şi posesor şi funcţionar, în

acelaşi timp. În ierarhia, se observă anumite redundanţe de-a lungul specializărilor. Această problemă se rezolvă prin structura Gen-Spec latice după cum se poate observa în exemplul următor:

Structură Gen-Spec pentru clasa Persoană, formă latice Acest exemplu evidenţiază că o persoană poate fi posesor, funcţionar sau şi posesor şi funcţionar. Specializarea PersoanăPosesorFuncţionar evidenţiază o clasă cu multiple generalizări.

PersoanăNumeLegal

Adresă

PersoanăPosesor CetăţeanAl

PersoanăFuncţionarDataNaşterii Identificator

Parolă Fotografie

PersoanăPosesorFuncţionarCetăţeanAl

DataNaşterii Identificator

Parolă Fotografie

PersoanăNumeLegal

Adresă

PersoanăPosesorCetăţeanAl

PersoanăFuncţionar DataNaşterii Identificator

Parolă Fotografie

PersoanăPosesorFuncţionar

Page 58: software engineering

11

Arată că un obiect din această clasă moşteneşte o combinaţie de Atribute şi Servicii de la predecesorii săi.

Se observă ca forma latice poate mări complexitatea structurii. Dacă acest lucru se întâmplă, se recomandă reorganizarea unor părţi din latice ca ierarhii.

Folosirea aceloraşi nume de Atribute şi Servicii în mai multe generalizări imediate, poate crea probleme în timpul specificării Claselor&Obiecte. Trebuie evitate asemenea conflicte de nume.

Exemplu: - Structură Gen-Spec latice, pentru Client şi Persoană

Această formă de Gen-Spec capturează o suprapunere între două structuri Gen-Spec diferite,

Client şi Persoană. Un client este fie o organizaţie (corporaţie, trust, întreprindere), fie o persoană individuală. O persoană este fie un client individual, fie un angajat, fie ambele. Deci, un obiect poate fi unul din următoarele: client organizaţie, client individual, angajat, angajat şi client individual, simultan.

Persoană

OrganizaţieClient

Client

IndividClientPersoan

AngajatPersoană

IndividClientAngajatPersoană

Page 59: software engineering

12

Structuri Întreg-Părţi Notaţii

Notaţia structurii Întreg-Parte

În partea superioară este reprezentat obiectul întreg al Clasei&Obiect, iar în partea inferioară părţi ale acestui obiect. Triunghiul face distincţia dintre întreg şi părţi. Se observă că liniile unesc între ele obiecte şi nu clase, reflectând o mapare între clase. Fiecare capăt al liniei este marcat cu un interval, indicând numărul de părţi pe care un întreg le poate avea şi numărul de întregi corespunzători unei părţi, la orice moment de timp . Exemple:

Un Avion este un ansamblu: • de 0 motoare (este un planor) • de cel mult 4 motoare

Un Motor este o parte din: • cel mult un avion • nu neapărat dintr-un avion

O organizaţie este o colecţie: • posibil, fără funcţionari • de cel mult m funcţionari

Un funcţionar este membru al unei singure organizaţii.

Dacă mapările către un alt Obiect de-a lungul timpului trebuie memorate, atunci acel Obiect

necesită un Atribut Data, sau Stare, pentru a distinge cele mai recente (respectiv active), Obiecte de celelalte.

Pentru identificarea potenţialelor structuri întreg-parte, se consideră aspectele:

Întreg

Parte1

Parte2

a,b e,f

c,d g,h

Avion

Motor

0,4

0,1

Organizaţie

Funcţionar

0,m

1

Page 60: software engineering

13

• ansamblu-părţi • container-conţinut • colecţie-membri În plus, se recomandă studiul rezultatelor AOO precedente, pentru evidenţierea eventualelor

structuri de acest tip, care ar putea fi refolosite.

Structură Întreg-Parte: ansamblu-părţi

Structură Întreg-Parte: container-conţinut Avionul este considerat un container, pilotul găsindu-se înăuntru. Dacă domeniul problemei şi responsabilităţile sistemului trebuie să asigneze un pilot unui avion, atunci o Clasă&Obiect Pilot este necesară.

Structură Întreg-Parte: colecţie - membri

O organizaţie este o colecţie de funcţionari.

Structură Întreg-Parte: colecţie - membri

Această structură este doar un “model mental” (părţile şi întregii nu sunt tangibili şi nici observabili) dar foarte util pentru a coordona complexitatea problemei.

Avion

Motor

0,4

0,1

Avion

Pilot

0,m

0,m

Organizaţie

Funcţionar

0,m

1

Misiune

SegmentDeZbor

0,m

0,m

Page 61: software engineering

14

Verificarea structurilor Întreg-Parte

Pentru fiecare obiect considerat întreg se verifică, pentru fiecare din părţile sale, dacă: • acea parte aparţine domeniului problemei şi interesează sistemul din punct de vedere al

serviciilor (Dacă domeniul problemei se referă la Serviciul meselor, atunci partea Motor pentru întregul Avion nu are sens. Dacă însă domeniul problemei este Transportul aerian, atunci ea are sens.)

• acea parte capturează mai mult decât o singură valoare de stare. (Dacă responsabilităţile sistemului includ doar cunoştinţe despre starea avionului - funcţional sau nefuncţional - sau starea motorului, atunci nu e necesară o clasă&obiect Motor. Este suficient de a se prevedea un Atribut Stare în clasa Avion. Dacă însă, sistemul trebuie să ştie mai mult despre motor - Model, NumărSerie, DataFabricaţiei etc., atunci este necesară o Clasă&Obiect Motor).

Considerând apoi fiecare obiect ca o parte potenţială dintr-un întreg, se verifică utilitatea prezenţei lui în acelaşi mod. Activitatea a III-a a metodei Coad-Yourdon: Identificarea Atributelor

Atributul = proprietate, calitate sau caracteristică pentru care fiecare Obiect al unei Clase are o anumită valoare.

Atributele adaugă detalii abstractizărilor Clasa&Obiect şi Structuri. Alegerea atributelor implică analiză şi decizii (exemplu: pentru Senzor - greutatea, culoarea, textura, deşi importante în alt context, nu sunt importante pentru exemplul nostru; în schimb, adresa, prioritatea, pragul acestuia sunt esenţiale.) Atributele descriu valori încapsulate în Obiect şi vor fi manipulate exclusiv de către Serviciile acelui Obiect. Atributele şi Serviciile Obiectului sunt tratate ca un întreg. Dacă o altă parte a sistemului doreşte să acceseze Atributele unui Obiect o poate face doar prin specificarea unui Mesaj de Conectare, corespunzător Serviciului definit de Obiect. De-a lungul timpului domeniul Claselor rămâne relativ stabil, în schimb, Atributele sunt mult mai susceptibile de a se modifica.

Se recomandă definirea Atributelor prin aplicarea următoarelor acţiuni: • Identificarea Atributelor

• Poziţia Atributelor

• Identificarea Conexiunii Instanţelor

• Verificarea cazurilor speciale

• Specificarea Atributelor Notaţii. Atributele se plasează în centrul secţiunii simbolurilor Clasa&Obiect şi Clasa. Identificarea Atributelor

Pentru fiecare Clasă&Obiect, urmărim: • cum sunt descrise obiectele în general

• cum sunt descrise obiectele în domeniul problemei

• cum sunt descrise obiectele în contextul responsabilităţilor sistemului

Page 62: software engineering

15

• ce anume trebuie memorat în timp

• care sunt stările în care se poate afla obiectul

• studiul rezultatelor anterioare a AAO în probleme similare pentru reutilizarea Atributelor

Identificarea atributelor trebuie să aibă în vedere următoarele aspecte; • fiecare Atribut trebuie să captureze un concept atomic (o singură valoare sau un grup de

valori, având acelaşi înţeles, ca de exemplu nume, format din nume şi prenume, sau adresa: compusă din ţara, oraşul, strada, numărul)

• identificarea Atributelor furnizează un mijloc de a referi un Obiect şi conexiunile sale cu alte Obiecte. Fiecare Obiect necesită asemenea identificatori. Fiecare Obiect are

- un identificator implicit (id pentru “identificator”) - identificatori pentru conectare (cid, pentru “identificatori de conectare”)

Aceşti identificatori sunt impliciţi în sensul că nu sunt arătaţi pe stratul Atributelor. Poziţia Atributelor

Fiecare Atribut va fi pus în Clasa&Obiect pe care o descrie mai bine.

Exemplu.

În sistemul de înregistrare a unui vehicul, culoarea acestuia este foarte importantă; ea este reţinută de sistem la momentul înregistrării vehiculului.

Este deci culoare un Atribut al Clasei&Obiect EvenimentÎnregistrare sau al Clasei&Obiect Vehicul ? Răspunsul este evident: Vehicul.

Pentru clasele care prezintă o structură Gen-Spec, se pune Atributul în cel mai de sus punct al structurii în care rămâne aplicabil pentru toate specializările sale.

Dacă un Atribut se aplică pe un nivel întreg de specializări, atunci este mutat pe nivelul generalizator corespunzător.

Exemplu:

Poziţionarea Atributelor

PersoanăNumeLegal

Adresă

PersoanăPosesorCetăţeanAl

PersoanăFuncţionar DataNaşterii Identificator

Parolă Fotografie

PersoanăPosesorFuncţionar

Page 63: software engineering

16

Identificarea Conexiunilor Instanţelor

Conexiunile instanţelor modelează principiul asocierii, un principiu pentru coordonarea complexităţii.

O conexiune a instanţelor e un model al mapărilor între domeniile problemelor Obiectelor.

Notaţie

Notaţia Conexiunea Instanţelor

Conexiunea Instanţelor e reprezentată printr-o linie unind Obiectele (părţile laterale ale

acestora). Fiecare Obiect are o cantitate (a) sau interval (a,b), marcate pe conexiune, reflectând restricţiile conexiunilor cu alte Obiecte.

Limitele intervalului: • Limita inferioară = 0, dacă este o conexiune opţională

= 1 sau mai mare, dacă e o conexiune obligatorie • Limita superioară = 1, dacă este o singură conexiune

>1, dacă sunt conexiuni multiple Exemplu:

Conexiunea Instanţelor- exemplu Un anumit plan de zbor trebuie pregătit pentru exact un avion. Fiecare avion poate fi pregătit pentru 0 sau mai multe planuri de zbor (un plan de zbor are o conexiune cu un anumit avion; un avion are mai multe conexiuni cu planurile de zbor).

Strategie • Se revăd rezultatele AOO anterioare pentru probleme similare, pentru refolosirea

conexiunilor evidenţiate.

• Pentru fiecare Obiect, se adaugă conexiuni spre alte Obiecte, reflectând mapări. Conectarea cu o Structură Gen-Spec se face prin nivelul cel mai din vârf al structurii.

• Pentru fiecare Obiect, se defineşte intervalul conexiunilor, din perspectiva fiecărui Obiect.

Verificarea cazurilor speciale privind Atributele • Se verifică pentru fiecare Atribut dacă sunt cazuri când nu sunt aplicabile

a,b c,d

Avion

PlanDeZbor

0,m 1

Page 64: software engineering

17

Exemplu:

Atributul Tracţiune poate avea valorile: petrol, diesel, electric. Dar pentru anumite vehicule, care nu au motor, acest atribut poate avea valoarea “Inaplicabil”. Dacă este un astfel de caz, trebuie reanalizată strategia Gen-Spec, verificând dacă nu mai sunt necesare structuri Gen-Spec care n-au fost cuprinse în model. • verifică fiecare Clasă&Obiect care are doar un Atribut, caz în care:

- fie Clasa&Obiect are un singur Atribut pentru că aşa impun responsabilităţile sistemului

Exemplu:

Plasarea unui singur Atribut într-o Clasă&Obiect, pe care o descrie

- fie Atributul nu este bine poziţionat, el aparţinând unei alte Clase&Obiect. Exemplu:

Plasarea unui Atribut în Clasa&Obiect pe care o descrie.

Verificând domeniul problemei, se constată că în loc de cele două simboluri din stânga (Garanţie şi Adresă) se poate folosi doar cel din dreapta. Specificarea Atributelor

• Numele Atributelor trebuie să fie sugestive, din domeniul problemei • Specificarea unui Atribut este însoţită de o sumară descriere a sa

• Specificarea unui Atribut este însoţită de eventuale restricţii: - unitate de măsură, intervale - precizie - valoare implicită - trebuie acest Atribut setat ? - în ce condiţii sunt permise Serviciile de creare şi acces - în ce măsură este afectat de valorile altor atribute

Vehicul

............... Tracţiune

Funcţionar

Nume

Adresă Adresă

Garanţie

Nume Cantitate

Garanţie

Nume Cantitate Adresă

Page 65: software engineering

18

Exemplu de specificare a Atributelor:

Specificaţie Senzor Atribut Model: numărul modelului Atribut SecvenţaInit: secvenţa de iniţializare Atribut Conversie: constă din factori de scalare şi unităţi de măsură Atribut Interval: intervalul de valori pentru senzor Atribut Adresă: adresa acestui senzor Atribut Prag: valoare de prag la care se semnalează alarma Atribut Stare: starea senzorului (on, off, standby) Atribut Valoare: cea mai recentă valoare a senzorului

Exemplu pentru Identificarea Atributelor - Sistemul Senzor

Unele Atribute îşi schimbă foarte rar valoarea (Model, SecvenţăIniţială, Conversie), altele îşi schimbă valoarea mai des (Interval, Adresa, Prag, Stare), iar altele sunt dinamice (Valoare).

Atributul Valoare este rezultatul citirii unei valori în unităţi fizice (ex: volţi ) şi conversia ei în unităţi standard de măsură. Poate fi tratată ca o valoare recalculabilă şi în acest caz nu e nevoie de un Atribut Valoare. Dar e posibil ca sistemul să necesite cunoaşterea acestei valori în orice moment, indiferent de starea Senzorului (chiar dacă Senzorul este în starea standby, în care valoarea nu poate fi citită şi deci, calculată). Este posibil deci, ca Atributul Valoare să nu poată fi recalculat de fiecare dată, şi atunci se impune existenţa acestui Atribut.

Sistemul Senzor: Stratul Clase&Obiecte, stratul Structurilor şi stratul Atributelor

Senzor

Model SecvenţaIniţializar

e Conversie Interval Adresă Prag Stare

Valoare

SenzorCritic

Toleranţă

Page 66: software engineering

19

Activitatea a IV-a a metodei Coad-Yourdon: Identificarea Serviciilor

În analiza orientată obiect se recomandă ca identificarea serviciilor să se realizeze după identificarea Claselor&Obiectelor, Structurilor şi Atributelor.

Serviciul este definit ca fiind o operaţie specifică a unui Obiect. Pe lângă evidenţierea acestor Servicii se pune problema şi de a defini comunicaţiile necesare între Obiecte (Message Connections). Notaţii

Strategia definirii Serviciilor constă în următoarele activităţi: • 1 Identificarea stărilor Obiectelor • 2 Identificarea Serviciilor • 3 Identificarea Conexiunilor-Mesaje între Obiecte • 4 Specificarea Serviciilor • 5 Realizarea documentaţiei finale OOA

1 Identificarea Stărilor Obiectelor

Starea unui Obiect este reprezentată de valorile atributelor sale. Pentru a identifica Starea

Obiectului: • se examinează valorile potenţiale ale Atributelor

• se determină dacă sistemul are comportări diferite pentru aceste valori

• se examinează rezultatele analizei OO anterioare Exemplu: care din Atributele sistemului Senzor reflectă o schimbare în starea Obiectului ? Atributele sistemului sunt: Model, SecvenţaIniţializare, Conversie, Interval, Adresă, Prag,

Stare, Valoare. Pentru acest sistem valorile Atributelor: Model, SecvenţaIniţializare, Conversie, Interval, Adresă, Prag nu implică o modificare a comportării sistemului. Dar atributul Stare reflectă o schimbare în comportarea sistemului. Valorile sale sunt: on, off şi standby. Diagramele Stărilor Obiectelor prezintă diferitele stări ale sistemului în timp. Notaţia pentru diagramele stărilor obiectelor: Stare

Clasă&Obiect

Serviciul1 Serviciul2

Clasă

Serviciul1 Serviciul2

Stare

Tranziţie

Page 67: software engineering

20

Exemplu: sistemul Senzor - diagrama stărilor obiectului

În acest exemplu, săgeata din vârf indică starea iniţială. Sunt prezentate doar stările şi

tranziţiile legale. 2 Identificarea Serviciilor

• servicii algoritmic-simple

• servicii algoritmic-complexe

Serviciile algoritmic-simple constau în specificarea unor servicii care se aplică fiecărei Clase&Obiect. Acestea sunt implicite, ele nu sunt reprezentate pe stratul Serviciilor. Cele 4 tipuri de servicii algoritmic-simple sunt:

• create - creează şi iniţializează un nou Obiect într-o clasă

• connect - conectează un Obiect cu altul. Acest Serviciu stabileşte sau anulează o mapare dintre Obiecte.

• acces - setează sau extrage valoarea unui Atribut al unui Obiect

• release (distrugere)- eliberează (distruge) un Obiect Majoritatea operaţiunilor unui sistem (80%-95%) se concentrează în serviciile algoritmic-

simple. Serviciile algoritmic-complexe constau în 2 tipuri de Servicii:

• Calculate (Calculează) - calculează un rezultat folosind valorile unor Atribute

• Monitor (Monitorizează) - supraveghează un sistem extern sau dispozitiv. Tratează intrările şi ieşirile sistemului extern, achiziţionează şi controlează date.

3 Identificarea Conexiunilor - Mesaje între Obiecte

O Conexiune prin Mesaje este o mapare de la un Obiect spre altul (sau spre o clasă, pentru a crea un nou obiect), în care un transmiţător trimite un mesaj către un receptor, pentru a executa o anumită procesare. Procesarea este denumită în specificarea Serviciilor transmiţătorului şi este definită în specificarea Serviciilor receptorului. Conexiunile prin Mesaje există doar în beneficiul Serviciilor.

Stare=off

Stare=standby

Stare=on

Page 68: software engineering

21

Notaţie Săgeata uneşte Obiecte.

Receptorul primeşte mesajul, execută operaţiunea corespunzătoare şi returnează un rezultat transmiţătorului.

Firele de execuţie pot fi denumite, definite şi reprezentate cu diferite pattern-uri de linii pentru fiecare fir. Cu ajutorul mediilor CASE:

• firele de execuţie pot fi denumite, definite şi reprezentate diferit

• un Serviciu poate fi selectat, pentru a vedea ce mesaje îl invocă şi ce mesaje trimite. Pentru Conexiuni prin Mesaje de la un Obiect spre mai multe Obiecte, există următoarea

notaţie:

Interacţiunile dintre factorul uman şi sistem sunt şi ele reprezentate în modelul OOA.

Pentru a evidenţia Conexiunile prin Mesaje între Obiecte, se pun următoarele întrebări pentru fiecare Obiect:

• de Serviciile căror alte Obiecte are nevoie? Se trasează câte o săgeată către fiecare din aceste Obiecte.

• ce alte obiecte au nevoie de Serviciile lui ? Trasează câte o săgeată dinspre fiecare din aceste Obiecte.

• urmăreşte conexiunea prin mesaj spre Obiectul destinatar şi repetă aceleaşi întrebări.

• examinează rezultatele analizei OO anterioare.

În aplicarea acestei strategii, analistul este interesat în firele execuţiei, formate din mesajele de la un obiect la altul. Firele execuţiei pot fi analizate mai departe (pentru determinarea completitudinii modelului) şi se pot impune constrângeri asupra lor, mai ales pentru sistemele de timp real. Firele de execuţie apar în specificaţiile Claselor&Obiecte, secţiunea Serviciilor sau în hărţile Serviciilor. 4 Specificarea Serviciilor

Serviciile se specifică în Clasele&Obiect, folosind o harta Serviciului pentru fiecare Serviciu.

Transmiţător Receptor

Transmiţător

Transmiţător

Page 69: software engineering

22

specification attribute attribute …. attribute ExternalInput ExternalOutput

objectStateDiagram additionalConstraints note service <nume & harta serviciului> …… service <nume & harta serviciului>

Harta Serviciului prezintă grafic cerinţele Serviciului:

Notaţiile Hărţii Serviciului

Notaţia Hărţii Serviciului furnizează un mijloc de a aplica principiul abstractizării procedurale sistematic, în contextul limitat al unui singur Serviciu. Exemplul 1 – Create

Harta Serviciului pentru Serviciul implicit Create

Condiţie (if; precondiţie; trigger, terminare)

Bloc text

Buclă (while; do; repeat; terminare)

Conector (conectat la simbolul următor, cel mai din vârf )

Verifică valorile atributului funcţie de restricţiile acestuia şi ale conexiunii

Sunt restricţii?NU

returnează eroare;

DA

creează; iniţializează;

returnează succes;

creează; iniţializează;

returnează warning;

doar restricţii ale atributului

Page 70: software engineering

23

Exemplul 2. Specificarea Clasei&Obiect Senzor

Se observă cum harta serviciului exprimă comportarea dependentă de stare folosind precondiţia, trigger (declanşator) şi terminare.

A se observa utilizarea mecanismului de moştenire în specificarea Atributelor şi Serviciilor în cazul Senzorului Critic. Specification: Senzor attribute Model: numărul modelului attribute SecvenţaIniţializare: secvenţa de iniţializare attribute Conversie: constă din factor de scalare, unităţi de măsură attribute Interval: intervalul de date (de eşantioane) pentru acest Senzor attribute Adresă: adresa acestui Senzor attribute Prag: valoarea de prag, indicând alarma attribute Stare: starea senzorului (monitor, off, standby) attribute Valoare: cea mai recentă valoare a senzorului şi convertită în unităţi de măsură ExternalInput CitireSenzor: datele citite de la Senzor ExternalOutput ControlSenzor: comanda de control trimisă spre Senzor

objectStateDiagram

service Iniţializează(out: rezultat)

Stare=off

Stare=standby

Stare=on

Trimite SecvenţaIniţializare către interfaţa SenzorControl a actualului Senzor, la Adresa sa

Precondiţie: State<>monitor

NU

Stare=standby

DA

returnează rezultatul transmiţătorului

Page 71: software engineering

24

service EşantioneazăSenzor (selectează)(out: rezultat)

service MonitorizeazăCondiţiaDeAlarmă

specification SenzorCritic

attribute Toleranţă: intervalul de date de toleranţă pentru acest senzor service Eşantionează (out: rezultat)

citeşte CitireSenzor din actualul Senzor,la Intervalul corespunzător

returnează CitireSenzor

citeşte CitireSenzor din actualul Senzor,la Intervalul şi Toleranţa

corespunzătoare

returnează CitireSenzor

La Intervalul specificat, trimite un mesaj către CitireSenzor (out: CitireSenzor)

Declanşare când Stare=monitor; terminare când Stare<>monitor

Precondiţie: Stare=standby

converteşte data în unităţi actuale, folosind Valoare=(Conversion.bias*CitireSenzor)+Conversion.offset

Valoare>=Prag?

raportează alarmă

DA

NU

Page 72: software engineering

25

5 Realizarea documentaţiei finale OOA

Documentaţia finala a modelului AOO conţine: • cele 5 straturi ale modelului OOA

• specificaţiile Claselor si Obiectelor.

Exemplu: Sistemul Senzor Se observa Serviciile şi moştenirea Serviciilor în Structura Gen-Spec. Serviciile Senzorului sunt:

Iniţializează, Eşantionează, MonitorizeazăCondiţiaDeAlaramă Serviciile SenzoruluiCritic sunt:

Iniţializează, Monitorizează, Eşantionează (care este extins în SenzorCritic)

Sistemul Senzor: straturile Claselor&Obiecte, Structurilor şi Serviciilor Activitatea a V-a a metodei Coad-Yourdon: Identificarea subiecţilor

În AOO termenul de Subiect este un mecanism de pentru ghidarea cititorului (analist, manager, expert, utilizator, client) în înţelegerea unui model de analiză foarte mare şi complex. Subiecţii oferă o imagine de perspectivă asupra unui model complex. Numărul de clase în modelul AOO este dependent de complexitatea problemei. În medie poate fi de 30-35 clase. 100 de clase sunt deja prea multe. Dar pot exista domenii ale unor probleme care la rândul lor se impart în sub-domenii, fiecăruia corespunzându-I 50-100 de clase. Astfel de modele sunt foarte dificil de înţeles dacă nu există un mecanism de coordonare a acestei complexităţi. Cum se selectează Subiecţii ?

Fiecare Clasă din vârful fiecărei Structuri se asignează unui Subiect. Fiecare Clasă&Obiect care nu face parte din nici o Structură se asignează, de asemenea, unui Subiect. Se recomandă studiul rezultatelor anterioare ale analizei OO pentru probleme similare pentru a se utiliza Subiecţi identificaţi deja.

Senzor

Iniţializează Eşantionează

Monitorizează

SenzorCritic

Eşantionează

Page 73: software engineering

26

Cum se rafinează Subiecţii ? Subiecţii se rafinează utilizând sub-domeniile problemei. De fapt, se aplică principiul

întreg-parte pe domeniul problemei. Rafinarea ia în consideraţie interdependenţele şi interacţiunile minimale între Subiecţi. “Interdependenţele” sunt exprimate de Structuri (Identificarea Structurilor) şi de Conexiunea Instanţelor (Identificarea Atributelor). “Interacţiunile” sunt exprimate de Conexiunile prin Mesaje (Message Connections - Identificarea Serviciilor) . Se folosesc deci, straturile Structurilor, Atributelor şi Serviciilor în stabilirea şi rafinarea Subiecţilor. Cum se construiesc ?

În stratul Subiecţilor, un Subiect se reprezintă printr-un dreptunghi, fiind etichetat în interior

cu un nume şi un număr şi conţinând şi lista claselor care fac parte din acel Subiect. Practic, pentru modele foarte complexe, Subiecţii se pot reprezenta în 3 moduri:

• Subiecţi neexpandaţi (doar dreptunghiul cu numele şi numărul lor)

Figura: Notaţia Subiectului neexpandat

• Subiecţi parţial expandaţi (conţinând lista claselor-obiecte componente)

Figura: Notaţia Subiectului parţial expandat (opţiune CASE)

• Subiecţi total expandaţi (când se reprezintă împreună cu alte straturi ale modelului

OOA, prin zone partiţionate şi numerotate)

Figura: Notaţia Subiectului total expandat

2. Subiect 1

Clasa&Obiect1 Clasa&Obiect2

1 1

1 1

1. Subiect 1

2. Subiect 2

1. Subiect 2

Clasa&Obiect3 Clasa&Obiect4

2 2

2 2

Page 74: software engineering

27

Clasă&Obiect poate face parte din mai mulţi Subiecţi (când e necesar pentru ghidarea cititorului). Subiecţii pot conţine la rândul lor Subiecţi, furnizând astfel o hartă multi-nivel. Când se introduc Subiecţii în model ?

În general, Subiecţii sunt necesari pentru modele relativ mari, având aproximativ 30-40 clase. Identificarea Subiecţilor se va face după ce Clasele şi Obiectele au fost identificate şi bine înţelese. Exemplu - Sistemul Senzor

Sistemul Senzor este atât de mic încât nu necesită un mecanism pentru ghidarea cititorului. Dacă totuşi dorim introducerea unui strat Subiect, este suficient unul singur.

Stratul Subiecţilor

Exemplu- Sistemul de Transport Aerian cu identificarea stratului Subiecţilor, Claselor&Obiectelor,

Structurilor şi Serviciilor Clasele din vârfurile Structurilor sunt: • Misiune, SegmentDeZbor, Încărcătură • Avion, DefecţiuneAvion • Traiectorie • Radar Rafinarea Subiecţilor, prin combinarea: Misiune, SegmentDeZbor, Încărcătură într-un singur Subiect: • Misiune • Avion, DefecţiuneAvion • Traiectorie • Radar Rafinare suplimentară, combinând prin: • interacţiune: Radar, Localizare, Traiectorie (vezi Identificarea Serviciilor) • interdependenţă: Avion, DefecţiuneAvion (vezi Identificarea Atributelor) Rezultă Subiecţii: • Misiune • Poziţionare • Avion Rafinare prin combinarea sub-domeniilor problemei: • Misiune • Transport aerian

Stratul subiecţilor

1. Senzor

1. Misiune 2. Transport aerian

Page 75: software engineering

28

Sistemul de transport aerian – stratul Subiecţilor, stratul Clase&Obiecte, stratul Structurilor şi stratul Serviciilor

Misiune

DefecţiuneAvion

Avion

Radar

CautăÎnSpaţiu

SegmentZbor

2,m

0,m

Traiectorie

ConstruieşteTraiectorie

PrezicePoziţie

Localizare

0,m

Încărcătură

ÎncărcăturăCargo

Pasageri

0,1

0,m

0,1 0,1

0,m

(1)

(2)

2 2

2 2

1 1

1 1

Page 76: software engineering

UML – Unified Modeling Language

Introducere

Problema principală care apare în dezvoltarea programelor este complexitatea. Folosirea de modele poate înlesni abordarea de probleme complexe.

Un model este o simplificare unui anumit sistem, ce permite analizarea unora dintre proprietăţile acestuia. Lucrul cu modelele poate facilita o mai bună înţelegere a sistemului modelat, datorită dificultăţii intrinseci de înţelegere a sistemului în întregul sau.

Folosirea tehnicii ” divide et impera” permite înţelegerea părţilor componente ale unui sistem, iar ansamblul sistemului ca o interacţiune între părţile acestuia. Un model reuşit reţine caracteristicile importante ale obiectului modelat şi le ignoră pe cele irelevante. De remarcat că noţiunile de important / irelevant sunt relative, ele depinzând de scopul pentru care se face modelarea. Astfel apare plauzibilă construirea mai multor modele pentru un anumit obiect, fiecare surprinzând anumite aspecte ale acestuia.

Orice metodologie de dezvoltare a programelor abordează problema comunicării între membrii echipei. Este posibil să apară situaţii în care modelul construit de proiectant să nu fie înţeles exact de cel ce scrie cod, fie din cauza lipsei de precizie a modului în care este prezentat modelul, fie datorită lipsei unor elemente importante ale acestuia; adesea o serie de amănunte subtile ce sunt evidente pentru designer nu sunt transmise. O rezolvare a problemei comunicării ar fi ca aceeaşi persoană să fie implicată direct în toate fazele dezvoltării. Chiar şi aşa, apare des situaţia în care o persoană trebuie să continue munca alteia.

Se impune aşadar existenţa unui limbaj formal de comunicare al cerinţelor. Termenul formal este esenţial. De obicei, chiar şi în proiecte de dimensiuni reduse, se

face modelare, însă într-un limbaj specific celui care modelează, determinat de viziunea asupra problemei şi de pregătirea acestuia. Folosirea unui limbaj ”intern” nu trebuie privită ca negativă, ea având se pare un rol esenţial în gândire în general şi în modelare în particular. Modelarea este posibilă, chiar şi fără folosirea explicită a unui limbaj.

Formalismul limbajului de modelare constă în stabilirea de elemente cu o semantică asupra căreia se convine şi cu ajutorul cărora să se poată transmite idei în mod cât mai eficient şi mai puţin ambiguu.

Limbajul de modelare UML îşi propune să definească o modalitate cât mai precisă, generală şi extensibilă de comunicare a modelelor. El a fost creat în primul rând pentru a facilita proiectarea programelor, însă datorită expresivităţii sale poate fi folosit şi în alte domenii (proiectare hardware, modelarea proceselor de afaceri etc.). Folosirea UML facilitează comunicarea modelelor, însă nu asigură crearea unui model bun. Limbajul de modelare nu specifică şi nu poate specifica ce modele trebuie create, în ce ordine şi cum trebuie ele utilizate pentru un sistem particular.

Începând cu mijlocul anilor 1970 şi continuând în anii 1980 au apărut diverse limbaje de modelare, odată cu creşterea experienţei de lucru în cadrul paradigmei orientate obiect. Astfel, numărul de limbaje de modelare ajunge de la 10 până la mai mult de 50 în perioada 1989-1994.

Limbajele de modelare de succes din această perioadă sunt: • Booch - potrivită mai ales pentru proiectare şi implementare, cu dezavantajul

unor notaţii complicate; • OOSE (Object-Oriented Software Engineering) - această metodă a propus aşa-

numitele cazuri de utilizare, care ajutau la înţelegerea comportamentului întregului sistem;

Page 77: software engineering

• OMT - Object Modeling Technique - potrivită pentru analiză şi sisteme informaţionale cu multe date.

La mijlocul anilor 1990, când este semnalată o nouă generaţie de limbaje de modelare, a

început un proces de omogenizare, prin încorporarea în fiecare limbaj a caracteristicilor găsite în celelalte limbaje.

Cei trei autori ai limbajelor de modelare principale, Booch, Jacobson şi Rumbaugh au ajuns la concluzia ca ar fi mai bine să conducă evoluţia limbajelor lor pe un acelaşi drum, pentru a elimina diferenţele gratuite ce nu făceau decât sa încurce utilizatorii. Un al doilea motiv a fost unul pragmatic, reieşit din necesitatea industriei software de a avea o oarecare stabilitate pe piaţa limbajelor de modelare. Al treilea motiv a fost convingerea că prin unirea forţelor se pot aduce îmbunătăţiri tehnicilor existente.

Dezvoltarea UML a început în mod oficial în octombrie 1994, când Rumbaugh s-a alăturat lui Booch în cadrul companiei Rational Software, ambii lucrând la unificarea limbajelor Booch şi OMT.

Versiunea preliminară 0.8 a Unified (Metoda Unificată - aşa cum era numită atunci) a fost publicată în octombrie 1995. Tot atunci, Jacobson s-a alăturat echipei de la Rational şi scopul UML a fost extins pentru a include şi OOSE. În iunie 1996 a fost publicată versiunea 0.9 a UML. Pe parcursul anului 1996, ca o consecinţă a reacţiilor comunităţii proiectanţilor de sistem, a devenit clar ca UML este văzut de către multe companii ca o opţiune strategică pentru dezvoltarea produselor lor.

A fost creat un consorţiu UML format din organizaţii doritoare să aloce resurse pentru a obţine o definiţie finală a UML. Dintre aceste companii care au contribuit la crearea UML 1.0 au făcut parte DEC, Hewlet-Packard, I-Logix, Intellicorp, IBM, MCI Systemhouse, Microsoft, Oracle, Rational, Texas Instruments etc.

UML 1.0 a fost propus spre standardizare în cadrul OMG în ianuarie 1997. Până la sfârşitul anului 1997 echipa care lucra la UML s-a extins, urmând o perioadă în

care UML a primit o specificare formală mai riguroasă. Versiunea UML 1.1 a fost adoptată ca standard de către OMG în noiembrie 1997.

Versiunea 1.2 a UML a fost o revizie editorială; versiunile 1.3 au fost publicate începând cu sfârşitul anului 1998.

În septembrie 2001 a fost publicată versiunea 1.4 şi în martie 2003 a fost versiunea 1.5.

În octombrie 2004 a fost introdusă versiunea 2.0.

UML este un limbaj de modelare bazat pe notaţii grafice folosit pentru a specifica, vizualiza, construi şi documenta componentele unui program.

UML este un limbaj cu ajutorul căruia se pot construi (descrie) modele. Un model surprinde un anumit aspect al unui program şi acelaşi model poate fi descris la diferite nivele de abstractizare. Fiecărui model îi corespunde o diagramă. Tipurile de diagrame existente în UML sunt:

Diagrama cazurilor de utilizare (Use Case Diagram)

Diagrama de clase (Class Diagram)

Diagrame care descriu comportamentul:

• Diagrame de interacţiuni (Interactions Diagrams)

- Diagrama de secvenţă (Sequence Diagram)

- Diagrama de colaborare (Collaboration Diagram)

Page 78: software engineering

• Diagrama de stări (State chart Diagram)

• Diagrama de activităţi (Activity Diagram)

Diagrame de implementare:

• Diagrama de componente (Component Diagram)

• Diagrama de plasare (Deployment Diagram)

Fiecăreia din cele trei mari faze din dezvoltarea un proiect software îi corespund una sau

mai multe diagrame UML şi anume:

- pentru faza de analiza se utilizează diagrama cazurilor de utilizare şi diagrama de activităţi;

- în faza de proiectare se folosesc: diagrama de clase pentru precizarea structurii sistemului şi diagramele de stări şi interacţiune pentru descrierea comportamentului acestuia;

- în faza de implementare se utilizează diagramele de implementare.

1. Diagrama cazurilor de utilizare (Use Case Diagram)

O diagramă use case este una din diagramele folosite în UML pentru a modela aspectele dinamice ale unui program alături de diagrama de activităţi, diagrama de stări, diagrama de secvenţă şi diagrama de colaborare. Altfel spus, diagramele use case se utilizează pentru:

• pentru a modela contextul unui sistem: determinarea graniţelor sistemului şi a actorilor cu care acesta interacţionează. • pentru a modela cerinţele unui sistem: ce trebuie să facă sistemul (dintr-un punct de vedere exterior sistemului) independent de cum trebuie să facă. Va rezulta specificarea comportamentului dorit. Sistemul apare ca o cutie neagră. Ceea ce se vede este cum reacţionează el la acţiunile din exterior. Elementele componente ale unei diagrame use case sunt:

- use case-uri;

- actori;

- relaţiile care se stabilesc între use case-uri, între actori şi între use case-uri şi actori.

Use case-uri

Un use case (caz de utilizare) reprezintă cerinţe ale utilizatorilor. Este o descriere a unei mulţimi de secvenţe de acţiuni (incluzând variante) pe care un program le execută atunci când interacţionează cu entităţile din afara lui (actori) şi care conduc la obţinerea unui rezultat observabil şi de folos actorului. Un use case descrie ce face un program sau subprogram, dar nu precizează nimic despre cum este realizată (implementată) o anumită funcţionalitate.

Fiecare use case are un nume prin care se deosebeşte de celelalte use case-uri. Acesta poate fi un şir arbitrar de caractere, însă de regulă numele sunt scurte fraze verbale care denumesc un comportament ce există în vocabularul sistemului ce trebuie modelat.

Figura 1.1 prezintă notaţia grafică pentru use case.

Page 79: software engineering

Figura 1.1: Notaţia grafică pentru use case

Comportamentul unui use case poate fi specificat descriind un flux de evenimente într-un text suficient de clar ca să poată fi înţeles de cineva din exterior (de exemplu utilizatorul). Acest flux de evenimente trebuie să includă cum începe şi se termină use case-ul atunci când acesta interacţionează cu actori, ce obiecte sunt interschimbate, precum şi fluxuri alternative ale acestui comportament. Aceste fluxuri de evenimente reprezintă scenarii posibile de utilizare a sistemului.

Identificarea use case-urilor se face pornind de la cerinţele utilizatorului şi analizând descrierea problemei. Actori

Un actor reprezintă idealizarea unei peroane, proces sau obiect exterior care interacţionează cu un sistem, subsistem sau o clasă. Actorii sunt entităţi exterioare sistemului. Ei pot fi utilizatori (persoane), echipamente hardware sau alte programe. Fiecare actor are un nume care indică rolul pe care acesta îl joacă în interacţiunea cu programul.

Notaţie grafică pentru un actor este ilustrată în figura 1.2.

nume

Figura 1.2: Notaţia grafică pentru actor

Există două moduri în care actorii pot interacţiona cu un sistem: • folosind sistemul, adică iniţiază execuţia unor use case-uri; • sunt folosiţi de către sistem, adică oferă funcţionalitate pentru realizarea unor use

case-uri.

Fiecare actor trebuie să comunice cu cel puţin un use case.

Pentru identificarea actorilor ar trebui să răspundem la următoarele întrebări: • Cine foloseşte programul? • De cine are nevoie programul pentru a-şi îndeplini sarcinile? • Cine este responsabil cu administrarea sistemului? • Cu ce echipamente externe trebuie să comunice programul? • Cu ce sisteme software externe trebuie să comunice programul? • Cine are nevoie de rezultatele (răspunsurile) oferite de program?

Relaţii

După cum am mai precizat, relaţiile exprimă interacţiuni între use case-uri, între actori şi între use case-uri şi actori. Relaţiile pot fi de mai multe tipuri: asociere, dependenţă şi generalizare.

Page 80: software engineering

Relaţia de asociere se defineşte între actori şi use case-uri, sau între use case-uri. Este folosită pentru a exprima interacţiunea (comunicarea) între elementele pe care le uneşte. Relaţia de asociere se reprezintă grafic printr-o linie şi este evidenţiată în exemplele din figurile 1.3 şi 1.4.

Fig. 1.3. Exemplu de asociere între use case-uri

Fig. 1.4. Exemplu de asociere între actor şi use case

Relaţia de dependenţă se poate stabili numai între use case-uri. Acest tip de relaţie modelează două situaţii:

• cazul în care un use case foloseşte funcţionalitatea oferită de un alt use case - dependenţa de tip include;

• există variante ale aceluiaşi use case – dependenţa de tip extend.

Dependenţa de tip include. Notaţia grafică este dată în figura 1.5.

Fig. 1.5. Dependenţă de tip include

În acest caz comportamentul use case-ului B este inclus în use case-ul A. B este de sine

stătător, însă este necesar pentru a asigura funcţionalitatea use case-ului de bază A. În exemplul din figura 1.6, use case-ul Stabileste grupul care lucreaza la campanie are o relaţie de dependenţă de tip include cu use case-ul Gaseste campanie. Aceasta înseamnă că atunci când actorul Manager campanie utilizează Stabileste grupul care lucreaza la campanie, comportamentul use case-ului Gaseste campanie va fi inclus pentru a putea selecta o campanie relevantă.

Fig. 1.6. Diagramă use case cu dependenţă de tip include

Dependenţa de tip include se foloseşte şi pentru a scoate în evidenţă un comportament

comun (B poate fi inclus în mai multe use case-uri de bază – vezi figura 1.7).

Fig. 1.7. Dependenţă de tip include în care un use case este inclus

în mai multe use case-uri de bază

Page 81: software engineering

Dependenţa de tip extend. Notaţie grafică se poate vedea în figura 1.8.

Fig. 1.8. Dependenţă de tip extend

În acest caz comportamentul use case-ului B poate fi înglobat în use case-ul A. A şi B

sunt de sine stătătoare. A controlează dacă B va fi executat sau nu (vezi exemplul din figura 1.9).

Fig. 1.9. Exemplu de dependenţă de tip extend

Într-o dependenţă de tip extend pot apărea aşa numitele puncte de extensie care specifică

locul în care use case-ul specializat (B) extinde use case-ul de bază (A). Pentru fiecare use case pot fi specificate mai multe puncte de extensie. Fiecare dintre aceste puncte trebuie să aibă un nume. Aceste nume trebuie să fie unice, însă nu este obligatoriu ca ele să coincidă cu numele use case-urilor specializate. De asemenea, trebuie precizată condiţia de care depinde apelul use case-ului specializat. Acest tip de relaţie se foloseşte pentru a modela alternative. În figura 1.10 este prezentată o diagramă use case cu dependenţă extend care are puncte de extensie.

Fig. 1.10. Diagramă use case cu dependenţă de tip extend cu punct de extensie

Relaţia de generalizare se stabileşte între elemente de acelaşi tip (doi actori, sau doua use case-uri).

Este similară relaţiei de generalizare (moştenire) care se stabileşte între clase. Figura 1.11 ilustrează notaţia grafică pentru relaţia de generalizare între use case-uri. Elementul derivat B moşteneşte comportamentul şi relaţiile elementului de bază A. Use case-ul B este o specializare a use case-ului A.

În cazul unei relaţii de generalizare între use case-uri comportamentul poate fi modificat sau extins; use case-ul derivat B poate înlocui în anumite situaţii use case-ul de bază A. Case-ul derivat B controlează ce anume se execută şi ce se modifică din use case-ul de bază A.

Page 82: software engineering

Fig. 1.11. Notaţia grafică pentru relaţia de generalizare între use case-uri

În figura 1.12 este prezentat un exemplu de relaţie de generalizare între use case-uri.

Fig. 1.12. Exemplu de relaţie de generalizare între use case-uri

După cum am precizat mai sus, relaţia de generalizare se poate aplica şi între actori. În exemplul din figura 1.13 este prezentată o relaţie de generalizare între actori.

Fig. 1.13. Relaţie de generalizare între actori

În exemplul din figura 1.14a actorii A şi B joacă acelaşi rol R atunci când interacţionează

cu use case-ul UC şi joaca roluri diferite în interacţiunea cu use case-ul UC în figura 1.14b.

(a)

(b)

Fig. 1.14. Tipuri de roluri jucate de actori în interacţiunea cu use case-ul În figura 1.15 este prezentată o diagramă use case care utilizează toate tipurile de relaţii

definite anterior.

Page 83: software engineering

Fig. 1.15. Exemplu de diagramă use case

2. Diagrama de clase (Class Diagram) Diagrama de clase este folosită pentru a modela structura (viziunea statică asupra) unui

sistem. O astfel de diagramă conţine clase / interfeţe, obiecte şi relaţii care se stabilesc între acestea. Relaţiile pot fi de tipul:

• asociere;

• agregare;

• generalizare;

• dependenţă;

• realizare.

Clasele sunt folosite pentru a surprinde vocabularul sistemului ce trebuie dezvoltat. Ele pot include:

• abstracţii care fac parte din domeniul problemei; • clase necesare la momentul implementării. O clasă poate reprezenta entităţi software, entităţi hardware sau concepte. Modelarea unui

sistem presupune identificarea elementelor importante din punctul de vedere al celui care modelează. Aceste elemente formează vocabularul sistemului. Fiecare dintre aceste elemente are o mulţime de proprietăţi.

Page 84: software engineering

Clase

Elementele unei clase sunt:

Nume - prin care se distinge de alte clase - o clasă poate fi desenată arătându-i numai numele;

Atribute - reprezintă numele unor proprietăţi ale clasei;

Operaţii (metode) - reprezintă implementarea unor servicii care pot fi cerute oricărui obiect al clasei.

Notaţia grafică pentru clasă poate fi observată în figura 2.1.

Figura 2.1. Notaţia grafică pentru clasă Specificatorii de vizibilitate au următoarea semnificaţie:

• + public (dreptul de utilizare se acordă şi celorlalte clase); • - private (numai clasa dată poate folosi atributul sau operaţia); • # protected (posibilitatea de utilizare este accesibilă numai claselor succesoare)

O clasă poate avea oricâte atribute şi operaţii sau poate să nu aibă nici un atribut sau nici

o operaţie. Modelarea vocabularului unui sistem presupune identificarea elementelor pe care utilizatorul sau programatorul le foloseşte pentru a descrie soluţia problemei. Pentru fiecare element se identifică o mulţime de responsabilităţi (ce trebuie să facă acesta), după care se definesc atributele şi operaţiile necesare îndeplinirii acestor responsabilităţi.

Există trei tipuri particulare de clase (stereotipuri): • clasa limită – realizează interacţiunea cu utilizatorii sau cu alte sisteme (notaţie - figura 2.2a); permit interfaţarea cu alte sisteme software şi cu dispozitive fizice ca imprimante, motoare, senzori etc. • clasa entitate – modelează obiecte din interiorul domeniului aplicaţiei, dar externe sistemului software, despre care sistemul trebuie să stocheze câteva informaţii (notaţie - figura 2.2b); • clasa de control – modelează coordonarea, secvenţierea, controlul altor obiecte (notaţie - figura 2.2c).; recomandarea este să existe câte o clasă de control pentru fiecare use-case.

a. b.

c.

Figura 2.2. Notaţii grafice pentru stereotipuri

JOB

Page 85: software engineering

Obiecte Obiectele sunt instanţe ale claselor. Obiectele au identitate şi valori ale atributelor. Notaţia grafică pentru obiect se poate observa în figura 2.3.

Figura 2.3 Notaţii grafice pentru obiecte

Interfeţe Interfaţa specifică un grup de operaţii caracteristice unei comportări determinate a unei clase. Se modelează cu acelaşi simbol ca şi clasele. Interfaţa are numai operaţii. Pentru a le putea deosebi de clase se plasează stereotipul <<interface>> sau caracterul “I” la începutul numelui interfeţei respective.

Figura 2.4. Notaţii grafice pentru interfeţe

Clasă parametrizată (template) Clasa parametrizată are unul sau mai mulţi parametri formali. Prin intermediul acestei clase se poate defini o familie de clase dând valori parametrilor formali. De obicei parametrii reprezintă tipuri ale atributelor. Notaţia grafică se poate vedea în figura 2.5.

Figura 2.5. Exemplu de clasă parametrizată

Relaţii

O relaţie modelează o conexiune semantică sau o interacţiune între elementele pe care le conectează. În modelarea orientată obiect cele mai importante relaţii sunt relaţiile de asociere, dependenţa, generalizare şi realizare. Un caz particular al relaţiei de asociere îl constituie relaţia de agregare. Între clase se pot stabili relaţii de generalizare, dependenţă şi realizare. Relaţiile de asociere şi agregare se stabilesc între instanţe ale claselor.

Page 86: software engineering

a)

b)

c)

d)

e)

e)

Figura 2.6. Notaţii grafice pentru diferite tipuri de relaţii: a)asociere bidirecţională; b)asociere unidirecţională; c) agregare; d) dependenţă; e) generalizare, f) realizare

Relaţia de asociere Relaţia de asociere exprimă o conexiune semantică sau o interacţiune între obiecte

aparţinând unor anumite clase. Asocierea poartă informaţii despre legăturile dintre obiectele unui sistem. Pe măsură ce sistemul evoluează, pot fi create legături noi între obiecte sau pot fi distruse legăturile existente. Relaţia de asociere oferă baza arhitecturală pentru modelarea conlucrării şi interacţiunii dintre clase. O asociere interacţionează cu obiectele sale prin intermediul capetelor de asociere. Capetele de asociere pot avea nume, cunoscute sub denumirea de roluri, şi vizibilitate, ce specifică modul în care se poate naviga înspre respectivul capăt de asociere. Cea mai importantă caracteristică a lor este multiplicitatea, ce specifică câte instanţe ale unei clase corespund unei singure instanţe a altei clase. De obicei multiplicitatea este folosită pentru asociaţiile binare.

Reprezentarea grafică a asocierii este o linie (sau drum) ce conectează clasele ce participă în asociere. Numele asocierii este plasat pe linie, iar multiplicitatea şi rolurile sunt plasate la extremităţile sale (figura 2.7).

Figura 2.7: Notaţia grafică detaliată a relaţiei de asociere

Observaţie. Numele rolurilor pot fi omise (eventual şi numele asocierii)

Este posibilă specificarea direcţiei unei asocieri, pentru a elimina legături redundante sau irelevante pentru un anumit model. În această situaţie notaţia grafică pentru relaţia de asociere este o linie cu o săgeată la unul din capete indicând direcţia asocierii (figura 2.6b).

Relaţia de agregare Relaţia de agregare este o asociere ce modelează o relaţie parte-întreg. Este reprezentată

ca un romb gol ataşat la capătul asocierii de lângă clasa agregat (figura 2.6c). În figură o instanţă a clasei A conţine o instanţă a clasei B (altfel spus un obiect B este o parte unui obiect A). Relaţia de agregare este deci un caz particular al relaţiei de asociere. Ea poate avea toate elementele unei relaţii de asociere, însă în general se specifică numai multiplicitatea. Se foloseşte pentru a modela situaţiile în care un obiect este format din mai multe componente.

Page 87: software engineering

Compoziţia este o formă mai puternică a agregării. Partea are „timpul de viaţă” al întregului. Întregul poate avea responsabilitatea directă pentru crearea sau distrugerea părţii sau poate accepta o altă parte creată şi mai apoi să paseze „responsabilitatea” altui întreg. Obs. Instanţele nu pot avea relaţii de agregare ciclice (o parte nu poate conţine întregul)

În figura 2.8 este prezentat un exemplu în care se foloseşte agregarea şi compoziţia.

Figura 2.8. Exemplu de relaţii de agregare şi compoziţie

Relaţia de dependenţă

O dependenţă (figura 2.6d) indică o relaţie semantică între două elemente ale modelului.

Se foloseşte în situaţia în care o schimbare în elementul destinaţie (B) poate atrage după sine o schimbare în elementul sursă (A). Această relaţie modelează interdependenţele ce apar la implementare.

Figura 2.9. Exemplu de relaţii de dependenţă

Dependenţele pot să apară şi la structurarea unui sistem în pachete, definind arhitectura

sistemului.

Relaţia de generalizare

Relaţia de generalizare (figura 2.6e) se foloseşte pentru a modela conceptul de moştenire între clase. În figură clasa A este derivată din clasa B. Spunem că A este clasa derivată (sau subclasa, sau clasa copil), iar B este clasa de baza (sau superclasă, sau clasă părinte).

Relaţia de generalizare mai poartă denumirea de relaţie de tip is a (este un fel de), în sensul că o instanţă a clasei derivate A este în acelaşi timp o instanţă a clasei de bază B (clasa A este un caz particular al clasei B sau, altfel spus, clasa B este o generalizare a clasei A). Clasa A moşteneşte toate atributele şi metodele clasei B. Ea poate adăuga noi atribute sau metode sau le poate redefini pe cele existente.

Page 88: software engineering

Figura 2.10. Exemplu de relaţie de generalizare

Relaţia de realizare

Relaţia de realizare (figura 2.6f) se foloseşte în cazul în care o clasă (A) implementează o interfaţă (B). Se spune că A realizează interfaţa specificată de B. O interfaţă este o specificare comportamentală fără o implementare asociată. O clasă include o implementare. Una sau mai multe clase pot realiza o interfaţă prin implementarea metodelor definite de acea interfaţă.

Figura 2.11. Exemplu de relaţie de realizare.

În figura 2.11 sunt prezentate două diagrame de clase în care se folosesc toate tipurile de

relaţii prezentate mai sus.

Page 89: software engineering

Figura 2.12. Exemple de diagrame de clase

Page 90: software engineering

3. Diagrama de stări (State chart Diagram)

Comportamentul unui program poate fi descris prin următoarele tipuri de diagrame: • diagrama de stări • diagrama de activităţi • diagrama de interacţiuni:

- diagrama de secvenţe - diagrama de colaborare

Diagrama de stări este folosită pentru a modela comportamentul unui singur obiect.

Diagrama de stări specifică o secvenţă de stări prin care trece un obiect de-a lungul vieţii sale ca răspuns la evenimente împreună cu răspunsul la aceste evenimente. Noţiuni preliminare Un eveniment reprezintă ceva (atomic) ce se întâmplă la un moment dat şi care are ataşată o locaţie în timp şi spaţiu. Evenimentele modelează apariţia unui stimul care poate conduce la efectuarea unei tranziţii între stări. Evenimentele nu au durată în timp. Evenimentele pot fi clasificate în felul următor:

• sincrone sau asincrone • externe sau interne Evenimentele externe se produc între sistem şi actori (de exemplu apăsarea unui buton

pentru întreruperea execuţiei programului). Evenimentele interne se produc între obiectele ce alcătuiesc un sistem (de exemplu

overflow exception). Evenimentele pot include: • semnale; semnalul este un stimul asincron care are un nume şi care este trimis de

un obiect şi recepţionat de altul (ex: excepţii). • apeluri de operaţii (de obicei sincrone): un obiect invoca o operaţie pe un alt

obiect; controlul este preluat de obiectul apelat, se efectuează operaţia, obiectul apelat poate trece într-o nouă stare, după care se redă controlul obiectului apelant.

• trecerea timpului • o schimbare a rezultatului evaluării unei condiţii

O acţiune reprezintă execuţia atomică a unui calcul care are ca efect schimbarea stării sau returnarea unei valori. Acţiunile au o durată mică în timp, fiind tranzitorie (ex.: i++).

Prin activitate se înţelege execuţia neatomică a unor acţiuni. Activităţile au durată în timp, pot persista pe toată durata stării şi poate fi întreruptă (ex.: execuţia unei funcţii).

O diagramă de stări poate conţine stări şi tranziţii. Starea Prin stare se înţelege o condiţie sau situaţie din viaţa unui obiect în timpul căreia acesta:

• satisface anumite condiţii; • efectuează o activitate; • aşteaptă apariţia unui eveniment.

Page 91: software engineering

Notaţia grafică pentru stare este prezentată în figura 3.1.

Figura 3.1: Notaţia grafică pentru stare Există două stări particulare şi anume starea iniţială şi starea finală. Starea iniţială (figura 3.2a) este starea din care pleacă entitatea modelată. Starea finală (figura 3.2b) este starea în care entitatea modelată îşi încheie existenţa.

a)

b)

Figura 3.2: Notaţii grafice pentru starea iniţială (a) şi starea finală (b)

Elementele care caracterizează o stare sunt: • Nume - identifică în mod unic o stare; numele este reprezentat de o succesiune de şiruri de

caractere. • Acţiuni de intrare/ieşire - sunt acţiuni ce se produc la intrarea, respectiv ieşirea din starea

respectivă. • Substări care pot fi

- concurente (simultan active) – figura 3.3a - disjuncte (secvenţial active) –figura 3.3b

a)

b)

Figura 3.3. Notaţii grafice pentru substări concurente (a) şi disjuncte (b)

• Tranziţii interne - sunt acţiuni şi activităţi pe care obiectul le execută cât timp se află în

acea stare; se produc între substări şi nu produc schimbarea stării obiectului.

Page 92: software engineering

Figura 3.4. Notaţia completă pentru stare nume_eveniment – identifică circumstanţele în care acţiunea specificată se execută;

condiţie_gardă – condiţie booleană care se evaluează la fiecare apariţie a evenimentului specificat; acţiunea se execută doar când rezultatul evaluării este true;

acţiunea – poate folosi atribute şi legături care sunt vizibile entităţii modelate. După cum se poate observa din figura 3.4, două evenimente au notaţii speciale: entry

şi exit. Aceste evenimente nu pot avea condiţii gardă deoarece se invocă implicit la intrarea, respectiv ieşirea din starea respectivă.

Activităţile sunt precedate de cuvântul cheie do. Pentru a arăta că o stare conţine substări, se foloseşte cuvântul cheie include, urmat de

numele diagramei substărilor.

Figura 3.5. Exemplu de stare Tranziţia

O tranziţie reprezintă o relaţie între două stări indicând faptul că un obiect aflat în prima stare va efectua nişte acţiuni şi apoi va intra în starea a doua atunci când un anumit eveniment se petrece. Notaţia grafică pentru tranziţie se poate observa în figura 3.6.

Starea sursă reprezintă starea din care se pleacă.

Eveniment este evenimentul care declanşează tranziţia.

Condiţie gardă (guard condition) este o expresie booleană. Aceasta se evaluează la producerea evenimentului care declanşează tranziţia. Tranziţia poate avea loc numai dacă condiţia este satisfăcută.

Page 93: software engineering

Figura 3.6. Notaţia grafică pentru tranziţie

Acţiune - opţional se poate specifica o acţiune care să se execute odată cu efectuarea tranziţiei.

Starea destinaţie reprezintă starea în care ajunge obiectul după efectuarea tranziţiei.

În figurile 3.7 şi 3.8 se pot observa exemple de stări cu substări disjuncte, respectiv concurente.

Figura 3.7. Exemplu de stare cu substări disjuncte

Figura 3.8. Exemplu de stare cu substări concurente

Page 94: software engineering

În figura 3.9 este prezentat un exemplu de diagramă de stare pentru un proiect propus de un student

Figura 3.9. Exemplu de diagramă de stare pentru un proiect propus de un student

4. Diagrama de activităţi (Activity Diagram)

Diagrama de activităţi este o variantă a diagramei de stare şi este folosită pentru a modela dinamica unui proces sau a unei operaţii.

Diagramele de activităţi scot în evidenţă controlul execuţiei de la o activitate la alta. Diagramele de activităţi pot conţine:

• stări activităţi şi stări acţiuni, care sunt stări ale sistemului; • tranziţii; • obiecte; • bare de sincronizare; • ramificaţii.

Stările activitate (activity states) - pot fi descompuse, activitatea lor putând fi

reprezentată cu ajutorul altor diagrame de activităţi. Stările activitate nu sunt atomice (pot fi întrerupte de apariţia unui eveniment) şi au

durată (îndeplinirea lor se face într-un interval de timp).

Stările acţiuni (action states) - modelează ceva care se întâmplă (de exemplu evaluarea unei expresii, apelul unei operaţii a unui obiect, crearea/distrugerea unui obiect).

Page 95: software engineering

O stare acţiune reprezintă execuţia unei acţiuni. Ea nu poate fi descompusă. Stările acţiuni sunt atomice (nu pot fi întrerupte chiar dacă se produc evenimente) şi au o

durată nesemnificativă (foarte mică).

Notaţia grafică a stărilor activitate/acţiune se poate observa în figura 4.1.

Figura 4.1. Notaţia grafică a stărilor activitate/acţiune

Tranziţiile – reprezintă relaţii între două activităţi. Tranziţia este iniţiată de terminarea primei activităţi şi are ca efect preluarea controlului

execuţiei de către a doua activitate.

Figura 4.2. Notaţia grafică a tranziţiei

În exemplul din figura 4.3, prima activitate este aceea în care se adaugă un client nou.

Tranziţia la a doua activitate (şi anume aceea de a atribui un staff de contact pentru o eventuală campanie de promovare) implică faptul ca odată ce prima activitate s-a terminat, a doua activitate este pornită.

Figura 4.3. Exemplu de două activităţi unite de o tranziţie

Ramificaţiile - se folosesc pentru a modela alternative (decizii) a căror alegere depinde

de o expresie booleană Au o tranziţie de intrare şi două sau mai multe tranziţii de ieşire Fiecare tranziţie de ieşire trebuie să aibă o condiţie gardă Condiţiile gardă trebuie să fie disjuncte (să nu se suprapună) şi să acopere toate

posibilităţile de continuare a execuţiei (vezi exemplele din figura 4.4), altfel fluxul de control al execuţiei va fi ambiguu (nu se ştie pe care cale se va continua execuţia).

Condiţiile trebuie însă să acopere toate posibilităţile, altfel sistemul se poate bloca.

Page 96: software engineering

a)

b)

Figura 4.4. Exemple de activităţi cu puncte de ramificaţie

Uneori nu este necesară precizarea explicită a unui punct de decizie, pentru a simplifica diagrama (vezi exemplul din figura 4.5).

În figurile 4.4 şi 4.5 apare un alt element al diagramelor de activităţi şi anume starea finală.

În general, odată încheiată ultima activitate dintr-o diagramă, trebuie marcată tranziţia spre starea finală. De asemenea, după cum se poate observa în figura 4.6, fiecare diagramă de activităţi trebuie să înceapă cu starea iniţială.

Page 97: software engineering

Figura 4.5. Exemplu de alegere reprezentată fără un punct de ramificaţie explicit

Figura 4.6. Diagramă de activităţi cu stare iniţială şi finală

Bare de sincronizare Există posibilitatea ca mai multe activităţi să se execute în paralel. Pentru sincronizarea

acestora se folosesc aşa numitele bare de sincronizare. Acestea pot fi de două feluri:

• fork - poate avea o tranziţie de intrare şi două sau mai multe tranziţii de ieşire, fiecare tranziţie de ieşire prezentând un flux de control independent. Activităţile de sub fork sunt concurente.

Page 98: software engineering

• join - reprezintă sincronizarea a două sau mai multor fluxuri de control. La join fiecare flux de control aşteaptă până când toate celelalte fluxuri de intrare ajung în acel punct. Poate avea două sau mai multe tranziţii de intrare şi o singură tranziţie de ieşire.

Figura 4.7. Notaţia grafică pentru barele de sincronizare

Conceptul de „swimlanes” modelează (arată) activităţile care au loc în interiorul unui sistem. Diagrama se împarte în coloane care se intitulează semnificativ pentru entitatea pe care o modelează (vezi figura 4.8a,b).

a)

Page 99: software engineering

b)

Figura 4.8. Diagrame de activităţi cu „swimlanes”

Obiecte

Acţiunile sunt realizate de către obiecte sau operează asupra unor obiecte. Un obiect poate interveni într-o diagramă de activităţi în două moduri:

• o operaţie a unui obiect poate fi folosită drept nume al unei activităţi (figura 4.9); • un obiect poate fi privit ca intrare sau ieşire a unei activităţi (figura 4.10).

Obiectele pot fi conectate de acţiuni prin linii punctate cu o săgeată la unul din capete (orientarea săgeţii indică tipul parametrului - intrare sau ieşire)

Un obiect poate apărea de mai multe ori în cadrul aceleiaşi diagrame de activităţi. Fiecare apariţie indică un alt punct (stare) în viaţa obiectului. Pentru a distinge apariţiile

numele stării obiectului poate fi adăugat la sfârşitul numelui obiectului .

Page 100: software engineering

Figura 4.9. Diagrama de activităţi cu operaţia obiectului ca activitate

Figura 4.10. Diagrama de activităţi cu fluxuri de obiecte

Page 101: software engineering

Figura 4.11. Diagramă de activităţi cu obiecte şi „swimlanes”

Page 102: software engineering

Figura 4.12. Exemplu de diagramă de activităţi pentru un automat de cafea

Page 103: software engineering

5. Diagrame de Interacţiuni

Diagramele de interacţiuni sunt folosite pentru a modela comportamentul unei mulţimi de obiecte dintr-un anumit context care interacţionează în vederea îndeplinirii unui anumit scop.

Scopul specifică modul în care se realizează o operaţie sau un caz de utilizare. Contextul unei interacţiuni (unde pot găsi interacţiuni) poate fi:

• sistem / un subsistem (uzual) - mulţimea obiectelor din sistem care colaborează între ele;

• operaţie - interacţiuni între parametri, variabile locale şi globale;

• clasă - interacţiuni între atributele unei clase (cum colaborează ele), interacţiuni cu obiecte globale, sau cu parametrii unei operaţii.

Obiectele care participă la o interacţiune pot fi lucruri concrete sau prototipuri. De obicei, într-o colaborare obiectele reprezintă prototipuri ce joacă diferite roluri, şi nu obiecte specifice din lumea reală.

Între obiectele care participă la o colaborare se pot stabili legături.

O legătură (link) reprezintă o conexiune semantică între obiecte. Ea este o instanţă a unei asocieri şi poate avea toate atributele specifice asocierii (nume, roluri, navigare, agregare), dar nu şi multiplicitate.

Obiectele care interacţionează comunică între ele, comunicarea făcându-se prin schimb de mesaje.

Un mesaj specifică o comunicare între obiecte. El poartă o informaţie şi este urmat de o activitate. Primirea unei instanţe a unui mesaj poate fi considerată o instanţă a unui eveniment.

Unui mesaj îi este asociată o acţiune care poate avea ca efect schimbarea stării actuale a obiectului.

Forma generală a unui mesaj este [cond_gardă] acţiune (lista_parametrilor)

unde condiţie_gardă – condiţie booleană care se evaluează la fiecare apariţie a mesajului

specificat; acţiunea se execută doar când rezultatul evaluării este true;

Tipuri de acţiuni existente în UML:

• call: invocă o operaţie a unui obiect. Un obiect îşi poate trimite lui însuşi un mesaj (invocare locală a unei operaţii). Este cel mai comun tip de mesaj. Operaţia apelată trebuie să fie definită de obiectul apelat şi vizibilă apelantului.

• return: returnează o valoare apelantului.

• send: trimite un semnal unui obiect.

• create: creează un obiect.

• destroy: distruge un obiect. Un obiect se poate autodistruge.

O diagramă de interacţiuni constă dintr-o mulţime de obiecte şi relaţiile dintre ele

(inclusiv mesajele care se transmit). Există două tipuri de diagrame de interacţiuni:

• diagrama de secvenţă;

• diagrama de colaborare.

Page 104: software engineering

Cele două diagrame specifică aceeaşi informaţie, însă pun accentul pe aspecte diferite.

5.1 Diagrama de secvenţă

Diagrama de secvenţă pune accentul pe aspectul temporal (ordonarea în timp a mesajelor).

Notaţia grafică este un tabel (figurile 5.1, 5.2) care are pe axa X obiecte, iar pe axa Y mesaje ordonate crescător în timp.

Axa Y arată pentru fiecare obiect:

• linia vieţii - linie punctată verticală;

• perioada în care obiectul preia controlul execuţiei - reprezentată printr-un dreptunghi subţire pe linia vieţii; în această perioadă obiectul efectuează o acţiune, direct sau prin intermediul procedurilor subordonate.

Figura 5.1. Exemplu de diagramă de secvenţă

Notaţia grafică pentru mesaje A B Comunicare sincronă. Controlul execuţiei trece de la A la B şi

revine la A după ce B îşi termină execuţia. Exemplu: apel de funcţie. A B Comunicare asincronă. A trimite un semnal după care îşi continuă

execuţia mai departe. Exemplu: aruncarea unei excepţii. Întoarcere dintr-o funcţie (procedură). În cazul în care este omisă

se consideră implicit că revenirea se face la sfârşitul activării.

În figura 5.2 este prezentat un exemplu de diagramă de secvenţă. Mesajul extrageNume() este primul mesaj recepţionat de Client şi corespunde cererii Managerului de Campanie de a furniza numele clientului selectat. Obiectul Client

Page 105: software engineering

recepţionează apoi mesajul listeazăcampanii() şi începe a doua perioadă de activare. Obiectul Client trimite apoi mesajul extrageDetaliiCampanie() fiecărui obiect Campanie pe rând pentru a construi o listă a campaniilor. Această operaţiune repetată se numeşte iteraţie şi se marchează prin caracterul „*” înaintea numelui mesajului. Condiţia de continuare sau de încetare poate fi precizată în interiorul numelui mesajului. Condiţia de continuare poate fi scrisă sub forma:

[pentru toţi clienţii campaniilor] *extrageDetaliiCampanie()

Manager Campanie trimite apoi un mesaj unui obiect particular Campanie pentru a obţine o listă a reclamelor. Obiectul Campanie deleagă responsabilitatea pentru a extrage titlul reclamei fiecărui obiect Reclamă deşi obiectul Campanie păstrează responsabilitatea pentru lista reclamelor (fapt indicat de păstrarea activării şi după ce este trimis mesajul).

Când o reclamă este adăugată la campanie este creat un obiect Reclama. Această creare este indicată de mesajul Reclama() (care invocă un constructor).

Figura 5.2. Exemplu de diagramă de secvenţă care modelează adăugarea unei noi reclame unei campanii

Obiectele pot fi create sau distruse la diferite momente ale interacţiunii. Distrugerea unui

obiect este marcată printr-un “X” pe linia vietii. Un obiect poate fi distrus când primeşte un mesaj (ca în figura 5.3) sau se poate distruge singur la sfârşitul unei activări.

Page 106: software engineering

Figura 5.3. Distrugerea unui obiect

Un obiect îşi poate trimite un mesaj lui însuşi. Acest mesaj este cunoscut sub numele de mesaj reflexiv şi este reprezentat de o săgeată care pleacă şi se termină pe o activare a aceluiaşi obiect. Diagram de secvenţă din figura 5.4 include mesajul reflexiv calculeazăCheltuieliregie() trimis de obiectul Campanie lui însuşi.

Figura 5.4. Diagramă de secvenţă care modelează Verifică bugetul campaniei

După cum am mai precizat, revenirea controlului la obiectul care a trimis un mesaj se poate marca explicit în diagrama de secvenţă printr-o săgeată trasată cu linie întreruptă (figura 5.5). Valoarea de revenire de obicei nu se prezintă într-o diagramă de secvenţă.

Page 107: software engineering

Figura 5.5. Diagramă de secvenţă care modelează Verifică bugetul campaniei cu

marcarea explicită a revenirilor

Dacă mesajele sincrone (care invocă o operaţie) determină suspendarea execuţiei obiectului sursă până când destinatarul îşi termină execuţia, mesajele asincrone nu necesită suspendarea execuţiei obiectului ce trimite mesajul. Mesajele asincrone sunt des folosite în aplicaţiile de timp real în care operaţiile diferitelor obiecte se execută în paralel, fie din motive de eficienţă, fie deoarece sistemul simulează procese concurente. Este necesar ca o operaţie invocată să notifice obiectul care a invocat-o în momentul când îşi termină execuţia. Această notificare se face printr-un mesaj explicit (numit callback). Constrângeri de timp

O diagramă de secvenţă poate fi etichetată cu constrângeri de timp în moduri diferite. În figura 6 se asociază expresiile de timp cu numele mesajului astfel încât constrângerile de timp pot fi specificate pentru execuţia unei operaţii sau transmisia unui mesaj. Spre exemplu funcţia a.sendTime furnizează timpul la care mesajul a este trimis şi d.receiveTime furnizează timpul la care o instanţă a clasei A primeşte mesajul d. Există construcţii care pot fi utilizate pentru a marca un interval de timp – în figura 5.6 este marcat intervalul de timp scurs între recepţia mesajului b şi trimiterea mesajului c. Constrângerile de timp sunt utilizate frecvent în modelarea sistemelor de timp real. Pentru alte tipuri de sisteme constrângerile de timp nu sunt semnificative.

Page 108: software engineering

Figura 5.6. Diagramă de secvenţă cu tipuri diferite de mesaje şi constrângeri de timp

Ramificaţii Diagramele de secvenţă permit reprezentările ramificaţiilor prin mai multe săgeţi care pleacă din acelaşi punct şi eventual sunt etichetate cu condiţii.

În figura 5.7 este prezentat un exemplu de diagramă de secvenţă cu ramificaţii.

Figura 5.7. Exemplu de diagramă de secvenţe cu ramificaţii.

Page 109: software engineering

5.2 Diagrama de colaborare Diagrama de colaborare este o diagramă de interacţiuni care pune accentul pe organizarea structurală a obiectelor care participă la interacţiune.

Diagrama de colaborare poate conţine: • obiecte; • legături între obiecte; • mesajele prin care obiectele comunică. Diagramele de colaborare au multe asemănări cu diagramele de secvenţă, exprimând

aceleaşi informaţii dar într-un alt format. Pot fi create la nivele diverse de detaliu şi în diferite stadii de dezvoltare a procesului software. Deoarece au un conţinut similar, pot fi folosite pentru generarea diagramelor de secvenţă şi viceversa.

Diferenţa semnificativă faţă de diagrama de secvenţă este aceea că diagrama de colaborare arată explicit legăturile dintre obiecte. De asemenea, la diagrama de colaborare timpul nu are o dimensiune explicită. Din acest motiv, ordinea în care sunt trimise mesajele este reprezentată prin numere de secvenţă.

Mesajele dintr-o diagramă de colaborare sunt reprezentate de un set de simboluri care sunt asemănătoare celor utilizate în diagrama de secvenţă, dar cu câteva elemente adiţionale pentru a marca secvenţierea şi recurenţa.

Notă. Termenii care vor apărea între paranteze pătrate sunt opţionali iar termenii care vor apărea între acolade pot să nu apară sau să apară de mai multe ori.

Sintaxa unui mesaj este următoarea:

[predecesor] [condiţie_gardă] expresie_secvenţă [valoare_întoarsă ‘:=’] nume_mesaj ‘(‘[listă_argumente]’)’

unde

• predecesor – listă a numerelor de secvenţă a mesajelor care trebuie trimise înainte de trimiterea mesajului curent (permite sincronizarea trimiterii mesajelor); permite specificarea detaliată a căilor ramificaţiilor.

Sintaxa predecesorului este următoarea: număr_secvenţă { ’,’ număr_secvenţă } ’/’

’/’ – marchează sfârşitul listei şi se include doar dacă este precizat explicit predecesorul.

• condiţie_gardă – expresie booleană care permite condiţionarea transmiterii mesajului (se scrie în OCL – Object Constraint Language) şi se poate utiliza pentru reprezentarea sincronizării diferitelor fluxuri de control.

• expresie_secvenţă – listă de întregi separaţi prin caracterul ’.’, urmată opţional de un nume (o singură literă), un termen recurenţă şi terminată de caracterul ’:’.

Sintaxa expresiei_ secvenţă este următoarea: întreg { ‘.’ întreg } [nume] [recurenţă] ‘:’

Se observă că numerotarea este asemănătoare celei utilizate la numerotarea capitolelor şi paragrafelor într-un document.

întreg – precizează ordinea mesajului; poate fi folosit într-o construcţie de tip buclă sau ramificaţie.

Page 110: software engineering

Exemplu: mesajul 5.1.3 se transmite după 5.1.2 şi ambele se transmit după activarea mesajului 5.1.

nume – se foloseşte pentru a diferenţia două mesaje concurente când acestea au acelaşi număr de secvenţă.

Exemplu: mesajele 3.2.1a şi 3.2.1b se transmit simultan în cadrul activării mesajului 3.2.

recurenţa – permite specificarea modului de transmitere a mesajelor:

secvenţial - ‘*’‘[‘clauză_iteraţie’]’

paralel - ‘||’‘[‘clauză_iteraţie’]’

ramificaţie - ‘[‘clauză_condiţie’]’

În tabelul următor se prezintă câteva exemple de tipuri de mesaje:

Tipuri de mesaje: Exemple

mesaj simplu 4: adaugă ReclamaNoua ()

subapeluri cu valoarea întoarsă Valoarea întoarsă este plasată în variabila nume

3.1.2: nume:= extrageNume ()

mesaj condiţional mesajul este trimis doar dacă este adevărată condiţia [balanţă > 0]

[balanţă > 0] 5: debit (sumă)

sincronizare cu alte mesaje mesajul 4: playVideo este trimis doar după ce mesajele concurente 3.1a şi 3.1b sunt complete

3.1a, 3.1b / 4: playVideo()

iteraţii [i = 1..n] update ()

În figura 5.8 este prezentată diagrama de colaborare corespunzătoare diagramei de secvenţă din figura 5.1.

Page 111: software engineering

Figura 5.8. Exemplu de diagramă de colaborare

Există mai multe posibilităţi de interacţiune pentru un use case particular. Acestea se datorează alocărilor posibile diferite ale responsabilităţilor. Spre exemplu, interacţiunile din figura 5.9 pot avea trăsături nedorite. Mesajul extrageDetaliiCampanie trimis de Client obiectului Campanie necesită ca obiectul Client să returneze aceste detalii obiectului AdaugaReclama. Dacă detaliile despre campanie includ doar numele campaniei atunci un volum relativ mic de date este pasat de la Campanie la Client şi apoi la AdaugaReclama. Acest fapt poate fi acceptabil.

Figura 5.9. Diagrama de colaborare pentru use case-ul Adaugă o reclamă nouă unei campanii

Page 112: software engineering

Pe de altă parte, dacă detaliile despre campanie includ data de start, de terminare şi bugetul campaniei, atunci prin Client se pasează mai mult de o dată. În acest caz obiectul Client este acum responsabil pentru furnizarea unor date semnificative pentru campanii în loc de obiectul Campanie. S-ar putea deci transfera date direct de la Campanie la AdaugaReclama. Această posibilitate este prezentată în figura 5.10, în care AdaugaReclama preia responsabilitatea de a extrage detalii despre campanie direct de la obiectul Campanie. În această interacţiune, obiectul Client este responsabil doar de furnizarea unei liste de campanii obiectului AdaugăReclamă.

Figura 5.10. Diagramă de colaborare alternativă pentru use case-ul

Adaugă o reclamă nouă unei campanii În figura 5.11 este prezentată o diagramă de colaborare care prezintă interacţiunile pentru o singură operaţie – verificăBugetCampanie() – care este una din operaţiile din diagramele din figurile 5.9 şi 5.10. Diagramele de colaborare sunt preferate de unii dezvoltatori diagramelor de secvenţă deoarece interacţiunile între obiecte pot fi translate uşor în diagramele de clase datorită vizibilităţii legăturilor între obiecte.

Figura 5.11. Diagrama de colaborare pentru operaţia verificaBugetCampanie()

Page 113: software engineering

6. Organizarea modelelor în pachete

Pachetul (package) este o grupare de elemente ale unui model (use case-uri, clase etc.) şi reprezintă baza necesară controlului configuraţiei, depozitării şi accesului. Este un container logic pentru elemente între care se stabilesc legături. Pachetul defineşte un spaţiu de nume.

Toate elementele UML pot fi grupate în pachete (cel mai des pachetele sunt folosite pentru a grupa clase). Un element poate fi conţinut într-un singur pachet.

Un pachet poate conţine subpachete, deci se creează o structură arborescentă (similară cu organizarea fişierelor/directoarelor). Notaţia grafică pentru pachet este prezentată în figura 6.1.

Figura 6.1. Notaţia grafică pentru pachet

Pachetele pot face referire la alte pachete, iar modelarea se face folosind unul din

stereotipurile <<import>> (import public) şi <<acces>> (import privat) asociate unei relaţii de dependenţă (vezi figura 6.2).

Figura 6.2. Exemple de relaţii care se pot stabili între pachete

Ambele tipuri de relaţii permit folosirea elementelor aflate în pachetul destinaţie de către

elementele aflate în pachetul sursă fără a fi necesară calificarea numelor elementelor din pachetul destinaţie.

Page 114: software engineering

Figura 6. 3. Exemplu de diagramă de pachete

În figura 6.3 elementele din Types sunt importate în ShoppingCart şi apoi sunt

importate mai departe de către WebShop. Elementele din Auxiliary pot fi accesate însă doar din ShoppingCart şi nu pot fi referite folosind nume necalificate din WebShop.

Utilitatea pachetelor. Pachetele împart sistemele mari în subsisteme mai mici şi mai uşor de gestionat. De asemenea permit dezvoltare paralelă iterativă şi definirea unor interfeţe clare între pachete promovează refolosirea codului (ex. pachet care oferă funcţii grafice).

Page 115: software engineering

7. Diagrame de implementare Diagrama de componente

Diagrama de componente este o diagramă de implementare care modelează dependenţele dintre componentele software ale sistemului şi entităţile care le implementează (fişiere cod sursă, cod binar, executabile, scripturi etc.). Într-un proiect de dimensiune mare, vor exista multe fişiere care realizează sistemul. Aceste fişiere depind unele de altele. Natura acestor dependenţe e dată de limbajul (limbajelor) folosite pentru dezvoltarea proiectului. Dependenţele pot exista în momentul compilării, link-editării sau rulării. Există de asemenea dependenţe între fişiere sursă şi cele executabile sau obiect, rezultate din primele prin compilare. În figura 7.1 este prezentată o diagramă de componente care descrie dependenţele dintre o sursă scrisă în C++ şi fişierul header asociat, dependenţa fişierului obiect de cele două fişiere anterioare şi dependenţa fişierului executabil de fişierul obiect. Se pot adăuga şi stereotipuri care se folosesc pentru a arăta tipurile diferitelor componente.

Figura 7.1. Diagramă de componente care arată dependenţele în C++

O alternativă de reprezentare a unei părţi a diagramei de componente este de a utiliza

notaţia pentru interfaţă în UML pentru a arăta specificaţia unei clase (fişierul header în C++) ca o interfaţă şi corpul ca o componentă (vezi figura 7.2).

Figura 7.2. Dependenţa unei componente printr-o interfaţă cu o altă componentă

Page 116: software engineering

Observaţii.

• Componentele unei diagrame de componente pot fi componente fizice ale sistemului.

• Diagramele de componente sunt utilizate în general pentru a marca dependenţele la scară mare între componentele unui sistem (vezi figura 7.3).

Figura 7.3. Exemplu de dependenţă la scară mare între componente unui sistem

• Obiectele active care rulează pe fire de execuţie separate pot fi prezentate în diagrama de componente (vezi figura 7.4)

Figura 7.4. Exemplu de obiect activ în interiorul unei componente

• În timpul analizei şi la începutul proiectării, se folosesc diagramele de pachete pentru a

arăta gruparea logică a diagramelor de clase (sau a modelelor care utilizează alte tipuri de diagrame) în pachete referitoare la subsisteme.

• În timpul implementării, diagramele de pachete pot fi folosite a arăta gruparea componentelor fizice în subsisteme.

• Diagrama de componente poate fi combinată cu diagrama de plasare pentru a arăta localizarea fizică a componentelor sistemului. Clasele dintr-un pachet logic pot fi distribuite peste locaţiile fizice dintr-un sistem fizic, iar diagramele de componente şi plasare arată tocmai acest lucru.

Page 117: software engineering

Figura 7.5. Exemplu de diagramă de componente

Page 118: software engineering

Diagrama de plasare

Diagrama de plasare arată configuraţia procesării elementelor care execută direct activităţi specifice şi componentele de program, procesele, obiectele care determină funcţionarea acestor componente.

Componentele care nu au rol direct în execuţie nu sunt arătate în această diagramă. Diagrama de plasare este alcătuită din:

• noduri; • Asocieri.

Nodurile arată computerele iar asocierile marchează reţeaua şi protocoalele care sunt folosite pentru a comunica între noduri (se modelează sistemele client / server din punct de vedere al topologiei).

Nodurile mai pot fi utilizate pentru a modela şi alte resurse cum ar fi personalul uman şi resursele mecanice.

Diagramele de plasare modelează arhitectura fizică a sistemului. Notaţia grafică pentru noduri este prezentată în figura 7.6.

Figura 7.6. Notaţia grafică pentru nodurile unei diagrame de plasare.

Diagramele de plasare pot arăta fie tipuri de maşini fie instanţe particulare ca în figura 7.7. În figura 7.8 se prezintă locul bazei de date Vanzari (pe server) şi câteva componente ale calculatoarelor clienţilor.

Figura 7.7. Exemplu de diagramă de plasare

Figura 7.8. Diagramă de plasare cu componente ale PC Client

şi cu un obiect activ pe server

Page 119: software engineering

Figura 7.9. Exemplu de diagramă de plasare

Page 120: software engineering

OCL - Object Constraint Language În realizarea unei diagrame de clase cea mai mare parte a timpului şi a efortului este dedicată aplicării constrângerilor. Spre exemplu, multiplicitatea într-o relaţie de asociere reprezintă o restricţie referitoare la modul în care mai multe obiecte ale unei clase pot fi legate de fiecare obiect al altei clase. Acest exemplu particular poate fi exprimat în mod adecvat în limbajul grafic al diagramei de clase, dar nu toate constrângerile pot fi exprimate astfel. Spre exemplu, multe pre şi post condiţii dintr-un contract reprezintă constrângeri asupra comportării obiectelor care sunt părţi ale contractului. Definirea unor astfel de constrângeri poate fi făcută într-o manieră informală, dar în cazul în care este cerută o precizie ridicată, se foloseşte exprimarea formală folosind OCL. OCL este un limbaj de exprimare a constrângerilor (restricţiilor) pentru obiecte. A fost dezvoltat de IBM (divizia de asigurări) şi se utilizează pentru precizarea caracteristicilor modelelor UML. OCL este un limbaj bazat pe teoria matematică a mulţimilor şi logica predicatelor. Este un limbaj tipizat, fiecare expresie având un tip. OCL este un limbaj declarativ în sensul că expresiile descriu ce anume este de realizat şi nu cum. Expresiile OCL nu au efecte secundare, ele conservând starea sistemului. Fiind un limbaj de modelare, OCL nu este executabil. Expresiile OCL se evaluează instantaneu. Nu există restricţii de implementare, un model UML/OCL putând fi realizat independent de platformă. OCL poate fi utilizat pentru:

• Specificarea invarianţilor;

• Specificarea pre-condiţiilor şi post-condiţiilor;

• Specificarea condiţiilor gardă;

• Limbaj de navigare.

Expresiile OCL sunt construite dintr-o colecţie de elemente predefinite şi tipuri, limbajul având o gramatică precisă care permite construcţia unor declaraţii clare despre proprietăţile componentelor modelului şi despre relaţiile dintre ele. Majoritatea construcţiilor OCL constau în următoarele elemente structurale:

• Contextul defineşte un domeniu în interiorul căruia expresia este validă. Acesta este de obicei o instanţă a unui tip specific, spre exemplu un obiect într-o diagramă de clase. O legătură (o instanţă a unei asocieri) poate fi de asemenea contextul pentru o expresie OCL. În cazul în care constrângerea este specificată într-o diagramă UML (de clase sau de colaborare) utilizând un stereotip şi linia punctată pentru a-l conecta de elementul contextual, nu mai este necesară declararea explicită a contextului în constrângere. Declararea contextului este opţională. Într-o diagramă de clase expresiile OCL sunt precizate sub forma din figura 1. Cuvântul rezervat self este folosit pentru a referi o instanţă contextuală. Spre exemplu, în cazul în care contextul este Persoana, atunci self se referă la o instanţă a clasei Persoana.

• Proprietatea acelei instanţe care este context pentru o expresie. Proprietăţile pot include atribute, capete de asociere, operaţii de interogare.

• Operaţia OCL se aplică proprietăţii. Operaţiile includ (dar nu sunt limitate la) operatorii aritmetici (*, +, -, /), operatori colecţie cum ar fi size, isEmpty şi select şi operatori de tip ca oclIsTypeOf.

Page 121: software engineering

Figura 1. Modelarea constrângerilor în UML

Declaraţiile OCL pot să includă de asemenea cuvinte cheie OCL cum ar fi operatorii logici (and, or, implies, if, then, else, not) şi operatorul mulţime in, scrise cu litere îngroşate pentru a-i distinge de alţi termeni şi operaţii OCL. Cuvintele cheie împreună cu cuvintele menţionate anterior (care nu sunt cuvinte cheie) pot fi folosite pentru a defini exact pre-condiţiile şi post-condiţiile pentru o operaţie.

În tabelul următor sunt prezentate câteva expresii OCL. Toate exemplele au drept context un obiect al unei clase. Se prezintă expresia OCL şi semnificaţia acesteia.

Expresie OCL Interpretare

context persoana self.gen

În contextul unei persoane specifice, valoarea proprietăţii „gen” a acelei persoane este genul acelei persoane

context persoana self.economii >= 500

Proprietatea „economii” a persoanei luate în considerare trebuie să fie mai mare sau egală cu 500.

context persoana self.sot -> notEmpty() implies self.sot.gen = masculin

În cazul în care colecţia „sot” asociat unei persoane nu este vidă, atunci proprietatea „gen” a soţului trebuie să fie „masculin”

context companie self.DT -> size() <= 1

Mărimea colecţiei proprietăţii DT (director tehnic) a unei companii trebuie să fie mai mică sau egală cu 1. Într-adevăr, o companie nu poate avea mai mult de un director tehnic.

context companie self.angajat -> select (varsta < 60)

Mulţimea angajaţilor unei companii cu vârsta mai mică de 60.

Page 122: software engineering

Figura 2. Exemplu de diagramă de clase

Conceptul de invariant – expresie booleană care exprimă o condiţie ce trebuie să fie îndeplinită de toate instanţele tipului pentru care este definită. Invariantul trebuie să aibă valoarea true la finalul execuţiei constructorului de instanţe precum şi după execuţia operaţiilor.

Spre exemplu, în contextul Companie referitor la figura 2, expresia următoare specifică faptul că numărul de angajaţi trebuie să fie mai mare decât 50.

self.numarAngajati > 50 unde self e o instanţă a tipului Companie. Acest invariant se păstrează pentru orice instanţă a tipului Companie. Tipul instanţei contextuale a unei expresii OCL care este parte a unui invariant se scrie folosind cuvântul context urmat de numele tipului ca în exemplul de mai jos. Eticheta inv: declară constrângerea ca fiind de tipul invariant.

context Companie inv:

self.numarAngajati > 50

În unele cazuri se poate renunţa la cuvântul cheie self dacă este clar contextul. Ca alternativă pentru self se poate defini un nume care joacă rolul cuvântului cheie self, ca în exemplul următor:

context c:Companie inv: c.numarAngajati > 50

Acest invariant este echivalent cu cel precedent.

Opţional, numele constrângerii poate fi scris după cuvântul cheie inv:, permiţând constrângerii să fie referite prin nume. În următorul exemplu, numele constrângerii este

Page 123: software engineering

angajatiSuficienti.

context c:Companie inv: angajatiSuficienti c.numarAngajati > 50

Specificaţiile operaţiei includ frecvent invarianţi. Când un invariant e asociat cu specificarea

unei operaţii, el descrie o condiţie care rămâne adevărată pentru un obiect şi care nu trebuie alterată de operaţie. Definiţia formală a invarianţilor este importantă deoarece furnizează teste riguroase pentru execuţia softului.

Exemplu: valoarea Campanie.costEstimat trebuie să fie întotdeauna egală cu suma tuturor valorilor Reclama.costEstimat asociate, multiplicate cu valoarea cheltuielilor de regie (CR). În OCL se poate scrie: Campanie inv: self.costEstimat=CR*self.Reclama.costEstimat -> sum

În exemplul precedent contextul este clasa Campanie. Pre-condiţii şi post-condiţii

O expresie OCL poate fi parte a unei pre-condiţii sau post-condiţii, corespunzătoare stereotipurilor <<pre-condiţie>> respectiv <<post-condiţie>> asociate cu o operaţie sau metodă (vezi figura 1).

OCL poate specifica multe constrângeri care nu pot fi exprimate direct în diagramă şi de aceea este necesar un limbaj precis pentru pre-condiţii şi post-condiţii.

Instanţa contextuală self este o instanţă a tipului care este proprietar al operaţiei sau metodei. Declaraţia contextului în OCL foloseşte cuvântul cheie context, urmat de tipul şi declaraţia operaţiei. Etichetele pre: şi post: declară constrângerea ca fiind o constrângere pre-condiţie respectiv post-condiţie. Sintaxa generală pentru specificarea unei operaţii este: context type::operation(param1:type, param2:type,...):returnType pre: param1 operation param2 operation post:result = ...

Expresiile pre: sunt funcţii de parametrii operaţiei, în timp ce expresiile post: sunt funcţii de

self, de parametrii operaţiei sau de ambele. Pre-condiţia este o expresia booleană care trebuie să fie adevărată în momentul începerii

execuţiei unei operaţii. Post-condiţia este o expresie booleană care trebuie să fie adevărată în momentul terminării

execuţiei unei operaţii. Result reprezintă valoarea returnată. Declaraţia explicită context poate lipsi.

Pentru exemplul din figura 2 putem scrie context Persoana::venit(d:Date):Integer

post: result = 5000

Opţional se poate da un nume pre-condiţiei, respectiv post-condiţiei, care permite referirea constrângerii prin nume. Numele este precedat de cuvintele cheie pre: respectiv post:. În exemplul

Page 124: software engineering

următor, numele pre-condiţiei respectiv al post-condiţiei sunt paramOk respectiv resultOK: context type::operation(param1:type, param2:type,...):returnType pre paramOK: param1 operation ... post resultOK: result = ...

Pentru utilizarea unui invariant în interiorul specificaţiei unei operaţii se poate scrie o clauză adiţională care începe cu inv:. ClassName::operation(param1:type, param2:type,...):return type pre: param1

param2 ...

post:result1... result2...

... inv: invariant1... invariant2... ...

Valori precedente în post-condiţii

O caracteristică particulară utilă a OCL-ului este că într-o post-condiţie expresia se poate referi la două seturi de valori pentru fiecare proprietate a unui obiect:

• valoarea proprietăţii la începutul operaţiei sau metodei;

• valoarea proprietăţii după terminarea operaţiei sau metodei. Valoarea unei proprietăţi într-o post-condiţie este valoarea după terminarea operaţiei. Pentru

a referi o valoare a proprietăţii la începutul operaţiei se adaugă sufixul @pre numelui proprietăţii. O utilizare tipică este de a constrânge relaţia între valorile unui atribut înainte şi după ce o

operaţie are loc. Exemplu:

context Persoana :: aniversare() post: varsta = varsta@pre+1

Proprietatea varsta se referă la proprietatea unei instanţe o clasei Persoană asupra căreia se execută operaţia. Proprietatea varsta@pre se referă la valoarea proprietăţii varsta la începutul execuţiei operaţiei.

Exemplu:

Să considerăm o decizie care defineşte diferitele acţiuni ce depind de schimbările costului unei campanii de publicitate în comparaţie cu bugetul său. Dacă noul cost estimat este mai mare decât costul vechi estimat, dar nu depăşeşte bugetul cu mai mult de 2%, valoarea pentru acest atribut este setată pe true şi se generează o scrisoare pentru client (aceasta se face prin adăugarea unui atribut Campanie.scrisoareCerutaClient). Aceste restricţii se scriu în OCL sub forma:

Page 125: software engineering

context Campanie inv post:if costEstimat > costEstimat@pre and costEstimat > buget and costEstimat <= buget * 1.02 then self.scrisoareCerutaClient:Boolean = ’true’ endif

Dacă proprietatea are parametri, sufixul @pre se adaugă înainte de parametri:

context Companie::angajeazăAngajat(p:Persoana)

post: angajat = angajat@pre -> including(p) and pretActiune() = pretActiune@pre()+10

Operaţia anterioară poate fi specificată folosind atât o post-condiţie cât şi o pre-condiţie: context Companie::angajeazăAngajat(p:Persoana)

pre: not angajat -> includes(p) post: angajat -> includes(p) and

pretActiune() = pretActiune@pre()+10 Tipuri şi valori de bază În OCL există un număr de tipuri de bază predefinite, independente de model. Câteva dintre acestea împreună cu exemple de valori ce le corespund sunt prezentate în tabelul următor.

Tip Valori Boolean true, false Integer 1, -5, 2, 34, ... Real 1.5, 3.14,... String ‘A fi sau a nu fi...’

OCL defineşte un număr de operaţii asupra tipurilor predefinite, câteva dintre acestea fiind

prezentate în tabelul următor.

Tip Operaţii Integer *, + - /, abs() Real *, + - /, floor() Boolean And, or, xor, not, implies, if-then-elseString toUpper(), concat()

Tipul enumerare Enumerarea este un tip de dată în UML şi are un nume (vezi figura 2). O enumerare

defineşte un număr de literali care sunt valori posibile ale enumerării. În cadrul OCL ne putem referi la o valoare a unei enumerări. Dacă spre exemplu avem enumerarea Sex cu valorile ‘masculin’, ‘feminin’, putem face construcţia

context Persoana inv:

sex = Sex::masculin

Page 126: software engineering

Expresii let Există situaţii în care o sub-expresie este utilizată de mai multe ori într-o constrângere.

Expresia let permite definirea unui atribut sau a unei operaţii care poate fi utilizată în constrângere. context Persoana inv: let venit:Integer = self.job.salariu -> suma()

let areTitlu(t:String):Boolean = self.job -> exists(titlu=t) if esteSomer then self.venit < 100 else self.venit >= 100 and self.areTitlu(‘manager’)

endif O expresie let poate fi inclusă într-un invariant sau în pre-condiţii şi post-condiţii şi este cunoscută doar în interiorul respectivei constrângeri. Pentru a putea reutiliza aceste expresii se poate utiliza o constrângere cu stereotipul <<definition>> în care se definesc expresiile let. Toate variabilele şi operaţiile definite în constrângerea <<definition>> sunt cunoscute în acelaşi context în care orice proprietate poate fi utilizată. În esenţă, astfel de variabile şi operaţii sunt pseudo-atribute şi pseudo-operaţii şi se utilizează în OCL în aceeaşi manieră ca şi atributele sau operaţiile. Notaţia pentru constrângerea <<definition>> utilizează cuvântul cheie def ca în exemplul următor: context Persoana def: let venit:Integer = self.job.salariu -> suma()

let areTitlu(t:String):Boolean = self.job -> exists(titlu=t) Cuvinte predefinite în OCL Lista cuvintelor predefinite este prezentată în tabelul următor

Obiecte şi proprietăţi Proprietăţi Valoarea unei proprietăţi a unui obiect care este definit într-o diagramă de clase este specificată printr-un „punct” urmat de numele proprietăţii:

Page 127: software engineering

context AType inv: self.proprietate Dacă self este o referinţă la un obiect, atunci self.proprietate este valoarea proprietăţii proprietate a lui self. Proprietăţi: Atribute Spre exemplu, vârsta unei persoane se scrie self.varsta:

context Persoana inv: self.varsta > 0 Valoarea sub-expresiei self.varsta este valoarea atributului varsta pentru o instanţă particulară a clasei Persoana identificată prin self. Tipul acestei sub-expresii este tipul atributului varsta, care este de tip Integer.

Proprietăţi: Operaţii Operaţiile pot avea parametri. Spre exemplu, un obiect Persoană are un venit exprimat ca funcţie de o dată (vezi figura 2). Această operaţie poate fi accesată în felul următor, pentru o persoană aPersoana şi o dată aDate:

aPersoana.venit(aDate) Operaţia însăşi poate fi definită printr-o constrângere de tip post-condiţie sub forma:

context Persoana::venit (d:Date) : Integer inv: post: result = varsta * 1000 Tipul lui result este tipul returnat de operaţie, care este Integer în exemplul anterior. Pentru a ne referi la o operaţie sau metodă care nu are parametri, se utilizezaă parantezele rotunde fără nici un argument:

context Companie inv: self.pretActiune() > 0 Proprietăţi: Capete de asociere şi Navigare Pornind de la un anumit obiect putem naviga pe o asociere într-o diagramă de clase pentru a ne referi la alte obiecte şi la proprietăţile acestora. În acest scop se utilizează extremitatea opusă a asocierii: obiect.numeRol Valoarea acestei expresii este un set de obiecte situat la extremitatea cealaltă a asocierii. Dacă multiplicitatea unui capăt de asociere este maxim 1 („0..1” sau 1) atunci valoarea acestei expresii este un obiect. Referitor la diagrama de clase din figura 2, dacă suntem în contextul Companie (deci self este instanţă a clasei Companie), putem scrie:

Page 128: software engineering

context Companie inv: self.manager.esteSomer = false

inv: self.angajat -> notEmpty() În primul invariant self.manager este o persoană, deoarece multiplicitatea asocierii este 1. În al doilea invariant self.angajat va fi evaluat ca mulţime de persoane. Observaţie. Colecţiile, cum ar fi mulţimi, secvenţe, sunt tipuri predefinite în OCL. Există şi un set de operaţii predefinite ce se pot efectua asupra lor. O proprietate a colecţiei este accesată folosind simbolul „->” urmat de numele proprietăţii.

Exemple context Persoana inv: self.angajator -> size() < 0 Proprietatea size se aplică asupra mulţimii self.angajator formată din numărul angajatorilor Persoanei self. context Persoana inv: self.angajator -> isEmpty() Proprietatea isEmpty se aplică asupra mulţimii self.angajator. Aceasta se evaluează ca fiind true dacă mulţimea angajaţilor este vidă şi false în caz contrar. Deoarece multiplicitatea unui rol manager este 1, self.manager este un obiect de tip Persoana. Un astfel de obiect singur poate fi utilizat ca Mulţime, presupunând de fapt că mulţimea are un singur element. Utilizarea ca mulţime este precizată prin utilizarea simbolului „->” urmat de numele proprietăţii mulţimii.

Exemple

context Companie inv: self.manager -> size() = 1 Sub-expresia self.manager este utilizată ca Mulţime deoarece se foloseşte săgeata pentru a accesa proprietatea size. Expresia precedentă este evaluată ca true.

context Companie inv: self.manager.varsta > 40 Sub-expresia self.manager este utilizată ca o Persoana deoarece se foloseşte simbolul „.” Pentru accesarea proprietatea varsta a Persoanei. În cazul unei asocieri opţionale (multiplicitate 0..1) este util de a verifica dacă există un obiect sau nu când se navighează spre asociere.

Exemplu context Persoana inv: self.sotie -> notEmpty() implies self.sotie.sex = Sex::feminin Proprietăţile pot fi combinate pentru a scrie expresii mai complicate. O regulă importantă

Page 129: software engineering

este că o expresie OCL se evaluează întotdeauna pe un obiect specific cu un tip specific. După obţinerea rezultatului se poate aplica întotdeauna o altă proprietate rezultatului pentru a obţine o altă valoare a rezultatului. Din acest motiv, fiecare expresie OCL poate fi citită şi evaluată de la stânga la dreapta. Exemplu: [1] Persoanele căsătorite au vârsta mai mare sau egală cu 18

context Persoana inv: self.sotie -> notEmpty() implies self.sotie.varsta >= 18 and self.sot -> notEmpty() implies self.sot.varsta >= 18

[2] o companie are cel mult 50 de angajaţi

context Companie inv: self.manager -> size() <= 50

În momentul în care proprietăţile se redefinesc în interiorul unui tip, proprietatea supra-tipului poate fi accesată utilizând operaţia oclAsType().Spre exemplu, dacă o clasă B este specializare a clasei A şi proprietatea p1 este a ambelor clase A şi B, se poate scrie:

context B inv: self.oclAsType(A).p1 -- se accesează proprietatea p1 definită în A self.p1 -- se accesează proprietatea p1 definită în B

Operaţii asupra tipurilor predefinite colecţie Tipurile colecţie definite în OCL sunt Set, Sequence, şi Bag. Tipul Set reprezintă o mulţime de valori în sens matematic (nu conţine duplicate). Tipul Bag este asemănător tipului Set, dar poate conţine duplicate. Tipul Sequence este asemănător tipului bag, elementele fiind însă ordonate. OCL are construcţii speciale pentru specificarea selecţiei dintr-o colecţie: select şi reject. Sintaxa este: colecţie -> select(...) Parametrii selecţiei au o sintaxă specială care permite specificarea elementelor din colecţie ce trebuie selectate. Un exemplu de astfel de parametri este următorul: colecţie -> select(expresie_booleană) Următoarea expresie OCL specifică faptul că mulţimea angajaţilor de peste 50 de ani nu este vidă:

context Companie inv: self.angajat -> select (varsta > 50) -> notEmpty() Contextul expresiei din argumentul construcţiei select este elementul colecţiei pentru care select este invocată. Astfel, proprietatea varsta e în contextul Persoana.

Page 130: software engineering

În exemplul precedent, este imposibilă referirea explicită la persoanele însele., referirea făcându-se doar la proprietăţile acestora. Pentru a evita acest inconvenient se foloseşte sintaxa: colecţie -> select(v | expresie_booleană_în_care_apare_v) Variabila v se numeşte iterator. Următoarele exemple sunt echivalente:

context Companie inv: self.angajat -> select (varsta > 50) -> notEmpty()

context Companie inv:

self.angajat -> select (p | p.varsta > 50) -> notEmpty() O altă extensie a sintaxei anterioare este aceea în care se dă şi tipul variabilei v. colecţie -> select(v:Type | expresie_booleană_în_care_apare_v) Exemplul următor este echivalent cu anteriorul: context Companie inv: self.angajat -> select (p:Persoana | p.varsta > 50) -> notEmpty() Operaţiunea reject este identică operaţiunii select, dar în acest caz se obţin elementele colecţiei pentru care expresia evaluată este false. Sintaxa este asemănătoare operaţiunii select: colecţie -> select(expresie_booleană) colecţie -> select(v | expresie_booleană_în_care_apare_v) colecţie -> select(v:Type | expresie_booleană_în_care_apare_v) Spre exemplu, pentru a specifica faptul că mulţimea angajaţilor care nu sunt căsătoriţi este vidă putem scrie:

context Companie inv: self.angajat -> reject (esteCasatorit) -> isEmpty()

Page 131: software engineering

PROIECTAREA SISTEMELOR SOFTWARE

1. Introducere Proiectarea sistemelor software poate fi privită ca un proces creativ de transformare a

unei probleme într-o soluţie; descrierea soluţiei face parte de asemenea din procesul de proiectare. Proiectarea presupune o experienţă practică, acumulată în timp şi implică o serie de paşi:

• Studiul şi înţelegerea problemei.

• Identificarea mai multor soluţii posibile şi evaluarea fiecăreia din ele. Alegerea ei depinde de experienţa proiectantului, simplitatea acesteia, valabilitatea componentelor reutilizabile.

• Descrierea fiecărei abstractizări a fiecărei soluţii. Înainte de crearea documentaţiei formale, ar putea fi necesar ca proiectantul să pregătească o descriere informativă a proiectului pentru a fi examinată în detaliu. În felul acesta, omisiunile şi erorile posibile ar putea fi eliminate înainte ca proiectul să fie documentat.

Pentru a transforma cerinţele într-un sistem funcţional, proiectanţii trebuie să ţină cont

atât de clienţi cât şi de programatori. Clienţii înţeleg ce face sistemul, în timp ce programatorii trebuie să înţeleagă cum funcţionează sistemul.

Din acest motiv, proiectarea are două părţi. Prima, proiectarea conceptuală, arată clientului exact ce va face sistemul. Odată ce clientul este de acord, proiectarea conceptuală se translează într-un document mai detaliat, proiectarea tehnică, care permite programatorilor să înţeleagă nevoile hard şi soft care pot rezolva problema clientului.

Activităţile esenţiale în cursul proiectării sunt următoarele:

• Proiectarea arhitecturală. Sub-sistemele întregului sistem sunt identificate şi documentate.

• Specificarea abstractă: Pentru fiecare sub-sistem, se prezintă o specificare abstractă a serviciilor şi a constrângerilor sub care acestea operează.

• Proiectarea interfeţelor. Pentru fiecare sub-sistem, interfaţa cu celelalte sub-sisteme este proiectată şi documentată.

• Proiectarea componentelor. Serviciile furnizate de un sub-sistem sunt partiţionate între componentele acelui sub-sistem.

• Proiectarea structurilor de date. Structurile de date utilizate în implementarea sistemului sunt proiectate în detaliu şi specificate.

• Proiectarea algoritmilor. Algoritmii utilizaţi pentru a furniza servicii sunt proiectaţi în detaliu şi specificaţi.

Acest proces se repetă pentru fiecare sub-sistem până când componentele identificate pot

fi mapate direct în componentele limbajului de programare Caracteristicile unei proiectări corecte

Ca rezultat al fazei de proiectare se obţine:

Page 132: software engineering

• Un model al codului care arată cum este implementat sistemul

• diagramă a dependenţelor dintre module, care arată cum va fi divizat în module sistemul şi cum interacţionează acestea

• Pentru module mai dificile, se includ specificaţii speciale Se pot defini nişte proprietăţi cheie pentru măsurarea calităţii proiectării şi anume:

Extensibilitatea • Proiectarea trebuie să poată suporta noi funcţii

• Modelul problemei trebuie să reflecte caracteristicile generale ale problemei

• Proiectarea trebuie să fie localizată; modulele trebuie decuplate cât mai mult

Siguranţa • Sistemul trebuie să aibă un comportament sigur, care nu presupune doar lipsa

„prăbuşirilor” sau a pierderii datelor, ci şi faptul că trebuie să ruleze corect, aşa cum se aşteaptă utilizatorul

• Pentru sistemele distribuite, este importantă disponibilitatea

• Pentru sisteme de timp real, este importantă sincronizarea

• Siguranţa nu poate fi introdusă uşor într-un sistem existent; cheia realizării de produse sigure este modelarea şi dezvoltarea atentă pe parcursul întregului ciclu de viaţă al produsului

Eficienţa • Sistemul trebuie să consume resurse în limite rezonabile

• O proiectare mai economică poate fi preferabilă uneia care îndeplineşte toate metricile de calitate dar este mai scumpă

• Puncte cheie

- Modelarea obiectelor (greu de modificat)

- Evitarea tendenţiozităţii (prin detalii de implementare)

- Optimizarea (nu trebuie făcută scăzând claritatea structurii) Metode de proiectare

1. Proiectarea structurată • metodele Yourdon, caracterizate de utilizarea: - Hărţilor Structurilor, pentru a evidenţia ierarhia, controlul şi fluxurile de date;

- pseudo-codului pentru descrierea procesului.

Există şi o versiune a lui DeMarco pentru proiectarea structurată.

Metode mai recente de proiectare structurată sunt cele ale lui Ward şi Mellor, în care ‘modelul esenţial’, obţinut în faza analizei, este transformat într-un ‘model de implementare’. Acesta este proiectat într-o manieră top-down prin alocarea funcţiilor către procesoare, taskuri şi module.

Page 133: software engineering

• SADT (Structured Analysis and Design Technique) - utilizează aceleaşi tehnici ale diagramelor atât pentru analiză cât şi pentru proiectare. Se poate utiliza pentru modelarea sistemelor de timp real, deoarece permite reprezentarea fluxurilor de control a datelor.

• SSADM (System Structured Analysis and Design Methodology) - SSADM rezultă într-un

model al proceselor şi al datelor. Modelele sunt construite în paralel şi fiecare este utilizat pentru verificarea consistenţei celorlalte, ceea ce constituie avantajul major al acestei tehnici. Nu suportă proiectarea sistemelor de timp real.

2. Proiectarea orientată obiect (OOD)

OOD este o strategie de proiectare bazată pe obiecte şi clase. Metodele orientate obiect oferă un suport mai bun de reutilizare decât celelalte metode. Mecanismul moştenirii permite refolosirea top-down a atributelor şi operaţiilor super-claselor.

Alte caracteristici ale strategiei orientată obiect sunt: • Comunicarea prin mesaje. Obiectele trimit mesaje spre alte obiecte pentru

executarea unor operaţii sau pentru transmiterea unor informaţii.

• Polimorfismul, reprezentând capabilitatea , în momentul execuţiei, de a referi instanţe ale diferitelor clase. El este implementat prin acceptarea “dynamic binding”, bazându-se pe alocarea dinamicã a memoriei.

Utilizarea proiectării orientate-obiect este avantajoasă doar atunci când implementarea se face într-un limbaj de programare care suportă definirea obiectelor, moştenirea, comunicarea prin mesaje şi polimorfismul (Smalltalk, C++, ObjectPascal). Tehnicile orientate obiect sunt mult mai potrivite pentru construirea sistemelor orientate-eveniment, cum sunt interfeţele GUI (Graphical User Interface), decât tehnicile structurate. Dacă se ia decizia de a se utiliza tehnica OO pentru dezvoltarea unui sistem, aceasta trebuie utilizată de-a lungul întregului ciclu de viaţă al sistemului. Booch a descris o tehnică de transformare a unui model logic construit folosind analiza structurată într-un model fizic utilizând proiectarea OO. In practică, rezultatele nu au fost satisfăcătoare. Analiza structurată se bazează pe funcţii şi date iar perspectiva OO este bazată pe clase, obiecte, atribute şi servicii. Perspectivele sunt diferite şi e dificil de a le avea pe amândouă simultan în minte. Ca şi analiza structurată, OOD este numele unei clase de metode OO: • Booch - continuă să reprezinte o metodă de referinţă în procesele de dezvoltare a sistemelor.

Booch modelează proiectul în termenii unei perspective logice (clase, obiecte şi relaţiile între ele) şi o perspectivă fizică (arhitectura modulelor şi proceselor).

Există 2 tipuri de diagrame: • diagrama modulelor pentru evidenţierea alocării claselor şi obiectelor în module

(programe sau taskuri). • diagrama proceselor care prezintă alocarea modulelor procesoarelor hardware.

• HOOD (Hierarchical Object-Oriented Design) - este o metodă care încearcă reunirea

metodei OO cu metodele structurate. Ierarhia decurge natural din descompunerea obiectului rădăcină. Ca şi în proiectarea structurată, fluxurile de date se reprezintă între componentele software. Principala diferenţă între HOOD şi metodele structurate este că identitatea componentelor software îşi au corespondent mai mult în lumea reală decât în cea a funcţiilor pe care sistemul trebuie să le îndeplinească. HOOD nu are o metodă complementară de analiză. Modelul logic al sistemului este construit prin metodele analizei structurate.

• Coad şi Yourdon. Un proiect OO este construit din 4 componente:

Page 134: software engineering

1. componenta domeniului problemei - se bazează pe modelul logic construit în timpul OOA. Dacă sistemul va fi implementat într-un limbaj de programare OO, atunci va exista o corespondenţă de 1 la 1 între clasele şi obiectele domeniului problemei.

2. componenta interacţiunii cu factorul uman - coordonează mesajele dinspre si spre utilizator.

3. componenta coordonării taskurilor - se refera la multiplele fire de execuţie, existente intr-un sistem.

4. componenta coordonării datelor - furnizează infrastructura pentru înregistrarea si regăsirea datelor.

Fiecare componentă este construită din clase şi obiecte. Clasele si obiectele sunt organizate în structuri generalizare-specializare şi întreg-parte. Structurile generalizare-specializare sunt “familii de arbori”, descendenţii moştenind

atributele şi serviciile părinţilor. Structurile întreg-parte sunt formate prin descompunerea unui obiect.

• OMT (Object Modelling Technique) - introdusă de Rumbaugh şi conţine 2 activităţi de proiectare:

- proiectarea sistemului

- proiectarea obiectelor • Shlaer-Mellor. Shlaer-Mellor descriu un limbaj pentru proiectarea OO (OODLE), derivat

din notaţiile Booch şi Buhr, punând în evidenţă 4 tipuri de diagrame: - diagrama claselor (definind atributele şi operaţiile clasei)

- clasa hărţilor structurii (definind structura modulelor claselor)

- diagrama dependinţelor între clase (tip client-server sau friend)

- diagrama moştenirilor (prezentând relaţiile de moştenire între clase) 3. Metode Formale - se aplică în faza proiectării doar dacă s-au aplicat în faza analizei.

Ele se recomandă pentru sistemele cu cerinţe critice din punct de vedere al siguranţei şi securităţii, furnizând specificaţii riguroase ale sistemului software.

Utilitare pentru proiectare

In cazul tuturor proiectelor, cu excepţia celor mici, se recomandă folosirea utilitarelor CASE. Documentul fazei de proiectare

Documentul fazei de proiectare este documentul cu care se finalizează această fază. El trebuie realizat de către dezvoltatorii de sisteme soft, cu aptitudini pentru proiectare şi implementare. Documentul trebuie să fie suficient de detaliat astfel încât coordonatorul proiectului să poată detalia un plan de implementare şi să poată urmări proiectul, în ansamblu, de-a lungul procesului de dezvoltare.

Page 135: software engineering

2. Proiectarea orientată – obiect (OOD). Metoda Coad-Yourdon

Modelul de proiectare OO Coad-Yourdon constă în patru componente: 1. componenta domeniului problemei (CDP)

2. componenta interacţiunii cu factorul uman (CIFU)

3. componenta coordonării taskurilor (CCT)

4. componenta coordonării datelor (CCD)

Aceste componente corespund următoarelor patru activităţi: 1. proiectarea componentei domeniului problemei

2. proiectarea componentei interacţiunii cu factorul uman

3. proiectarea componentei coordonării taskurilor

4. proiectarea componentei coordonării datelor

Există mai multe strategii care se pot aplica pentru realizarea proiectării orientate-obiect:

1. Se aplică OOA (analiza orientată obiect)

OOA este organizată în 5 straturi, OOD este organizată în 5 componente. Cum se vor aplica OOA şi OOD? Utilizând Waterfall, modelul spirală sau incremental ?

Prin Modelul Waterfall, un proiect include analiza, proiectarea, implementarea, cu o secvenţă strictă a acestora, deşi întoarceri în fazele anterioare sunt permise în timpul etapelor timpurii, în procesul de dezvoltare.

Prin Modelul spirală, un proiect include analiza, proiectarea, implementarea, cu specificarea , prototipizarea şi analiza riscurilor fiecărei faze.

Modelul incremental aplică OOA, OOD şi OOP într-un număr mai mic de paşi. Pentru fiecare increment, un profesionist poate utiliza toate cele trei activităţi la momente diferite de timp.

OOA şi OOD (metoda Coad-Yourdon) pot fi utilizate cu oricare din cele trei modele, menţionate mai sus. 2. Se utilizează rezultatele OOA, îmbunătăţindu-le în timpul OOD

Rezultatele OOA se preiau direct în componenta domeniului problemei cu eventuale modificări datorate schimbărilor cerinţelor utilizatorului sau neînţelegerii problemelor de către analist, etc. 3. Se utilizează rezultatele OOA şi se adaugă în timpul OOD

Criteriile de adăugare în CDP sunt: • reutilizarea claselor proiectate şi programate; • gruparea claselor specifice domeniului problemei; • stabilirea unui protocol prin adăugarea unei clase de generalizare; • acomodarea nivelului de moştenire; • îmbunătăţirea performanţei; • suportarea componentei coordonării datelor; • revizuirea adăugărilor rezultatelor OOA.

Ne vom referi în continuare la această din urmă strategie.

Page 136: software engineering

2.1 Proiectarea componentei domeniului problemei

2.1.1 Reutilizarea claselor proiectate şi programate

Se recomandă reutilizarea claselor deja proiectate sau programate. Ele se introduc în componenta domeniului problemei, marcându-se Atributele şi Serviciile ce nu vor fi utilizate şi introducându-se o structură Gen-Spec de la această clasă către o clasă din domeniul problemei. În această clasă-specializare se vor identifica Atributele şi Serviciile care se moştenesc acum din clasa adăugată. Se revizuiesc apoi structurile şi conexiunile dintre clase, mutându-le spre clasa nou adăugată (mediile CASE ar trebui să ţină cont de aceste modificări).

2.1.2 Gruparea claselor specifice domeniului problemei.

Aceasta este o modalitate de a grupa anumite clase specifice domeniului problemei într-o bibliotecă de clase, când un model mai sofisticat de grupare nu este disponibil. Acest mecanism constă în introducerea unei noi clase ca vârf al unei ierarhii conţinând clasele ce se doresc grupate împreună.

2.1.3 Stabilirea unui protocol prin adăugarea unei clase de generalizare

La un moment dat, e posibil ca un număr de clase specializate să necesite un protocol similar (trebuie deci să definească un set similar de Servicii şi de Atribute). În acest caz, poate fi introdusă o nouă clasă pentru a stabili acest protocol pentru definirea setului comun de Servicii, care vor fi definite în detaliu în clasele specializate.

2.1.4 Acomodarea nivelului de moştenire

Dacă Structurile Gen-Spec ale modelului OOA includ multiple moşteniri, trebuie făcute câteva modificări ale acestora atunci când se va utiliza un limbaj de programare OO care nu suportă mecanismul moştenirii sau care nu suportă decât moştenirea simplă.

Tipuri de moştenire multiplă:

1. Diamantul mic

Page 137: software engineering

2. Diamantul mare

Acomodarea cu limbajele care suporta doar simpla moştenire

În acest caz se pot aplica 2 metode de a transforma o moştenire multiplă într-o moştenire simplă:

1) formarea unor ierarhii separate, mapate între ele prin structuri Întreg-Parte sau prin Conexiunea Instanţelor

Exemplu:

Page 138: software engineering

Alternativ, aceasta poate fi modelată prin Conexiunea Instanţelor:

Exemplu:

2) Transformarea multiplei ierarhii intr-o ierarhie cu simplă moştenire - caz în care anumite Atribute şi Servicii vor fi repetate în clasele specializate.

Acomodarea cu limbajele care nu suporta mecanismul de moştenire

Fiecare structură Gen-Spec se va descompune în clasele-obiecte componente:

2.1.5 Îmbunătăţirea performanţei

Creşterea vitezei - e necesară când între Obiecte există in trafic prea mare de mesaje. În acest caz, se combină două sau mai multe clase. Singurul mod de a şti dacă aceste modificări contribuie la creşterea vitezei, este prin măsurare şi observare.

2.1.6 Suportarea componentei coordonării datelor

Pentru suportarea componentei de coordonare a datelor, fiecare Obiect care trebuie memorat trebuie să ştie cum să se auto-memoreze:

• fie i se adaugă un Atribut şi un Serviciu în acest scop • fie acest Obiect trimite un mesaj către componenta coordonării datelor cerându-i

memorarea sa

Page 139: software engineering

2.2 Proiectarea Componentei de Interacţiune cu Factorul Uman (interfeţei utilizator)

Interfaţa utilizator necesită o examinare detaliată atât în faza analizei cât şi a proiectării. În OOD, Interfaţa utilizator referă la proiectarea formatelor ferestrelor şi rapoartelor.

Prototipizarea este utilizată pentru a ajuta la selecţia şi dezvoltarea mecanismelor de interacţiune. Unele companii consideră important de a proiecta porţiuni ale interfeţei utilizator paralel cu faza analizei Aplicarea unei strategii sistematice suportate de prototipizare este vitală în acest domeniu.

Această componentă se referă la modul în care factorul uman va comanda sistemul şi modul în care sistemul va furniza informaţii utilizatorului.

2.2.1 Clasificarea utilizatorilor

Se recomandă a se apela şi la un specialist în studiul interacţiunilor umane şi în testarea acestora. Se vor studia viitorii utilizatori ai sistemului, urmărindu-i cum îşi desfăşoară activitatea. Se urmăreşte:

• ce probleme anume vor utilizatorii să rezolve;

• ce utilitare li se pot furniza pentru a-i ajuta;

• cum pot fi ele realizate fără a-i obstrucţiona în activitatea lor.

Utilizatorii pot fi clasificaţi după următoarele criterii: • nivelul de îndemânare: începător, ocazional, intermediar, avansat;

• nivelul organizaţional: executiv, conducere, supervizor, funcţionar;

• după apartenenţa la diferite grupuri: conducere, client.

2.2.2 Descrierea utilizatorilor

Pentru fiecare categorie de utilizatori din pasul anterior, se consideră următoarele: • profesiunea

• scopul

• caracteristici (vârsta, educaţie, restricţii)

• factori critici de succes (ce îi place, ce îi displace)

• nivelul de îndemânare

• scenariul de lucru

2.2.3 Proiectarea ierarhiei comenzilor

Pentru aceasta, se recomandă: • dacă ierarhia comenzilor trebuie să se integreze într-un sistem de interacţiuni deja

existent, acesta trebuie mai întâi studiat.

• stabilirea unei ierarhii iniţiale de comenzi care poate fi prezentată utilizatorilor în mai multe moduri:

- o serie de ecrane meniu

- o bară meniu

Page 140: software engineering

- o serie de imagini (icons) Se poate începe cu următoarea ierarhie de bază a comenzilor (Serviciilor):

File Edit Format Calculate Monitor Window • rafinarea ierarhiei comenzilor prin:

- ordonarea serviciilor din fiecare ramură a ierarhiei:

1) cele mai frecvente Servicii să apară primele în listă,

2) în ordinea logică în care trebuie să se execute.

- lăţimea şi adâncimea ierarhiei: evitarea supraîncărcării memoriei pe termen scurt a factorului uman.

- minimizarea numărului de paşi, de acţiuni (apăsări ale butonului mouse, combinaţii de chei) pe care trebuie să le efectueze utilizatorul pentru a-şi îndeplini sarcinile.

2.2.4 Proiectarea detaliată a interacţiunilor

Interacţiunile cu factorul uman pot fi proiectate pe baza următoarelor criterii: • consistenţa: se recomandă utilizarea unor termeni consistenţi şi acţiuni consistente.

• număr mic de paşi - trebuie să se minimizeze numărul de acţiuni pe care trebuie să le îndeplinească utilizatorul

• evitarea “aerului mort”- “dead air”; aer mort este un termen semnificând faptul că utilizatorul nu trebuie lăsat singur, fără nici un semnal, atunci când trebuie să aştepte ca sistemul să execute o acţiune. Utilizatorului trebuie să i se semnaleze:

- faptul că sistemul execută o acţiune;

- cât din acţiunea respectivă s-a realizat.

• undo: se recomandă a se furniza acest serviciu sistemului, datorită erorilor utilizatorului.

• timpul şi efortul de învăţare trebuie să fie scurt; în general, utilizatorii nu vor citi documentaţia. Se recomandă a se furniza referinţe on-line.

• prezentarea interfeţei - factorul uman utilizează un software care este plăcut şi amuzant.

2.2.5 Prototipizarea

Un bun punct de start este de a se folosi ca model un software deja existent cu o interfaţă bine realizată. Dacă exemplul ales face parte din domeniul problemei, este cu atât mai bine. Se consideră meniurile, submeniurile şi prescurtările deja existente. Se folosesc utilitare pentru prototipizări vizuale sau generatoare de aplicaţii. Se recomandă realizarea mai multor prototipuri care vor fi puse la dispoziţia utilizatorilor, urmărindu-le reacţiile în timp ce le folosesc.

2.2.6 Proiectarea claselor pentru Interfaţa Utilizator

Pentru a proiecta clasele pentru interfaţa utilizator se începe prin a organiza interacţiunile cu factorul uman în ferestre şi componente:

Fiecare clasă conţine definiţia pentru: menu-bar, pull-down menu, şi pop-up menu pentru o fereastră. Fiecare clasă defineşte Serviciile necesare pentru a crea meniurile, pentru a evidenţia un element selectat şi pentru a invoca răspunsul corespunzător. Fiecare clasă este

Page 141: software engineering

răspunzătoare pentru prezentarea informaţiei în interiorul ei şi încapsulează toate informaţiile pentru dialog. 2.3 Proiectarea Componentei de Coordonare a Taskurilor

Taskul este un alt nume pentru proces. Execuţia concurentă a mai multor taskuri se numeşte multi-tasking.

Taskurile multiple sunt necesare în unele cazuri: • pentru sistemele pentru achiziţie de date;

• pentru anumite interfeţe utilizator - acele care au multiple ferestre selectate pentru intrare;

• pentru sistemele multi-user;

• pentru arhitecturi multi-subsistem;

• pentru cazul mai multor taskuri şi un singur procesor; un task trebuie să coordoneze şi să comunice cu alte taskuri în timpul execuţiei; asemenea taskuri se execută prin partajarea timpului procesor, creând iluzia că se execută în paralel;

• pentru arhitecturile multi-procesor.

Taskurile separă acţiunile care trebuie să aibă loc în paralel. Această comportare concurentă poate fi implementată pe procesoare separate sau poate fi simulată pe un singur procesor în conjuncţie cu un sistem de operare multi-tasking. O alternativă este de a considera un program secvenţial ciclic. După executarea fiecărei părţi de program el verifică ce s-a întâmplat cât timp a fost ocupat răspunzând corespunzător. O abordare neeficientă ar fi de a intercala comportări concurente într-un singur program secvenţial, rezultând un program foarte mare şi necesitând teste la fiecare câteva linii de cod, teste care să verifice intrarea datelor sau diverse cereri. Utilizarea taskurilor va simplifica proiectarea şi implementarea acţiunilor concurente.

Scopul acestei strategii este de a identifica şi de a proiecta taskurile şi Serviciile incluse în fiecare task: 1. identificarea taskurilor determinate de evenimente (taskuri responsabile pentru comunicarea

cu un dispozitiv, una sau mai multe ferestre pe ecran, un alt task, sub-sistem sau procesor. Taskul poate fi proiectat pentru a se declanşa la un anumit eveniment, deseori semnalând apariţia unor date).

2. identificarea taskurilor determinate de ceas (aceste taskuri se declanşează la anumite intervale de timp).

3. identificarea taskurilor prioritare şi critice. E posibil ca unele Servicii să fie de prioritate maximă. Acestea trebuie izolate într-un task separat de prioritate mare. Alte Servicii sunt de mică prioritate, iar altele sunt critice.

4. identificarea unui task coordonator - acest task coordonează executarea celorlalte taskuri

5. definirea fiecărui task:

• numele taskului şi o scurtă descriere

• adaugă fiecărui Serviciu identificat un nume de task. Fiecare Serviciu este mapat unui task.

Page 142: software engineering

• specifică dacă taskul este coordonat de eveniment (şi indică evenimentul respectiv) sau ceas (indică intervalul de timp la care se declanşează)

• specifică modul de comunicare (de unde îşi ia intrarea şi unde trimite rezultatele) Paragrafele anterioare pot fi rezumate prin următoarea schemă privind componenta de

coordonare a taskurilor:

2.4 Proiectarea Componentei de Coordonare (Gestiune) a Datelor

Componenta de coordonare a datelor furnizează infrastructura pentru depozitarea şi regăsirea obiectelor dintr-un sistem de coordonare a datelor.

Există trei abordări majore pentru coordonarea datelor: • coordonarea datelor utilizând fişiere • sistem de coordonare a datelor prin baze de date relaţionale.

Din categoria sistemelor de gestiune a bazelor de date relaţionale enumerăm: dBASE, FOXBASE, FOXPRO, ORACLE, INGRES, INFORMIX, DB2, CAMPUS, ACCESS. Un astfel de sistem coordonează datele printr-un număr de tabele, fiecare având un nume. Fiecare coloană are un nume şi conţine o singură valoare (atomică). Fiecare rând reprezintă un set de valori în tabel. Rândurile sunt unic identificabile. Una sau mai multe coloane pot fi definite drept chei primare-unicul identificator pentru fiecare rând din tabel. Una sau mai multe coloane pot fi definite drept chei externe (străine) pentru a facilita accesul la rândurile corespunzătoare din alt tabel. Tabelele şi coloanele pot fi reorganizate pentru a reduce redundanţa datelor şi deci numărul de paşi pentru modificarea consistentă a datelor. Această reorganizare poartă numele de normalizare. Gradul de eliminare a redundanţei datelor e definit ca “forme normale”.

• sistem de coordonare a datelor prin baze de date orientate obiect

Page 143: software engineering

Sistemele de gestiune a bazelor de date orientate-obiect reprezintă o tehnologie încă în curs de implementare. Primele produse comerciale au apărut în 1986. Există 2 mari abordări:

- produsele relaţionale extinse - produsele limbajelor de programare extinse orientate-obiect Produsele relaţionale extinse extind sistemele de gestiune a bazelor de date

relaţionale, adăugând tipuri de date abstracte, mecanismul de moştenire şi câteva Servicii pentru crearea şi manipularea Claselor şi Obiectelor. Produsele limbajelor de programare extinse orientate-obiect extind un limbaj de programare orientat-obiect cu sintaxă şi capabilităţi de gestiune a Obiectelor într-o bază de date.

Proiectarea componentei de coordonare a datelor constă în proiectarea machetelor de date

şi a Serviciilor corespunzătoare.

Proiectarea machetelor datelor se realizează funcţie de abordarea aleasă, din cele trei expuse mai sus, pentru coordonarea datelor.

Definirea Serviciilor corespunzătoare constă în adăugarea unui Atribut şi Serviciu fiecărei Clase&Obiect căreia îi corespund Obiecte ce trebuie memorate. În acest fel un Obiect trebuie să ştie singur cum să se înregistreze. Un Obiect trebuie să ştie ce fişier (tabel) trebuie să deschidă, cum să poziţioneze fişierul pe înregistrarea corectă, cum să regăsească vechi valori, şi cum să se actualizeze. Se defineşte o Clasă&Obiect, ObiectServer, cu Servicii pentru:

1) a semnala fiecărui Obiect să se salveze (în fişier);

2) a regăsi Obiecte înregistrate (căutări, creări şi iniţializări de Obiecte).

Page 144: software engineering

Modele de proiectare

Modelele (şabloanele) de proiectare se utilizează în toate domeniile care implică o activitate de proiectare. În domeniul sistemelor software orientate-obiect soluţiile sunt exprimate în termeni de obiecte şi interfeţe. Esenţa noţiunii de şablon este aceeaşi: un şablon (pattern) reprezintă o soluţie comună a unei probleme într-un anumit context.

Modelele de proiectare utilizate în sistemele orientate-obiect se pot clasifica în: • idiomuri – legate de anumite limbaje de programare şi care se referă la practici sau

obiceiuri „bune”, care se indică a se utiliza când utilizăm limbajul respectiv.

• mecanisme – structuri în cadrul căreia obiectele colaborează în vederea obţinerii unui anumit comportament care satisface o anumită cerinţă a problemei.

- decizii de proiectare privind modul în care operează colecţiile de obiecte.

- se mai numesc şabloane de proiectare (design patterns)

• cadre (frameworks) – descriu şi menţin cu ajutorul unui set de clase abstracte relaţii între obiecte. De exemplu, un editor grafic este specializat pentru diferite domenii: editor muzical, editor CAD etc. Scheletul unei aplicaţii „editor grafic” poate fi gândit fără să se ţină cont de domeniul particular în care se va folosi. Indiferent de tipul editorului, se poate „inventa” un set de clase abstracte, relaţii între ele şi cod generic ce va fi reutilizat în fiecare caz concret.

Un proiectant experimentat ştie că nu trebuie să rezolve fiecare problemă începând de la

zero, ci reutilizând soluţii (bune) din proiecte anterioare. Atunci când descoperă o soluţie bună o va folosi mereu.

Pentru descrierea modelelor de proiectare se utilizează notaţii grafice (în UML) şi un limbaj care permite o descriere uniformă a tuturor modelelor. Formatul de descriere variază, dar în general cuprinde secţiunile:

• numele modelului – descrie sintetic problema rezolvată de model şi soluţia; când este un „pattern” clasic se precizează şi categoria din care face parte.

• scopul – se precizează pe scurt ce problemă rezolvă.

• problema – descriere mai largă a problemei rezolvate şi a contextului în care ea apare.

• soluţia – descriere a elementelor de proiectare utilizate şi a relaţiilor dintre ele. Soluţia nu descrie un proiect particular sau o implementare concretă, ci un ansamblu abstract de clase şi obiecte care rezolvă un anumit gen de probleme de proiectare.

• consecinţele implicate de folosirea modelului – acestea pot privi impactul asupra flexibilităţii, extensibilităţii sau portabilităţii sistemului, după cum pot să se refere la aspecte ale implementării sau limbajului de programare utilizat.

În funcţie de scopul lor, modelele de proiectare se pot clasifica în: • modele creaţionale – privesc modul de descriere al obiectelor;

(abstract factory, builder, factory method, prototype, singleton)

Page 145: software engineering

• modele structurale – se referă la compoziţia claselor sau obiectelor;

(adapter, bridge, composite, decorator, façade, flyweight, proxy)

• modele comportamentale – caracterizează modul în care obiectele şi clasele interacţionează şi îşi distribuie responsabilităţile.

(chain of responsibility, command, interpreter, iterator, mediator, memento, observer, state, strategy, template method, visitor)

În funcţie de domeniul de aplicare, modelele de proiectare se pot aplica obiectelor sau

claselor.

Modele de proiectare pentru obiecte se referă la relaţiile dintre instanţe, relaţii care au un caracter dinamic.

• Modelele creaţionale ale obiectelor acoperă situaţiile în care o parte din procesul creării unui obiect cade în sarcina unui alt obiect.

• Modelele structurale ale obiectelor descriu căile prin care se asamblează obiecte.

• Modelele comportamentale ale obiectelor descriu modul în care un grup de obiecte cooperează pentru a îndeplini o sarcină ce nu ar putea fi efectuată de un singur obiect

Modelele de proiectare ale claselor se referă la relaţiile dintre clase, relaţii stabilite prin moştenire şi care sunt statice (fixate la compilare).

• Modelele creaţionale ale claselor acoperă situaţiile în care o parte din procesul creării unui obiect cade în sarcina subclaselor.

• Modelele structurale ale claselor descriu modul de utilizare al moştenirii în scopul compunerii claselor.

• Modelele comportamentale ale claselor utilizează moştenirea pentru descrierea unor algoritmi şi fluxuri de control.

Scop-Domeniu aplicare Creaţionale Structurale Comportamentale Clasă factory method adapter (class) interpreter

template method Obiect abstract factory

builder prototype, singleton

adapter (object) bridge composite decorator façade flyweight proxy

chain of responsibility command iterator mediator memento observer state strategy visitor

Page 146: software engineering

3.1 Modele creaţionale 3.1.1 Modelul Singleton / Unicat

Scop: Garantarea existenţei unei singure instanţe a unei clase. Se asigură o modalitate de a accesa instanţa respectivă. Se furnizează un punct global de acces la ea.

Motivaţie: există situaţii în care unele clase trebuie să aibă exact o singură instanţă. – Un singur spooler – Un singur sistem de fişiere – Un singur gestionar de ferestre

Aplicabilitate : pattern-ul Singleton se foloseşte atunci când: – trebuie să existe o singură instanţă a unei clase şi trebuie să fie accesibilă

clienţilor din diferite puncte de acces; – o singură instanţă ar trebui extinsă în subclase şi clienţii ar trebui să folosească

instanţa extinsă fără să-şi modifice codul. Structura:

3.1.2 Modelul abstract factory / fabrică abstractă

Scop: Oferă o interfaţă pentru crearea unei familii de obiecte înrudite sau dependente, fără a specifica explicit clasele lor concrete.

Motivaţie: Să considerăm o aplicaţie care suportă mai multe moduri de prezentare. Acestea implică diferite imagini şi comportamente pentru componentele interfeţei utilizator, cum ar fi scrollbar-uri, ferestre şi butoane

Aplicabilitate: – Sistemul trebuie să fie independent de modul în care produsele cu care lucrează

sunt create, compuse şi reprezentate. – Sistemul trebuie să fie configurat în una sau mai multe familii de produse. – O familie de produse sunt proiectate să funcţioneze doar împreună. – Se doreşte proiectarea unei familii de produse înrudite care să lucreze împreună şi

această constrângere ar trebui păstrată. – Se doreşte furnizarea unei librării de produse şi dorim să facem publică interfaţa

acestora, dar nu şi implementarea. Participanţi:

- AbstractFactory – declară o interfaţă pentru operaţii de creare a produselor abstracte - ConcreteFactory – implementează operaţiile de creare a produselor concrete - AbstractProduct – declară o interfaţă pentru o categorie de produse - Client – utilizează doar interfeţele AbstractFactory şi AbstractProdus

Consecinţe: - izolează clasele (se izolează clienţii de implementarea claselor); clienţii

manipulează instanţele prin interfeţele lor abstracte; deoarece o clasă factory abstractă creează o familie de produse, întreaga familie se schimbă simultan;

- asigură consistenţa între produse;

Page 147: software engineering

- suportarea noilor tipuri de produse este dificilă (implică extinderea interfeţei). Structura:

3.1.3 Modelul builder

Scop: Separă construirea unui obiect complex de reprezentarea sa, astfel ca procesul de construire să poată crea diferite reprezentări.

Aplicabilitate: – Algoritmul de creare a unui obiect complex este independent de părţile care

compun efectiv obiectul. – Sistemul trebuie să permită diferite reprezentări pentru obiectele care sunt

construite. Motivaţie:

Structura:

Page 148: software engineering

3.1.4 Modelul Factory Method / Metodă fabrică

Scop: Defineşte o interfaţă pentru crearea unui obiect, dar lasă în sarcina subclaselor alegerea tipului acestuia.

Motivaţie: – O bibliotecă foloseşte clase abstracte pentru a defini şi menţine relaţii între

obiecte. – Un tip de responsabilitate este crearea de astfel de obiecte. – Biblioteca ştie când trebuie creat un obiect, dar nu şi ce tip de obiect trebuie creat

(acesta este specific aplicaţiei care foloseşte biblioteca) Exemplu

Aplicabilitate: – Când o clasă nu poate anticipa tipul obiectelor care trebuie să le creeze – Când o clasă vrea ca subclasele să specifice tipul obiectelor de creat

Structura:

3.1.5 Modelul Prototype / Prototip

Page 149: software engineering

Scop. Specifică ce obiecte trebuie create folosind o instanţă pe post de prototip. Noile obiecte sunt create prin copierea acestui prototip.

Motivaţie: aplicaţie grafică / drag-and-drop Aplicabilitate

– Sistem independent de cum sunt create produsele şi – Una dintre următoarele

• Clasele de instanţiat sunt specificate în momentul rulării • Se doreşte evitarea creării unei ierarhii de fabrici • Este mai convenabil să copiez o instanţă existentă decât să creez una nouă. •

3.2 Modele structurale

3.2.1 Modelul Façade / Faţadă

Scop: oferă o interfaţă unificată pentru un set de interfeţe dintr-un sistem. Motivaţie:

– subsisteme = reducerea complexităţii – Minimizarea comunicaţiei dintre subsisteme

Aplicabilitate:

– Se doreşte utilizarea unei interfeţe simplificate la un sistem complicat – Există multe dependenţe între clienţi şi implementările concrete ale conceptelor – Se doreşte stratificarea sistemului

Page 150: software engineering

3.2.2 Modelul Adapter / Adaptor

Scop – converteşte interfaţa unei clase la interfaţa pe care clienţii acesteia o aşteaptă. – permite inter-operabilitatea claselor care altfel nu ar fi compatibile

Motivaţie – O clasă dintr-o bibliotecă, proiectată să fie reutilizabilă, nu este reutilizabilă din

simplul motiv că interfaţa acesteia nu se potriveşte cu una specifică domeniului în care se doreşte utilizată.

Aplicabilitate – Se doreşte utilizarea unei clase cu o interfaţă incompatibilă – Se doreşte crearea unei clase reutilizabile ce colaborează cu clase neprevăzute – (adaptor de obiecte) Se doreşte folosirea a câtorva subclase, dar adaptarea prin

derivare este nepractică.

3.2.3 Modelul Proxy / Substitut

Scop

Page 151: software engineering

– Oferă un surogat sau înlocuitor pentru un obiect, prin care se controlează accesul la acel obiect.

Motivaţie – Creare / iniţializare la cerere a obiectelor

Aplicabilitate – Substitut pentru depărtat, ambasador – Substitut virtual – Substitut protector – Referinţă deşteaptă

• Indicator deştept • Încărcarea unui obiect persistent la prima accesare • Asigurarea excluderii mutuale

Tipuri de obiecte proxy: – Cache Proxy: salvează resurse memorând rezultate temporare – Count Proxy: face si alte operaŃii înainte/după apelarea subiectului real – Protection Proxy: controlează accesul la obiectul real – Remote Proxy: reprezentant local al unui obiect aflat la o altă adresă – Virtual Proxy: creează obiecte la cerere (când este nevoie de ele)

3.2.4 Modelul Decorator

Scop: – Obiectelor li se pot ataşa responsabilităţi în mod dinamic. – Alternativă flexibilă la derivare pentru extinderea funcţionalităţii

Motivaţie:

Aplicabilitate:

– Adăugarea responsabilităţilor în mod dinamic şi transparent – Retragerea responsabilităţilor

Page 152: software engineering

– Atunci când derivarea devine nepractică Structura:

3.2.5 Modelul Composite / Amestec

Scop: – Se doreşte gruparea obiectelor în structuri arborescente pentru a reprezenta relaţii

de tip parte-întreg. – Obiectele şi amestecurile de obiecte sunt tratate uniform.

Motivaţie:

Aplicabilitate: – Reprezentarea relaţiei parte-întreg – Ignorarea diferenţei dintre obiecte individuale şi amestecuri de obiecte

Structura

Page 153: software engineering

Participanţi: • Component (Grafic)

- declară interfaţa pentru obiectele compuse - declară o interfaţă pentru accesarea şi maparea componentelor copil - defineşte o interfaţă pentru accesarea componentelor părinte într-o

structură recursivă • Leaf (Rectangle, Line, Text etc.) – reprezintă obiectele frunză • Composite (Picture)

- defineşte comportamentul pentru componentele care au copii - memorează componentele copil

• Client – manipulează obiectele 3.2.6 Modelul Flyweight / Muscă

Scop: – Folosirea partajării pentru gestionarea unui număr mare de obiecte cu granulaţie

mică. Numărul total de obiecte este mult mai mare decât numărul de obiecte distincte. Starea unui obiect poate fi divizată în două părţi distincte: stare extrinsecă şi stare intrinsecă. Starea intrinsecă reprezintă partea constantă (nu este modificată de alte acţiuni). Starea extrinsecă este dependentă de context şi este transmisă ca argument al unei metode.

Motivaţie

Aplicabilitate (îndeplinirea simultană a condiţiilor): – Aplicaţia foloseşte un număr mare de obiecte.

Page 154: software engineering

– Spaţiul necesar stocării este foarte mare din cauza numărului mare de instanţe – Cea mai mare parte a stării unui obiect poate fi făcută extrinsecă – Multe grupe de obiecte pot fi înlocuite cu relativ puţine obiecte partajate – Aplicaţia nu depinde de identitatea obiectelor

Structura:

Observaţie: FlyweightFactory creează şi gestionează obiectele „flyweight”

3.2.7 Modelul Bridge / Punte

Scop – Decuplarea unei abstractizări de implementarea sa astfel încât cele două să poată

varia independent Exemplu:

O arhitectură îmbunătăţită se poate vedea mai jos:

Page 155: software engineering

Motivaţie:

– Când o abstractizare are câteva implementări posibile, se foloseşte de obicei moştenirea

– Folosirea moştenirii în această situaţie duce la cod greu de modificat şi de extins. – Punerea abstractizărilor şi a implementărilor în ierarhii diferite duce la crearea de

cod mai uşor de întreţinut Structura:

3.3 Modele comportamentale

3.3.1 Modelul Chain of Responsibility / Lanţ de responsabilităţi

Scop: – evită cuplarea emiţătorului unei cereri de receptorul acesteia dând posibilitatea

mai multor obiecte să trateze cererea. – obiectele sunt înlănţuite, iar cererea este trimisă de-a lungul lanţului din obiect în

obiect până când un obiect o va trata. Motivaţie: help contextual

Page 156: software engineering

Structura:

Aplicabilitate: – Mai multe obiecte pot trata o cerere, iar obiectul care o va trata nu este cunoscut a

priori, el va fi determinat in mod automat. – Se doreşte ca cererea să fie făcută unui grup de obiecte fără a specifica în mod

explicit receptorul acesteia. – Mulţimea obiectelor care pot trata cererea trebuie specificată în mod dinamic.

Alt tip de structură:

Page 157: software engineering

3.3.2 Modelul Command / Comandă

Scop: – încapsulează o cerere sub forma unui obiect; – permite parametrizarea clienţilor cu cereri diferite; – permite memorarea cererilor într-o coadă; – suportă operaţii reversibile (undoable operations)

Motivaţie: – asignarea unor funcţionalităţi opţiunilor dintr-un meniu

Exemplu:

Page 158: software engineering

- definirea macrourilor = secvenţă de comenzi Exemplu:

Aplicabilitate:

– Parametrizarea obiectelor în funcţie de acţiunea care trebuie să o facă; – Specificarea, adăugarea într-o coadă şi executarea cererilor la momente diferite; – Suportă operarţii reversibile (metoda Execute poate memora starea şi permite apoi

revenirea la această stare); – Structurează sistemul în operaţii de nivel înalt care sunt construite pe baza unor

operaţii primitive (ex. tranzacţii).

Structura:

Page 159: software engineering

3.3.3 Modelul Iterator

Scop: Oferă o modalitate de a accesa obiecte agregate în mod secvenţial fără a cunoaşte modul de agregare.

Motivaţie – exemple:

Page 160: software engineering

Structura:

3.3.4 Modelul Mediator

Scop:Defineşte un obiect care încapsulează modul de interacţiune al unui set de obiecte. Promovează cuplarea slabă.

Motivaţie: În aplicaţiile reale, putem ajunge în situaţii în care fiecare obiect este legat cu fiecare (ceea ce nu e indicat).

Page 161: software engineering

Aplicabilitate: – Un set de obiecte interacţionează într-un mod determinat dar complicat – Reutilizarea unui obiect este dificilă din cauza comunicării cu multe alte obiecte. – Comportamentul distribuit prin multe clase să fie refolosit fără folosirea excesivă

a moştenirii Structura

Page 162: software engineering

Exemplu

Page 163: software engineering

3.3.5 Modelul Memento

Scop: Fără violarea încapsulării, captarea şi externalizarea stării interne a unui obiect astfel ca obiectul să îşi poată reface starea mai târziu.

Motivaţie: refacere Aplicabilitate:

– Un instantaneu al unei (sub)stări ale unui obiect trebuie luat pentru a fi restaurat şi – O interfaţă directă pentru obţinerea stării ar expune detalii de implementare şi ar

compromite încapsularea Structura:

Consecinţe:

Page 164: software engineering

– Păstrează graniţele încapsulării – Simplifică obiectul Originator – Folosirea memento-urilor poate fi costisitoare si poate induce costuri ascunse

3.3.6 Modelul Observer / Observator

Scop: defineşte o dependenţă de tip 1-la-n între obiecte, astfel ca atunci când un obiect se modifică, cele care depind de el sunt notificate şi actualizate automat.

Motivaţie

Aplicabilitate

– Când o abstractizare are două aspecte. Încapsularea fiecăruia în obiecte diferite permite modificarea şi refolosirea lor independentă.

– Când o schimbare a unui obiect are ca efect schimbări ale altor obiecte, fără a şti de la început câte obiecte sunt în această situaţie.

– Când se doreşte decuplarea obiectelor notificate de obiectul care se schimbă. – Când un obiect are posibilitatea să anunţe ceva altor obiecte (notify) fără să

cunoască cine sunt aceste obiecte. – Fiecare obiect observabil (subiect) poate să aibă unul sau mai mulţi observatori

Structura:

Page 165: software engineering

În UML interacţiune dintre obiectele participante în model poate fi descrisă cu diagrame de secvenţe:

3.3.7 Modelul State / Stare

Scop: Permite unui obiect să îşi schimbe comportamentul atunci când starea sa se modifică.

Motivaţie

Page 166: software engineering

Aplicabilitate: – Comportamentul unui obiect depinde de stare. Schimbarea comportamentului

trebuie să fie făcută în timpul rulării. – Se doreşte evitarea existenţei unei structuri decizionale identice în fiecare metodă.

Structură

3.3.8 Modelul Strategy / Strategie

Scop: Se defineşte o familie de algoritmi; se încapsulează fiecare membru; algoritmii se fac interschimbabili.

Motivaţie:

Aplicabilitate: – Multe clase înrudite diferă doar prin comportament – Se folosesc diverse variante ale unui algoritm – Algoritmii folosesc date irelevante pentru client – O clasă defineşte comportamente multiple, definite de condiţii gardă la începutul

metodelor. Structură

Contextul este configurat cu una din strategiile concrete. Menţine o referinţă către interfaţa Strategy, prin care accesează operaţiile publice ale strategiei cu care este configurat. Poate să pună la dispoziţia strategiilor o interfaţă de acces la datele prelucrate de strategia concretă. Strategy introduce interfaţa comună strategiilor concrete.

Page 167: software engineering

3.3.9 Modelul Template Method / Metodă şablon

Scop: Se defineşte scheletul unui algoritm într-o metodă, lăsând implementarea paşilor algoritmului în seama subclaselor.

Motivaţie:

Aplicabilitate: – Implementarea structurii fixe a unui algoritm, lăsând clasele derivate să

implementeze funcţionalitatea care variază – Când funcţionalitatea comună a unor clase este relocată într-o clasă de bază

Structură

3.3.10 Modelul Visitor / Hoinar

Scop: Reprezintă o operaţie ce se efectuează asupra structurii obiectului. Permite definirea de noi operaţii fără a schimba clasele elementelor asupra cărora se lucrează.

Motivaţie – exemple:

Page 168: software engineering

Structura:

Page 169: software engineering

1

IMPLEMENTAREA SISTEMELOR SOFTWARE

În faza de implementare este produs codul corespunzător proiectului furnizat de faza proiectării, îndeplinind restricţiile de resurse, acurateţe şi performanţă indicate de specificaţii. Procesul implementării este cel mai dificil de descris, nefiind riguros definit.

Implementarea este procesul transformării abstractizării prezentate în proiect într-o realizare fizică utilizând limbajul arhitecturii ţintă.

O problemă majoră a fazei de implementare constă în dificultatea translării proiectului în cod sursă. Oricât de bun ar fi proiectul este necesar un efort oarecare de a scrie codul corespunzător, ori aceasta este o sursă de a introduce erori.

Procesul de transformare proiect-implementare este şi mai dificil când proiectul nu este complet, consistent sau nu comunică exact şi inteligibil ceea ce se doreşte din partea sistemului. Erorile de proiectare determină pierderea timpului programatorilor în a rezolva probleme greşite puse. Acestea sunt erorile de logică şi sunt cele mai frecvente. De aceea este foarte importantă utilizarea unor metode riguroase pentru prezentarea proiectului.

Efectele exacte ale utilizării unui anumit sistem de operare sau limbaj de programare sunt în afara scopului proiectantului dar reprezintă o importantă decizie a programatorului.

În cele din urmă, implementarea însăşi este predispusă către erori, fiind un proces creator uman. Limbajul de programare poate fi folosit incorect, aceasta însemnând că oarecare timp şi efort se vor consuma pentru corectarea acestor erori. Din păcate, corectarea erorilor nu este o sarcină uşoară. S-a constatat că un programator are 50% şanse să descopere eroarea într-un interval de 5-10 linii de cod şi numai 20% şanse să o descopere într-un domeniu de 40-50 linii.

Documentele de bază produse în această fază sunt: • codul sursă şi obiect comentate într-o formă standard sau respectând anumite

convenţii • pliante (dosare) ale software-ului, prezentând modulele software individuale • manualul de utilizare a produsului software, prezentând convenţiile utilizate în

programe, o prezentare generală a implementării, descrierea particularităţilor • planul pentru coordonarea configuraţiei • planul pentru testarea produsului

Un aspect important în managementul fazei de implementare este cel al

managementului configuraţiei sistemului software. Motivul constă în faptul că produsul se găseşte în diverse faze pe măsură ce echipele de programatori implementează diferite părţi ale sale şi nu există un produs “întreg” până la integrarea tuturor modulelor. De aceea, la anumite intervale de timp, toate modulele vor fi reunite formând o anumită versiune a produsului, baza de la care programatorii vor lucra în continuare.

1. Scrierea codului

Codul este produs în module. Fiecare modul trebuie să fie inteligibil pentru cel care îl verifică şi pentru programatorul care ulterior îl va întreţine.

Fiecare modul : • include un header introductiv (titlu, nume autor, data creării, istoria modificărilor) • declară toate variabilele şi le documentează • foloseşte nume semnificative şi neambigue pentru variabile, funcţii, etc.

Page 170: software engineering

2

• foloseşte comentarii (acestea se recomandă pentru zonele dificile ale codului şi nu pentru cele evidente. Se recomandă să se separe comentariile de codul sursă prin linii vide)

• evită ascunderea logicii modulului de către codul de diagnoză (Codul de diagnoză se utilizează, de obicei, pentru a afişa conţinutul unor variabile sau pentru a evidenţia starea programului. Există tendinţa de a şterge acest cod din versiunea finală a sistemului, totuşi ele este folositor şi în faza de întreţinere a sistemului. De aceea, se recomandă ca acest cod să fie comentat sau compilat condiţionat (inclus ca linii de depanare)).

• utilizează regulile programării structurate • este consistent în folosirea limbajului de programare (păstrează acelaşi stil) • menţine un cod cât mai scurt şi mai simplu (Un modul trebuie să aibă o astfel de

dimensiune încât să fie vizibil dintr-o dată. Lungimea maximă recomandată este de 50 linii, fără a considera header-ul şi codul de diagnoză. În ceea ce priveşte simplitatea codului, numărul de elemente care trebuie cuprinse mental examinând o parte a modulului nu trebuie să depăşească aproximativ 7 elemente.)

• are o prezentare care să evidenţieze uşor logica de control (Tehnica obişnuită este de a separa blocurile între ele prin linii vide şi de a alinia blocurile din diversele construcţii ale limbajului. Se recomandă a nu se utiliza mai multe instrucţiuni pe aceeaşi linie.)

Standardele codării trebuie să fie stabilite pentru fiecare limbaj utilizat şi prevăzut în

documentaţia sistemului. Aceste standarde trebuie să furnizeze reguli pentru: • prezentarea informaţiilor (din header) şi forma comentariilor • denumirea programelor, subprogramelor, fişierelor, variabilelor şi datelor • limitarea dimensiunii modulelor • folosirea rutinelor de bibliotecă • definirea constantelor • definirea tipurilor de date • folosirea datelor globale • tratarea erorilor

2. Metode pentru implementare

În faza de implementare se extinde mai întâi proiectul din faza anterioară la componentele primitive ale sistemului. Se vor folosi aceleaşi metode din faza de proiectare (proiectarea structurată, proiectarea orientată-obiect, dezvoltarea sistemelor Jackson, metode formale).

Următorul pas este a defini procesarea fiecărui modul prin metode ca: hărţi de fluxuri (fowcharts), rafinarea pas cu pas, programarea structurată, limbaje de proiectare a programelor (PDL), pseudo-codul, programarea structurată Jackson.

Producerea codului implică scrierea codului într-un limbaj de programare, verificarea şi integrarea sa cu alte coduri pentru obţinerea unui sistem final.

În scopul scrierii codului se vor utiliza limbajele de programare. Limbaje de programare

Următoarele clase de limbaje de programare sunt larg recunoscute: a) limbaje procedurale (imperative sau algoritmice) b) limbaje orientate-obiect

Page 171: software engineering

3

c) limbaje funcţionale d) limbaje de programare logică

Limbajele funcţionale şi logice sunt numite şi declarative deoarece permit programatorului să declare “ce” trebuie executat şi nu “cum”. a) Limbaje procedurale - suportă următoarele caracteristici:

• secvenţa (permite specificarea ordinii execuţiei instrucţiunilor) • selecţia (permite evaluarea unei condiţii ţi luarea unei decizii) • iteraţia (permite structurilor repetitive) • diviziunea în module (permite descompunerea funcţională) Limbajele procedurale tradiţionale sunt COBOL şi FORTRAN. Unele limbaje procedurale suportă: • structurarea în blocuri - impune ca un modul să aibă un singur punct de intrare şi

un singur punct de ieşire. Pascal, Ada şi C suportă această caracteristică. • tipizarea puternică - impune ca tipul fiecărei date să fie declarat. Acest lucru

previne aplicarea operatorilor asupra obiectelor incompatibile din punct de vedere al tipului. Această caracteristică ajută compilatorul în evidenţierea erorilor şi în compilarea eficientă. Ada şi Pascal sunt limbaje puternic tipizate.

• recursivitatea - permite unui modul să se autoapeleze. Pascal, Ada şi C suportă recursivitatea.

b) Limbaje orientate-obiect - suportă toate caracteristicile limbajelor de programare structurată şi, în plus:

• moştenirea - tehnica prin care modulele pot prelua capabilităţi de la modulele de nivel superior.

• polimorfismul - abilitatea unui proces de a lucra cu diferite tipuri de date sau a unei entităţi de a se referi la momentul execuţiei la instanţe ale diferitelor clase. Ideal ar fi ca un limbaj să fie complet polimorf, astfel încât nu ar mai fi necesare porţiuni de cod pentru fiecare tip de dată. Polimorfismul implică suportul pentru “dynamic binding”. “Dynamic binding” înseamnă legarea metodelor obiectelor de selectarea mesajului la momentul execuţiei şi nu al compilării.

• mesajele - Limbajele orientate-obiect utilizează mesaje pentru implementarea interfeţelor. Un mesaj încapsulează detaliile acţiunii care trebuie realizată. Un mesaj este trimis de către un obiect către un alt obiect-receptor pentru a invoca serviciul celui din urmă.

Exemple de astfel de limbaje sunt: Smalltalk şi C++. c) Limbaje funcţionale (LISP) - suportă structurarea declarativă, construcţiile procedurale fiind inutile. În particular, construcţia secvenţă nu mai este utilizată în logica programului. Un model informaţional de bază (arbore sau listă) este utilizat pentru a defini această logică. Dacă o anumită informaţie este necesară pentru o operaţie, ea este automat obţinută din modelul informaţional. În programarea funcţională operatorii (funcţiile) se aplică argumentelor (parametrii). Înşişi parametrii pot fi expresii funcţionale astfel încât un program funcţional poate fi gândit ca o singură expresie aplicând o funcţie alteia. Programele scrise în limbaje funcţionale par diferite faţă de cele scrise în limbaje procedurale deoarece asignările sunt absente. Programele în limbaj funcţional sunt scurte, clare şi sunt potrivite atât pentru specificaţii cât şi pentru implementarea rapidă.

Page 172: software engineering

4

d) Limbaje de programare logică - implementează o anumită formă a logicii clasice. Ca şi limbajele funcţionale, ele au o structură declarativă. În plus, suportă:

• backtracking - abilitatea de a reveni la un punct anterior în lanţul de deducţii, utilă în momentul traversării unui arbore de cunoştinţe

• backward chaining - începe cu o ipoteză şi raţionează înapoi spre factorii care au determinat ca această ipoteză să fie adevărată. De exemplu, dacă factorul A şi ipoteza B sunt înlănţuite în expresia IF A THEN B, backward chaining permite să se deducă faptul că A este adevărat din ipoteza că B este adevărat.

• forward chaining - opusul conceptului backward chaining. Începe de la o colecţie de factori şi raţionează spre o concluzie. De exemplu, dacă factorul A şi concluzia B sunt înlănţuite în expresia IF A THEN B, backward chaining permite să se deducă din faptul că A este adevărat concluzia că B este adevărat

Cel mai important limbaj de programare logică este Prolog.

3. Utilitare pentru implementare şi test

O gamă largă de utilitare sunt valabile pentru dezvoltarea programelor, depanarea şi testarea acestora:

• utilitare de modelare (Modelling Tools) - generează nucleul (“scheletul”) modulelor.

Se generează automat declaraţii pentru constante, variabile, tipuri pentru includerea în codul sursă al fiecărui modul. Unele utilitare de modelare pot transforma diagramele reprezentând apelurile modulelor în apeluri de funcţii sau proceduri complet comentate, deşi fără a avea valorile parametrilor actuali. Dacă asemenea utilitare sunt folosite, scrierea codului începe prin a completa “scheletul” unui astfel de modul: se completează toate apelurile; se introduc construcţiile iterative (while, repeat, loop, etc); se introduc construcţiile alternative (if, case, etc.) şi se adaugă în final detaliile de bază ca operaţii aritmetice, operaţii de intrare-ieşire şi alte apeluri sistem.

• generatoare de cod - transformă relaţii formale în cod sursă. Se utilizează în domenii ca gestiunea bazelor de date şi interacţiunea cu factorul

uman, domenii caracterizate de un cod repetitiv şi de necesitatea de a executa numeroase operaţii de rutină dar esenţiale. Deoarece generatoarele de cod sunt din ce în ce mai mult integrate în metodele de proiectare, va fi posibil de a genera automat codul sursă pentru porţiuni din ce în ce mai mari ale componentelor unui sistem. Chiar dacă pentru părţi ale sistemului codul va fi scris manual, utilizarea generatoarelor de cod rămâne în continuare avantajoasă. Modificări în cerinţele software pot rezulta în schimbări automate în declaraţiile datelor şi modulelor, păstrând şi verificând consistenţa de-a lungul ciclului de viaţă al produsului.

• editoare - creează şi modifică codul sursă şi documentaţia.

• editoare senzitive la limbaj - creează cod sursă corect din punct de vedere sintactic.

Aceste editoare conţin un interpretor care ajută în scrierea unui cod sursă corect d.p.d.v. sintactic. Cele mai simple astfel de editoare recunosc parantezele şi realizează o aliniere automată care fac programul mai uşor de înţeles şi reduc erorile. E posibil, de asemenea, de a furniza scheme (tipare) pentru construirea programelor, conţinând headere standard, secţiuni obligatorii pentru declararea constantelor şi tipurilor de date. Acestea pot fi generate automat de utilitarele de modelare. Editoarele care recunosc aceste scheme pot reduce timpul de dezvoltare şi pot preveni erorile.

Page 173: software engineering

5

• analizoare statice - examinează codul sursă. Analiza statică este procesul de scanare a textului unui program pentru detectarea unor

erori: 1. identifică variabile neutilizate sau utilizate înainte de a fi asignate 2. verifică dacă valoarea variabilei este în intervalul admis 3. furnizează o prezentare a structurii aplicaţiei 4. măsoară complexitatea codului în termenii unei metrici 5. transformă codul sursă într-un limbaj intermediar pentru verificare formală 6. măsoară anumite atribute ale codului cum ar fi numărul de linii de cod şi nivelul

maxim de imbricare. Cele mai multe compilatoare furnizează unele din caracteristicile analizoarelor statice

(cum ar fi caracteristica 1). Analizoarele statice dedicate de obicei furnizează funcţii de analiză statică avansate, cum ar fi analiza structurii codului.

• compilatoare - transformă codul sursă în cod obiect. Acestea variază în viteză, completitudinea verificărilor, uşurinţa utilizării, folosirea sintaxei standard, calitatea codului şi afişărilor şi prezenţa caracteristicilor de programare. Alegerea compilatorului este de importanţă crucială. Viteza compilatorului afectează costul produsului şi uşurinţa în dezvoltarea, depanarea şi întreţinerea produsului, în timp ce calitatea codului afectează performanţele produsului în timpul execuţiei. Compilatoarele ar trebui comparate ţinând cont de viteza lor, de timpul de execuţie al programului şi dimensiunea codului. Dimensiunile stivei şi a memoriei heap pot fi, de asemenea, importante. Compilatoarele variază mult şi funcţie de caracteristicile care suportă programarea:

1. listare completă 2. cross-referenţierea 3. dimensiunea datelor şi modulelor 4. diagnosticare 5. verificare completă 6. switch-uri (ex: verificarea limitelor vectorilor; limbaj strict sau extensii)

Cele mai avansate compilatoare execută anumite optimizări pentru maşini secvenţiale sau paralele, încercând să descopere şi să elimine deficienţele codului sursă. Aceste optimizări pot fi impuse prin switch-uri, de exemplu prin directive în codul sursă (exemplu: directiva pragma în Ada). Utilizatorii ar trebui să verifice dacă optimizările pe care le doresc sunt implementate în compilatoarele candidat.

• linkeditoare - reunesc modulele obiect în programe executabile Acestea sunt furnizate de maşină, sistemul de operare sau compilator. De aceea, utilizatorul are în foarte mică măsură controlul asupra alegerii acestora. Este util ca linkeditorul să determine automat bibliotecile şi directoarele pe care trebuie să le utilizeze şi care sunt modulele sau componentele care trebuie linkeditate. Cele mai multe linkeditoare pot fi controlate de parametri creaţi de utilitare build sau make.

• depanatoarele - localizează erori în timpul execuţiei programului Utilizarea depanatoarelor simbolice interactive este puternic încurajată, mai ales pentru verificare. Un depanator bun este integrat cu editorul şi compilatorul / interpretorul şi permite o gamă de moduri de investigare: pas cu pas, trasare prin breakpoint, vizualizarea valorilor variabilelor, setarea unor condiţii.

• analizoarele dinamice - examinează programele în curs de execuţie. Analiza dinamică este procesul de măsurare a resurselor (timp CPU, timp intrare-ieşire, memorie) consumate de fiecare modul şi linie de cod. În contrast cu analizoarele statice, cele dinamice se folosesc pentru programe în curs de execuţie. Analizoarele dinamice

Page 174: software engineering

6

se mai numesc şi profilers. Ele mai pot fi folosite şi pentru a determina dacă toate instrucţiunile programului au fost executate în timpul testului (coverage test). Unele analizoare dinamice verifică dacă programul utilizează corect memoria, de exemplu, verifică dacă apelurile pentru alocarea memoriei au corespondent în apeluri pentru dealocare, determinând astfel golurile de memorie (memory leaks). Analizoarele dinamice pot localiza părţile sistemului care cauzează slabe performanţe ale acestuia şi pot detecta erori de programare (exemplu: iniţializări inutile).

• utilitare de test - testează module şi programe. Acestea suportă una sau mai multe din următoarele funcţii: 1. generarea şi gestiunea datelor de test 2. verificarea automată a rezultatelor 3. diagnoza erorilor şi depanarea 4. realizarea testelor driver şi stubs Utilitarele generale de test pot genera mari cantităţi de date de intrare

• procesoare de text- pentru crearea documentelor

• generatoare de documentaţie - generează documentaţie utilizator din codul sursă. Menţin consistenţa dintre cod şi documentaţie şi fac procesul de documentare concurent cu cel de codare. Generatoarele de cod pot include utilitare pentru generarea automată a documentaţiei.

• utilitare pentru managementul configuraţiei - înregistrează versiunile modulelor şi fişierelor.

Sunt organizate în baze de date şi controlează dezvoltarea sistemelor când multe module pot exista în diferite versiuni. Unele utilitare permit specificarea unei configuraţii (m module în n versiuni) şi compilare automată, linkeditare şi arhivare a acestora. Este recomandată folosirea utilitarelor pentru managementul configuraţiei când numărul de module sau de versiuni devine foarte mare.

În concluzie, procesul de implementare este dificil de caracterizat şi de descris. Aici se regăsesc aspecte ale analizei cerinţelor, ale specificaţiilor şi proiectării. Programatorul va trebui să facă un număr de importante compromisuri între siguranţa produsului, costul, eficienţa, timpul de execuţie, posibilitatea lui de întreţinere, etc. Sarcina cea mai dificilă a programatorului este de a realiza această pluralitate a scopurilor. Este dificil de a spune care va fi rezultatul acestor compromisuri atât timp cât produsul nu este complet şi testat. Odată ce produsul a fost finalizat, în sensul că toate părţile sale componente au fost reunite şi sistemul poate funcţiona, începe etapa următoare a procesului de dezvoltare şi anume faza testării.

Page 175: software engineering

1

TESTAREA TESTAREA TESTAREA TESTAREA SISTEMELOR SOFTWARESISTEMELOR SOFTWARESISTEMELOR SOFTWARESISTEMELOR SOFTWARE

Testarea software determină dacă un sistem software este gata de livrare şi estimează nivelul de performanŃă al acestuia. Testarea furnizează o bază pentru interacŃiunea cu persoanele implicate în proiect. Creşterea complexităŃii sistemelor software a dus la o creştere a bugetului alocat acestei faze din procesul de dezvoltare al unui proiect (între 30 şi 50%). O mare parte a efortului necesar realizării sistemelor software este alocată dezvoltării modelelor de testare şi a aplicaŃiilor de testare automată. Testarea este procesul execuŃiei programului cu scopul de a pune în evidenŃă erorile. Detectarea erorilor este scopul principal al testării. În acelaşi timp, prezintă interes atât dezvoltarea unor seturi de date de test adecvate care să conducă la activarea erorilor precum şi modalităŃile de alocare a timpului necesar testării, în special în sistemele de mare complexitate. În mod obişnuit, spunem că un sistem software eşuează atunci când nu îndeplineşte cerinŃele impuse. FuncŃionarea defectuoasă poate fi rezultatul unuia dintre următoarele motivele:

• SpecificaŃiile sunt greşite sau unele cerinŃe ale clienŃilor nu sunt specificate; • SpecificaŃiile pot conŃine cerinŃe care nu pot fi implementate cu softul disponibil; • Proiectarea sistemului poate fi greşită. • Implementarea codului are defecte; unii algoritmi sunt greşit sau incomplet implementaŃi.

ExperienŃa acumulată de-a lungul timpului în domeniul testării software a dus la elaborarea unor politici de testare. Spre exemplu, Myers (1976) a propus următoarele reguli de bază pentru realizarea testării sistemelor software:

• Se determină momentul în care se opreşte testarea; • Responsabilitatea testării programului revine unui tester, nu celui ce realizat programul; • Se descriu rezultatele aşteptate pentru fiecare caz de test; • Se scriu cazuri de test pentru condiŃii de intrare valide şi nevalide; • Se verifică rezultatele fiecărui test. • Testarea se atribuie celor mai creative persoane din echipă

Pentru proiectele complexe, specificaŃiile de test pentru sistem şi pentru acceptarea acestuia nu trebuie scrise de către analişti, proiectanŃi şi programatori care au lucrat la proiectul respectiv (pentru sistemele mici şi medii e acceptabil ca aceste specificaŃii să fie scrise de către cei ce dezvoltă sistemul) ci de către utilizatorii sistemului.

Testarea software cuprinde o multitudine de strategii de testare. În general, metodele de testare sunt specializate, în sensul că cele mai multe proiecte creează propriile metode de testare depinzând de produsul respectiv.

Metodele de testare dinamică presupun executarea programului folosind aşa numitele date de test. Datele de test se construiesc conform cerinŃelor funcŃionale specificate iar rezultatele furnizate de program se compară cu cele prezentate în specificaŃii.

Metodele de testare statică cuprind verificarea programului, analiza anomaliilor, inspecŃia codului. Verificarea programului necesită specificarea precondiŃiilor la intrare şi a postcondiŃiilor la ieşire. Analiza anomaliilor caută eventuale comportări anormale ale programului (spre exemplu, porŃiuni de cod care nu sunt executate niciodată). Scopul testării statice este de a analiza sistemul software şi de a deduce operaŃiile sale curente ca o consecinŃă logică a deciziilor de proiectare. Această modalitate de testare nu necesită execuŃia programului.

1. Clasificarea metodelor de testare

Metodele de testare pot fi clasificate în două mari categorii: • Testarea black box (cutie neagră). Această abordare se concentrează asupra intrărilor,

ieşirilor şi funcŃionalităŃii modulelor software.

Page 176: software engineering

2

• Testarea white box (cutie albă). Această abordare presupune inspectarea structurii codului modulelor software.

Testarea black box se mai numeşte testare funcŃională. Punctul de plecare este fie o specificaŃie, fie codul. În cazul codului, datele de test trebuie să permită verificarea funcŃionalităŃii programului. Testerul nu este interesat de modul în care este implementat programul respectiv, ci de modul în care acesta furnizează răspunsul dorit.

Testarea white box, cunoscută şi sub numele de testare structurală, presupune analizarea implementării programului (modulului). Se verifică executarea corectă a tuturor căilor şi ramurilor codului programului testat. În tabelul 1 se prezintă câteva metode de testare ce fac parte din cele două mari categorii prezentate mai sus, metode ce vor fi prezentate pe larg în secŃiunile ulterioare.

Tabelul 1 Clasificarea formelor de testare Testare funcŃională Testare structurală Dinamică Testare aleatoare

Testare pe domenii Graf cauză-efect

Testare computaŃională Testare pe domenii Testare căi Generare date Analiza schimbărilor

Statică Verificare specificaŃii Inspectare cod Verificare program ExecuŃie simbolică Analiză anomalii

În cazul testării sistemelor software există şi probleme ce nu Ńin de tehnică. Spre exemplu, se pot pune următoarele întrebări: Cine face testarea? Testarea poate fi realizată de un programator care a fost implicat în scrierea codului? Se apelează la un tester independent, se schimbă porŃiuni de cod între membrii aceleiaşi echipe sau se lasă testarea în seama utilizatorului final? Fiecare dintre alternativele propuse are argumente pro şi contra.

O altă problemă fundamentală este legată de durata activităŃilor de testare, când apar două puncte de vedere cel puŃin contradictorii care trebuie luate în considerare. Primul este al proiectanŃilor care fac tot posibilul pentru a realiza un produs fără defecte. Cel de-al doilea este al managerilor de proiect care iau în considerare constrângerile de timp impuse proiectului.

Înainte de a intra într-o prezentare mai detaliată a diferitelor variante de testare, este importantă precizarea paşilor principali care intervin în orice schemă de testare.

Etapele principale ale unei scheme de testare • SelectaŃi ce trebuie măsurat (cuantificat) de testul respectiv. Înainte de realizarea testului, trebuie identificate scopurile acestuia. Scopurile pot fi diferite (spre exemplu, testarea fiabilităŃii, testarea completitudinii cerinŃelor). • DecideŃi cum faceŃi testarea a ceea ce trebuie testat. După ce aŃi stabilit ce este de testat, trebuie să decideŃi cum realizaŃi testele relevante. • DezvoltaŃi cazurile de test. Pentru tipurile de testare deja acceptate, trebuie creată o colecŃie de cazuri de test (situaŃii de test) pentru antrenarea sistemului supus testării. • DeterminaŃi rezultatele aşteptate ale testului respectiv. • ExecutaŃi cazurile de test.

• ComparaŃi rezultatele obŃinute cu cele aşteptate.

2. Niveluri ale testării software

Testarea software se realizează la diferite nivele de-a lungul întregului ciclu de viaŃă al produsului. Testarea începe la nivel de componente software individuale. Se verifică funcŃionalitatea şi structura fiecărei componente, după care se face testarea la integrare a componentelor. Standardul IEEE de verificare şi validare software (IEEE Std. 1059-1993) identifică patru nivele de testare, după cum se poate observa în tabelul 2. CorespondenŃa între nivelele de testare şi etapele ciclului de viaŃă a sistemului este prezentată în figura 1.

Page 177: software engineering

3

Tabel 2 Testare DefiniŃie Scop Componentă Se verifică implementarea elementelor

software (ex. FuncŃii, module). Logica programului este completă şi corectă. Componentele funcŃionează conform proiectării.

Integrare Componentele software şi hardware sunt combinate şi testate până la integrarea întregului sistem

Obiectivele proiectării sunt satisfăcute

Sistem Se testează sistemul integrat Proiectul software este o entitate completă în concordanŃă cu cerinŃele operaŃionale.

Acceptare Se verifică dacă rezultatele testelor satisfac criteriile de acceptare ale clienŃilor

Obiectivele clienŃilor sunt satisfăcute

Figura 1. Nivele de observabilitate a testării

3. ActivităŃi de test

În cadrul testării software se pot delimita următoarele activităŃi cheie: • Elaborarea planului de testare • Proiectarea testului • Stabilirea cazurilor de test • Determinarea procedurii de testare • Executarea testului • Realizarea raportului de testare Planul de testare trebuie să precizeze scopul, tipul abordării, resursele necesare şi un orar al

activităŃii de testare. Este necesară de asemenea identificarea surselor şi nivelelor de risc şi stabilirea persoanele ce realizează testarea. Planificarea testării poate începe din momentul în care cerinŃele sistemului sunt complete. Este dificilă determinarea momentului în care se opreşte testarea. Din acest motiv trebuie introduse criterii pentru a stabili dacă un test este complet sau nu.

Proiectarea testului rafinează abordarea propusă în planul de testare. În această etapă se identifică principalele caracteristici ce trebuie testate şi se definesc cazurile de test asociate. Este recomandat ca proiectarea testelor să se facă pentru o testare de regresiune (testele executate anterior să poată fi repetate la un punct ulterior în procesul de dezvoltare şi întreŃinere).

Cazurile şi procedurile de test se construiesc în faza de implementare. Se urmăreşte realizarea unei colecŃii de cazuri de test cât mai redusă care să poată duce la îndeplinirea scopurilor propuse. Cazurile de test bine realizate au o mare probabilitate de a detecta erorile. Procedura de testare identifică toŃi paşii necesari operării sistemului şi rulării cazurilor de test ce implementează proiectul de test obŃinut în etapa anterioară.

Executarea testului începe la nivel de componente şi continuă cu testarea la integrare, testarea sistemului şi testarea de acceptare.

Raportul de testare rezumă toate ieşirile testului şi subliniază discrepanŃele detectate. ActivităŃile de testare se distribuie de-a lungul întregului ciclu de viaŃă al produsului.

4. Tipuri de teste software

łinând cont de multitudinea metodelor de testare existente este avantajoasă luarea în

Page 178: software engineering

4

considerare a testelor în funcŃie de modalitatea în care acestea devin accesibile proiectantului. Testele funcŃionale sunt utilizate pentru a rula codul cu intrări nominale pentru care valorile

aşteptate sunt disponibile. Pentru aceste intrări sunt cunoscute de asemenea condiŃiile la limită. Spre exemplu, pentru a testa funcŃional înmulŃirea matricelor se vor lua în considerare matrice al căror produs este dinainte cunoscut.

Testele de performanŃă ajută la determinarea unor performanŃe ale sistemului cum ar fi timpul de execuŃie al unor părŃi de cod şi timpul de răspuns (în cazul sistemelor încorporate). Scopul acestui tip de testare constă în identificarea punctelor slabe ale sistemului software, cuantificarea neajunsurilor în scopul unei viitoare îmbunătăŃiri.

Testele la stres sunt proiectate pentru a urmări comportarea sistemului atunci când acesta cedează. Acest tip de testare evaluează limitările sistemului software.

Testele structurale sunt folosite pentru a verifica logica internă a sistemului. Testele pe componente se efectuează asupra modulelor individuale, proceduri şi funcŃii. Testele la integrare sunt proiectate pentru a testa comportarea sistemului pe măsură ce se

adaugă modulele componente. Testarea interfeŃelor are ca obiectiv detectarea erorilor cauzate de interfeŃele dintre obiecte.

Pot apărea următoarele tipuri de erori: utilizare greşită a interfeŃei (parametri cu un alt tip sau într-o altă ordine decât sunt specificaŃi în interfaŃă), înŃelegerea greşită a interfeŃei (presupuneri greşite legate de ce ar trebui să facă o componentă), erori de timing (au loc în sistemele în timp real care folosesc memorie partajată sau transmitere de mesaje).

5. Testarea funcŃionala (black box)

După cum am precizat anterior, testarea de tip black box nu necesită cunoaşterea codului pentru realizarea unor teste semnificative. În continuare vom discuta despre câteva categorii reprezentative ale acestei metode de testare cum ar fi testarea derivată din sintaxă, testarea bazată pe tabele de decizie şi abordarea bazată pe grafuri cauză efect.

T5.1 Testarea derivată din sintaxă

Această clasă de teste funcŃionale se aplică sistemelor ale căror specificaŃii sunt descrise de o anumită gramatică. Această constă, spre exemplu, în compilatoare şi clasificatori sintactici. Deoarece specificarea formală a unor astfel de sisteme se exprimă prin reguli de producŃie, generarea cazurilor de test urmăreşte un ca fiecare regulă de producŃie să fie aplicată (testată) cel puŃin o dată.

Exemplu. Să considerăm o clasă de expresii aritmetice descrisă de următoarele reguli de producŃie:

<expresie>::=<expresie>+<termen>|<expresie>-<termen>|<termen> <termen>::=<termen>+<factor>|<termen>-<factor>|<factor> <factor>::=<identificator>|(<expresie>) <identificator>::=a|b|c|d|e|...|z

Un set de cazuri de test pentru testarea derivată din sintaxă conŃine expresii ce verifică regulile de mai sus. Un exemplu de expresie împreună cu regula corespunzătoare este dată în figura următoare.

<expresie>::=<expresie>+<termen>|

<expresie>-<termen>| <termen>

<termen>::=<termen>+<factor>| <termen>/<factor>| <factor>

<factor>::=<identificator>| (<expresie>) <identificator>::=a|b\c|d|e|...|z

Figura 2. Caz de test şi regulă de producŃie (subliniată)

Page 179: software engineering

5

5.2 Testarea bazată pe tabele de decizie

Această formă de testare prezintă interes atunci când cerinŃele produsului software sunt formulate cu ajutorul regulilor de decizie de tipul „if-then”. Exemplele care se pretează la acest tip de testare sunt sistemele bazate pe reguli. O regulă este de forma:

If cond1 and cond2 and cond3 and ... condn then actiune

Un tabel de decizie este compus dintr-un număr de coloane ce conŃin toate situaŃiile de test. Partea superioară a coloanei conŃine condiŃiile ce trebuie satisfăcute. Partea de jos a tabelului specifică acŃiunile care au loc dacă sunt satisfăcute condiŃiile din regulă. Un exemplu de tabel de decizie este prezentat în figura 3.

CondiŃii ... 1

CondiŃia i 1 ... 0

AcŃiuni ... 0

AcŃiunea j 1 ... 0

Figura 3. Exemplu de tabel de decizie

Exemplu: Controlul nivelului de lichid. Să considerăm o problemă simplă de control care are specificaŃiile exprimate sub forma unor tabele de decizie. Se consideră un rezervor de lichid cu doi senzori şi două valve (figura 4). Senzorul 1 detectează un nivel maxim acceptabil al lichidului iar senzorul 2 detectează un nivel minim acceptabil al lichidului. Fiecare senzor generează valoarea 1 logic dacă lichidul depăşeşte nivelul corespunzător. Altfel, senzorii generează 0 logic. Valva de intrare se deschide doar dacă nivelul scade sub limita minimă (senzorul 2 devine activ) iar valva de ieşire se deschide dacă senzorul 1 se activează. sunt următoarele:

Figura 4. Rezervor de lichid

Reguli:

• Dacă senzorul 1 este activ (prea mult lichid în rezervor), atunci se deschide valva de ieşire.

• Dacă senzorul 2 este activ ( prea puŃin nivel în rezervor) atunci se deschide valva de intrare.

În plus, se adaugă o acŃiune de avertizare în momentul în care senzorul 2 furnizează rezultate

eronate. Tabelul de decizie complet are 22 4= coloane (figura 5A). Dacă nu interesează mesajele de avertizare în caz de eroare, se poate reduce dimensiunea tabelului de decizie aşa cum se poate observa în figura 5B.

În general, pentru „n” condiŃii se va ajunge la 2n combinaŃii, deoarece fiecare coloană a

tabelului trebuie folosită cel puŃin o dată. Prin urmare vor exista 2n cazuri de test. Se observă că şi pentru valori mici ale lui „n”, tabelul de decizie ajunge la dimensiuni mari. Această creştere exponenŃială se explică prin faptul că nu au fost luate în considerare constrângerile între variabilele din condiŃii, constrângeri ce presupun limitări fizice şi conceptuale între variabile. A treia coloană din tabelul de decizie din figura 5B poate fi astfel eliminată.

Page 180: software engineering

6

În secŃiunea următoare vom prezenta metoda de testare bazată pe grafuri cauză efect care elimină neajunsul major al metodei bazate pe tabele de decizie, şi anume creşterea exponenŃială a dimensiunii tabelelor odată cu creşterea numărului de reguli.

S 1 0 0 1 1 CondiŃii S 1 0 1 1 CondiŃii S 2 0 1 0 1 S 2 0 0 1

Deschide valvă ieşire

0 0 0 1 Deschide valvă ieşire

0 0 1

Deschide valvă intrare

1 0 0 0 AcŃiuni Deschide valvă intrare

1 0 0 AcŃiuni

Trimite mesaj eroare

0 1 0 0 Trimite mesaj eroare

Figura 5A. Tabel de decizie complet Figura 5B. Tabel de decizie redus

5.3 Testarea funcŃională bazată pe grafuri cauză-efect

Principalul dezavantaj al metodei bazate pe tabele de decizii este că intrările sunt luate în considerare separat chiar dacă problema necesită o altă abordare. Garfurile cauză-efect iau în considerare relaŃiile dintre combinaŃii specifice de intrări (cauze) şi ieşiri (efecte). Se evită în acest mod creşterea exponenŃială a dimensiunii tabelelor de decizie. Cauzele şi efectele sunt reprezentate ca noduri ale grafului. Un astfel de graf include un număr de noduri intermediare care leagă cauzele şi efectele prin expresii logice.

Exemplu. Se consideră un bancomat (ATM) simplu. Lista cauzelor şi efectelor este următoarea:

Cauze C1: comanda este „creditare” C2: comanda este „debitare” C3: numărul de cont este valid C4: tranzacŃia este validă

Efecte E1: tipăreşte „comandă nevalidă” E2: tipăreşte „număr cont nevalid” E3: tipăreşte „sumă debit nevalidă” E4: cont debit E5: cont credit

Graful cauză-efect este prezentat în figura 6. Nodurile intermediare realizează operatorii logici „and” şi „or”. Simbolul de negare ¬ stabileşte

faptul că efectul are valoarea de adevăr „true” doar dacă nodul asociat este „false”. Graful cauză-efect ajută la determinarea cazurilor de test corespunzătoare. Aceste cazuri de test se

obŃin parcurgând în sens invers (de la efect la cauză) porŃiuni din graful prezentat în figura 6. dacă spre exemplu suntem interesaŃi în determinarea cauzelor efectului E3 se urmăreşte porŃiunea de graf prezentată în figura 7.

Figura 6. Graf cauză-efect

Figura 7. Determinarea cauzelor efectului E3

Page 181: software engineering

7

Se observă că C2, C3 şi ¬C4 determină E3, în timp ce cauza C1 nu influenŃează E3. Cauza C1 poate fi privită drept o condiŃie de tip „nu contează”, ce va fi notată cu „x”. Această observaŃie reduce dimensiunea tabelului de decizie corespunzător. Coloana din tabelul de decizie care va fi folosită la generarea cazurilor de test este:

C1

C2

C3

C4

X 1 1 0

Dacă nu se iau în considerare condiŃiile de tip „nu contează”, porŃiunea rezultată din tabelul de

decizie va conŃine 12 2= coloane ce implică o enumerare a valorilor cauzei C1. Tabelul de decizie corespunzător grafului cauză-efect al unui ATM constă în cinci coloane cu un

număr substanŃial de condiŃii de tip „nu contează” (figura 8). Dacă nu ignorăm aceste condiŃii, va rezulta un

tabel cu 42 16= coloane.

C1 0 1 x x 1 C2 0 x 1 1 x C3 x 0 1 1 1 C4 x x 0 1 1 E1 1 0 0 0 0 E2 0 1 0 0 0 E3 0 0 1 0 0 E4 0 0 0 1 0 E5 0 0 0 0 1

Figura 8. Tabel de decizie ATM În general, dacă se doreşte generarea unui tabel de decizie redus, se va adopta un mecanism

de tip „backtracking” pentru traversarea unui graf de la efecte spre cauze (Ghezzi et al., 1991):

• La parcurgerea inversă a unui nod „or” a cărui ieşire este „true” se vor utiliza doar combinaŃii de intrări care au valoarea de adevăr „true”. Dacă, spre exemplu, avem trei cauze (a, b, c) ce afectează un nod de tip „or” a cărui ieşire este „true”, se vor considera doar combinaŃiile <a=true, b=false, c=false>, <a=false, b=true, c=false>, <a=false, b=false, c=true>.

• La parcurgerea inversă a unui nod „and” a cărui ieşire este „false” se vor utiliza doar combinaŃii de intrări care au doar o singură valoare „false”. Pentru exemplul precedent, se vor considera combinaŃiile <a=false, b=true, c=true>, <a=true, b=false, c=true>, <a=true, b=true, c=false>.

În grafurile cauză-efect pot fi introduse constrângeri suplimentare între intrări, cum ar fi cele de tipul „a implică b”. Acestea reduc numărul cazurilor de test deoarece unele combinaŃii de intrări nu vor mai fi luate în considerare în procedura de testare.

6. CondiŃii de testare la limită

Testarea de tip white box, care necesită cunoaşterea codului, nu se poate face pentru cazurile care nu sunt vizibile în mod explicit, sau care nu sunt suficient reliefate. Să considerăm spre exemplu o instrucŃiune de tipul if (x>y) then S1 else S2. Această formă a unei instrucŃiuni condiŃionale este generică şi se întâlneşte în multe tipuri de probleme. Să considerăm spre exemplu doi senzori ale căror citiri (x şi y) sunt folosite pentru luarea unor decizii, notate S1 şi S2. CondiŃia x>y determină două clase de echivalenŃă: • E1 – clasa de echivalenŃă a valorilor lui x şi y pentru care x y>

• E2 – clasa de echivalenŃă a valorilor lui x şi y pentru care x y≤ Cele două clase de echivalenŃă sunt formate din perechi de valori citite (x,y) care determină

valoarea de adevăr a condiŃiei relaŃionale asociate. Criteriul de acoperire a ramurilor (care presupune testarea tuturor ramurilor din program) duce la selectarea a două combinaŃii de intrări: una

Page 182: software engineering

8

provenind din E1 şi cealaltă din E2 (vezi figura 9). Se testează căile x y> şi x y< . Cazul x y= , care este parte a clasei de echivalenŃă E2, are o probabilitate nulă de a fi testat, deci nu va fi selectat niciodată pentru testare. Cu toate acestea, cazul la limită x y= prezintă interes şi din acest motiv, se poate prevedea o cale de realizare.

Figura 9. CondiŃia de testare la limită x = y

7. Testarea exhaustivă

Testarea exhaustivă face parte din metoda de testare black box. Cu toate că este impracticabilă, ea furnizează o imagine asupra complexităŃii procesului de testare. Un test exhaustiv trebuie să arate că programul funcŃionează corect pentru toate intrările posibile. Când ne referim la intrări trebuie să avem în vedere şi aspectele hardware ale realizării codului.

Exemplu. Se consideră ecuaŃia de gradul doi de forma 2ax bx c 0+ + = , unde a, b, c sunt parametrii ecuaŃiei. Din punct de vedere funcŃional, programul transformă spaŃiul tridimensional al parametrilor (a, b, c) într-un spaŃiu bidimensional al rădăcinilor ecuaŃiei (r1, r2). Testarea exhaustivă pleacă de la reprezentarea internă a parametrilor. Dacă presupunem că reprezentarea internă este pe 16 biŃi, pentru

fiecare intrare vom avea 162 cazuri de test. Considerând toate cele trei intrări, vom avea în final 482 cazuri de test ce trebuie executate, ceea ce este nefezabil.

8. Testarea structurală

Testarea structurală presupune dezvoltarea de cazuri de test ce iau în considerare structura codului (logica internă). Există mai multe categorii de testarea structurală, funcŃie de cât de complet trebuie să fie procesul de testare şi de restricŃiile de timp.

Testarea la nivel de instrucŃiune este o formă de testare primară, care necesită executarea fiecărei instrucŃiuni cel puŃin o dată.

Exemplu. Se consideră următoarea porŃiune de cod care se presupune că determină modulul lui y.

begin if (y ≥ 0) then y = 0-y; abs = y; end;

Cazul de test y 0= este suficient pentru a testa toate instrucŃiunile din porŃiunea de cod prezentată.

Este evident faptul că această formă de testare nu detectează o eroare evidentă a codului şi anume aceea că nu se calculează de fapt modulul numărului y.

Testarea la nivel de ramură. Cazurile de test sunt alese astfel încât fiecare ramificaŃie a codului să fie executată cel puŃin o dată.

Exemplu. Dacă ne referim la instrucŃiunea anterioară, cazurile de test y 0= şi y 4= − sunt

suficiente pentru a executa ambele variante ale blocului de decizie. Pentru y 0 abs 0= ⇒ = . Pentru

Page 183: software engineering

9

y 4 abs 4= − ⇒ = − , ceea ce indică o eroare. Indiscutabil, această metodă de testare conduce la detectarea

erorilor.

Testarea la nivel de ramură/condiŃie. Fiecare ramură trebuie parcursă cel puŃin o dată şi toate combinaŃiile posibile ale condiŃiilor de decizie trebuie executate.

Exemplu. Se consideră instrucŃiunea:

if ((x<val_1) && (y>val_2)){z=calculeaza_1(x,y); else z= calculeaza_2(x,y);}

Să considerăm cazurile de test x 4, y 10= − = , x 6, y 12= − = . În primul caz, blocul de decizie returnează „false” şi atunci se execută o ramură a codului, iar în cel de-al doilea caz, blocul de decizie returnează „true” şi atunci se execută cealaltă ramură a codului. Se observă faptul că, dacă o eroare este asociată cu o condiŃie compusă dintr-un bloc de decizie, ea rămâne nedetectată. Din acest motiv, testarea trebuie completată cu verificarea tuturor subcondiŃiilor ce apar în blocul de decizie. Deoarece în exemplul prezentat avem două subcondiŃii în blocul de decizie, trebuie adăugate două perechi suplimentare de teste şi anume („true”, „false”) respectiv („false”, „true”).

ObservaŃie. Dacă fiecare subcondiŃie este privită ca o intrare singulară, atunci acest tip de

testare este analogă testării exhaustive, „n” condiŃii necesitând n2 cazuri de test. În cazul în care „n” creşte, testarea poate deveni nefezabilă.

Testarea la nivel de cale. Criteriul de acoperire a căilor consideră toate căile logice dintr-un program şi duce la cazuri de test care verifică programul de-a lungul fiecărei astfel de căi. Acest criteriu poate deveni impracticabil, mai ales în situaŃiile în care programul are un număr mare de căi. Cu toate acestea, este o metodă de testare folosită, mai ales pentru că permite detectarea defectelor nedescoperite prin testarea la nivel de ramură.

Exemplu. Se consideră schema logică din figura 10.

Figura 10. Exemplu de schemă logică

Dacă se urmăreşte o testare la nivel de ramură se pot alege următoarele cazuri de test:

x 1, y 5= = , x 0, y 12= =

Aceste două cazuri de test acoperă toate ramurile schemei logice (vezi figura 11), dar execuŃia lor corectă nu garantează lipsa erorilor.

Să considerăm situaŃia în care la un anumit moment x 0= . În acest moment raportul y / x eşuează. Acest

scenariu nu a fost luat în considerare prin cazurile de test anterioare.

Figura 11. Testarea la nivel de ramură

Page 184: software engineering

10

Testarea la nivel de cale evită situaŃia prezentată anterior. Se pot considera următoarele cazuri de test:

x 1, y 5= = ; x 2, y 15= = ; x 0, y 7= = ; x 0, y 13= = .

Figura 11. Testarea la nivel de cale

ObservaŃie. Se observă că şi în cazul unui exemplu relativ simplu, numărul de căi ce trebuie parcurse este mai mare decât numărul ramurilor. Din cauza complexităŃii principiului acoperirii căilor este esenŃială numărarea căilor dintr-un program.

În cazul lipsei buclelor, numărul căilor este determinat de numărul de noduri de decizie şi de distribuŃia lor. Cele două extreme ale numărului de căi dintr-un graf se pot observa în exemplul din figura 12. În cazul în care se unesc ramurile, blocurile de decizie sunt „stivuite” unele peste

altele (figura 12a). Unirea ramurilor poate duce la n2 căi posibile. Numărul maxim de căi dintr-un

graf este deci n2 . În cazul în care nu se face unirea ramurilor există n 1+ căi posibile (vezi figura 12b), deci:

n 1+ ≤ număr de căi ≤ n2 Este de remarcat faptul că şi în cazul valorilor mici pentru „n”, între cele două limite există o

diferenŃă semnificativă. Pentru a micşora această diferenŃă se poate face o descompunere a grafului original în părŃi mai mici şi se determină extremele separat. Să considerăm spre exemplu un graf cu 6 noduri de decizie. În acest caz limitele ar fi 7 şi 64. Dacă se împarte graful original în trei părŃi, fiecare conŃinând 2 noduri, limitele pentru fiecare parte ar fi 3 şi 4. Numărul de căi de testat în graful original este cuprins între 27( 3*3*3)= şi 64( 4*4*4)= .

Page 185: software engineering

11

(a) ramuri unite

(b) ramuri neunite

Figura 12. Cazuri de acoperire a căilor

În cazul grafurilor ce conŃin bucle, acoperirea căilor va fi restricŃionată la bucle ce sunt traversate doar o singură dată. Utilizând această abordare, se poate transforma orice graf cu o buclă la unul fără nici o buclă. Ideea este de a împărŃi orice nod, să zicem A, care este nod terminal al unei căi cu reacŃie în A şi A’. Noul nod este conectat cu nodul final sau cu orice alt nod de mai jos. ConstrucŃiile de bază ale programării structurate pot fi transformate în grafuri fără bucle (figura 13). Enumerarea căilor va fi dată de sumele produselor limitelor grafului fără bucle.

Exemplu. Să considerăm graful din figura 14. Se porneşte cu frontierele care fac parte din toate căile posibile. Acestea sunt, evident, a şi h. Atunci:

FGC aFGC hα= ,

unde FGC este funcŃia de generare a căii iar α este funcŃia de generare a căii pentru sub-graful dintre B şi E. În continuare se construieşte funcŃia de generare a căii pentru α, FGCα:

Figura 13. Transformarea schemei logice în grafuri fără bucle

FGC de bFGCα β= + ,

unde semnul „+” se foloseşte pentru operaŃia „sau”. Pentru sub-graful cu nodurile C, B’, E’ şi E se obŃine:

FGC f cbfβ = + .

Revenind la expresia originală se obŃine:

Page 186: software engineering

12

FGC aFGC h a(de bFGC )h a(de b(f cbf ))h adeh abfh abcbfhα β= = + = + + = + +

Figura 14. Conversia unui graf într-un graf echivalent fără bucle

Se poate observa că numărul de căi poate creşte foarte mult, mai ales pentru porŃiunile de

cod cu fluxuri de control semnificative. Acest fapt limitează aplicabilitatea acestei metode de testare. Criteriul de testare a căilor nu poate detecta toate defectele, deoarece se bazează pe faptul că specificaŃiile software sunt transformate cu exactitate în cod. Lipsa unor elemente îngreunează semnificativ testarea.

9. Testarea regresivă

Scopul acestei metode de testare este de crea posibilitatea repetării testelor în momentul în care apare o modificare a produsului software. Există două activităŃi principale ale testării regresive:

• Stabilirea unui test (sau a unei serii de teste) pentru reluare. Regula este să se meargă pe teste puternice (şi anume acele teste cu nivel mare de acoperire).

• Compararea ieşirilor noi cu cele vechi (de bază) pentru a fi siguri că nu există schimbări nedorite.

Pentru testarea regresivă efectivă, trebuie realizate prelucrări suplimentare ale seriilor de test.

Eficacitatea testării regresive se exprimă în termenii următoarelor condiŃii: (a) cât de grea este construirea şi menŃinerea seriilor de test şi (b) cât de fezabil este sistemul de testare regresivă.

10. Testarea software statică

Testarea statică, spre deosebire de cea dinamică, nu se concentrează asupra execuŃiei codului. Există două variante de tehnici de testare statică:

• tehnici informale care includ trecerile rapide prin cod şi inspectarea propriu zisă a codului;

• tehnici formale ce cuprind demonstraŃii de corectitudine şi execuŃia simbolică.

10.1 Tehnici informale

Tehnicile informale au fost introduse la sfârşitul anilor ’70 şi diferă prin faptul că, dacă inspectările softului sunt orientate pe reacŃie, trecerile prin cod se bazează pe interacŃiunea dintre testeri, membrii echipei proiectului şi alte persoane implicate în proiect.

Inspectările sunt activităŃi realizate de o echipă experŃi care verifică proiectul sau codul cu scopul de a identifica erorile. Au fost propuse în 1976 de Fagan şi au fost dezvoltate de IBM. O inspectare conŃine cinci paşi principali:

• Privirea de ansamblu asupra documentelor ce trebuie inspectate • Pregătirea. ParticipanŃii încearcă să înŃeleagă documentul în detaliu. Tipurile de erori şi

frecvenŃa acestora găsite în inspecŃiile recente sunt utile pentru ca atenŃia să se concentreze asupra ariilor predispuse în măsură mai mare la erori

Page 187: software engineering

13

• Inspectarea. Pentru început, un participant parcurge codul împreună cu echipa de inspecŃie, asigurându-se că fiecare problemă este acoperită şi că fiecare ramură e parcursă cel puŃin o dată. Fiecare participant continuă cu propria listă de verificare. Scopul este de a găsi şi documenta erorile, nu de a le înlătura. Liderul echipei de inspecŃie (moderatorul) are ca sarcini pregătirea raportului scris şi asigurarea unei rezolvări potrivite

• Refacerea. Erorile şi problemele din raportul scris sunt rezolvate • Continuarea. Moderatorul se asigură că toate problemele ridicate au fost rezolvate. Toate

rezolvările trebuie verificate pentru a fi siguri că nu au fost introduse noi erori. În cazul în care mai mult de 5% din materialul inspectat a fost refăcut, echipa se reuneşte pentru o nouă inspectare.

Echipa responsabilă cu inspectarea este formată în general din 3-6 persoane. Spre exemplu, dacă se inspectează proiectul, echipa va conŃine un moderator, un proiectant, un dezvoltator şi un tester. Fiecare inspecŃie trebui să utilizeze o listă de verificare a defectelor potenŃiale (cum ar fi corespondenŃa între specificaŃii şi proiectare, între parametrii actuali şi cei formali ai interfeŃelor, compatibilitatea softului cu hardware-ul disponibil etc.). Rezultatele inspecŃiei sunt înregistrate funcŃie de nivelul de severitate şi tip. Pentru ca inspecŃia să aibă succes ea trebuie să aibă un caracter iterativ. În cazul inspectării codului activităŃile au scopul de a descoperi erorile obişnuite sau pe cele provenind din clase specifice cum ar fi:

• Variabile neiniŃializate; • Salturile în interiorul buclelor; • Bucle fără condiŃie de terminare; • Indexarea vectorilor în afara limitelor; • Nepotriviri între parametrii actuali şi cei formali. • Trecerea rapidă prin cod presupune organizarea unor întâlniri de lucru pentru analizarea

unui produs software, unui modul de cod, unui plan de testare etc. AcŃiunea este condusă de un persoană ce face o prezentare a produsului ce trebuie analizat. Erorile sunt înregistrate de un coordonator. Grupul de lucru se concentrează pe detecŃia erorilor, nu pe corecŃia lor. În general, o astfel de echipă este formată din următorii membri: un prezentator al problemelor ce trebuie revăzute, un coordonator al echipei de lucru, un secretar ce se ocupă cu pregătirea tuturor materialelor necesare, un reprezentant al persoanelor ce se ocupă cu întreŃinerea produsului, o persoană responsabilă cu îndeplinirea standardelor interne şi un reprezentant al clientului.

10.2 Tehnici formale

Tehnicile formale constau în demonstraŃii de corectitudine şi execuŃie simbolică.

DemonstraŃiile de corectitudine se bazează pe observaŃia că orice porŃiune de cod (program) este un obiect formal, în timp ce orice specificaŃie poate fi realizată printr-o metodă formală. Aceasta înseamnă că se pune accentul pe echivalenŃa dintre program şi specificaŃii. EchivalenŃa poate fi pusă în evidenŃă printr-o demonstraŃie matematică.

ExecuŃia simbolică utilizează simboluri în locul valorilor numerice, adică se bazează pe clase de date. Pentru a ilustra esenŃa acestei idei să considerăm următorul exemplu:

x = 7*y; if (x>a) then a = a+x-3 else y = sin(x/2); b = x+a*y;

În figura 15 literele mari cum ar fi X sau Y semnifică valori simbolice, acestea corespunzând variabilelor originale utilizate în cod). Să presupunem că la începutul execuŃiei simbolice, x X= şi a A= . Prima instrucŃiune duce la X 7*Y= . Celelalte variabile rămân neschimbate. Blocul de decizie poate fi activat pe oricare din cele două direcŃii (comparaŃia 7*Y A> poate fi adevărată sau falsă). Vom selecta unul din cele două fire de execuŃie ca un triplu de forma:

<valori variabile simbolice, cale de execuŃie, condiŃie>

Page 188: software engineering

14

Cele două căi de execuŃie sunt asociate grafului de control al fluxului.

Figura 15 Exemplu de execuŃie simbolică

11. Testarea la integrare

Componentele majore rezultate din scrierea codului se integrează formând sistemul final. Stilul de testare ales depinde de strategia aleasă pentru proiectarea sistemului software. În

cazul strategiei de proiectare top-down (care presupune o serie de rafinări succesive) se utilizează module înlocuitoare sau substitute (stubs) care au rolul de a emula modulele ce nu au fost dezvoltate încă (vezi figura 16). În cazul strategiei de proiectare bottom-up sistemul se dezvoltă plecând de la module detaliate, implementând funcŃii din ce în ce mai complexe. Se utilizează modulele driver pentru reprezentarea modulelor de nivel mai înalt ale căror nume le poartă (vezi figura 17).

Figura 16. Strategia top-down de testare a sistemului

Figura 17. Strategia bottom-up de testare a sistemului

Plecând de la strategiile de proiectare se pot defini următoarele strategii de testare la integrare:

• Testarea bottom-up – pleacă de la module detaliate şi se extinde spre nivele mai înalte ale ierahiei; această testarea necesită drivere.

• Testarea top-down - porneşte de la modulul de pe cel mai înalt nivel şi necesită substitute.

• Testarea big-bang - modulele se integrează într-un singur pas iar testarea se face asupra întregului sistem.

• Testarea în straturi suprapuse - combină testarea bottom-up şi top-down definind un anumit strat Ńintă în ierarhia modulelor; modulele inferioare stratului Ńintă se testează printr-o abordare bottom-up iar cele superioare printr-o metodă top-down.

ObservaŃie. Există situaŃii în care unele module nu sunt testate separat la testările bottom-up şi top-down.

Page 189: software engineering

15

Figura 18. Ierarhie de module software

Exemplu. Pentru a ilustra aceste idei de testare, să considerăm o ierarhie simplă de module ca în figura 18.

În figura 19 sunt prezentate clasele de testare la integrare pentru exemplul anterior.

Testare bottom-up

Testare top-down

Testare big-bang

Testare în straturi Stratul de test este situat între

A şi (B, C, D) Figura 19. Exemple de testări la integrare

Page 190: software engineering

1

Estimarea costurilor unui sistem software

Estimarea costurilor necesită o atenŃie specială în cadrul procesului de dezvoltare a unui proiect software. łinând cont de faptul că un produs software este unic, experienŃa unor proiecte anterioare trebuie utilizată cu precauŃie. CircumstanŃele în care se realizează noul produs pot fi diferite, plecând de la specificaŃii noi, alte platforme hardware şi software şi continuând cu noi aplicaŃii de dezvoltare şi metodologii de proiectare.

Odată cu creşterea complexităŃii sistemelor software, orice estimare poate duce la o alocare inadecvată a resurselor. Resursele limitate determină întârzierea proiectului, iar alocarea supradimensionată duce la o scădere substanŃială a profitului.

În practică se iau în considerare trei valori pentru costuri: valoarea cea mai probabilă, limita maximă şi limita minimă. Aceste valori reflectă factorul de incertitudine în ceea ce priveşte estimarea costului unui proiect software. În general, nivelul de incertitudine scade pe parcursul dezvoltării produsului.

Necesitatea introducerii de modele pentru estimarea costului este justificată de un număr de cerinŃe comune ale proiectelor software:

• Identificarea, stabilirea priorităŃilor şi justificarea resurselor necesare. • Negocierea bugetului adecvat şi stabilirea echipei proiectului. • Optimizarea costului, productivităŃii, calităŃii şi funcŃionalităŃii. • Nevoia de cuantificare a impactului riscului. • Stabilirea impactului schimbărilor. • Modificarea bugetelor în funcŃie de apariŃia unor evenimente neprevăzute. Există doi predictori principali ai costului unui proces software: efortul aşteptat şi timpul

consumat pentru realizarea acestuia. Metodele de estimare a costului întâlnite în practică sunt următoarele:

1. Opiniile experŃilor – se bazează pe experienŃa experŃilor acumulată în dezvoltarea altor proiecte software;

2. Analogia. Cheia acestei metode este de a realiza judecăŃi bazate pe proiecte anterioare, de a utiliza estimările obŃinute în proiecte anterioare şi de ale aplica în proiectul curent. Estimarea iniŃială este ajustată pe baza diferenŃei dintre proiectele anterioare şi cel curent. Rezultatul estimării depinde de posibilitatea cuantificării nivelului de similaritate dintre proiectele anterioare şi cel curent. Judecarea greşită a similarităŃilor şi diferenŃelor poate fi o sursă a estimărilor eronate.

3. Descompunerea. Această metodă presupune împărŃirea proiectului în sub-taskuri, estimarea costului componentelor şi sumarea acestora într-o estimare generală. Sumarea se face printr-o ponderare ce Ńine cont de complexitatea componentelor.

4. Modele PERT (Program Evaluation and Review Technique- Tehnica evaluării repetate a programului). Efortul necesar se estimează plecând de la cea mai bună valoare posibilă, cea mai rea valoare posibilă şi cea mai probabilă valoare conform următoarei formule:

A 4 M B

efort6

+ ⋅ += , (1)

unde efort = nr ore muncă/activitate calculat în ipoteza că un singur om este alocat; A = estimare pesimistă; B = estimare optimistă; M = estimarea cea mai frecventă. Metoda permite compensarea riscului prin realizarea unei estimări avantajoase. Estimările A,

B şi M se realizează fie prin metode analogice, fie prin metoda Delphi, metode ce vor fi discutate ulterior.

5. Modele matematice. Cele mai cunoscute modele din această categorie sunt COCOMO (COnstructive COst Model – Modelul constructiv al costurilor), modele bazate pe curba Rayleigh şi

Page 191: software engineering

2

modele bazate pe analiza punctelor funcŃionale. Parametrii acestor modele se determină prin metode statistice.

1. Modele bazate pe analiza punctelor funcŃionale

Această clasă de modele, ce are la bază punctele funcŃionale ale lui Albrecht, este în strânsă legătură cu documentul de specificare a cerinŃelor, în care este determinată funcŃionalitatea sistemului software. În esenŃă, această metodă de estimare a costurilor pleacă de la acele caracteristici ale sistemului care pot conduce la obŃinerea unui rezultat bun. IntenŃia este de a construi o măsură a dimensiunii proiectului ce poate fi disponibilă încă de la începutul procesului de dezvoltare. Metoda este independentă de tehnologie. Pentru a putea construi un astfel de model se identifică numărul de puncte cheie ce apar în sistem, care sunt în mod obişnuit derivate din documentul de specificare a cerinŃelor şi anume:

• Intrările externe (IE) sunt intrările de la utilizator care furnizează date distincte orientate pe aplicaŃie. Exemple de astfel de intrări sunt numele de fişiere şi selecŃiile din meniuri.

• Ieşirile externe (OE) sunt orientate spre utilizator; acestea sunt sub formă de rapoarte şi mesaje.

• Cererile externe (CE) sunt intrări interactive ce necesită un răspuns. • Fişierele externe (FE) asigură interfaŃa cu alte sisteme; utilizatorul nu este responsabil de

întreŃinerea datelor. • Fişierele interne (FI) sunt fişierele principale ale sistemului; permit utilizatorilor să

folosească datele pe care trebuie să le întreŃină Cu toate că aceste caracteristici ale sistemului software sunt definite mai degrabă informal,

identificarea lor nu este dificilă când se lucrează cu sisteme specifice. Pentru a ajusta nivelele de complexitate pentru fiecare sub-funcŃie, se face o evaluare a complexităŃii. Această evaluare conŃine trei nivele de complexitate: simplu, mediu şi complex.

În funcŃie de complexitatea tipurilor de date, se disting o serie de valori pentru aceste puncte funcŃionale, prezentate mai jos:

Nivel de complexitate (pondere) Tip Simplu Mediu Complex

IE 3 4 6 OE 4 5 7 CE 3 4 6 FE 7 10 15 FI 5 7 10

Se observă faptul că fişierele externe au cea mai mare pondere. Fişiere interne au, de asemenea, o contribuŃie semnificativă la complexitatea programului. Ieşirile externe, intrările externe şi cererile externe au un nivel scăzut în această schemă. Acest nivel de evaluare a fişierelor externe şi interne este o consecinŃă a ponderii mari pe care o au integrarea modulelor unui sistem şi interfaŃarea cu alte sisteme în cadrul dezvoltării proiectului software.

Într-o primă fază se determină numărul de puncte funcŃionale neajustate (PFN) folosind următoarea relaŃie:

i iPFN tip pondere= ⋅∑ . (2)

În faza a doua, numărul de puncte funcŃionale se rafinează folosind aşa numitul factor de complexitate tehnică (FCT) care multiplică valoarea iniŃială a PFN producând numărul de puncte funcŃionale ajustate (PFA):

PFA PFN FCT= ⋅ . (3)

Factorul de complexitate tehnică se calculează cu următoarea formulă obŃinută pe cale experimentală:

Page 192: software engineering

3

14

ii 1

FCT 0.65 0.1 c=

= + ∑ , (4)

unde ic reprezintă următoarele caracteristici detaliate: funcŃii distribuite, comunicaŃii de date,

performanŃă, intrări de date on-line, actualizări on-line, prelucrări complexe, uşurinŃă la instalare, facilităŃi de schimbare, refolosire, amplasări multiple, interfaŃă complexă, configuraŃii utilizate masiv, utilizare operaŃională, capacitate de recuperare. InfluenŃa fiecărei caracteristici este evaluată pe o scară de la 0 (nerelevantă) la 5 (influenŃă mare). Gradul de influenŃare este suma acestor puncte pentru toate caracteristicile. ObservaŃie. Factorul de complexitate tehnică poate varia între 0.65 şi 1.35, deci o variaŃie de 35%± faŃă de valoarea nominală.

Exemplu. Se consideră un regulator care acceptă două intrări discrete ce provin de la un traductor de temperatură şi de la unul de debit. În cazul în care semnalele eşantionate provenite de la traductoare sunt între nişte limite admisibile, regulatorul furnizează comenzi adecvate pentru reglarea celor două mărimi. În cazul în care măsura depăşeşte limitele impuse, trebuie activat un scenariu de alarmă; valorile parametrilor regulatorului în caz de alarmă se preiau dintr-un fişier separat (fişier alarmă). Acest fişier mai conŃine şi alte versiuni ale valorilor parametrilor regulatorului astfel încât să se poată aplica o comandă adecvată. Valorile citite de la traductoare şi comenzile aplicate sunt arhivate într-un fişier. Operatorul uman este informat în permanenŃă despre starea sistemului (valorile intrărilor, comenzile aplicate, informaŃii auxiliare cum ar fi dispersia semnalelor etc.). Se furnizează de asemenea un raport separat despre cazurile de alarmă.

Analiza specificaŃiilor de mai sus duce la o schiŃă a funcŃionalităŃii sistemului ce poate fi observată în figura 1. Se identifică următoarele puncte funcŃionale:

A – numărul de intrări externe = 2 (temperatură, debit); B – numărul de ieşiri externe = 4 (raport alarmă, stare sistem, comandă, citiri traductoare); C- număr de cereri externe = 0; D – număr de fişiere externe = 1 (arhivă); E – număr de fişiere interne =1 (fişier alarmă).

Figura 1. FuncŃionalitatea sistemului de reglare

Vom considera pentru început că fiecare tip are complexitate medie. În acest caz se obŃine:

PFN 4A 5B 4C 10D 7E 8 20 0 10 7 45= + + + + = + + + + = . (5) În cazul în care se consideră cele două limite de complexitate se obŃin următoarele valori pentru

punctele funcŃionale neajustate:

PFN 3A 4B 3C 7D 5E 6 16 0 7 5 34= + + + + = + + + + = , (6)

respectiv PFN 6A 7B 6C 15D 10E 12 28 0 15 10 65= + + + + = + + + + = . (7) Dacă se presupune că un punct funcŃional necesită un efort de 2 persoane / zi , atunci cele două

limite se convertesc într-un domeniu de timp de la 68 la 130 zile. În cazul unei complexităŃi medii, va fi nevoie de 90 de zile pentru implementare.

ObservaŃii : • Modelul punctelor funcŃionale are avantajul că poate fi folosit încă din faza de pornire a

proiectului, deoarece se bazează pe documentul specificaŃiilor software.

Page 193: software engineering

4

• Rezultatele furnizate de acest model pot subestima realitatea deoarece în documentul specificaŃiilor software nu este elaborat la nivel de detalii de implementare.

• Abordarea bazată pe puncte funcŃionale nu se poate aplica în cazul în care se utilizează mediile de dezvoltare integrate de tipul CASE, în cazul programării orientate obiect sau reutilizării librăriilor.

2. Modelul COCOMO

Modelul COCOMO (COnstructive COst Model – Modelul constructiv al costurilor) este cel mai bun şi documentat model utilizat în estimarea efortului. COCOMO a fost dezvoltat de Boehm pe baza analizei a 63 de proiecte software. Modelul furnizează o formulă detaliată de determinare a orarului dezvoltării proiectului, a efortului de dezvoltare general, de descompunere pe faze şi activităŃi precum şi a efortului de întreŃinere. COCOMO estimează efortul în luni-om. Estimarea se bazează pe numărul de linii de cod (SLOC – source lines of code) exprimat în mii de instrucŃiuni de cod livrat (KDSI – thousands of delivered source instructions). Aceste instrucŃiuni includ toate instrucŃiunile programului, instrucŃiunile de formatare, declaraŃiile de date. Nu sunt numărate comentariile. Modelul COCOMO presupune că modelul de dezvoltare ales pentru proiectul software este cel în cascadă şi că proiectul are asigurat un management performant. Modelul COCOMO este dezvoltat în trei versiuni, în funcŃie de nivelul de rafinare a estimării: de bază, intermediar şi detaliat. În cele ce urmează vom discuta despre primele două. Boehm ia în considerare trei clase de siteme:

1. Încorporate. Aceste sisteme sunt caracterizate de constrângeri severe. Produsul este integrat într-un mediu strict şi are constrângeri de timp, fiind relativ nou pentru companie. Un exemplu tipic este cel al sistemelor de timp real (în aeronautică, medicină etc.).

2. Organice. Această clasă cuprinde sistemele ce sunt dezvoltate de echipe mici, într-un mediu cunoscut, cu o interfaŃă relaxată. În această categorie intră proiectele relativ mici.

3. Semidetaşate. Sistemele software din această clasă sunt intermediare celor două prezentate anterior. Exemple de astfel de sisteme sunt sistemele de operare şi sistemele de management al bazelor de date.

2.1 Modelul COCOMO de bază

În forma de bază a modelului COCOMO se pleacă exclusiv de la dimensiunea programului exprimată în KDSI, pe care o vom nota cu KDLOC (kilo delivered lines of code). Legătura între efort şi dimensiunea programului este dată de:

bEfort a KDLOC= ⋅ , (8)

unde a şi b sunt parametrii modelului, ale căror valori depind de clasa din care sistemul software face parte, după cum se poate observa în tabelul 1:

Tabel 1. Valorile parametrilor pentru COCOMO de bază Clasa de sisteme a b

Încorporate 3.6 1.2 Organice 2.4 1.05

Semidetaşate 3.0 1.12

ObservaŃii : • Forma funcŃiei din (8) precum şi valorile parametrilor sunt obŃinute experimental, pe baza

unor proiecte software anterioare. Din acest motiv, în cazul în care proiectul în lucru diferă foarte mult de proiectele pe baza cărora s-a realizat modelul COCOMO, s-ar putea folosirea acestui model să nu fie relevantă.

• În reprezentarea grafică din figura 2 se poate observa că pentru valori mari ale KDLOC apar diferenŃe semnificative între cele trei clase de sisteme prezentate.

Page 194: software engineering

5

Modelul COCOMO determină de asemenea orarul de dezvoltare al proiectului, M (exprimat în luni) folosind efortul calculat anterior:

dM c Efort= ⋅ , (9)

unde parametrii c şi d au valorile precizate în tabelul 2. ObservaŃiile anterioare rămân valabile şi în cazul determinării orarului de dezvoltare a proiectului. În figura 3 este prezentată dependenŃa orarului de numărul de linii de cod sursă livrate.

Tabel 2. Valorile parametrilor orarului de dezvoltare Clasa de sisteme c d

Încorporate 2.5 0.32 Organice 2.5 0.35

Semidetaşate 2.5 0.32

COCOMO se foloseşte şi pentru estimarea costurilor de întreŃinere. Formula se bazează pe eforturile anterioare estimate:

int retinereEfort TMA Efort= ⋅ , (10)

unde TMA este traficul de modificare anual, adică acea fracŃiune din KDLOC care se schimbă pe parcursul unui an.

Figura 2. DependenŃa efort(KDLOC)

Figura 3. DependenŃa orar(KDLOC)

Page 195: software engineering

6

2.2 Modelul COCOMO intermediar

Acest model, cel mai des utilizat, se obŃine prin rafinarea modelului de bază. ÎmbunătăŃirea constă în luarea în considerare a 15 atribute ale produsului. Pentru fiecare astfel de atribut, utilizatorul modelului trebuie să precizeze o pondere din gama: foarte mică (engl. very low, VL), mică (engl. low, LO), nominală (NM), mare (engl. high, HI), foarte mare (engl. very high, VH) şi extrem de mare (engl. extra high, XH). Lista atributelor este compusă din caracteristici ale produsului, sistemului de calcul, personalului şi proiectului.

Atributele produsului: • Fiabilitate cerută (RELY). Este utilizată pentru a exprima efectul defectelor software,

într-o gamă de la inconvenient minor (VL) la defect major (VH). • OcteŃi de date pe instrucŃiune sursă livrată(DATA). • Complexitate (CPLX). Atributul exprimă complexitatea codului, de la un cod simplu

(VL) la un cod de timp real (XH).

Atributele sistemului de calcul: • Timp de execuŃie (TIME) şi constrângeri de memorie (STOR). Acest atribut identifică

procentul de resurse ale calculatorului (timp şi memorie) utilizate de sistem. În starea nominală procentul este mai mic de 50% iar ponderea extrem de mare este dată de un procent de 95%.

• Volatilitatea platformei de dezvoltare (VIRT) este utilizată pentru a indica frecvenŃa schimbărilor hardware-ului, sistemului de operare şi mediului de programare. Schimbările frecvente şi semnificative au o pondere mai mare.

• Timp de răspuns (TURN) reprezintă timpul scurs de la începerea aplicaŃiei până la obŃinerea rezultatelor. LO indică un mediu cu interactivitate mare iar VH cuantifică situaŃia în care timpul este mai mare de 12 ore.

Atributele personalului • Capacitatea analiştilor (ACAP) şi a programatorilor (PCAP) descriu aptitudinile echipei

de dezvoltare. • ExperienŃa în domeniul aplicaŃiei (AEXP), în limbajul de programare (LEXP) şi în

mediul de dezvoltare (VEXP). Sunt utilizate pentru a cuantifica experienŃa echipei de dezvoltare în domeniile precizate anterior.

Atributele proiectului • Practicile de dezvoltare moderne (MODP) sunt legate de utilizarea practicilor software

moderne cum ar fi programarea structurată şi abordarea orientată obiect. • Utilizarea aplicaŃiilor software automate (TOOL). Acestea sunt folosite pentru măsurarea

ponderii pe care respectivele aplicaŃii le au în dezvoltarea proiectului şi la integrare. O pondere mare presupune nivele înalte în ambele aspecte precizate.

• Modificări ale orarului planului de dezvoltare (SCED) ce constau în comprimări (HI sau VH) sau extindere (LO sau VL) în raport cu orarul nominal (NM).

În tabelul 3 sunt prezentate ponderile caracteristicilor descrise anterior. În funcŃie de proiect, aceste rezultate parŃiale se înmulŃesc, obŃinându-se multiplicatorul final (P). Efortul se exprimă cu formula:

nomin alEfort Efort P= ⋅ , (11)

unde efortul nominal are diferite expresii, funcŃie de tipul de sistem:

• în cazul sistemelor încorporate: 1.20nomin alEfort 2.8KDLOC= ;

• în cazul sistemelor semidetaşate : 1.12nomin alEfort 2.8KDLOC= ;

• în cazul sistemelor organice: 1.05nomin alEfort 2.8KDLOC= .

Page 196: software engineering

7

ObservaŃii:

• relaŃiile anterioare sunt asemănătoare celor din modelul de bază, diferenŃa apărând la parametrul a, parametrul b rămânând nemodificat;

• dacă atributul are valoare nominală, nu influenŃează multiplicatorul P; • unele atribute se pot compensa: creşterea valorii unor atribute este anihilată de scăderea

valorii altor atribute; • estimarea timpului de dezvoltare a produsului este aceeaşi ca în modelul COCOMO de

bază; • efortul de întreŃinere se calculează cu formula:

int retinere nomin alEfort TMA Efort P= ⋅ ⋅ . (12)

Tabelul 3. Atributele modelului COCOMO intermediar VL LO NM HI VH XH RELY 0.75 0.88 1.00 1.15 1.40 DATA 0.9 1.00 1.08 1.16 CPLX 0.70 0.85 1.00 1.15 1.30 1.65 TIME 1.00 1.11 1.30 1.66 STOR 1.00 1.06 1.21 1.56 VIRT 0.87 1.00 1.15 1.30 TURN 0.87 1.00 1.07 1.15 ACAP 1.46 1.19 1.00 0.86 0.71 AEXP 1.29 1.13 1.00 0.91 0.82 PCAP 1.42 1.17 1.00 0.86 0.70 LEXP 1.14 1.07 1.00 0.95 VEXP 1.21 1.10 1.00 0.90 MODP

1.24 1.10 1.00 0.91 0.82

TOOL 1.24 1.10 1.00 0.91 0.83 SCED 1.23 1.08 1.00 1.04 1.10

Exemplu. Să considerăm un proiect software cu o dimensiune estimată la 300 KDLOC. Proiectul este parte a unui sistem de control a unui autovehicul, sistem ce preia informaŃii de la diferiŃi senzori, le procesează şi ini Ńiază acŃiuni de control. Evident proiectul face parte din clasa de sisteme încorporate.

Folosind modelul COCOMO de bază, obŃinem 1.20Efort 3.6 300 3379= ⋅ = luni-om. Timpul de dezvoltare

este 0.32M 2.5 3379 33.66= ⋅ = luni. În cazul modelului COCOMO intermediar, avem următoarele valori ale caracteristicilor:

RELY HI 1.15 VIRT NM 1.00 LEXP NM 1.00 DATA HI 1.08 TURN LO 0.87 VEXP NM 1.00 CPLX NM 1.00 ACAP HI 0.86 MODP NM 1.00 TIME VH 1.30 AEXP HI 0.91 TOOL LO 1.10 STOR VH 1.21 PCAP NM 1.00 SCED VH 1.10

Multiplicând valorile de mai sus se obŃine P 1.6095= . Eforul nominal este 1.202.8 300 2628⋅ = luni-om. Aplicând factorul de corecŃie P se obŃine un efort de 4229 luni-om, semnificativ mai mare decât cel estimat folosind modelul de bază.

3. Metoda Delphi de estimare a costului

În metodele de analiză anterioare era necesară determinarea unor parametri pe baza estimărilor unor experŃi. AcurateŃea acestor determinări este esenŃială în estimarea costului. Este de aşteptat ca rezultatele furnizate de un grup de experŃi să fie bune decât cele ale unei singure

Page 197: software engineering

8

persoane. Metoda Delphi ajută la coordonarea procesului de obŃinere de informaŃii de la un grup de experŃi şi are următorii paşi esenŃiali:

• Coordonatorul prezintă fiecărui expert specificaŃiile proiectului şi alte informaŃii relevante.

• Coordonatorul convoacă o întâlnire unde experŃii discută estimările. • ExperŃii completează un formular cu estimările personale ale efortului de dezvoltare a

proiectului; experŃii furnizează cea mai probabilă valoare precum şi limitele inferioară şi superioară. • Coordonatorul pregăteşte şi pune în circulaŃie un raport ce indică estimările individuale şi

de grup. • Coordonatorul convoacă o nouă întâlnire în care experŃii discută estimările curente.

Aceste etape se repetă până când se ajunge la un consens. Estimarea de grup se obŃine ca o medie ponderată a estimărilor individuale cu următoarea formulă:

LI 4VP LS

estimare6

+ += (13)

unde LI – limita inferioară a estimării; VP – valoarea probabilă a estimării; LS – limita superioară a estimării. VarianŃa unei estimări individuale este definită ca:

LS LI

var ianta6

−= . (14)

VarianŃa estimării de grup este media varianŃelor individuale.

Exemplu. Se consideră un sistem software de management al traficului. Sistemul trebuie să livreze informaŃii despre condiŃiile curente de trafic, să facă predicŃii şi să identifice punctele unor congestionări potenŃiale ale traficului. Există cinci experŃi implicaŃi în estimarea costului (exprimat în luni). Coordonatorul furnizează experŃilor informaŃiile necesare. Într-o primă fază, experŃii furnizează estimările din tabelul 4. Coordonatorul calculează media estimărilor şi prezintă experŃilor rezultatele, conform tabelului 5. La următoarea întâlnire, experŃii discută estimările curente şi trec la rafinarea acestora (tabelul 6). Se calculează din nou estimarea medie şi varianŃa conform tabelului 7.

VarianŃa grupului este un indicator al convergenŃei procesului de estimare a costului. VarianŃa ar trebui să scadă de la iteraŃie la iteraŃie.

Tabelul 4. Prima iteraŃie a estimării timpului de dezvoltare LI VP LS Expert 1 20 50 60 Expert 2 25 40 70 Expert 3 10 55 75 Expert 4 30 60 70 Expert 5 15 35 85

Tabelul 5. Calculul estimării de grup şi a varianŃei – prima iteraŃie

Expert Estimare VarianŃă 1 46.7 6.7 2 42.5 7.5 3 50.8 10.8 4 56.7 6.7 5 40.0 11.7 Medie 47.3 8.6

Tabelul 6. A doua iteraŃie a estimării timpului de dezvoltare LI VP LS Expert 1 30 50 60 Expert 2 30 45 65 Expert 3 20 50 70 Expert 4 30 55 70 Expert 5 25 40 75

Tabelul 7. Calculul estimării de grup şi a varianŃei – a doua iteraŃie

Expert Estimare VarianŃă 1 48.3 5.0 2 45.8 5.8 3 48.3 8.3 4 53.3 6.7 5 50.0 8.7 Medie 49.1 6.8

Page 198: software engineering

Bibliografie 1. B.P. Douglas, Real Time UML, 3rd edition, Addison-Wesley, 2004 2. B.P. Douglas, Real Time Design Patterns, Addison-Wesley, 2003 3. J. Rumbaugh, I. Jacobson, G. Booch, The Unified Modeling Language Reference manual, 2nd edition, Addison Wesley,2004. 4. S. L. Pfleeger, Software engineering. Theory and practice, Prentice Hall, 1998. 5. Gheorghies, O., Apetrei, A., Ingineria programãrii, http://thor.info.uaic.ro/~ogh/ip/index.php, 2002 6. F. Leon, Ingineria Programarii, note de curs, http://eureka.cs.tuiasi.ro/~fleon. 7. J. F. Peters, W. Pedrycz, Software engineering. An engineering Approach, J.Wiley&Sons, 2000. 8. S. Bennet, S. McRobb, R. Farmer, Object-Oriented Systems Analysis and Design Using UML, McGraw-Hill, 2002 9. Pressman R., Software Engineering: A practitioner's Approach, (4th ed.), McGraw-Hill, 1997. 10. Sommerville I. Software Engineering (5th ed.), Addison-Wesley, 1996. 11. Van Vliet H., Software Engineering -Principles and Practice , J.Wiley&Sons, 1993