Kuolema nullpointerexceptioneille: Kotlin ftw!

Lomaillessa ja sairastaessa on hyvin aikaa leikkiä jollain jolle ei ole ollut kysyntää ns oikeissa, hiellä ja tuskalla väännetyissä Wakavissa Projekteissa. Tällä kertaa tutkaan osui Kotlin, johon on ollut tarkoitus perehtyä tilaisuuden tullen.

Kotlin on tuorein lisäys JVM-perheen kieliin; Eli kuten Scala, Clojure, ja Groovy, se on ihan oma erillinen kielensä, syntaksinsa, ja filosofiansa, mutta kun se menee kääntäjän läpi, putkesta ulos tulee Java-virtuaalikoneen bytecodea – vaatii tosin minimitasoksi Java 6 myllyn.

Ajonaikaiset virheet ohjelmissa ovat nykypäivän ohjelmistokehityksessä niitä kalleimpia virheitä – koska ne löytyvät vain kattavalla testauksella, voivat vaatia hyvinkin eksoottisia tiloja ja kombinaatioita ilmentyäkseen, ja mitä myöhemmin ne löytyvät, sitä enemmän ne maksavat. Esim. käyttöönottovaiheen jälkeen löytyvä bugi pitää ensin havaita, sitten raportoida, sitten toistaa, sitten ymmärtää, sitten korjata, sitten testata korjaus, ja testata ettei korjaus rikkonut mitään muualla, jne. Tästä kertyy ihan kohtuullisesti hintaa pienille asioille. Java-kielessä on alusta alkaen ilmennyt kahta eri virhettä yli kaiken muun: ClassCastException, sekä NullPointerException. Java 5 onnistui aikanaan hävittämään edellisen lähes sukupuuttoon Generics tyypitettyjen kokoelmien myötä. Mutta NullPointer on edelleen valitettavan yleinen virhe. Ja kun se paukahtaa, se usein valuu pinossa ylöspäin, ja voi ilmentyä hyvin mielikuvituksellisin tavoin – tai voi aiheuttaa seurauksia jotka näkyvät jossain aivan muualla myöhemmin. Eli pirullisia virheitä.

Nullpointereita on jahdattu eri tavoin. Olen itse opettanut ja kirjoitellut siitä miten Java-kielellä koodatessa voi tiedostaa tämän, ja koodata fiksusti. NullPointer paholainen iskee tyypillisemmin kun metodi palauttaa kokoelman sijasta null-arvon. Eli parempi filosofia on palauttaa aina ei-null arvo, esim. tyhjä. Jos jossain oikeasti tulee vastaan niin harvinainen tapaus, että null ja tyhjä ovat eri asia ja molemmat tarpeen palauttaa, niin se poikkeus on hyvä dokumentoida ja nimetä selkeästi, jotta kutsuja osaa käsitellä arvot oikein. Scala ja Groovy hoitavat nulleja omilla tavoillaan, mutta molemmat kielet edelleen sallivat null arvoja. Java 8 esitteli uuden Optional-tyypin, josta olen myös kirjaillut, ja se tuo vähän helpotusta ongelmiin oikein käytettynä – mutta ei sekään ongelmaa poista, ja mikään ei sitä pakota käyttämään.

Joten – long story short – Kotlin kielen mainostetuin uutuuspiirre on juurikin kuolema nullpointtereille, taas uudella ja tuoreella näkökulmalla. Mutta ei mennä asioiden edelle. Kotlin on syntaksiltaan ja toiminnaltaan eniten lähellä Scala-kieltä, ja Java-koodaajillekin tuttu.

fun main(args: Array<String>) {
  print("Kuolema NULLPOINTEREILLE!")
}

Jeah, puolipisteet valinnaisia, pääohjelman voi tehdä ilman luokkaa. Itse asiassa on myös mahdollista tehdä Kotlin scriptitiedosto, joka sisältää vain pääohjelman koodin:

print("Kuolema NULLPOINTEREILLE scriptissä!")

Kotlin käännetään kotlinc-kääntäjällä, joka voi suoraan paketoida java-kirjastot mukaan. Lopputuotos voi olla .class tiedostoja, tai suoraan ajettava .jar. Kotlin voi vapaasti importoida ja kutsua Java-kirjastoja, sekä JVM sisältä että mitä hyvänsä lisäkirjastoa mitä on tehty sitten vuoden 1995.

