Introducere în CQRS


(Cosmin Popescu) #1

Am gasit acest articol interesant care explica pe intelesul tuturor conceptul de CQRS. Unul din lucrurile pe care vreau sa le invat in 2018 sunt design patterns.
Nu toate !
Doar cele mai uzuale.

:slight_smile:
Este scris de tekkie !

PS: Revista Today Software Magazine are articole interesante care merita sa fie citite.


(Stanciu Bogdan Mircea) #2

O lectură plăcută și utilă. Lucrez și am lucrat în mare parte de unul singur dar tot cred că astfel de cunoștințe îmi vor fi utile.


(Cosmin Popescu) #3

Mai mult ca sigur !

Te vor ajuta in a scrie cod testabil si cu cat mai putine erori :slight_smile:

Vreau sa mai studiez un pic acest concept si sa incerc sa fac o mica aplicatie in care sa il pun in aplicare.


(Georgiana Gligor) #4

Mulțumesc pentru aprecieri, mă bucur să aud că am reușit să mă exprim destul de bine încât să explic conceptul, care e unul destul de greu de înțeles și de internalizat pentru cei care sunt obișnuiți cu CRUD.
CQRS este deosebit de util pentru a înțelege cum se implementează partea de performanță, fără a tot adăuga layere de tehnologie suplimentare. Eu îl apreciez și pentru separarea codului, astfel probabilitatea de a introduce buguri e mai mică.


(Cosmin Popescu) #5

Am o mica intrebare

Lucrez la o aplicatie in .net(win forms) si am o clasa care se chama “DatabaseOps” cu tot felul de metode CRUD. Ar fi ok daca as separa metodele ce tin de aducere de date din bd intr-o clasa dedicata ?

Cum ai facut aici

public class EmployeeReadService {  
    public function obtineAngajat($id) { /* ... */}  
    public function obtineAngajatiiInConcediu() { /* ... */}  
}  

// foloseste acelasi model Angajat  
public class EmployeeWriteService {  
    public function angajeaza(Persoana $persoana, $laData) { /* ... */}  
    public function promoveaza($id, $noulPost, $deLaData) { /* ... */}  
    public function maresteRemuneratia($id, $suma, $delaData) { /* ... */}  
    public function concediaza($id, $laData) { /* ... */}  
    public function modificaAdresa($id, Adresa $adresa) { /* ... */}  
}


(Serghei Amelian) #6

CQRS e un concept cam bizar şi nu cred că ar trebui folosit doar ca să te afli în treabă :slight_smile: Dar nici să ai o clasă generică de genul DatabaseOps unde să ai tot felul de metode random nu cred că e o idee prea bună.


(Cosmin Popescu) #7

Asta este problema sunt multe metode si ma incurc in ele. Am inceput-o in primavara, n-am mai facut nimic timp de 6 luni si m-am reapucat sa lucrez la ea din decembrie. Nu este complicata ca functionalitate si logica, dar incepe sa se adune cod :slight_smile:

Aici nu te pot contrazice ! :smiley:


(Serghei Amelian) #8

Dacă eşti tentat să faci o clasă cu tot felul de metode random, probabil nu ai structurat bine problema. Mie imi place să lucrez cu entităţi, de genul ăsta:

class Factura {
    public load(int id = 0);
    public save();

   std::string serie;
   int nr;
   std::string data;
   std::list<Produs> produse;
   ... alte câmpuri ...
}

Ca să decuplez partea de date de GUI de regulă folosesc adapter pattern.

PS Cred că am dat rău în offtopic, mă opresc aici :slight_smile:


(Cosmin Popescu) #9

Stai linistit. Este interesant ce ai scris(si ontopic).

Este ok sa avem discutii conexe !
:slight_smile:


(Serghei Amelian) #10

