• Ei tuloksia

Asiointipalvelun lisäominaisuuksien kehitysprosessi

N/A
N/A
Info
Lataa
Protected

Academic year: 2022

Jaa "Asiointipalvelun lisäominaisuuksien kehitysprosessi"

Copied!
51
0
0

Kokoteksti

(1)

Henrik Virrankoski

Asiointipalvelun lisäominaisuuksien kehitysprosessi

Metropolia Ammattikorkeakoulu Insinööri (AMK)

Tieto- ja Viestintätekniikka Insinöörityö

13.4.2020

(2)

Tekijä Otsikko Sivumäärä Aika

Henrik Virrankoski

Asiointipalvelun lisäominaisuuksien kehitysprosessi 45 sivua

13.4.2020

Tutkinto Insinööri (AMK)

Tutkinto-ohjelma Tieto- ja viestintätekniikka Ammatillinen pääaine Ohjelmistotuotanto

Ohjaajat Lehtori Simo Silander

Teknologiajohtaja Jari Laurila

Tässä insinöörityössä esitellään vaadittuja työstettyjä muutoksia ja uutta toiminnallisuutta Futunio Oy:n kehittämään selainpohjaiseen asiointipalveluun sekä tutustutaan kehityspro- sessin eri vaiheisiin. Asiointipalvelu on suunnattu työttömyyskassoille, joissa asiointipalve- lua käyttävät työttömyyskassojen jäsenet. Koska tuotteella on jonkin verran käyttäjäkuntaa, on muutokset kehitettävä huolellisesti, jotta varmistetaan palvelun toimivuus.

Ennen muutosprosessia käydään läpi työn vaatimukset, työssä käytettävä Angular-ohjel- mistokehys sekä koodin laatuun vaikuttavia toimintatapoja. Aluksi työssä tutustutaan oleel- lisimpiin Angular-ohjelmistokehyksen tuomiin ominaisuuksiin ja toimintamalleihin, joita on käytetty myöhemmin muutosprosessissa. Työssä käydään läpi tuotteen kehitysprosessia askel kerrallaan. Kehitysprosessissa käydään läpi asiointipalveluun tehtyjä muutoksia, joissa on pyritty hyödyntämään opittuja kehitysmenetelmiä ja toimintamalleja kestävän koodin tuottamiseksi.

Vaaditut työn toiminnallisuudet saatiin työstettyä, ja muutokset päätyivät lopulta tuotan- toon.

Avainsanat Angular, kehitysprosessi, käyttöliittymä, TypeScript, C#

(3)

Author Title

Number of Pages Date

Henrik Virrankoski

Development Process of Member Service Features 45 pages

13 April 2020

Degree Bachelor of Engineering

Degree Programme Information and Communications Technology Professional Major Software Engineering

Instructors Simo Silander, Senior Lecturer Jari Laurila, Chief Technology Officer

This thesis introduces required new changes and new functionality developed for a browser-based member service program by Futunio, as well as the steps required in the development process. The member service is intended for unemployment funds, where the member service is used by the unemployment funds’ members. The changes had to be done carefully as the service has a user base, to ensure a functional working product at all times.

The change requirements, the Angular framework and factors affecting the code quality are reviewed before introducing the developing process. The study was started by getting to know the Angular framework features and operating models, of which the relevant parts were later used in the developing phase. The thesis presents the developing process one step at a time. The changes to the member service are gone through in the developing process, seeking to utilize the acquired development methods.

The required functionality was created, and the changes eventually ended up in the pro- duction.

Keywords Angular, development process, UI, TypeScript, C#

(4)

Sisällys

Lyhenteet

1 Johdanto 1

2 Angular-ohjelmistokehys 2

2.1 Angular lyhyesti 2

2.2 TypeScript 3

2.3 Komponenttirakenne Angularissa 4

2.4 Komponenttien välinen kommunikointi 8

2.5 Komponenttirakenteen hyödyt 9

2.6 Material UI 12

3 Koodin laadun varmistaminen 13

3.1 Logiikan koostuminen osista 13

3.2 Tietorakenteen laatu 14

3.3 Yksikkötestaus 15

4 Asiointipalvelun kehitysprosessi 17

4.1 Muutosvaatimukset 17

4.2 Nykyinen tietorakenne ja käyttöliittymätoteutus 18

4.3 Muutokset komponentti- ja tietorakenteeseen 20

4.4 Syöttökenttien validointiongelman korjaus 25

4.5 Työnantajatiedon valinnan rajoittaminen 31

4.6 Työaikarajoitteen korjaus 33

4.7 PDF-generoinnin muutokset 35

5 Yhteenveto 41

Lähteet 43

(5)

SPA Single Page Application. Selainsovellus, joka lataa kerralla kaikki toimin- nallisuudet selaimeen ja jossa näkymää vaihdetaan dynaamisesti.

MPA Multi Page Application. Perinteinen selainsovellus, jossa jokainen näkymä ja sen toiminnallisuus ladataan erikseen kokonaan.

HTTP Hypertext Transfer Protocol. Siirtoprotokolla, jota käytetään TCP-yhteyden kautta tiedonsiirtoon, varsinkin selainsovelluksissa.

HTML Hypertext Markup Language. Merkintäkieli, jota käytetään käyttöliittymien, kuten verkkosivujen, esittämiseen.

CSS Cascading Style Sheets. Tyylittelyyn tarkoitettu kieli, jonka avulla käyttöliit- tymää on mahdollista tyylitellä kielessä esiteltyjen tyylittelysääntöjen avulla.

SCSS Sassy CSS. Kuten CSS, mutta syntaksissa on enemmän ominaisuuksia.

UI User Interface. Tarkoittaa käyttöliittymää eli sitä osaa, jonka käyttäjä näkee laitteen ruudulla ja jonka avulla pystyy vuorovaikuttamaan ohjelman kanssa.

UI Library User Interface Library. Näkymän kustomointiin tarkoitettu kirjasto, joka tuo lisämahdollisuuksia käyttöliittymän ja komponenttien tyylittelyyn.

TypeScript Microsoftin kehittämä JavaScriptiin pohjautuva ohjelmointikieli, joka tuo tyypittelyn ja muita ominaisuuksia JavaScript-kieleen.

C# Yleiseen tarkoitukseen tarkoitettu Microsoftin kehittämä ohjelmointikieli.

MVC Model-View-Controller. Ohjelmistoarkkitehtuuri, jonka avulla erotetaan käyttöliittymä, tiedon tallennus ja ohjelmalogiikka toisistaan.

(6)

1 Johdanto

Nykymaailmassa useammat palvelut toimivat web-pohjaisina nettisovelluksina. Koska monet olennaiset palvelut ovat siirtyneet web-palveluiksi, voidaan niiden käyttöä pitää osittain välttämättömänä. Kun nettisovellukset määrittelevät suuren osan palveluis- tamme, on luonnollista, että käyttäjät odottavat palveluiden toimivan moitteettomasti, verkkosivujen lataavan nopeasti ja käyttäjäkokemuksen olevan yleisesti miellyttävä.

Työssä tarkastellaan sovelluskehityksen kautta, mitä haasteita web-sovelluskehitykseen liittyy. Työssä kehitetään selainpohjaiseen asiointipalvelusovellukseen uusia vaadittavia toiminnallisuuksia sekä käydään läpi kehitysprosessia ja tarkastellaan sen eri vaiheita sekä mahdollisia vaikutuksia.

Työ on tehty Futunio Oy:lle. Futunion yksi tuotteista on selainpohjainen asiointipalvelu työttömyyskassoille [1]. Asiointipalvelun yksi päällimmäisistä käyttötarkoituksista on pal- velun käyttäjien, työttömyyskassojen jäsenien, mahdollisuus hakea työttömyysetua asi- ointipalvelussa täytettävän hakemuksen kautta. Hakemus on jaettu osiin, joissa hakijan on täytettävä kukin hakemuksen osa kerrallaan ennen hakemuksen lähettämistä. Yksi näistä hakemuksen osista on päiväselvitysosio. Päiväselvitysosio sisältää aikaisemmin hakijan ilmoittaman hakujakson sisältämät kaikki päivät listattuna. Hakijan on kullekin palkalliselle päivälle syötettävä työllisyystietonsa, jotka sitten myöhemmin vaikuttavat työttömyysedun käsittelyprosessiin. Päiväselvitykseen haluttiin muutoksien avulla uutta toiminnallisuutta vanhan tilalle, kuitenkin niin, että vanha toiminnallisuus säilytettäisiin sovelluksessa, ja uuden ja vanhan toiminnallisuuden käyttöönottoa voitaisiin hallinnoida asetuksen avulla. Työssä tehdyt muutokset liittyvät päiväselvitysosion uuden toiminnal- lisuuden lisäämiseen. Samalla huomioidaan vanhan toiminnallisuuden säilyttäminen.

Uutta toiminnallisuutta työstämällä pyrittiin samalla tuottamaan laadukasta koodia, jotta muutokset tuottaisivat mahdollisimman paljon hyötyä tuotteelle, mutta samalla otetaan huomioon yrityksen asettamat kriteerit, kuten työhön käytettävä aika. Työssä käydään myöhemmin läpi se, mitä tarkoittaa koodin laatu.

Ennen työn läpikäymistä tutustutaan Angular-ohjelmistokehykseen, jolla selainpohjainen asiointipalvelu on rakennettu sekä käydään läpi toimintaperiaatteita koodin laadun var- mistamiseksi. Näiden jälkeen käydään läpi työn muutoksia sekä työssä käytettyjä tieto-

(7)

ja komponenttirakenteita ennen ja jälkeen muutosten. Lopuksi käydään läpi muutokset hakemusten PDF-raporttien generointiin, joka on työstetty Crystal Reports -nimisellä työ- kalulla. Muutoksia läpi käydessä analysoidaan koodia ja pohditaan, mitä eri asioita on otettava huomioon muutoksia tehtäessä. Raportin yksi tavoitteista onkin pyrkiä autta- maan keskivertokäyttäjää, kenties jopa asiointipalvelun käyttäjää, hahmottamaan, min- kälainen muutosprosessi on kehittäjän näkökulmasta ja mitä haasteita näinkin näennäi- sesti yksinkertaisten toiminnallisuuksien muutosten kehittäminen tuo mukanaan.