kotlinc app.kt -include-runtime -d app.jar

Miten Kotlin sitten auttaa nullpointerien kanssa? Kotlin ei salli normaalien tyyppien asettamista null-arvoon: kääntäjä estää sen. Esim. tyyppi String vaatii aina ei-null arvon. Jos haluat asettaa null-arvon, tyypin perään tulee kysymysmerkki merkiksi, esim. String?

var name:String?
var email:String
name = null
email = null // This line does not compile at all!
print("HELLO " + name + "!")
print("Your email is " + email)

Ylläolevassa koodiesimerkissä näet molemmat käytössä. Jos halutaan siis varata oikeus käyttää null-arvoja, se pitää näkyä jo alunperin tyyppimäärityksessä. On siis varsin mahdollista käyttää null-arvoja – mutta useimmiten ne ovat vain puhdasta laiskuutta. Useimmiten kun on mielijohde palauttaa null-arvo, onkin fiksumpaa palauttaa ns tyhjä arvo, esim. tyhjä String, tyhjä List, jne, tai heittää poikkeus. Niihin harvoihin tapauksiin kun null arvo on oikeasti kätevä, se on helppo ottaa käyttöön.

Mitä muuta jännää on Kotlinissa, verrattuna Java/Scala kieliin esim? Aika paljolti paletti molempien parhaita puolia. Primitiivityypit on poistettu: Kaikki ovat oliotyyppejä. Ei ns checked exceptions poikkeuksia, kaikki ovat nykymuodin mukaan runtime exception tyyppiä, eli käsitellään kun halutaan, ei ole pakko. Nykymuodin mukaan myös kielessä on paljon älykkyyttä ja päättelyä: esim. muuttuja/vakiotyyppiä ei tarvitse määrittää jos kääntäjä sen jo osaa päätellä arvon perusteella. Erikseen löytyy val ja var avainsanat immutable/mutable käyttöä varten. Tottakai lambda expressionit pelaavat mainiosti.

Kielestä on sitten vastaavasti jätetty pois monia piirteitä, joilla Java/Scala koodaajat ampuvat itseään lahjakkaasti jalkaan, esim. static avainsanat ja osat, implicit conversions, ja rohkaisu on ratkoa ongelmia siten että koodi pysyy luettavana ja selkeänä. Toisin kuin Scala, kieli on myös rakennettu modernin Java 8 pohjalle, eli on lähempänä nykysyntaksia mm. Lambdojen ja Stream käsittelyn osalta. Itse pidän myös esim. funktioparametrien oletusarvoista, ja mahdollisuudesta asettaa parametreille arvot nimen perusteella. Tämä vähentää tarpeetonta polymorfismia – toki kohtuudella käytettynä tämäkin, muuten polymorfisuus korvautuu modaalisuudella joka taas ei ole hyvä vaihtokauppa.

2016-06-10 13.13.59

Firman Flamingo hyväksyy Kotlinin

Kotlin on tosiaan melko tuore tulokas kentällä: JetBrains niminen paja lanseerasi sen vuonna 2011, vuonna 2012 se vapautettiin Apache lisenssillä open sourceksi, ja nyt vuonna 2016 siitä on julkaistu vakaaksi laskettava versio 1.0, vuoden alusta. Sen osuus on sen verran marginaalinen ettei vielä näy esim. TIOBE indeksissä, mutta se ei toki tarkoita etteikö sitä jo kentällä käytettäisi.

Kannattaisiko siis käyttää Kotlinia seuraavaan projektiin? Omalta puoleltani annan vahvan peukutuksen. Clojure uskovaiset tuskin kokevat halua kääntyä tänne, se on edelleen oma maailmansa. Java uskovaisten kannattaisi tehdä seuraava projekti ihan millä hyvänsä modernimmalla kielellä, Java on nykymuodossaan aika rasitettu ja päällelaastaroitu sekamelska, ja Scala, Clojure, ja Kotlin ovat kaikki huimia parannuksia siihen. Scala kielen pieni haitta on se että se oli kentällä aikaisin, ja nyt sen linjaus Java 8 mukaiseksi on vähän isompi operaatio. Scalassa on myös turhankin voimallisia tapoja ampua itseään jalkaan, jotka ovat Kotlinista tahallisesti poistettuja.

