GDPR – Tietosuoja ja sovelluskehitys osa 1

Pyydän jo etukäteen anteeksi, tämä jos mikään on TL;DR settiä. Asiaa on vain aika vaikeaa kuvata ytimekkäästi, tahoja on monia. Jos artikkelin pituus haittaa lukemista, asennoidu lukemaan vaikka yksi kappale päivässä. Ota mukaan yhtälöön kupillinen mielijuomaasi, ja hyvää musiikkia taustalle, niin kyllä se siitä. Lupaan että substanssi on rautaa, kuittaa kommentteihin jos olet eri mieltä – saa toki kuitata vaikka olisi samaakin 😉

Totean myös, että en ole lakimies, ja tällä hetkellä tietosuoja-asetuksessa on monia alueita joista edes lakimiehet eivät voi sanoa mitään varmaa. Paras viisaus on jälkiviisaus, ja vuonna 2027 osaan kertoa faktaa. Tässä kohtaa kaikki blogautusten pointit edustavat omia näkemyksiä, jotka ovat ilman muuta ainutlaatuisen arvokkaita ja fiksuja. Mutta osa niistä on väistämättä tässä kohtaa ennustellessa väärin, ja tulkinnat tulevat sen aikanaan todistamaan. Toivon kuitenkin että mahdollisimman pieni osa.

Miksi jotain kannattais tehdä?

Tietosuoja-asetuksen siirtymä-ajan päättyessä 2018, sovellukset jotka eivät tue uusia vaatimuksia ja käyttäjän oikeuksia, muodostavat merkittävän liiketoiminnallisen riskin yrityksille. Olemassaolevien sovellusten, järjestelmien, rekisterien ja infran osalta muutos on kivuliaampi. Helpompi on alkaa tutkailemaan ihannetilaa uusien sovellusten osalta, joita vielä vasta suunnitellaan tai rakennetaan, ja tulevaisuuden sovellusten osalta, joita tullaan rakentamaan jatkossa. Ajatuksena on, että aikaa myöten opitaan ottamaan tietosuojavaatimukset huomioon automaattisesti, ja niistä tulee yhtälailla sisäänrakennettu osa kaikkea tekemistä kuin esim. sovelluksen toimivuuden testauksesta eri selaimissa. Ja tätä myöden myös kuluja saadaan alas/opitaan laskemaan ne luonnolliseksi osaksi tekemistä ja testaamista.

Ok, tylsä johdanto. Terästetäänpä tätä toisin. Kun Harri H Hakkeri eräänä päivänä penetroi systeemin ytimeen, haluamme rajoittaa riskiä siitä miten paljon sakkoja tulee maksettavaksi, ja kuinka laajaa osaa asiakasrekisteriä joudut kontaktoimaan tietosuojamurron osalta, sekä millä sävyllä iltapäivälehdet repostelevat asiaa.

On väärinkäsitys ajatella myös, että tämä koskee vain suuria organisaatioita. Sen verran uskaltaudun ennustamaan tulevaisuutta, että muutamakin keskikokoinen paja tulee ajautumaan konkurssiin jos tietosuojan kanssa ollaan leväperäisiä tai peräti röyhkeitä. Tietämättömyys tai pää puskaan-strutsiefekti ei ole tässä puolustus tai suojautumiskeino, päinvastoin. Se että yrittää vaikkei 100% onnistuisikaan, lasketaan todennäköisesti eduksi ja sakkoja tai sakon uhkaa merkittävästi pienentäväksi tekijäksi.

TL;DR

No, tässä kuitenkin tiivistelmä, mitä tulisi huomioida sovelluskehityksessä vuonna 2017, ja projekti/järjestelmätasolla noin muutenkin. Jos muistan, rupattelen infratason ratkaisuista ja hallinnasta, ja organisaatiotason prosesseista lisää toisella kertaa.

  • Riskilähtöisyys: tunnista, minimoi, dokumentoi
  • Henkilötietojen esiprosessointi: Tunnista, minimoi, dokumentoi
  • Sama juttu 3. osapuolien riippuvuuksien osalta: tunnista, minimoi, dokumentoi
  • Sama juttu henkilötiedon prosessoinnin osalta myös sisäisesti: tunnista, minimoi, dokumentoi
  • Tiedon elinkaari: määrittele,minimoi, toteuta, dokumentoi
  • Varmuuskopiot ja arkistointi, huomioi kaikki edellämainitut
  • Testidata, huomioi kaikki edellämainitut
  • Testiympäristöt, tarkkana myös tämän kautta
  • Verkkoinfra, verkkosegmentointi, minimoidaan vahingot, maksimoidaan jäljet
  • Tietoaineiston suojaus: anonymisointi,pseudonymisointi,salaus
  • Käytön valvonta, monitorointi, hälytykset
  • Kyvykkyys osoittaa tehdyt toimenpiteet, ja prosessien toteutuminen
  • Murtautumistapauksessa: prosessien tuki, forensiikka, hälytykset
  • Tietoturva-ja muut päivitykset
  • CI- ja CD- toimitusputkien suojaus ja tietoturva
  • Huom. Myös availability, saatavuus, on tietosuoja-huolenaihe
  • Henkilön oikeudet uuden tietosuoja-asetuksen alaisuudessa, käytännön toteutus?

 

Oletusarvoinen tietosuoja tähtää aikalailla samaan asiaan kuin itse tietosuoja-asetuskin – riskipohjaiseen lähestymistapaan. Ja se taas tarkoittaa että matalan riskin järjestelmiä voidaan suojata keveämmin kuin korkean riskin järjestelmiä. Eli askel numero 1…

Tunnista henkilötiedot, tunnista riskit

Tietosuoja-asetuksen kannalta riskin näkökulma on vähän eri kuin yrityksen kannalta – mutta riskin kohde on silti sama, henkilötiedot. Aiemmin puhuttiin jo siitä, miten tietoa voidaan tunnistaa, luokitella. Järjestelmissä on paljon tietoa, joka ei ole tietosuoja-asetuksen mielessä kiinnostavaa, mutta on silti ollut – ja tulee olemaan – hyvin tarpeellista suojata, esim. tuotetiedot, strategiat, ennusteet. Se mitä ei tietosuoja-asetus määritä henkilötietoksi, on kuitenkin oman harkinnan mukaan edelleenkin vapaasti suojattavissa ja käytettävissä, miten halutaan. Henkilötiedon suojaamiseen taas löytyy GDPR suunnalta kättä pidempää.

Se, minkä voi rajata pois tietosuojalain tarkoittaman henkilötiedon piiristä, voidaan salata – tai jättää salaamatta – vapaasti miten halutaan.

Tietosuoja-asetuksen välineenä käytetään pitkälti DPIA analyysiä. DPIA, eli Data Protection Impact Analysis, on vaikutusten arvioinnin malli, jolla voidaan analysoida riskikulmaa. Ennestään käytössä on monessa yrityksessä ollut PIA, Privacy Impact Assessment, joka on tähdännyt samalle alueelle, mutta hieman laveammalla pensselillä. Molemmissa on ajatuksena määrämuotoinen ja kattava tarkastelu järjestelmässä kerättävälle tiedolle. Molemmat perustuvat riskien hallinnan ajatukseen. Eli analysoidaan kerättävän tiedon riskien taso, ja sen jälkeen, riskipohjaisesti, sovelletaan sopivia kontrolleja, kunnes riski saadaan laskettua hyväksyttävälle tasolle.

DPIA mallia ei tarvitse soveltaa joka järjestelmään, mutta jonkinmoinen esikarsinta olisi tietysti aina hyvä tehdä. Periaatteessa järjestelmän tavoiteltu tietosuojataso määräytyy aika yksinkertaisesti sen mukaan, mikä on sen sisältämä riskialttein yksittäinen tieto, eli vaikka muu järjestelmä olisi aika tylsä, jos yhdestä taulusta löytyy sairauspoissaolojen syitä, se määrittää aikalailla järeimmän kautta suojaustarpeen.

Tähän väliin on hyvä todeta oma lempiteesini. Sataprosenttista tietoturvaa ei ole. Sataprosenttista tietosuojaakaan ei ole. Jokainen järjestelmä voidaan murtaa, jokaiseen dataan päästä käsiksi, jos tarkastellaan asiaa rajattoman ajan, ja rajattoman budjetin suunnasta. Lisäksi tietojärjestelmät elävät mutatoituvassa maailmassa – järjestelmä joka on tänään 99% turvallinen, kokee muutoksia vuoden aikana, ja voi ensi vuonna ollakin vain 70% turvallinen, koska sen ympäristöön on vuoden aikana tullut uusia komponentteja, avauksia, muutoksia, tai vanhoista komponenteista on löytynyt haavoittuvuuksia. Yksi suurimmista tietoturva-haavoittuvuuksista on security misconfiguration, eli virhe ympäristöjen asetuksissa, ja niitä pujahtaa sisään helposti myös järjestelmiin jotka olivat luotaessa arkkitehtuurisesti kauniita ja täydellisiä. Kun huomioidaan prosessit, ympäristöt, teknologiat, muuttujia on vain niin paljon, ettei kukaan voi väittää hallitsevansa niitä kaikkia, nyt ja aina, ja vaikka istuisit palvelimen päällä haulikko kädessä vahdissa 24 tuntia vuorokaudessa, niin mörkö pujahtaa sisään heti jos herpaannut hetkeksi. Ja ensi vuonna voi olla että istut väärän palvelimen päällä.