2 Angular-ohjelmistokehys

2.1 Angular lyhyesti

Angular on Googlen kehittämä nettiisovellusten kehittämiseen tarkoitettu avoimeen läh- dekoodiin perustuva ohjelmistokehys [2]. Angular-ohjelmistokehyksellä on mahdollisuus luoda tehokkaita, natiiveja, eri alustojen kanssa yhteensopivia SPA-sovelluksia [3]. SPA- sovellukset toimivat lyhykäisesti siten, että toisin kuin perinteisesti MPA-sovelluksissa, sovelluksen vaatimat toiminnallisuudet ladataan kerralla käyttäjän selaimeen ensim- mäistä kertaa sivulle vieraillessa. Täten sovellukseen on valmiiksi säilytetty tietoja, joita käytetään eri näkymiin ja toiminnallisuuteen. SPA-sovelluksissa navigoidessa näky- mästä päivitetään ainoastaan vaadittavat ja muuttuvat osat toisin kuin silloin, kun sivut ladattaisiin aina kokonaan uudelleen. Aina tarvittaessa palvelimelta voidaan kuitenkin hakea lisää sovelluksen vaatimaa tietoa. [4.]

Angular-ohjelmistokehys tarjoaa SPA-sovellusten mahdollistavien ominaisuuksien li- säksi useampia työkaluja ja ominaisuuksia. Niiden avulla on nettisovelluksien kaikkein olennaisimpien ominaisuuksien kehittäminen mahdollista ilman, että sovellukseen tarvit- see asentaa ylimääräisiä riippuvaisuuksia tai että joutuu itse työstämään perustoiminnal- lisuutta. Sovelluksen toiminnallisuuden riippuvaisuutta ainoastaan Angular-ohjelmistoke- hyksestä voidaankin yleisesti pitää järkevämpänä ratkaisuna, kuin että lisää kolmannen osapuolen kirjastoja projektiin useasta eri lähteestä. Angularin kehityksestä vastaa Google, joten on varmempaa, että nettipalveluihin perustuva suuryritys on kykenevämpi kehittämään ohjelmistokehystä enemmän ja pidempään. Jos sovelluksen toiminnallisuus riippuu useammista pienemmistä kehittäjätahoista, on todennäköisempää, että käytössä

(8)

olevia riippuvaisuuksia ei kehitetä ja ylläpidetä yhtä pitkään. Suurempia yrityksiä voidaan myös pitää luotettavampana kuin yksittäisiä kolmannen osapuolen kirjastojen kehittäjiä.

Angular-ohjelmistokehys tarjoaa valmiiksi esimerkiksi HttpClient-nimisen kirjaston, jonka avulla nettisovelluksen on mahdollista kommunikoimaan palvelimien kanssa HTTP-pro- tokollan kautta [5]. HTTP on protokolla, jonka yleisin käyttötarkoitus on nettipalveluiden, kuten selainsovellusten, ja pilvessä toimivien palvelimien välisen kommunikoinnin mah- dollistaminen. Käytännössä jokainen palvelimien kanssa kommunikoiva web-sovellus käyttää HTTP-protokollaa tiedonvälitykseen. [6.]

Angulariin liittyy monia ominaisuuksia, työkaluja sekä käsitteitä. Työn kannalta on oleel- lista ymmärtää vain komponenttirakenne, komponentit, niiden toiminnallisuus ja miten niiden avulla pystytään luomaan toimiva käyttöliittymä web-sovellukselle. Angular-sovel- lusten kehityksessä usein hyödynnetään muun muassa palveluiden (engl. service) käyt- töä, jotka tuovat oleellista toiminnallisuutta sovellukseen, mutta niiden käyttö ei suoraan liity työssä tehtäviin muutoksiin, joten ne jätetään raportissa käymättä läpi [7].

2.2 TypeScript

Angularin yksi suurimmista eduista on TypeScript-kielen käyttö ohjelmistokehyksessä.

TypeScript on Microsoftin kehittämä JavaScriptiin pohjautuva vahvaa tyypitystä tukeva ohjelmointikieli [8]. Perinteisesti web-palvelukehityksessä käytettävään JavaScriptiin verrattuna TypeScript tuo paljon hyötyjä pääosin tyypityksen kautta: luettavuus paranee, testattavuus ja muutosten tekeminen koodiin helpottuu, uusien kommunikointitekniikoi- den, kuten Dependency Injection, käyttö on mahdollista ja projektin rakennetta on hel- pompi hallita [9]. Hyödyt huomaa varsinkin isomman skaalan projekteissa, joissa moni- mutkaisia rakenteita on helpompi hallita tyypittelyn avulla, jolloin selkeän koodin työstä- minen on ylipäätänsä edes mahdollista.

Kielen tyypittely määrittelee, missä muodossa käytössä olevien muuttujien ja lausekkei- den on esiinnyttävä koodissa [10]. Käytössä oleva koodieditori osaa yleensä huomauttaa kehittäjälle, jos muokattu koodi ei sovellu sen määrittelyyn eli sisältää virheitä, jotka es- tävät ohjelman toimimasta. Moni tiedostaa TypeScriptin tuomat hyödyt, ja nykyisten muutosten perusteella TypeScript tulee luultavasti ennen pitkään saavuttamaan Ja- vaScriptin valtavan suosion [11; 12].

(9)

2.3 Komponenttirakenne Angularissa

Angularissa käyttöliittymä koostuu komponenteista. Komponentti voidaan jakaa kahteen osaan: näkymään sekä komponenttilogiikkaan. Komponenttilogiikka koostuu komponen- tin TypeScript-tiedostosta (kuva 1). Se sisältää ns. komponentin logiikan ja tiedot kom- ponentista. Sen avulla voidaan kommunikoida näkymän sekä muun ohjelman kanssa.

Komponenttilogiikka sisältää komponentin toiminnallisuuden muuttujien ja funktioiden muodossa. MVC-malliin verrattaessa komponenttilogiikka vastaa lähiten ohjainta (engl.

controller) [13]. Usein komponentista puhuttaessa viitataan sen komponenttilogiikkaan.

Näkymä taas toimii komponentin ulkoasuna tai näkymänä. Se koostuu template-koodista sekä SCSS-koodista, jotka ovat usein omina tiedostoinaan (kuva 1). Angularissa kom- ponentin HTML-koodia kutsutaan template-koodiksi [14]. HTML-merkintäkielen avulla perinteisesti luodaan verkkosivun ulkoasu, mutta komponenteissa sillä luodaan yksittäi- sen komponentin ulkoasu. Angular tuo lisäominaisuuksia HTML-koodiin, joita ei normaa- listi löydy HTML-syntaksista, mikä tekee siitä template-koodin. Template-koodi muun muassa mahdollistaa yhdessä komponenttilogiikan kanssa näkymän, komponenttilogii- kan sekä komponenttien välisen kommunikoinnin. Näkymää voi myös tyylitellä SCSS- koodin avulla. SCSS-koodin tarkoitus on ulkoasun muokkaus SCSS-koodissa esiteltyjen tyylittelysääntöjen avulla. MVC-malliin verrattaessa komponentin näkymä vastaa eniten näkymää (engl. view), vaikka toisin kuten yleensä, kommunikointi komponenttilogiikan kanssa tapahtuu kaksisuuntaisesti [13].

Kuva 1. Angular-komponentteja on mahdollista luoda komennolla, joka generoi .html- ja .scss- tiedostot näkymää varten, .ts-tiedoston komponenttilogiikkaa varten ja .spec.ts-tiedos- ton yksikkötestausta varten.

Angularissa komponentteja on mahdollista lisätä yksi tai useampi toistensa sisälle, jolloin on mahdollista luoda puulta muistuttava komponenteista koostuva malli - komponentti-

(10)

rakenne. Käännösaikana kääntäjä muuntaa kaikki sisäkkäiset ja käytössä olevat kom- ponentit niissä määriteltyiksi näkymiksi, jotka yhdessä luovat kokonaisen käyttöliittymän nettisovellukselle. Komponenttia voidaan kuvailla sovelluksen yhdeksi rakennuspali- kaksi, jolla on oma toiminnallisuutensa.

Seuraavassa esimerkissä on esitelty kahdesta komponentista koostuva komponenttira- kenne. Olemassa oleva my-heading-niminen komponentti sekä perinteinen HTML:n div- elementti leipätekstiä varten on lisätty main-nimisen komponentin sisälle.

<my-heading></my-heading>

<div class=”body-text”>leipätekstiä</div>

Esimerkkikoodi 1. main-nimisen komponentin template-koodin sisältö.

Koodiesimerkki 1 kuvastaa main-komponentin template-koodin sisältöä. my-heading - komponentti on lisätty main-komponentin sisälle HTML-elementtinä, jonka tunnistaa <>- merkeistä. Komponenttilogiikassa on myös määritelty se, minkä niminen komponentin elementti on. Tässä tapauksessa ja yleensä my-heading-komponentin elementti on kom- ponenttinsa niminen eli <my-heading></my-heading>. Myös leipätekstiä on lisätty main- komponenttiin tekstin näyttämistä varten tarkoitetun div-elementin avulla. div-elementti ei ole komponentti, vaan HTML-kielen tuomaa perustoiminnallisuutta. Komponenttien elementtejä ei voi siten nimetä HTML:n peruselementeiksi. Esimerkkikoodissa 1 kum- matkin otsikko ja leipäteksti on lisätty elementteinä, mutta vain otsikko on komponentti.

Käännöksen aikana otsikkokomponentin kohdalle luodaan se näkymä ja toiminnallisuus, jotka on määritelty kyseisessä komponentissa.

