ClojureScript-kokemuksia

Olen edelleen jatkanut ohjelmointia Clojurella. Vaikka alkuhuuma on jo haihtumaan päin, näyttäisi kieli tulleen työkalupakkiini jäädäkseen. Olen tutustunut sekä palvelinpuolen ohjelmointin, että selainpuolen ClojureScriptiin. Kieli on muuten melkein sama, mutta kääntäjä tuottaa Java-tavukoodin sijaan JavaScriptia. JavaScript tunkee itsensä nykyään joka paikkaan, joten se on yhä houkuttelevampi ohjelmointialusta, vaikka itse kielestä ei niin innostuisikaan.

Kirjoitin aiemmin JavaScriptillä tekemästäni Drizzle-työkalusta. Päätin nyt harjoitusprojektina portata sen ClojureScriptille. Matkalla on mm. selkeytynyt Clojuren ja ClojureScriptin yhtenevyydet ja erot, tullut tutuksi ReactJS-kirjastot Om ja Reagent, projektinkoostotyökalut Leiningen ja Boot.

(Sovellus pitäisi käynnistyä tähän alle iframeen. Koodi GitHubissa. Avaa omassa ikkunassa.)

Päätin lähestyä tehtävää iteratiivisesti, siirtämällä vähitellen ominaisuuksia ClojureScript-koodiin ja kutsuen sieltä vanhaa JS-koodia. Hieman kömpelöä kyllä, eikä dokumentaatiokaan aina ollut aivan ajantasalla (CLJS kehittyy vauhdilla). Pelkän ohjelmointikielen lisäksi jouduin vaihtamaan koko ajattelumallin imperatiivisesta funktionaaliseen. Pian totesin, että parempi vaan kirjoittaa kokonaan uudestaan ClojureScriptillä ja unohtaa vanha, pääsi paljon helpommalla.

React: Om ja Reagent

Facebookin React on saanut huikean suosion viimeaikoina ja se vaikuttaisi kieltämättä merkittävältä askeleelta selainkäyttöliittymien kehityksessä. Idea lyhykäisyydessään on ylläpitää selaimen näkymää vastaava virtuaalinen versio muistissa. Selaimen dokumenttirakenteen suoran muokkauksen sijaan muutokset tehdään tähän virtuaaliseen DOMiin, mikä mahdollistaa tehokkaat muutosvertailut ja päivitykset.

ClojureScriptille löytyy useampia Reactin päälle rakentavia kirjastoja. Ensimmäiset kokeiluni tein Om-kirjastolla, koska se sen ympärillä vaikutti olevan eniten aktiivisuutta. Riittävästi turhauduttuani päätin kokeilla Reagentia, ja sille tiellä olen toistaiseksi jäänyt. Om mukailee Reactin APIa, kun taas Reagent tarjoaa huomattavasti yksinkertaisemman näkemyksen ja rajapinnan. Quiescent vaikutti myös kokeilun arvoiselta vaihtoehdolta, mutta jääköön se myöhemmäksi.

Projektin rakennus ja riippuvuudet

Clojurelle on kaksi omaa build-työkalua: Leiningen ja Boot. Olen tehnyt rinnakkain eri projekteja nyt molemmilla. Leiningen tarjoaa deklaratiivisen ja Boot proseduraalisen lähestymisen aiheeseen. En vielä ole vahvaa mielipidettä muodostanut asiasta, mutta alan kyllä kallistua Bootin kannalle, koska se tarjoaa läpinäkyvämmän ja hallitumman build-prosessin.

Riippuvuuksista sinänsä, minulla oli käytännössä hankaluuksia hahmottaa mikä riippuu mistäkin. Useat eri kirjastot halusivat eri CLJS-version (joka taas saattoi haluta eri Clojure-version). Olisin halunnut käyttää tuoreempia versioita, mutta käytännössä jouduin käyttämään vanhoja, koska en yksinkertaisesti saanut uusia toimimaan keskenään.