Eli, ainoa oikea lähestymistapa on tunnistaa suurin riski, madaltaa sitä sopivin keinoin, ja jatkaa kunnes ollaan hyväksyttävällä riskitasolla. Lisäksi tätä ei voi tehdä kertarysäyksenä, projektina, vaan tietosuojan täytyy olla jatkuva prosessi.

Tai vielä mielummin sisäänrakennettu, läpinäkyvä osa prosesseja, kaikkea tekemistä. Siihen on vielä useimmilla yrityksillä pitkä aika. Valitettavasti monet ottavat lähtölaukauksen tekemiseen vasta ensi kesänä, kun uhat alkavat toden teolla realisoitumaan.

Tietosuoja-asetuksen kannalta erityisriskin muodostavia tietoja, joihin tulee kiinnittää erityistä huomiota, ovat mm.

  • Alaikäisistä rekisteröidyistä kerätyt tiedot (vaikka rekisteröity sittemmin olisi jo täysi-ikäinen)
  • Rotu,uskonto,politiikka,terveydentila,rikosrekisteri eli eiheet jotka monen mielestä eivät ole hyviä ruokapöytäkeskustelun aiheita (mutta omasta mielestäni niitä kiintoisimpia, moukka kun olen!)
  • Biometriset tunnisteet

Eli näitä tietysti suojataan rankimman kautta. Hyvä huomata kuitenkin, että ns kovan ja yksilöivän henkilötiedon ohella, myös identiteettiin liittyvää tietoa koskee moni tietosuoja-vaatimus, esim. henkilön oikeudet. Ja se mikä liittyy identiteettiin voi joissain tapauksissa olla yksilöivää, ’jos yksilöinti voi tapahtua kohtuullisella vaivalla tietoja yhdistelemällä’ – esim. muutama erillinen paikkatieto, tai erityinen tietopaketti harvaan asutulla alueella, jne – eli samalla lailla kuin itse identifioivaa tietoa, voi varautua suojaamaan myös identiteettiin liittyviä tietoja.

Toinen tapa lähestyä riskiä on miettiä ihan terveellä järjellä, miten suuren riskin REKISTERÖIDYLLE muodostaa, jos tämä tieto julkaistaisiin iltapäivälehden etusivulla. On hyvin tärkeää muistaa, että tietosuoja-asetuksen riskianalyysissä riskin näkökulma on aina rekisteröity, ei rekisterinpitäjä. Se näkökulma määrää, miten raskaasti tietoa tulisi suojata ja vartioida.

Toisaalta samoja periaatteita voi myös soveltaa muuhun sensitiiviseen tietoon, vaikka ei henkilötietoa olisikaan. Se ei ole tietosuoja-asetuksen kannalta mielenkiintoista, mutta voi olla liiketoiminnan kannalta hyvinkin mielenkiintoista.

Minimoi ja dokumentoi kerättävä tieto

No niin, nyt tulee se hyvä uutinen. Paras tapa keventää kuluja ja suojauskontrollien tarvetta, on olla keräämättä sitä henkilötietoa alunperinkään. Ennen vanhaan oli tapana keräillä kaikenlaista ihan vain varmuuden vuoksi, ties vaikka sitä jossain raportissa tai analyysissä kaivattaisiin, ja miksikäs ei. Sellainen lähestymistapa ei enää tietosuoja-asetuksen aikana kanna pitkälle.

Nyt kannattaa aloittaa miettimällä, mitä tietoa todella tarvitaan, ja millä oikeudella sitä kerään, varastoin, prosessoin. Tämä osa kannattaa dokumentoida hyvin, ja keskustella niistä harmaista alueista, joista ei olla varmoja. Voi myös miettiä sitä, voiko henkilötietoja eristää esim. omaan erilliseen järjestelmään, palveluun, kantaan, tauluun, jota voidaan suojata järeämmin kuin muita.

Sen ohella että minimoidaan siis ’leveyssuunnassa’ kerättävää tietoa – kyseenalaistamalla jo alun alkaen mitä kenttiä laitetaan, mitä tietoja kysellään – kannattaa myös huomioida aikadimensio, eli minimoida miten pitkään tietoja säilytetään. Minimointi ei tarkoita, että kaikki tieto pitäisi heti pyyhkiä, mutta tiedon elinkaaren suunnittelu on erittäin hyvä käytäntö ottaa mukaan tietomalliin alusta alkaen. Elinkaari voi olla vaikkapa puoli vuotta, tai viisi vuotta, kymmenen vuotta, jne. Mutta kun se ymmärretään, dokumentoidaan, ja toteutetaan, on taas pienennetty merkittävästi hyökkäyspinta-alaa.

Jos tapahtuu se pahin, eli huomataan tietomurto tai väärinkäytös järjestelmän ytimessä, muualle arkistoitu ja erikseen suojattu, tai täysin poistettu tieto voi olla sellaista, jota tietomurron ei katsota koskevan, ja näin ollen joudutaan kontaktoimaan vain niitä, joiden tiedot ovat aktiivisessa kannassa. Lisäksi tämäntyyppinen elinkaariajattelu ja suojauskontrollit lasketaan eduksi jos joudutaan jotain sakkorangaistuksia tai muita sanktioita miettimään.

Mutta siis, vanha tapa kerätä kaikki mahdollinen, ja säilyttää sitä ajan tappiin on huono käytäntö, ja sitä ei enää pitäisi harrastaa. Ja jos tiedon pinta-alaa tai säilytysaikaa ei pysty fiksusti minimoimaan, ainakin se kannattaa dokumentoida. Dokumentaatiota tulisi tuottaa sekä järjestelmäkehityksen ja ylläpidon tarpeisiin, että myös rekisteröidyn selosteeseen, jotta läpinäkyvyyden periaate toteutuu. Ja jos rekisteröity pystyy ymmärtämään kerätyn tiedon laajuuden, syyt, ja elinkaaren sen perusteella, pyynnöt esim. poistaa tietojaan järjestelmästä saattavat harventua.

Varaudu kuvaamaan MITÄ kerätään, MIHIN tarkoitukseen, ja MITEN sitä prosessoidaan (aka keiden toimesta). Varaudu tarjoamaan yhtä helpot keinot myöntää lupia tiedon keruuseen ja käyttöön, kuin lupien tarkistamiseen ja poistamiseen.

Minimoi pääsy

Tietosuojassa ei ole kyse vain ulkoisista tietomurroista, yli 30% väärinkäytöksistä tapahtuu verkon sisäpuolella, usein omien työntekijöiden, nykyisten tai entisten, toimesta. Huonosti suunnitellussa (tai monimutkaisessa, suurikokoisessa, iäkkäässä) verkossa voi olla myös pääsyä partnereilla, ulkoisilla työntekijöillä, konsulteilla, vuokratyöntekijöillä, tai miksei myös sovelluskehittäjillä, ylläpitäjillä, järjestelmätoimittajilla, jne.

Motiiveja voi olla esim. uteliaisuus, pyrkimys hyötyä, vandalismi, jne. Tietosuoja-asetus on tältä osin hyvin yksinkertainen. Henkilötietoon ei tulisi olla pääsyä enempää kuin mitä on tarpeen. Se mitä on tarpeen tulisi olla dokumentoituna. Eli ei ole kiellettyä että ylläpitäjillä on pääsy tietoon, kunhan se on läpinäkyvää. Eri asia on millaisen riskin se muodostaa.

Jos jotain tapahtuu, pääsyn minimointi myös voi rajoittaa vahinkoja, tai parantaa mahdollisuuksia näyttää toteen, mitä osaa tietoja tietomurto tai tietosuojaloukkaus koskee.

Näissä on hyvä suunnata huomiota terveydenhuollon järjestelmien suhteen, Suomessa ja muualla. Niissä on jouduttu jo iät ja ajat huomioimaan potilastietojen luottamuksellisuus, ja sieltä löytyy hyvin ideoita, käytäntöjä, toimintatapoja. Eri asia on, onko niitä terveydenhoidon järjestelmissäkään aina toteutettu ideaalisti. Mutta siellä on jouduttu jo pitkät ajat vastaamaan tällaiseen vaatimukseen.

3. osapuolen prosessointi

Tietosuoja-asetus ei estä sitä että dataa voi nyt ja jatkossakin prosessoida myös 3. osapuoli. Itse asiassa, prosessoijaksi kun lasketaan myös esim. pilvipalvelutarjoajat, kuten Amazon AWS, ja Microsoft Azure, enenevässä määrin toimitaan ympäristössä jossa on useampia osapuolia prosessoijina.

Nyt mennään alueelle joka ei ole omaa vahvinta aluetta: Lakipykälät ja niiden tulkinta. Mutta vapaasti oman ymmärryksen mukaan tärkeää on huomioida tämän osalta dokumentointi, ja sen mukana tulee luonnollisesti muut hyveet, kuten tiedon ja pääsyn minimointi ja suojaus, sekä sopimukset. Sopimustekniikka tulee varmaan tässä vielä kehittymään vuoden sisään, esim. Amazon on luvannut että ensi vuoden kesään mennessä tulee olemaan tietosuoja-asetuksen edellyttämät asiat huomioituna palvelusopimuksissa.

Se missä tulee olla tarkkana, on yhteisen vastuualueen kasvu, ja se missä rajat kulkevat. Moderni tietojärjestelmä on kokonaisuus jossa on aika monia tahoja. Jos nyt sattuisi että esim. AWS vastuunjakomallin mukaisesti tietosuojaloukkaus on tapahtunut 3. osapuolen tontilla, esim. medioiden huolimattoman hävityksen, tai fyysisen tietoturvan puutteen vuoksi, kantaako Amazon myös rahallista vastuuta sakoista, ja minkä firman liikevaihdon mukaan se menee? Entä jos 3. osapuoli ei olekaan AWS, joka sinällään on rutinoitunut ja ison talon koneisto, vaan autotallissa majaileva analytiikkafirma?

