În trecut software-ul era scris sub forma unei singure componente, ca un tot unitar, cu toate mecanismele interne la un loc, cu foarte mici excepții.
Acest tip de arhitectură se numește în prezent “monolit” și nu se mai folosește în dezvoltarea de sisteme noi din mai multe motive:
- Mentenabilitate și scalabilitate scăzute (e complicat de modificat și ajustat pentru un număr mare de utilizatori)
- Performanță în general mai slabă
- Proces greoi de dezvoltare atunci când sistemul crește foarte mult
Dacă vei avea ocazia să atingi codul unor sisteme scrise în urmă cu câteva zeci de ani sunt șanse mari ca arhitectura lor să fie monolit.
Tot codul, front-end, back-end și între cele două va fi consolidat în același proiect cu complexitate extrem de mare.
De multe ori genul ăsta de proiect e complicat de configurat încă din faza de dezvoltare, încât să-l faci să se compileze pe mașina locală și să-l pornești în debuger.
Nu mai vorbim de făcut modificări în codul existent sau adăugat componente noi.
REST: arhitectura aplicațiilor moderne
REST sau RESTful e un tip de design arhitectural, nu mai intrăm în detaliile istorice legate de cum a apărut, pentru că am vorbit deja despre asta în articolul de aici.
Plec de la premisa că înțelegi deja conceptul de API (Application Programming Interface), dacă nu, citește întâi articolul anterior menționat.
În articolul respectiv am enumerat o serie de criterii pe care ar trebui să le respecte o aplicație back-end pentru a fi cu adevărat RESTful, dar în articolul prezent vreau să ne uităm într-un mod puțin mai pragmatic la ideile astea și să vedem cum putem să implementăm un sistem RESTful fără să ne ascundem după concepte teoretice complicate.
Pe parcursul carierei tale de dezvoltator software vei vedea multe proiecte ce se pretează a fi RESTful APIs, dar 99% din ele nu sunt. Deloc. Nu au nicio treabă.
Vei lucra în echipe care-ți vor spune că dezvoltă aplicații REST, dar în realitate sunt doar servicii web ce comunică prin JSON, fără nicio legătură cu principiile REST.
Denumirea de REST API a ajuns mai degrabă să fie folosită ca opus pentru un serviciu de tip SOAP.
Serviciile SOAP se foloseau în trecut, atunci când s-au făcut primii pași la tipul de arhitectură client - server, care reprezintă și una din constrângerile REST, dar revenim imediat la asta.
Serviciile SOAP funcționau tot pe bază de comunicare HTTP, dar schimbul de date se făcea diferit și structura folosită era XML, nu JSON.
SOAP e, în schimb, mai degrabă un protocol decât un stil arhitectural, dar nu mai intrăm în detalii acum.
Cert e că multe servicii care se recomandă a fi REST, sunt defapt dezvoltate după același șablon cu cele SOAP, dar cu comunicare JSON în schimb.
Cum faci o aplicație RESTful
Unul din principalele criterii ca o aplicație back-end să poată fi încadrată ca RESTful, e aceea de a respecta principiul client - server.
Dar după cum am văzut, ăsta e un principiu care prinsese deja formă cu ceva timp înainte de apariția REST, încă de pe vremea serviciilor SOAP.
Așa că aici, în general, nu trebuie să ne facem griji, criteriul ăsta e acoperit în mod implicit.
De asemenea, dacă ești deja familiar cu constrângerile ce stau la baza arhitecturii REST, vei vedea că o parte din ele sunt, fie un pic abstracte, fie nu au neapărat sens.
Cel mai improtant principiu, și cel care nu este respectat de către cele mai multe echipe de dezvoltatori, e cel al interfeței uniforme, adică mai simplu spus, la modul cum sunt definite resursele și implicit definirea URL-urilor spre acestea.
Termenul de “resurse” este iarăși unul care poate aduce confuzie, însă el înseamnă tipuri de “entități” din baza de date.
Modul cum îți definești aceste entități nu e important, dar ele reprezintă “tipuri de date” existente în contextul aplicației tale.
Hai să dau niște exemple, ca să nu fiu și eu tot abstract.
În cazul unui magazin online, să spunem, resursele pot fi:
- Produse (Products)
- Utilizatori (Users)
- Comenzi (Orders)
- Plăți (Payments)
- ș.a.
Aplicația client trebuie să manipuleze aceste resurse pe măsură ce utilizatorii interacționează cu ea.
Adică trebuie să: adauge, modifice, creeze sau să șteargă din colecțiile de date pentru aceste resurse (adică tabele într-o bază de date relațională, de cele mai multe ori).
Reprezentarea acestor resurse pe interfața publică a aplicației trebuie făcută cu un pic de atenție și ai obținut deja 95% dintr-un REST API.
Uite câteva exemple:
Observi cum am folosit peste tot termenul pentru resursa respectivă la plural (products), un aspect care nu trebuie neglijat.
De asemenea, folosirea metodelor HTTP într-un mod extrem de specific: GET pentru citire, POST pentru creare, DELETE pentru ștergere și PUT pentru actualizare.
Aici nu există loc de interpretare, altfel ceea ce ai nu este o aplicație REST.
Astea sunt niște exemple mai simple, dar să spunem că ai și situații în care o resursă nu poate exista independentă, ci este să spunem, o “sub-resursă” a altei resurse.
Ruta de mai sus se citește astfel: plățile comenzii cu ID-ul 1.
Pentru identificarea unei resurse anume nu se poate folosi altceva decât un identificator unic, nu alte tipuri de câmpuri, cum ar fi dată sau orice altceva mai poate avea resursa respectivă.
În cazul de mai sus, vor fi returnate toate plățile comenzii respective.
Dacă vrem, de exemplu, să filtrăm pe colecția de sub-resurse după alte câmpuri decât identificatorul unic, putem să o facem astfel:
În răspuns va trebui să întoarcem produsul din comanda cu ID-ul 1 al cărui câmp denumit name are valoarea phone.
sau chiar să filtrăm și sub-resursa după ID:
În acest caz, în răspuns ar trebui să întoarcem produsul cu ID-ul 13 din comanda cu ID-ul 1.
Dacă respecți aceste convenții și îți structurezi resursele aplicației astfel vei fi mult mai “RESTful” decât ceea ce fac multe echipe de dezvoltare la ora actuală în industrie.
Ca să fiu și mai clar, modul în care îți structurezi baza de date nu are nicio legătură cu definirea resurselor. Acolo ai mână liberă să faci ce vrei, atâta timp cât interfața publică este definită după regulile descrise.
Mulți oameni, chiar și cei cu ceva experiență, nu fac altceva decât să “trântească” niște endpoint-uri la întâmplare cărora le spun REST și cam atât.
Concluzie
Convențiile definite de arhitectura REST permite aplicațiilor de back-end să comunice într-o manieră cât mai uniformă, fără particularități greu de înțeles și tratat.
Altfel, dacă fiecare își implementează propriile reguli, va fi greu să “comunice” eficient cu alții.
Așa cum, și noi oamenii, ne folosim de gramatică și vocabular pentru a defini o limbă (română, în cazul nostru) pe care o folosim toți pentru a comunica între noi.
Dacă fiecare și-ar inventa propria limbă cred că ne-ar fi mai greu să vorbim între noi, nu-i așa?
Sunt multe de discutat în ceea ce privește implementarea conceptelor REST într-o aplicație, dar consider că principiul descris anterior reprezintă cam 95% din ceea ce înseamnă REST (și partea unde se greșește cel mai des), pentru că o parte din celelalte principii vin de multe ori natural.
Atât pentru azi, pe data viitoare.
