1 Sisällysluettelo 2 Johdanto 3 Menetelmän käyttö

Samankaltaiset tiedostot
SEPA REFAKTOROINTI Antti Ahvenlampi, 57408L Erik Hakala, 57509T

Ohjelmistojen mallintaminen. Luento 11, 7.12.

SEPA päiväkirja. Aihe: Staattiset menetelmät Tekijät: Mikko Halttunen 58198B, Mikko Närjänen 58122B Ryhmä: Neptune T Ohjelmistoprojekti I

SEPA päiväkirja. BetaTeam. Juho Mäkinen, 57796V, Jari Leppä, 42710V, Versio Pvm Tekijä Kuvaus

dokumentin aihe Dokumentti: Testausraportti_I1.doc Päiväys: Projekti : AgileElephant

Eclipse ja JUnit-ohjelmoijatestit

Menetelmäraportti - Konfiguraationhallinta

COTOOL dokumentaatio SEPA: Refaktorointi

TT00AA Ohjelmoinnin jatko (TT10S1ECD)

Ylläpitodokumentti. Boa Open Access. Helsinki Ohjelmistotuotantoprojekti HELSINGIN YLIOPISTO Tietojenkäsittelytieteen laitos

ELM GROUP 04. Teemu Laakso Henrik Talarmo

Sisällys. JAVA-OHJELMOINTI Osa 7: Abstrakti luokka ja rajapinta. Abstraktin luokan idea. Abstrakti luokka ja metodi. Esimerkki

JReleaser Yksikkötestaus ja JUnit. Mikko Mäkelä

Ohjelmointi 1 / syksy /20: IDE

SEPA diary. Dokumentti: SEPA_diary_PK_HS.doc Päiväys: Projekti: AgileElephant Versio: V0.3

Project group Tete Work-time Attendance Software. Henkilökohtainen SE harjoitus: loppuraportti

Kieliversiointityökalu Java-ohjelmistoon. Ohje

Project group Tete Work-time Attendance Software

FENG OFFICE -PROJEKTINHALLINTATYÖKALU

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. IX Suunnittelumallit Proxy, Factory Method, Prototype ja Singleton

BlueJ ohjelman pitäisi löytyä Development valikon alta mikroluokkien koneista. Muissa koneissa BlueJ voi löytyä esim. omana ikonina työpöydältä

Automaattinen regressiotestaus ilman testitapauksia. Pekka Aho, VTT Matias Suarez, F-Secure

COTOOL dokumentaatio Testausdokumentit

812341A Olio-ohjelmointi, IX Olioiden välisistä yhteyksistä

Good Minton Sulkapalloliiton Kilpailujärjestelmä SEPA: Heuristinen arviointi

T SEPA - päiväkirja: Design Patterns. ETL työkalu

Oppilaan pikaopas. Project 2013 käyttöliittymä ja näkymät

Oliosuunnitteluesimerkki: Yrityksen palkanlaskentajärjestelmä

Tarjolla tänää: Ohjelmiston toteutuksesta. Kuinka tulla hyväksi ohjelmoijaksi? CRC-kortit. Testilähtöinen kehittäminen JOT2007. Uudelleenrakentaminen

Testivetoinen ohjelmistokehitys

Hirviö. Design Patterns

9. Periytyminen Javassa 9.1

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op

Maastotietokannan torrent-jakelun shapefile-tiedostojen purkaminen zip-arkistoista Windows-komentojonoilla

C# 3.0:n uudet ominaisuudet Language Integrated Query...45

Lohkot. if (ehto1) { if (ehto2) { lause 1;... lause n; } } else { lause 1;... lause m; } 16.3

Ohjelmistojen laadun parantaminen refaktoroinnilla Simo Mäkinen Tietojenkäsittelytieteen laitos Helsingin yliopisto

Sisällys. 16. Lohkot. Lohkot. Lohkot

Käyttöliittymän muutokset ProCountorin versiossa 3.0

Suomi.fi: Asiointi ja lomakkeet osion käyttöliittymämallien käyttäjätestaus. Testaustulosten esittely

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

CLOUDBACKUP TSM varmistusohjelmiston asennus

Ohjelmoinnin jatkokurssi, kurssikoe