Kuten Scala, myös Kotlin on hyvä alusta jossa voit toteuttaa vapaasti haluamaasi yhdistelmää funktionaalista tai olio-ohjelmointityyliä. Voit esim. aloittaa iisisti perinteisemmällä Java oliokoodilla, ja hivuttaa itseäsi kohti korkeamman tason funktioita ja immutable, arvoja. Kotlin käyttöönotto on helppoa, ja sen voi perinteiseen tapaan aloittaa vaikkapa testipuolella. Kotlin toimii myös mukavasti esim. Spring Boot+REST alustana, ja sen saumaton yhteensopivuus olemassaolevien Java-kirjastojen kanssa tuo ratkaisua mm. tietokantojen kanssa pelaamiseen.

Itse ainakin käyttäisin. Rakastuin aikanaan Scalaan, ja Kotlin on Scalalle vähän samaa kuin Scala oli Javalle. Scala on edelleen paljonkin voimallisempi työkalu, ja kypsempi myös, mutta molemmat piirteet ovat kaksiteräisiä miekkoja. Ja Java-kieltä taas kukaan ei varmaan ihan ehdottoman innoissaan halua koodata. Sen paras argumentti lienee Cobol-mainen 20 vuoden tuoma maturiteetti, se on hyvä sveitsin armeijan linkkuveitsi siellä työkalupakin pohjalla. Ehkä sen olisi kielenä jo aika kuolla pois. Mutta toki maailmalta löytyy 10 miljoonaa enemmän tai vähemmän aktiivista koodaajaa jotka sitä ymmärtävät. Digitalisoinnin tarpeiden taas laajentuessa eksponentiaalisesti sekin on hyve.

 

Tuolta lisää:

https://kotlinlang.org/

 

Java 9 ja CORBA

Heh, niinpä. Olen kirjaillut aiemmin useammankin kerran tulevan Java 9:n ihmetyksen aiheista. Silmiin osui hauska artikkeli siitä miten viimeinkin CORBA, Common Object Request Broker, tuo kaikkien väylien ja hajautuksen edelläkävijä ja kaikkien sitä käyttäneiden inhokki, ei enää tule vakiovarusteena perus-Javassa.

Java 9 suuri uudistushan on modulaarisuus, ja sen tärkeimpänä osana ja ajurina Javan n. 20-megainen runtime modularisoidaan, siten että sieltä löytyy tiukka ydin-kernel, ja lukuisia moduuleita joita voi halunsa mukaan ottaa mukaan tai jättää ottamatta. Pitkän tähtäimen strategia on varmasti paluu mobiili ja IoT ympäristöihin uusin voimin.

Eli, oletuspaketti, root moduulit, ei sisällä enää tarpeetonta kuraa, ja osa tarpeellisistakin lähtee erilleen. Jos kaipaat CORBAA, saat sen takaisin kytkimellä:

-addmods java.corba

Hyvä huomata että vastaavia muita moduuleita ovat mm.:

java.activation
java.annotations.common
java.corba
java.transaction
java.xml.bind
java.xml.ws

Näyttäisi siis siltä että viimein Java menee tosissaan tiukalle dieetille. Java 9:stä kuulemme varmaan lisää tämän vuoden JavaOne seminaarissa San Franciscossa – mutta mielenkiintoa näyttäisi olevan. Varmaa on, että jatkossa on syytä opetella käyttämään moduulijärjestelmää ja sen kytkimiä – muuten ei vanhat Java-koodit enää edes käänny.

Toinen tutkaimiin osunut juttu on moneltakin taholta julistettu Java EE 8 kuolema. Oraclen panostus ja mielenkiinto sen suhteen näyttää olevan lopahtamassa. Mielenkiinnolla seuraan mitä tämä tarkoittaa, ja mitä tuo tullessaan. Tutkaimet herkkinä. Tämäkin selvinnee syksymmällä.

 

http://mail.openjdk.java.net/pipermail/jdk9-dev/2016-May/004309.html

 

Nexus 6P ja Android N(ext)