Mitä ajan takaa tässä, on pari huomiota. Tulkinnat tulevat elämään ja muotoutumaan vielä vuosia, sitä mukaa kun ikäviä asioita tapahtuu. Ja jatkossa ei riittäne pestä käsiään tietoturvasta ja tietoturvasta siinä kohtaa kun data siirtyy 3. osapuolen käsiin. Yhteisvastuullisuus on päivän sana, ja hyvä niin.

 

Jatkuu ensi numerossa…

No niin, kuten varoittelin, tästä tulee pitkä juttu. Kulmia on monia. Kirjailen lisää ajatuksia toisella kertaa, mennen lähemmäs kehittäjän konkretiaa. Osa näistä asioista, kuten 3. osapuolen sopimukset, eivät ole välttämättä heti toimittajan mielestä ehkä asioita joihin voi vaikuttaa, mutta softaprojektissa tulisi asianmukaisen matkaopastelijan kiinnittää huomiota siihen, miten asiat kokonaisuutena tehdään. Jos joku osa-alue on rempallaan, siitä kannattaa keskustella, ja kiinnittää huomiota, vaikka sieltä voisikin löytyä lisäkuluja.

Osittainen tietoturva on hyödytöntä tietoturvaa.

 

Mainokset

GDPR – henkilön (uudet) oikeudet

Uuden tietosuoja-asetuksen alla henkilöllä on terävöitettyjä oikeuksia, kuten oikeus poistaa tietonsa (right of erasure/right to be forgotten), tai siirtää niitä, ja tietysti myös tarkistaa ja korjata niitä. Tässä voi tulla muutama suorastaan ironinen ongelma vastaan – miten voimme varmuudella yksilöidä ja ennenkaikkea tunnistaa kaiken henkilöön liittyvän tiedon?

Screenshot 2017-06-28 10.01.52

Otetaan skenaario, Harri A Tötteström, asiakkaamme, ottaa yhteyttä ja haluaa 25.5.2018 poistaa tietonsa järjestelmästä. Kehen hän ottaa yhteyttä? Miten prosessi etenee? Vai saako tätä itsepalveluna?

Tunnista

Ensimmäinen temppu on tunnistaa Harri varmasti. Miten sen teemme? Jos käytössä on sähköinen id ja tunnistus jo ennestään, homma hoituu sillä. Jos ei, miten tunnistetaan? Asetus erikseen mainitsee, että tunnistamisen vaikeus ei ole syy evätä pyyntö. Tarvittaessa tulee hyväksyä Harrilta riittävä määrä tietoja, että voidaan varmasti tunnistaa. Tullaanko näyttämään passi paikan päälle? Piisaako lista henkilökohtaisista tiedoista identifioimaan? Tätä pitää terävöittää useimmissa yrityksissä.

Mitä jos meillä ei ole rekisterissä varmaa tunnistetta, vaan vain etunimi+sukunimi-pari?

Tarkista

Seuraava askel on tarkistaa, onko pyyntö validi. Jos kyseessä on esim. asiakassuhde, ja tiedot ovat toiminnan jatkamisen kannalta välttämättömiä, ja Harri ei ole päättämässä asiakassuhdettaan, tietojen poistoa ei voitane tehdä, ja tästä tulee tiedottaa Harrille. Muita syitä evätä pyyntö on jos Harri yrittää poistaa jonkun muun tietoja, tai jos lainsäädäntö vaatii tietojen säilyttämistä. Henkilön oikeudet ovat tässä kuitenkin hyvin vahvat, ja erityisen tärkeää on, että vastaus pyyntöön tulee 1kk kuluessa pyynnön esittämisestä. Kuulostaa että siinä olisi paljonkin aikaa, mutta ellei tätä prosessia ole jo jumpattu hyvissä ajoin, ja aletaan vasta pyynnön tultua pähkäilemään, ollaan pulassa.

Suorita

Päästiinkö tänne asti? Rekisteröity on tunnistettu, pyyntö on validi, ja nyt pitäisi toimittaa. Pari uutta haastetta ratkaistavaksi. Voiko henkilötiedot oikeastaan poistaa järjestelmästä ilman että viite-eheydet kärsivät tai ilmenee bugeja? Useimmissa tapauksissa voi olla turvallisempaa suorittaa poisto päällekirjoittamalla, anonymisoimalla tiedot tarpeeksi vahvasti. Tätäkin tulee järjestelmän tukea, esim. jos anonymisoinnissa poistetaan henkilötunnus, puhelinnumero, jne, järjestelmän tulee siitä huolimatta toimia. Tämä ei välttämättä toimi etenkään vanhoissa järjestelmissä ihan oikein. Jos kylmästi poistetaan tietorivejä, tulee ymmärtää miten ne liittyvät toisiinsa, katsoa että poistetaan tarpeeksi, mutta ei liikaa.

Tässä voi herätä ajatus, että ainakin alkuun palvellaan muutamia pyyntöjä käsin, manuaalisilla prosesseilla. Se on ihan validi ajatus, joskin täytyy tarkistaa, että siinäkin toteutuu muut tietosuojan edellyttämät vaateet, esim. minimointi tietoihin pääsyyn, ja kyky näyttää toteen kuka pääsi tietoon, ja mitä tiedolle on tapahtunut. Jos logataan sql:llä suoraan kantaan, tämä voi toteutua, tai sitten olla toteutumatta.

Tähän kohtaan ei ole mitään fiksua viisasten kiveä jaossa. Manuaalisia prosesseja tullaan tarvitsemaan jossain määrin, mutta niiden kanssa täytyy olla tarkkana, tai ne avaavat lisää tietosuojahaavoittuvuuksia tai riskejä, ja ihan liiketoiminnallisiakin riskejä. Itse vihaan manuaalisia prosesseja, ja jonain päivänä automatisoin ne kaikki, se on minun riskiretkeni. Mutta reaalimaailmassa tähän voi parhaiten vaikuttaa uusien ja tulevien tietojärjestelmien osalta. Muille pitää luoda paras mahdollinen ratkaisu nykytilassa, ja tarpeen vaatiessa laittaa parannuksia roadmapille. Yksi idea voi olla esim. datan virtualisointi abstraktiokerrokseen, jossa valvotaan pääsyä ja tekemisiä. Mutta se ei ole yleensä halpaa.

Jutustelen myöhemmin sovelluskehityksen näkökulmasta miten asiaa kannattaa taklata, mutta tärkeintä on että tietomalli sallii poisto- ja siirtopyynnöt, siitä lähtee kaikki.

Anna mun kaikki tiedot, kiitos

Toinen mielenkiintoa herättävä pyyntö on saada kaikki itsestään kerätyt tiedot konekielisessä yleisessä siirtomuodossa. Tämä on uudistus jo aiemmin voimassaolevaan direktiiviin, jossa oli mukana oikeus tarkistaa tietonsa. Nyt puhutaan tietojen siirtämisestä. Se voi tapahtua siten, että rekisteröity lataa tietonsa, esim. csv, xml, json muodossa itsepalvelukäyttöliittymässä, mutta asetus rohkaisee myöskin kehittämään valmiuksia siirtää tietoja suoraan toisille vastaaville palveluntarjoajille, ilman että rekisteröidyn täytyy toimia välissä. Se, millä toimialoilla tässä on järkeä, tietysti vaihtelee.

Mutta Harri T esittää taas siis pyynnön. Anna mun kaikki tiedot, kiitos. Aikaa kuukausi – tai kolme kuukautta jos pyynnön toteuttaminen on erityisen hankalaa syystä tai toisesta. Mitä tapahtuu?

Samat kuin aiemmin. Tunnista vahvasti. Tarkista pyynnön validiteetti. Jos kaikki näyttää hyvältä, on aika miettiä, mitä tietoa laitetaan pakettiin. Asetuksen mukaan pakettiin pitäisi tulla kaikki henkilöstä suoraan kerätyt ja henkilön itse toimittamat tiedot, mutta pakettiin ei kuulu tiedot jotka on näistä johdettu, analysoitu, tai jotka edustavat liiketoiminnallisia salaisuuksia. (No, asetus ei itseasiassa mene näin tarkkoihin lausuntoihin, mutta Working Party 29 tulkinnat tarkentavat). Hyvä huomata myös artiklan 23 asettamat rajoitukset siihen milloin näitä oikeuksia ei voi harjoittaa.

Mielenkiintoinen kohta tulee, jos henkilön tietopaketti sivuaa toisen henkilön tietoja. Jätän kotitehtäväksi selvittää mitä sitten tapahtuu. Vinkkinä voin kertoa, että se ei ole syy evätä pyyntöä saada tietonsa.

Ai niin, ja tämä oli se kohta josta on tarjolla 20 miljoonan sakko tai suurempi, jos homma ei toimi.

Otetaanpa tuosta vielä maistiainen lakipykälää, tietosuoja-asetuksen peruslausunto (recital) 68:

Jotta voitaisiin edelleen vahvistaa rekisteröityjen oikeutta valvoa henkilötietojaan silloin, kun henkilötietojen käsittely suoritetaan automaattisesti, rekisteröidyn olisi myös voitava saada häntä koskevat henkilötiedot, jotka hän on toimittanut rekisterinpitäjälle, jäsennellyssä, yleisesti käytetyssä, koneellisesti luettavassa ja yhteentoimivassa muodossa ja siirtää ne toiselle rekisterinpitäjälle. Rekisterinpitäjiä olisi kannustettava kehittämään yhteentoimivia muotoja, jotka mahdollistavat tietojen siirtämisen. Tätä oikeutta olisi sovellettava silloin, kun rekisteröity on antanut henkilötiedot oman suostumuksensa perusteella tai kun käsittely on tarpeen sopimuksen täytäntöönpanemiseksi. Sitä ei sovelleta silloin, kun käsittely perustuu muuhun lailliseen perusteeseen kuin suostumukseen tai sopimukseen. Tämä oikeus on luonteeltaan sellainen, ettei sitä olisi käytettävä niitä rekisterinpitäjiä vastaan, joiden julkisiin velvollisuuksiin henkilötietojen käsittely kuuluu. Siksi sitä ei pitäisi soveltaa silloin, kun henkilötietojen käsittely on tarpeen rekisterinpitäjää koskevan lakisääteisen velvoitteen noudattamiseksi tai yleisen edun vuoksi toteutettavan tehtävän suorittamiseksi tai julkisen vallan käyttämiseksi. Rekisteröidyn oikeus siirtää tai vastaanottaa häntä koskevia henkilötietoja ei saisi luoda rekisterinpitäjille velvoitetta hyväksyä tai ylläpitää tietojenkäsittelyjärjestelmiä, jotka ovat teknisesti yhteensopivia. Jos tietyssä henkilötietoja sisältävässä tietojoukossa tiedot koskevat useampia kuin yhtä rekisteröityä, oikeus vastaanottaa henkilötietoja ei saisi rajoittaa toisten rekisteröityjen tämän asetuksen mukaisia oikeuksia ja vapauksia. Tämä oikeus ei saisi myöskään rajoittaa rekisteröidyn oikeutta saada henkilötiedot poistetuiksi eikä tämän asetuksen mukaisia rajoituksia kyseiseen oikeuteen, ja se ei etenkään saisi merkitä niiden rekisteröityä koskevien henkilötietojen poistamista, jotka tämä on antanut sopimuksen täytäntöönpanoa varten, siinä määrin ja niin kauan kuin henkilötiedot ovat tarpeen sopimuksen täytäntöönpanoa varten. Kun se on teknisesti mahdollista, rekisteröidyllä pitäisi olla oikeus saada henkilötiedot siirrettyä suoraan rekisterinpitäjältä toiselle.

Muut oikeudet

No niin, nämä oikeudet ovat saaneet eniten huomiota, mutta ei pidä laiminlyödä muitakaan. Aika pitkälle tosiaan päästään jos muistetaan nämä:

  • Tietojen keruun ja käsittelyn tulee olla läpinäkyvää
  • Henkilöllä tulee olla helppo pääsy siihen mitä tietoja hänestä on kerätty, miksi, ja mikä on niiden elinkaari
  • Pitää olla helpot keinot poistaa tietonsa järjestelmistä, kun niiden säilytykselle ei ole enää perustetta, tai ladata ne itselleen tai kolmannelle osapuolelle käyttöön
  • Kaiken tämän tulee tapahtua tietoturvallisesti ja tietosuojaa kunnioittaen
  • Rekisteröidyllä tulee olla mahdollisuus tarkastaa myös luvituksensa, ja peruuttaa niitä yhtä helposti kuin antaa niitä

Nämä johtavat kohden keskitettyä tunnistamista, ja jonkunmoista identiteetin ja lupienhallinnan näkymää/portaalia, jossa on paljon itsepalveluita. Pakko ei ole moiseen ryhtyä, mutta pitkällä juoksulla homma tulee varmasti halvimmaksi, ja tätä kauttahan ne uudet liiketoimintamahdollisuudet avautuvat. Jos lupien antaminen ja peruuttaminen on helppoa, se rohkaisee antamaan niitä pienemmilläkin täkyillä, ja avaamaan henkilötietojensa käyttöä jopa rohkeammin alueille joille ei ole vielä menty.

Automaattinen poisto

Aika paljon rahaa säästää myös, jos alusta alkaen sovelletaan kerättyjen tietojen minimointia hyvänä periaatteena järjestelmäsuunnittelussa. Minimoinnissa on kaksi tärkeää pointtia: Kerätään vain se mitä on tarpeen, ei tarpeetonta. Ja säilytetään sitä tietoa vain sen verran mitä on tarpeen, sen jälkeen arkistoidaan, ja aikanaan automaattisesti poistetaan. Jos nämä prosessit on myös selkeästi kuvattu tiedon keruun yhteydessä, tarvetta erilliselle tietojen poistolla asiakassuhteen päätyttyä on vähemmän. Arkistointivaihe välissä voi olla tarpeen, ja se voi olla esim. kuudesta kuukaudesta vuosiin, riippuen vähän siitä, millaisia tarpeita kerätylle tiedolle on jälkeenpäin.

Tämä edellyttää kuitenkin prosessijumppaa, ja se on organisaatioille aina paljon kivuliaampi ja hitaampi ratkaisu kuin joku järjestelmähankinta tai koulutus.

Ensi kerralla lisää tiedon suojaamisen keinoista, ja sovelluskehitys/hankintanäkökulmista.

Angular 2 käyttöön

Viime ajat on tullut vietettyä Angular kakkosen kanssa. Tarkoitus oli alunperin jo joulun aikoihin käyttää kunnolla aikaa tähän uuteen päivitykseen, mutta silloin tuli kaikenlaista pientä tekemistä tielle.

Ensivaikutelma on ihastus. Kirjoittelin taannoin Aureliasta, joka on myös hieno paketti, ja jossa on paljon samaa Angularin kanssa. Mutta Angularin vahvana etuna on pitkät perinteet ykkösversiosta, ja sen myötä laaja käyttäjäkunta. Uusi versio ei heitä kaikkea roskiin, mutta tuo kaikenlaista mukavaa uutta. Tässä muutama highlight poimintana:

  • Typescript – ei ole pakko käyttää sitä mutta onhan se ihanaa
  • ES6 ja moduulit – käytä mitä osia kaipaat, ei tarvitse ladata kaikkea joka projektiin
  • Komponentit – ah miten elegantti ja ketterä lähestymistapa ui kehityskeen

Angular kakkosesta on ehditty jo kirjoittamaan tiukkoja vertailuja toista kuningasta – Reactia vastaan – ja puolin ja toisin. Molemmilla lähestymistavoilla lienee jatkossakin omat faninsa.

Vastaavasti laskukäyrän puolella olisi Bower ja Grunt – tuntuu että Angular kakkosen kanssa luontevaa on yhdistää npm, Webpack, ja tarvittaessa Gulp – jos sitäkään. Keep it simple, stupid! Node vitonen on myös nopea buildihommissa – ja aiemmin taisinkin jo kehaista npm:n nykyistä windows-ystävällistä hakemistorakennettakin.

Lähitulevaisuudessa tulossa jotain katsojaystävällistä getting started-tutoriaaliakin, toki hyviä on ihan Angularin omillakin sivuilla.. Mutta jos haluaa vähän helloworldiä realistisempaan mennä…

JSON serialisointi: Pois Circular Reference – manalasta

En tiedä onko tuttu tilanne, mutta itselleni harmillisen usein tavattu. Otetaan oliorakenne, esim. Order -> OrderItem, eli tilaus ja tilausrivejä. Rakenne menisi näin:

class Order {

  List<OrderItem> orderItems;

}

class OrderItem {}

Tähän asti kaikki loistavasti. Nyt kuitenkin on useita syitä miksi haluaisimme myös linkin OrderItemistä Order-luokkaan, esim. jos item-riveissä on assosiaatioita muuallekin ja niistä pitäisi näppärästi päästä header-tietoihin kiinni. Tai jos käyttää serialisointiin JPA-tekniikkaa eikä halua tehdä turhia välitauluja (One-to-Many assosiaatiossa tieto assosiaatiosta on many-päässä eli OrderItem luokassa)

Pysyitkö mukana? Hyvä, muutamme siis rakenteen tällaiseksi:

class Order {

  long id;
  List<OrderItem> orderItems;
}

class OrderItem {
  long id;
  Order order;
}

Ja tästä päästääkin syklisten referenssien helvettiin. Tämä on oliorakenteena ihan kelvollinen ja mahdollistaa juuri edellämainitun navigoinnin molempiin suuntiin (bidirectional one-to-many association). Tähän voisi iloisesti läpsäyttää JPA annotaatiot ja antaa sen valua kantaan ja kannasta triviaalilla koodilla.

Ongelmia tulee siinä vaiheessa kun haluttaisiin serialisoida tätä rakennetta johonkin hierarkiseen puurakenteeseen, esim. XML tai JSON. Ongelma johtuu siitä että dynaaminen sarjallistaja, esim. JAXB tai Jackson, käy läpi olion ominaisuudet yksi kerrallaan, ja kutsuu gettereitä, kerää tiedot, ja muuttaa ne tekstimuotoiseksi siirtokelpoiseksi dataksi. Siinä käy siis näin:

  1. Tallennetaan order, hienoa. Order on oliorakenne, joka sisältää orderItems listan, käydään se läpi
  2. Käsitellään jokainen orderItem vuorollaan. OrderItem on oliorakenne, joka sisältää viittauksen Order olioon
  3. Käsitellään jokainen viitattu Order vuorollaan. Order on oliorakenne joka sisältää OrderItems listan

Ja niin edelleen. Ikiliikkuja on keksitty. Tästähän saa palkakseen yleensä jonkun hienon kaatumisen ja cyclic/circlar reference errorin. Tai jos hauskasti käy, kone puuskuttaa hetken ja antaa stack overflow errorin tai out of memory errorin.

