Laboratorul 01: Scrierea specificatiilor unui proiect

Cuvant inainte. Scopul laboratoarelor

Pe parcursul acestor laboratoare noi vom realiza un proiect de la 0 si va vom trece prin toate etapele sale (de la intelegerea proiectului, la testare). Fiecare laborator reprezinta o etapa din realizarea proiectului. O parte din laboratoare vor avea si o componenta video (in stilul cursurilor de pe Udemy).

La finalul parcurgerii materialelor incarcate pentru laborator va trebui sa fiti capabili sa dezvoltati un proiect intreg, precum si sa dobanditi cunostinte ce va vor ajuta si in situatii mai complexe.

Ce veti invata la acest laborator?

In acest prim laborator vom cunoaste proiectul. Vom citi cerintele clientului si vom realiza impreuna o arhitectura, pe care sa o putem folosi mai departe, in realizarea proiectului.

Vom aplica o forma foarte simpla de Tactical Domain Driven Design pentru a delimita domeniul proiectului (informatia utila de business logic). Vom folosi User Stories si vom crea o schema de date.

Timp estimat de parcurgere: 30 - 40 de minute

Cuprins

Scenariul de proiect

Sunteti un startup de IT si realizati proiecte la comanda. Primul vostru client este un tanar care si-a deschis o biblioteca. Deoarece traim in era digitala, doreste ca biblioteca sa aiba o aplicatie web. Acesta este descrierea aplicatiei:

“Mi-as dori sa am o aplicatie prin care pot gestiona cartile din biblioteca. Vreau sa pot aduaga carti in sistem, pentru fiecare carte specificand Nume, Autor, Gen, cat zile poate fi imprumutata si o serie de keywords.

Doar oamenii care au cont in platforma pot imprumuta carti. Un utilizator nu poate imprumuta mai mult de 3 carti o data.

Mi-ar placea ca cititorii sa vada ce carti au imprumutate in prezent, cat timp mai au si, in plus sa vada si un istoric al cartilor imprumutate si returnate si cat timp au fost fiecare imprumutate.

Mi-ar placea ca eu sa pot vedea pentru fiecare carte daca este imprumutata sau nu, si daca da, de ce utilizator, fiind specificat e-mailul si telefonul.

Nu in ultimul rand, mi-as dori sa pot vedea urmatoarele metrici:

  • Per carte - de cate ori a fost imprumutata, timpul mediu de imprumutare, timpul mediu de retur la timp si istoricul de imprumut (email, telefon, data de start imprumut si data de retur). Utilizatorii care au adus cartile mai tarziu, sa fie cumva diferentiati.
  • Per total - Cate carti sunt imprumutate din totalul de carti, top X autori imprumutati, top X genuri imprumutate si top X keyword-uri imprumutate. Vreau sa pot sa dau orice valoare pentru acest X.

Cam asta ar fi aplicatia, sper sa va descurcati. Multumesc!”

Extragerea User Stories din cerinte

Aplicatia pe care clientul vostru o doreste pare simpla. Pe scurt, doreste sa poata adauga carti, sa aiba utilizatori, ei sa imprumute carti, si apoi sa vada cine ce carti a imprumutat si inca 2-3 informatii care se pot extrage usor din niste JOIN-uri. Chiar daca pare simplu, si se poate rezolva rapid, vom profita de simplitatea proiectului pentru a va trece prin mai multe concepte care se aplica, in special, in scenarii complexe.

Asadar, in loc sa ne apucam sa deschidem un tutorial de pe net de genul ”how to create a simple web app in 5 minutes”, vom scrie User Stories pentru acest proiect.

User Stories sunt un concept care tin de metodologia Agile (si Kanban). Prin User Stories se intelege un feature care poate fi dezvoltat intr-o unitate scurta de timp, expus din perspectiva unui utilizator care doreste sa realizeze o actiune. Totalitatea User Stories constituie intreg proiectul. Asadar, extragerea User Stories-urilor din cerintele clientului este un proces iterativ, care cere experienta si rabdare. In general, acest proces se face de catre sau impreuna cu Product Owner-ul.

Tehnica Simplificata

Chiar daca procesul de a extrage User Stories revine unui Product Owner, este bine ca si dezvoltatorii sa cunoasca procedeele, cel putin cele simplificate. In plus, in cadrul unui Startup, nu va garanteaza nimeni ca veti avea PO la dispozitie.

Un user stories este cuprins din:

  1. Utilizatorul (Actorul) care vrea sa faca ceva
  2. Actiunea care este facuta de utilizator
  3. Obiectul asupra caruia se resfrange actiunea
  4. Conditiile in care acea actiune se poate intampla (optional)

Aplicand aceasta logica, putem transforma cerinta clientului intr-o insiruire de X doreste sa FACA Y [in conditiile Z].

User Stories sunt scrise din perspectiva utilizatorului.

Determinarea Utilizatorilor

