dukai.net
2017-09-08 · 10 min

Döntéshozatali folyamat isomorphic webalkalmazások tervezésénél

Miért élik túl a minimalista, nem-véleményes framework-ök az éppen divatos versenytársaikat - útmutató fejlesztőknek és architecteknek.


Miért

A tervezési és választási megfontolásaim évek alatt formálódtak nagy, komplex, UI-intenzív alkalmazások és iparági best practice-ek körüli munkán keresztül. Az alábbi gondolatcsokor azt magyarázza, miért volt értelme bizonyos döntéseknek a maguk idejében, és minden szempontot előtérbe hoz, ami szoftverarchitektúra-szempontból fontos. Ez egy útmutató fejlesztőknek és architecteknek, hogy megértsék az adott választásokat és preferenciákat. Egyúttal bemutatja a megfelelő naming convention-ök szervezőelvként betöltött fontosságát is.

Elvárások és követelmények

  • A termék egy már létező korábbi rendszert vált le, amely nagy komplexitású (sok üzleti tartalom) és különféle konfigurációkkal (termékszintű csomagajánlatokkal) rendelkezik.
  • Hosszú élettartamra szánjuk; a karbantarthatóság minden fölött áll.
  • Több csapat dolgozik majd a terméken, így intenzív párhuzamos fejlesztés várható.
  • Az új szoftver mobile-first (responsive UI), így a magas teljesítmény és a gyors válaszidő minden fölött áll.
  • A teszt területe legyen maximális, és terjedjen ki vizuális és nem-vizuális komponensekre is.

Általános megfontolások és framework-ök

Elfogulatlan, véleménymentes minimalista framework (jellemzően vanilla, elnevezési konvenciókkal)

A framework-ök általában több különböző csoportra oszthatók:

A véleményes (elfogult) framework-ök beégetik a fejlesztési mintákat a kódba, és arra kényszerítik a fejlesztőket, hogy ezeket kövessék. Általában a fejlesztési minták jók - összehangoltságot biztosítanak, és lehetővé teszik, hogy a kevésbé tapasztalt fejlesztők is követni tudják őket. De abban a pillanatban, amikor egy valós helyzet már nem fér bele az előre definiált mintába, a fejlesztők elkezdenek a framework ellen küzdeni, ami késlelteti az implementációt, rontja a kódminőséget (csúnya hekkelések), és a végterméket is megviseli. Az erősen véleményes framework-öket olyan csapatok kedvelik, amelyek végterméke nem feltétlenül igényel magas minőséget (kis cégeknek készülő szerződéses munkák, generic weboldalak), vagy ahol kevés senior fejlesztőnek nagyszámú tapasztalatlan vagy junior fejlesztővel kell dolgoznia (kizsákmányoló minta). Tipikus példák: Ruby on Rails, AngularJS, React.

A véleménymentes framework-ök specifikus problématerületeken segítenek anélkül, hogy belső alkalmazásstruktúrát kényszerítenének rád. Kínálhatnak hasznos fejlesztési mintákat, de sohasem erőltetik őket. A fejlesztők gyorsan építhetnek ott, ahol a mintázat illik a követelményekhez, és tisztán kiléphetnek belőle, amikor egy kivétel jelentkezik. Tapasztalatom szerint egy alkalmazás kb. 60%-a követ egyetlen mintát, a maradék pedig így vagy úgy megtöri azt - miközben teljesen valós üzleti igényeket képvisel. Ez a fejlesztési stílus a jó architektúra-döntésekre, fejlesztői tudásra és fegyelemre épít. Tipikus példák: Hapi.js, Dust.js, Gulp.js.