Mitä sitten on tehtävissä? Tämä artikkeli koskee JSON vaihtoehtoa, jos olet vielä XML parissa, olet pysyvästi helvetissä vailla poispääsyä, pahoittelen.

Jos käytät tätä esim. Jacksonin puitteissa, vaikkapa REST-rajapinnassa, ratkaisutapoja on muutama (tosiasiassa osa näistä sopii XML hommiinkin, jos edellisestä kohdasta tuli paha mieli):

  1. Katkaise syklinen referenssiketju merkkaamalla jommassakummassa päässä referenssi ei-serialisoitavaksi. Tapoja tähän on monia, Jackson taitaa tukea esim. Javan transient avainsanaa, @JsonIgnore annotaatiota, ja luokkatasolla voi myös listata ohitettavat kentät @JsonIgnoreProperties-annotaatiolla
  2. On myös mahdollista merkitä master-dependant suhde Jackson annotaatioilla @JsonManagedReference ja @JsonBackReference
  3. Tehdään aina value/transfer object johon normalisoidaan kulloinkin tarvittavat tiedot
  4. Myös voi merkitä identity-kentät Jackson annotaatioilla, @JsonIdentityInfo kertoo mikä kenttä on uniikki avain, jonka jälkeen serialisoinnissa voidaan viitata vain id arvoon, ei käydä läpi koko sisältöä.
  5. @JsonView annotaation käyttö näkymien muodostamiseen

Kahdessa ensimmäisessä kohdassa on yksi ongelma: Ne eivät salli talsimista edestakaisin, vaan vain yhteen suuntaan. Mutta ne ratkaisevat syklisen referenssipulman katkaisemalla rekursioketjun, eli sopivat moneen tilanteeseen. Kolmas kohta sisältää potentiaalisesti hurjan paljon virhealtista käsityötä ja myöhemmin ylläptoa ja en ole ollut koskaan kummankaan suuri fani. Neljäs kohta generoi kauheaa huttua serialisoinnista, ja en ole vielä löytänyt sille hyötykäyttöä. Neljäs kohta on näistä oma suosikkini. Se voisi olla vielä parempikin mutta sillä ainakin pääsee alkuun. Ja uusin Spring, Spring Boot, ja JAX-RS yhdistelmä tukee näitä ihanasti.

Homma toimi näin: Merkataan @JsonView annotaatiolla ne kentät, joita halutaan ehdollisesti serialisoida tai olla serialisoitamatta. Parametrina tulee tyypin nimi, joka on yleensä Java rajapinta. Esim. näin:

class View {

interface GimmeOrderRows {}

interface GimmeOrderHeader {}

}

Nyt voidaan muokata aiempia koodeja näin:

class Order {
  
  long id;
  
  @JsonView(View.GimmeOrderRows.class)
  List<OrderItem> orderItems;

}

class OrderItem {
  long id;

  @JsonView(View.GimmeOrderHeader.class)
  Order order;

}

Nyt pystyt hakemaan assosiaatiot on-demand periaatteisesti, eli voit navigoida kummasta päästä vaan. Jos et anna JsonView-annotaatiota, oletuksena saat kaiken. Heti jos annat yhdenkin @JsonView annotaation, saat kaikki kentät joihin se täsmää tai joita ei ole millään JsonView annotaatiolla varustettu. Eli jos meillä olisi tämän näköinen jax-rs palvelu…

@GET
@Path("order")
@JsonView(View.GimmeOrderRows.class)
public Order fetchOrderWithItems(long id) {
  return orderRepository.getOne(id);
}

… niin syklisen referenssin peikko pysyisi piilossa. Koska Jackson serialisoisi Orderin, ja sen sisältämät OrderItemit id-arvoineen, mutta ei seuraisi enää polkua niiden sisältämiin Order-instansseihin.

Vastaavasti nyt voisi huoletta hakea vaikkapa yhden OrderItem instanssin OrderHeadereineen ilman syklisiä referenssejä:

@GET
@Path("orderitem")
@JsonView(View.GimmeOrderHeader.class)
public OrderItem fetchOrderItemWithOrder(long id) {
  return orderItemRepository.getOne(id);
}

Samalla tekniikalla voi noutaa ehdollisesti esim. salasanatietoja, tai binäärisisältöä, tai muuten vain pitkiä kenttiä. Yhdessä kohtaa voi olla vain yksi JsonView-parametri, mutta koska niillä voi olla perintähierarkioita jotka tunnistetaan, rajoitus ei ole paha. On myös mahdollista säätää sellainen oletus, että mitään kenttää ei palauteta elleivät jsonviewt täsmää – ei myöskään niitä joista annotaatio puuttuu kokonaan.

Nyt kun vielä saisi Javaan luontevan suorastaan sisäänrakennetun JSON rajapinnan….

First rule of exception handling: Do not do exception handling!

Error: There is no error!

Tästä onkin pitänyt jo hetken aikaa pistää ajatuksia ylös, koulutuksissa aiheesta aina saarnaan mutta yritetään koota ajatuksia enemmän tai vähemmän koherentisti jopa artikkelin muotoon. Lainasin iskevän Fight Club henkisen artikkelin toisesta paikkaa, mutta ajatukset ovat ihan omia. Niissähän voi olla myös mielipiteitä ja jopa väärinkäsityksiä, eli tunne olosi vapaaksi kertoa mielipiteitäsi 😉 😉

NullpointerException at line 5872/Error: There is no error!

Konsulttihommissa ja ihan vain käyttäessä kotimaisia ja ulkomaisia web-sovelluksia on tullut nähtyä mitä kauheampia lähestymistapoja virhekäsittelyyn. Alkaen ohjelmiston kaatumisesta ja stacktrace-virhepinosta ruudulla tai lähdekoodin näkemisestä ihan vain tyhjään valkoiseen sivuun tai klassisiin: generic error, something unexpected happened tyyppisiin. Kun virhekäsittely on tehty huonosti, se luo suunnattomia tietoturva-haavottuvuuksia, ja luo ohjelmistosta myös huonolaatuisen ja epävakaan kuvan käyttäjille – mikä kaiken lisäksi on useimmiten totta.

Takaisin polulle

Miksi sitten virhekäsittelyä ei tehdä oikein? Kun projektin aikataulupaineet puskevat päälle mennään usein kiireen alla koodaamaan ja silloin saattaa olla että keskitytään vain siihen yhteen ainoaan happy-skenaarioon testauksessa, siihen kun kaikki toimii. Yhtä tärkeää olisi myös miettiä polut: Mikä voi mennä pieleen. Testata ne, rakentaa niille käsittelyt jotka mahdollisimman sulavasti ohjaavat käyttäjän taas tuottavalle polulle. Tässä onkin virheiden käsittelyn tärkein oppi (ja hyvä neuvo elämässä noin muutenkin). Älä keskity siihen mikä meni pieleen – keskity siihen miten normaalitoiminta voi taas jatkua.

Sovelluksessa tapahtuvat epänormaalit tilanteet johtuvat tyypillisesti kahdesta eri asiasta: Käyttäjästä, tai olosuhteista. Edelliset eivät ole oikeastaan virheitä, vaan väärinkäsityksiä, jotka pitää lempeästi ohjaten oikaista. Jälkimmäiset taas ovat asioita joista käyttäjälle on tarpeetonta tiedottaa näyttäen poikkeuspinoa ja koodin rivinumeroita: Loggaa niiden tekniset yksityiskohdat talteen, korjaa ne välittömästi jos pystyt, tai jos et pysty, kerro käyttäjälle että järjestelmässä on ongelmaa, anna ohjeet miten tästä voi edetä, ja mielellään tiketti jolla logiviestit voidaan jäljittää.

Opasta käyttäjää lempeästi

Ohjaa siis käyttäjä takaisin tuottavalle polulle. Se tarkoittaa että ennakoit mahdollisia virhetiloja. Tuliko syöte joka ei ole sallittu? Opasta käyttäjää hyvin esimerkein. Älä anna sovelluksen kaatua ylimääräiseen heittomerkkin tai pienempi-kuin merkkiin. Älä tyhjennä syötettyä lomaketta tiedoista ja näytä käyttäjälle virheilmoitusta tyyliin: ”Syötteessä oli virhe. Yritä uudelleen”.  Hyvä virhekäsittely ei hävitä jo syötettyjä tietoja mutta näyttää tarkalleen missä syötevirhe oli ja mieluiten hyvän esimerkin kera millaista syötettä tässä odotetaan. Esim. puhelinnumerot, päivämäärät, numerot menevät herkästi sekaisin, ja väärinkäsityksen vuoksi merkkijono voi olla aivan liian lyhyt tai pitkä. Tarkista myös että syötetyt merkit ovat järkeviä sovelluksen kannalta: Unicodessa on n. 65 000 merkkiä joista periaatteessa jokainen voi olla turvariski väärissä olosuhteissa. Ehkä siis on parempi olla tarkistamatta erikseen vaarallisia merkkejä, ja sensijaan miettiä tarkemmin mikä on sallittua.

Jotain odottamatonta tapahtui – odota hetki ja yritä uudelleen, tai ota yhteys ylläpitoon