13/20: Kierrätys kannattaa koodaamisessakin

Pedacode Pikaopas. Java-kehitysympäristön pystyttäminen

Rajapinnasta ei voida muodostaa olioita. Voidaan käyttää tunnuksen tyyppinä. Rajapinta on kuitenkin abstraktia luokkaa selvästi abstraktimpi tyyppi.

Asiakas ja tavoite. Tekninen toteutus

Versio Päiväys Tekijä Kuvaus Tikkanen varsinainen versio

Tekstinkäsittelyn jatko. KSAO Liiketalous 1

Sisällys. 6. Metodit. Oliot viestivät metodeja kutsuen. Oliot viestivät metodeja kutsuen

VERSIONHALLINTA. PARIOHJELMOINTI Lari Ahti, 62634M Antti Kauppinen, 58390D

15. Ohjelmoinnin tekniikkaa 15.1

Pakkauksen kokoaminen

Sisällys. 11. Rajapinnat. Johdanto. Johdanto

SATAKUNNAN AMMATTIKORKEAKOULU. Hakala Toni Varpelaide Heidi TEKSTINKÄSITTELYN OHJEET CASE: OPINNÄYTETYÖN RAPORTOINTI WORDILLA

HELIA 1 (14) Outi Virkki Käyttöliittymät ja ohjlmiston suunnittelu

TAMK Ohjelmistotekniikka G Graafisten käyttöliittymien ohjelmointi Herkko Noponen Osmo Someroja. Harjoitustehtävä 2: Karttasovellus Kartta

Visma Business AddOn Tositteiden tuonti. Käsikirja

Sisällys. 15. Lohkot. Lohkot. Lohkot

Kysely lähetettiin Helmen kautta toukokuun lopussa 2018 Vastausaika kaksi viikkoa Vastauksia tuli 548 suomenkielistä ( peruskoululaisia n 4000) ja

Javan perusteita. Janne Käki

Sisällys. Metodien kuormittaminen. Luokkametodit ja -attribuutit. Rakentajat. Metodien ja muun luokan sisällön järjestäminen. 6.2

TEEMA 3 TEKSTIDATAN KÄSITTELY JA JULKAISEMINEN LUENTO 5 TEKSTINKÄSITTELY

15. Ohjelmoinnin tekniikkaa 15.1

16. Javan omat luokat 16.1

FiSMA 1.1 Toiminnallisen laajuuden mittausmenetelmä Ohje monikerrosarkkitehtuurin mittaamiseen

Version päivittäminen

Lohkot. if (ehto1) { if (ehto2) { lause 1;... lause n; } } else { lause 1;... lause m; } 15.3

Web-palvelu voidaan ajatella jaettavaksi kahteen erilliseen kokonaisuuteen: itse palvelun toiminnallisuuden toteuttava osa ja osa, joka mahdollistaa k

C-ohjelmoinnin peruskurssi. Pasi Sarolahti

CIRI Ontologiaperustainen tiedonhakuliittymä

Onnistunut ohjelmistoprojekti

7/20: Paketti kasassa ensimmäistä kertaa

TIE Principles of Programming Languages CEYLON

erasmartcardkortinlukijaohjelmiston

Väitöskirja -mallipohja

Digi-tv vastaanottimella toteutettavat interaktiiviset sovellukset Selvitys GPL-lisensoinnin tuomat ongelmat

Written by Administrator Monday, 05 September :14 - Last Updated Thursday, 23 February :36

Tekstinkäsittely ja opinnäytetyö I sisällysluettelo ja sivunumerointi. Word 2007

Automaattinen yksikkötestaus

SOLIDPDM 6 Plus uudet ominaisuudet osa 2

Eclipse, SVN ja HelloWorld

XPages käyttö ja edut Jarkko Pietikäinen toimitusjohtaja, Netwell Oy

AS C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin

SEPA - Design Patterns

Tyyppiluokat II konstruktoriluokat, funktionaaliset riippuvuudet. TIES341 Funktio-ohjelmointi 2 Kevät 2006

MOBISITE-TYÖKALUN SISÄLTÄMÄT TOIMINNOT

Johdanto 1. Projektille esiteltävä versio. Kokemukset ja muutokset 3. Projektille esiteltävä versio. Iteraatio 2., suunnitelma