Jahas, ei ole tullut blogailtua hetkeen, työkiireitä. Mutta pusketaan nyt vaikka ilmoille pientä mietelmää Android puolelta, ihan vain ettei touchi katoa 😉

Sain viimein käsiini Nexus 6P luurin työpuhelimeksi. Se tarkoittaa että aiempi Nexus 6 – joka jo vetelee viimeisiään – pääsee eläkkeelle ja samantien Googlen beta-ohjelmaan. Eli tilasin siihen Android N version developer preview:n OTA päivityksenä.

Nexus 6P

Eli, ensivaikutelmia molemmista. Ensin Nexus 6P. Ihana puhelin. Nexus 5:sta alkoi teema jossa nämä laitteet alkoivat oikeasti olla hyviä kuluttajaluureja. Valitettavasti hintakin on kasvanut sen mukana. Mutta toinen toistaan parempia ovat. Nexus 6P on hieman kapeampi ja pidempi kuin Nexus 6, mutta edelleen ohut ja kevyt. Akkukesto on käytössä jotakuinkin vastaava, ei parempi, ei huonompi, mutta kestää läpi työpäivän, täytyy ladata iltasella. Paljon dramatisoitu paksunnos kamera+sensoreille on käytännössä hyvin huomaamaton. Sopii samaan autotelineeseen kuin vanha Nexus, kun päälle on pujotettu pieni suojakuori joka lisää leveyttä muutamalla millillä.

2016-04-25 10.15.32

Nexus 6P kamera ja etenkin etupuolen selfie-kamera ovat huimasti parempia kuin aiemmin, ainakin omalla näppituntumalla. Parannukset lähinnä hämäräolosuhteissa ja nopeudessa. Muutenkin taas laitteessa potkua riittää, ei jumita, ei nyi. Tämä oli odotettavissakin prosessoripäivityksen myötä. Taustakannen sormenjälkisensori toimii, no niin hyvin kuin sormenjälkisensorit nyt voivat toimia. Sille voi opettaa useamman sormen jos vaikka tykkää välillä vaihtaa kättä. Kaikenkaikkiaan toimiva ja sulava laite. Ei toki mitään häkellyttävän uutta ja innovatiivista sinänsä.

Android N

Android N on tosiaan työn alla oleva, seuraava Android major versio nykyisen kuutosen jälkeen. Sen kunniaksi Google julkaisi juuri uudistetut 2.0 versiot kehittäjätyövälineistä, sisältäen mm. nopeamman emulaattorin.En ole ehtinyt vielä ottamaan kunnon tyyppejä kiukun alla, mutta kuulostaa hyvältä.

Noin luurista kurkistellen on välittömästi havaittavissa jonkun verran eroja visuaalisella puolen, mutta ei suuria muutoksia siihen miten asiat noin yleensä toimivat. Notifikaatioita on niputettu, yläpalkissa on pikavalikko.

Android N Notifikaatiot

Nyt voi ruudulle tulevasta flash notifikaatiosta myös vastata nopeasti, esim. tekstariin, lähtemättä pois auki olevasta sovelluksesta (jos sille on tuki rakennettu notifikaatioon).

Blogautin aiemmin yhdestä tulevan Android alustan näkyvästä muutoksesta: Splitscreen. Kun multi-tasker menussa painaa pitkään, voi raahata sovelluksia split-screen moodiin, jossa myös niiden ruututilaa voi säätää. Jotain saa aikaan vaikka sovellus ei olisi splitscreenistä yhtään tietoinen. Suhteen ei ole pakko olla 1:1, vaan sitäkin voi säätää. Herranjestas, tässähän keksitään pian uudestaan Windows 3.1!

2016-05-19 06.07.12

Vitsit sikseen, on aika loogista että kun ruutujen koko kasvaa, niihin ahnehditaan yhä enemmän piirteitä työpöytäkoneista. Mikä on hyötyarvo, jää nähtäväksi. Itse en lyhyellä testailulla vielä vakuuttunut, vaikuttaisi hiukan kömpelöltä.

Syvältä asetusten uumenista löytyy VR Helper säätöjä sovelluksille. Ei suuri yllätys että tuolle puolen tulee taas panostusta, tämä on VR härpäkkeiden vuosi. Ei vielä paljoa lisätietoja tästä, mutta Google I/O on käynnissä, ja uutta tietoa tulee joka hetki. Joka tapauksessa, tulee liittymään Daydream alustaan.

