React on viime vuosien aikana saavuttanut valtavasti suosiota ja se on muodostunut jonkinasteiseksi de facto -standardiksi frontend-toteutuksissa. Reactin suosio on täysin ansaittua ja se on ehdottomasti järkevä valinta fronttitekniikaksi, mutta kannattaa kuitenkin pitää mielessä, että vaihtoehtoja Reactille on olemassa. Yksi mielenkiintoisimmista - ja mielestäni vahvimmista - vaihtoehdoista on Elm.

Mikä hemmetin Elm? Suksi kuuseen!

Elm on tiukasti tyypitetty funktionaalinen ohjelmointikieli, joka kääntyy tavalliseksi, selaimessa ajettavaksi JavaScriptiksi. Elmin päämääränä on auttaa rakentamaan virheettömiä web-sovelluksia ja tämän päämäärän se saavuttaa loistavasti. Elm nimittäin on suunniteltu niin, että jos koodi menee kääntäjästä läpi, se toimii käytännössä absoluuttisella varmuudella. Haluatko todisteita? Tässäpä niitä:

Se, miksi Elm-sovellukset ovat pääsääntöisesti virheettömiä, johtuu muutamasta Elmin ominaisuudesta:

  • Tiukka tyyppijärjestelmä pakottaa mallintamaan tiedon huolellisesti.

  • Kääntäjä vaatii, että jokainen mahdollinen tila huomioidaan sovelluksessa.

  • Kaikki tieto on muuttumatonta ja koodilla ei ole sivuvaikutuksia.

Nämä ominaisuudet tuovat mukanaan muitakin hyötyjä, mutta juurikin sovellusten virheettömyys on se, mikä Elmissä minua itseäni eniten houkuttaa. Näiden lisäksi yksi Elmin vahvuuksista on se, että kieli on hyvin suppea, joten teoriassa sen oppimisen pitäisi sujua melko helposti. Omakohtaisesta kokemuksesta voin sanoa, että opiskelua kuitenkin oikeasti tarvitaan, sillä imperatiivisiin ohjelmointikieliin tottuneelle Elm tuntuu todella kummalliselta ja jopa hyvin rajoittuneelta komennettavalta. Onneksi Elmin kääntäjä on niin uskomattoman avulias ja ihmisrakas, että sen kanssa työskentely on silkkaa iloa ja opiskelu sujuu kuin itsestään (tämä ei ole sarkasmia)!

Sä ja sun Elmis! En mä jaksa kuunnella minkään kääntäjän urputuksia!

Kyllä, Elm on pakko kääntää JavaScriptiksi, jotta sitä voidaan suorittaa selaimessa. Tämä ei kuitenkaan ole ollenkaan huono juttu, sillä Elm-kääntäjä on huippu. Se auttaa kaikin mahdollisin tavoin kehittäjää kirjoittamaan koodinsa ajettavaan kuntoon. Muutama hyvä esimerkki Elm-kääntäjän ihanuudesta löytyy virallisesta Elm-blogista:

Elm-kääntäjän avuliaisuus on pantu merkille varsin laajalti ja mm. Rust-kielen kääntäjää on kehitetty hyvin paljon Elm-kääntäjän kaltaiseksi.

Funktionaalinen ohjelmointi on snobbailua ja akateemista sontaa! Ei sillä tosimaailmassa tee mitään!

Funktionaalinen ohjelmointi ei ole mikään uusi ohjelmointiparadigma. Imperatiiviset kielet ja erityisesti olio-ohjelmointi ovat dominoineet alaa pitkään, mutta funktionaalinen ohjelmointi on jo muutaman vuoden ajan kokenut uutta nostetta. Toistaiseksi esim. Haskell-osaajan löytäminen avoimeen työtehtävään olisi Suomessa hankalaa - eikä toisaalta Haskell-osaajaa varmasti moneen paikkaan erikseen haettaisikaan - mutta funktionaaliset kielet valtaavat alaa kovaa vauhtia. Ja eipä ihme, sillä:

  • puhtaasti funktionaalisten kielten suoritus on erittäin hyvin rinnakkaistettavissa (tarpeellinen ominaisuus mm. keinoäly- ja grafiikkaohjelmoinnissa)

  • funktionaalisilla kielillä kirjoitettujen ohjelmien oikeellisuus voidaan todistaa matemaattisesti

  • funktionaaliset kielet ovat pääsääntöisesti yksinkertaisia

Elm on huomattavasti Haskellia lempeämpi johdatus funktionaaliseen ohjelmointiin, eikä Elmin opiskelu edellytä aikaisempaa tuntemusta funktionaalisesta ohjelmoinnista. Omakohtainen todisteeni siitä on tätä blogikirjoitusta varten luomani esimerkkisovellus, joka on itse asiassa vasta toinen koskaan rakentamani Elm-sovellus.

