Angular-sovelluksen arkkitehtuurissa keskeinen käsite on moduulirakenne, jossa yksi moduuli toimii juurimoduulina ja muut ovat niin kutsuttuja feature-moduuleja. Juurimoduuli on ainutlaatuinen ja vastaa sovelluksen lähtökohdasta, kun taas feature-moduulit koostuvat toiminnallisista kokonaisuuksista, jotka voidaan ladata ja ylläpitää itsenäisesti. Tämä parent/child-suhde helpottaa sovelluksen ylläpitoa, modulaarisuutta ja mahdollistaa useiden kehitystiimien työskentelyn rinnakkain ilman ristiriitoja. Feature-moduulit vaativat riippuvuuksiensa selkeän määrittelyn omissa import-, declaration- ja provider-listoissaan, mikä voi aluksi tuntua toistolta mutta on välttämätöntä sovelluksen ennustettavuuden ja riippuvuushallinnan kannalta.

Palvelut (services) ovat oletuksena singletoneja moduulitasolla, mutta niiden elinkaarta voi hallita määrittämällä ne eri injection-konteksteissa, kuten feature-moduulissa tai komponentissa. Tällöin on huomioitava, että sama palvelu useassa kontekstissa luo useita instansseja, mikä voi rikkoa riippuvuuksien hallinnan periaatteita ja johtaa epätoivottuun tilaan.

Moduulit ja niiden käyttö Angularissa voivat aluksi vaikuttaa ylimääräiseltä abstraktiokerrokselta, minkä vuoksi Angular on siirtynyt yhä enemmän kohti standalone-komponenttien käyttöä. Tämä muutos helpottaa sovellusten rakentamista ilman tarpeetonta monimutkaisuutta.

Sovelluksen suorituskyvyn ja käyttäjäkokemuksen kannalta tärkeää on myös lazy loading -periaate, joka jakaa sovelluksen feature-moduuleihin. Näin sovellus lataa vain käyttäjän nykyiseen näkymään tarvittavat osat ja hakee muut resurssit dynaamisesti tarpeen mukaan. Erityisesti mobiilikäytössä, jossa yli puolet käyttäjistä hylkää sivun jos latausaika ylittää kolme sekuntia, tämä on kriittistä.

Moduulien jakaminen voi perustua käyttäjärooleihin, jotka määrittävät käyttäjän oikeudet ja käytettävissä olevat toiminnot. Esimerkiksi data-entry -käyttäjä ei tarvitse pääsyä johtajan näkymiin, jolloin kyseiset moduulit voidaan jättää lataamatta hänen käyttökokemuksensa nopeuttamiseksi. Toinen looginen jako voi perustua liiketoimintafunktioihin, jolloin samaan moduuliin kootaan tiiviisti yhteistoiminnalliset ominaisuudet. Näin saavutetaan matala kytkentä ja korkea koheesio, jotka tukevat selkeää ja ylläpidettävää arkkitehtuuria.

Lazy loading voidaan toteuttaa myös standalone-komponenteilla, jotka eivät vaadi perinteisen Angular-sovelluksen bootstrappausta. Tämä mahdollistaa kevyemmät ja modulaarisemmat rakenteet entistä helpommin.

Tärkeä käytäntö on toteuttaa "walking skeleton" – eli sovelluksen rungon ja navigaation toimiva versio mahdollisimman aikaisessa vaiheessa. Tämä mahdollistaa käyttäjäpalautteen keräämisen ja perusvirtausten testaamisen ennen täyden toiminnallisuuden rakentamista. Se myös tukee tiimityötä, kun useat kehittäjät voivat työstää eri moduuleita rinnakkain ilman, että työn eteneminen estyy.

Tilattoman, dataohjatun suunnittelun periaate on olennainen osa skaalautuvan sovellusarkkitehtuurin rakentamista. Angularin ja sen tilanhallintaratkaisujen, kuten NgRx:n, avulla voidaan toteuttaa immuuttinen tila ja selkeä datavirta, mikä helpottaa sovelluksen ylläpitoa ja laajentamista. Näin varmistetaan, että sovellus pysyy hallittavana ja ennustettavana myös kasvavassa ja monimutkaistuvassa kehitysympäristössä.

Sovelluksen alkuvaiheen suunnittelussa on tärkeää keskittyä hankkeen laajuuden määrittelyyn ja tiekartan laatimiseen. Prototyyppien, wireframejen ja backlogien avulla voidaan konkretisoida visio ja välttää turhaa hiomista ennen perusrakenteiden sopimista. Tämä varmistaa, että kehitys etenee iteratiivisesti ja hallitusti.

Kuinka rakentaa navigointikomponentteja ja huolehtia käyttöliittymän johdonmukaisuudesta Angular-sovelluksessa