Sokkelon sisältö säilötään linkitetyille listalle ja tekstitiedostoon. Työ tehdään itsenäisesti yhden hengen ryhmissä. Ideoita voi vaihtaa koodia ei.

Sisäänrakennettu tietosuoja ja ohjelmistokehitys

Ohjelmistotekniikan menetelmät, Ohjelmistotuotannon työkaluista

Office ohjelmiston asennusohje

Matopeli C#:lla. Aram Abdulla Hassan. Ammattiopisto Tavastia. Opinnäytetyö

Olio-ohjelmointi: Luokkien toteuttaminen. Jukka Juslin

Visma Fivaldi -käsikirja Tehtävienhallinta- ohje käyttäjälle

Solidity älysopimus ohjelmointi. Sopimus suuntautunut ohjelmointi

Predictable 5 Uudet ominaisuudet

Test-Driven Development

T Refaktorointi

Operaattorin ylikuormitus ja käyttäjän muunnokset

Transkriptio:

SEPA-päiväkirja Aihe: Refaktorointi Tekijät: Markku Huttunen, Antti Poikela 1 Sisällysluettelo 1. Sisällysluettelo 2. Johdanto 3. Menetelmän käyttö 4. Kokemukset ja muutokset 5. Lähdeluettelo 2 Johdanto SEPA-aiheeksemme valitsimme refaktoroinnin. Ohjelmistokehityksessä tämä tarkoittaa lyhyesti sitä, että ei ole erillistä suunnitteluvaihetta ennen buildien tekoa, vaan suunnittelua muokataan tuotteen kehityksen aikana muuttamatta sen ulkoista toimintaa. [1] Refaktorointia käytetään ohjelmistokehityksessä jatkuvasti, osin sitä edes tiedostamatta, ohjelmiston ymmärrettävyyden ja toiminnan loogisuuden parantamiseksi. Refaktorointia voidaan suorittaa myös erillisenä työtehtävänä, jonka tavoitteena on parantaa koodin laatua esimerkiksi paremman ylläpidettävyyden ja laajennettavuuden saavuttamiseksi. Tämä voi olla tähdellistä varsinkin, jos joudutaan työskentelemään jo olemassa olevan koodin kanssa, jonka laadussa olisi parannettavaa, mutta jota ei kuitenkaan keretä kirjoittamaan uudelleen. Käytännössä refaktorointi näkyy ohjelman lähdekoodin uudelleenjärjestämisenä, usein erilaisten automatisoitujen työkalujen avulla. Valitimme refaktoroinnin aiheeksemme, koska siitä on todennäköiseesti hyötyä kaikille kehittäjille projektissamme. Lisäksi käyttämämme kehitystyökalu, Eclipse, tukee refaktorointia erinomaisesti. Uskomme myös, että refaktoroinnin avulla pystymme paremmin noudattamaan konventioita ja näin ollen tuottamaan yhdenmukaisempaa ja ymmärrettävämpää koodia. 3 Menetelmän käyttö Refaktorointia tulevat käyttämään kaikki kehittäjät. Tarkoituksena on käyttää refaktorointia jatkuvasti kehityksen aikana. Hyvä käytäntö on tarkistaa refaktorointitarve jokaisen metodin kirjoittamisen jälkeen sekä jokaisen työskentelyjakson päätteeksi. Vähintäänkin koodin ulkoasun muotoilu konventioiden mukaiseksi työrupeaman päätteeksi on välttämätöntä, jotta muun muassa testaajan työaika ei kuluisi hukkaan. Kannattavaa on myös varmistaa metodin järkevä suunnittelu metodin kirjoittamisen jälkeen, sillä myöhemmin tehtynä metodin toiminnan joutuu turhaan kertaamaan uudelleen. Myöhemmässä vaiheessa tapahtuvan refaktoroinnin jälkeen on aina syytä ajaa uudelleen mahdolliset automatisoidut testit koodin toiminnan varmistamiseksi.

