Java 20 vuotta

Jep, tämä on se vuosi. Vuonna 1995, toukokuussa, Sun Microsystems puski jakoon 1.0 version Javasta. Se sai huimasti sykettä ja suosiota ja nousi yhdeksi suosituimmista työkaluista. Ihan vain sen kunniaksi, hiukan muisteloita ja hajatuksia tästä.

Nillittäjät voivat huomata että vuoden 95 Java oli lähes käyttökelvotonta Alpha ja Beta versiota, ja vasta -96 saatiin vakaa 1.0 JDK. Ehkä synttäreitä voi siis juhlia uusiksi ensi vuoden tammikuussa 😉

The Duke

Vuonna 95

Tarina alkoi jo kauan ennen vuotta 95, työnimellä Oak – ja alunperin kohteena älykkäät kodinkoneet ja PDA laitteet. Vuoden 95 julkaisussa nimi muuttui Javaksi, ja fokus kiteytyi WORA periaatteeseen: Write Once, Run Anywhere. Tässä oli jotain uutta ideaa, kun ei tarvinnut tehdä natiivikäännöksiä joka alustalle softasta. Sekä lähdekoodi että binäärit olivat kaikilla tuetuilla alustoilla toimivia. Tämän mahdollisti virtuaalikonearkkitehtuuri, jota sittemmin menestyksellä kopioitiin muuallakin.

Mitä muuta meni nappiin? Yksinkertaisuus – kieli ei ollut aiempia monimutkaisempi tai monipuolisempi, vaan ohjelmoijalta abstraktoitiin pois mm. pointteriaritmetiikka ja muistinhallinta – virtuaalikone hoiti ne pinnan alla. Paradigmaksi valittiin objektiorientaatio, ja toimntaympäristöksi hajautettu ja monisäikeinen. Network is the computer.

java-duke-guitar

Kolikolla oli kääntöpuolensakin. Etenkin alkuaikojen Java oli tunnettu surkeasta suorituskyvystään: Kymmeniä kertoja C++ koodia hitaampaa. Sillä ei voinut tehdä ollenkaan kaikkea: suora pääsy virtuaalikoneen ulkopuolella käyttämään ympäristön natiiviominaisuuksia ei ollut helppoa eikä hauskaa (JNI). Appletit olivat suosituin tekniikka, pelit ja vilkkuvat bannerit, ja tietoturvaongelmat alkoivat nostamaan päätään heti kun annettiin voimaa ja valtaa asiakaspuolelle. Swing oli sinällään hieno käyttöliittymäkirjasto joka pyöri kaikkialla, mutta oli toisaalta yhtä tympeän karu ja hidas kaikkialla.