Completare, în cazul celor mai multe proiecte, CQRS este probabil ceea ce se numeşte overengineering. Eu mereu am grijă să nu fac designul mai complicat decât este necesar, din motive de “maintanbilitate” şi de multe ori din considerente practice de genul “consum de memorie” şi “timp de execuţie”. Chiar dacă RAM-ul şi capacitatea de procesare sunt ieftine în zilele noastre, clienţii (cel puţin unii dintre ei) tot vor aprecia fiecare megabyte şi fiecare milisecundă economisită.


(Cosmin Popescu) #11

Inteleg la ce te referi. Nu doresc sa schimb din temelii aplicatia dpdv arhitectural. Mai mult o organizare a codului, este ceea ce vreau sa fac. Sunt adeptul pricipiului KISS.

N-as putea sa spune ca este overengineering trecerea de la

// foloseste model Angajat  
public class EmployeeService {  
    public function obtineAngajat($id) { /* ... */}  
    public function obtineAngajatiiInConcediu() { /* ... */}  
    public function angajeaza(Persoana $persoana, $laData) { /* ... */}  
    public function promoveaza($id, $noulPost, $deLaData) { /* ... */}  
    public function maresteRemuneratia($id, $suma, $delaData) { /* ... */}  
    public function concediaza($id, $laData) { /* ... */}  
    public function modificaAdresa($id, Adresa $adresa) { /* ... */}  
}

la

// foloseste acelasi model Angajat  
public class EmployeeReadService {  
    public function obtineAngajat($id) { /* ... */}  
    public function obtineAngajatiiInConcediu() { /* ... */}  
}  

// foloseste acelasi model Angajat  
public class EmployeeWriteService {  
    public function angajeaza(Persoana $persoana, $laData) { /* ... */}  
    public function promoveaza($id, $noulPost, $deLaData) { /* ... */}  
    public function maresteRemuneratia($id, $suma, $delaData) { /* ... */}  
    public function concediaza($id, $laData) { /* ... */}  
    public function modificaAdresa($id, Adresa $adresa) { /* ... */}  
}

:slight_smile:

Nu imi place sa imi bat joc de resursele de ram si timpi de procesor. Chiar daca sunt din plin in zilele noastre.

PS: In niciun caz nu sunt adeptul overengineering - ului si. Sunt la inceput. Imi place sa invat concepte care m-ar putea ajuta pe viitor.
PPS: Daca vrei, facem topic separat !


(Serghei Amelian) #12

O să fragmentezi excesiv codul, o să ai număr dublu de clase şi fişiere…


(Silviu) #13

Sunt mai multe moduri de a rezolva o problema și acum o să copiez un fragment dintr-un blog post al lui Carlos Buenosvinos https://carlosbuenosvinos.com/event-sourcing-is-not-a-messaging-integration-pattern/:

When implementing a Bounded Context, you can use different architectural styles:
Spaghetti Architecture: I’m a Rasmus Fanboy (aka fuck phptherightway)
Framework Fanboy: I’m a Fabpot Fanboy (aka coupled to my framework)
Hexagonal Architecture: I’m an Alaistar Cokburn Fanboy (aka decoupled from my framework)
Hexagonal Architecture with CQRS: I’m an Alaistar Cokburn and Martin Fowler Fanboy (aka decoupled with performance tunnings)
Event Sourcing with CQRS: I’m a Greg Young Fanboy (aka I do not know what I’m doing)

sau mai nou prezentarea lui de la symfonycon https://www.slideshare.net/carlosbuenosvinos/a-journey-from-hexagonal-architecture-to-event-sourcing-symfonycon-cluj-2017

Acum, știm că nu exista un silver bullet și că fiecare are metoda sa de a aborda o problemă, însă cred că nu putem aborda o anumită arhitectură în afară de spaghetti/framework fără a avea mai înainte o sesiune de brainstorming între echipa tehnică: developer,tester,ux și domain experts/product owner că să putem trece dincolo de o gândire crud/structurală-relațională și să trecem spre o gândire bazată pe mesaje desfășurate în timp în domeniul respectiv.