Kun jotain odottamatonta menee pieleen se voi johtua esim. odottamattomasta kuormituksesta, verkkoyhteyksien menettämisestä, sähkökatkoksesta, odottamattomasta uudelleenkäynnistyksestä, viiveiden aiheuttamasta timeoutista, siitä että joku kompastui verkko tai sähköjohtoon, kovalevy hajosi, etc. Mikään näistähän ei ole oikeasti odottamatonta, eihän? Näitä tapahtuu, ja näitä voi myös testata. Voit tarkistaa miten sovelluksessasi näkyy kun kantapalvelin ajetaan alas tai joku osakomponentti hajoaa tai sammuu. Kuormitusta voidaan simuloida ja vasteaikoja testata. Toisin sanoen, kun odotettuja odottamattomia virhetiloja ilmenee, hyvin tehty järjestelmä kertoo käyttäjälle riittävästi, loggaa yksityiskohdat talteen, ja tarvittaessa hälyttää ylläpidon jotta jotain voidaan tehdä. Ja kun jotain todella odottamatonta tapahtuu, prosessi on periaatteessa sama mutta ehkä kiireisempi. On mahdollista tehdä geneerinen virhekäsittely joka kattaa loput tilanteet joita ei todellakaan osattu odottaa. Miten nopeasti virheen sattumisesta päästään taas takaisin tuottavalle polulle? Siinä erottuvat jyvät akanoista.

Virheiden käsittelyn Antipatterneja

Sanaa antipattern en edes yritä suomentaa (Vastahahmo? ;), mutta on tullut nähtyä kooditasolla levinneitä turmiollisia lähestymistapoja siihen miten virheitä käsitellään. Mitä vikaa on seuraavissa malleissa?

try {
      // Some code that causes errors here
} catch (NullPointerException npe) {
} catch (ArrayIndexOutOfBoundsException aiooe) {
      aiooe.printStackTrace();
} catch (Exception ex) {
      showErrors("Connection failure, please try again");
}

Hoksaatko mitään turmiollista? Siinä on ainakin kolme antipatternia käytössä. Osa näistä johtui Java kielen valitettavasta visiosta käyttää checked exception mallia eli pakko-käsitellä tyyppisiä poikkeuksia. Se on saanut ohjelmistokehittäjät generoimaan usein tarpeettomia try-catch-lauseita, piilottelemaan poikkeuksia, käsittelemään niitä kun ei ole aika käsitellä, ja käsittelemään niitä huonosti. Mikä meni pieleen?

– Huomasit varmaan tyhjän catch-lohkon. Sellaisia löytyy jopa tuotantokoodista. Oletan että syynä on, että poikkeus laukeaa herkästi mutta on suhteellisen harmiton joten se lakaistaan maton alle. On ehkä 1 tapaus 100:ssa missä on perusteltua tehdä sellainen, eli poikkeus pitää piilottaa. Sellainen poikkeuksellinen tilanne pitäisi kuitenkin dokumentoida ja sen pitäisi olla harvinaisuus, ei yleinen käytäntö. Jos jotain menee pieleen, ja piilotat sen, ongelma ei ole poistunut, ja se tyypillisesti rantautuu myöhemmin jossain muualla mitä mielikuvituksellisimmin tavoin, ja tekee alkuperäisen syyn löytämisen äärettömän vaikeaksi. Se harvinainen tilanne jossa tuo voi olla ok on jos pitää tulla toimeen taustajärjestelmän päällä joka jostain syystä käyttää poikkeuskäsittelyä väärin, ei kerro virhetiloista vaan tekee niillä jotain muuta. Tyhjä catch lohko on paholaisesta.

– Toinen antipattern on äärimmäisen yleinen ex.printStackTrace() kutsu, generoituna suoraan Eclipsestä. Se toimii kehittäjän koneella hienosti, kun virhepino menee konsoliin, mutta asennettuna ei konsolia olekaan. Jos kyseessä on android tai palvelinsofta, virheet tulostuvat logiin. Mutta kukaan ei ehkä koskan katsele logia. Tai jos katselee, merkityksellinen tieto hukkuu sadantuhannen stacktrace tulostuksen alle. Ei näin. Tämä on oikeastaan variaatio edellisestä eli tyhjästä catch lohkosta. Mitä pitää tehdä kun havaitaan poikkeus? Pysähdy, pistä detailit logiin jos virhe todella johtuu ympäristöstä tai on syytä logata. Korjaa ongelma jos se on korjattavissa. Jos ei ole, tiedota niitä jotka pystyvät sen korjaamaan. Ellet pysty tekemään mitään näistä, kuplita virhe eteenpäin tasoon jossa voidaan näin tehdä, yleensä UI taso. Tiedota ylläpitoa jos tarpeen. Tiedota käyttäjää aina. NullPointerException ei kerro mitään käyttäjälle (toivon mukaan), muista kertoa miten tästä päästään eteenpäin eikä sitä mikä meni vikaan.

– Kolmas antipattern yllä on catch-all lohko. Sitä näkee usein ainoana try-catch lohkona, ja usein viimeisenä käsittelynä kuten yllä. Tällekin voi olla joskus perusteensa, mutta useimmiten sitä käytetään aivan liian aikaisin. Catch-all lohkon ongelma on että se todella saa kaikki virheet kiinni, mistä ikinä ne johtuivatkaan. Jos se on liian aikaisin otettu käyttöön, siihen sisältyy röyhkeä oletus että pystyt käsittelemään minkä hyvänsä virheen samalla kaavalla. Mikä voi olla totta, mutta ellei se olekaan, olet taas piilottanut ongelmia muiden alle. Eli käsittely on ok kun todella haluat käsitellä kaikki jäljellä olevat ongelmat, käsittely on väärin kun otat laajasti kiinni mutta sovellat suppeasti virheen näyttöä, kuten yllä.

Mikään ylläolevista ei ole 100% ajasta tuhoisa tai edes väärin, kyse on nyansseista.

Suosituksia poikkeuskäsittelyyn

Älä ota poikkeuksia kiinni liian aikaisin. Jos et ole valmis korjaamaan ongelmaa tai keskustelemaan käyttäjän kanssa, heitä sama poikkeus tai uusi poikkeus uudelleen, kuplita, delegoi seuraavalle kutsupinossa kunnes päästään paikkaan missä voidaan korjata ongelma tai keskustella käyttäjän kanssa siitä miten se korjataan.

Älä loggaa samaa ongelmaa kahdesti tai useammin, kerta riittää. 

Paras tapa saada aikaan hyvä poikkeuskäsittely on hyvä testaus. Kehitä automatisoidut testit käyttöliittymään ja simuloi virheellisiä syötteitä ja muita virhetiloja siinä missä onnistumistakin. Kehitä myös kuormatestausta. Näin näet miten ne ilmenevät käyttöliittymässä, ja bonuksena tällaisten testien uudelleenkäytettävyysarvo on erinomainen. Testaa, testaa, testaa.

– Käyttäjävirheitä jotka johtuvat esim. validoinnista ei yleensä kannata logata (ja tukkia logia tarpeettomalla hälyllä), vaan keskity ohjaamaan käyttäjä oikealle suorituspolulle takaisin. Älä keskity siihen mikä meni pieleen, vaan keskity ohjaamaan käyttäjää miten toimia oikein, hyvän esimerkin kera. Jos käyttöliittymäsi käyttää idioottivarmoja kontrolleja tiedon keruuseen ja omaa hyvän validointilogiikan, voi olla että käyttäjävirheitä ei juuri tapahdu. Pyri siihen että käyttäjän aiheuttamat virheet eivät aiheuta poikkeuksia.

– Järjestelmä ja ympäristövirheet ovat vakavia, ja usein toiminnan pysäyttäviä. Käyttäjä harvoin voi niitä itse korjata. Osa virheistä voi korjautua itselläänkin, mutta tyypillisesti on hyvä logata yksityiskohdat, herätellä joku ylläpidosta tekemään jotain. Jos automatiikka ei siihen riitä, manuaalinen tapa on näyttää käyttäjälle geneerinen sivu jossa on ylläpidon yhteystiedot ja tikettinumero. Tässä tapauksessa älä anna käyttäjälle yksityiskohtia jo tietoturvasyistäkään, mutta loggaa ne huolella, ja pidä huoli että asialle tehdään jotain nopeasti.

– Sitten on ryhmä, todella odottamattomat virheet. Jos näihin yleensä pystyy reagoimaan, lähestymistapa on jotakuinkin sama kuin yllä, sillä erotuksella että nyt on KRIITTISTÄ pistää tietoa ylös virheestä ja nopeasti saada korjausta aikaan. Nämä tulisi myös logissa nostaa selkeästi omaan kategoriaansa että johtolangat löytyvät selkeästi. On ihan ok tehdä koko pinon päälle vielä geneerinen catch-all lohko joka ottaa kiinni kaikki todella odottamattomat virheet – jotta käyttäjän ruudulle ei pauku poikkeuskoodeja ja pinoja. Se ei vain saa olla ainoa poikkeuskäsittelymalli. Pidä myös huoli että käsittely tallettaa riittävästi yksityiskohtaista tietoa siitä mikä meni vikaan.

Siinäpä se. Suorituskyvyn suhteen on myös hyvä muistaa että poikkeuksien heittäminen ja etenkin poikkeuksen ottaminen kiinni ja heittäminen uudelleen on erittäin tehosyöppöä. Mutta sovelluskehityksen ensimmäiset prioriteetit ovat toimivuus ja selkeys, ja kuten opetan kursseilla, optimointia ei pidä lähteä tekemään ellei siihen ole syytä. Jos on, poikkeuskäsittelyn minimointi antaa vastalahjaksi usein suoritusnopeutta lisää. Tästä on kirjoitettu lukemattomia artikkeleita jos aihe kiinnostaa.

Muutamia muita hajatuksia aiheesta:

http://mikehadlow.blogspot.fi/2009/08/first-rule-of-exception-handling-do-not.html

http://today.java.net/article/2006/04/04/exception-handling-antipatterns

