Odată cu ascensiunea web-ului ca platformă de programare, în aplicațiile web au fost implementate o serie de metode de proiectare începând cu MVC, MVVM și ajungând la legături de date în UI, stocarea centralizată a stării și GraphQL. Dar ceea ce devine o tendință majoră în dezvoltarea software este abordarea centrată pe date de a descrie o aplicație.
Aplicația sunt datele
o aplicație provine dintr-un cod stocat ce poate fi privit drept configurația ei inițială. Insulele de cod programabil convertite în format executabil pot fi privite ca insule de date imuabile ce dau naștere la programul propriu-zis. Variabilele și zonele alocate de memorie pot fi privite ca insule mutabile de date ce sunt vizitate și transformate de semnalul care e aplicația ce rulează. Mai mult, o aplicație poate avea un set de date de configurare ce sunt stocate ca o configurație arborescentă care este de asemenea aproape statică în comparație cu programul ce rulează.
Separarea și structurarea datelor mutabile și imuabile reprezintă cheia pentru construirea unei soluții durabile ce poate fi scalată și se adaptează în timp.
Aplicația e business-ul
Separarea datelor utile face parte din domeniul proiectării arhitecturii aplicațiilor curente. Pentru o aplicație pe platforma web, această arhitectură e modelul client-server cu împărțirea aplicației în UI, programul de pe server și centrul de date. De obicei, modelul de date de la ultima parte este transmis primelor două părți, ce sun structurate de cele mai multe ori ținând cont de metode de separare a preocupărilor precum MVC sau MVVM. Dar, după cum vom demonstra mai jos, adevărata aplicație e partea de procesare de pe server pe care o mai putem numi logica de business. De asemenea, canalul de comunicare dintre secțiunile client și server poate fi la distanță, local sau direct, ultimul caz descriind aplicațiile clasice precum cele desktop ce vor fi puternic ajutate de arhitectura propusă.
Cele 3 modele de date
Să presupunem că ambele canale de schimb de date de la UI la logica de business și de la logica de business la serviciul de persistență folosesc mesageria JSON. Fiecare mesaj JSON, fie trimis sau recepționat, poate avea mai multe tipuri de insule de date cum ar fi: conținut, validare și erori, parametrii interogării ș.a.m.d.. aceste structuri de date pot fi ajustate să corespundă schemei JSON ce descrie modelul de date al aplicației, a se vedea de exemplu abordarea GraphQL. Ce-ar fi dacă imediat după recepționarea unui mesaj sau chiar înainte de trimiterea lui aplicăm o transformare de date asupra insulelor sale de date, ceva mai complex sau neliniar precum o variantă XSLT pentru JSON sau mai simplu și liniar precum JUL Data Mapper?
Acum putem decupla modelul de date al logicii de business de celelalte două părți, interfața utilizator și nivelul de persistență și putem utiliza 3 scheme JSON pentru a descrie separat fiecare model.
De remarcat faptul că o aplicație poate avea multiple perspective UI precum web, mobil, desktop, versiune publicitară, versiune plătită, etc.. se poate conecta de asemenea la mai multe servicii de persistență precum bază de date locală sau la distanță, API cloud, serverless, etc.. avansarea versiunii modelului de date al aplicației este, de fapt, ajustarea modelului de date al logicii sale de business și nu în mod necesar a celorlalte două părți ce pot avea o structură și o denumire a câmpurilor destul de diferită. Dacă privim diversele perspective ale UI și ale serviciului de stocare drept servicii externe, devine clar aspectul că funcționalitatea aplicației ar trebui să fie concentrată în partea sa de business. Aceasta este posibil acum prin separarea celor trei modele de date pe baza transformării datelor canalelor de date JSON, vom numi codul transformării ca driver al transformării de date (DTD).
Flux de lucru
Primul pas e identificarea corectă a părții logică de business a aplicației. Această parte a aplicației are o serie de trăsături comune dar nu obligatorii sau exclusive precum: abilitatea de a servi clienți multipli în același timp, rezidă pe partea de server, externalizarea serviciilor de persistență/stocare. Caracteristica definitorie este însă, procesarea informației critice de business, proces ce include luarea automată a deciziilor, validarea datelor, tratarea erorilor, întreținere, agregarea datelor, etc..
Al doilea pas este formatarea tuturor cererilor și răspunsurilor ale fiecăreia din cele trei părți ale aplicației conform utilizării și semanticii respectivei părți, adică a schemei de date a acesteia. Ca exemplu, daca partea UI client trimite o cerere GET către logica de business, transmitem de obicei un ID al interogării și un hash cheie/valoare al parametrilor interogării vom folosi parametri interogare alfanumerici de forma ‘prop1.prop2.prop3 ‘ și vom converti hash-ul într-un obiect structurat ce corespunde schemei de date a UI utilizând o metodă simplă cum ar fi aplicarea lui JUL.ns() asupra fiecărei chei alfanumerice. Răspunsul JSON recepționat de la server va avea vectorul de articole și poate datele de validare sau de eroare structurate a se potrivi la schema de date a logicii de business și nu neapărat ca membri direcți ai obiectului rădăcină JSON.
Pasul trei constă în a determina unde să inserăm codul DTD. Pentru partea client UI,, există de obicei un canal de date JSON la distanță către punctele de conectare server ca în arhitectura API REST. Vom aplica DTD-ul la punctul de conectare client al canalului de date, chiar înainte de apelarea metodei JSON.stringify() sau imediat după metoda JSON.parse() sau a hook-urilor/callback-urilor echivalente ale acestora.
Logica de business e conectată la un serviciu de persistență/stocare via un modul ORM sau entitate-la-serviciu iar apoi, în multe cazuri, un canal de date la distanță ce poate să nu fie mesagerie JSON. ORM-ul trebuie privit ca parte a modelului de date al serviciului și trebuie să urmeze schema de date a serviciului de persistență. vom insera codul DTD ca hook-uri de transformare a datelor pe valorile argumentelor și pe valoarea răspuns/rezultat ale metodelor CRUD și altor metode ORM. Pentru cazurile î care canalul de schimb de date dintre partea de mijloc/secundă a aplicației și partea a treia a aplicației e JSON precum API web sau mesaje NoSQL, DTD-ul este situat la punctul de conectare al logicii de business cu canalul de date.
Pasul patru este organizarea codului DTD în module. Pentru UI client există de regulă un singur modul DTD bidirecțional care va fi folosit pentru a transforma mesajele JSON trimise sau primite adică cererile și răspunsurile. La logica de business, există de regulă mai multe module DTD, câte unul pentru fiecare serviciu de persistență, unele dintre ele acționând doar asupra datelor JSON recepționate. În cazuri speciale, când la serviciul de persistență este disponibilă și procesare programabilă utilizator, se poate aplica un modul DTD la acel capăt al aplicației.
Al cincilea pas este testarea end-to-end a aplicației cu modulele DTD introduse. Aceasta se face prin modificarea incrementală a structurii modelului de date al logicii de business apoi ajustând modulele DTD UI client și business-la-serviciu afectate. Ajustarea codului DTD ar trebui făcută prin configurare, lăsând intact codul principal al transformării de date ca în, de exemplu, JUL Data Mapper. Desigur, modificări structurale de date pot fi aplicate și la UI client și respectiv la serviciile de persistență, doar că într-un pas de testare separat.
Tipuri de DTD și canale de date asociate
Codul DTD poate fi rulat ca script, ca format binar sau chiar implementat în hardware. Toate aceste metode au în comun rularea transformării de date în memorie, lăsând configurabilă de către utilizator matricea de configurare a DTD sau codul său echivalent. Transformarea datelor în memorie poate fi aplicată pe orice structură arborescentă precum XML, DOM. SVG, JSON, etc. și e, în esență, limbaj-agnostică.
Un model des întâlnit de utilizare a canalelor de date este transmisia folosind o infrastructură fizică sau livrarea de informație comprimată/criptată în software. La o privire mai atentă, în toate cazurile când avem un canal de date pentru a transmite informația relevantă, avem de asemenea cel puțin un conector de date hardware sau software ce acționează asupra informației relevante, în cazul cel mai simplu ca o matrice identitate.
Vom utiliza reversul acestui model menționat anterior ca o regulă pentru a descrie arhitectura unei aplicații web: într-o aplicație, oriunde este un conector de date adică un DTD, există un canal de date.
În concluzie, tipurile de canale de date în legătură cu un DTD sunt:
- Canale de date la distanță: când cele două capete ale canalului de date se află pe sisteme/infrastructuri diferite
- Canale de date locale: când ambele capete ale canalului de date se află în același sistem
- Canale de date virtuale/directe: când introducem un conector de date într-un schimb de date în memorie sau direct, altfel nealterat
Merită menționat că, pe lângă DTD tipice unu-la-unu, pot exista DTD unu-la-mai-multe ce pot servi ca agregator de date pentru canale de date multiple. Totuși, în acest caz, va apărea problema sincronizării în timp a intrărilor de date, schimbând DTD-ul dintr-o transformare matricială liniară într-o mașină de stare. Ați putea încerca să utilizați mai multe DTD-uri unu-la-unu urmate de un modul de agregare a datelor.
Aplicații
Scenariul tipic pentru aplicarea arhitecturii propuse este inserarea DTD-urilor într-o aplicație web client-server. Fiind dată distincția clară dintre cele trei părți ale aplicației, beneficiile utilizării celor 3 modele de date sunt evidențiate anterior și se aplică aplicației instalate dar mai ales fazelor de dezvoltare inițială, mentenanță software și upgrade software a produsului.
Paleta de aplicabilitate a unui DTD e totuși mai largă și include printre altele pe cele mobile, desktop, încapsulate, VR sau de limbaj natural. Aceasta se întâmplă deoarece partea UI/UX a acestor tipuri de aplicații poate fi privită ca o perspectivă utilizator pentru accesarea și manipularea părții de business a aplicației respective. De exemplu, dacă luăm o aplicație desktop ce se conectează la o bază de date serviciu local, legăturile de date în UI urmăresc structura și denumirile din modelul bazei de date printr-un cod ORM dacă însă inserăm un DTD direct înainte de ORM, nu numai că vom putea folosi un singur cod ORM dacă elevăm conexiunea la o bază de date producție, dar putem utiliza codul de business ce controlează operațiile crud pentru un UI diferit precum o aplicație mobilă remote.
Deci, observați, cele 3 modele de date este un mod direct pentru dumneavoastră de a construi aplicații mai scalabile și mai universale.