Raportissa käytetään diagrammeja komponenttirakenteiden hahmottamisen helpotta- miseksi. Esimerkkikoodi 1 esitettynä diagrammina on hahmoteltu kuvassa 2.

(11)

Kuva 2. Esimerkkikoodin 1 komponenttirakenne.

Kuvan 2 diagrammi esittää main-elementin näkymän koostumista my-heading-otsikko- komponentista ja leipätekstin div-elementistä. Nuoli kahden palikan välillä tarkoittaa sitä, että nuolen osoittama palikka on komponentti, joka on lisätty nuolen vasemmalla puolella olevan komponentin sisälle. Kaksiviivainen ”linkki” tarkoittaa sitä, että viivan oikealla puo- lella oleva palikka on osa viivan vasemmalla puolella olevaa komponenttia. Tämänlainen palikka on HTML-elementeistä koostuva yksi kokonaisuus, kuten vaikka leipäteksti- kenttä. Huomioitavaa on se, että komponenttinäkymätkin ovat loppujen lopuksi elemen- teistä koostuvia kokonaisuuksia, joten kyseiset palikat ovat verrattavissa keskenään.

Esimerkkikoodissa 1 otsikko on merkattu ennen leipätekstiä, joten käyttöliittymässäkin otsikko tulee perusasetuksilla leipätekstin yläpuolelle.

Komponenttien lisääminen toisiin komponentteihin on vain yksi Angularin tuomista omi- naisuuksista template-koodin syntaksiin. Ominaisuuksien avulla kehittäjän on helpompi hallinnoida näkymää ja lisätä toiminnallisuutta käyttöliittymään. Template-syntaksi mah- dollistaa sen, että näkymän on mahdollista hakea käyttöliittymään tarvittavaa näyttötie- toa muuttujien tai funktioiden palautusarvojen kautta, sekä pystyy myös toiseen suun- taan viemään tietoa komponenttilogiikkaan, kuten esimerkiksi käyttäjän syöttämiä ar- voja. Näiden lisäksi template-syntaksin tärkeimpiä ominaisuuksia ovat mahdollisuus eh- dollisesti piilottaa osan komponenttinäkymästä sekä mahdollisuus näyttää ja hallita use-

(12)

ampi elementti tai komponentti toistuvana, usein allekkain ns. listana. Muokataan aikai- sempaa esimerkkikomponenttirakennetta sisältämään kaksi edellä mainittua Angularin tuomaa ominaisuutta: ehdollinen näkyvyys sekä näkymän toistuvuus.

public showHeading: boolean = ...;

public bodyTexts: Array<string> = ...;

...

<!-- näyttää my-heading-komponentin jos showHeading-muuttuja on tosi -->

<my-heading *ngIf="showHeading"></my-heading>

<!-- iteroi ja näyttää alla olevan div-elementin käyttöliittymässä kullekin iteraatiolle -->

<div class="body-text" *ngFor="let text of bodyTexts">{{text}}</div >

Esimerkkikoodi 2. Päivitetty main-komponentin sisältö. Komponentin komponenttilo- giikkaa ylempänä ennen ...-merkintää ja template-koodia alempana.

Kuva 3. Esimerkkikoodia 2 kuvaava diagrammi.

Esimerkkikoodin 2 ja kuvan 3 komponenttirakenne kuvastavat päivitettyä esimerkkiä.

main-komponentti näyttää nyt ngIf-attribuutin avulla otsikkokomponentin (my-heading) ehdollisesti, eli silloin, kun showHeading-muuttuja on tosi. Diagrammissa ehdon tunnis- taa vuokaavioista tutusta timanttikuviosta. Vaikka ehtojen vertailut on tehty template- koodissa, on ehdoissa käytetyt muuttujat haettu ja käsitelty yleensä komponenttilogii-

(13)

kassa. main-komponentti näyttää nyt myös lisätyn ngFor-attribuutin avulla nollan tai use- amman leipätekstin toistettuna, listana. Diagrammissa body-text-palikan kohdalla kaksi päällekkäistä palikkaa kuvaavat, että elementti on toistuva. Diagrammin osalta ei tarvitse tietää, kuinka usein palikka esiintyy käyttöliittymässä, kunhan tiedetään, että palikka voi esiintyä nolla kertaa tai useamman kerran eli toistuvasti.

2.4 Komponenttien välinen kommunikointi

Angular-komponentti voi sisältää useamman komponentin, mutta useammassa tapauk- sessa siitä ei ole paljonkaan hyötyä, jos komponentit eivät osaa kommunikoida keske- nään. Angular mahdollistaa tiedon välityksen komponenttien välillä. Sen avulla on mah- dollista kätevästi jakaa toiminnallisuutta ja vastuuta useammalle komponentille. [15.] Toi- minnallisuuden pilkkomisesta saatuihin hyötyihin palataan myöhemmässä luvussa. Vii- meisessä esimerkissä tarkastellaan komponenttikokonaisuutta, jonka avulla käyttäjä pystyy muokkaamaan henkilön tietoja.

interface IPerson { name: string, age: number, employed: boolean, salary: number | null }

. . .

public person: IPerson = { name: "",

age: 0,

employed: false, salary: null }

Esimerkkikoodi 3. Main-komponentissa henkilöolion alustus on tehty toteuttamalla IPerson-rajapintaa, jolla varmistetaan, että jokainen ominaisuus (engl. property) on alus- tettu ja tyypitelty oikein.

<input class="name-input" [(ngModel)]="person.name" .../>

<my-number-input [age]="person.age" (change)="ageChanged($event)">

</my-number-input>

<my-employment [employed]="person.employed" [salary]="person.salary"

(change1)="employedChanged($event)" (change2)="salaryChanged($event)">

</my-employment>

(14)

Esimerkkikoodi 4. Päivitetty main-komponentin template-koodi, joka sisältää yhden syöttökentän ja kaksi muuta komponenttia. Tietoa komponenttien muuttujille annetaan []- merkinnän avulla ja komponentit lähettävät tarvittaessa tietoa takaisin tapahtumien (event) avulla.

Vaikka yksi tietokokonaisuus, kuten vaikka henkilötiedot, olisi alustettu yksittäisessä komponentissa, voi tietokokonaisuuteen liittyviä yksittäisiä ominaisuuksia jakaa muiden komponenttien välillä. Tietojen välittäminen voidaan toteuttaa jakamalla tietokokonai- suuksia tai yksittäisiä viittauksia tietokokonaisuuden ominaisuuksiin, kuten vaikka henki- lön ikään, jolloin komponentti pystyy lukemaan tai muokkaamaan annettua tietoa. Jos komponentille siirretään tietokokonaisuuksia oliomuodossa, voi vastaanottava kompo- nentti olioviittauksen avulla tehdä muutoksia olioon, jolloin muutokset näkyvät myös lä- hettävässä komponentissa, eikä tietoja tarvitse erikseen siirtää takaisin.

Komponenttien välinen tiedon siirtäminen voi olla joko yksisuuntaista tai kaksisuuntaista.

Yksisuuntaisessa tiedonsiirrossa tietoa voi nimensä mukaisesti siirtää vain yhteen suun- taan komponentista toiseen. Tämä on kätevää silloin, kun halutaan viedä ei-muokatta- vaa näyttötietoa komponentille. Kaksisuuntaisessa tiedon sitomisessa tietoa voi viedä kumpaankin suuntaan. Tämänlainen menettely on yleensä silloin välttämätöntä, kun ha- lutaan toisessa komponentissa muokata jotakin arvoa ja palauttaa muokattu arvo takai- sin lähdekomponenttiin. Tällöin muokkaavan komponentin on pystyttävä saamaan alku- peräinen muokattava tieto, sillä se tieto on pystyttävä näyttämään muokkauskentässä, ja samalla muokattu tieto on pystyttävä siirtämään takaisin alkuperäiseen lähdekompo- nenttiin. Diagrammien suhteen voidaan tosin olettaa, että kaikki tiedon siirtäminen ta- pahtuu kaksisuuntaisesti.

2.5 Komponenttirakenteen hyödyt

Esimerkkikoodissa 3 henkilötiedot koostuvat neljästä eri tiedosta, ts. ominaisuudesta, joita käyttäjän on tarkoitus pystyä muokkaamaan käyttöliittymästä. Eräs komponenttira- kenne sen toteuttamiseksi voisi olla kuvan 4 kaltainen.

(15)

Kuva 4. Esimerkki komponenttirakenteesta hallitsemaan esimerkkikoodissa 3 esiteltyjen henki- lötietojen muokkaamista. main-komponentin template-koodi on sama kuin esimerkki- koodissa 4, vaikka sillä ei tässä esimerkissä ole väliä.

Kuvassa 4 lukuun ottamatta nimen syöttökenttää (name-input) henkilötietojen täyttä- mistä on jaettu useammalle komponentille, jossa nimen syöttökenttä on vielä osa main- komponenttia. Diagrammissa merkityt vihreät tekstit kuvaavat niitä ominaisuuksia, jotka kyseisille komponenteille on sidottu. Komponentit pystyvät lukemaan sekä muokkaa- maan niille annetta arvoja eli ominaisuuksia. Kuvassa 5 on hahmoteltu käyttöliittymärat- kaisu, joka toteuttaa kuvan 4 komponenttirakennetta.

Kuva 5. Yksinkertainen käyttöliittymä, joka noudattaa kuvan 4 komponenttirakennetta. Kuvan oikealla puolella on sama käyttöliittymä, jossa on värikoodattu kukin komponentti.

(16)

Jos henkilötietojen muokkaus ei vaatisi paljon yksilöllisiä näkymiä, toiminnallisuutta tai ominaisuuksia, olisi kaikki se voitu rakentaa yhteen (main) komponenttiin. Kuvan 4 dia- grammiesimerkin kaltaisesti jokaisen yksinkertaisen kentän toiminnallisuuden jakaminen omaan komponenttiin voi olla vähän liioiteltua toimintalogiikan ollessa niin vähäistä. Kui- tenkin logiikan kasvaessa ja käyttötarkoituksien erottamisen vuoksi on toiminnallisuus kuitenkin kannattavaa jakaa omiin komponentteihin.