Käymme kohta hiukan tarkemmin tuota sovellusta läpi, mutta mielestäni tärkein huomioitava asia siinä on, että sovellus on käytännössä vain yksi elementti sivulla. Toisin kuin monien muiden web-sovelluskehysten kanssa, Elmin voi helposti tuoda osaksi laajempaa koodipohjaa ihan vain kokeilumielessä ja ilman sen isompaa sitoutumista. Tätä auttaa erityisesti se, että Elmin kirjoittamisen voi aloittaa heti kääntäjän asentamisen jälkeen - erilaisten työkalujen asentamiseen ja konfigurointiin ei tarvitse tuhlata aikaa. Elm myös tarjoaa mahdollisuuden viestiä "normaalin" JavaScriptin kanssa, joten sen kanssa voi kohtuullisen yksinkertaisesti käyttää olemassa olevaa JS-koodia, jos niin välttämättä haluaa.

Jos on tottunut rakentelemaan sovelluksia nykyaikaisten JS-sovelluskehysten, kuten Reactin, kanssa, tuntuu Elmin käyttäminen käsittämättömän yksinkertaiselta. Elmissä kun tulee oletuksena kääntäjän lisäksi pakettimanageri, kehityspalvelinohjelmisto (Elm Reactor) ja aikamanipulaatiolla varustettu debuggeri. Kääntäjä osaa kääntää sovelluksen valmiiksi, tiukasti optimoiduksi jakeluversioksi. Pakettimanageri pakottaa paketit automaattisesti käyttämään semanttista versiointia oikein, mikä takaa rajapintojen pysyvän muuttumattomina paketin pääversion sisällä. Kehityspalvelinohjelmistolla sovelluksen osasia pääsee rakentamaan nopealla iteraatiosyklillä. Debuggerin kanssa sovelluksen tilan voi siirtää ajassa taaksepäin ja koko tilahistorian voi halutessaan siirtää käyttäjältä toiselle. En ole minkään vastaavan sovelluskehyksen tai ohjelmointikielen mukana nähnyt tulevan näin korkealuokkaisia kehitystyökaluja.

Sisäänrakennettujen ominaisuuksien lisäksi Elmin kanssa voidaan tietysti käyttää myös lukuisia muita kehitystyökaluja. Hyvä esimerkki tällaisesta on elm-format, joka varmistaa, että Elm-lähdekoodi on aina muotoiltu vastaamaan virallista tyylisäännöstöä. Tämä on erinomainen ajatus, sillä kehittäjän ei tarvitse tämän jälkeen ollenkaan miettiä sitä, miten lähdekoodi pitäisi muotoilla, vaan työkalu tekee kaiken muotoilun automaattisesti.