Kun olemme jo ottaneet käyttöön laiskan latauksen ManagerModulelle, voidaan edetä seuraaviin vaiheisiin navigointielementtien toteuttamiseksi. Nykyisessä asettelussa ManagerHomeComponent renderöidään AppComponentin templateissa, joten kun käyttäjä siirtyy HomeComponentistä ManagerHomeComponentiin, AppComponentin toteuttama työkalupalkki pysyy paikoillaan. Tämä luo yhtenäisen ja ennakoitavan käyttökokemuksen, joka parantaa navigointia sovelluksessa.

Voimme helposti laajentaa tätä periaatetta luomalla samanlaisen työkalupalkin, joka pysyy näkyvillä ManagerModule-yksikössä. Näin ollen käyttäjän navigointi, olipa kyseessä käyttäjähallinta tai kuittien tarkastelu, ei aiheuta häiriöitä ja käyttöliittymä pysyy johdonmukaisena koko sovelluksessa. Tällöin navigointipainikkeet, kuten "User Management" ja "Receipt Lookup", olisivat aina näkyvillä riippumatta siitä, mihin alisivuille käyttäjä siirtyy.

Tämän toimenpiteen toteuttaminen vaatii rakenteellista lähestymistapaa. Ensimmäinen vaihe on luoda ManagerComponent, joka toimii peruskomponenttina. Tämän jälkeen voit luoda siihen liittyvän navigointityökalupalkin, joka seuraa aktiivisten linkkien tilaa ja tarjoaa visuaalisia vihjeitä siitä, missä käyttäjä on sovelluksessa. Tämä voidaan saavuttaa lisäämällä tyyliin seuraavat säännöt: aktiivinen linkki voidaan korostaa lihavoinnilla ja alaviivalla, mikä parantaa navigoinnin ymmärrettävyyttä.

Kun nämä peruskomponentit on luotu, voidaan edetä seuraaviin vaiheisiin, kuten lasten komponenttien ja reitityksen määrittelyyn. Ensiksi on määriteltävä, mitkä reitit vievät käyttäjän eri alisivuille, kuten "users" (käyttäjähallinta) tai "receipts" (kuittien tarkastelu). Näiden reittien määrittelyyn liittyy aina parent-child-suhteen ymmärtäminen, jossa vanhempi komponentti (ManagerComponent) huolehtii työkalupalkin näkyvyydestä, ja lapset (esim. UserManagementComponent, ReceiptLookupComponent) sisältävät varsinaiset sisällöt.

Kun reititykset on luotu, on tärkeää testata sovelluksen toiminta. Esimerkiksi kun käyttäjä klikkaa "Manager's Dashboard" -painiketta, sen pitäisi viedä hänet oikealle alisivulle, ja aktiivinen linkki näkyy selkeästi työkalupalkissa. Tämä ei ainoastaan paranna navigointia, vaan myös estää käyttäjää eksymästä sovelluksen eri osiin.

Tärkeitä huomioita ja jatkotoimenpiteitä

Vaikka tämänkaltaisten komponenttien luominen saattaa tuntua yksinkertaiselta, on tärkeää muistaa muutama perusperiaate, jotka vaikuttavat pitkällä aikavälillä sovelluksen käyttökokemukseen ja ylläpidettävyyteen. Ensinnäkin on tärkeää ymmärtää, että jokaisella komponentilla tulee olla selkeä ja eriytetty vastuu, jotta niitä on helppo muokata tai laajentaa tulevaisuudessa ilman, että koko sovelluksen rakenne menee sekaisin.

Toiseksi, vaikka reitityksen ja komponenttien luominen saattaa alkuun näyttää yksinkertaiselta, laiskan latauksen (lazy loading) ja muiden optimointitekniikoiden käyttö ovat kriittisiä sovelluksen suorituskyvyn kannalta. Tämä on erityisen tärkeää, kun sovellus kasvaa ja sen rakenne monimutkaistuu. Laiskan latauksen hyödyntäminen auttaa varmistamaan, että vain tarpeelliset osat sovelluksesta ladataan kerralla, mikä parantaa sekä latausnopeutta että käyttäjäkokemusta.

Samoin käyttöliittymän johdonmukaisuus on tärkeä tekijä sovelluksen käytettävyyden parantamisessa. Vaikka työkalupalkkien ja navigointipainikkeiden luominen ja sijoittaminen ovat tärkeitä, yhtä tärkeää on myös se, että ne ovat helposti ymmärrettäviä ja saavutettavia kaikille käyttäjille. Tämä tarkoittaa muun muassa sitä, että icon-painikkeet tulisi aina varustaa selkeillä kuvauksilla ja työkaluilla, kuten mat-tooltip, joka kertoo, mitä kukin painike tekee.

Kun jatkat sovelluksen kehittämistä, on tärkeää myös miettiä roolipohjaisen navigoinnin toteuttamista, jossa käyttäjät voivat nähdä tai olla näkemättä tiettyjä osia sovelluksesta sen mukaan, millainen rooli heillä on. Tämä mahdollistaa sovelluksen mukautumisen eri käyttäjäryhmille ja parantaa sen turvallisuutta ja käyttökelpoisuutta.