Din start, ne-am dat seama ca aplicatia va avea 2 categorii de utilizatori: administrator (clientul) si utilizatori (viitorii cititori). Asadar, exista 2 categorii de User Stories:

  • Din perspectiva Administratorului
  • Din perspectiva Cititorului

User Stories Administrator

As an administrator I would like to be able to add books, by providing their name, author, genre and maximum time for rental in days. For each book, I want to assign some keywords that describe the book. The same keyword can be used for more than 1 book.

As an administrator, I would like to be able to modify any book.

As an administrator, I would like to be able to delete any book, only if it is not already rented.

As an administrator, I would like to be able to check status of a book, by seeing its name, if is rented, who rented it (email, phone number), when it was rented, for how long, and how much until returning.

As an administrator, I would like to be able to view metrics of a specific book. Metrics should be how many times a book was rented, average rental time, average rental in-time completion and its rental history (email, phone, date start, date end). The rentals that exceed the normal completion time should be highlighted.

As an administrator, I would like to be able to view overview metrics. Metrics should be how many books are rented out of the total number, top X author rented, top X genres rented rented and top X keywords rented. I want to be able to set this X manually.

User Stories Cititori

As a user, I would like to be able to access the platform.

As a user, I would like to be able to setup a profile, consisting of email, phone number, name and address.

As a user, I would like to be able to view all the books in the library, together with their status (rented or available).

As a user, I would like to be able to rent an available book for a certain amount of time.

As a user, I should not be able to rent more than 3 books at a time.

As a user, I should not be able to rent a book that is already rented.

As a user, I would like to be able to see the books I am currently renting and see the remaining time for each.

As a user, I would like to be able to see the books I have rented and returned and see total time rented for each.

Validarea User Stories

Dupa cum puteti observa, aceste User Stories reprezinta destructurarea cerintelor clientului in fraze care descriu fiecare feature in parte. Pentru verificare, trebuie sa mergeti cu aceste user stories catre client, sa le discutati si sa le aprobe.

Este important ca User Stories sa fie explicate in limbaj cat mai natural pentru a putea fi intelese si de oameni non tehnici.

Presupunem ca am primit aprobarea si ne putem apuca de arhitectura.

Realizarea arhitecturii de domeniu

Pasul 2 de care trebuie sa tinem cont inainte sa ne apucam sa scriem cod este sa definim domeniul proiectului. Prin domeniu intelegem data pe care proiectul o utilizeaza si comportamentul ei. Bineinteles, in cazul unei aplicatii simple, acest pas poate fi ignorat si se poate crea direct schema de baza de date, insa in proiectele complexe, acest pas este esential.

Una dintre cele mai folosite metode de schitare a informatiilor de proiect este Domain Driven Design. DDD este o strategie dificila si necesita multa experienta pentru a fi realizata la potential maxim. In plus, nu se preteaza la proiecte simple, de multe ori ingreunand dezvoltarea unui proiect simplu. Acestea fiind spuse, in proiecte enterprise, sau complexe, DDD forteaza dezvoltarea proiectului intr-o maniera care creaza ordine in randul datelor de proiect.

Va recomandam sa cititi cartea, daca sunteti interesati de arhitectura sau concepte avansate de backend.

Mai multe informatii veti obtine la cursul dedicat strategiilor de dezvoltare pentru backend-uri.

In continuare, vom aplica Tactical Domain Driven Design, care este o componenta a DDD.

Tactical DDD Simplificat

Tactical DDD se refera, pe scurt, la structurarea datelor tinand cont de urmatoarele concepte:

  1. Entitati - obiecte de domeniu care au identitate proprie (ex: scaunele dintr-un avion)
  2. Value Objects - obiecte de domeniu imutabile, care nu au identitate (ex: scaunele din Ikea)
  3. Agregate - mai multe Entitati si Value Objects care trebuie grupate din motive de colaborare stransa (constrangeri). Orice agregat trebuie sa aiba o radacina (Aggregate Root)

Diferenta dintre o Entitate si un Value Object o face identitatea obiectului. Un scaun dintr-un avion are identitate proprie, pentru ca este identificat de un numar. Un scaun in Ikea nu are identitate, pentru ca nu este diferenta intre bucati diferite ale aceluiasi model. Entitatile au identitate, Value Objects, nu.

Aplicand Tactical DDD obtinem o schema de date care ne asigura consistenta in cadrul tranzactiilor din acelasi agregat. Dificultatea in aplicarea Tactical DDD consta in identificarea agregatelor si a radacinilor de agregate (Aggregate Root - AR).

AR sunt responsabile de pastrearea consistentei intre toate entitatile care fac parte din agregatul in care AR este radacina. Altfel spus, nicio entitate din interiorul agregatului nu poate fi modificata din exterior, decat prin AR. Asta creaza o relatie de dependenta intre entitati si AR care poarta numele de “Invariant Rule”

Puteti asocia Agregatele si Radacinile de Agregat cu o structura arboresecenta, unde radacina este AR, iar celealte noduri sunt Entitati.

Si Radacina de Agregat (AR) este tot o entitate.