Alla käymme läpi Eclipsen keskeisimpiä refaktorointitoimintoja, joita kehittäjien on suositeltavaa käyttää projektin kuluessa tarpeen vaatiessa. Suurimman osan operaatioista voi suorittaa myös manuaalisesti, mutta Eclipsen avulla se on nopeampaa ja turvallisempaa muun muassa viittauksien eheys säilyy. Kehittäjät käyttävät refaktorointitoimenpiteitä itsenäisesti oman harkintakykynsä mukaan. Eclipse tarjoaa muun muassa loistavat uudelleennimeämis- ja siirtomahdollisuudet kaikilla koodin tasoilla (mm. pakettien, metodien ja luokkien) säilyttäen koodin sisäiset viittaukset ehjinä. Siirtäminen toimii sekä Eclipsen Refactor -valikosta (Move) että Package Explorer -näkymässä drag&drop -toiminnolla. Siirtotoimintoja käytetään designin korjaamiseen, esimerkiksi kytkentöjen ja koheesion parantamiseen. Tarpeen sille voi havaita koodia tutkimalla tai esimerkiksi Together -työkalun metriikka-analysaattorilla. Change Method Signature -toiminnolla voidaan muuttaa metodin parametreja, näkyvyyksiä, palautusarvoja ja poikkeuksia siten, että viittaukset muualla koodissa pysyvät ehjinä. Convert Anonymous Class to Nested muuttaa nimensä mukaisesti anonyymin luokan sisäkkäiseksi (vrt. inner eli sisäinen) luokaksi. Tästä voi olla etua mm. haluttaessa välttää koodin kopiointia. Anonyymia luokkaa tulisi käyttää lähinnä vain ns. singleton -tapauksissa, ts. kun sisäisestä luokasta ei haluta tehdä kuin yksi instanssi (näin on usein muun muassa graafisten sovellusten kuuntelijoiden tapauksissa). Toiminnolla Move Member Type to New File voidaan erottaa sisäisiä luokkia uusiksi ulkoisiksi tiedostoiksi. Toiminto on hyödyllinen, jos sisäinen luokka esimerkiksi kasvaa kovin pitkäksi. Pull Up ja Push Down siirtävät metodeita ja kenttiä ylempiin ja alempiin luokkiin luokkahierarkiassa. Voidaan käyttää, jos esimerkiksi alaluokan kenttä tai metodi ei ole niin spesifinen, etteikö se olisi helposti yleistettävissä yläluokkaansa. Esimerkkinä voisi toimia Lehmä -luokalle tehty oliontuhoamismetodi kuole() joka paremminkin voisi esiintyä yläluokassa Eläin. Tällöin käytämme Pull Up -toimintoa. Extract Interface -toiminnolla voidaan luokan julkisista metodeista erottaa rajapinta. Toiminto osaa myös ottaa tämän uuden rajapinnan käyttöön sen toteuttavien luokkien sijasta muiden luokkien instanssimuuttujissa, mikä onkin hyvien koodauskäytäntöjen mukaista. Generalize Type muuttaa viittauksen sen mahdolliseksi yleistykseksi. Tämä toiminto voidaan suorittaa tyyppiviittauksille, kenttien ja paikallisten muuttujien määrityksille ja referenssityypitetyille parametreille. Toiminto tarkistaa, voidaanko muunnos suorittaa turvallisesti. Use Supertype Where Possible -toiminto voidaan ajaa luokalle, jolloin etsitään kyseisen projektin polulla olevista paketeista viittauksia kyseiseen luokkaan ja muutetaan ne halutuksi yleistykseksi, jos mahdollista. Toimii siis kuten Generalize Type, mutta ainoastaan tyypeille ja suoritetaan kerralla koko luokalle. Infer Generic Type Arguments -toiminnolla voidaan muuttaa raakojen kokoelmien (Collection) esiintymät niiden tyypitetyiksi versioiksi (esim. Collection<String>), jos mahdollista. Voidaan suorittaa joko yksittäiselle luokalle, paketille tai jopa koko projektille kerralla. Tyypitettyjen kokoelmien käyttö on erittäin suositeltavaa (muun muassa vältytään tyyppimuunnoksilta) ja siksi suosittelemme tämän toiminnon käyttämistä.

