SSTool – Headless Drupal amb React

Client
  • Omitsis
Technologies
Date
  • 12/05/2022

Des de Adevinta Spain ens van demanar, al departament de Drupal d’Omitsis, que milloréssim la seva eina d’autoavaluació d’equips (Self Sufficient Teams o SST). Adevinta és la super empresa que gestiona els marketplaces Fotocasa, habitaclia, InfoJobs, coches.net, motos.net i Milanuncios, cadascun d’ells amb milions de visites. Són uns mega cracks, molt professionals i a més molt macos.

L’eina estava a WordPress i els havia servit molt bé, però necessitaven aplicar algunes millores. En avaluar-les, tots dos vam veure que la millor solució era crear un backend amb Drupal 9 i un frontend amb React. És a dir, un Headless Drupal amb React.

Un dels avantatges és que ells, sent experts en react, podrien involucrar-se en el desenvolupament del frontend en qualsevol moment. Evidentment, un altre gran avantatge en usar React era que el frontend podia ser més dinàmic, amb canvis instantanis a les accions de l’usuari.

I Drupal, com a backend, està més que demostrat que és robust i alhora flexible a les necessitats del projecte.

A més, en ser programari lliure no és necessari pagar unes quotes mensuals per les llicències d’ús com altres CMS propietaris (Adobe Experience Cloud, Liferay, Contentful, etc)

L’eina

Com a resum ràpid del funcionament de l’eina, podem dir que es tracta d’una sèrie de tests d’autoavaluació. Cada test consisteix en una sèrie de preguntes agrupades.

Els usuaris poden contestar sí o no a una pregunta, i posar un comentari. Segons contestin, se’ls atorga una puntuació per grup de preguntes i una puntuació final.

Per poder millorar com a equip es poden crear accions, coses que l’equip pensa els ajudarà a passar del no al sí, i es compromet a fer.

El backend: Headless Drupal 9

Com ja hem comentat per al backend vam usar la darrera versió de Drupal 9 amb les següents característiques especials:

Entitats personalitzades

En lloc d’usar bundles de nodes (tipus de contingut), vam veure que tenia més sentit crear entitats personalitzades per a cadascuna de les estructures requerides per a la nostra aplicació. Aquesta necessitava unes especificacions molt concretes, com la possibilitat de poder crear noves plantilles de tests, sense modificar els tests passats.

Migració des de WordPress a Drupal 9

Com sempre des d’Omitsis encarem una migració usant el fantàstic mòdul migrate. Per això, es va crear un source plugin per a cada entitat a migrar, més uns quants process plugins, per poder transformar les dades de WordPress en la forma que Drupal les necessita.

JSON:API

Per poder passar informació entre el frontend i el backend vam usar JSON:API, ja al core de Drupal des de fa un temps.

En JSON:API s’envia el que són camps referenciats en un array diferent de l’array retornat de les dades de l’entitat sol·licitada. Posem que faig una petició d’una entitat anomenada recepta i aquesta té camps d’ingredients.

Quan li diem a JSON:API que inclogui la informació dels ingredients, no ho fa dins de cada recepta, ja que si tenim mil receptes i la gran majoria contenen l’ingredient ceba, ens inclouria moltes vegades la informació completa de la ceba.

En lloc d’això, s’inclou una referència (un id) a l’entitat ceba, però els camps de la ceba estan en un array d’includes i, per tant, només hi serà una vegada, i ocuparà molt menys.

Però això és molt poc pràctic quan s’obté al React, ja que per a cada entitat cal buscar totes les seves entitats niades, i més si hi ha més d’un nivell.

Per a això existeix el mòdul JSON:API Include però, després d’avaluar-lo, el vam desestimar perquè feia que les nostres peticions, amb l’arquitectura niada que teníem, fossin massa pesades.

En lloc d’això, vam veure molt més eficient fer el mateix procés en client amb el paquet jsona. Així, teníem peticions més lleugeres i en React una estructura de dades molt més pràctica.

A més, per millorar el rendiment de les peticions, sempre que va ser possible vam unir totes les peticions en una, estalviant-nos el cost de la capa de xarxa de cada petició. Per a això, existeix l’excel·lent mòdul subrequests, molt ben explicat aquí per Mateu, el seu autor.També vam usar Open API, perquè l’equip de frontend tingués molt clar i fàcil conèixer tots els endpoints de JSON:API, filtres, etc.

Administració del backend

Per facilitar l’administració al backend es va usar el tema Gin, juntament amb la Gin toolbar. També es va crear un simple dashboard amb els accessos directes més importants.

A més, es va tenir especial cura amb els llistats i els formularis de les entitats, perquè fossin el més usables possibles. I amb l’ajuda del mòdul Corresponding Entity References es va facilitar crear referències creuades, tan sols editant des d’una part.

Adevinta ens va demanar que, per accedir al backend i al frontend, es pogués fer mitjançant Okta. Per gestionar el SSO (single sign on) amb Okta al backend vam usar el mòdul SAML SP 2.0 Single Sign On (SSO) – SAML Service Provider