Esimerkiksi my-employment-komponentti on luotu hallinnoimaan palkkakentän näky- vyyttä. Jos käyttäjä on merkannut rastin ruutuun, ettei ole työssä, osaa komponentti pii- lottaa palkkasyöttö-komponentin, jota ei enää tarvita, koska käyttäjä ei ole voinut saanut palkkaa. Myöskin my-employment-komponentissa voidaan hakijalle työllisyyteen liittyen näyttää lisätietoa tekstimuodossa, laskea nettopalkka tai lisätä toiminnallisuutta kom- ponentteina riippuen käyttäjän syöttämistä arvoista. Logiikkaa ja toiminnallisuutta alkaa tällöin olemaan sen verran liikaa, että niitä ei kannata kasata kaiken muun kanssa sa- maan juurikomponenttiin.

Komponentteja on myös mahdollista kierrättää, eli samaa komponenttia voidaan sovel- taa useammassa tilanteessa. Komponentin kierrättämisessä ilmiselvä hyöty on se, että samaa komponenttia ei tarvitse luoda uudelleen useampaan paikkaan. Kuvan 4 dia- grammissa on samaa my-number-input-komponenttia käytetty kahdessa paikassa nu- meroarvon syöttämistä varten. Kyseisen komponentin nimestä voi päätellä, että kompo- nentti on luotu enemmän yleiseen numeronsyöttötarkoitukseen. Komponentille voidaan kuitenkin mahdollistaa parametrien käyttö, jolloin komponentin toiminnallisuutta voidaan laajentaa ja käyttötarkoitusta soveltaa useampaan tilanteeseen.

Jakamalla toiminnallisuutta useampaan komponenttiin pyritään estämään komponentin logiikan paisumista liian suureksi, jotta koodin luettavuus ei kärsi. Komponentit on luo- tava niin, että niillä on vain yksi tehtävä, jonka on ilmettävä komponentin nimestä. Se, miten kunkin komponentin tehtävä määritellään, ei ole täysin yksiselitteistä. Yhden kom- ponentin vastuulla voi olla yksittäisen kentän syötön hallinta, kun taas toinen hallitsee koko hakemuksen täyttämistä. Voidaan sanoa, että kummassakin tilanteessa kom- ponenteilla on vain yksi tehtävä, mutta tehtävät ovat aivan eri suuruusluokissa. Jos yk- sittäinen syöttökenttä ei vaadi paljon toiminnallisuutta, voi sen omaksi komponentiksi muuttaminen olla turhaa, sillä uuden komponentin työstäminen vie kuitenkin aikaa, ja

(17)

muutaman rivin toiminnallisuuden siirtäminen omaksi komponentiksi saattaa vain vai- keuttaa koodin luettavuutta. Hakemuksen täyttämistä hallinnoiva komponentti vaatii taas useampia toiminnallisuuksia: navigointi hakemuksessa, kenttien validointi, tietojen päi- vittäminen, kommunikointi palvelimen kanssa, kuten hakemusta lähettäessä. Listattu on vain osa hakemukseen liittyvistä toiminnallisuuksista, joita on tosiasiassa paljon enem- män. Tällaisessa tapauksessa toiminnallisuutta yhdelle komponentille on liikaa, ja se on hyvä jakaa komponentteihin. Hakemus voi kuitenkin itsessään olla komponentti, jonka rakenne koostuu useammasta komponentista, komponenttirakenteesta. Se, milloin on kannattavaa muuttaa toimintaa omaksi komponentiksi, tai kuinka suuriksi komponentit on luotava, on itse kehittäjän vastuulla päättää.

2.6 Material UI

Kuvan 5 käyttöliittymästä huomaa, että käyttöliittymä ilman mitään tyylittelyä näyttää melko pelkistetyltä ja jopa tylsältä. Angular-ohjelmistokehys itsessään ei tuo minkäänlai- sia lisätyökaluja käyttöliittymän ulkoasun tyylittelyä varten, mutta siihen on helppo lisätä Angular Material UI -ulkoasukirjasto (engl. UI library). Työssä läpikäytävässä palvelussa on käytössä kyseinen UI-kirjasto, jonka avulla käyttöliittymistä luodaan miellyttävän nä- köisiä, modernikkaita, selkeitä sekä funktionaalisia. Angular Material UI -kirjasto tekee käyttöliittymän muokkaamisesta sen verran vaivatonta, että se mitätöi vähintään osittain perinteisten SCSS-tyylittelysääntöjen käyttämisen. Kirjastoa käytettäessä on samalla py- ritty noudattamaan material-oppaan sääntöjä ja suosituksia käyttöliittymäsuunnittelussa takaamaan mahdollisimman miellyttävän käyttäjäkokemuksen [16]. Angular Material UI -kirjastoa kehitetään yhdessä Angular-ohjelmistokehyksen kanssa, mikä takaa sen yh- teensopivuuden Angular-ohjelmistokehyksen kanssa sekä laajat muokkausmahdollisuu- det. Kuvassa 6 näkyy kuvan 5 käyttöliittymä, joka on tyylitelty tyylikkäämmäksi Angular Material UI -kirjaston avulla.

(18)

Kuva 6. Kuvan 5 käyttöliitymä tyyliteltynä Angular Material UI -kirjaston avulla.

3 Koodin laadun varmistaminen

Työssä pyritään kiinnittämään huomiota kirjoitettavan koodin laatuun. Työstetyn koodin laadun lisäksi pyritään muutosten kautta mahdollisesti parantamaan jo olemassa olevaa toteutusta. Laadukkaalla koodilla tarkoitetaan pääsääntöisesti sen selkeyttä ja ylläpidet- tävyyttä [17]. Oletuksena on, että tuote tulee elämään vielä pitkään, joten muutokset on tehtävä siten, että tuotteen jatkokehitys olisi mahdollisimman vaivatonta.

3.1 Logiikan koostuminen osista

Angularin komponenttirakenteessa luettavuutta ja ylläpidettävyyttä edistää toiminnalli- suuden koostuminen osista, kuten komponenteista. Yksittäistä käyttötarkoituksen mu- kaan nimettyä komponenttia on helpompi ymmärtää toisin kuin yhtä suurempaa kompo- nenttia, jolla on paljon toiminnallisuutta ja joka sisältää paljon sekalaista logiikkaa ja koo- dia. Muutoksien tekeminen komponenttiin on vaivatonta, kun sen riippuvuudet muuhun toiminnallisuuteen on rajaamalla selkeytetty, ja uuden toiminnallisuuden lisääminen on helppoa uusien komponenttien muodossa.

Toiminnallisuuden jakaminen ei ainoastaan kohdistu komponenttirakenteeseen. Myös komponenttilogiikkaa on kannattavaa jakaa esimerkiksi funktioihin. Myös funktioiden

(19)

luonnissa toimii sama periaate: yksi funktio tekee yhden asian. Sama neuvo pätee ylei- sestikin ohjelmistokehityksessä [18]. Samalla lailla komponenttilogiikasta tulee luetta- vampi, kun sen koodiosioilla on selkeä tarkoitus.

3.2 Tietorakenteen laatu

Hyvä tietorakenne varmistaa, että käytössä oleva tieto on oikeanlaista. Hyvien ni- meämiskäytäntöjen ja nimeämisen avulla pystyvät muut kehittäjät tulkitsemaan helpom- min tietorakennetta ja tekemään olettamuksia sen perusteella. Olettamuksien tekeminen ei välttämättä tarkoita, että oletetaan, miten sovellus toimii, vaan että on nopeampaa navigoida projektissa ja varmistaa ohjelman toimintaa. Esimerkiksi hyvin nimetystä muuttujan nimestä voi päätellä, mitä muuttujan on tarkoitus pitää sisällään. Jos muuttu- jaan voi päätyä tietoa, joka ei sovi muuttujan kuvaukseen, tarkoittaa se sitä, että ohjel- massa on joko virhe, tai muuttuja on nimetty huonosti. Muuttujan nimi kannattaa olla myös mahdollisimman tarkasti nimetty, sillä kovin yleiskuvaavasta nimestä voi olla vai- kea ymmärtää sen käyttötarkoitusta. Esimerkiksi data-nimisestä muuttujasta on vaikea päätellä, mitä tietoa muuttujassa kuuluisi olla tai mihin tarkoitukseen sitä käytetään.

Tietorakenteen kenttien tyypitykset varmistavat, että tiedon muoto on oikeanlaista, mikä auttaa ymmärtämään, minkälainen käytössä oleva tieto on. Tyypityksessä sovelluksen eri konstruktioille, kuten muuttujille, on olemassa sääntöjä, jotka määrittelevät konstruk- tion rakenteen ja miten sitä kuuluisi käsitellä sovelluksessa. Viimeistään sovelluksen käännöshetkellä kääntäjä antaa virheilmoituksen, jos huomaa, että sovelluksessa yrite- tään mahdollisesti väärinkäyttää tietoa, joka ei sovi konstruktion tyypityksen määritte- lyyn. Myös modernit koodieditorit osaavat ilmoittaa, jos koodi sisältää tyypittelyvirheen, kuten on esitelty kuvassa 7.

(20)

Kuva 7. TypeScript ei salli tekstiarvon asettamista muuttujaan, jonka tyyppi on numero.

Tyypityksen avulla on mahdollista myös määritellä tietojen olemassaolon pakollisuus.