Parhaimmillaan muutokset koodiin näkyvät selaimessa sekunnissa ilman sivun uudelleenlatausta, ohjelman tilan säilyessä. Käytännössä kuitenkin joudun usein tekemään sivun latauksen, sillä en vielä oikein ymmärrä live-reloadin kaikkia kiemuroita. En vielä ole onnistunut saamaan esim. makrojen lataamia sivupohjia päivittymään lennossa muokattaessa. Käyttöliittymän koodaus on ollut kuitenkin sujuvaa ja lopputulos tuntunut huomattavasti ymmärrettävämmältä ja hallitummalta kuin alkuperäinen JavaScript.

Clojure ja ClojureScript

Yksi ClojureScriptin lupauksista on kaventaa selain- ja palvelinkoodin välistä kuilua, ja kyllä se siinä yhä paremmin onnistuukin. Odotin JavaScript/Node.js -tyyppistä kokemusta, mutta vielä ei ihan siellä olla. Tilannetta hankaloitti se, että Clojure ja ClojureScript näyttävät samalta, joten niiden eroavaisuudet eivät heti auenneet.

Lähtökohtaisesti Clojurea ja ClojureScriptiä ei voi käyttää ristiin. ClojureScriptissä ei voi käyttää Clojure (ja siten Java-) kirjastoja suoraan, merkittävänä poikkeuksena makrot, jotka taas kirjoitetaan nimenomaan Clojurella (ja ajetaan käännösaikana). Tähän tilanteeseen on tulossa helpotusta Clojure 1.7:n myötä (reader conditionals). Odotin myös selaimen ja palvelimen välisen kommunikointiin parempia työkaluja, mutta jokseenkin perinteisellä http-kutsulla ja rest-rajapinnalla mennään toistaiseksi.

Jos Node.js:llä on tottunut kirjoittamaan koodia, joka voidaan ajaa yhtälailla selaimella ja palvelimella (esimerkiksi verkkosivu, jonka ensilatauksen renderöi palvelin, jatkossa selain, samalla koodilla), ei tämän hetken Clojure/Script-työkalut käytännössä vielä pysty samaan. Yksi vaihtoehto (joka on alkanut kuulostaa yhä houkuttelevammalta), olisi käyttää JVM:n sijasta NodeJs-palvelinta, ja kirjoittaa koko ohjelmisto ClojureScriptillä. Tällöin toki menettää Clojure- ja Java-kirjastojen tuen.

Mitä seuraavaksi?

Olen viimeaikoina keskittynyt käyttöliittymäpuoleen, ja seuraavaksi onkin vuorossa palvelinpuoleen syventyminen. ClojureScript-käyttöliittymätkin tarvitsevat yleensä jossain kohtaa tietokannan, samoin kuin mobiilisovellukset. Tallennuksen lisäksi tarvitsisi ratkaista selaimen datan synkronointi tietokannan kanssa, erityisesti mobiilikäyttöliittymiä varten. David Nolenin Euroclojure -esityksessään esittelemä Om Next kuulostaa oikealta suunnalta. Täydellistä ratkaisua odotellessa taidan kuitenkin rakentaa ensin REST-rajapinnan ja kokeilla MongoDb:n ja Clojuren yhteensopivuutta.

Jos tässä kohtaa pitäisi pelimerkit jollekin teknologiahevoselle laittaa, niin se olisi ClojureScript. Vielä kun se saadaan mobiililaitteisiin, esimerkiksi React Nativen avulla, niin tarjolla olisi hyvin houkutteleva kehitysympäristö. ClojureScriptillä saattaa vielä tänä vuonna voida tehdä sekä mobiili että webkäyttöliittymän kuin myös palvelinpäädynkin, vieläpä asiakas/palvelin -rajapinta häivyttäen. Ja kaupan päälle REPL ja uuden koodin lataus lennossa niin selaimeen kuin puhelimeenkin. Jos tämä toteutuu, on odotettavissa sellainen, anteeksi sipilismi, tuottavuusloikka, että luulisi konservatiivisempaakin ohjelmistokehityspuljua kiinnostavan.

Linkkejä

comments powered by Disqus
2015-07-19