Extract Method luo uuden metodin valitusta koodipätkästä. Tämän toiminnon voi varsin helposti tehdä myös käsin ilman Eclipsen apua, ja haluammekin korostaa itse käytäntöä pitkien metodien sijaan kannattaa usein erottaa loogisia kokonaisuuksia yksityisiksi metodeiksi koodin hahmotettavuuden parantamiseksi. Sama tilanne on vakioiden ja paikallisten muuttujien tapauksissa, joiden erottamiseen Eclipse myös tarjoaa vastaavan työkalun. Kaikissa näissä refaktorointitoiminnoissa on esikatseluominaisuus, jonka avulla tulevia muutoksia voi tarkastella ennen niiden suorittamista. 4 Kokemukset ja muutokset Kappaleessa käymme läpi kehittäjien kokemuksia refaktoroinnista iteraatioiden aikana. Lisäksi listaamme mahdolliset muutokset käytäntöön. 1 Suunnitteluvaihe Suunnitteluvaiheessa ei vielä saatu varsinaisia kokemuksia refaktoroinnin käytöstä, koska ohjelmointitehtävät alkoivat vasta seuraavassa iteraatiossa. 2 Iteraatio 1 Keräsimme kokemuksia refaktoroinnin käytöstä ensimmäisen iteraation aikana lähettämällä kehittäjille sähköpostikyselyn. Kysyimme, kuinka paljon ja minkä tyyppistä refaktorointia kehittäjät käyttivät. Kysyimme myös heidän mielipiteitään refaktoroinnin käytön tarpeellisuudesta ja sen vaikutuksista ohjelmiston laatuun. Kyselystä kävi ilmi, että jokainen kehittäjä käytti refaktorointia projektissamme. Keskimäärin kehittäjät ovat käyttäneet ohjelmointiajastaan alle 10% refaktorointiin. Lähinnä Valppaan kehittäjät käyttivät hieman muita enemmän aikaa refaktorointiin. Useimmiten refaktorointia käytettiin koodin luettavuuden ja ymmärrettävyyden parantamiseen. Suosituimmat refaktorointimenetelmät olivat koodin automaattinen formatointi sekä uudelleennimeämistoiminnot. Osa kehittäjistä käytti refaktorointia myös koodin rakenteen muokkaamisessa esimerkiksi luokkien vastuiden muutoksissa ja toimintojen uudelleenjärjestämisessä. Eclipsen tarjoamasta runsaasta refaktorointivalikoimasta käytettiin kuitenkin vain murto-osaa. Kukaan kehittäjistä ei kokenut refaktoroinnin käyttöä työläänä vaan se nähtiin ennemminkin erottamattomana osatekijänä ohjelmointitehtävissä. Kehittäjät eivät oppineet ensimmäisen iteraation aikana refaktoroinnista varsinaisesti mitään uutta, vaan käytetyt menetelmät olivat heille tuttuja entuudestaan. Itse opimme uusista refaktorointimenetelmistä jo edellisessä iteraatiossa jolloin teimme SEPA:n ensimmäisen vaiheen. Käyttämämme IDE:n tarjoamat automaattiset refaktorointiominaisuudet koettiin varsin hyviksi, lukuun ottamatta koodin automaattisen formatoinnin toisinaan vajavaista toimintaa. Varsinkin Eclipsen tarjoama esikatselutoiminta nähtiin hyvänä ominaisuutena. Kokonaisuutena koettiin, että Eclipse toimi hyvänä apuna refaktoroinnissa ja kannusti sen käyttöön.