Monet modernit ohjelmointikielet mahdollistavat ei-pakollisten (engl. nullable) tyyppien soveltamisen, jossa tieto voi olla ns. tyhjä, eli ilman arvoa. Kuitenkin omasta mielestä ei- pakollisia tyyppejä on liian helppo väärinkäyttää. Ei-pakollisten tyyppien välttämisellä voi- daan ennaltaehkäistä tulevia virheitä, sillä ei-pakollisten tietojen olemassaolo täytyy yleensä ohjelmassa erikseen tarkistaa, ennen niiden soveltamista. Esimerkiksi, kun ky- seessä on ei-pakollista tietoa, voi kehittäjä olla tietyllä hetkellä varma, että tiedon ole- massaolo on tarkistettu, jolloin voi muualla koodissa jättää tarkistuksen tekemättä. Kui- tenkin on mahdollista, että jokin muu taho tekee koodiin muutoksia, jonka jälkeen tietoa voidaan mahdollisesti yrittää soveltaa ennen sen olemassaolon tarkistusta. Tästä seuraa yleensä virhetilanteita, jos sovellettava tieto onkin tyhjä. Pakollisissa tyypeissä varmiste- taan, että tieto on aina olemassa. Suosimalla pakollisia tyyppejä aina, kun on mahdol- lista, vähennetään tarkistusten tekemisen tarvetta, jolloin virheetkin pysyvät minimissä.

3.3 Yksikkötestaus

Projekti sisältää myös yksikkötestejä toiminnallisuudelle. Koodin laatu tarkoittaa myös yksikkötestien koodin laatua, ja testien laadukkuuteen on käytetty samoja edellä mainit- tuja periaatteita. Päämääränä on mahdollisimman suuri testikattavuus mahdollisimman vähällä ja selkeällä koodilla. Laadukkaat ja kattavat yksikkötestit luovat itsevarmuutta muutoksien tekemiseen, sillä testit auttavat huomaamaan muutoksien aikana syntyneet mahdolliset virheet.

Komponenttirakenteen jakautuessa osiin on luonnollista, että myös yksikkötestit jakau- tuvat pienempiin kokonaisuuksiin. Luvussa mainittujen hyötyjen lisäksi myös testien

(21)

suunnittelu ja työstäminen helpottuvat, kun testattavan koodin määrä on pilkottu osiin.

Testattavan koodin ollessa osissa on helpompi hahmottaa logiikan kaikki sen testattavat osat ja haarat. Myöskin, jos käytössä on työkaluja, jotka analysoivat testikattavuutta, voi- vat ne helposti antaa väärennetyn kuvan testikattavuudesta, jos esimerkiksi yhdestä tie- dostosta puuttuu testejä, mutta tiedosto onkin toiminnallisuudeltaan jättimäinen.

Kuvassa 8 on Istanbul.js-testityökalun käyttöliittymä, joka näyttää erään sovelluksen tes- tikattavuutta. Testikattavuutta mitataan yleensä sillä, kuinka suurta sovelluksen osuutta vasten testiohjelmaa on ajettu. Se voi olla vaikka prosenttimäärä kutsutuista sovelluksen funktioista tai tehdyistä operaatioista. Kuvasta voidaan päätellä, että heroes-komponen- tilla on huonoin testikattavuus. Testikattavuus ei tosin kerro koko kuvaa testien laadusta.

Kannattavinta on kuitenkin pitää silmällä jokaista testikattavuutta mittaavaa arvoa.

Kuva 8. Istanbul.js-testityökalun näkymä, jolla voi tarkastella Angular-sovelluksen yksikkötes- tien kattavuutta [19].

(22)

4 Asiointipalvelun kehitysprosessi

4.1 Muutosvaatimukset

Työssä tehdään muutoksia asiointipalvelussa täytettävään hakemuksen päiväselvitys- osaan (kuva 9). Päiväselvitys-osiossa hakijan on ilmoitettava työllisyystilanteensa kulle- kin ilmoittamansa hakujakson päivälle. Päivät jakautuvat päivänäkymiin, jossa kullekin päivälle hakija vähintään valitsee alavalikosta työllisyystilanteensa kyseiselle päivälle.

Työllisyystilanne voi olla esimerkiksi ”työssä”, jolloin hakijan on täytettävä työnantajan nimi sekä tehty työaika. Pidemmissä työjaksoissa saman työnantajan nimen kirjoittami- nen jokaiselle päivälle voi olla hakijalle puuduttavaa ja mahdollistaa myös virheiden syn- tymisen muun muassa kirjotusvirheiden kautta. Onneksi valtionvarainministeriön ja ve- rohallinnon luoman Kansan Tulorekisteri -hankkeen ansiosta hakijan työnantajatiedot on nykyään mahdollista hakea suoraan tulorekisteristä. Täten hakemusta haluttiin muuttaa siten, että hakijan tarvitsee kirjoittamisen sijaan ainoastaan valita oikea työnantaja ala- valikosta, johon on valmiiksi haettu hakijan työnantajat tulorekisteristä.

Lisäksi tilanteissa, jossa hakija on merkannut työllisyystilanteensa palkalliseksi, nykyi- sessä päivänäkymässä on mahdollista syöttää vain yhden työnantajan työaikatiedot, vaikka hakija voi joissakin tilanteissa olla saman päivän aikana tehnyt työtunteja useam- malle työnantajalle. Muutoksia haluttiin päiväselvitys-osioon niin, että hakijan on mah- dollista syöttää kussakin päivässä yhden sijaan useamman työnantajan ja niille tehdyt työajat.

Työtä hankaloittaa se, että vanha tai uusi toiminnallisuus on oltava samanaikaisesti mah- dollista ottaa käyttöön sovelluksessa, sillä asiakkaat saavat päättää muutoksien käyt- töönotosta. Toisin sanoen on luotava asetus, jonka avulla hallitaan muutoksien käyttöön- ottoa. Kun asetus on pois päältä, sovellus toimii kuten ennenkin ja työnantajatietoja voi syöttää päivälle vain yhden, ja työnantajan nimi on syötettävä tekstikenttään. Kun asetus on päällä, käytetään uutta toiminnallisuutta ja työnantajatietoja on mahdollista syöttää useampi päivälle ja työnantajan nimi on valittavissa alavalikosta. Kun halutaan käyttää vanhaa toiminnallisuutta, ei riitä, että käytetään vain vanhempaa versiota sovelluksesta, sillä sovellus kokee jatkuvasti muutoksia, jotka halutaan viedä aina uusimpaan julkai- suun riippumatta päiväselvitysosion muutoksien käyttöönotosta.

(23)

Kuva 9. Osa nykyisen päiväselvitysosion näkymää, joka koostuu päivänäkymistä (rivit).

4.2 Nykyinen tietorakenne ja käyttöliittymätoteutus

Työssä tehdyt muutokset liittyvät asiointipalvelun päiväselvitysosioon. Päiväselvitys- osiota voidaan ajatella eräänlaisena tietokokonaisuutena, joka on osa hakemusta. Se sisältää tiedot hakijan työllisyystiedot ilmoitetulle hakujaksolle. Nykyinen tietorakenne mallintuu seuraavanlaisesti: päiväselvitys-osio sisältää listan viikoista, ja viikot sisältävät listan päivistä. Päiväselvitysosio on jaettu aluksi viikkoihin pelkkien päivien sijaan sen takia, koska viikkotietoa tarvitaan muualla sovelluksessa ja myöhemmin hakemuksen käsittelyprosessissa. Yksittäinen päivä sisältää kaikki tarvittavat tiedot liittyen hakijan työllisyystilanteeseen kyseiselle päivälle.

Esimerkkikoodi 5 kuvastaa päiväkohtaisen TypeScript-olion määrittelyä, joka sisältää hakijan työllisyyteen liittyvät tiedot (ts. ominaisuudet) kyseiselle päivälle. Yksi kokonai- nen viikko sisältää seitsemän kyseistä oliota kullekin viikonpäivälle. Rakenne on toteu- tettu niin, että yksi olio koostuu kyseisen päivän päivämäärästä, tilasta, joka kertoo ha-

(24)

kijan työllisyystilanteen, mahdollisesta lisäselvityksestä sekä numerokentistä mahdol- lista tehtyä työaikaa varten. Kysymysmerkki ominaisuuden (esimerkkikoodi 5) perässä tarkoittaa, että kyseinen kenttä voi saada ns. tyhjän arvon, eli ominaisuuden ei ole pakko sisältää arvoa.

export interface IDay { // päivämäärä date: Date;

// työlliyys-tila status: DayStatus;

// lisäselvitys (tai työnantaja) explanation?: string;

// tehdyt työtunnit ja -minuutit hours?: number;

minutes?: number;

}

Esimerkkikoodi 5. Nykyinen päiväkohtainen oliorakenne. Oliorakenteen määrittelevä TypeScript-rajapinta koostuu viidestä ominaisuudesta.

Kaikki ominaisuudet eivät kuitenkaan vaadi, että niihin syötettäisiin arvot. Se riippuu käyt- täjän valitsemasta työllisyystilanteesta. Käyttöliittymä on toteutettu niin, että käyttäjä pys- tyy aina valitsemaan työllisyystilanteensa päivälle. Päivänäkymän muu toiminnallisuus käyttäjän valitseman työllisyystilan suhteen noudattaa seuraavia sääntöjä.

1. Jos tilaksi on valittu arvo ’työtön’, mikään muu arvo ei ole tällöin muokattavissa.

2. Jos tilaksi on valittu arvo, jossa hakija on kelvollinen saamaan palkkaa työnan- tajalta, on hakijan täytettävä työnantajan nimi lisäselvityskenttään sekä työaika tunti- ja minuuttikenttiin.

3. Muilla tilan arvoilla on hakijalla mahdollisuus lisätä lisäselvitys lisäselvityskent- tään.

Päiväkohtainen tietorakenne on sellaisenaan toimiva ratkaisu ja palvelee hyvin käyttö- tarkoitusta. Tietorakenteesta kuitenkin ilmenee pieniä ongelmia, joihin pyritään kehittä- mään ratkaisu muutosten yhteydessä. Tarkastellaan aluksi edellä mainituista tilanteista kohtaa 2, jossa käyttäjän syöttämä työnantajan nimi asetetaan lisäselvitys-ominaisuu- teen (esimerkkikoodi 5: ’explanation’). Ongelmana ilmenee se, että ominaisuuden nimi

(25)