A minimalista vagy vanilla implementációk csökkentik a tudást, ami egy projekthez való csatlakozáshoz kell - a framework könnyű marad, és példákra meg elnevezési konvenciókra épít a struktúra szervezésénél, nem pedig homályos API-kra. Az ember nagyon jó a mintafelismerésben, de a memóriája a nagy API-kra korlátozott. Az általános szabály: a legjobb architektúra-döntés mindent olyan egyszerűen tartani, amennyire csak lehet (még ha ennek nehéz is ellenállni!). A minimalizmus nem azt jelenti, hogy minden third-party könyvtárat száműzünk; csak az érvénytelen indoklásokat utasítja el - például hogy valami azért kerül be, mert “menő”, vagy egy jelentéktelen megoldás kedvéért. Ez a megközelítés az olvashatóságot és a karbantarthatóságot helyezi a középpontba. (Egy alkalmazás életciklusának kevesebb mint 3–5%-a a megírása, több mint 95%-a a karbantartása.)

Izomorfikus webalkalmazások

Mindkét oldal JavaScript-ben íródik: a szerver oldal a Hapi.js-t használja a nem-intruzív Dust.js view engine-nel; a kliensoldal vanilla JS-t, Bootstrapot vagy TailWind-et és ugyanazt a Dust view engine-t.

Egy klasszikus webalkalmazás-architektúrában a server side Ruby, Java, .NET, PHP stb. nyelven készült - miközben a front end mindig HTML, CSS, JavaScript volt. Ez a kettéosztás arra kényszerítette a fejlesztőket, hogy szerver-nehéz vagy kliens-nehéz megoldás között válasszanak. A szerver-nehéz hagyományosan alacsony kliens oldali minőséget és kényelmet jelentett. A kliens-nehéz megoldás pedig lassú letöltéseket, értelmezést és DOM-manipulációt. Egy kiegyensúlyozott megoldás mindig dupla implementációt jelentett, és az üzleti logika karbantartását mindkét oldalon, két különböző nyelven. A Node.js óta lehetővé váltak az izomorfikus webalkalmazások - ugyanazt a nyelvet használja mindkét oldalon, a kód jelentős része megosztható. Ez lehetővé teszi a fejlesztőknek, hogy a végrehajtást mindig a hatékonyabb oldalra optimalizálják, kódduplikáció nélkül. Olyan fejlesztőket lehet felvenni, akiknek nem kell több nyelvet tudniuk, ami szintén könnyebb. Ezekért az okokért az izomorfikus webalkalmazások jelentősen felülmúlnak minden más klasszikus típust.

Nem-intruzív view motor

A view motorok az alkalmazás adatait egyesítik a HTML markup-pal, hogy dinamikus UI-t generáljanak. Sokféle van, nagyon különböző szintaxissal, ami gyakran tükrözi az alkotók filozófiáját és a markup nyelvével kapcsolatos tudásukat. Sajnos sokuk másodrangú állampolgárként kezeli a markup-ot, és eltorzítja vagy kiegészíti a kódot. Ez betör a UX fejlesztők területére, akiknek aztán a saját oldalukon kell megküzdeniük az obfuszkálással. Az ilyen átfedés egészen kicsi full-stack csapatokban indokolható lehet; legtöbbször azonban ugyanazok a minimalista alapelvek vonatkoznak rá, amiket korábban említettem, és pont annyira káros, mint a könyvtárak menőség alapján való túlhasználata.

Kettős renderelés

A magasabb performance érdekében a view-k mindkét oldalon - szerver és kliens oldalon - futtathatók. A kezdeti renderelés a szerveren történik; minden további DOM-manipuláció (részleges renderelés) a kliensen. (Google performance konferencia videó.)

A kettős renderelés jelentős teljesítménynövekedést hoz, és lehetővé teszi, hogy bármelyik erőforrást közvetlen, állandó URL-en érjük el (SEO) - például egy kapcsolati lista, vagy egy adott kapcsolati személy részletes nézete.

View modellek

A view modellek tartalmazzák a nézethez kapcsolódó logikát (transzformáció, renderelés, konfigurációs opciók), és 100%-ban újrafelhasználódnak mindkét oldalon.

A view motor szintaxisa nem tör be a HTML domain-be és nem torzítja azt