Jos et vielä käynyt, niin käypä nyt testaamassa esimerkkisovellusta. Sovellus käyttää Microlink-palvelun REST-rajapintaa metatietojen lukemiseen verkkosivuilta. Anna sovelluksen tekstikenttään jonkin verkkosivun kokonainen URL (eli mukaan se edeltävä https://-osa) ja paina enteriä (tai klikkaa sinistä nappia), niin näet antamastasi verkkosivusta metatietoja. Kun olet tarpeeksesi leikkinyt sovelluksen kanssa, palaa lukemaan loput tästä kirjoituksesta. 🙂

Elm ihan oikeasti saa ohjelmoinnin tuntumaan todella mukavalta puuhalta

Badass - Daniel Pascoa / Unsplash

Dorka "sovellus"! Ei tohon mitään Elmiä tarvii!

No joo, onhan se varmasti näinkin. Tarkoituksena tässä on demota Elmin soveltuvuutta juurikin pienen ja yksinkertaisen frontend-sovelluksen rakentamiseen. Ja vaikka sovellus on tässä tapauksessa varsin triviaali, tuo Elm mukanaan useita hyötyjä verrattuna esimerkiksi pelkkään JavaScriptiin. Tutkaillaanpa sovelluksen lähdekoodia hieman tarkemmin.

TEA: Elm-arkkitehtuuri

Yksi Elmin keskeisimmistä käsitteistä on Elm-arkkitehtuuri, eli TEA (sanoista The Elm Architecture). Kaikki Elm-sovellukset käyttävät aina TEA-arkkitehtuuria. TEA määrittelee seuraavat asiat:

  • Sovelluksella on yksi kaikenkattava tila, jota mikään ei voi suoraan muuttaa. Tämä on sovelluksen tietomalli, eli Model.

  • Sovelluksen tila voi muuttua vain ennaltamääriteltyjen viestien perusteella. Tämä on sovelluksen päivitys, eli Update.

  • Sovelluksen näkymä, eli View, rakennetaan kulloisenkin tilan mukaan.

Jokainen Elm-sovellus rakentuukin aina vähintään näistä kolmesta osasta. Esimerkkisovelluksessa näiden osien lisäksi on esitelty myös osat Subscriptions ja HTTP.

Model, sovelluksen tietomalli

Elmissä sovelluksen tila mallinnetaan yhden tietomallin perusteella. Esimerkkisovelluksessa tietomalli koostuu seuraavista tyypeistä:

  • LoadStatus: Tyyppi, joka mallintaa sovelluksen lataustilaa. Tila voi olla joko Loading tai Idle. Tämä on kuvaavampi tapa mallintaa lataustilaa, kuin esimerkiksi totuusarvon (True tai False) käyttäminen isLoading -ominaisuuden kanssa.

  • Microlink: Microlink-rajapinnan vastaus. Tämä tyyppi on luotu automaattisesti rajapinnasta saadun JSON-vastauksen perusteella JSON-to-Elm-työkalulla.

  • MicrolinkDataImage: Microlinkin vastauksissa olevia kuvaviittauksia mallintava tyyppi. Tämä tyyppi on myös luotu automaattisesti JSON-to-Elm-työkalulla.

  • MicrolinkData: Microlink-vastausten varsinainen data. Tämäkin tyyppi syntyi automaattisesti JSON-to-Elm-työkalulla.

  • Model: Sovelluksen kaikenkattava tila, joka käyttää yllä määriteltyjä tyyppejä.

Sovelluksen käynnistyessä tila alustetaan sopivilla arvoilla ja jätetään käyttäjän komennettavaksi.

Update, sovelluksen tilan päivitys

Elm-sovellusten tilaa voidaan muuttaa vain välittämällä viestejä päivitysfunktiolle. Koska sovellus ei saa milloinkaan ajautua ennalta-arvaamattomaan tilaan, on myös päivitysviestit määriteltävä ennakkoon:

  • SubmitForm: Käyttäjä lähettää sovelluksessa olevan lomakkeen.

  • ChangeAddress: Käyttäjä vaihtaa sovelluksen osoitekentän sisältöä.

  • GotResult: Sovellus sai HTTP–vastauksen Microlink-API:lta.

Näillä kolmella päivitysviestillä pystytään hoitamaan kaikki sovelluksen tilamuutokset. Sovelluksen update-funktio vastaanottaa näitä päivitysviestejä ja korvaa sovelluksen tilan uudella viestien perusteella.

Subscriptions, ulkopuolisten syötteiden kuuntelua

Ulkopuolisia syötteitä, kuten hiiren osoittimen liikkeitä, voidaan Elmissä kuunnella subscription-menetelmän avulla. Ideana on, että sovellus voi "tilata" haluamistaan asioista syötteet, mutta oletuksena tietoja ei tule sovellukselle mitenkään. Tämä saattaa aluksi tuntua hieman kummalliselta, mutta ajatuksenahan on, että sovelluksen tila voi päivittyä ainoastaan ennalta määriteltyjen viestien kautta. Tilaukset mahdollistavat tilaa päivittävien viestien luomisen sovelluksen ulkopuolisesta lähteestä. Aika siistiä!

View, sovelluksen näkymä

Sovelluksen tila esitetään selaimessa HTML-rakenteena. Tämä rakenne on sovelluksen näkymä, joka tuotetaan Elmin HTML-paketin tarjoamilla funktioilla. Jokaista HTML-elementtiä varten on olemassa oma funktionsa, joka käytännössä aina ottaa vastaan kaksi listaa: elementin attribuutit ja lapsielementit. Jos elementillä ei voi olla lapsielementtejä, ottaa ko. elementin funktio vastaan ainoastaan listan attribuutteja. Tämä on erittäin kätevä abstraktio HTML-rakenteeseen ja tekee näkymien rakentamisesta helppoa.

Näkymä tuotetaan uusiksi aina, kun sovelluksen tila päivittyy. Koska tilapäivityksiä saattaa olla useita sekunnissa, on järjetöntä, että selaimelle asti välitettävä HTML-rakenne luotaisiin aina alusta asti uusiksi. Tätä varten Elm käyttää omaa virtuaali-DOM-toteutustaan. Kun tila muuttuu, Elm selvittää, mitkä asiat näkymässä päivittyvät ja päivittää ainoastaan niitä kohtia selaimen näyttämässä HTML-dokumentissa. Tämä on hyvin vastaava mekanismi kuin esim. Reactissa, enkä usko, että eri VDOM-toteutusten suorituskyvyssä on nykyään enää mitään käytännön eroa.

HTTP, viestintää ulkomaailman kanssa

Esimerkkisovelluksen on pystyttävä viestimään Microlink-palvelun rajapinnan kanssa. Jotta viestintä onnistuu järkevästi, tarvitaan kaksi asiaa: HTTP-protokollan toteuttava viestintäväylä sekä keino tulkita palvelun lähettämät vastaukset Elm-kielen tietorakenteiksi. HTTP-viestintä onnistuu hyvin yksinkertaisesti Elmin HTTP-paketin avulla, mutta vastausten tulkitseminen onkin sitten astetta kinkkisempi juttu.

Microlink-rajapinta palauttaa vastauksensa JSON-muodossa ja JSON-dekoodaus saattaa monesta aloittelevasta Elm-koodarista tuntua turhauttavan hankalalta. Koska kaikki data on Elmissä tiukasti tyypitettyä, on JSON-dekoodausta varten pystyttävä kirjoittamaan tyypit, joihin tiedot voidaan lukea. Onneksi tämä sentään onnistuu lähes kokonaan automaattisesti JSON-to-Elm-työkalulla. Koska JSON voi kuitenkin olla muodoltaan oikeastaan ihan mitä tahansa, on sudenkuoppiin Elmin JSON-dekoodauksessa helppo langeta.

JSON-dekoodaus myös tuottaa suuren määrän ns. boilerplate-koodia Elm-sovelluksiin. Tässä hyvin yksinkertaisessa esimerkkisovelluksessa JSON-dekoodaukseen tuhlaantuu lähes neljäsosa koko sovelluksen lähdekoodista.

Aivan suolesta koko Elm! En koske pitkällä tikullakaan!

No, ei se Elm täydellinen ole, mutta sillä on yksi aivan verraton valtti puolellaan: Elmillä ohjelmointi on kivaa! Tämä ei siis ole sellaista "leluilla on kiva leikkiä" -kivaa, vaan Elm ihan oikeasti saa ohjelmoinnin tuntumaan todella mukavalta puuhalta. Elmillä ohjelmointi on tiedon kuvaamista ja sen esittämistä - toteutuksen pienempiin yksityiskohtiin ei tarvitse paneutua millään tavalla. Tästä syystä Elmillä ohjelmointi on todella tuotteliasta ja oikeasti paljon yksinkertaisempaa kuin voisi ensinäkemältä uskoa.

Elmistä julkaistiin muutama kuukausi sitten versio 0.19.0. Kieli kehittyy koko ajan ja uudet versiot eivät välttämättä ole taaksepäin yhteensopivia kaikilta osin. Tästä syystä Elmiä täytyy vielä toistaiseksi suositella tuotantokäyttöön hieman varauksella - vaikkakin isoja Elm-sovelluksia on maailmalla tuotannossa pyörinyt jo muutaman vuoden ajan.

Imperatiivisiin ohjelmointikieliin tottuneelle Elmin edustama funktionaalinen ohjelmointiparadigma tuntuu raikkaalta. Elm on erinomainen alusta funktionaalisen ohjelmoinnin opiskeluun ja imperatiivisten aivojen tuulettamiseen - se jopa saattaa tehdä sinusta paremman imperatiivisen ohjelmoijan.

Elm ja Parcel vievät nirvanaan

Tuore versio Parcel-paketoijasta pitää sisällään Elm-tuen. Tämä tekee kokonaisten Elm-sovellusten rakentamisesta vielä entistä yksinkertaisempaa, sillä Parcelilla sovelluksiin voi ympätä niin tyylit kuin kaikki muutkin staattiset resurssit todella helposti. Tässä kirjoituksessa käytetty esimerkkisovellus on paketoitu Parcelilla ja mikäli huippuhelppo fronttikehitys kiinnostaa, voit kokeilla seuraavaa:

  1. Kloonaa esimerkkisovellus Githubista

  2. Asenna Parcel

  3. Aja esimerkkisovelluksen juurihakemistossa komento parcel index.html

  4. Avaa selaimessa sivu http://localhost:1234

  5. Muokkaa sovelluksen koodia ja ihaile, kuinka muutokset päivittyvät automaattisesti sovellukseen

Parcel ja Elm ovat siksi loistava parivaljakko, että kumpikaan ei tarvitse minkäänlaista konfiguraatiota. Yhdistelmänä ne tarjoavat lyömättömän alustan frontend-kehitykselle: ei mitään konfiguroitavaa, ei JavaScript-väsymystä, ei pelkoa.

Elämä on liian lyhyt käytettäväksi huonoilla työkaluilla työskentelemiseen tai ylipitkien blogikirjoitusten lukemiseen. Kokeile Elmiä ja tee backend-koodarit kateelliseksi!