VR Helper

Android N julkaistaan ihan kuukausien sisään nyt, ja valuu tietysti ensiksi Nexus-puhelimiin. Todennäköisesti myös Sonyn puhelimet saavat maistella tätä herkkua aikaiseen. Nähtäväksi jää onko esim. Samsung skarpannut tällä saralla yhtään.

Jäljellä on vain yksi kysymys: Mikä siitä tulee? Tuleeko Nutella? Nutmeg? Vai Naughty Biscuit? No, käypä itse ehdottelemassa: https://www.android.com/versions/name-n/

 

Android N ja Java 8

Tuloillaan on uusi versio Android käyttöjärjestemästä, tässä vaiheessa koodinimellä N tunnettu. Siinä on taas aika suuri heilutus tuloillaan alustaan, jota on jo puitu monissa ulkomaan artikkeleissa. Mutta tässä omasta näkökulmasta kiinnostavia juttuja:

Jack it to the max

Jep, kuten otsikko kertoo, nyt voi koodata täydellä Java 8 ilmaisuvoimalla. No, lähes täydellä. Käytössä on Jack-niminen työkaluketju, jolla käännetään Java 8 lähdekoodit Android .dex bytecodeksi. Tämä on kahdestakin syystä ihastuttavaa. Ensinnäkin Java 8 on ihanaa! Toisekseen tämä kertoo että Google ei ole antamassa periksi Javan osalta, ja siirtymässä johonkin uuteen. Tai ehkä onkin, mutta näyttää silti siltä, että Javalla on vielä tulevaisuutta edessään täälläkin alustalla.

https://developer.android.com/preview/j8-jack.html

https://source.android.com/source/jack.html

Joka tapauksessa, ei mene ihan perusputken mukaan, eli pieniä eroja täysiveroiseen OpenJDK ympäristöön voi tulla. Lähinnä esim. työkalustojen osalta voi tulla säätöä. Mutta näin on odotettavissa, aika iso hyppäys siirtyä Java vitostasosta kolme tasoa kerralla ylöspäin.

Saako sitä jo?

No tottakai sitä saa. Google on avannut beta-ohjelmaa, johon voi imaista sopivaan kännykkään N-version ihan OTA päivitysenä, rekisteröitymällä vain kiinnostuneeksi. Ei siis ole tarpeen viriviritellä laitettaan usb piuhalla. No sitten on, jos haluaa palata takaisinpäin. Se ei OTA:lla onnistukaan. No, ainakaan ilman että pyyhkii kaiken sisällön pois.

Ihan harmittaa ettei itsellä ole redundanttia Android vehjettä käsillä. Jahka saan firman uuden puhelimen hyppysiini, nykyinen/vanhaksi jäävä Nexus tilannee OTA päivitystä samantien. Mutta ihan työ/käyttöpuhelimeen ei kannata N versiota vetäistä, sen verran varhaisia hetkiä elellään.

https://www.google.com/android/beta

Virallisempaa releasea luvassa vuoden loppupuoliskolla.

Ikkunointia

No niin, hulluus on saavuttanut uuden tason. Aloitimme kännyköistä missä tärkein ominaisuus oli kyky soittaa. Siten päädyimme kännyköihin joissa laskentateho ja ominaisuudet tekevät niistä pieniä tietokoneita – tai rökittäväthän ne aika kevyesti aikanaan supertietokoneiksi kutsuttuja talonkokoisia yksiköitäkin. Nyt pistetään lisää pykälää – lisääntyvä teho ja näyttökoko ovat ajaneet meidät tilanteeseen jossa kännykässä voi olla tarvetta ajaa sovelluksia ikkunoissa. Ja tätä tulee Android N:ssä.

Eli jep, voidaan avata sovelluksia eri ikkunoihin, ajaa samanaikaisesti, ja muuttaa kokoa. Tämä vaatii toki sovellukselta tukea, mutta eiköhän sitä ole tulossa. Clash of Clans ja Youtube strategiavideo auki rinnakkain. Copy/Paste. Jepjep, me olemme viimein saaneet työpöytäkoneet taskuihimme, viimein on käyttöä tarpeettoman järeille moniydinprosessoreille 😉

