ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 150
Numărul 149 Numărul 148 Numărul 147 Numărul 146 Numărul 145 Numărul 144 Numărul 143 Numărul 142 Numărul 141 Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 8
Abonament PDF

Probleme arhitecturale în proiecte Liferay

Alexandra Coldea
Java Developer
@ISDC



PROGRAMARE


Într-un mediu de afaceri din ce în ce mai agile, cu tot mai multe companii care concurează pentru aceeaşi cotă de piaţă, posibilitatea de a dezvolta aplicaţii cu multe funcţionalităţi "out of the box", Liferay este un framework cel puţin interesant.

Acest articol analizează probleme arhitecturale care trebuie adresate la începutul proiectului pentru a obţine un produs flexibil fără ajustări majore ulterioare.

Cu Liferay sau fără Liferay

Liferay este un portal open source sub licență GPL, pentru aplicații enterprise. Vine împreună cu multe funcționalități personalizabile: user management, multi-tennant și multi-language, CMS, integrare cu motoare de reguli ("rule engine"), cu motoare de căutare și multe altele "out of the box".Funcționeză pe o serie de application servers (printre care JBoss, GlassFish), servlet containers (Tomcat, Jetty, Resin) și cu multe DBMS-uri. Poate fi deployat în cloud.

Înainte de începerea oricărui proiect trebuie pusă întrebarea: este într-adevăr nevoie de Liferay? Astfel, dacă e nevoie de un portal complex, o aplicaţie care administrează conţinut mult atunci se potriveşte. Dacă aplicaţia este mare ca dimensiune, dar nu e orientată spre conţinut ("content-centric"), Liferay poate să fie util, dar nu e recomandabil. În schimb, dacă aplicaţia este simplă şi manipulează conţinut puţin, atunci Liferay adaugă prea multă complexitate. Trebuie să se ţină cont şi de faptul că Liferay este un container de portleţi şi nu merită să se folosească pentru aplicaţii web clasice.

Service Builder sau Layer de servicii propriu

Service Builder-ul este un tool dezvoltat de Liferay pentru a automatiza crearea interfeţelor şi claselor folosite de portal și portleţi pentru layer-ele de servicii și acces la date. Se generează codul pentru bean-uri, Persistenţa, Model şi mapările de Spring. Acesta este tool-ul folosit şi de developeri Liferay pentru a genera serviciile din Liferay core. De aceea, a fost îndelung testat şi problemele rezolvate sau cel puţin identificate. Problemele găsite sunt logate în Jira și sunt publice: http://issues.liferay.com/browse/LPS. Service Builder-ul asigură tranzacționalitatea serviciilor, are un mecanism de clustering și chiar oferă posibilitatea de a internaționaliza orice entitate cu efort minim.

Totuşi, din punctul de vedere al documentaţiei, Service Builderul beneficiază doar de o pagină de wiki care nu este foarte detaliată. Aceasta înseamnă că, dacă nu întelegi exact ce fac anumite atribute, trebuie să investighezi codul generat pentru a anticipa cum se va comporta. De obicei, nevoia pentru aceste investigații nu poate fi identificată decât în timpul implementării și aceasta înseamnă întârzieri neprevăzute. În schimb, există training-uri organizate de Liferay unde se pot acumula cunoştinţele necesare.

Pe de altă parte, se poate opta pentru dezvoltarea unui layer de servicii propriu. Avantajul este deţinerea controlului complet asupra codului scris şi posibilitatea definirii documentaţiei proprii. Însă, overhead-ul de a defini două layere - persistență şi servicii - cu interfeţele şi nivelul de abstractizare oferit de Service Builder este foarte mare. Astfel, timpul de implementare și livrare ("time to market") va fi foarte ridicat.

Totuşi, există unele cazuri în care Service Builder-ul nu este necesar. De exemplu dacă se comunică cu un sistem 3rd party care administrează datele și expune servicii, va fi nevoie doar de apelarea lor.

În continuare vom discuta despre proiecte în care se folosește Service Builder-ul.

Decuplarea componentelor aplicaţiei

Ca în orice arhitectură pe layere, componentele trebuie menținute separate, dar decizia asupra nivelului de granularitate la care se separă în artefacte trebuie cântărită cu atenţie pentru că poate aduce o penalizare de performanţă sau poate face codul greu de înteles și menținut.

Figura 1 prezintă împarţirea logică a componentelor dintr-un proiect de Liferay. În mod implicit, Service Builder-ul generează api-ul separat de implementare, într-un folder din WEBINF. Aceasta este modalitatea Ant de structurare a proiectului. Modalitatea Maven este de a-l genera într-un modul separat.

Cât despre împachetarea componentelor, există mai multe modalităti de a face acest lucru, în funcţie de necesităţile proiectului. Pentru cel mai simplu proiect, este suficient să se împacheteze api-ul într-un jar şi portleţii împreună cu implementarea într-un war. Avantajul acestei soluţii e că odată ce contractul e definit implementarea se poate schimba şi i se poate face hot deploy. Teoretic, se poate modifica logica de business şi serverul nu trebuie oprit pentru a avea soluţia în producţie. Dar, din păcate, în practică de foarte puţine ori se va întampla să lucrezi un sprint la servicii şi să nu modifici ceva din interfată. Hot deploy-ul este mai mult pentru hot fixes.

