Dokumentoin tässä oppimisprojektin ja siihen liittyvän teknologian yleisellä tasolla. Teknisiä yksityiskohtia ja lähdekoodia varten projekti löytyy GitHubista. Docker-image on saatavilla Docker Hubissa, ja tuotannossa oleva sovellus itse löytyy osoitteesta https://anttihalla.fi/golang-docker-circleci-example
Tällä kertaa tarkoitus oli opetella perusteet kolmesta työkalusta: ohjelmointikieli Go, virtualisointityökalu Docker ja jatkuvan integraation palvelu CircleCI.
Miten nopeasti saada pohjaosaaminen näistä kaikista kolmesta? Yritänkö tehdä projektin joka yhdistää nämä kaikki kolme, vai olisiko siinä liikaa opittavaa kerralla? Toinen vaihtoehto olisi ensin siirtää vanhoja projekteja Dockeriin ja/tai CircleCI:hin. Tällä tavalla saisi oppimisen määrää ja uusia tuntemattomia minimoitua.
Annoin ajatuksen hautua sen aikaa, kun kävin googlettamassa perustietoja aiheesta. Naputtelin Go-tutorialin, lueskelin CircleCI:n dokumentaatiota, katselin YouTubesta Dockerin perusteita. Näitä haudutellessa päädyin lopulta siihen, että yritän tehdä suoraan yhden projektin, joka yhdistää nämä kolme asiaa. Pitäisi vain suunnitella etenemisaskeleet siten, että joudun opettelemaan vain yhden uuden asian kerrallaan.
Alustava suunnitelma oli lyhyesti:
Olen liian monta kertaa kehitellyt pöytälaatikkoprojekteja vain huomatakseni, että tuotantoon viemisessä onkin monta mutkaa vielä matkassa. Nyt halusin välttää sen harjoittelemalla myös julkaisun tuotantopalvelimelle. Toki tuotantokoodia pitää myös osata päivittää, joten automaattinen testien ajo ja tuotantoversion päivityksen sujuvuus pitää myös varmistaa.
Monet ohjelmointikielten oppikirjat eivät ole yksinään riittäviä tietolähteitä käytännön ohjelmistoprojektia varten samasta syystä: kirjat keskittyvät itse kielen ominaisuuksiin, esimerkiksi juuri tuotantoonvientiin liittyvien toimintojen jäädessä sivuseikoiksi, mikäli niitä edes käsitellään.
Ohjelma itse saa olla simppeli, mutta koko tuotantoketju pitää testata, mukaan lukien kehitysyökalut ja tekstieditorien kielituet. Tämän vuoksi suunnitelmaan piti lisätä vielä muutama askel:
Suunnitelma kuulosti toteutettavissa olevalta ja riittävän pieneltä, jotta saan sen myös tehtyä. Tavoite oli saada homma tehtyä vähitellen yhden viikon aikana, pari tuntia päivässä tehden ja opiskellen.
Go (kirjoitetaan usein Golang) on Googlella kehitetty kohtuu nuori ohjelmointikieli (1.0 versio julkaistiin vuonna 2012). Tarkoitukseni oli saada nopea kosketus kielen ominaisuuksiin ja tarjolla olevaan dokumentaatioon.
Pelkän “Hello world” -tulosteen lisäksi halusin hieman kielen ominaisuuksiakin kokeilla, joten lisäsin soppaan yksinkertaisen HTTP-palvelimen, HTTP-kutsun ulkoiseen API-rajapintaan ja sieltä saadun JSON-vastauksen parsimisen. Yksi Go:n mainostetuista vahvuuksista on rinnakkaisuus, joten halusin myös nähdä miten useampi rajapintapyyntö kerralla onnistuu asynkronisesti.
Ohjelmointikielen kirjoittamista varten tarvitaan lisäksi tietenkin editori. Pääasiallisena tekstieditorinani on viime aikoina ollut Atom. Siihen löytyi suoraan muutama Go-plugin, joiden avulla sain editoriin syntaksikorostukset, käännösvirheet ja jopa automaattiset testiajot näkymään ilman sen kummempaa vaivaa. Mahdollisesti parempiakin ratkaisuja on, mutta tämä oli enemmän kuin riittävä minulle.
Haluamani tärkeimmät toiminnallisuudet onnistuivat suuremmitta mutkitta Go:n standardikirjaston avulla esimerkkejä seuraamalla. Ainoastaan koodin automaattista uudelleen kääntämistä varten jouduin asentamaan ulkoisen kirjaston. Go-lähdekoodi käännetään binääriksi ajamista varten, joten nopeaa kehitystä varten (jotta muutokset näkyvät selaimessa koodi tallennettaessa) tarvitsin tiedostojen muuttumista tarkkailevan lisäpalikan.
Projektia varten loin julkisen projektin GitHubiin, josta ohjelmakoodi löytyy. Julkinen projekti mahdollistaa myös Docker Hubin ja CircleCI:n maksuttoman käytön. Näistä lisää alla.
Docker on lyhykäisyydessään kevyt käyttöjärjestelmän virtualisointitekniikka, jonka avulla voidaan ohjelmisto rakentaa, asentaa ja hallinnoida käyttäen toisistaan eristettyjä sovelluskontteja (container). Konttien ajamista palvelimella täytyy olla asennettuna Docker-ohjelmisto.
Ajettava kontti vaatii pohjakseen sovelluksen Docker-levykuvan (image), joka puolestaan määritellään tyypillisesti projektin lähdekoodin rinnalla Dockerfile-tiedostossa. Tiedostossa määritellään pohjana käytettävä levykuva sekä askeleet ohjelmiston koostamiseksi.
Tämän harjoitusprojektin tapauksessa tiedostoon tulee vain muutama rivi: pohjana on Go-ohjelmointikielen työkalut sisältävä levykuva, ohjelma kopioidaan konttiin, käännetään ja ajetaan.
Tuotantovalmiit levykuvat tallennetaan levykuvarekisteriin (Docker registry), josta ne voidaan ladata tuotantopalvelimelle ajettavaksi. Rekisteriä voi ylläpitää itse tai voi hyödyntää Docker Hub -palvelua. Avoimen lähdekoodin ylläpitoon Docker Hub sopii hyvin, joten työnsin levykuvan sinne.
Jatkuva integrointi, continuous integration (CI), lienee nykyään niin keskeinen osa ohjelmistokehitystä, että harva vähänkin kunnianhimoisempi projekti pärjää ilman. CI toimii kehitystyön selkärankana, joka mahdollistaa ohjelmiston uusien versioiden hallitun tuotantoonviennin sekä laadun jatkuvan kehittämisen.
Yksinkertaisimmillaan CI-palvelin noutaa päivittyneen ohjelmakoodin automaattisesti versionhallinnasta, ajaa nipun testejä ja ilmoittaa menivätkö ne läpi. Tämä voi vuorostaan liipaista tuotantoonvientiautomatiikan. Monivaiheiset tuotantoonvientiprosessit saattavat käsin viedä tunteja, jopa päiviä joissain ympäristöissä. Toimivan CI:n avulla tämä aika lasketaan ennemminkin minuuteissa, jos ei sekunneissa.
Ennen CircleCI:tä kokemukseni oli lähinnä itse asennetuista Jenkins-palvelimista ja odotin tuntien mittaista konfigurointiurakkaa alkuun pääsemiseksi. Sain kuitenkin yllättyä positiivisesti: 15 minuutissa olin luonut palveluun tunnuksen, liittänyt GitHub-projektin automaattista koostoa varten. Palvelu tarjosi valmiin pohjatiedoston, jonka avulla perusasennus meni kivuttomasti. Konfiguraatiotiedosto liitetään lähdekoodin rinnalle versionhallintaan.
Kyllä CircleCI:n kanssakin aikaa saa kulumaan asetusten säätämisessä. Konfiguraatio-tiedostot kun loppujenlopuksi voi testata vain ajamalla koko prosessi läpi. Tätä helpottaa kyllä komentorivityökalut, joilla tiedoston voi validoida ennen ajamista.
Netistä löytyviä ohjeita seuratessa kannatta huomata myös että CircleCI versiot 1 ja 2 eivät ole täysin yhteensopivia keskenään (ja monet ohjeet viittaavat versioon 1).
Viimeinen askel kehitysputkessa oli vielä tuotantoonvienti automaattisesti CI-palvelimelta. CircleCI tarjoaa valmiita liityntöjä palveluihin kuiten AWS, Heroku, Azure, GoogleCloud ja Firebase. Päätin kuitenkin käyttää olemassaolevaa Ubuntu-virtuaalipalvelintani.
Tuotantoonviennin säätäminen olisi saattanut mennä yksinkertaisemmin ja nopeammin ottamalla käyttöön jokin tuetuista palveluntarjoajista, mutta halusin myös selvittää miten tämä kuvio toimii perinteisen palvelimen kanssa.
Tavallinen tapa asentaa valmis Docker-levykuva on kierrättää se keskitetyn rekisterin kautta. Tällaisen voi asentaa itse tai käyttää Docker Hub -palvelua. Avoimen koodin projektiin Hub sopii hyvin, joten latasin levykuvan sinne. Tuotantopalvelimeni voi sitten noutaa uuden sovellusversion Hubista – joko CI-palvelimen liipaisemana tai ajastetusti – ja asentaa uuden kontin vanhan tilalle.
Kokonaisuutena näiden kolmen teknologian – Go, Docker ja CircleCI – käyttöönotto onnistui yllättävänkin sujuvasti. Yhteensä tähän käytin aikaa noin 15 tuntia. Uusiin kilkkeisiin tutustuessa on helppo uppoutua yksityiskohtiin ja käyttää loputtomasti aikaa. Materiaalin syvyyssuuntaisen läpikäynnin sijaan leveyssuuntainen läpikäynti auttaa pitämään opiskeltavan kokonaisuuden paremmin tasapainossa ja ymmärtämään miten palikat liittyvät toisiinsa. Tällä tavoin kosketus jää ehkä hieman pinnalliseksi, mutta osaamiselle muodostuu kehikko, johon syvällisempi ymmärrys on myöhemmin helppo liittää.
Minimaalisen toimivan kokonaisuuden rakentaminen estää teknisiin nippeleihin jumittumisen ja auttaa ymmärtämään miten eri työkalut toimivat yhdessä. Koko tuotantoputken rakentaminen valmiiksi ensimmäisenä työnä auttaa vähentämään piileviä teknologiariskejä ja luo uudelle ohjelmistoprojektille vahvan perustan.
Tästä onkin hyvä sitten lähteä vaikka syventymään Go-kielen saloihin.
Olen rakentanut tämän blogin ennen mm. Julialla, Clojurella ja Racketilla. Edelliset blogialustani olivat niin sanottuja sivugeneraattoreita: järjestelmä itse oli asennettuna vain omalle koneelleni, kun palvelimelle siirrettiin vain lopputuloksena syntyneet staattiset html- ja muut tiedostot.
Tällä kertaa lähdin luomaan dynaamisempaa sivustoa, koska valitsemani teknologia vaikutti sellaiseen erityisen soveltuvalta. Tässä artikkelissa en kuitenkaan kovin syvälle teknisiin yksityiskohtiin mene, vaan tarkastelen aihetta yleisemmällä tasolla, lähtien siitä miten ylipäänsä päädyin taas uuden ohjelmointikielen pariin.
Phoenixin valintaan – nyt jo puolitoista vuotta sitten – minut johti kaksi erillistä polkua. Toissaalla olin innostunut funktionaalisesta Elm-ohjelmointikielestä web-käyttöliittymien toteutukseen ja toisaalla olin aloittanut tutustumisen Ruby on Railsiin, joka oli pieni aukko web-sivistyksessäni.
Rails-maailmaa tutkiessani törmäsin pian siihen, että osa Ruby-ohjelmoijista näytti olevan siirtymässä itse uuteen ohjelmointikieleen ja kehitysalustaan – kuten myös itse Elixirin isä José Valim. Tämä oli sinänsä outoa, sillä Rails on yleisesti hyvänä pidetty systeemi webkehitykseen, etenkin Rails-tekijöiden itsensä mielestä. Aloin epäillä valintaani ja vilkuilemaan tämän uuden ihmeen perään.
Elm taas tarvitsee kaverikseen palvelinohjelmiston ja sama ohjelmointikieli, josta en ollut ennen kuullutkaan nousi toistuvasti esiin. Molemmat ovat funktionaalisia kieliä, joissa arvojen muuttumattomuus on keskeistä. Kummallista tässä oli se, että nopealla vilkaisulla Elixirin tyyppijärjestelmä oli melko vaatimaton – kun taas Elm nojaa vahvasti tyypitykseen Haskellin tapaan. Mitä Elm-koodarit näkivät tässä kielessä?
Sekä Railsin että Elmin tapauksessa kyseessä oli sama parivaljakko: Elixir-kieli ja Phoenix Framework web-ohjelmointikehys. En heti tuolloin puolitoista vuotta sitten vielä halunnut aiheesta kirjoittaa, sillä halusin ensin varmistua etten ole vain hypen perässä juoksemassa.
Olen kuitenkin jäänyt koukkuun. Kävi ilmi, että Phoenix on itse asiassa vain portti kovempiin teknologioihin, kuten Erlang virtuaalikone BEAM ja sen päälle vuosien saatossa rakentunut ohjelmointialusta OTP.
Ensivilkaisulla Phoenix oli kuin mikä tahansa Model–View–Controller -ohjelmisto, ja useampaan sellaiseen tutustuneena alkuunpääsy olikin helppoa. Pian kuitenkin kävi selväksi, että tässä on nyt jotain uutta.
Ohjelmistokehys on rakenteeltaan selkein mitä olen kohdannut. MVC ja siihen liittyvät ideat eivät yksittäisinä sinänsä ole uusia, mutta kokonaisuus on poikkeuksellisen onnistunut. Funktionaalisuus näkyy kaikessa: koko HTTP pyyntö/vastaus -kierto ajatellaan pyynnön funktiona: HTTP-pyyntö, yksinkertaistettuna URL-tekstijono, muunnetaan askel askeleelta selaimelle palautettavaksi vastaukseksi.
Palvelinohjelma on siis ketju transformaatioita datalle. Elixir-kielessä tälle funktioiden yhdistämiselle on oma merkintätapansa, joka lisäksi helpottaa ketjun ajattelua. Edellisen funktion tuloste annetaan seuraavalle ensimmäisenä argumenttina.
request |> route() |> middleware() |> action()
Sama tyyli jatkuu kontrollerin toiminnon sisälläkin. Haetaan tiedot kannasta pyynnön parametrien perusteella, ja lopulta tehdään viewissä muunnos rakenteellisesta datasta pyytäjälle kelpaavaksi vastaukseksi, kuten html:ksi. Mahdolliset template-tiedostot muutetaan jo käännösaikana funktioiksi, mikä tekee niistä varsin ripeitä.
html = req_params |> Domain.get_records() |> filter() |> order() |> render()
Vaikeahan tätä kokonaisuutta on yrittää muutamalla rivillä tässä selittää, mutta koen joka tapauksessa tämän olevan todella ymmärrettävä ja selkeä tapa ajatella ohjelman toimintaa. Yleisesti ottaen yksi Phoenixin vahvuus on nimenomaan läpinäkyvyys. Jokseenkin koko toimintoketju on kehittäjän nähtävissä ja muokattavissa, ilman pinnan alla tapahtuvaa taikuutta.
Perinteisen pyyntö/vastaus -meiningin lisäksi Phoenix tukee <em>kanavia (channels)</em>, jotka ovat tyypillisesti websocketien avulla toteutettuja pysyviä kaksisuuntaisia yhteyksiä selaimen ja palvelimen välillä.
Uuden ohjelmointikielen kanssa on aina kysymys: mistä lähden liikkeelle? Lähdenkö lukemaan pulteista ja muttereista, ja opiskelemaan kielen ominaisuuksia oppikirjasta. Vai lähdenkö suoraan vain tekemään projektia.
Phoenix, sen dokumentaatio ja siitä kirjoitetut artikkelit vaikuttivat kattavilta, joten päätin lähteä suoraan rakentamaan blogialustaa Phoenixilla, opetellen Elixiriä vähitellen matkan varrella.
Sain kuin sainkin ensimmäisen version sivustosta tehtyä malliesimerkkejä seuraillen ja muokkaillen, ilman syvempää ymmärrystä Elixir-kielestä. Innostuin nopeasti sen verran, että ostin Phoenix-aiheisen kirjan.
Ruokahalu kasvoi syödessä ja aloin kiinnostua enemmän itse Elixir-kielestäkin. Hankin toisenkin kirjan – tällä kertaa itse kielen perusteista – ja aloin soveltaa Elixiriä myös muihin aiheisiin: algoritmit, shell-skriptaus, slackbot, Raspberry Pi, sensorit, itsenäiset ohjelmistoagentit… Huomasin, ettei Elixir ole vain verkkopalveluja varten, vaan kielestä on muutkin kiinnostuneet, erityisesti IoT -ja robotiikkapuolella tälle on selvästi tilausta.
Erlang? Hetkinen? Kuulostaa 80-luvulta? Erlang on Ericssonilla kehitetty kieli puhelinverkkoja varten, jonka lähdekoodi avattiin 1998. Erlang voi jo syntaksinsa osalta vaikuttaa vieraalta monille koodareille. Oleellisinta Erlangissa ei kuitenkaan ole itse kieli vaan virtuaalikone BEAM, jossa ohjelmakoodi ajetaan.
Elixir-koodi käännetään Erlang -tavukoodiksi ja ajetaan virtuaalikoneessa, kuten vaikkapa Scala tai Clojure Java-virtuaalikoneessa. Samoin kuin Scala voi hyödyntää olemassaolevia Java-kirjastoja, voi Elixiristä kutsua suoraan Erlang-kirjastoja. Elixir itse on kohtuu tuore ohjelmointikieli (Elixir 1.0 vuonna 2014, Phoenix 1.0 vuonna 2015 [edit]), mutta se voi hyödyntää 20 vuoden kehitystyötä <em>vikasietoisten</em> ja <em>skaalautuvien</em> järjestelmien kehityksestä.
Suosittelen Phoenixiin tutustumista oikeastaan kaikille (palvelinpuolen) webkehityksen ammattilaisille. Se tarjoaa hyvin suunnitellun, toimivan ja läpinäkyvän kokonaisuuden, jonka kanssa on helppo päästä alkuun, mutta tarjoaa valtavasti muutakin. Enkä edes maininnut suorituskykyä vielä (ennätys lienee edelleen 2 miljoonaa yhtäaikaista websocket-yhteyttä yhdellä palvelimella).
Elixir ja sen perustana oleva Erlang virtuaalikone tarjoaa paljon opittavaa ja mahdollisuuksia muillekin kehittäjille. Esimerkiksi Nerves-projekti tuo sulautetut järjestelmät käden ulottuville, vaikka laitteistopuoli ei vielä muuten olisikaan kovin tuttua.
Elixir, Phoenix Framework, Erlang VM. Kannattaa laittaa teknologiatutkalle, jos eivät siellä vielä ole.
Aloin pari vuotta sitten kirjoittaa pientä kirjaa mind mappayksestä eli miellekartoista, mutta projekti jäi aina syystä tai toisesta muiden asioiden jalkoihin. Tänä keväänä sain sen vihdoin pakettiin ja julkaistua.
Toistuva piirre, jonka keskusteluissa kirjan tiimoilta olen huomannut on se, että monet käyttävät karttoja lähinnä kertaluontoisina juttuina. Suurin osa on ainakin kuullut miellekartoista ja monet kokeilleetkin, mutta harva käyttää niitä järjestelmällisesti päivittäisenä työkaluna.
Miellekartoilla tehdään muistiinpanoja tai brainstormataan, joskus järjestellään olemassa olevaa tietoa rakenteelliseksi kokonaisuudeksi. Otokseni on vielä kovin pieni, mutta karttojen yhdistely toisiinsa yhtenäiseksi kartastoksi vaikuttaisi monille vieraalta ajatukselta. Kulmakarvoja nostelee myös ajatus, että kartat voisivat olla kertakäyttöasian sijaan jatkuvasti muuttuvia ja eläviä työkaluja, jotka pysyvät hengissä vuodesta toiseen.
Yksi syy karttojen kertakäyttöisyyteen voi löytyä itse mind map ohjelmistoista – ja nyt puhun digitaalisista kartoista, en kynäpaperisellaisista. Ne eivät varsinaisesti tue kovin hyvin kartasto-ajatusta. Esimerkiksi Freemind, joka puutteistaan huolimatta on suosikkiohjelmani, mahdollistaa kyllä linkkauksen kartasta toiseen, mutta visuaalista kuvaa näiden linkkien muodostamasta verkostosta ei käyttäjä näe, vaan se pitää kuvitella itse.
Vaikka eräänlainen ihme ja pohdinnan aihe on se, että pystymme ylipäänsä mielessämme ymmärtämään erilliset palaset kartastona, niin eiköhän datan visualisointi voisi olla paikallaan. Auttaisihan se ainakin keventämään omaa kognitiivista kuormaa, jos ei sitten viestimään kartaston saloja muille.
Aloin jo vuosia sitten järjestelmällisesti linkkaamaan miellekarttani toisiinsa, joten niitä oli kasaantunut jo kokoelmaksi asti. Alkuvaiheen innoittajana oli muistipalatsi-muistamisjärjestelmä, jossa mieleen painettavat asiat sijoitetaan mielessä rakennukseen, jonka huoneesta toiseen kulkemalla voi muistaa sinne talletetut asiat. Kartat olivat minun huoneitani ja linkit ovia huoneesta toiseen.
Jokainen kartta on eri tiedostossa. Punaiset nuolet ovat karttoja yhdistäviä linkkejä, joista voi siirtyä huoneesta toiseen. Kartat ja niiden väliset yhteydet muodostavat verkon, mutta se pitää tässä itse kuvitella – tai piirtää käsin kuten alimmassa kuvassa on tehty: käytävä yhdistää huoneet, huoneen keskusnuolesta pääsee takaisin ‘käytävään’ ja toimistosta on yksisuuntainen yhteys kirjastoon.
<map version="1.0.1">
<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net -->
<node CREATED="1470757729087" ID="ID_1057651209" MODIFIED="1470757763121" TEXT="Kartasto">
<node CREATED="1470757852521" ID="ID_1131565593" LINK="Kirjasto.mm" MODIFIED="1470757852522" POSITION="right" TEXT="Kirjasto"/>
<node CREATED="1470757858377" ID="ID_1998336246" LINK="Toimisto.mm" MODIFIED="1470757858382" POSITION="right" TEXT="Toimisto"/>
</node>
</map>
Freemind tallentaa miellekartat xml-tiedostoon
Verkosto koostuu solmuista (node, vertex) ja näitä yhdistävistä kaarista (edge). Mahdollisia ohjelmallisia toteutustapoja on useita, mutta yksinkertaisin lienee solmupareista koostuva kaarilista.
Pythonilla olin tottunut tekemään komentoriviskriptejä datankäsittelyyn liittyen, joten sillä sain kaivettua xml-tiedostoista listan, jossa oli noin 1000 linkkiä 600 kartan välillä. Datan tallensin csv-tiedostoon, jossa oli kaksi saraketta: lähde- ja kohdesolmu, joiden merkitsijänä toimi karttatiedoston polku levyjärjestelmässä. Tällä pitäisi päästä alkuun.
Pääsin pitkästä aikaa käyttämään verkostoanalyysiohjelma Gephiä. Olen aiemminkin käyttänyt sitä onnistuneesti visualisoimaan miellekarttadataa (ks. Datatiedetaiteilua) ja mm. Facebook-kaveriverkostoani. Se oli helppo työkaluvalinta.
Gephi sai luotua linkkilista-tiedostoni pohjalta verkoston ja visualisoitua sen kohtuu järkevän näköisesti ruudulle. Minulla ei kummoisia ennakko-odotuksia tai hypoteeseja ollut siitä mitä tuleman pitää, vaan lähestyin aihetta eksploratiivisesti, katsoen mitä tulee vastaan ja seuraten uteliaisuuttani. Hiiren osoittimella sain tutkittua mikä kartta on missäkin ja miten se liittyy toisiin.
Data ladattuna Gephiin
Verkosto automaattisen asettelun jäljiltä
Sivuhuomioita
Gephi bugitti hieman, mutta osasin kyllä odottaa sitä… Kubuntu 16.04:lläni Gephin editorinäkymä ei mistä lie johtuu toiminut alkuunkaan, vaan vaati käynnistysvaiheeseen joidenkin taikasanojen googletusta. Jouduin myös tässä välissä myös viemään verkostomallin gexf-muotoon ja tuomaan takaisin gephiin, muuten meni koko kone jumiin joissain toiminnoissa. Olisikohan csv-tiedoston sisäänluvussa jotain bugeja.
Verkoston silmämääräinen tutkiminen nopeasti oli vaikeaa ilman selkokielisiä kartan nimiä (nyt oli vain /home/user/bling/blong.mm). En ollut poiminut karttojen nimiä mukaan – datassanihan oli ainoastaan tiedostopolkujen nimet. Lisätiedon tuominen Gephiin tarkoitti kuitenkin sitä, että jouduin tuomaan solmulistan tietoineen erikseen ohjelmaan. Pelkkä kaarilista ei enää riittänyt.
Yhdistin lähde ja kohde -solmut ensin tekstieditorissa yhdeksi listaksi ja poistin säännöllisellä lausekkeella polkuosan tiedostonimestä. Lämmittelin myös hieman datansiivoustyökalu Open Refineä, jolla poistin duplikaatit nimilistasta. Tämän jälkeen luin syntyneen solmutaulukon (tiedostopolku + nimi) uudeksi projektiksi Gephiin ja luin perään vanhan linkkilistan. Nyt sain linkkilistan tiedostopolut kohdistettua luettavampiin nimiin.
Nyt minulla oli perusrakenne visualisoituna, mutta kuva kaipasi lisää informaatiota. Gephillä verkostosta voi laskea tunnuslukuja, jotka sitten koodataan visuaalisten elementtien ominaisuuksiksi, esimerkiksi kokoa ja väriä muuntelemalla.
Erityisesti kaipasin modulaarisuuden laskentaa, jonka avulla saa värjättyä verkon osiin jotka ovat sisäisesti suhteellisen paljon toisiinsa linkittyneitä. Verkon muotoilua varten on tarjolla useita eri menetelmiä. Palluroiden koot tässä kuvassa kuvaavat eigenvector centrality -arvoa, joka kuvaa solmun eli kartan keskeisyyttä ja tärkeyttä verkostossa (tietoa karttojen sisäisestä koosta minulla ei tässä ollut). Paksummat kaaret tarkoittavat karttojen välillä olevan useamman linkin, todennäköisesti yksi molempiin suuntiin.
Verkosto ryhmiteltynä, painotettuna ja värjättynä
Kuvan viennin Gephistä tein svg-muodossa, sillä en ainakaan keksinyt miten png-muodosta saisi riittävän isoa tarkoituksiini. Svg:tä taas voin suurentaa laadun kärsimättä niin paljon kuin haluan.
Kuvassa iso vihreä pallo on keskuskartta, joka on jo vuosia toiminut muita karttoja yhdistävänä päähakemistona. Sen ympärillä on useita väliaikaisempia hakemistoja, joita kutsun aikaikkunoiksi. Ne toimivat kotikarttoina, lähtöruutuina jotka keräävät yhteen ajankohtaiset tärkeät aiheet ja kartat, yleensä 3–12 kuukautta, minkä jälkeen avaan uuden aikaikkunan. Violetti alue on teknologiaan liittyviä karttoja, esimerkiksi ohjelmistokehitykseen ja data-analyysiin liittyen. Harmaa taas on kirjastoalue, jossa on sekalaisempaa tietoa ja muistiinpanoja perinteisellä kirjastojärjestelmän jaottelulla.
Kovin syvälle verkoston analyysiin menemättä voi kuvasta tehdä heti muutaman huomion. Rakenne on melko itsestään syntynyt ajan myötä, ilman suurta suunnittelua. Vanhemmat kartat ovat kuvan oikeassa laidassa hieman erillään muista. En vielä silloin linkittänyt karttoja kovin aktiivisesti toisiinsa. Toisaalta irrallisuus saattaa tarkoittaa myös rikkoutuneita linkkejä karttojen välillä.
Pitkien polkujen päässä olevat kartat ovat käytännössä kadonneet: niihin eksyminen linkkejä seuraamalla on todella epätodennäköistä (tätä voisi jatkossa tutkia vaikkapa pagerank-tunnusluvun avulla). Joskus nämä ovatkin kertakäyttökarttoja, joilla ei juuri käyttöarvoa enää ole. Toisinaan kuitenkin myös käyttökelpoisia karttoja katoaa, esimerkiksi joidenkin kurssien tai tapahtumien muistiinpanoja. Kokonaiskuvan avulla pystyn tutkimaan myös näitä kartaston reuna-alueita.
Miellekartaston kanssa työskennellessä minulla ainakin pätee sama kuin verkkosivuilla tietoa etsiessä: kovin montaa klikkausta en ole valmis tekemään tiedon löytämiseksi. Jo näiden muutaman uudesta kuvasta tehdyn havainnon perusteella pystyn ohjaamaan karttojen kanssa työskentelyäni jatkossa sujuvammaksi. Näen, että tietyt kartat olisi hyvä linkata suoremmin toisiinsa, jotta ne saisi paremmin jokapäiväiseen käyttöön.
Entä sitten jatkossa? Jo nyt visualisoinnin pohjalla oleva data on vanhentunutta. Aionko tehdä saman työn manuaalisesti jatkossakin? Toivottavasti en kovin montaa kertaa. Etenkin alkuvaiheen tiedonputsausvaiheen voisi suhteellisen helposti ohittaa tiedonkeruukoodia kehittämällä. Samalla yksittäisistä kartoista voisi kerätä enemmän tietoa analyysiä varten, esimerkiksi solmujen lukumäärästä ja karttojen syvyydestä tai vaikkapa muutospäivämääristä.
Muodostaa datan sitten käsin tai automaattisesti, tällaista päälleliimattua kartaston tarkastelua kuitenkin rajoittaa pohjalla oleva tietomalli. Tietokannassahan tämä kaikki pitäisi olla eikä erillisissä tiedostoissa ympäri järjestelmää. Itse tiedon lisäksi tietoa voisi kerätä tiedon muutoksista. Samoin voisi linkkien olemassaolon lisäksi saada tilastoja myös niiden klikkauksista. Ja tämän tulisi tietenkin olla osa mind map ohjelmistoa, jotta visualisointia voisi käyttää suoraan esimerkiksi kartaston navigointiin. Kukapa tekisi sellaisen?
Olin tänä vuonna toista kertaa mukana kyläkirjan kirjoittamisprojektissa. Minun tehtäväkseni jäi tekstien editointi ja viimeistely, sekä lopullisen painovalmiin kirjan taittaminen. Edellisen kirjan taitoin Wordilla ja tämän kirjan LyXillä (vertaa pdf-näytteet Word / LyX ). Toki typografinen silmä on tässä parin vuoden aikana muutenkin hieman kehittynyt, mutta iso osa taittojäljestä menee kyllä taitto-ohjelman piikkiin.
LyX on taittojärjestelmien veteraanin, tekstipohjaisen LaTeX -järjestelmän päälle tehty käyttöliittymä. Se on WYSIWYM-tyyppinen editori – What you see is what you mean. Kirjoittaessa näkyvä teksti ei yritäkään vastata tarkasti lopputulosta, kuten esimerkiksi Wordissa, vaan ulkoasu erottelee lähinnä rakenteelliset seikat toistaan kirjoittajaa varten: tämä on otsikko, tämä on leipäteksti, tämä alaviittaus. Valmiin näköisversion voi milloin tahansa pulauttaa pdf-muodossa tarkasteltavaksi.
Olin jo aiemminkin käyttänyt LyXiä tekstin tuottamiseen ja editointiin, mutta painovalmista materiaalia en sillä vielä ollut tuottanut.
LyXin valintaan johti useampia seikkoja. Ensinnäkin, yksinkertaisesti pidän sen editointimoodista. Häiriötön tila, jossa ruudulta on piilotettu kaikki muu paitsi yksi kapea tekstipalsta keskellä, toimii hyvin. Muokkain huolehtii automaattisesti pikkuasioista, kuten poistaa ylimääräiset välilyönnit ja rivinvälit – pieni mutta yllättävänkin arvokas yksityiskohta.
Kyläkirjan koostaminen tarkoitti usean eri kirjoittajan eri ohjelmilla kirjoittamien tekstien kokoamista yhtenäiseen muotoon. Kyllähän Wordissäkin tyylit on mahdollista säätää kohdilleen, mutta kertaluokkaa helpompaa se oli LyXin kanssa.
LyXin oma tallennusmuoto on tekstipohjainen, joten sen voi hyvin tallentaa versionhallintaan. Versiohallinta osoittautuukin arvokkaaksi monessa paikassa, kuten ohjelmavirheitä selvittäessä (kyllä, niihin todennäköisesti törmää) ja varmistaessa, ettei vahinkomuutoksia ollut päässyt tapahtumaan. 250-sivuisen kirjan kanssa saa olla jo aika tarkkana.
Katselmointiakin varten LyX olisi ehkä voinut toimia, mutta päätin kuitenkin käyttää siihen tarkoitukseen säännöllisesti tuotettua pdf-versioita ja sen kommentointia.
Olen koittanut teknisten juttujen lisäksi myös tutustua hieman graafiseen suunnitteluun ja erityisesti typografiaan. Vaikken mikään sankari sillä saralla vielä olekaan, niin olen ainakin oppinut arvostamaan kirjan taittamiseen vaadittavaa taitoa ja tarkkuutta.
LyXissä tämä muiden typografinen osaaminen on tiivistynyt asiakirjamalleihin: jos kirja on jäsennelty hyvin, tapahtuu itse taittaminen automaattisesti. Valmiit pohjat tuntuvat keskittyvän tieteelliseen kirjoittamiseen, mutta myös kaunokirjallisuuteen sopivia asiakirjaluokkia on tarjolla. Tähän kirjaan valitsin Koma script book -mallin.
Luotin pääasiassa asiakirjamallin vakioasetuksiin tekstin osalta. Kirjasimia vaihdoin ja aivan muutamassa kohdassa jouduin turvautumaan LaTeX-koodeihin viimeisessä viimeistelyvaiheessa. Tämäkin lähinnä koski kirjan alkuun ja loppuun tulevia erikoissivuja. Taiton puolesta eniten työtä oli kuvien asettelussa. Ne piti saada kuvateksteineen upotettua siististi tekstin joukkoon. Wordin kanssa en sitä tosin olisi lähtenyt edes yrittämään…
LyX-dokumenttiin liitetyt kuvat ovat linkattuina tiedostoihin levyllä, joten niihin oli helppo tehdä muutoksia erikseen kuvankäsittelyohjelmalla. Ajoin kaikkiin kuviin painoa varten tarvittavia peruskorjaustoimenpiteitä, kuten muunnokset mustavalkoiseksi ja sävyalueen laajennuksen.
Lopuksi pdf:n sai pulautettua ulos ja se meni painoon sellaisenaan.
Sähköisestä kirjasta tuli kolme muotoa: pdf-näköiskirja sekä epub- ja mobi-formaatit. LyXin tuottama pdf kävi melkein sellaisenaan näköiskirjaksi. Vain kuvatiedostot piti pakata pienemmäksi ja kansilehdet piti lisätä.
Varsinaiset e-kirjaversiot, Amazon Kindlen mobi-versio ja yleisempi epub, vaativat hieman odottamaani enemmän työtä. Ne sain sain kuitenkin tehtyä Calibre-ohjelman avulla. LyXistä sai kirjan ulos xhtml-muodossa, joka taas kelpasi Calibrelle pohjaksi. Korjaukset tehtiin Calibressa html- ja css-tiedostoihin, joista ohjelma rakensi epub- ja mobi-tiedostot.
Kirjoittelin keväällä Pollen-järjestelmästä ja kirjan taittamisesta selainluettavaksi. Sanoin, että Pollen voisi toimia valmiin kirjan julkaisemiseen webissä. Tämän kirjan osalta selainluettava versio sai nyt kuitenkin jäädä tekemättä, ainakin toistaiseksi. Tietokoneella voi kuitenkin lukea pdf-versiota ja myös erillisen lukuohjelman avulla e-kirjaversioita.
Web-taittamisessa on ongelma, jota ei jostain syystä ole vieläkään kunnolla yleisesti ratkaistu: sivutus. Jos luet tavallista kirjaa, on katse helppo siirtää sivun lopusta seuraavan sivun alkuun. Netissä taas joudut selaamaan ruutua alaspäin, mikäli se ei mahdu ruudulle. Tällöin kuitenkin hukkaat todennäköisesti tarkan kohdan josta lukemista pitäisi jatkaa. Pitkän tekstin lukeminen selaimessa on raskasta. Toinen syy lukemisen raskauteen on ruudun tuijottaminen: paperin – tai taustavalottoman lukulaitteen – lukeminen on silmille huomattavasti ystävällisempää kuin kirkkaan ruudun tuijottaminen.
Olin pääosin tyytyväinen LyXin kanssa työskentelyyn. LaTeXia jouduin vähän opettelemaan, mutta alkukynnyksen jälkeen se ei kuitenkaan osoittautunut ylipääsemättömäksi suoksi. Heikkohermoisimmille LyXiä ei kuitenkaan voi suositella, mutta jos teknistä tuunauskestävyyttä löytyy niin mikä ettei. Ei se mitään rakettitiedettä varsinaisesti ole.
Aion seuraavankin kirjan taittaa LyXillä.
Olen lähestynyt aihetta kahdesta näkökulmasta. Yhtäällä aloin selvittää miten toteuttaa selainkäyttöinen online-kirja Pollenin avulla, edeten vähitellen syvemmälle kohti Racketin yksityiskohtia. Toisaalla lähdin rakentamaan tätä sivustoa uudestaan suoraan Racketin ruuveista ja muttereista, ajatuksena oppia minulle uusi kieli nopeammin ja liittää Pollen mukaan järjestelmään sisällön muotoilu- ja esitysvaiheessa.
Kaksi näkökulmaa – top-down ja bottom-up — tarjoavat eräänlaisen hampurilaislähestymisen siis. Etenen vastakkaisista suunnista kohti keskustaa, jossa toivon polkujen kohtaavan ja minulle selviävän mikä on homman pihvi.
Pöytälaatikossani on pitkään ollut kirjaluonnos, jonka loppuunsaattamista olen viivytellyt jo hyvä aikaa. Sain taas hyvän tekosyyn viivytellä lisää ja alkaa sisällön viimeistelyn sijaan tehdä kirjasta selainversiota Pollenilla. Kirjan vedoksen olin tehnyt LyX-ohjelmalla. Kirjoittaessa olin vielä onnellinen, mutta tullessani muotoiluvaiheeseen koin törmänneeni seinään. Etsin vaihtoehtoista työkalua työn loppuun viemiseksi, ja tässä minulla oli uusi ehdokas.
Pollenin “kirja on ohjelma” -näkökulman mukaan jokaista (html-)sivua vastaa oma ohjelmakooditiedostonsa. Nämä ovat tallennettu tiedostojärjestelmään, hakemistorakenne vastaten url-rakennetta. Tämä tuulahdus 90-luvulta aiheutti minulle pienen kynnyksen aluksi, mutta jatkoin kuitenkin eteenpäin. Otin tekstin, pilkoin sen luvuittain Pollen-tiedostoihin ja määrittelin sisällysluettelon erilliseen tiedostoon. Kunhan niitä tiedostoja ei vain tarvitsisi siirrellä ja nimetä uudelleen kovin usein jatkossa…
Pollen-tiedostot eivät ole perinteisiä sivupohjia, vaan omia suoritettavia ohjelmiaan. Html-sivuja luodessaan järjestelmä tekee tiedostoille kaksi läpikäyntiä. Ensin käydään läpi sivuston rakenne ja metatiedot. Tämän avulla rakennetaan esimerkiksi automaattinen sisällysluettelo ja navigaatio. Sen jälkeen luodaan html-tiedostot ja homma on valmis.
Tekstisisältöä voi halutessaan rikastaa pollen-kielen avulla. Sivulla olevan sisällön voi ajaa itsemääriteltyjen käsittelyrutiinien läpi tai mukaan voi tuoda kirjan muihin osiin liittyvää tietoa ja sisältöä. Käsittelijä voi esimerkiksi muuntaa rivivaihdot kappalemerkeiksi tai rakennetiedoista voi kaivaa seuraavan luvun linkin ja otsikon.
Sain toteutettua mitä tavoittelinkin: kirja pelkistettynä websivustona. Kirjassa on yksinkertainen käyttöliittymä, jossa visuaalisuus on lähinnä typografialla pelaamista. Käytettävyyttä on lisäksi hieman höystetty Javascript-toiminnoilla, kuten kirjan selauksen mahdollisuus nuolinäppäinten avulla.
Racketissa innosti yksinkertaisuus. Kun päätin kirjoittaa Clojurella toteutetun blogini uudestaan Racketilla, se onnistui varsin sujuvasti yhden lähdekooditiedoston avulla. Jaottelin sen toki myöhemmin loogisiin komponentteihin, mutta havahduin kuitenkin siihen kuinka yksinkertaista se oli. Alkuunpääsyn helppous Clojureen verrattuna oli huomattava, vaikka oli niitä turhautumisia Racketinkin kanssa luvassa aivan riittävästi.
Kirjoitin blogini sivupohjat käyttäen Racketin oman html-kirjaston template-toimintoa. Varmistin ensin, että saan tehtyä sivuston toimimaan kuten ennenkin, ja vasta sen jälkeen aloin miettiä miten Pollenin saisi tuotua mukaan kuvioon.
Pollenia ei nähtävästi ole suunniteltu käytettäväksi erillisenä kirjastona, ja sen integroiminen omaan blogiin osoittautuikin huomattavan hankalaksi Racket-tulokkaalle. Olin tottunut perinteisiin sivupohjiin, jossa sivurakenne määritellään yhdessä paikassa ja sisältö tuodaan mukaan rakenteeseen sijoitettujen muuttujien kautta. Pollen-tiedostot ovat kokonaisia suoritettavia ohjelmia, jotka pitäisi suorittaa omassa hiekkalaatikossaan. Sinänsä mielenkiintoista ja jännittävää selvitellä miten tämä käytännössä tapahtuisi, mutta tovin jos toisenkin ihmeteltyäni päätin tällä erää heittää pyyhkeen kehään blogi-integraation osalta.
Tämän kokemuksen perusteella Pollenin pihvi on koko ohjelmointikielen voiman hyödyntäminen yksittäisen html-sivun latomiseen. Sivupohjansa tuntevilla saattaa tässä kohtaa nousta karvat pystyyn: eikö ole täysin vastoin parhaita käytäntöjä sallia ohjelmakoodi vapaasti sivupohjassa? Tämä oli minunkin ensireaktio, kunnes tajusin, että rajoitettujen syntaksien taustalla on muunmuassa oletus siitä, että kuka tahansa voi kirjoittaa tekstikenttään selaimen kautta sisältöä ja muotoiluja. Entä jos kirjoittaja onkin tiedossa, luotettu henkilö ja tietää mitä on tekemässä? Onko tällaisen henkilön luovia mahdollisuuksia tarvetta keinotekoisesti rajoittaa?
Järjestelmä on parhaimmillaan sisällöltään valmiin kirjan latomiseen staattisiksi html-sivuiksi. Ja siihen se ilmeisesti on tarkoitettukin. Järjestelmä ei sen sijaan ole parhaimmillaan mikäli on tarvetta sisällön jatkuvalle työstämiselle tai kirjan liittämiselle osaksi olemassaolevaa järjestelmää. Kirjan rakenne on kiinteästi sidottu tiedostojärjestelmän rakenteeseen, ja tarve parametroidun tulostamisen sijaan suorittaa sivu kokonaisena ohjelmana aiheuttaa omat mutkansa integroinnille.
Ohjelmistokehittäjänä kaipaisin monoliitin sijaan selkeätä kirjastoa, jonka voisin liittää omaan projektiini. Pollen on nyt vähän kaikkea. Oma buildaussysteemi, webipalvelin ja sivupohjasysteemi. Ymmärrän sen olevan kokonaisuus, mutta ei kuitenkaan sitä mitä haluan. Parasta siinä on nimenomaan Racketin mahdollistama oma täsmäkieli dokumenttien määrittelyyn. Muut osat jäävät vähän puolitiehen, mikä on harmi, sillä nämä ovat kuitenkin muualla jo kohtuullisen hyvin ratkaistuja ongelmia.
Kenelle sitten suosittelisin Polleniin tutustumista? Tässä vaiheessa lähinnä jos olet kiinnostunut sekä ohjelmoinnista, webjulkaisusta että typografiasta, ja mikään julkaisualusta ei ole sinulle vielä ollut riittävän hyvä. Pollen tarjoaa uutta näkökulmaa – vanhat kyseenalaistaen – ja ideoita siitä mihin suuntaan teknologiaa voisi kehittää. Minulle siihen tutustuminen on tuonut huimasti uutta näkemystä webjulkaisuun ja siihen liittyvien järjestelmien vaatimuksiin.
Taidanpa jäädä kanavalle.
Olin vasta päässyt vauhtiin Clojuren kanssa ja kuvitellut, että minun tuskin tarvitsisi opetella uusia ohjelmointikieliä taas vähään aikaan. Lisp-fobiasta selvinneenä ja koodisulkeisiin vähitellen tottuneena alkoi mieleen hiipiä kuitenkin ajatus, että ehkä Clojure olikin vain alku.
Lokakuussa olin poikennut Tampereella ClojuTRE-tapahtumassa. Tilaisuus sinänsä oli huikea näyttö Suomen Clojure-skenen draivista. Tämän tarinan osalta oleellisinta oli kuitenkin se, että ensimäinen henkilö, johon siellä tutustuin, olikin Racket-koodari. Kieli oli tullut vastaan myös Cognicast-podcasteissa, mutta vasta nyt alkoi hahmottua mikä tämä Scheme-johdannainen lisp oikeastaan on, ja miksi se sattaisi olla oikea työkalu joihinkin tehtäviin.
Pollen ei todellakaan ole mikään jokamiehen kliksutteluratkaisu, vaan enemmänkin julkaisijanörtin työkalu. “Kirja on ohjelma” on järjestelmän isän, Matthew Butterickin, näkemys. Typografina hänelle ei riitä sisällön printtaaminen valmiisiin sivupohjiin, vaan hän haluaa maksimoida vapauden sivun muotoiluun ja asetteluun. Ohjelmointitaitoja siis tarvitaan. Kun selvisi, että Pollen on kirjoitettu nimenomaan Racketilla, sain itselleni riittävästi tekosyitä tutustua taas yhteen uuteen ohjelmointikieleen.
Olen yrittänyt kääriä päätäni Pollen-systeemin ympärille ja kokeillutkin sitä jo parilla sivustolla. Ensituntumalta ratkaisu tuntuu hieman erikoiselta monella tavalla. Sekoitetaan syntaksia, semantiikkaa ja logiikkaa, ja lispin myötä soppa vain sakenee. Toisaalta Racketissa, kuten lispeissä yleensäkin, koodi ja data tuppaavat muutenkin sekoittua yhdeksi muovailuvahaksi. Pollen tuo esiin myös muita Racketin vahvuuksia, kuten oman täsmäkielen (DSL) luonnin.
En oikein vielä ymmärrä täysin mikä Pollen oikeastaan on. Staattinen sivugeneraattori? Template-kieli? Jokumuumikä? Tätä selvittääkseni päätin — mitäpä muutakaan — kirjoittaa tämän blogin uudestaan Racketilla ja katsoa pystynkö näkemään siinä saman potentiaalin kuin Butterick.
##Linkit
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.
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.
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.
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.
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.
Tarkoitus alusta asti oli saada sovellus Play-kauppaan asti ja oppia miten homma toimii. Mahdollisimman yksinkertainen sovellus, jonka saa valmiiksi nopeasti. Ehtii niitä sitten iteroida. Sovelluksen rakentaminen oli suoraviivaista kohtuullisen hyvien ohjeiden avulla. Valmistelu ja paketoiminen kauppaa varten vaati enemmän selvittelyä kuin odotin, mutta tämä työmäärä on toki huomattavasti pienempi seuraavalla kerralla.
Mutta siellä se nyt on: NumberVision, eräänlainen visuaalinen aivojumppaharjoitus. Ei kovin kummoinen, mutta jostain sitä pitää aloittaa.
Androidia ohjelmoidaan Javalla. Kieli oli minulle tuttu, vaikken sitä useampaan vuoteen ollutkaan koodaillut. Nopeastihan se palasi mieleen. Kieltä sinänsä en hirveästi ole kaivannut, mutta montaa siihen liittyvää asiaa kyllä: hyvä editori, ohjelmakirjastot sekä projektin/riippuvuuksien hallinta.
Android Studio on IntelliJ-johdannainen kehitysympäristö, joka on ilmeisesti syrjäyttämässä, jos ei vielä syrjäyttänyt, Eclipsen Android-keityksessä. Tähän mennessä toiminut loistavasti, ei mitään valittamista. Mitä nyt shortcutit joutuu taas opetella uudestaan. Android-kirjastojen lataaminen, sovelluksen testaaminen ja debuggaus puhelimella ja emulaattoreissa on toiminut pääosin hyvin.
Tein viitisen vuotta sitten pieniä selainsovelluksia GWT:llä (Google Web Toolkit). GWT on/oli myös Google-lähtöinen, Java-pohjainen alusta, ja olin huomaavinani paljon yhtäläisyyksiä. Android-frameworkin kanssa pääsin tosin huomattavasti nopeammin vauhtiin ja koko kuvio tuntui yksinkertaisemmalta. Napit ruutuun graafisella editorilla, klikinkäsittelijät paikoilleen, siirtymät toiminnosta toiseen, done. Pääpiirteittäin siis. Sovelluksen ensimmäiseen versioon käytin toki vain murto-osaa Androidin ominaisuuksista, enkä yhtään ulkopuolista ohjelmakirjastoa Google Play SDK:ta lukuunottamatta.
Projektit pidetään koossa Gradlen avulla, ja hyvin tuntui toimivan buildaukset ainakin pienessä mittakaavassa. Mavenia olen aiemmin käyttänyt Javalla tähän, mutta en ainakaan vielä sitä kaivannut. Muutamia muutoksia HelloWorld-pohjaan, ja perushomma toimi ilman sen syvällisempää Gradle-ymmärrystä.
…
Kokonaisuudessaan varsin positiiviset tunnelmat ensimmäisen kuukauden jälkeen. Tärkein positiivinen tekijä lienee hyvä IDE-tuki. Se on toistaalta myös pakollinen, sillä käännös/lataus-sykli on hidas. Editori onneksi poimii suuren osan virheistä lennossa.
Tilin luonti Play-kauppaan ja tietojen syöttö oli suht helppoa. Signeeratun sovelluspaketin lähettämisen jälkeen meni jokunen tunti, niin sovellus ilmestyi kauppaan. Ensimmäisenä päivänä tuli yksi lataus. Mitään markkinointiakaan ei tosin tehty, joten tilanne lienee jo kuten verkkosivujenkin kanssa: ei niitä kukaan löydä ellei niistä pidä meteliä. Taitaa sitä kuitenkin ihan töitä joutua tekemään, jos appseilla aikoo elantonsa tienata.
Olen pitkään etsinyt itselleni mieluista työkalua selainpohjaisten sovellusten tekemiseen, sellaista vielä löytämättä. Lähimmäksi lienee päässyt Node.js -framework DerbyJS, mutta se on ollut hieman turhan nopeasti liikuva maali minun makuuni. Toinen ehdokas on ollut Scala.js. Olen säännöllisesti palannut Scalan pariin, mutta hieman turhautunut mm.ide- ja versioyhteensopivuusongelmiin.
Haluan jotain uutta.
Paras tapa oppia uutta on ajankohtainen, itseä kiinnostava ja itse valittu sovelluskohde.
Yksi houkuttelevista asioista Clojuressa oli JavaScriptia tuottava ClojureScript ja React.js:n päälle rakennettu Om-kirjasto reaktiiviseen ohjelmointiin. Aloitin Om-kirjaston tutoriaalilla ja proof-of-conceptina porttaamaan erästä keskeneräistä Derby-projektiani. ClojureScript-tutoriaalista opettelin Clojuren syntaksia ja perustietorakenteiden käyttöä. Om-kirjaston kanssakin pääsin jo alkuun, mutta tarvitsin ensin jotain tutumpaa.
Päätin lämmittelyharjoituksena ensin portata Julialla tekemäni blogigeneraattorin Clojurelle. Hyvät palikat löytyivät helposti kevyellä googletuksella: Ring (HTTP), Compojure (routing), Enlive (template), Yesql (kevyt SQL) sekä Leiningen (projektin ja rippuuvuuksien hallinta). Eniten päänraavintaa aiheutti Enliven template-tyyli, vaikka css-valitsimiin ja dom-muunnoksiin olin jo aiemmin törmännyt Scala/Lift -kehityksessä. Muuten sain homman tehtyä melkeinpä kirjastojen readme-ohjeiden avulla.
Tämä blogi generoituu nyt Clojurella.
Viime vuoden uusi kieli oli Julia, jolla tämänkin blogin aiemmin generoin. Haaveilin sen yhdistävän kaksi pääaluettani, webin ja datan. Ehkä se vielä jonain päivänä sen tekeekin, mutta en jää pidättämään hengitystäni. Julian kanssa näin mahdollisuuksia tulevaisuudessa. Clojuren kanssa koin käytännön hyödyt ensikokeilulla. Vertailu ei tietenkään ole reilu, sillä Julia on vielä beta-vaiheessa. Clojure on kuitenkin webialustana yksinkertaisesti valovuosia sitä edellä, enkä minä taida nyt olla se oikea henkilö raivaamaan Julia-latua eteenpäin. Clojuren soveltuvuudesta datan käsittelyyn ja analysointiin en vielä osaa antaa arviota.
Paluu funktionaaliseen kieleen oli myös tervetullut muutos. Julia tukee funktionaalistakin tyyliä, mutta käytännössä ohjelmointi on pitkälti imperatiivista, päämotivaationa optimaalinen suorituskyky. Blogin Clojure-version koodissa ei ole tällä hetkellä yhtään muuttujaa, enkä missään vaiheessa vielä edes kaivannut sellaisia. Funktionaalisuus sinänsä oli jo ennestään tuttua. Scalaa on tullut koodattua ja Haskelliakin vähän ihmeteltyä. Olen aikoinaan koodaillut koulussa Lisp-johdannaista Schemeä, mikä varmasti nopeutti omaksumista. Ei se niin vieraalta lopulta tuntunutkaan.
Hurahdin nopeasti hommaan ja pian huomasin asentaneeni Emacsinkin taas koneelleni. Tärkeimmät näppäinyhdistelmät palasivat 15v tauon jälkeenkin hämmentävän nopeasti mieleen. Aikoinaan en Schemestä varsinaisesti innostunut, mutta nyt Clojuren kanssa kävi toisin. En edes muista milloin minulla on viimeksi ollut yhtä kivaa ohjelmoidessani.
Oppimiskokemuksena Clojure on ollut hyvin positiivinen yllätys. En ole minkään muun kielen kanssa päässyt yhtä nopeasti vauhtiin ja tuottavaksi. Toki uusien kielten opettelu helpottuu kokemuksen myötä muutenkin, mutta työkalujen ja dokumentaation laatu on ollut poikkeuksellista. Kaikki on tähän mennessä ollut yllättävän toimivaa ja valmista.
Linkit
Totesin siinä, etten ole tainnut koskaan itse kirjoittaa blogin sivutustoimintoa, vaan aina on cms:ssä ollut valmiina tai edes frameworkissa sivutus-komponentti. “No, puolen tunnin juttu”, ajattelin. Varmistin, että minulla on puolen tunnin työn vaatimat kaksi tuntia aikaa vapaana, ja aloitin työt.
–
Toimintona sivutus on jokseenkin yksinkertainen, ja pystyinkin rakentamaan sen ensin mielessäni melkein kokonaan: dynaamiseksi url-parametriksi sivun numero (tyyliin ?page=2), joka parsitaan kontrollerissa ja jonka avulla lasketaan tietokantahaun offset. Itse sivulla näkyvän valitsimen toteutukseen prev/next -nappuloineen ei ollut niin selkeää ajatusta. Twitter bootstrap tarjoaa visuaalisen komponentin, mutta sen generointi datan perusteella vaatisi hieman kokeilua. Matkaan tuli kuitenkin pari ylimääräistä mutkaa…
Ensimmäinen mutka tuli heti alkuun, kun sivusto ei toiminut alkuunkaan. Koneellani on vain yksi Julia-ympäristö, jota kaikki koodi käyttää. Parissa kuukaudessa suurin osa kirjastoista oli päivittynyt, eikä yhteensopivuus taaksepäin ollut aina säilynyt. Tämä oli toki alusta asti tietoisesti otettu riski, kun käyttää uutta teknologiaa. Julialta puuttuu vielä työkalut projektien erityttämiseen omiin ympäristönsä, jotta yhden projektin päivitys ei rikkoisi toista [Playground.jl sanoo tuovansa Pythonin virtualenv-tyyppisen ratkaisun Juliaan].
Puolisen tuntia meni selvittää mikä oli hajonnut ja miten korjata. Toinen hidaste tapahtui url-parametrien käsittelyssä. Tässä samoin, kirjastokutsujen rajapinta oli muuttunut edellisestä kerrasta.
Itse toteutuksen detaljeissakin, kuten kontekstin määrittelyssä Mustache-templatelle, oli pientä säätöä, mutta lopulta sivutus näytti toimivan. Voitonriemuisena päivitin blogin tuotantoon. Käytän edelleen staattista generointia, eli lataan sivun wgetillä levylle, ja siirrän rsyncillä palvelimelle. Hyvältä näytti. Vaan ei toiminut. Ei tietenkään toiminut, sillä eihän staattisilla sivuilla voi käyttää dynaamisia url-parametreja. Nolohko huomio tässä vaiheessa.
Ratkaisuna toteutin routerin ilman get-parametreja, käyttäen url-polun osaa parametrina. Eli kysymysmerkki kauttaviivaksi. Ja tähän vielä bonuksena myös route-parametrien käsittelyn rajapinta oli ehtinyt muuttua edelliskerrasta…
Toimisko nyt?
Ei. Klikatessani staattisen version sivuttimen linkkiä, kysyykin selain minulta mihin haluan tallentaa tiedoston. Väärä sisältötyyppi. Tämä korjaantui onneksi yhdellä rivillä (default_type text/html;) Nginx-konfiguraatioon. [Myöhemmin tajusin, että asia olisi korjautunut myös lisäämällä url:n perään kauttaviiva, jolloin wget olisi luonutkin päätteettömän tiedoston sijaan uuden hakemiston ja sinne index.html-tiedoston.]
Huh. Nyt näyttäisi toimivan. Itse sivuttaminen jäi tässä työssä sivuosaan, mutta kyllä siitäkin silti jotain opin.
Odotin aluksi joutuvani tekemään monimutkaisemman härvelin, koska sovelluskehysten sivutuskomponentit saattavat olla monimutkaisia. Ne yrittävät sivuttaa mitä tahansa asioita missä tahansa tilanteessa. Ja koodarin pitää pystyä pääsemään väliin sivuttimen luontiin sekä tiedonhaku- että html-tulostusvaiheessa. Olen käyttänyt helposti pari tuntia myös niiden käytön ja kustomoinnin opetteluun. Saman ajan käyttäminen sivutuspyörän uudestaan keksimiseen oli ainakin oppimisen kannalta mielekkäämpi kokemus.
]]>