Odota hetki, päivitän sovelluksia…….

Myös optimointi on käynyt läpi omat elinkaarensa. Ensin oli JIT käännökset, jossa sovellusta optimoitiin ajon aikana. Sitten keksittiin, että on parempi optimoida jo asentaessa, niin sovellus käynnistyy nopeammin (ART). Tästä saatiin kaikkien rakastamat Android sovelluspäivitysodottelut aina käyttöjärjestelmän päivittyessä – ja yleensä juuri silloin kun puhelinta tarvitsisi. Nyt, Android N myötä, tämä vaihe poistuu unholaan. Palataan taas JIT-malliin, nyt kun tehoa on enemmän, voidaan taas jakaa optimoinnin kuorma tasaisemmin ajon ajaksi. Tästä lisää täällä:

http://www.androidauthority.com/android-n-app-optimization-compile-679129/

Ja paljon paljon muuta. Onhan tuota tulossa, mutta näitä piirteitä on jo analysoitu hyvin muualla. Itseä kiinnostaa eniten tuo Java 8 piirre, se on kehittäjänäkökulmasta tuoretta ja virtaa tuovaa. Myös mahdollisuus osallistua aikaisin testaukseen – niinkuin nyt – on aika kova. Palaan astialle jahka saan jonkun omista laitteista N-aikaan ja vähän konkretiaa testailuun.

 

 

RESTAssured ja Istuntokeksit

REST ja istunnot ovat aikalailla paradoksi. Mutta silti joskus löytää itsensä tilanteesta jossa tilattomat REST palvelut ovat tilallisen autentikoinnin takana, esim. JSESSIONID evästeellä seurattuna (Ja kyllä, Suomen Kielitoimisto suosittaa nykyisin Cookielle termiä eväste, aiemmin keksi, ja uskokaa tai älkää, alunperin Taikapipari). Jos vielä heikommin käy, edessä voi olla joku single-signon hirviö joka tokenien sijasta käyttää useampaa istunto-evästettä. Ja jotenkin pitäisi saada kirjautumisen jälkeen istunnot säilymään.

Jos kyseessä on vain yksinkertainen JSESSIONID case, alkaen RestAssured versiosta 2 sille on tuki valmiina, parillakin eri tavalla. Nopein tapa saada sessio-cookie lähetettyä edestakaisin on tähän tapaan:

RestAssured.filters(sessionFilter);

Tuo pitää huolen, että sessio-eväste kaapataan vastauksista, ja liitetään pyyntöihin. Toimii heittämällä jos nimi on JSESSIONID – kunhan vain pidät huolen siitä, että sessionFilter on kaikissa kutsuissa sama, esim. luomalla sen staattisena:

public static final SessionFilter sessionFilter = new SessionFilter();

Entä jos evästeen nimi ei ole JSESSIONID? No, sen voi helposti muuttaa RESTAssured konfiguraatiolla:

RestAssured.config = newConfig().sessionConfig(new SessionConfig().sessionIdName("KOTLINSESSIONID"));

Entä jos pitäisi puljata useampia tracking cookieita, ja niiden nimet muuttuvat välissä? No ei hätää, sen voi hoitaa omalla custom filterillä, tähän tapaan:

public class CookieResenderFilter implements com.jayway.restassured.filter.Filter {

  private Map<String, Object> cookiesMap = new HashMap<String, Object>();

  @Override
  public Response filter(FilterableRequestSpecification filterableRequestSpecification,
                         FilterableResponseSpecification filterableResponseSpecification,
                         FilterContext filterContext) {
    filterableRequestSpecification.cookies(cookiesMap);
    Response response = filterContext.next(
      filterableRequestSpecification,
      filterableResponseSpecification);
    Map<String, String> cookiesReceived = response.getCookies();
    if (cookiesMap.size() == 0 && cookiesReceived.size() > 0) {
      for (String key : cookiesReceived.keySet()) {
        cookiesMap.put(key, cookiesReceived.get(key));
      }
    }
    return response;
  }
}

Ja tuo rekisteröidään käyttöön kuten yllä, taas pitäen huolta siitä että kyseessä on aina sama instanssi, ei aina uusi – koska sen jäsenmuuttujia käytetään tiedon varastointiin testisession ajan.