Ryhmämme kokee, että refaktoroinnin käyttö paransi ohjelmistomme laatua. Esimerkiksi muuttujannimien vaihto käyttämällä Find/Replace -toimintoa ei olisi todennäköisesti johtanut yhtä hyvään lopputulokseen. Aika-ajoin koettiin kuitenkin, että Eclipsen formatointitoiminto teki koodista epäselvempää huonoilla rivitysvalinnoilla. 3 Iteraatio 2 Iteraation alussa järjestimme kehittäjille noin puolen tunnin koulutustilaisuuden, jossa kävimme yksityiskohtaisesti läpi myös tässä dokumentissa esitellyt Eclipsen tärkeimmät refaktorointitoiminnot. Lisäksi kehittäjille oli varattu iteraation alusta puolentoista tunnin aika oman koodin läpikäymiseen refaktorointitarpeen varalta. Koska ensimmäisen iteraation lopussa lähettämämme sähköpostikysely kehittäjien refaktoroinnin käytöstä osoittautui näppäräksi keinoksi saada yleiskuva refaktoroinnin määrästä ja menetelmistä, päätimme tehdä samantyyppisen kyselyn myös Iteraatio 2:n lopussa. Tässä kyselyssä tiedustelimme kehittäjiltä perinteisesti, kuinka paljon he käyttivät refaktorointia ohjelmointityössään. Tämän lisäksi kysyimme, kokivatko he hyödylliseksi vuoden alussa pitämämme refaktorointikoulutuksen. Kuten ensimmäisessäkin iteraatiossa, myös toisessa kaikki kehittäjät tekivät refaktorointia. Keskimäärin refaktorointiin käytettiin kehittäjien omien arvioiden perusteilla noin 15% ohjelmointiajasta. Tosin vaihtelevuutta löytyi huimasti kehittäjien välillä joku tunnusti käyttäneensä ajasta alle 5% refaktorointiin kun taas toinen kertoi käyttäneensä jopa 50%. Kaikki kehittäjät myönsivät, että Eclipsen työkaluesittelystä oli hyötyä ainakin tulevaisuuden kannalta, joskaan kaikkien mielestä ei suoranaisesti tämän projektin kannalta. Eclipsen työkaluista monet tekevät aika isoja muutoksia, jonka takia kaikkia ei tarvittu käyttää projektissa. Kaksi viidestä kehittäjästä sanoo oppineensa jotain uutta refaktoroinnista tämän iteraation aikana. Kysyimme lisäksi oliko kehittäjien mielestä Eclipsen tarjoamissa työkaluissa puutteita. Yksi oli sitä mieltä, että oli välillä epävarma olo, toimivatko ne oikein, ja toisen mielestä joissain tilanteissa oli epäselvää, mikä kohta koodista täytyisi olla valittuna tiettyä toimintoa tehdessä. Muilta osin kehittäjät kokivat, ettei työkaluissa ollut puutteita. Vaikka Eclipsen tarjoama työkaluvalikoima onkin laaja, monet kehittäjät tekivät varsinkin monimutkaisimmat refaktorointitehtävät käsin. Automaattisia toimintoja käytettiin lähinnä uudelleennimeämisiin ja metodien ja muuttujien irrottamiseen koodista. Suurin osa kehittäjistä oli sitä mieltä, että refaktoroinnin käyttö paransi ohjelmistotuotteemme laatua merkittävästi. 4 Yhteenveto Yhteenvetona voidaan todeta aiheen olleen hyödyllinen projektin kannalta, sillä kaikki kehittäjät olivat sitä mieltä, että ohjelmiston laatu on merkittävästi parantunut refaktoroinnin ansiosta. Lisäksi järjestetty pikakoulutus ja lyhyt erillinen refaktorointihetki pakotti kehittäjät miettimään refaktorointitarvetta, ja vastaukset kertoivatkin kaikkien oppineen refaktoroinnista uutta. Itsellemme aiheesta voisi todeta syvyyden hieman loppuneen ensimmäisen iteraation jälkeen. Merkittävimmät uudet asiat ilmenivät ensimmäisessä iteraatiossa, ja lisäksi Antilla ei ollut lainkaan koodaustehtäviä toisessa iteraatiossa, joten refaktorointia hän ei päässyt

soveltamaan käytännössä. Ongelmallista refaktoroinnin yhteydessä oli sen käyttömäärän arviointi, ts. kuinka suuri osa kehittäjien ajasta kului refaktoroinnin parissa. Koska arviot vaihtelivat jopa 5 ja 50 prosentin välillä, on hyvinkin mahdollista, että kehittäjille jäi erilaiset kuvat siitä, mitkä toimet ovat refaktorointia. Toisaalta ero voi myös ainakin osittain selittyä myös toimintatapojen erilaisuudella. Todellisia käyttölukuja tärkeämpää on kuitenkin se, että refaktorointia selvästi käytettiin läpi projektin ja se koettiin yksinomaan hyödylliseksi. 5 Lähdeluettelo [1] Schach, Stephen R. Object-Oriented & Classical Software Engineering, 6th ed., 2002. [2] Eclipsen manuaali. 2005.