ei ole tilanteessa kovinkaan kuvaava. Ominaisuuteen asetetaan kahta erilaista tietoa:

työnantajan nimi sekä lisäselvitys. Ainoastaan jälkimmäisessä tapauksessa ominaisuu- den nimi kuvaisi sisältöään. Toinen pienempi ongelma rakenteessa on joidenkin ominai- suuksien tyhjän arvon hyväksyminen. Lisäselvitys, työtunnit ja työminuutit -ominaisuudet ovat käytössä vain palkallisissa työllisyystilanteissa. Siksi nämä ominaisuudet on luotu hyväksymään myös tyhjän arvon, eli tarvittaessa eivät sisällä mitään arvoa. Rakenne sallii kunkin kyseisten ominaisuuksien olevan joko ilman arvoa tai sisältävän arvon riip- pumatta muiden ominaisuuksien arvoista. Mieluummin haluaisimme selkeyttää, mitkä ominaisuudet voivat olla muokattavissa keskenään. Toisin sanoen joko kaikkien kenttien on pystyttävä sisältämään arvon tai ei minkään, niin kuin sen on käyttöliittymässäkin toi- mittava.

4.3 Muutokset komponentti- ja tietorakenteeseen

Uuden toiminnallisuuden lisääminen tarkoittaa käyttöliittymässä näennäisesti kahta muutosta: työnantajia pitää olla mahdollista lisätä useampi yhdelle päivälle sekä työnan- tajan nimen tekstisyöttökentän muuttaminen alavalikkokentäksi. Tietorakenteen muutos- ten kannalta olemme kiinnostuneita vain ensimmäisestä kohdasta. On muistettava, että uusi tietorakenne on kehitettävä yhteensopivaksi uuden ja vanhan toiminnallisuuden kanssa.

Esimerkkikoodi 6 kuvastaa muutosten jälkeistä uutta päiväkohtaista tietorakennetta.

Uusi rakenne ratkaisee edellä mainitut tietorakenteeseen liittyvät ongelmat. Yksi päi- väolio ei sisällä enää työaikaominaisuuksia itsessään, vaan yhden listan työaikatie- doista, mikä mahdollistaa useamman työsuhteen lisäämisen. Yksi työaikatieto koostuu työnantajan nimestä, tehdyistä työtunneista ja -minuuteista. Uusi rakenne kuitenkin mah- dollistaa yhteensopivuuden vanhan toiminnallisuuden kanssa sovellusrajoitteiden kautta. Työaikatietolistaa voidaan sovelluksessa rajoittaa niin, että siihen on käyttäjän mahdollista lisätä vain yksi työaikatieto, jolloin vanha toiminnallisuus saadaan säilytettyä.

Työnantajan nimen -ominaisuus on nyt eroteltu lisäselvitysominaisuudesta, mikä sel- keyttää koodin lukemista. Tietojen pakollisuuteen on saatu selkeyttä muuttamalla omi- naisuudet keskenään pakollisiksi: kukin päivän sisältämän työaikatiedon rakenne vaatii sen, että työaikatiedolla on olemassa arvo työnantajan nimelle ja tehdyille työtunneille ja -minuuteille.

(26)

export interface IDay { date: Date;

status: DayStatus;

explanation?: string;

workTimes?: Array<IWorkTime>;

}

export interface IWorkTime { employerName: string;

// työaikakentät hours: number;

minutes: number;

}

Esimerkkikoodi 6. Päiväkohtainen oliorakenne muutosten jälkeen.

Muutokset helpottavat myös ohjelman kehitystä pitämällä rakennetta mahdollisimman johdonmukaisena. Työaikaominaisuuksien ollessa nyt pakollisia ei niitä tarvitse enää oh- jelmallisesti tarkastaa, sisältävätkö ne tyhjiä arvoja, jolloin niihin olisi varauduttava erik- seen. Ainoastaan työaikatietolista voi enää olla ilman arvoa.

Tietorakennemuutosten jälkeen haasteena on muuttaa komponenttirakennetta yhteen- sopivaksi uuden tietorakenteen kanssa. Kuvan 9 diagrammi kuvastaa nykyistä kompo- nenttirakennetta. Rakenne on toimiva vanhan rakenteen kanssa, ja logiikkaa on pilkottu useammalle komponentille. Diagrammin ehtosolmuista voidaan myös päätellä, että nä- kymässä voidaan syöttökomponentteja näyttää kolmessa eri muodossa. Komponentti- rakennetta on muutettava niin, että se olisi yhteensopiva uuden tietorakenteen kanssa.

(27)

Kuva 10. Nykyinen päivänäkymän komponenttirakenne. Kunkin kentän muokkaus tapahtuu use- ammassa komponentissa, jossa vihreällä on merkattu se esimerkkikoodin 5 ominai- suus, joka saa kyseisessä komponentissa syötetyn arvon.

Kuva 10 kuvastaa päiväkohtaista muutostenjälkeistä komponenttirakennetta. Päivän työaikatiedot näytetään listana päivänäkymässä, jolloin työaikatietoja voi nyt lisätä use- amman yhdelle päivälle. Aikaisemmin työnantajan nimi ja lisäselvitys syötettiin samaan syöttökenttään, mutta nyt diagrammissa esiteltynä työnantajan nimen syöttö on eroteltu selkeämmin lisäselvityskentästä omaan komponenttiin, jossa työnantajan nimi valitaan alavalikosta.

(28)

Kuva 11. Komponenttirakenteen diagrammi muutosten jälkeen.

Koska myös vanhan toiminnallisuuden on toimittava tarvittaessa riippuen asetuksen ar- vosta, on komponenttirakenne muutettava yhteensopivaksi kummankin toiminnallisuu- den kanssa. Sen seurauksena komponenttirakenne monimutkaistuu osittain, mutta se on välttämätöntä, jos kumpaakin toiminnallisuutta halutaan tukea. Komponenttiraken- netta on järkevintä muuttaa siten, että komponenttirakenne pysyy mahdollisimman yk- sinkertaisena. Käyttöliittymämuutokset koskevat työnantajatietoja, joten helpointa muu- tosten kannalta on tuoda takaisin osa vanhaa koodia liittyen työnantajatietojen syöttöön.

Myös asetuslogiikka on lisättävä hallitsemaan uuden ja vanhan rakenteen käyttöönottoa.

Kuvan 12 päivitetty komponenttirakenne tukee vanhaa sekä uutta toiminnallisuutta.

Komponenttirakennetta monimutkaisti se, että aikaisemmin lisäselvityksen syöttökenttää käytettiin myös työnantajan nimen syöttökenttänä. Tilanne tosin auttaa hahmottamaan työstetyn rakenteen laadun merkityksellisyyttä jatkokehityksen kannalta. Vanhassa toi- minnallisuudessa työnantajan nimen lisäselvitysominaisuuteen (esimerkkikoodi 5) aset- tamisen takia lisäselvityskomponentin näyttäminen ei nyt ole täysin yksiselitteistä. Jos

(29)

työnantajan nimellä olisi ollut oma ominaisuus ennen muutoksia, olisi muutostenjälkei- nen komponenttirakenne saatu sellaiseksi, jossa uutta ja vanhaa toiminnallisuutta hallit- taisiin vain yhdestä solmukohdasta, asetuksesta.

Kuva 12. Päivitetty komponenttimalli, joka mahdollistaa vanhan ja uuden toiminnallisuuden.

On hyvä huomioida, että joskus koodiin tarvitsee tehdä muutoksia, jotta sen toiminnalli- suus saadaan säilytettyä muutosten jälkeen. Muutokset tietorakenteeseen olivat välttä- mättömiä, jotta uuden toiminnallisuuden työstäminen oli mahdollista. Komponenttira- kenne ja komponentit oli tällöin työstettävä yhteensopivaksi uuden tietorakenteen kanssa. On siis välillä mahdollista, että vanhaa toiminnallisuutta menee rikki uutta luo- dessa, vaikka palvelun käyttäjän näkökulmasta mikään toiminnallisuus ei olisi muuttunut.

Sen takia muutosten myötä on myös tärkeää päivittää testit vastaamaan nykyistä tilan- netta varmistamaan, että myös vanha toiminnallisuus toimii yhä moitteettomasti. Käyttö- liittymän lopputulos näkyy kuvassa 13.

(30)

Kuva 13. Päivitetty päiväosion käyttöliittymä, joka tukee nyt useamman työajan valintaa. Kuvan oikealla näkyy myös käyttöliittymän mobiilinäkymä, sillä sivun responsiivisuus täytyi myös säilyttää.

4.4 Syöttökenttien validointiongelman korjaus

Käyttöliittymässä useamman työllisyyskentän mahdollistaminen yhdelle päivälle on se- koittanut kenttäarvojen validoimisen, mikä pitää korjata. Angular mahdollistaa kahden- laisten lomakkeiden käyttämistä tiedon validointia varten. Toinen niistä on ’template-dri- ven forms’, jota käytetään projektissa hakemuksen kunkin osion tietojen validoimiseen, jolloin myös päiväselvitysosiossa on käytetty kyseistä lomaketyyppiä [20]. Toinen loma- ketyyppi on ’reactive forms’, jossa validointilogiikka on pääsääntöisesti komponenttilogii- kassa TypeScript-koodina, kun taas template-driven lomakkeissa validointikoodi on pää- sääntöisesti template-koodin muodossa. Olennaista on tietää, että päiväselvitys-osioon liittyy ns. lomake, joka on joko validi tai epävalidi riippuen syöttökenttien arvojen oikeel- lisuudesta. Jos yksikin syöttökenttä sisältää väärää tietoa eli on epävalidi, koko lomake muuttuu epävalidiksi, mitä pystyy sitten hyödyntämään sovelluksessa. Hakemus on tehty sellaiseksi, että kunkin osion lomakkeen on oltava validi, jotta käyttäjä pystyy navigoi- maan seuraavaan osioon.

(31)

