[Curs nr.2]
In foarte multe privinte procesul de dezvoltare software
se aseamana cu procesul de construire a unei case. Astfel, daca cineva
doreste sa-si construiasca o casa, in primul rand va purta discutii cu
arhitectul, discutii care vor ajuta la formarea unei viziuni
comune asupra produsului care sa satisfaca nevoile familiei si sa se incadreze
in limitele impuse de buget si de timp. Schitele de proiect sunt
importante atat pentru beneficiar cat si pentru arhitect, deoarece constituie
un mijloc de comunicare a intentiilor intr-un mod mai formal si mai precis.
Uneltele de constructie performante si masuratorile sunt necesare pentru
toti tamplarii, electricienii, instalatorii si zugravii pentru a materializa proiectul. Inspectiile periodice la fata
locului, din partea beneficiarului ca si din partea unor experti in domeniul
constructiilor, sunt esentiale pentru a verifica daca ceea ce se face este conform cu dorintele clientului si cu
standardele in vigoare. In final, insa, ceea ce
este mai important pentru client si familia
sa este produsul finit - insasi casa. Orice alta activitate
este secundara, dar constituie pasi inevitabili in procesul de elaborare
a produsului final.
Pe masura ce nevoile familiei se modifica (de ex. poate
aparea necesitatea amenajarii unei parti din subsol ca birou sau dormitor), respectiv pe masura ce lucrurile
se uzeaza (de ex. este necesara renovarea bucatariei sau repararea
unui robinet fisurat in baie), urmatorul lucru
important il constituie existenta unei marturii palpabile sau conceptuale
care sa reflecte scheletul arhitectural al casei. Un asemenea
document:
Tot acest proces descris mai sus este analog procesului
de dezvoltare software. O organizatie care dezvolta un software de calitate niciodata nu pierde din vedere obiectivul
primordial: dezvoltarea, furnizarea si intretinerea in mod eficient a unor
produse care sa multumeasca utilizatorul si care sa
satisfaca toate cerintele
stabilite.
Un program care face ceva util este cel mai important produs al oricarui proiect.Activitatile de analiza, proiectare, implementare, verificare a calitatii si documentare sunt importante numai in masura in care contribuie la atingerea acestui scop. Orice altceva (discutii, intalniri, programare, redactare, testare) este secundar.
Al doilea ca importanta dupa programul insusi, este documentul care descrie arhitectura produsului.Acesta este esential pentru evolutia si intretinerea programului. Toate modificarile impuse fie de aparitia unor cerinte noi, fie de eliminarea unor erori, trebuie facute de asa maniera incat sa se armonizeze cu arhitectura originala. Altminteri, in timp, se va ajunge la un sistem "peticit", de calitate slaba, a carui structura originala devine din ce in ce mai obscura, pana cand nu mai poate fi modificata.
Dezvoltarea unor produse de calitate
Ce este un produs software de calitate
? Din perspectiva unui programator OO, raspunsul este unul obiectiv:
un program de calitate este acela care functioneaza
si care realizeaza tot ce se asteapta de la el, nimic mai mult sau mai
putin. Din perspectiva utilizatorului final si a echipei de
dezvoltare in ansamblu, raspunsul este unul subiectiv: un
program de calitate este unul elegant.
Eleganta este un atribut care presupune simplitate, claritate,
usurinta in intelegere. Software-ul de calitate rezolva probleme complexe
prin intermediul unor mecanisme a caror bogatie semantica permite aplicarea
lor in domenii complet diferite. Eleganta inseamna a gasi abstractizarea
potrivita, inseamna utilizarea resurselor limitate in maniere mereu noi.
Exemplu: O companie de transporturi intampina probleme cu gestionarea miilor de colete care circula prin reteaua sa. Ea a creat un sistem orientat pe obiecte pentru managementul operatiilor zilnice. Un model obiectual de abordare a problemei a parut a fi solutia potrivita. Pe baza acestei structuri a fost posibila adaugarea incrementala a noi module care au dus la eficientizarea procesului ca timp si cost. Folosind algoritmi genetici, ruland pe un supercalculator independent, consultantii software au putut sa supravegheze constant reteaua si sa ofere sfaturi personalului de deservire. A reiesit ca algorimii de baza puteau fi utilizati si pentru determinarea rutelor optimale de livrare a pachetelor catre clienti.Acest exemplu arata importanta unei arhitecturi orientate pe obiecte. Vom discuta arhitectura unei asemenea aplicatii, pornind de la clase si ajungand la generatoare de aplicatii (frameworks).
Pentru un programator individual, care utilizeaza programarea
orientata pe obiecte (OOP, Object Oriented Programming), unitatea primara
de compunere a programului este clasa.
Pentru programatorii care folosesc metode neobiectuale,
unitatea primara a unui program este algoritmul.
Pentru proiectele OO unitatea de baza in care ele se pot descompune este clasa, nu algoritmul. |
---|
Trebuie insa precizat ca, asa cum s-a aratat in capitolul anterior clasa este necesara dar nu suficienta ca element de descompunere.
O clasa de calitate are urmatoarele caracteristici:
Furnizeaza o abstractizare clara, bine delimitata a unui concept din vocabularul domeniului problemei sau al solutiei ei.Dezvoltarea claselor in conditii de izolare este dificila. A crea un sistem OO de calitate inseamna mai mult decat a crea niste clase individuale de calitate. Intr-un sistem complex nici o clasa nu exista in izolare, dimpotriva: clasele colaboreaza unele cu altele pentru a se obtine functionarea sistemului. De aceea, din perspectiva unui arhitect software, a construi sisteme de calitate implica luarea in considerare a unor structuri software care transcend clasele individuale si anume, ca urmare a unei distribuiri judicioase a responsabilitatilor se va urmari obtinerea unor colaborari calitative intre clase.
O clasa denota un set de obiecte care impartasesc o structura si un comportament comun. Astfel, intr-un sistem OO se pot identifica multe clase care materializeaza limbajul specific domeniului abordat. De exemplu, intr-un sistem de plati, se vor gasi clase reprezentand clienti, furnizori, plati si produse. Intr-un sistem medical veti identifica clase reprezentand pacienti, prestatori si servicii. In amandoua cazurile prezentate, daca privim din perspectiva implementarii, se pot identifica clase care reprezinta elemente specifice limbajului programatorilor: tranzactii, liste (de produse sau servicii) si tabele (de furnizori sau prestatori de servicii). Cu alte cuvinte:
Orice clasa dintr-un sistem OO trebuie sa corespunda unei entitati tangibile sau unei abstractiuni conceptuale din domeniul utilizatorului final sau al implementatorului. Se recomanda inlaturarea tuturor claselor care nu satisfac aceasta cerinta. Prin "abstractizare clara", se intelege ca o clasa trebuie sa aiba frontiere bine definite in spatiul problemei. O clasa reprezentand toti furnizorii costisitori dintr-un sistem medical nu este o abstractizare buna, deoarece notiunea de "costisitor" este vaga si subiectiva.
Un alt element legat de delimitarea unei abstractizari se refera la structura si comportamentul incapsulate intr-o clasa. De exemplu, o clasa reprezentand clientii dintr-un sistem de evidenta a platilor va contine atribute ca: numele, adresa si telefonul clientului. A atasa insa ca atribut al clientului o lista a angajatilor ar fi o eroare, deoarece lista respectiva nu face parte din vocabularul sistemului de plati. Similar, comportamentul asociat cu clasa ce reprezinta clientii poate include posibilitatea de a consulta istoricul platilor sau esalonarea creditului unui anumit client. In schimb, ar fi deplasat sa se dea posibilitatea de a consulta numele copiilor unui client, deoarece acest lucru este total irelevant in contextul sistemului abordat.Incorporeaza un set minimal si bine definit de responsabilitati, pe care le indeplineste foarte bine. O responsabilitate denota obligatia unui obiect de a manifesta un anumit comportament. Deoarece orice obiect este instanta unei anumite clase, rezulta ca o clasa trebuie sa inglobeze responsabilitatile tuturor instantelor sale.
Distribuirea responsabilitatilor intr-un sistem OO reprezinta o decizie critica. Nu trebuie nici sa avem putine clase care "au prea multe de facut", dar nici sa avem multe clase care "au prea putine de facut". Ca regula generala:Desigur ca de la regula generala vor exista unele exceptii. De exemplu o clasa care modeleaza o fereastra dintr-o interfata grafica este o abstractiune fundamentala si ea va contine foarte multe responsabilitati. In schimb, o clasa care modeleaza o valva sau un aparat de masura dintr-un sistem de automatizari industriale poate include doar 1-2 responsabilitati. Important este ca, la aplicarea regulii de mai sus sa se aiba in vedere caracteristici ca: usurinta in intelegere si flexibilitate.
O clasa obisnuita trebuie sa inglobeze cam 3-5 responsabilitati.
Trebuie subliniat faptul ca responsabilitatea unei clase nu se confunda cu operatiile sale. O responsabilitate este dusa la indeplinire printr-un set de operatii care coopereaza intre ele
Realizeaza o separare clara a interfetei (comportamentului) abstractiunii, in raport cu implementarea.
Este usor de inteles si simpla dar totodata extensibila si adaptabila. Daca distribuirea responsabilitatilor in cadrul sistemului s-a facut bine, atunci clasele rezultate vor fi clare si simple.
Exemplu: Sistemul MacApp este poate cel mai elocvent exemplu de generator de aplicatii de calitate. Prima versiune disponibila a aparut la inceputul lui 85 si folosea limbajul Object Pascal. MacApp a reprezentat unul dintre primele generatoare de aplicatii disponibile comercial. Domeniul sau era general, intentia fiind de a permite crearea de aplicatii conforme cu standardul Macintosh in ceea ce priveste interfata utilizator. Dupa cum era de asteptat, primele versiuni ale bibliotecii generatorului nu au fost prea grozave, in principal din cauza ca biblioteca, in ansamblul ei, se prezenta ca o mare de clase, ale caror interrelatii trebuiau descoperite de catre cei ce aveau indrazneala sa se avante pe acest teritoriu neexplorat. Mai mult, responsabilitatile nu erau clar distribuite intre clase, adaptarea unor clase individuale fiind astfel mult ingreunata. Dupa considerabile experimentari si utilizari reale, biblioteca a fost radical modificata (clase, ierarhii, distributia responsabilitatilor), pe la sfarsitul anilor 80. In jurul anului 1990 biblioteca a fost in intregime rescrisa in C++, operandu-se si alte modificari in structura claselor. O versiune relativ stabila a fost gata in 1992. De aceasta data biblioteca a fost mult mai abordabila, inteligibila si adaptabila. Important a fost ca avea o arhitectura explicita, nu mai era doar o mare de clase, iar colaborarile intre clase erau bine documentate.O colaborare de clase bine conceputa se caracterizeaza prin:
Este rezultatul contributiei unui set restrans de clase care conlucreaza in vederea obtinerii unui anumit comportament.Crearea colaborarilor importante dintr-un sistem este activitatea centrala a arhitectilor software pe durata fazei de proiectare. Aceste colaborari reprezinta "sufletul" unei arhitecturi, deoarece ele sunt deciziile strategice care realizeaza conturul de baza al sistemului.
Genereaza un comportament care nu reprezinta responsabilitatea unei singure abstractiuni, ci care deriva din ansamblul de responsabilitati distribuite pe setul de clase.
Distribuirea
responsabilitatilor intr-un sistem OO trebuie sa se faca pe 2 directii:
|
---|
O arhitectura OO bine structurata consta din:
Un set de clase organizate de regula in ierarhii multiple.Prima dimensiune a unei arhitecturi OO (setul de clase) realizeaza captarea MODELULUI STATIC al abstractiunilor care formeaza vocabularul domeniului problemei. Spunem vocabular, deoarece fiecare abstractiune reprezinta ceva din limbajul unui utilizator sau al unui implementator.
Un set de colaborari care specifica modul in care clasele coopereaza intre ele pentru a genera diversele functiuni ale sistemului.
Intr-un proiect OO cea mai mare unitate de descompunere o reprezinta categoria de clase. |
---|
Persistenta obiectelor (adica pastrarea valorilor lor pentru perioade nedefinite de timp; cel mai adesea mecanismele de asigurare a persistentei presupun existenta unor baze de date OO sau relationale).Aceasta lista nu este exhaustiva, dar reprezinta cele mai des intalnite mecanisme dintr-un sistem. Pentru fiecare din aspectele enumerate exista mai multe solutii, iar sarcina echipei de proiectanti este de a alege una dintre ele, tinand cont si de cerinte precum: performanta, capacitate, fiabilitate, securitate etc. Fiecare asemenea decizie strategica implica, la un nivel de detaliu mai mare, o suma de decizii tactice.
Gestionarea memoriei.
Gestionarea proceselor.
Transmiterea/receptionarea mesajelor.
Distribuirea si migrarea obiectelor.
Conectarea in retea.
Tranzactiile.
Tratarea evenimentelor.
Tratarea exceptiilor.
Interfata utilizator.
Un sablon reprezinta o solutie comuna a unei probleme intr-un anumit context. |
---|
Produsele unui proiect software
Reluand exemplul cu
casa,
prezentat la inceputul acestui capitol, putem spune ca, pe langa casa propriu-zisa,
pe durata constructiei ei rezulta si alte produse care, fie sunt derivate
din procesul de construire, fie sunt ajutatoare acestui proces. De exemplu,
constructorul si proprietarul semneaza un constract in care se specifica
ce anume se va construi. Pentru unele constructii se elaboreaza si un model
la scara redusa. Se elaboreaza, de asemenea, desene care vor reda aspectul
general al casei, precum si schite de detaliu necesare executiei instalatiilor
electrice si de canalizare. Constructorii vor avea nevoie la un moment
dat de niste schele, pe care le vor demonta la terminarea lucrului. Se
pot folosi fotografii ale unor case existente sau desene care sa serveasca
drept model pentru anumite detalii de constructie sau decorare. La sfarsit,
din toate acestea, proprietarul va ramane probabil cu casa, un rand de
chei, cateva schite generale si cu instructiunile de intretinere si garantie.
Si procesul de dezvoltare software este similar. La dezvoltarea
unui proiect, o echipa bine organizata va elabora doar cantitatea necesara
de produse, pe langa aplicatia propriu-zisa.
Lista produselor reutilizabile a oricarui sistem software
include:
Pentru echipa de dezvoltare produsele relevante sunt:
Pentru utilizatorul final, in afara de aplicatia executabila propriu-zisa, produsele relevante sunt:
Datele se refera la totalitatea informatiilor brute care sunt prelucrate de aplicatie. In cazul in care datele nu apar descrise explicit intr-un document, pe masura ce sistemul dezvoltat creste in dimensiuni, se ajunge adesea la situatii de fragmentare a datelor si de inmultire a redundantelor.
Interfetele
utilizator, ca produse reutilizabile, reprezinta aspectul
general (look & feel) al unei familii de programe. Desi platformele
grafice bazate pe ferestre existente la ora actuala propun un "look &
feel" propriu, ele lasa totusi programatorilor un grad considerabil de
libertate in alegerea stilului interfetei, mai ales la utilizarea
elementelor de control din ferestre.
In forma intangibila, o interfata exista ca stil aplicat in realizarea
ferestrelor si controalelor ce intervin intr-o aplicatie aflata in
executie. Forma tangibila presupune de regula un document cu rol de ghid
de stil. Un asemenea ghid poate oferi o baza pentru stabilirea
consensului intre dezvoltatori si utilizatori. In plus, el ar putea fi
folosit si in proiecte viitoare. In felul acesta se pot economisi
costurile de instruire necesare atunci cand aplicatiile livrate nu
prezinta o consistenta a interfetelor.
Pentru echipa de management produsele importante sunt:
Planificarea proiectului cuprinde infrastructura necesara pentru
stabilirea termenelor si alocarea resurselor umane.
In cazul proiectelor care se desfasoara intr-un mod haotic, termenele
sunt stabilite ad-hoc, iar alocarea resurselor reprezinta putin mai mult
decat angajarea in proiect a persoanelor care in momentul respectiv nu
sunt prea incarcate.