Väärä ketteryys ja oikea ketteryys

No niin, tämä teema on kypsynyt jo hetken aikaa mietintämyssyn alla, on tehnyt mieli kirjoittaa omia ajatuksiani tästä. Osittain kypsyttelyyn on vaikuttanut se, että olen työstänyt kollegan kanssa Agile Engineering Practises koulutusta osana Certified Scrum Developer koulutusta, jossa pyritään parantamaan valmiuksia tehdä sitä oikeaa Scrummia, käytännön tasolla ongelmia ratkaisten siis. Powerpoint kalvojen sijaan tällä kurssilla tuotetaan ja testataan jatkuvasti sitä toimivaa softaa siis, sikäli ei riitä että osaa puhua, vaan tässä pitää osata soveltaa.

Olen törmännyt asiakkaiden kanssa yllättävän usein siihen että ollaan olevinaan ketteriä, tai ollaan tekevinään Scrummia tai Leaniä, ja kuitenkin ollaan katkeria menetelmää kohtaan ja koetaan että se ei toimi. Tässä ei toki ole vielä ihmeellistä, ei kaikki toimi kaikille, mutta kun olen udellut lisää syitä tyytymättömyyteen, paljastuu pian etteivät he usein ole tehneet tosiasiassa mitään ketterää ollenkaan, vaikka sertifikaatit on taskussa ja johdon siunaus. Ei ihme että on tyytymättömyyttä kun odotukset ja tulokset eivät kohtaa. Joten mietitäänpä paria oikean ja väärän agilen tunnusmerkkiä.

1. Manuaali kädessä

Ensimmäinen mieleentuleva tunnusmerkki väärästä ketteryydestä on lähteä toteuttamaan sitä manuaali toisessa kädessä otsa rypyssä. Tai vaikka tämä artikkeli käteen printattuna. Tämähän on ketteryyden irvikuva ja paradoksi. Ketteryyden ydin on sopeutua ja kehittyä, ei toistaa vanhaa. Oikea ketteryys ei lähde vanhan toistamisesta (tosin se voi olla tarpeen opiskeluvaiheessa), vaan jatkuvasta kehittymisestä ja eteenpäin menosta, ja sopeutumisesta. Tässä piilee toki yksi sudenkuoppa: monet agile menetelmät ovat jopa vaarallisia jos valikoi vain piirteen sieltä toisen täältä, koska piirteet tukevat toisiaan. Mutta on silti väärä lähtökohta pyrkiä toteuttamaan niitä fanaattisesti ja itseisarvoisesti sokkona toistellen – ei ole sellaista kuin täydellinen menetelmä, kehittymisen varaa on aina.

Oikea ketteryys? Se lähtee siitä että myönnetään että ihmiset voivat tehdä virheitä, etenkin alueille jotka ovat entuudestaan vieraita, tuntemattomia. Rakennetaan sisään itsetarkistelu ja jatkuva kehittyminen niin että se on yhtä arkipäiväistä kuin hengittäminen. On ok tehdä virhe, on väärin toistaa sitä. Tehdään jatkossa aina paremmin, tehokkaammin, fiksummin. Projektimenetelmän nimellä ei ole väliä. Onko se Scrum, Lean, Kanban, vai jotain mitä tulee tulevaisuudessa, se ei merkitse. Se mikä merkitsee on sisäänrakennettu kyky toipua ja kehittyä.

2. Scrummerfall

Suurin murhe ketterillä tiimeillä on perinteinen Scrummerfall – aloitetaan jäykästä vesiputousmallisesta projektista jossa on tiukka budjetti ja deadline, ja tiukka lista ominaisuuksia joista ei voi tinkiä. Tehdään raskas upfront määrittely – suunnittelu – ja paljon handoffeja ja tarpeetonta dokumentaatiota – ja sitten toteutusvaiheessa sanotaan: ok, aloittakaa Scrum. Siinä ei paljon sopeuduta, iteroida, priorisoida, eikä olla ketteriä. Näissäkin oloissa voi saada aikaan jotain, mutta lähtökohtaisesti ketteryyden hyödyt on jo menetetty ennen kuin peli on edes käynnistynyt. Ongelmana on että ketteryyden ostaminen vaatii näkemystä ja osaamista myös, ja vasta viime vuosina on esim. Product Owner koulutuksista tullut kovia hittejä. Lisäongelmana on ketteryyden kilpailuttaminen – mitä muuta siinä voi käyttää kriteerinä kuin referenssejä ja uskottavuutta? Tai tuntihintaa? 😉

Oikea ketteryys? Se lähtee osaavasta product ownerista jolla on selvillä tarpeet, ja kyky tai tuki priorisoida ne siten että aloitetaan tärkeistä ja edetään kohden vähemmän tärkeitä. Jos tarpeet ovat liian suuria on aika paloitella ja priorisoida lisää. Jos tuntuu että kaikki tarpeet ovat ykkösprioriteetin tärkeitä niin varmaan on syytä joustaa aikataulussa ja budjetissa sitten sen mukaan, ja puhua vaiheista – eikä big bang päivityksistä. Oikea ketteryys priorisoi ja tuottaa jatkuvasti demonstroitavaa liiketoiminnallista arvoa. Näin pidetään ostajat tyytyväisenä ja sitoutuneena ja päädytään siihen vähemmistöön it-projekteja jotka onnistuvat.

Vesiputousmallista tulikin mieleen: Katsokaapa wikipediasta anti-patterns artikkeli, ja katsokaa mitä waterfall projektimallista sanotaan 😉

3. Jätetään suunnittelu ja dokumentointi pois, mutta ei myöskään testata tai toimiteta

Ok, nämä ovat aika ilmeisiä heikkouksia. Otetaanpa vaarallisempia mukaan. Yksi helmasynti on mennä käsikirjan mukaan pitämään pystypalaverit aamuisin, iteroimaan vähän, ja keventää suunnittelua ja dokumentointia, kerätä kivoja velocity raportteja, ja kuvitella tekevänsä Scrummia. Kaikki nämä ovat hyvästä, mutta mikään niistä ei oikeastaan ole sellaista mitä ei voisi vesiputouksessakin tehdä, ja mikään näistä ei ole ohjelmiston tilaajan kannalta olennaista. Näitä usein tehdään koska ne on helppoa ottaa käyttöön, niihin ei liity muutosvastarintaa paljoakaan, ja eivät vaadi teknistä osaamista juurikaan. Kun hyödyt ja kustannukset laitetaan puntariin, molemmat ovat vähäisiä. Ei se Scrummia ole.

Oikea ketteryys hyökkää vaikeampien asioiden kimppuun, tässä pari oikean ketteryyden tunnusmerkkiä: Projekti toimittaa joka Sprintin aikana loppuun asti tehtyä, demonstroitavaa toiminnallisuutta jolla mennään eteenpäin. Näin säilytetään sitoutuminen, usko, visio ja mielenkiinto. Sovelluskoodi on kauttaaltaan testattua, ja testejä voidaan ajaa milloin vain, toistuvasti, koko ajan. Testikattavuutta ja testiraporttien historiaa voidaan helposti seurata. Testaus kattaa yksikkötestausta, integraatiotestausta, hyväksyntätestausta, ja suorituskyky-, kuorma-, ja toipumistestausta. Testit toimivat koodin dokumentaationa suurelta osin. Miksi näin ei tehdä? Tämä vaatii osaamista, ohjelmistoja, ja harjoittelemista ja soveltamista. Se on investointi. Investointi antaa takaisin varmuutta ja rohkeutta tehdä muutoksia ja korjauksia. Ääripäässä käytetään TDD menetelmää, joka ei ole enää testausta vaan suunnittelua, se ei siis ole testaajan osaamista vaan jokaisen tiimin sovelluskehittäjän. TDD on niin hieno ja monelle myös vaarallinen juttu että se taitaa ansaita joskus ihan oman artikkelin.

Kuulin muuten jenkkiprojektista jossa oli neljä sprinttiä vedetty läpi ilman että oli kertaakaan pystytty toimittamaan ulospäin yhtään mitään. Tässä kannattaisi ehkä vetää hätäkahvasta ja pistää homma seis ja tiimi opiskelemaan lisää. Ketteryys ei ole tekosyy osaamattomuudelle vaan se oikeastaan vaatii osaamista ja itseohjautumista. Se ei myöskään sovi kaikille.

Scrum ja kumppanit ei ole maaginen ratkaisu kaikkiin sovelluskehityksen kiputiloihin. Jos mitään, ne ovat välineitä joilla kivut pyritään nostamaan esille jotta ne voidaan ratkaista ja kehittyä.

4.Cowboy coding

Edelleen yksi kipeimpiä väärinymmärrettyjä ketteryysteemoja on sekoittaa ketteryys cowboy koodaukseen. Olen törmännyt joskus tilanteeseen missä tiimi iloisesti hyväksyy että dokumentointia vähennetään ja keskitetään, suunnittelua ei tehdä raskaasti etukäteen vaan matkan varrella, mutta on jätetty esim. testaus pois tai hunningolle tai projektityön jälkeiseksi ei-kuulu-meille asioiksi. Sitten alkaa cowboy koodaus: Tehdään suttuista spagettikoodia juuri tarpeeksi että saadaan ns ’happy scenario’ manuaalisesti testatuksi läpi, miettimättä virhetilanteita, uudelleenkäytettävyyttä, ylläpidettävyyttä, arkkitehtuuria, jne. Ketteryys ei ole tekosyy unohtaa näitä asioita, se vaatii osaamista pohjalleen. Muuten meillä on tiimi tuuliajolla ulapalla vailla suuntaa tai taitoja. Siitä ei ketteryydenkään nimessä hevillä selvitä.