A minimális átfedés mind a UX tervezőknek, mind a fejlesztőknek nagyobb szabadságot ad. A view-k szerver és kliens oldalon egyaránt újrafelhasználhatók. Az intruzív view-motor framework-ök utasításokat injektálnak a DOM-ba (AngularJS, Knockout), és a rendereléshez szükséges kapcsolati információkat speciális HTML tag-ekben tárolják. A tag-ek gyakran tartalmaznak JavaScript kódot is, ami megnyitja az utat komplex feltételek markup-ba ágyazásához. Ez rossz gyakorlat - az üzleti logika egy része elválik a többitől, ami a debug-olást és a karbantartást sokkal nehezebbé teszi. A React pont ugyanazt teszi csak az ellenkező irányból: a HTML szétszabdalva, eltorzitva kerül be a Javascript kódok közé.

Szerver oldali unit tesztek minden modellhez és minden további üzleti logikai darabhoz (100% lefedése a kódnak)

Lab.js, Mocha vagy Chai. A tesztelés mindkét oldalon kötelező. A szerver-oldali kódot általában egyszerűbb tesztelni, mint a kliens oldalit, ahol a logika összegabalyodik a UI viselkedésével (a Cucumber-stílusú framework-ök user interakciót szimulálnak, és sosem izolálnak igazán egyetlen logika-darabot). Izomorfikus alkalmazásokban a view modellek, amelyek a transzformációs logika nagy részét tartalmazzák, egyszerű szerver oldali unit tesztekkel tesztelhetőek.

UI tesztelés teszt hámmal

Egyedi elemek izolálása csökkenti a tesztelés komplexitását. A teszt hámmal a UX tervezőket és fejlesztőket is segítik kisebb komponensekkel dolgozni, a QA pedig egyszerűsített, izolált use case-eket tesztelhet.

A UX tervezők általában HTML szimulációkat készítenek a UED dizájn alapján. Egy intruder-stílusú view motor esetén ezeket a szimulációkat a fejlesztők szétszedik és eltorzítják. Ez mindkét oldal számára sokkal több munkát ad. A Dust.js nem torzítja a HTML-t - a készített lapokat közvetlenül lehet használni. Minden vizuális komponenshez biztosíthatunk vizuális teszt hámot, amely részleges UI elemeket jelenít meg és tesz manipulálhatóvá. Ez megszünteti a kétfázisú UI dizájn szétválását. A termékmenedzserek és koncepció-tervezők sokkal gyorsabban tudnak véleményezni ilyen komponenst, a fejlesztők pedig anélkül hozzáadhatják a logikájukat, hogy szétdúlnák az eredeti tervet. Ettől a pillanattól külső függőségek nélkül lehet valós adatbeillesztést és szélsőséges eseteket vizsgálni, ami nagy mértékben növeli az iteráció és a validáció sebességét - miközben a JavaScript és a HTML tisztán elkülönül egymástól.

Teljes validáció Joi-val (a Hapi részeként)

A szerver-oldali kód egyszerűsítésének remek módja, ha a lehető legtöbb input változót validáljuk és default értékkel látjuk el. Ekkor a mélyebb kódrészek elkerülhetik a szétszórt paraméterellenőrzéseket. A Joi pontosan ezt biztosítja. A validációs sémák nem kötődnek az endpoint-jaikhoz - központi tárolás is lehetséges, és ugyanazok a schema-k unit tesztekben is felhasználhatók.

Modulszeparáció elnevezési konvenciókra alapozva, egyetlen építési folyamat Gulp-pal

A teljesítmény érdekében minden, a kliensre letöltött erőforrást összevonunk: CSS, JavaScript, kliens oldali view-k. Sok eszköz létezik (webpack stb.). Közülük sok ismét elhomályosítja a folyamatot, és nehezíti a speciális szabályok és kivételek kezelését. Gulp is a véleménymentes, minimalista megközelítést követi, így tökéletesen igazítható a saját igényeinkhez (plugin-okhoz tartozó elnevezési konvenciók, finom ellenőrzést ad az erőforrások kezelése felett).


- Tamara Dukai