Un agregat poate fi format doar din radacina sa (agregat cu o singura entitate care este AR).

Avantajul in lucru cu Agregatele este ca obtinem o separatie clara a functionalitatilor dintre grupuri de date. Mai mult, Tactical DDD impune ca tranzactiile intre mai multe agregate sa se faca folosind consistenta in cele din urma (Eventual Consistency), prin propagare de evinemente.

Asadar, avem urmatoarele reguli:

  • Datele din interiorul unui agregat sunt sincronizate in orice moment de timp (Consistenta Stricta - Strong Consistency)
  • Datele in interiorul unui agregat pot fi modificate doar prin intermediul radacinii (Aggregate Root)
  • O tranzactie care schimba date intre doua sau mai multe agregate trebuie sa fie facuta asincron (Consistenta in cele din Urma - Eventual Consistency)

Prin tranzactie se inteleg doar de operatiile care modifica starea unui obiect (Create, Update, Delete).

Va recomand vizionarea acestui videoclip al lui Vaughn Vernon, unul dintre pionierii DDD

Aplicarea Tactical DDD pe proiect

Daca analizam User Stories create recent, observam ca in majoritatea cazurilor avem urmatoarele:

  • Utilizator
  • Carte
  • Imprumut

Toate actiunile se invart in jurul acestor 3 elemente. Asta inseamna ca, pentru domeniul nostru, aceste elemente reprezinta entitatile de domeniu. Intrebarea se pune, cum le impartim in agregate? Pentru a raspunde, trebuie sa vedem ce constrangeri (Invariant Rules) gasim.

In primul rand, un utilizator poate exista fara carte, si o carte poate exista fara utilizator. Deci, User si Book NU vor face parte din acelasi agregat. Deci, avem 2 agregate. Ce facem cu Rental?

Rental are sens in ambele agregate:

  • Utilizatorul imprumuta
  • Cartea este imprumutata

Pare ca suntem in impas. Pentru a rezolva acest lucru, trebuie sa analizam ce constrangeri gasim in user stories:

  • As a user, I should not be able to rent more than 3 books at a time.
  • As a user, I should not be able to rent a book that is already rented.

Daca traducem asta intr-un scenariu real, un utilizator nu va putea imprumuta niciodata o carte, daca ea nu se afla la biblioteca. Dar, daca nu sunt impuse constrangerile in mod corect, poate imprumuta mai mult de 3 carti. Deci asta inseamna ca Rentals trebuie legat de utilizator.

Asadar, obtinem urmatoarele 2 agregate:

  1. UserRentals Aggregate, care contine 2 entitati: Users (AR) si Rentals
  2. Books Aggregate, care contine 1 entitate: Books (AR)

Ce facem in cazul in care un utilizator va imprumuta o carte? Aceasta operatie implica o tranzactie intre doua agregate separate (UserRentals si Books). Dar in cazul in care un utilizator returneaza o carte?

Asa cum am precizat in sectiunea anterioara, in cadrul tranzactiilor intre doua agregate separate se foloseste Eventual Consistency si propagare de evenimente. Asta inseamna ca, in momentul in care un User imprumuta o carte, trebuie lansat un eveniment care sa notifice AR-ul din Books ca o carte a fost imprumutata. La fel si pentru cand o carte este returnata.

Mai multe detalii veti vedea la Cursul de Strategii pentru Backend si la un laborator viitor unde se discuta aceasta bucata de backend.

Arhitectura de Domeniu. Schema de Date

Dupa aplicarea Tactical DDD, obtinem aceasta schema:

Simplu, nu? Urmatorul pas este sa transformam aceasta arhitectura intr-o schema de date, care va fi persistata intr-o baza de date. Din nou, trebuie sa analizam User Stories si sa identificam campurile care vor face parte din fiecare entitate.

In final, vom obtine urmatoarea schema de date:

Chiar daca nu am folosit o notatie specifica de baze de date, se observa relatiile intre entitati prin id-urile corespunzatoare.

Observati cum Keywords este notat cu VO. Aceasta inseamna ca este Value Object, adica nu are identitate.

User are campul identityGuid deoarece vom folosi un sistem extern pentru gestiunea conturilor, numit Auth0. Mai multe detalii la laboratorul dedicat pentru acest lucru.

Pasii Urmatori

Acum ca avem arhitectura de domeniu gata, putem sa ne apucam de lucru efectiv. De obicei, munca diverge in doua directii paralele:

  • Se realizeaza un mockup pentru a valida partile grafice cu clientul
  • Se incepe lucrul la backend pentru a fi pregatit pentru momentul in care incepe si frontend-ul munca

In cadrul laboratoarelor urmatoare vom prioritiza partea grafica, si vom realiza mockup-urile si frontendul, iar apoi ne vom concentra pe backend. La final, vom imbina frontend-ul cu backend-ul.

Felicitari pentru parcurgerea acestui laborator!

pw/laboratoare/01.txt · Last modified: 2022/03/15 19:31 by alexandru.hogea
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0