Angularin kenttäelementit toimivat niin, että kullakin syöttökentällä on oma Angularin alustama ns. form control [21]. Template-driven lomakkeissa form controllin alustus vaa- tii ngModel-attribuutin lisäämisen lisäksi yksilöivän nimen antamista name-attribuutin kautta (esimerkkikoodi 7) toimiakseen. ngModel-attribuuttia käytetään template-driven lomakkeissa muuttujan sitomiseen syöttökenttään, jotta kenttä tietää, minkä muuttujan arvoa se muokkaa. Form control on osa syöttökentän toiminnallisuutta, joka hallitsee ja seuraa kentän arvoa ja sen validisuutta. Form control muuttaa kuvan 14 kaltaisesti syöt- tökentän varoitusvärin mukaiseksi ja asettaa lomakkeen epävalidiksi kentän sisältäessä epävalidia tietoa, jolloin käyttäjän on korjattava tieto oikeanlaiseksi.

Template-driven lomakkeissa syöttökenttien validointisäännöt annetaan template-koo- din kautta (esimerkkikoodi 7). Validointisäännöt ovat esimerkiksi kentän arvon pakolli- suus, tekstin minimipituus tai numeron maksimiarvo. Kentälle syötetyn arvon on nouda- tettava jokaista kentälle määriteltyä validointisääntöä, jotta kenttä olisi validi. Validointi- säännöt ovat oiva tapa varmistaa syötettyjen arvojen oikeanlaisuus, mitä on myös hyö- dynnetty hakemuksen täyttämisessä.

Jokaisella kentällä on oltava yksilöivä nimi form controllille. Jos esimerkiksi kahdella ken- tällä on samannimiset form controllit, toimivat kentät niin, kuten ne jakaisivat saman form controllin. Tällöin riittäisi, että vain toiseen kentistä syöttää virheellistä tietoa, jolloin kum- matkin kentät menevät epävalidiksi. Esimerkkikoodissa 7 on luotu yksinkertainen teks- tinsyöttökenttä, jolle käännösaikana automaattisesti alustetaan oma form control.

<input ...

name="minutes"

minlength="2"

[(ngModel)]="myMinutes"

required>

Esimerkkikoodi 7. Eräässä template-koodissa on luotu tekstinsyöttökenttä, jonka form control saa nimeksi ”minutes” name-attribuutin kautta. Kenttä on sidottu myMinutes- muuttujaan ja kentälle on myös annettu 2 validointisääntöä: minimipituus sekä arvon pa- kollisuus.

(32)

Kuva 14. Syöttökenttä, joka sisältää esimerkkikoodin 7 validointisäännöt. Syöttökenttä on epäva- lidi ja varoitusvärin mukainen syötetyn arvon ollessa noudattamatta minimipituus-vali- dointisääntöä.

Päiväselvitys-osiossa on jokaiselle syöttökentän form controllille annettu komponentti- kohtainen nimi, jolloin ne erottuvat muiden komponenttien syöttökentistä. Koska päi- väselvitysosio sisältää useamman päivän, koostuu näkymä samoista toistuvista kom- ponenteista. Jotta syöttökentät eivät jaa samaa nimeä päivien välillä, on form controllit nimetty päivämäärien mukaan.

Päivä-komponentista annetaan parametrina päivämäärä sen lapsikomponenteille, kuten on esitelty esimerkkikoodissa 8. Esimerkiksi tuntisyötön form control voi päivämäärästä riippuen olla nimetty ”hours-20201231”, jolloin se on eri kuin muiden päivien vastaavien.

Näin varmistetaan, että jokaisella päiväosion syöttökentällä on oma yksilöivä nimi form controllille.

<div *ngFor="let workTime of day.workTimes;">

...

<working-time-input [value]="workTime"

[identifier]="formatDate(day.date)">

</working-time-input>

</div>

Esimerkkikoodi 8. Osa päivänäkymän template-koodia. Kullekin työaikasyöttö-kom- ponentille annetaan parametrina kyseinen päivä tekstimuotona formatDate-funktion kautta.

(33)

@Input() public identifier: string;

public hoursInputName: string;

public minutesInputName: string;

public ngOnInit() {

if (this.identifier) {

this.hoursInputName = 'hours-' + this.identifier;

this.minutesInputName = 'minutes-' + this.identifier;

} } ...

<input type="number" [name]="hoursInputName" required/>

<input type="number" [name]="minutesInputName" required/>

Esimerkkikoodi 9. Työaika-komponentin sisältöä, joka sisältää tunti- sekä minuutti- kentät alempana sen template-koodissa. Kenttien form controllit saavat esimerkkikoo- dissa 8 annettujen päivämäärien avulla yksilöidyt nimet.

Nyt muutosten jälkeen, kun päivänäkymä sisältää useamman työnantajatiedon, esiintyy näkymässä jälleen työnantajakohtaisia syöttökenttiä, joiden form controllit jakavat saman nimen, eli kentät jakavat saman form controllin (kuva 15). Päivänäkymä voi sisältää use- amman työaikakomponentin, joten ei riitä enää, että työnantajatietoihin liittyvät syöttö- kentät on eroteltu toisistaan ainoastaan päivämäärän perusteella.

Kuva 15. Ennen korjausta päivänäkymän kentät pystyivät jakamaan saman form controllin. Aino- astaan alempaan tuntisyöttökenttään on syötetty epävalidi arvo, mutta kummatkin ken- tät asettuivat epävalidiksi.

Ratkaisuna ongelmaan kuhunkin työnantajatietoon liittyvään kenttään lisätään listan in- deksi tunnisteeseen (esimerkkikoodi 10). Listan indeksi tarkoittaa sitä nollasta alkavaa lukua, joka kertoo, kuinka monentena työaikatieto on työaikatietolistassa. Tunniste sisäl- tää nyt siis kyseisen päivämäärän tekstimuodossa, listan indeksin sekä kentän nimen tunnisteen alussa. Esimerkiksi kolmannen työnantajan tuntisyöttökentän form controllin

(34)

nimi voi saada arvoksi ”hours-20201231-2”. Päiväselvityksen syöttökenttien form cont- rollien nimet ovat jälleen yksilöityjä, jolloin kenttien validointi toimii jälleen halutusti. Muu- tosten myötä testit on lisätty varmistamaan ohjelman toiminta ja estämään saman ongel- man syntymistä jatkokehityksessä. Testeillä testataan, että työaikatietokenttien muok- kaaminen ei vaikuta muihin kenttiin ja niiden validisuuteen riippumatta työnantajien luku- määrästä päivälle.

<div *ngFor="let workTime of day.workTimes; let i=index;">

<working-time-input [value]="workTime"

[identifier]="formatDate(day.date) + '-' + i">

</working-time-input>

</div>

Esimerkkikoodi 10. Työaika-komponenteille on annettavan tunnisteeseen lisätty listan indeksiarvo (i).

Kun on mahdollista lisätä useampi työaikatieto, on oltava myös mahdollisuus poistaa niitä tarvittaessa. Työaikatiedon poistaminen on käyttöliittymässä toteutettu niin, että kunkin työaikatiedon vieressä on nappi, jota painamalla poistetaan työaikatieto listalta.

Poistaminen listalta toimii oikein, mutta kenttien validointi alkaa taas käyttäytymään vir- heellisesti, kun lisätään työaikoja listalle sen jälkeen, kun on niitä listalta poistettu. Tar- kastellaan yhden päivänäkymän tuntisyöttökentän form controllien nimiä, kun päivänäky- mään on yhden perusarvon lisäksi lisätty kaksi uutta työaikatietoa.

hours-20001231-0 hours-20001231-1 hours-20001231-2

Poistetaan keskimmäinen työaikatieto listalta.

hours-20001231-0 hours-20001231-2

Lisätään uudestaan kolmas työaikatieto.

hours-20001231-0 hours-20001231-2 hours-20001231-2

(35)

Huomataan, että kolmas työaikatieto saa oikein listan indeksiarvoksi 2, koska on kol- mantena listassa. Aikaisemmin kolmantena listassa ollut työaikatietokenttien form cont- rollien nimi ei muutu, vaikka työaikatieto on nyt toisena listassa. Form controlleille jää virheellisesti sama nimi uuden kolmantena olevan kanssa. Valitettavasti Angularissa ei ole mahdollista, ainakaan helposti, muuttaa form controllin nimeä sen jälkeen, kun se on alustettu. On keksittävä vaihtoehtoinen ratkaisu asian korjaamiseen.

Esimerkkikoodissa 11 on esitelty yksinkertainen ratkaisu, johon päädyin. Päivänäkymää muutettiin niin, että poista-nappi on näkyvissä ainoastaan listan viimeiselle työaikatie- dolle. Mahdollistamalla ainoastaan viimeisen työaikatiedon poistamisen listalta, varmis- tetaan, että yllä kuvattu ongelmatilanne ei voi toistua, jolloin form controlleille jää aina yksilöivä nimi. Myös koodiin on lisätty ehto, joka varmistaa, että työaikatietoja ei voi pois- taa listalta, kun niitä on ainoastaan yksi olemassa, sillä kun tilaksi on valittu palkallinen, on hakijalla oltava vähintään yksi työaikatieto syötettynä. Lisätyt testit varmistavat, että käyttöliittymän validointi toimii oikein riippumatta siitä, missä järjestyksessä työaikatietoja lisätään tai poistetaan listalta.

<div *ngFor="let workTime of day.workTimes; let i=index; last as isLast">

<employer-select ... >

</employer-select>

<working-time-input ... >

</working-time-input>

<button

class="remove-work-time"

*ngIf="day.workTimes.length > 1 && isLast"

(click)="removeWorkTime(workTime, i);"

> ... </button>

</div>

Esimerkkikoodi 11. Päivänäkymän template-koodia. Työnantajan kohdalla näkyy poista-nappi ainoastaan, jos työnantajia on päivälle yli 1 ja kyseinen työnantaja on viimei- nen listassa. Ehdot on määritelty ngIf-attribuutissa.