Exportacions de les taules de dades

Per integrar els resultats amb el seu data lake, vam crear unes exportacions en csv, que es generaven amb el cron (amb ajuda d’ ultimate cron) cada nit. Aquestes exportacions es pujaven directament a un bucket de S3 d’Adevinta, usant el mòdul S3 File System.

Frontend amb React

L’aplicació de React la vam crear usant create-react-app. En ser un frontend privat, no era necessari usar eines per crear codi estàtic o que s’executés al servidor (Server Side Rendering)

El disseny de la part pública ho va assumir el nostre fantàstic departament de disseny d’ Omitsis. Es van reunir amb el client per conèixer les seves necessitats i així poder crear els primers wireframes.

Wireframe de la pàgina principal, on es mostra el llistat d’equips.

Pàgina d’un equip, amb les seves avaluacions i accions.

Wireframe d’una avaluació, amb els grups de preguntes i els seus resultats.

Wireframe d’una avaluació, amb zoom a la part d’una pregunta.

Un cop creats i validats, es va crear el disseny de cada pàgina, usant el design system d’Adevinta:

Adevinta design system

Disseny de la pàgina d’equips

Disseny de la pàgina d’un equip

Disseny de la pàgina d’una avaluació

Disseny de la pàgina d’una avaluació, zoom en una pregunta

Millores de performance del frontend en React

Per aconseguir que tot funcionés de la manera més fluida es va tenir en compte els aspectes següents:

Minimitzar peticions

Millor sempre dues peticions que tres, i una encara millor que dues. Gràcies a JSON:API pots incloure tota la informació que necessites en una sola petició: l’entitat, les entitats relacionades i les relacionades de les relacionades. Així, fins al nivell que vulguem.

Incloure només el necessari al JSON:API

Relacionat amb l’assumpte anterior, si afegim moltes entitats relacionades amb tots els seus camps, podem trobar-nos amb una consulta interna molt complexa. Això pot fer que necessiti molta memòria i que el fitxer JSON resultant sigui massa pesat.

Per evitar això, cal podar tot el que no es necessiti, usant Sparse Fieldsets que permet especificar quins camps volem que retorni de cada entitat.

Agrupar peticions

Com ja hem comentat abans, vam usar profusament el mòdul subrequests per agrupar més d’una petició, quan és possible. Així ens estalviem el temps de la capa de xarxa.

No usar JSON:API Include

També com hem comentat abans, en el nostre cas usar JSON:API Include no era una bona idea, ja que podíem tenir peticions que retornaven json massa grans (> a 1MB).

Vam instal·lar el paquet jsona i tan sols fent això:

import Jsona from 'jsona';
const dataFormatter = new Jsona();

Converteix el json que obtenim del JSON:API en un més amable per al programador.

const json = {
    data: {
          type: 'town',
          id: '123',
          attributes: {
              name: 'Barcelona'
          },
          relationships: {
              country: {
                  data: {
                      type: 'country',
                      id: '32'
                  }
              }
          }
    },
    included: [{
        type: 'country',
        id: '32',
        attributes: {
            name: 'Spain'
        }
    }]
};

const town = dataFormatter.deserialize(json);
console.log(town); // will output:
/* {
    type: 'town',
    id: '123',
    name: 'Barcelona',
    country: {
        type: 'country',
        id: '32',
        name: 'Spain'
    },
    relationshipNames: ['country']
} */

Skeleton

En lloc de mostrar loaders, vam pensar que era millor usar un skeleton mentre es carreguen les dades. Això és quasi ja un estàndard a la indústria, ja que el rendiment percebut per l’usuari és major.

Single Sing On amb Okta

Per accedir al frontend era necessari que els usuaris ho fessin validant-se amb Okta. Per aconseguir això, vam usar el paquet Okta React i Okta Auth js.

Els usuaris en entrar al lloc, si no estaven autentificats, eren redirigits al login d’Okta d’Adevinta.

Integració contínua amb amazon

Usant Elastic Beanstalk, CodePipeline, EC2 i CloudWatch d’Amazon, el nostre departament de sistemes va crear un procés d’integració contínua.

Amb CodePipeline s’«escolta» a canvis a les branques del repositori: master per a l’entorn de producció, staging per a l’entorn de staging. Quan veu que hi ha un canvi, fa un nou deploy usant Elastic Beanstalk.

Llavors Elastic Beanstalk s’encarrega de crear una nova instància d’EC2, fa els tests necessaris i si tot va bé, la intercanvia per l’anterior. Si no passa els tests, no la reemplaça i l’elimina.

Conclusió

Tenim molta experiència creant projectes de gran qualitat, centrats en l’usuari, amb Drupal i React, però aquest projecte ens va agradar especialment.

Per ser un gran exemple de Headless Drupal amb React i perquè treballar amb Adevinta Spain és un plaer: són accessibles, van saber crear unes excel·lents especificacions, ràpids, tenen recursos i són molt bona gent.

JU

julia

manager

Recent Posts