Eli oikea ketteryys rakentuu kohtuulliselle osaamiselle ja riittävälle arkkitehtuurille. Itse suosin kovasti Architectural Spike termiä jossa tehdään kevyt arkkitehtuuri alussa jonka uskotaan riittävän projektin vaatimuksiin. Mieluiten pieni POC tueksi poistamaan tekniset riskit jos arkkitehtuuri on kovin uusi. Sen jälkeen astuu peliin Emergent Architecture jossa voidaan muuttaa arkkitehtuuria tarpeen mukaan. Käyttäisin tässä itse esimerkkinä Eiffel-tornin rakentamista ketterästi. Voi kokeilla rakentaa vastaavaa kapistusta metri kerrallaan ketterästi, oppien matkalla virheistä ja tehden aina paremmin, mutta mahtaako siitä tulla mitään? Olisiko sittenkin parempi alunperin karkeasti arvioida tornin korkeus, rakennusmateriaalit, tehdä pari lujuuslaskelmaa? Vai sopiiko ketteryys ollenkaan jos projektin muuttujat ovat jo tiedossa ja kokemusta on? Kuitenkin, spike vaihe ei pitäisi olla liian raskas, tai liian pitkä, muuten riskeerataan jatkuva toiminnallisuuden toimitus ja sitä myöden sitoutuminen.

Pelkkä emergent design ei mielestäni riitä, vaan alkuarkkitehtuurin tulee olla riittävä että sillä voidaan edetä jonkin matkaa ja että se ei välittömästi mene uusiksi. Muuten haaskataan taas aikaa ja energiaa. Good enough siis.

5. Tuuliajolla muuttuvien vaatimusten kanssa

Vielä yksi väärän ketteryyden tunnusmerkki joka tulee mieleen on product ownerin kykenemättömyys sitoutua mihinkään suuntaan. Ideana olisi kuitenkin edetä kohden visiota, vaikka yksityiskohdat voivat muuttua. Jos hankkeella ei ole visiota tai matkan varrella se muuttuu rajusti, tulee aika kallis hanke jonka tyytyväisyys ei ehkä ole huippuluokkaa. Tämä vaatii ammattitaitoa ostajalta, product ownerilta, mutta tarpeen vaatiessa myös Scrum masterilta. Vastuu onnistumisesta on yhteinen, ja jos muutos itsessään muodostuukin riskiksi, sitä pitäisi hallita iteraatioissa.

Eli pähkinänkuoressa:  Väärän ketteryyden tunnusmerkkejä ovat:

– hallitsematon muutos

– vajavainen tai puutteellinen testaus

– puutteellinen arkkitehtuuri

– puutteellinen visio

– kyvyttömyys sitoutua ketteryyteen työtapana

Tässä oli omia näkemyksiä siihen miten niitä voisi korjailla, mutta meikäläisen näkemykset eivät ole tärkeitä. Se mikä on tärkeää on oma halu kehittyä ja olla taitavampi joka päivä.

Ja tässä piti tietysti puffata tätä uutta kurssia, mutta enpä puffaisi sitä ellen uskoisi että se on hyödyllinen 😉  Sitäpä ei enää tälle vuodelle ehtinyt toteuttaa, mutta ensi vuosi on uusi vuosi ja uudet kujeet.

http://www.tieturi.fi/kurssit/kurssi.html?course=83904030&category=Ketteryys%2B%2528Agile%2529&city=Helsinki&training=21.03.2012

Ja tietysti muita ketteriä koulutuksia:

http://www.tieturi.fi/kurssit/koulutus.html?&category=Ketteryys+%28Agile%29

 

Tiedätkö jotain muita ketteryyden sudenkuoppia? Aihe on kiinnostava ja siinä on kehittymisen varaa. Blogihan on siitä kiva että sitä voi helposti kommentoida.

Maven ja Artifactory

Mavenin kanssa peuhatessa tuli mieleen halu pystyttää oma repository Mavenille. Tähän on monia syitä.

Oma repository toimii kätevästi proxynä julkisille repositoryille: kun lataat sen kautta pluginit, ne täytyy ladata vain kerran, ja sitten ne löytyvät läheltä paikallisesti, vaikka koko tiimille tai yritykselle. Kun internet on epävarma nykyisellään aika ajoin, ja kun maven central repositoryt kuten repo1 ovat ylikuormitettuja, tämä voi pelastaa päiväsi.

Toinen syy on tietysti että on mukavaa kun maveniä käyttäessä on julkaisuja varten oma tiimirepository, jossa valmiita snapshot ja muita releaseja voi jaella. Voittaa levynnurkan!

Vertaillessa eri vaihtoehtoja esiin nousi selkeästi kova repository nimeltä Artifactory – sitä löytyy tuen kera kaupallisena, ja avoimen lähdekoodin community editiona. Asennus on helppo: lataat zipin, purat sen haluamaasi paikkaan, ja ajat bin-kansiosta artifactory.bat:in – tai sh:n.

Mitäs sitten? Nyt olisi repository pystyssä, ainakin hetken. Pidemmäksi aikaa sen saa päälle asentamalla sen serviceksi. Tätä ennen on kuitenkin myös syytä asettaa ARTIFACTORY_HOME ympäristömuuttuja, osottamaan johonkin sopivaan olemassaolevaan kansioon. Muuten artifactory luo asetukset ja muut käyttäjäprofiilisi alle. Kun olet tyytyväinen artifactoryn toimintaan, löytyy bin-kansiosta ytimekäs installservice.bat jolla saat ratkaisun pyörimään windows-palveluna (Linux käyttäjät, sorry, joudutte järkeilemään tämän itse, kun omassa koneessani on vain windows 7. Olisiko apua install.sh scriptistä? 😉

Seuraavaksi on syytä kertoa Mavenille että käyttää kaikkiin pyyntöihin vain ja ainoastaan tätä omaa artifactory repositoryä. Tämän voi tehdä käyttäjäkohtaisessa settings.xml tiedostossa profiilien alla, mutta varmaan helpointa on lisätä pom.xml tiedostoon jotain tämäntapaista:

<repositories>
  <repository>
    <id>central</id>
    <url>http://http://localhost:8081/artifactory/repo</url>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
  </repository>
  <repository>
    <id>snapshots</id>
    <url>http://http://localhost:8081/artifactory/repo</url>
    <releases>
      <enabled>false</enabled>
    </releases>
  </repository>
</repositories>
<pluginRepositories>
  <pluginRepository>
    <id>central</id>
    <url>http://http://localhost:8081/artifactory/plugins-releases</url>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
  </pluginRepository>
  <pluginRepository>
    <id>snapshots</id>
    <url>http://http://localhost:8081/artifactory/plugins-snapshots</url>
    <releases>
      <enabled>false</enabled>
    </releases>
  </pluginRepository>
</pluginRepositories>
Ja tuossapa tietysti pidemmän päälle localhostin tilalle todellinen palvelinosoite kun saat sen pysyvämmin pystyyn. Tämä ylikirjoittaa mm. central repositoryt siten että aina mennään artifactoryn kautta. Lisäksi voisit vielä pistää settings.xml tiedostoosi tällaisen:
<mirrors>
  <mirror>
    <id>artifactory</id>
    <mirrorOf>*</mirrorOf>
    <url>http://localhost:8081/artifactory/repo</url>
    <name>Artifactory</name>
  </mirror>
</mirrors>

Ehkä ekstravarovaisuutta – mutta tuo tekee kaikkien osoitteiden eteen taas mirrorin joka menee artifactoryn kautta. Nyt voit kokeilla ottaa käyttöön uuden pluginin ja seurata mavenin log-viestejä: Pyynnöt menevät nyt artifactory proxyn kautta.

Vaihe 2

Kun haluat julkaista tuotoksesi artifactoryyn oman levyn sijasta voit lisätä pom.xml tiedostoon nämä tiedot:

<distributionManagement>
  <snapshotRepository>
    <id>asantala_w7</id>
      <name>asantala_w7-snapshots</name>
      <url>http://localhost:8081/artifactory/libs-snapshots-local</url>
  </snapshotRepository>
  <repository>
    <id>asantala_w7</id>
    <name>asantala_w7-releases</name>
    <url>http://localhost:8081/artifactory/libs-releases-local</url>
  </repository>
</distributionManagement>

Selvää kuin pässi, eikö? Säädämme siis julkaisu-repositoryksi snapshoteille ja aidoille julkaisuille Artifactoryn. Nyt voit tehdä esim.

mvn deploy

Ja katsoa miten projekti paukkuu paikalleen. Repository hallinnasta voi katsella miten omat tuotokset ja proxyn kautta ladatut plug-init siellä muhivat. Jos repository vaatii autentikointia, voit vielä lisätä settings.xml:ään määrityksen em servereille. Tarkista että serverin id täsmää edellämainittuihin säätöihin, ja aseta tunnus ja salasana siten miten olet ne artifactoryssä säätänyt (ethän käytä oletussalasanoja missään palvelimessa, ethän…?)

<servers>
  <server>
    <id>asantala_w7</id>
    <username>admin</username>
    <password>password</password>
  </server>
</servers>

Ensi jaksossa kirjailen siitä miten Maven, Subversion, Artifactory ja SCM plugin ja Release plugin toimivat yksiin – jotta saat automaattisesti snapshoteista julkaisuversioita ja versionumeroita päiviteltyä ilman että täytyy käsin muutella POM tiedostoa joka kerta. Tämä on Maven 2:sen uusi ominaisuus.