Työaikatietojen poistamisen rajoittaminen listan viimeiseen työaikatietoon kerrallaan ei ole se tavoiteltava ratkaisu. Ottaen huomioon sen, että ongelma oli osittain Angularissa, jossa form controllin nimeä ei ollut mahdollista muuttaa ilman monimutkaista viritelmää, oli mielestäni ratkaisu tarpeeksi perusteltu. Ratkaisu ei myöskään aiheuta käyttäjälle suurta vaivaa käyttöliittymässä, sillä niissä harvoissa tilanteissa, joissa työaikalistan kes-

(36)

kelle on syötetty virheellinen työaikatieto, voi listan viimeisen työaikatiedon helposti pois- taa ja muuttaa virheelliset tiedot samoiksi poistetun työaikatiedon kanssa. Jos käy ilmi, että poista-nappi tullaan tarvitsemaan jokaiselle työaikatiedolle, voi tämänhetkistä ratkai- sua pitää väliaikaisena, jotta muutokset saadaan julkaistua määräajassa. Kenties myö- hemmin Angulariin on kehitetty helpompi tapa uudelleennimetä form controlleja.

4.5 Työnantajatiedon valinnan rajoittaminen

Virheiden poistamisen lisäksi käyttöliittymässä on otettava muitakin asioita huomioon.

Hakija ei voi saman päivän aikana olla tehnyt töitä kahdesti samalle työnantajalle, aina- kin vaatimusten mukaan, joten työnantajatietojen valintaa yhdelle päivälle on rajoitettava niin, että samaa työnantajaa ei voi olla mahdollista valita useamman kerran samalle päi- välle. Angular mahdollistaa disabled-attribuutin avulla vaihtoehdon ottamisen pois käy- töstä, jolloin se ei ole valittavissa (kuva 16). On siis saatava ei-valittaviksi ne alavalikon työnantajavaihtoehdot, jotka on jo valittu kyseiselle päivälle.

Kuva 16. Koodiesimerkki vaihtoehdon asettamisesta ei-valittavaksi disabled-attribuutin kautta.

Käyttöliittymässä kolmas vaihtoehto, jonka disabled-attribuutti on asetettu todeksi, ei ole valittavissa ja näkyy harmaana.

(37)

Päivän jokaiselle työnantajavalinta-komponentille on annettu oma työnantajan nimi -omi- naisuus (kuva 11: employer-select). Annetaan sille myös parametrina jo samalle päivälle valitut työnantajat, jolloin kukin valintakomponentti tietää, mitkä työnantajat on asetettava ei-valittavaksi valikkoon (esimerkkikoodi 12). Päiväkohtaisen jo valitut työnantajien nimet työstettiin päivittymään kullekin valintakomponentille aina, kun käyttäjä valitsee alavali- kosta uuden arvon tai poistaa työaikarivin. Muutosten jälkeen yhdelle päivälle ei voi enää lisätä kahta samaa työnantajaa (kuva 17), jolloin työantajan valinta vaikuttaa olevan vii- mein toimintavalmis. Jälleen testit on lisätty varmistamaan, että työnantaja-alavalikossa on vaihtoehdot oikein joko valittavissa tai ei, tilanteissa, jossa työnantajia lisätään, pois- tetaan tai valintaa muutetaan.

public isDisabled(employerSelection: IEmployer) {

// Palauttaa tosi, jos löytää jo valituista valinnoista (disabledEmp…) // valikkovaihtoehdon arvon (parametri), mutta jättää kuitenkin

// nykyisen valinnan valittavaksi uudelleen.

return this.disabledEmployerSelections.some((disabledSelection: IKey) =>

disabledSelection.employerName === employerSelection.employerName &&

disabledSelection.employerName !== this.currentSelection );

} ...

<mat-select (selectionChange)="_change()" ... >

<mat-option ngFor="let employerSelection of employerSelections"

[disabled]="isDisabled(employerSelection)"

[value]="employerSelection.employerName">

<span class="employer-selection"> ... </span>

</mat-option>

</mat-select>

Esimerkkikoodi 12. Template-koodissa jokaisessa alavalikon vaihtoehdossa (mat-op- tion) tarkistetaan, onko se valittavissa isDisabled-funktion kautta, jolle annetaan paramet- rina vaihtoehdon valinta-arvo. isDisabled-funktio palauttaa tosi, jos löytää vaihtoehdon arvon jo valituista valinnoista, ja vaihtoehto merkitään ei-valittavaksi. Valinnan jälkeen _change-funktion kautta välitetään valintatieto muille komponenteille.

(38)

Kuva 17. Alavalikossa on asetettu päivänäkymän jo valitut työnantajavaihtoehdot ei-valittaviksi.

4.6 Työaikarajoitteen korjaus

Ennen muutoksia oli työaikakirjaus rajoitettu niin, että tehty työaika työnantajalle ei saa- nut ylittää 24 tunnin rajaa (esimerkkikoodi 13). Tällöin myöskään päiväkohtainen työaika ei voinut ylittää kyseistä rajaa. Kun päivänäkymä sallii useamman työaikatiedon, ja 24 tunnin raja oli vain työnantajakohtainen, on nyt mahdollista syöttää työaika useammalle työaikatiedolle, joiden yhteenlaskettu summa ylittää 24 tunnin rajan. Hakijan tekemä yli 24 tunnin työaika vuorokaudessa kuulostaa epäuskottavalta, joten päiväkohtainen työ- aika rajoitetaan 24 tuntiin riippumatta työnantajien määrästä.

<input type="number" [name]="hours"

[minValue]="value.minutes > 0 ? 0 : 1"

[maxValue]="value.minutes > 0 ? 23 : 24"

...

/>

Esimerkkikoodi 13. Nykyinen tuntisyöttökenttä template-koodissa. Syötettävän tunti- määrään minimi- ja maksimiarvoja hallinnoidaan minValue- ja maxValue-attribuuttien (va- lidointisääntöjen) avulla. Rajoitteiden arvot riippuvat myös siitä, onko minuuttikenttään syötetty yli 0:n arvoa.

Ennen muutoksia 24 tunnin rajoite oli asetettu tunti- ja minuuttisyöttökenttiin. Kenttien ollessaan samassa työaikakomponentissa (kuva 11: working-time-input) on työaikakom-

(39)

ponentti tietoinen tunti- ja minuuttiarvoista. Tuntien ja minuuttien yhteenlasketun sum- man ylittäessä 24 tunnin rajan työaikakomponentti asettaa kummatkin kentät epävali- deiksi eikä hakemusta pysty jatkamaan. Useamman työaikatiedon tapauksessa työaika- arvot omissa komponenteissaan eivät ole tietoisia toisten työaika-arvoista. Työajan las- keminen pitää siis suorittaa kerrosta ylempänä, päiväkomponentissa, jonka päiväolio si- sältää kaikki työaikatiedot ja niiden työajat.

Työajan yli 24 tuntia ylittävässä tilanteessa komponentin tarvitsee asettaa ainakin yksi kenttä epävalidiksi, jotta hakemusta ei pääsisi jatkamaan virheellisillä arvoilla. Yhden työaikakentän asettaminen epävalidiksi voi olla epäselkeää käyttäjälle, ja kaikkien päi- vän työaikakenttien asettaminen epävalideiksi voi myös aiheuttaa epäselkeyttä käyttö- liittymässä sekä vaatii jo liikaa logiikkaa toimiakseen, varsinkin kun kyseessä on suhteel- lisen pieni toiminnallisuus.

Esimerkkikoodin 14 mukaisesti päiväkomponenttiin päädyttiin luomaan näkymätön kenttä, joka tarvittaessa asetetaan epävalidiksi, mikä estää hakemuksen jatkamisen. Se toimii siten, että se tarvittaessa lisätään käyttöliittymään, joka epävalidina muuttaa myös lomakkeen epävalidiksi. Kenttä on huomaamaton, jolloin se ei muuta käyttöliittymän nä- kymää mitenkään. Lomakkeen epävalidiksi asettamisen lisäksi näytetään käyttäjälle vir- heteksti, josta ilmenee epävalidisuuden syy. Kätevästi kyseistä kenttää tarvitaan myös tilanteessa, jossa käyttäjä on merkannut päivän tilaksi ’työssä’, mutta rekisteristä saatu- jen tietojen perusteella yhtäkään työnantajaa ei hakijalla ole, jolloin lomake on tarpeen näkymättömän kentän kautta asettaa epävalidiksi.

Viittaukset

LIITTYVÄT TIEDOSTOT

 Pitkään  palautteita   odottaneita  kasvatustieteilijöitä  oli  siis  paljon,  eikä  tilanne  varmaan  ole  kovin  toisen-­‐. lainen  media-­‐  ja

Viime vuosien uudet tutkimustulokset ovat kuitenkin osoitta- neet…” Usein tiedotteeseen ei edes rakenneta selvää ristiriitaa vanhan ja uuden tiedon välille, vaan uskotaan,

Ross korosti esitelmässään sitä, miten tällaiset isojen aineistojen tallennuspro- jektit eivät ole vain tallentamista vaan myös perustutkimusta.. Esimerkiksi mor- fologisten

Vuonna 1999 perustetun Korkeakoulututkimuksen seura ry:n tavoitteena on edistää korkeakouluihin kohdistuvaa laaja-alaista ja monitieteistä tutkimusta sekä parantaa alan

Älykännyköiden ja mobiilimedi- an aikakaudella lankapuhelin ja muut tuon ajan laitteet, koneet, ohjelmasovellukset sekä käyttöesineet edustavat mennyttä käyttökulttuuria,

Museon toiminnan tulee olla kohdistunut myös uuden tekniikan esittelyyn.. Suomen

Tuo tavallaan yksinkertainen ajatus – että ääniaallot ovat ilman värinää, joka värisyttää ja liikuttaa kehon sisuksia sysäten sitä kautta liikkeelle myös tunteet – on

Helka-yksikkö on saanut helmikuun aikana kaksi uutta työntekijää Ari Ahlqvistin ja Maarit Saareston tilalle.. Eevaliisa Colb aloitti