Pentru a pastra un "separation of concerns" şi a creşte nivelul de izolare, se poate ca implementarea serviciilor să constituie un modul separat şi să fie deployat ca un jar, aşa cum e prezentat în Figura 2. Aceasta ar însemna că, dacă la un moment dat clientul se hotărăşte că doreste să stocheze datele într-un mod diferit, trebuie doar înlocuit modulul de implementare. Dezavantajul este că deploy-ul durează mai mult, fapt care se simte mai ales în timpul development-ului.

Din acest punct de vedere, dacă proiectul este unul mare şi foarte agil, cu un client imprevizibil, cea mai bună soluţie ar fi să se separe implementarea serviciilor într-un modul diferit de la început, dar se renunță la posibilitatea de a deploya hot fixes pe servicii. Pentru development se poate folosi o configurare asemănătoare cu cea din Figura 3, în care acest modul e împachetat împreună cu portleţii într-un war şi astfel se poate face hot deploy şi nu se crează overhead pentru asta.

Un alt aspect care diferă de la proiect la proiect este modul în care portleţii sunt separaţi în plugin-uri. Variaţiile sunt foarte mari: în unul dintre proiectele pe care am lucrat, se folosea un plugin per portlet, pe când în altul exista un singur plug-in pentru toţi portleţii. Fiecare abordare are avantajele şi dezavantajele ei. În prima este foarte uşor să controlezi ce funcţionalităţi pui la dispozitie unui tenant, dar deployul durează mult şi comunicarea inter-pluginuri poate fi costisitoare. A doua este o variantă mai rapidă, tot business-ul fiind la un loc. Dar aceasta din urmă este avantajoasă numai până la un anumit număr de portleți.

Decizia depinde de necesităţile clientului și dimensiunea proiectului. Când aceasta din urmă începe să crească, funcţionalităţile care au o legătură logică sau au sens împreună pentru business, ar trebui să fie grupate în acelaşi plugin. Chiar dacă la începutul proiectului totul este dezvoltat împreună, este posibil ca la un moment dat clientul să vrea să pună la dispoziţie diverşilor tenanţi funcţionalităţi diferite.

Interacţiunea dintre componente

O problemă care de cele mai multe ori se pune prea târziu este standardizarea la nivel de proiect a comunicării dintre componente.

Liferay urmărește un Model Driven Architecture, unde Service Builderul acţionează ca un Model Driven Transformation Tool. Deci, layer-ul de servicii este cel responsabil cu transformarea entităților de back-end în entităţi care pot fi folosite de layer-ul de portleţi. Dar, la fel ca portleţii, serviciile pentru entităţile care au valoare de business împreună ar trebui grupate şi aceste grupuri să fie izolate unele de altele. Aceasta pentru că se poate decide la un moment dat că anumite funcţionalităţi trebuie mutate pe un complet alt environment. De exemplu, într-o aplicaţie care se ocupă cu managementul studenţilor, toate informaţiile referitoare la notele de la examene trebuie mutate într-un "trust center" din motive legale.

În aceste condiţii, pentru a face legătura dintre prezentare şi back-end, avem nevoie de servicii compuse, numite wrappere. Figura 4 prezintă această arhitectură. Comunicarea dintre nivelul de wrappere si nivelul portleţilor se face folosind DTO-uri sau business objects. Layer-ul de servicii expune entităţi de Service Builder şi toate operatiile pe care le face sunt atomice, pentru că totul e într-o tranzacţie. De aceea, nivelul de granularitate la care serviciile se împart în unităţi funcţionale trebuie cântărit cu grijă pentru a nu scoate din tranzacţii operaţii care ar trebui să fie atomice (ex. ștergerea unui student separată de ştergerea notelor lui). Mai mult, clientul poate să decidă că doreşte să îşi expună business-ul ca un serviciu (Software as a Service). Dacă proiectul e modularizat eficient, logica de business pentru o funcţionalitate e centralizată, această schimbare ar trebui să fie simplă, pentru că Service Builder-ul oferă posibilitatea de a expune servicii REST sau SOAP doar scriind o implementare în layer-ul de servicii. În schimb, dacă layerul cu wrapper-ul este cel care asigură consistenţa bazei de date, trecerea va fi una dureroasă.

Concluzii

În concluzie, nu există un mod standard de a structura o aplicaţie Liferay, există doar o serie de întrebări care trebuie puse la începutul fiecărui proiect. Cu cât aceste întrebări care standardizează modalităţile de lucru sunt puse mai târziu, cu atât refactorizarea pentru a avea un proiect consistent va fi mai costisitoare, flexibilitatea şi extensibilitatea vor fi afectate.

NUMĂRUL 149 - Development with AI

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • Colors in projects