Oikeastihan tilallisuus + REST rajapinnat ovat helvetin seitsemännen tason keksintö ja jo tätä artikkelia kirjoittaessa tuli likainen olo, mutta aina ei pääse valitsemaan työkalupakkiaan. Kun pääsee, käyttäkää BCRYPT Token headereita, ihmiset!

Angular2 + NPM + Webpack

Lupailin kirjailla vähän lisää fiksusta Angular2 setupista tuotantohommiin. Tarkoitus oli tunkkailla minimaalinen paketti jossa on helppo erottaa eri tekniikoiden tehtävät. Valitettavasti Angular2 on aika liikkuva kohde tällä hetkellä – ja kiirettäkin on pitänyt, joten yksinkertainen POC projekti on jäänyt haaveeksi.

Onneksi joku muu on tehnyt sellaisen. Tällä hetkellä fiksuinta on aloittaa kokeilut ylläpidetystä Angular2 Webpack Starter projektista: https://github.com/AngularClass/angular2-webpack-starter

Valitettavasti tuo projekti ei ole yksinkertainen eikä siisti, mutta hoitaa homman. Ja se on kuitenkin hyvin linjassa sen kanssa mitä itse ajattelen. Angular2 kehittyy vauhdilla juuri nyt, ja joka releasen myötä se on siistimpi ja eheämpi ja vähemmän tarvitaan purkkaa taustalle. Sitä myöten voisin kuvitella että tämä webpack starterkin yksinkertaistuu.

Joka tapauksessa, vähän saatesanoja projektin suhteen. Senhän saa käyttöön nätisti kokeiluun (kun nodet on asennettuna), esim. näin:

 

git clone https://github.com/angularclass/angular2-webpack-starter.git
cd angular2-webpack-starter
npm install
npm start
curl http://localhost:3000

Curlin sijasta voit luonnollisesti tyypittää oikealla selaimella. Kuten kynäilin viimeksi, Bower on vähän menemässä muodista pois, samoin Grunt – paljon kuin sitä ja Gulpia rakastankin. Jos haluaa, voihan molempia noita käytellä vieläkin, ja voi olla joku tehtävä jossa Gulp voi olla esim. hyödyllinen. Mutta vanilla on päivän maku näissä asioissa, ja aikalailla paljon saa aikaan ihan vain puhtaalla JavaScriptillä ja NPM:llä.

Kannattaa luoda silmäys package.json tiedostoon. Se on tässä kaiken avain. Ja voi olla pelottava kokemus tässä vaiheessa jos on tottunut että se on vain kirjastomanifesti. Tosiaan devdependencies-lista on aika kattava näinkin yksinkertaiselle projektille, mutta tulee yksinkertaistumaan jatkossa. Ja toki siinä on jo aika kattavasti testaustyökaluja mukana. Pääjuju kuitenkin, että riippuvuudet on fiksuinta hakea kaikki npm keinoin, softan omat riippuvuudet ovat dependencies kohdassa, ja Boweria ei käytetä.

Mielenkiintoinen osio on kuitenkin scripts-osio. Vielä pari vuotta sitten oli tavanomaista että tämä oli tyhjä tai siinä oli 1-2 kohtaa, build ja test. Nyt tässä näkyy hyvin painopisteen muutos. Perinteiset grunt/gulp työvaiheet on nyt npm scripts työvaiheina, ja ne ovat modulaarisia ja ketjutettuja. Tarvittaessa käytetään noita dpm dev moduuleja, esim. rimraf poistaa tyylikkäästi tarvittavat hakemistopuut. Jos tuosta poimii muutaman mehukkaan ja keskeisen komennon niin ne ovat:

"clean": "npm cache clean && rimraf node_modules doc typings coverage dist"
"build:dev": "webpack --progress --profile --colors --display-error-details --display-cached"
"server:dev": "webpack-dev-server --progress --profile --colors --display-error-details --display-cached --content-base src/"

Näitä pääsee ajamaan komennolla npm run, esim.

npm run build:dev (ajaa kehitysversion buildin)

Samaan listaan on myös määritetty oikopolkuja yleisimpiin, esim:

"build": "npm run build:dev"
"server": "npm run server:dev"

Siinäpä nuo yleisimmät. Ja loput hoitaa webpack. Webpackillä on tässä kaksi keskeistä tehtävää: Tärkein on lähdekoodin prosessoiminen halutuksi paketiksi (sisältäen tarpeen mukaan babelifioinnit, minifioinnit, obfuskoinnit, jne), ja sen ohella myös sisäänrakennettu testiserveri on mukava. Konfiguraatiot käännöksiin löytyvät projektin juuresta, esim. tsconfig.json ja webpack.config.js. En pui niiden sisältöä tässä sen enempiä, mutta ne ovat aika selkeitä ja tehtäväänsä keskittyneitä. Ehkä hyvä mainita että toisin kuin Angularin omassa yksinkertaisessa tutoriaalissa, moduulijärjestelmänä SystemJS on korvattu CommonJS:llä.

Mitäpä muuta? Sain aiemman artikkelin suhteen vähän kommenttia/kysymystä tuosta Mavenin käytöstä. Itsehän tyypillisesti teen backendit Javalla/Spring Bootilla, ja frontend on vain osa kokonaisprojektia. Ja koska asiat on kiva pitää yksinkertaisena, samalla kun buildataan Mavenillä backend hyväksi, on mukava rusauttaa läpi myös frontend buildit. Käytän tähän tosiaan eirslett maven plugaria, joka voi yksinkertaisimmillaan näyttää tältä:

<plugin>
  <groupId>com.github.eirslett</groupId>
  <artifactId>frontend-maven-plugin</artifactId>
  <version>0.0.27</version>
  <executions>
    <execution>
      <id>install node and npm</id>
      <goals>
        <goal>install-node-and-npm</goal>
      </goals>
      <configuration>
        <nodeVersion>v5.5.0</nodeVersion>
        <npmVersion>3.3.12</npmVersion>
      </configuration>
    </execution>
    <execution>
      <id>npm install</id>
      <goals>
        <goal>npm</goal>
      </goals>
    </execution>
    <execution>
      <id>npm build</id>
      <goals>
        <goal>npm</goal>
      </goals>
      <configuration>
        <arguments>run build:prod</arguments>
      </configuration>
      <phase>compile</phase>
    </execution>
  </executions>
</plugin>

Käytännössä siis tuo tarkoittaa:

  • Varmista että node ja npm ovat asennettuna paikallisesti
  • Aja npm install
  • Aja npm run build:prod scripti – automaattisesti Mavenin Compile vaiheessa, eli samalla kuin backend kooditkin käännetään

Yksinkertaista. Webpack on konfiguroitu puskemaan prosessoidut .js tiedostot, html:t ja muut staattiset osat sopivaan kansioon, josta Mavenin paketointivaihe ne sitten nappaa mukaan .war pakettiin.

Huomaa että jos haluat ajaa Mavenin läpi muitakin npm taskeja, se onnistuu määrittämällä sopiva Maven property jonka voit komentoriviltä ylikirjoittaa, ja käyttämällä sitä tuon npm taskin konfiguraatiossa, esim. näin:

<execution>
  <id>npm build</id>
  <goals>
    <goal>npm</goal>
  </goals>
  <configuration>
    <arguments>${npm.argument}</arguments>
  </configuration>
  <phase>compile</phase>
</execution>

En kuitenkaan nykyisellään koe tälle erityistä tarvetta. Mavenin päätehtävä on varmistaa että riippumatta koneen varustuksesta paketti osaa buildata itsensä eheäksi itsenäisesti, oli sitten kyseessä Jenkins ympäristö tai uuden projektiin tulevan kehittäjän kone, tai vanhan devaajan uusi kone. Eli toiminta varmistetaan kaikissa olosuhteissa. Mutta noita muita npm käskyjä voi hyvin ajaa ohi mavenin esim. frontend-painotteisten kehittäjien toimesta, esim.watch on varsin hyödyllinen kun haluaa saada käyttöliittymäkehityksessä jatkuvaa palautetta. Siksi perusbuildi Mavenin kautta ajettuna usein riittää, ja oletuksena production buildi on tietysti hyvä.

Tässä mietteitä tällä kertaa. Matka vilkkaassa frontend maailmassa jatkuu….