Muutama vuosi myöhemmin mentiin pykälällä eteenpäin: JIT eli Just-In-Time käännökset antoivat potkua suoritukseen, ja nopeasti sen perässä tulikin jako kolmeen: J2ME, J2EE, J2SE – eli Javaa pieniin ja suuriin ympäristöihin. Mobiililaitteiden myötä Javaa ajavien ympäristöjen määrä räjähti pilviin, ja serveripuolella tuli käyttöön standarditapoja tehdä asioita – ja ajaa samaa koodia SUN, IBM, Oracle, BEA alustoilla (Sittemmin lista on kaventunut, koska yritysostot 😉

2000-luku

2000-luvulle siirryttäessä Java alkoi näyttää vanhalta ja kankealta. Markkinoille tuli paljon uutta ja hyvää. Ruby, Rails, C# ja .NET, PHP ja JavaScriptin uusi tuleminen. Yhtäkkiä Java olikin se kankea perinnealusta joka ei ollut inspiroivaa koodata. Java oli se uusi Cobol.

Onneksi heiluri heilahti takaisinpäinkin. Siinä missä Microsoft otti huomattavasti inspiraatiota Javasta omaan .NET alustaansa ja C#-kieleen, Java 5 otti taas hienoja asioita siltä puolen ja antoi ne Java-kehittäjille. Osa päivityksistä oli kiistanalaisia ja hieman päälle laastaroituja, mutta silti, Generics, ja annotaatiot, toivat ruutia alustaan. Samalla avoin lähdekoodi saavutti Javan, ja alkoi tulemaan pilvin pimein hienoja tuotteita joiden koodi oli avointa ja käyttöönotto mutkatonta ja nopeaa. Eclipse, Tomcat, JBOSS avasivat tietä, ja saivat nopeasti lukuisia kilpailijoita.

IMG_3013

Sitten tuli turbulenssin aika, ja pari vähäisempää Java-versiota – Java 6, ja Java 7. Niiden suunnitelmat olivat kunnianhimoisia, mutta Sun Microsystems ajautui Oraclen sulauttamaksi, ja kaikkeen meni enemmän aikaa kuin arvioitiin – Java 7 suunnitellut muutokset valuivatkin eteenpäin tuleviin julkaisuihin.

Olisiko Sun Microsystemsin kirouksena ollut liiketoimintamallin puute? Java mahdollisti softan kehityksen ja ajon melkein missä vain – eikä sitonut tietyn valmistajan alustaan tai tuotteisiin. Sen käytöstä ei hurjia tuottoja tippunut eikä se sitonut kotiinpäin asiakkaita. Siitä tuli liiankin avointa ja vapaata.

Fast forward to Now

Nyt eletään vuotta 2015 – ja Oraclen valtakautta, kuudetta vuotta. Käytössä on Java 8 ja ysiversiota rakennetaan jo. Java 8 otti paljon vaikutteita erinomaisen Scala-kielen pohjalta, ja muualtakin, ja Lambat ja Streamit ja parannetut päivämääräkirjastot maistuvat kieltämättä hyvältä. Kieli on onnistunut uudistumaan mukavasti vaikka on jo ajat sitten saavuttanut täysi-ikäisyyden. Se on pysynyt markkinoilla validina. Mikä vielä kiehtovampaa, virtuaalikonearkkitehtuuri on osoittanut hyötynsä, ja Java-kielen rinnalla voi tuottaa toimivia ratkaisuja mm. Scala, Groovy, tai Clojure-kielellä – joissa kaikissa on omat vahvuutensa. Uusia Javantappajia ei ole näköpiirissä – ellei noita edellämainittuja kieliä lasketa. Java-koodaajia on maailmanlaajuisesti yli 10 miljoonaa.

Uuden maailman ilmiöitä ovat mainitut Lambdat, streamit, niiden ohella funktionaalinen ohjelmointi, ja rohkea yhdistäminen Javascript-raskaisiin käyttöliittymiin – Angular, React, Aurelia. Staattisen tyypityksen voi kyseenalaistaa esim. Clojurella – tai tiputtaa koodin määrää 90% melkein millä vain noista edellämainituista virtuaalikonekielistä. Java toimii kaikkialla missä ennenkin – ja monessa uudessa paikassa. Androidin myötä se valloitti mobiililaitteet rytinällä – ja nyt on IoT valloitus kovassa käynnissä. Eli vahvasti mennään taas.

IMG_8068

Ainoa ongelma on se kun tajuaa koodanneensa Javaa alkuajoista asti. Sehän tuntuu kuin olisi saanut alkunsa eilen? Samaa hommaa tehdään siis edelleen – vain tukkaa on vähemmän. Olisiko aika jollekin uudelle ja virkistävälle kielelle? 😉

Mockito – ja testataan ihan mitä vain isolaatiossa

Olen joskus aiemmin kirjaillut juttuja siitä miten esim. EJB komponentteja voidaan yksikkötestata – ja käytellyt välineenä EasyMockia. Testaus isolaatiossa, eristyksissä muusta on yksi tavoiteltava asia koska näin tehdyt testit voidaan ajaa salamannopeasti ja jatkuvasti, saaden palautetta muutoksista koko ajan.

Mockito-JUnit

Sanoinko testit? Köhköh, tarkoitin tiestysti speksit. Isolaatiotestit mahdollistavat TDD ja BDD disipliinien soveltamisen haltuessaan, tai itseni suosima Spec-While-Writing tapa joka on oikeastaan ihan samaa kuin em mutta rennommin rantein. Fanaattiset isolaatiotestithän eivät nimenomaan ole testeinä kovinkaan hyviä usein, mutta spekseinä ne ovat aivan verrattomia, ja monimutkaiselle logiikalle lähes ilmaiseksi sivuvaikutuksena syntyvät testitkään eivät ole ihan huono asia.

Sanoinko ilmaiseksi? Hups. Kyllähän testien kirjoittamiseen aikaa kuluu, etenkin jos niitä säveltää etupainotteisesti ennen koodipyrähdyksiä. Etenkin isolaation saavuttaminen on aika ajoin hankalaa. Viime aikoina olen löytänyt uutta apua tälle saralle: Kuten otsikko jo spoilasi, Mockito framework on varsin kiva, etenkin Spring Bootin kanssa. Vastaavaan tapaan Javascript-puolella käyttelen nykyään Jasmine mockeja, mutta tämä ei ole artikkeli niistä vaan Mockitosta. Tässä siis vähän maistiaisia siitä miltä maistuu yksikkötestaus mockitolla ja mitä hyöytyä siitä saa.

Mockito testi voi olla tavallinen JUnit tai TestNG testi, eli aloitellaan tähän tapaan:

public class UserResourceTest {

  @Test
  public void changePasswordShouldSucceedWithValidParameters() 
    throws Exception {
      fail("Not implemented yet");
  }

}

Testatessa on tietysti mukavaa olla se mitä testataan. Perinteisesti sen voi vaikka instansioida nimellä sut – system under test, Mockitolla homma hoituu näin:

@InjectMocks
private UserResource sut;

Jotta tuo tekee jotain on tietysti syytä ajaa tämä Mockiton kera. Lisätäänpä siis testiluokan alkuun:

@RunWith(MockitoJUnitRunner.class)

Nyt tapahtuu jo jotain. Tässä testattavassa luokassa on kuitenkin paljon riippuvuuksia, jäsenmuuttujissa on yhtä ja toista jota Spring injektoi ajon aikana, mutta jotka aiheuttavat nullpointer exceptioneitä ellei niitä ole alustettu. Olen joskus injektoinut näitä riippuvuuksia reflectionin avulla, joskus setXXX-metodeita tekemällä. Mockitolla homma sujuu kokonaisuudessaan näin:

@RunWith(MockitoJUnitRunner.class)
public class UserResourceTest {

    @Mock
    private Utils utils;

    @Mock
    private UserDetailsService userDetailsServiceMock;

    @InjectMocks
    private UserResource sut;

Eli, kun alan kirjoittelemaan omaa testiäni, kaikki kolme edellämainittua on instansioitu Mockiton toimesta, mock objekteille on mock toteutukset, jotka esim. palauttavat null/eivät tee mitään. Ja mikä parasta, mock objektit on injektoitu sut objektin sisään, privaatteihin jäsenmuuttuja-kenttiin. Ensin yritetään samalla tyypillä, sitten samalla nimellä.

Mockiton oma dokumentaatio InjectMocks-metodista sanoo näin:

Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order and as described below. If any of the following strategy fail, then Mockito won’t report failure; i.e. you will have to provide dependencies yourself.

Eli tarkkana tämän kanssa.

Mitä muuta hienoa? No Mockitossa on verrattain helppoa opettaa mockit palauttamaan sopivia arvoja, esim:

UserEntity currentUser = new UserEntity();
UserAuthentication userAuthentication = new UserAuthentication(currentUser);
when(utils.getAuthentication()).thenReturn(userAuthentication);

Ja sitten vain paukuttamaan omaa suttia, joka taas kutsuu tuota utils.getAuthentication() metodia. Jos haluat tarkistaa, kutsuiko, sen voi tarkistaa verify-kutsulla:

verify(utils).getAuthentication();

Eli, Mockito vaikuttaisi hyvältä. Pääidea on tuoda testauksen hintaa alas, ja näin saada siitä yhtä luontevaa kuin hengittäminen. Tai luontevampaa.