Category: Teknologia

AI-avusteinen ohjelmistokehitys

Näin käytämme tekoälyä ohjelmistokehityksessä – konkreettiset esimerkit asiakastyöstä

Tiedät ehkä jo, että tekoäly on tullut ohjelmistokehitykseen jäädäkseen, mutta mitä se konkreettisesti tarkoittaa? Entä mitä arvoa se voi tuoda juuri sinun projektiisi?

Sinun ei tarvitse olla uusia teknologioita tai työkaluja iltaisin testaava tekninen velho, jotta ymmärtäisit tämän julkaisun sisällön. Minäkään en ole markkinoinnin asiantuntijana erityisen teknisesti orientoitunut. Teknologian kehitys ja sen suunta koskettavat kuitenkin meitä molempia ainakin jollain tavalla. Siksi tein pienen sukelluksen teknisten konsulttiemme maailmaan ja kerron nyt pari konkreettista esimerkkiä siitä, millaista arvoa heidän AI-osaamisensa tuo parhaillaan asiakkaidemme projekteihin ja niiden tuloksiin. Olipa taustasi tekninen tai ei, teen sen niin, että sinäkin ymmärrät.

Tekoäly on osa arkea ohjelmistokehityksessä

Tekoälyn hyödyntäminen ohjelmistokehityksessä ei ole enää kokeiluasteella. Se on kiinteä osa arkea ja monien asiakkaidemme digikehityksessä jo vaatimus. Yritykset ottavat AI-työkaluja käyttöön hyvin eri tahtiin – osa on pitkällä, kun osa vasta tekee maltillista ja varovaista siirtymää. Asiakkaan ympäristö, toimiala, projektien luonne ja talon sisäinen osaaminen ovat myös vaikuttaneet siihen, kuinka nopeaa siirtymä on tähän asti ollut. Sanon heti, että et ole pudonnut kelkasta, mikäli tuotteenne tai palvelunne kehitys ei vielä pyöri AI:n säestämänä.

Konsulttimme ovat omaksuneet erilaiset kielimallit ja AI-agentit osaksi omaa työtään. Kerroimme aiemmassa julkaisussamme siitä, miten 100 % konsulteistamme hallitsee tekoälytyökalut. Niiden hyödyntäminen asiakastöissä kuitenkin vaihtelee. Joku koodaa täysin “AI-natiivisti”, eli tekoäly kirjoittaa kaikki koodirivit, kun taas konsultin tehtävä on ohjata ja validoida. Toiset ovat projekteissa, joissa asiakas on rajannut kaikki AI-työkalut pois käytöstä. Näissä tapauksissa konsulttimme ovat ottaneet erilaisia työkaluja käyttöön omissa testi- ja harrasteprojekteissaan.

AI ei korvaa osaamista – se nostaa rimaa

Tekoäly ei kuitenkaan yksin ole avain onneen. Todellisuudessa ohjelmistosuunnittelu ja ohjelmistokehitys kielimallien ja agenttien kanssa on haastavaa. Työkalujen käytön ymmärtäminen vaatii paljon syvällistä tietoa ja niihin liittyy monia sudenkuoppia, joista konsultin on oltava tietoinen. Kun konsultti ottaa tekoälytyökalut osaksi arkeaan ja oppii käyttämään niitä tehokkaasti, rima nousee korkealle. Kyky tuottaa toimivaa koodia nousee korkeammaksi, kuin aiemmin. Kuten sanottu, tämä vaatii ohjelmoinnin periaatteiden tuntemista sekä vahvaa asiantuntemusta ja kokemusta alalta.

Alla avaan konkreettisten asiakastyöstä poimittujen esimerkkien kautta, miten AI auttaa monissa toiminnoissa ja työtehtävissä, kuten koodin ymmärtämisessä, testien generoinnissa, uusien ominaisuuksien suunnittelussa.

1. Vieras koodi ei ole enää hidaste – tekoäly apuna koodipohjan lukemisessa

Asiakastilanne: Asiakas ylläpitää vanhaa ja uutta järjestelmää rinnakkain ennen täyttä siirtymistä uuteen järjestelmään. Nykyinen tiimi tuntee järjestelmien rakenteet hyvin, mutta uusi konsultti joutuu tutustumaan olemassa olevaan koodipohjaan. Konsultilta odotetaan nopeaa reagointia erilaisiin kysymyksiin ja kykyä ratkaista ongelmia nopeasti.

Miten AI auttaa:

  • Konsultti käyttää kielimalleja (kuten Claude Code tai GitHub Copilot) löytääkseen nopeasti, missä tietty logiikka tapahtuu koodissa.
  • Esimerkiksi AI:lle esitetty kysymys “missä vaiheessa asian x status muuttuu y:stä z:ksi?” tuo suoraan esiin olennaiset tiedostot ja funktiot.
  • AI ohjaa fokuksen oikeaan kohtaan ilman, että koko koodipohjaa tarvitsee ymmärtää kokonaisvaltaisesti.

🎯 Asiakasarvo:

  • Konsultti toimii tehokkaasti alusta alkaen ilman viivettä.
  • Pyyntöihin vastataan nopeammin ja luotettavammin ja asiakas saa nopeita, varmoja vastauksia.
  • Muutoksiin liittyvä riski pienenee, kun päätökset perustuvat loogiseen analyysiin, ei arvaukseen.

2. Testien automaatio ja laadunvarmistus AI-avusteisesti

Asiakastilanne: Asiakas siirtää dataa vanhasta järjestelmästä uuteen järjestelmään oman migraatiotyökalunsa avulla. Jotta siirrot voidaan hyväksyä, on pystyttävä todentamaan, että data on siirtynyt oikein. Manuaalinen testaus vie paljon aikaa.

Miten AI auttaa:

  • Konsultti voi rakentaa AI-avusteisen testauksen tilan, jossa esim. GitHub Copilotille kirjoitettu ohjedokumetti antaa sille ymmärryksen koko tuotteen tai palvelun rakenteesta. Testaustilassa Copilotille voidaan antaa haluttuja funktioita tai osioita koodipohjasta.
  • AI ehdottaa testejä vanhojen esimerkkien pohjalta huomioiden monet poikkeukset tai epätavalliset tekijät, jotka voisivat muuten jäädä huomaamatta.
  • Testit voidaan tuottaa systemaattisesti ja nopeasti — laadusta tinkimättä. Jos testejä on paljon, niiden kirjoittaminen voi nopeutua AI:n avulla tunneista minuutteihin.

🎯 Asiakasarvo:

  • Laadunvarmistus toimii jatkuvana prosessina, eikä ole pullonkaulana.
  • Kehityssykli nopeutuu. Konsultti tekee vähemmän virheitä ja pystyy tuomaan tuloksia nopeammin.
  • Testikattavuus paranee ilman ylimääräistä manuaalista työtä.

3. Uusien ominaisuuksien suunnittelu: AI auttaa fokusoimaan

Asiakastilanne: Tuotteeseen tai palveluun halutaan kehittää uusi ominaisuus, mutta speksit ovat vielä epäselviä. Asiakas ei halua pysäyttää kehitystyötä siksi aikaa, että määrittelyt ovat täysin valmiita. Konsultilta odotetaan asiantuntemusta niin suunnittelussa kuin toteutuksessa.

Miten AI auttaa:

  • AI toimii tällaisessa tilanteessa ideoinnin sparraajana. Se voi antaa näkemyksiä siitä, mitä pitää huomioida ja missä järjestyksessä eteneminen on järkevää.
  • Konsultti jakaa tehtävät loogisiksi kokonaisuuksiksi AI:n avulla.
  • Toteutus syntyy AI:n avulla nopeammin. Jos jokin osa tehdään manuaalisesti, sekin voidaan tehdä paremmalla fokuksella.

🎯 Asiakasarvo:

  • Kehitystyö ei pysähdy suunnittelun puutteeseen tai siihen, että määrittely on vielä tekemättä.
  • Iterointi nopeutuu ja muutosten tekeminen on hallitumpaa.
  • Konsultti toimii itsenäisesti mikä tarkoittaa, että asiakkaan ei tarvitse ohjata työtä yhtä paljon kuin aiemmin.

4. Tekoäly tuo tehokkuutta arkeen toistuvissa manuaalisissa tehtävissä

Asiakastilanne: Kehitystiimi työskentelee järjestelmien parissa, joissa toistuvat tietyt tekniset tehtävät: tiedonsiirto, testien kirjoittaminen ja refaktorointi. Kaikki nämä ovat tarpeellisia, mutta usein ne ova aikaavieviä ja rutiininomaisia tehtäviä.

Miten AI auttaa:

  • Konsultti voi antaa AI:lle tiedot olemassa olevasta toteutuksesta ja pyytää sen pohjalta listan tarvittavista testeistä.
  • Yksinkertaiset ns. one-shot -tyyliset tehtävät syntyvät hyvin nopeasti AI-työkalujen avustuksella.
  • Refaktorointiehdotukset ja parhaat käytännöt nousevat esiin AI:n ehdottamina ja konsultti voi täydentää niitä tarvittaessa.

🎯 Asiakasarvo:

  • Työ tehostuu ja aikaa vapautuu tärkeämpiin asioihin ja oikeiden ongelmien ratkaisemiseen.
  • Tekninen laatu pysyy tasaisena eri osissa järjestelmää.
  • AI muistaa ja monistaa hyväksi todetut ratkaisut, kun sille antaa rittävästi referenssikontekstia. Näin pyörää ei aina tarvitse keksiä uudelleen.

5. Uusien työkalujen nopeampi oppiminen

Asiakastilanne: Konsultti kohtaa asiakkaan projektissa uuden työkalun tai kirjaston, jota hän ei ole aiemmin käyttänyt. Hän saattaa kuitenkin tietää, mihin tarkoitukseen hän haluaa sitä hyödyntää ja miksi.

Miten AI auttaa:

  • Konsultti käy AI:n kanssa vuoropuhelua uuden teknologian oppimiseksi. Tämä mahdollistaa kokeilun, vertailun ja kysymisen.
  • AI voi tuottaa esimerkkikoodia suoraan määrittelyn ja halutun lopputuloksen pohjalta.

🎯 Asiakasarvo:

  • Uudet teknologiat saadaan käyttöön nopeasti ja turvallisesti.
  • Konsultti pysyy tehokkaana myös uusissa ympäristöissä.
  • Projektin eteneminen ei riipu yksittäisen työkalun opettelun aikataulusta.

Yhteenveto

Tekoäly ei tee työtä ohjelmistokehittäjän puolesta, mutta oikean asiantuntijan käsissä se lisää tuottavuutta, nopeutta ja varmuutta. Tekoäly siirtää ohjelmistokehittäjän fokuksen koodirivien kirjoittamisesta arkkitehtuuriin ja ongelmanratkaisuun. Tällaisessa muutoksessa on osattava entistä paremmin kokonaisuuden hallintaa sekä tekoälyn oikeanlaista ja tarkkaa ohjaamista.

AI-osaamisemme näkyy asiakkaidemme tuloksissa monilla eri tavoin, mutta mainitsemisen arvoista on erityisesti resurssien tehokkaampi hyödyntäminen. Enää asiakas ei välttämättä osta koodaria sanan perinteisessä mielessä. Asiakas ostaa asiantuntijan, joka osaa kommunikoida tekoälylle ja ohjata sitä oikealla tavalla.

Kun AI-työkalut ovat käytössä läpi kehitysprosessin:

  • Kokonaisuuden hallinta ja ongelmanratkaisu nousevat keskiöön koodirivien kirjoittamisen sijaan.
  • Konsultti pääsee nopeammin tuottavaan työhön, vaikka järjestelmä olisi uusi tai monimutkainen.
  • Kehityksen laatu paranee, kun AI auttaa havaitsemaan virheitä, tukee suunnittelua ja parantaa koodin ymmärrettävyyttä jo varhaisessa vaiheessa.
  • Asiakas saa enemmän arvoa vähemmällä ohjauksella ja pienemmällä kokonaisriskillä.

Haluatko pohtia, mitä AI voisi tarkoittaa juuri teidän ohjelmistokehityksessänne?
Keskustellaan siitä, missä tekoäly tuo aidosti arvoa ja missä ei.

Näin rakennamme Minimum Lovable Productin vuonna 2025 – tuotteen julkaisu

Minimum Lovable Productia (MLP) käsittelevän blogisarjan viimeisessä osassa sukellamme digitaalisen tuotteen elinkaarivaiheeseen. Nyt olemme siinä vaiheessa, että “vähimmäinen” on jo saavutettu ja tuote tulisi julkaista ja sitä pitää jatkokehittää ja/tai ylläpitää.

Kun MLP-tuote on valmis ja ehkä jo käytössä, on seuraava askel laajentaa sen ominaisuuksia kohti viimeistellympää kokonaisuutta. Tällöin keskitymme teknisen vakauden parantamiseen ja niiden lisäominaisuuksien toteuttamiseen, jotka jätimme alkuvaiheessa pois.

Tuotteesta riippuen tavoite voi olla joko varmistaa, että kertaluontoinen tuote on vakaa ja helposti ylläpidettävä sen koko elinkaaren ajan, tai kuten useimmissa tapauksissa – jatkaa kehitystä ja rakentaa entistä parempaa tuotetta rakastettavan perustan päälle.

Tuotteen julkaisu

Jos luit tämän blogisarjan aikaisemmat osat, niin tiedät, että alkuvaiheen kehitysprosessi on toteutettu tiiviissä yhteistyössä eri käyttäjäryhmien kanssa. Rakastettavan tuotteen myötä nämä alkuvaiheen käyttäjät voivat toimia ohjelmistosi parhaimpina lähettiläinä. Tämä voi näkyä esimerkiksi tuotteen laajempana käyttöönottona yritysympäristössä tai kuluttajasovelluksen varhaisina omaksujina.

Vaikka moni päätös tässä vaiheessa on tekninen, erityisesti skaalautuvuuteen kannattaa kiinnittää huomiota. Jos tuotteesi menestyy, joudut ratkaisemaan infrastruktuuriin liittyviä haasteita. “Konepellin alla” olevat ongelmat, kuten kuormantasauksen tarpeet ja lisääntyvät datamäärät, voivat hidastaa vasteaikoja ja heikentää käyttökokemusta, joka aiemmissa testiryhmissä teki tuotteestasi rakastettavan. Nämä ovat yleisiä ohjelmistokehityksen haasteita, mutta vältettävissä rakastettavuuteen panostamalla. Pienetkin käyttöliittymän häiriöt voivat vahingoittaa mainettasi tärkeiden alkuvaiheen käyttäjien silmissä. Huonot ensivaikutelmat ovat erityisen vaikeita korjata hyviksi jälkeenpäin, olipa kyse sanallisesta palautteesta tai käyttäjän suorasta kokemuksesta.

On myös mahdollista, että käyttäjätestaus joka johti rakastettavaan lopputulokseen, on sisältänyt jotain huomaamatonta, joka ei välttämättä heijastu todellisiin käyttäjäryhmiin. Silloin on tärkeää selvittää, edustaako testausvaiheen käyttäjäryhmä todellista käyttäjäkuntaa vai onko tarpeen miettiä uutta suuntaa. Mitkä ovat tuotteesi rakastettavat ja vähemmän rakastettavat ominaisuudet? Mitä kannattaa säilyttää ja mistä kannattaa luopua?

Rakastettavan tuotteen ylläpitäminen ja sen jatkokehittäminen

Rakastettavuus on kontekstisidonnainen ominaisuus. Kun ohjelmisto saavuttaa elinkaarensa ylläpitovaiheen, pitäisi olla selvää, mihin rakastettavuus oikeastaan perustuu. Se voi tarkoittaa esimerkiksi “konepellin alla” olevia teknisiä asioita, kuten nopeita vasteaikoja, jotka edellyttävät erityistä huomiota infrastruktuurin ylläpidossa ja skaalautuvuudessa.

Tekninen velka on hankala asia, joka voi hallitsemattomana kasvaa eksponentiaalisesti ja muodostua kehityksen esteeksi. Tämä voi johtaa siihen, ettei uusia päivityksiä ja ominaisuuksia pystytä toimittamaan halutussa aikataulussa. Tässä vaiheessa on tärkeää ymmärtää, mikä tekee tuotteestasi rakastettavan: missä tuotannon alkuvaiheessa otetut oikopolut alkavat kostautua merkittävästi? Esimerkiksi nopea ja huolimaton tietokantaratkaisu saattaa olla järkevää päivittää hajautettuun ja skaalautuvaan järjestelmään, jos se estää rakastettavan tuotteen kaatumisen siinä vaiheessa, kun ohjelmisto saavuttaa alkuperäistä laajemman käyttäjäkunnan. Toisaalta rakastettava tuote voi houkutella innokkaita käyttäjiä, jotka vaativat uusia ominaisuuksia – ja viivästykset taas saattavat turhauttaa heitä. Esimerkkejä tällaisista tilanteista löytyy usein peliteollisuudesta.

Usein kuitenkin käyttäjäkokemus (UX) käy läpi muutoksia jatkuvan kehityksen myötä. Jatkuvasti kehittyvän ohjelmiston kohdalla on houkutus lisätä yhä uusia ominaisuuksia eri käyttötarkoituksiin tai liittää ohjelmisto eri ulkoisiin palveluihin. Tällainen ylimääräinen kuorma voi kuitenkin heikentää käyttäjäkokemuksen rakastettavuutta, muuttaen yksinkertaisen ja selkeän käyttöliittymän sekavaksi ja raskaaksi kokonaisuudeksi. Toisaalta lisäominaisuudet voivat olla juuri sitä mitä käyttäjät haluavat tai tarvitsevat. Voimme kuitenkin integroida uusia elementtejä rakastettavuutta vaarantamatta. Tapauskohtaisesti tämä voi tarkoittaa esimerkiksi muokattavaa käyttöliittymää käyttäjän tarpeisiin tai harvemmin käytettyjen ominaisuuksien siirtämistä erillisiin näkymiin.

Vaikka houkutus lisätä uusia ominaisuuksia on suuri, on tärkeää miettiä, voimmeko toteuttaa ne rakastettavasti. Jos tuotteen pääominaisuudet on tehty huolella ja rakkaudella, kömpelö ominaisuus erottuu samalla tavalla kuin tahmea välilyöntinäppäin näppäimistössä. Toisaalta liiketoiminnallisia päätöksiä on pakko tehdä: ovatko ominaisuudet kömpelyyden arvoisia? Monissa tapauksissa vahva ydintuote ja sujuvat peruskäyttötapaukset tekevät tuotteesta käyttökelpoisen, vaikka mukana olisi joitakin harvoin käytettyjä mutta hieman vaivalloisia ominaisuuksia.

Tie eteenpäin

Usein MLP-tuotteet tähtäävät kasvuun. Kasvun saavuttamiseksi on monia keinoja, mutta jokaisella vaihtoehdolla on omat sudenkuoppansa ja vaatimuksensa. Sovelluksen rakastettavuuden säilyttäminen on itsessään liiketoimintapäätös, joka sisältää kustannuksia, mutta saattaa samalla auttaa säilyttämään kilpailuedun. Tapauksissa, joissa ohjelmistoa kehitetään ennalta määrättyyn käyttötarkoitukseen, kuten joukkoliikenteen lippu- ja reittipalvelu, päätös korostaa rakastettavuutta ja helppokäyttöisyyttä jatkuvassa kehityksessä vaikuttaa suoraan käyttäjien elämään. Tämä voi puolestaan toimia parhaana mahdollisena referenssinä työnne laadusta.

Lopuksi

Rakastettavien tuotteiden rakentaminen vaatii aikaa ja työtä. Monet kehittäjät saattavat väittää, että MLP:n tulisi olla jokaisen ohjelmistotuotteen lähtökohta, sillä miellyttävien asioiden rakentaminen on monille kehittäjille innostavampaa.

Totuus on kuitenkin se, että joskus nopeat ja ei niin viimeistellyt ratkaisut voivat olla tehokkain vaihtoehto esimerkiksi tilanteissa, joissa käyttäjät eivät välitä käyttöliittymän ulkoasusta, vaan haluavat vain saada työnsä tehdyksi. MLP ei ole ratkaisu jokaiseen ohjelmistoon, jonka aiotte rakentaa, mutta aina kun tavoitteena on voittaa käyttäjät puolelleen ja pitää heidät, ajattelutavan muuttaminen rakastettavan tuotteen rakentamiseen saattaa olla oikea valinta.

Toivomme, että olemme tarjonneet näkemyksiä tehokkaasta tuotekehityksestä rakastettavalla tavalla.

Kiinnostuitko? Kerromme mielellämme lisää miten me Identiolla voisimme auttaa teitä luomaan jotain rakastettavaa käyttäjillenne.


Osa 1: Näin rakennamme Minimum Lovable Productin vuonna 2025 – ymmärryksen saavuttaminen
Osa 2: Näin rakennamme Minimum Lovable Productin vuonna 2025 – sovelluksen kehittäminen
Osa 3: Näin rakennamme Minimum Lovable Productin vuonna 2025 – tuotteen julkaisu

A bright, abstract illustration with a large black-and-white gear, purple plant shapes, and swirling lines on a yellow background. The title reads "Minimum Lovable Products in 2025 – part 2.

Näin rakennamme Minimum Lovable Productin vuonna 2025 – sovelluksen kehittäminen

Kun koemme ymmärtävämme riittävästi sekä yhteistyökumppaneitamme, ratkaistavaa ongelmaa että tuotteen käyttäjiä, olemme valmiita aloittamaan verkkosovelluksen kehittämisen. Pidämme lähestymistavasta, jossa rakennamme ohjelmistotuotteita asiakkaillemme iteratiivisesti.

Aiemmin olemme määritelleet asiat, jotka ovat tärkeimpiä tuotteen menestyksen kannalta, sekä kaikkein haastavimmat teknologiset ongelmat, jotka meidän täytyy ratkaista päästäksemme tavoitteeseemme. Emme kuitenkaan käy näiden kimppuun suoraan, vaan aloitamme tutkimuksen samalla, kun laadimme asiakkaalle rautalankamallia.

Oikeiden teknologioiden valinta

Otamme aina huomioon asiakkaan nykyisin käyttämät ohjelmistopalvelut, erityisesti jos olemme integroimassa uutta ratkaisua olemassa oleviin palveluihin. Kun kehitämme verkkopohjaisia tuotteita, erityisesti täysin alusta lähtien, pidämme tällä hetkellä Next.js:ää parhaana lähtökohtana.

Olemme yleensä melko teknologianeutraaleja. “Valitse oikea teknologia oikeaan projektiin ja käyttötapaukseen” on ohjelmistosuunnittelussa yleinen mantra, jota mekin noudatamme mielellämme. Jopa täysin uuden tuotteen kehittämisessä on erikoistapauksia, joissa voi olla perusteltua valita jokin toinen vaihtoehto.

Next.js tarjoaa paljon valmiina sen laajan mallipohjakirjaston ansiosta, jota sen kehittäjä Vercel tukee. Kun rakennamme tuotteen alustavaa versiota, haluamme keskittyä toimittamaan kriittiset ominaisuudet, jotka tekevät tuotteestanne arvokkaan ja erittäin käyttökelpoisen jo julkaisuvaiheessa. Olemme työskennelleet Next.js:n kanssa useissa projekteissa saavuttaen erinomaisia tuloksia. Tämä mahdollistaa keskittymisen asiakkaiden ongelmien ratkaisemiseen sen sijaan, että käyttäisimme aikaa teknologian valintaan.

Muut tekniset valinnat

Useimmat merkittävät ohjelmistotuotteet vaativat tietokannan, jonka valitsemme liiketoimintavaatimustenne perusteella. Tavallisimmin suosittelemme SQL-tietokantaa, kuten PostgreSQL:ää sen monipuolisten ominaisuuksien ja erinomaisen toimintavarmuuden vuoksi. Vain harvoissa tapauksissa Postgres ei tarjoa tarvittavia ratkaisuja tuotteen alkuvaiheessa.

Vaihtoehdot Next.js:lle

Meillä on kokemusta myös SvelteKitin ja Remixin kanssa työskentelystä. Nämä tarjoavat yhtä houkuttelevia lähtökohtia hyvien mallipohjiensa ansiosta. Next.js:llä on kuitenkin yleensä laajempi valikoima valmiita mallipohjia, mikä antaa enemmän vaihtoehtoja.

Jotkut asiakkaat saattavat olla vahvasti mieltyneitä tiettyihin teknologioihin. On myös erityistapauksia, joissa muut teknologiat voivat tarjota paremman lähtökohdan kuten esimerkiksi paremman integraation nykyisiin ohjelmistojärjestelmiisi.

Rakastettavan sovelluksen kehittäminen

Rakastettava tuote on se lisäpanostus, joka erottaa tuotteesi kilpailijoista tai saa käyttäjät omaksumaan uuden tuotteen ilman valituksia. Siirtyminen MVP:sta (Minimum Viable Product) MLP:iin (Minimum Lovable Product) tarkoittaa käyttäjäpolkujen suunnittelua yksinkertaisiksi ja intuitiivisiksi. Ensimmäisen version tulisi olla yksinkertainen ja keskittynyt; lisäominaisuuksia voidaan lisätä myöhemmin.

Klassinen esimerkki MLP:sta ohjelmistomaailmassa on deittisovellus Tinder. Sen oikealle tai vasemmalle pyyhkäisyyn keskittyvä käyttöliittymä (UX) nähdään yleisesti ominaisuutena, joka nosti sen kilpailijoiden yläpuolelle ja josta on tullut jopa yleisesti käytetty tapa muissakin yhteyksissä “tykätä” tai “olla tykkäämättä”. Lisäominaisuudet, kuten Spotify- ja Instagram-yhteyksien lisääminen, olivat toki mukavia lisäyksiä, mutta eivät olleet sovelluksen alkuvaiheessa keskiössä. Tärkeintä on rakentaa toimiva ratkaisu käyttäjän tarpeeseen – ei vain teknisesti mahdollinen tapa toteuttaa se, vaan myös nautittava kokemus.

Voimme palata aiempaan selitykseemme Minimum Lovable Productista korostaaksemme tätä näkökulmaa.

Minimum Viable Product

  • Alustava Proof of Concept -tasoinen runko.
  • Yksinkertaiset ominaisuudet vaatimusten tyydyttämiseksi.
  • Antaa käyttäjille mahdollisuuden testata ideaa, mutta ei tavallisesti ole tarpeeksi vetovoimainen.

Minimum Lovable Product

  • Kaikki edellä mainitut.
  • Käyttäjäkokemuksen kehittäminen ensisijaisten työnkulkujen osalta.
  • Herättää käyttäjissä myönteisiä tunteita.

Miltä kehitysprosessi näyttää

Kun kehitys alkaa, tavoitteemme on pitää selkeä ja jatkuva keskusteluyhteys asiakkaan kanssa koko prosessin ajan. Tiimi sopii asiakkaan kanssa viikottaisista tai kahden viikon välein pidettävistä kokouksista, joiden aikana priorisoidaan kehitystyötä ja saadaan säännöllistä palautetta varmistaaksemme, että suunta on oikea.

Haluamme korostaa, kuinka tärkeää on saada asiakas mahdollisimman nopeasti käyttökelpoisen version äärelle. Tämä mahdollistaa käyttäjätestauksen aloittamisen projektin varhaisessa vaiheessa. Kun asiakkaalla ja käyttäjillä on konkreettinen tuote esikatseltavana, on todennäköisempää, että keskitymme oikeisiin ominaisuuksiin tässä tuotteen kehityksen kriittisessä alkuvaiheessa.

sovelluksen kehityssykli

Kun rakennamme jotain käyttäjäkeskeisestä näkökulmasta, kuten aiemmin kuvailimme, palautteen merkitys korostuu entisestään. Vaikka käytämme tavanomaisia työkaluja, kuten Kanban-tauluja ja ketteriä menetelmiä, emme yleensä työskentele sprinttimuodossa, jotta voimme säilyttää mahdollisimman suuren joustavuuden.

Tämä ei tarkoita, että vältämme kokonaan backlogeja ja estimointeja, mutta nopeatahtinen iterointi hyötyy usein lyhyemmästä palautesyklistä asiakkaan ja käyttäjien kanssa.

Suunnan muuttaminen

Kehitysprosessin aikana saattaa joskus käydä ilmi, että jotkut asiat eivät ole toteutettavissa nykyisessä toimituslaajuudessa. Näissä tilanteissa on tärkeää tuoda esiin ongelmat varhain, jotta voimme tehdä tarvittavat muutokset tavalla, joka säilyttää tuotteen hengen ja mahdollistaa asiakkaan tavoitteiden saavuttamisen. Loppujen lopuksi rakennamme rakastettavia tuotteita, joten on yleensä hyödyllisempää lykätä ominaisuutta, jota ei voida toimittaa rakastettavassa muodossa, kuin heikentää tuotteen kokonaislaatua toteuttamalla keskeneräinen ja ei-kriittinen ominaisuus. Vaihtoehtoisesti voimme toteuttaa rakastettavan mutta väliaikaisen ratkaisun, edellyttäen että se voidaan myöhemmin korvata teknisesti kestävämmällä ratkaisulla ilman, että tuotteen rakastettavat ominaisuudet kärsivät.

Yhteenveto

Tässä toisessa osassa olemme käsitelleet tarkemmin teknologiavalintojamme ja konkreettista kehityssykliä, jonka avulla hyödynnämme tehokkaasti aikaa tuotteen toimittamisessa.

Mielestämme kaikki kiteytyy muutamaan asiaan:

  • Avoimen viestintäkanavan ylläpitäminen kehitysvaiheen aikana.
  • Oikeiden teknologioiden valitseminen oikeaan tehtävään.
  • Konkreettisen tuotteen iterointi ja muutoksiin suhtautuminen avoimin mielin.
  • Käyttäjien mukaan ottaminen jo varhaisessa vaiheessa.

Kolmannessa osassa tarkastelemme, mitä tapahtuu ja miten asiat voivat muuttua, kun MLP on julkaistu ja käytössä oikeassa maailmassa.


Osa 1: Näin rakennamme Minimum Lovable Productin vuonna 2025 – ymmärryksen saavuttaminen
Osa 2: Näin rakennamme Minimum Lovable Productin vuonna 2025 – sovelluksen kehittäminen
Osa 3: Näin rakennamme Minimum Lovable Productin vuonna 2025 – tuotteen julkaisu

How we build minimum lovable products in 2025 – Gaining Understanding

Näin rakennamme Minimum Lovable Productin vuonna 2025 – ymmärryksen saavuttaminen

Varoitus. Tämä kolmiosainen artikkeli on melko kantaaottava, ja saatat olla eri mieltä joistakin valinnoistamme ja lähestymistavoistamme. Se ei kuitenkaan haittaa! Olemme havainneet asiakkaidemme kanssa työskennellessämme, että tietyt teknologiset ja toiminnalliset valinnat tekevät asioista sujuvampia. Voit vapaasti olla niistä eri mieltä ja kertoa meille, mitä tiimisi tekee toisin.

Me Identiolla työskentelemme erilaisten yksityisen ja julkisen sektorin asiakkaiden kanssa, jotka ovat elinkaarensa eri vaiheissa. Mielestämme tässä kuvattu lähestymistapa on suhteellisen helposti sovitettavissa eri asiakkaille, mutta se toimii parhaiten alkuvaiheen startup-yrityksille tai yrityksille, joilla on pieni määrä olemassa olevia ohjelmistopalveluja, jotka halutaan integroida uuteen tuotteeseen. Tässä sarjassa tarkastellaan käsitteenä ja kehitysprosessina MLP-tuotetta (Minimum Lovable Product), jonka tavoitteena on tuottaa teknisesti toimivan ohjelmiston lisäksi myös sellainen ohjelmisto, jota käyttäjät käyttävät mielellään.

Olemme jakaneet tämän artikkelin kolmeen osaan, jotka julkaisemme noin viikon välein ja joissa käsittelemme alustavaa tiedonkeruuvaihetta, Minimum Lovable Productin toimittamista ja seuraavia vaiheita, jotka toteutetaan, kun tuotteen ensimmäinen versio on käyttäjien käsissä.

Minimum Lovable Product

Lyhyen johdannon tarjoamiseksi asiaan perehtymättömille, MLP on tuote, joka on kehitetty ja suunniteltu niin, että käyttäjät ottavat sen innokkaasti käyttöön. Helpoin tapa määritellä Minimum Lovable Product käsitteenä, on vertailla sitä ja monille tutumpaa Minimum Viable Productia.

Minimum Viable Product

  • Alustava Proof of Concept -tasoinen runko.
  • Yksinkertaiset ominaisuudet vaatimusten tyydyttämiseksi.
  • Antaa käyttäjille mahdollisuuden testata ideaa, mutta ei tavallisesti ole tarpeeksi vetovoimainen.

Minimum Lovable Product

  • Kaikki edellä mainitut.
  • Käyttäjäkokemuksen kehittäminen ensisijaisten työnkulkujen osalta.
  • Herättää käyttäjissä myönteisiä tunteita.

Määritelmän mukaan MVP:llä saadaan työ tehtyä, mutta usein ohjelmistotuotteet eivät saa käyttäjiä, tai käyttäjät käyttävät työkaluja vastahakoisesti vaihtoehtojen sijaan. Kun käyttäjäkokemus vaikuttaa käyttäjiin suuresti tai kun tavoitteena on saavuttaa laaja käyttäjäkunta, kannattaa nähdä ylimääräistä vaivaa, jotta tuotteen elinkelpoisuus muuttuu rakastettavuudeksi.

Ennen kuin aloitamme

Tuotekehityksen alussa on yleensä muutaman viikon jakso, jolloin tutkimme asioita ja keskustelemme yksityiskohdista, kuten sopimuksista. Aloitamme oppimisprosessin jo osana myyntiprosessia, mutta tutustumme asiakkaaseen kunnolla yhteistyön alkaessa – kick-offin tai design sprintin yhteydessä.

Asiakkaan ymmärtäminen

Haluamme tuntea asiakkaamme ja heidän liiketoimintansa hyvin. Tutustumme tiimiin tai tiimeihin, joiden kanssa työskentelemme, alaan, jolla he työskentelevät sekä heidän päivittäiseen liiketoimintaansa. Alkuvaiheen startup-yrityksissä tämä tarkoittaa yleensä sitä, että tapaamme tiimin ja opimme tuntemaan heidät ja heidän asiantuntemuksensa.

Tuotteen ensimmäisen version rakentaminen on usein pohjimmiltaan selkeää viestintää ja ongelman, jota haluamme ratkaista, ymmärtämistä. Mielestämme on tärkeää ottaa asiakas mukaan kehitysprosessiin jo varhaisessa vaiheessa. Läpinäkyvä tiedonvaihto tekee asioista helpompia myöhemmässä vaiheessa.

Tuotteen vision ymmärtäminen

Kun olemme saaneet selkeämmän käsityksen asiakkaasta, on aika syventyä paremmin ongelmaan. Yleensä se tapahtuu asiakkaan tarjoaman kuvauksen ja tietojen perusteella. Tiimimme ovat parhaimmillaan työskennellessään liiketoimintaongelmien ja teknisten ratkaisujen kehittämisen risteyskohdassa. Pyrimme ymmärtämään parhaamme mukaan seuraavat asiat:

  • Miksi asiakas on kiinnostunut rakentamaan tämän tuotteen ongelman ratkaisemiseksi?
  • Miksi asiakas on nimenomaan kiinnostunut ongelman ratkaisemisesta?
  • Miksi hän haluaa ratkaista ongelman juuri nyt?

Kun saamme vastaukset näihin kysymyksiin, voimme rajata tuotteen ensimmäisen iteraation laajuutta. Ensimmäinen versio tarjoaa yleensä vain osan lopullisen tuotteen toiminnallisuuksista, jotta voimme toimittaa jotain käyttökelpoista, testattavaa ja käyttäjille mieluisaa.

Käyttäjien ymmärtäminen

Vain harvoin asiakas on tuotteen suora käyttäjä, jolloin pelkkä asiakkaan ymmärtäminen riittäisi. Vaikka asiakkaalta saattaisikin saada hyvin selkeän käsityksen käyttäjistä, kannattaa eri käyttäjäryhmien ymmärtämiseen silti käyttää aikaa. Tämä saattaa tarkoittaa esimerkkikäyttäjäpersoonien luomista sekä heidän tarpeidensa ja käyttötapaustensa määrittelyä. Todellisten potentiaalisten käyttäjien ottaminen mukaan alustavaan käyttötapausten määrittelyyn on erittäin hyödyllistä. Käyttäjäkeskeinen lähestymistapa edellyttää jatkuvaa vuoropuhelua aiottujen käyttäjien kanssa, jotta voimme keskittyä ratkaisua vaativaan ongelmaan ja välttää suunnittelemasta ratkaisua, joka ei ratkaisekaan keskeistä ongelmaa.

Kun pureudutaan perustavanlaatuisimpaan asiaan, saattaa myös paljastua, että eri käyttäjäsegmenttien tarpeet ja käyttötapaukset eroavat toisistaan. Niiden ymmärtäminen auttaa myös päättämään, pitäisikö keskittyä yhteen segmenttiin vai voidaanko eri käyttötapaukset ottaa huomioon vaarantamatta käyttäjäkokemusta ja siten tuotteen rakastettavuutta.

Resurssien keskittäminen oikeisiin asioihin

Nyt kun meillä on parempi käsitys ongelmista, joita haluamme ratkaista, voimme keskittyä oikeisiin asioihin:

  • Mitkä ominaisuudet ovat käyttäjälle ensisijaisia
  • Mitkä asiat on testattava ensin

Käyttäjäkeskeisten prioriteettien avulla voit keskittyä siihen, miten nämä ominaisuudet toteutetaan. Mitä tarvitaan, jotta käyttötapaus tai käyttäjävirta olisi sujuva ja intuitiivinen? Minkä on toimittava, jotta käyttäjävirta toimii tarkoitetulla tavalla? Mikä edellyttää käyttöliittymäelementtejä ja vuorovaikutusta ja mitä voi tapahtua konepellin alla? Näihin kysymyksiin vastaaminen johtaa yleensä monimutkaisempien teknisten ongelmien kartoittamiseen, jotka saattavat vaatia ratkaisua, ja antaa sinulle kehyksen, jonka varaan voit rakentaa mahdollisen tulevan kehityksen.

Yhteenveto

MLP:n toimittamisen alkuvaiheessa tehdään paljon työtä, jonka avulla saamme paremman käsityksen siitä, mitä asiakas haluaa rakentaa ja miksi. Tämä prosessi jatkuu koko kehitystyön ajan, ja työskentelemme usein iteraatioissa, jotka perustuvat parhaaseen ajan myötä kasvavaan ymmärrykseemme.

Tässä on lyhyt luettelo asioista, joita tarkastelemme tuotetoimituksen alussa:

  • Asiakkaan ymmärtäminen: ymmärrämme asiakkaan taustan, hänen aiemmat pyrkimyksensä ja sen, miksi hän keskittyy ratkaisemaan ongelman ohjelmistotuotteella.
  • Ongelman ymmärtäminen: ketä ongelma koskee, miksi se on korjattava ja mitä aiempaa työtä on tehty ongelman ratkaisemiseksi.
  • Käyttäjien ymmärtäminen: miksi käyttäjät ovat huolissaan tästä ongelmasta, millaisia käyttäjäryhmiä ongelma koskee ja miten tuote sopii heidän nykyisiin työnkulkuihinsa.
  • Prioriteettien ymmärtäminen: sen selvittäminen, mitkä tuotteen ominaisuudet ovat ratkaisevan tärkeitä ongelman ratkaisemiseksi, sen ymmärtäminen, mitkä ratkaisut ovat käyttäjille tärkeimpiä, ja niiden haasteiden löytäminen, joista meidän on huolehdittava alusta alkaen.

Seuraavaksi: tuotteen rakentaminen

Seuraavassa osassa menemme hieman syvemmälle Work in Progress -vaiheeseen, jossa alamme rakentaa ratkaisua ongelmaan: tuotetta. Kerromme, mitkä teknologiat toimivat mielestämme hyvin tämäntyyppisissä tuotetoimituksissa, ja annamme kuvan siitä, miltä kehitysprosessi näyttää.


Osa 1: Näin rakennamme Minimum Lovable Productin vuonna 2025 – ymmärryksen saavuttaminen
Osa 2: Näin rakennamme Minimum Lovable Productin vuonna 2025 – sovelluksen kehittäminen
Osa 3: Näin rakennamme Minimum Lovable Productin vuonna 2025 – tuotteen julkaisu

Systeemiajattelu ohjelmistokehityksessä – Systems thinking in software development

Systeemiajattelu ohjelmistokehityksessä – näin hallitset monimutkaisia järjestelmiä

Elämme järjestelmien aikakautta, jossa systeemien monimutkaisuus kasvaa ja ongelmat muuttuvat yhä enemmän ja enemmän koko järjestelmään vaikuttaviksi. Monimutkaisten ongelmien ratkaisemiseksi tarvitsemme enemmän kuin pelkästään suoraviivaisen ajattelun työkaluja. Tarvitsemme kykyä ajatella laajemmin, ymmärtää asioiden välisiä suhteita ja nähdä tuo kuuluisa suurempi kuva. Suoraviivainen ajattelu on hyvä lähtökohta, mutta se ei aina riitä. Systeemiajattelu tuo mukanaan uudenlaisen tavan tarkastella ongelmia ja ratkaisuja.

Systeemiajattelu ei ole vain taito, jonka opit – se on käytäntöjä ja näkökulmia. Mielestäni sitä voidaan kutsua jopa elämäntavaksi. Sitä ei voi täysin ymmärtää pelkästään lukemalla, aivan kuten et voi oppia pelaamaan golfia vain lukemalla siitä. Se täytyy kokea ja sitä täytyy harjoitella. Systeemiajattelu vaatii meitä ymmärtämään.

Lineaarinen ajattelu

Monet meistä ajattelevat lineaarisesti, ilman että sitä edes tiedostaa. Tämä ajattelutapa on niin syvään juurtunut, ettemme edes tunnista sitä yhdeksi monista lähestymistavoista. Lineaarinen ajattelu on ennustettavaa ja johonkin tiettyyn, usein opittuun, menettelytapaan perustuvaa. Kuulostaa hyvältä, varsinkin ohjelmistokehityksen kaltaisella alalla, missä pyritään usein lineaarisesti rakentamaan modulaarisia ja mahdollisimman tehokkaita palasia osaksi järjestelmää.

Lineaarinen ajattelutapa onkin varsin hyvä ja tehokas tapa ajatella monessa tilanteessa. Se tarjoaa selkeyttä ja hallittavuutta, mikä varsinkin ohjelmistosuunnittelijoille on työssä tärkeää. Kun lähdemme pohtimaan monimutkaisempia järjestelmiä ja relaatioita järjestelmien osien välillä, olisi ajattelutapaa kuitenkin syytä laajentaa.

Muutos kohti systeemiajattelua

Monimutkaisten järjestelmien suunnittelu on haastavaa ja esiin tulevat ongelmat muuttuvat yhä enemmän koko järjestelmään vaikuttaviksi ja monihaaraisiksi, jolloin lineaarinen ajattelu ei takaa parasta mahdollista lopputulosta. Systeemitason ongelmien ratkaisemiseksi tarvitaan uusia näkökulmia ja työkaluja.

Ajatellaan hyvin yksinkertaistettua esimerkkiä. Jos istutetaan seitsemän kasvin siementä, odotetaan että x päivän kuluttua voidaan korjata satona seitsemän täysikasvuista kasvia. Jos peura syö yhden kasveista, laitetaan aita estämään peuroja tekemästä tuhojaan ja korjataan loppu sato. Tällä tavalla lähestymme usein myös ohjelmistoprojektien suunnittelua.

Todellisuudessa asiat eivät kuitenkaan ole näin yksinkertaisia. Joskus saadaan yhdeksän kasvia, koska kasvit saattoivat jatkaa kasvuaan seuraavanakin vuonna. Toisinaan ei saada yhtään satoa. Syynä voi olla esimerkiksi jänikset, peurat, sade, sen puute tai vaikka liiallinen kylmyys. Lopputulos on käytännössä aina monen tekijän yhdistelmä, jotka vaikuttavat toisiinsa ennalta arvaamattomilla tavoilla.

Koska systeemit harvoin ovat täysin hallittavissa ja niiden käyttäytyminen on monesti ennakoimatonta, emme voi lähestyä monimutkaisempia kokonaisuuksia ainoastaan lineaarisesti ajatellen.

Systeemiajattelu vaatii työtä – mutta se on sen arvoista

Valitettavasti epälineaariset lähestymistavat ovat lähes aina vaikeampia kuin lineaariset. Systeemiajattelu ei tee elämästäsi helpompaa, mutta se tekee sinusta tehokkaamman. Systeemiajattelu lisää kykyäsi kohdata vaikeita haasteita, parantaa päätöksenteon laatua ja auttaa tunnistamaan, mitkä asiat ovat todellisia ongelmia ja mitkä vain oireita jostain muusta. Systeemiajattelun avulla voidaan löytää ja paneutua varsinaiseen signaaliin kaiken kohinan keskellä.

Systeemiajattelussa kyse on kuitenkin enemmän kuin vain ongelman ratkaisemisesta. Pohjimmiltaan kyse on ymmärryksestä – siitä, että ymmärretään koko konteksti, jossa ongelma esiintyy. Tämä vaatii jatkuvaa oppimista, ennen kaikkea sen tiedostamista, kuinka paljon et vielä tiedä. Systeemiajattelijan arvokkaimpia ominaisuuksia onkin, että tiedostaa sen, että ei tiedä kaikkea.

Miten tunnistaa systeemiajattelijan?

Hyvä systeemiajattelija tunnistaa lineaarisen ajattelun hyvät ja huonot puolet ja osaa valita, milloin käyttää lineaarista lähestymistapaa ja milloin asioita pitäisi katsoa koko systeemin perspektiivistä.

Systeemiajattelussa tulee tiedostaa, että tekniset ja sosiaaliset järjestelmät ovat lähes aina toisiinsa kietoutuneita. Pitää ymmärtää konteksti missä toimitaan ja miten tekniset ratkaisut sekä toiminnassa mukana olevat ihmiset vaikuttavat toisiinsa ja pyrkivät näkemään tilanteen useasta eri näkökulmasta.

Tärkeimpänä piirteenä systeemiajattelussa on se, että oppii ja mukautuu jatkuvasti. Hyvä systeemiajattelija on myös itseään reflektoiva ja tietoinen omista ajatusmalleistaan, reaktioistaan ja mahdollisista virhepäätelmistä. Systeemiajattelussa pyritään lisäämään tietoisuutta omasta ajattelusta ja auttaamaan tiimejä ja organisaatioita ymmärtämään, miten yhteiset prosessit, mallit ja päätökset vaikuttavat järjestelmään kokonaisuutena.

Muutamia systeemiajattelijan tunnusmerkkejä:

  • Ajattelee ajattelemista.
  • Ymmärtää ja tunnistaa lineaarisen ja epälineaarisen ajattelun ominaisuudet ja erottaa mikä on milloinkin paras lähestymistapa.
  • Osaa suunnitella ratkaisuja, missä on huomioitu konteksti ja koko systeemin tarpeet.
  • Ymmärtää että ihmiset ovat osa teknisiä systeemejä.
  • Pystyy luontevasti vaihtamaan näkökulmaa ratkaisuja etsiessään.
  • Pyrkii aina kehittämään omaa osaamistaan.
  • Pystyy ymmärtämään ja löytämään juurisyyt systeemitason ongelmiin ja ratkaisuihin.
  • Pystyy kommunikoimaan ja ennen kaikkea perustelemaan ideat ja muutosehdotukset.
  • Pystyy ymmärtämään miten toisistaan riippuvaiset ja toisiinsa liittyvät osat luovat kokonaisuuksia ja miten näitä riippuvuuksia voidaan hyödyntää parhaiten.
  • Pystyy luomaan perusteltuja malleja ja konsepteja päätöksenteon tueksi.
  • Ja ennen kaikkea hyväksyy, että epävarmuus on tervetullutta ja luonnollista sekä vääjäämätön osa elämää.

Ohjelmistokehittäjät osana systeemiä

Ohjelmistot eivät ole pelkästään teknisiä, vaan ne ovat itseasiassa sosio-teknisiä systeemejä. Lyhykäisyydessään tarkoittaen tapa, jolla ajattelemme, viestimme ja työskentelemme, on hyvin paljon sidoksissa siihen, miten ohjelmistot kehittyvät. Kun osat toimivat hyvin yhdessä, niin tekniset kuin sosiaalisetkin, on systeemi usein enemmän kuin vain osiensa summa.

Jos haluamme parantaa ohjelmistojärjestelmää, meidän on ensin tunnistettava, miten ohjelmiston parissa työskentelevä tiimi ajattelee siitä ja tarvittaessa pyrittävä muuttamaan tätä ajattelutapaa. Systeemin eheys, eli kuinka hyvin järjestelmän osat (niin tekniset kuin ei teknisetkin) toimivat yhdessä on erittäin tärkeää. Kun ideat ja konseptit ovat koko systeemin tasolla linjassa keskenään, järjestelmät palvelevat paremmin tarkoitustaan. Pienet muutokset ajattelutavassa voivat kantaa suuriin muutoksiin ohjelmistojärjestelmässä.

Kun tämä eheys puuttuu, näemme ongelmia, kuten tietojen siiloutumista, tiimien välisen työskentelyn tehottomuutta, purkkaratkaisuja, ohjelmistojen yhteensopimattomuutta ja teknistä velkaa, mitkä vaikeuttavat järjestelmän kehittämistä ja ylläpitoa.

Relaatiot ovat systeemisuunnittelua

Systeemiajattelussa keskeistä on relaatioiden ymmärtäminen. Ohjelmistosta tulee systeemi vasta, kun sen osat ovat keskinäisessä vuorovaikutuksessa. Kolme erillistä mikropalvelua pilvessä eivät ole vielä systeemi, vaan nämä ohjelmistokomponentit muuttuvat systeemiksi vasta siinä vaiheessa, kun niiden välillä on riippuvuuksia ja relaatioita.

Samoin kehitystiimi voidaan laskea systeemiksi siinä vaiheessa, kun tiimin jäsenet työskentelevät yhdessä ja heidän välillään on suhteita, jotka tukevat yhteistä tavoitetta.

Lineaariset lähestymistavat, joissa strategia tulee ylhäältä ja tiimit vain toteuttavat sen, eivät riitä monimutkaisessa, systeemisessä maailmassa. Organisaatioiden tulee ymmärtää, että muutokset vaikuttavat eri tavalla eri osiin järjestelmää ja että muutoksen onnistuminen riippuu kyvystämme suunnitella ja rakentaa toimivia suhteita systeemin sisällä.

Strategiset muutokset kuten digitaalinen transformaatio, modernisaatio tai vaikka muutos ohjelmistomonoliitistä mikropalveluarkkitehtuuriin ei voi olla vain ylhäältä alaspäin johdettu prosessi, koska muutos itsessään ei ole lineaarinen. Jos tällaista muutosta lähdetään viemään eteenpäin vain lineaarisesti ajatellen, tulee tie olemaan pitkä ja kivinen ja lopputuloksena tuskin saadaan aikaan mitään kovin pysyvää. Toki prosessi saadaan vietyä läpi, mutta todennäköisesti systeemi ei muutosten jälkeen ole kovin toimiva.

Yhteenvetona voidaan sanoa, että systeemiajattelu ei ole helppoa, mutta se on välttämätöntä, jos halutaan onnistua monimutkaisissa, epälineaarisissa ympäristöissä. Kun opitaan ajattelemaan tilannetta koko systeemin näkökulmasta konteksti ymmärtäen, voidaan luoda kestäviä ratkaisuja, jotka palvelevat parhaiten sekä teknisiä että sosiaalisia tavoitteita.

Lue lisää konsultointiin liittyvää sisältöä englanniksi.

React Native vs Flutter cover

React Native vs Flutter – usein kysytyt kysymykset

Sotkuinen tai epäselvä käyttöliittymä? Ei kiitos. Löydät etsimäsi tiedon, mutta sen etsimiseen meni kolme kertaa odotettua aikaa kauemmin? Ei kiitos. Tämän päivän mobiilisovellusten odotetaan olevan helppokäyttöisiä, nopeita ja luotettavia – ja tarjoavan sitä mitä lupaavat. Jos sovelluksesi ei täytä näitä odotuksia, saatat hyvin todennäköisesti jäädä kilpailijoidesi jalkoihin. Laadukkaiden sovellusten kehittäminen ei kuitenkaan tapahdu käden käänteessä eikä useimmiten myöskään pienin kustannuksin. Mikä siis avuksi? Yksi vaihtoehdoistasi on hyödyntää työkalua, joilla voit kehittää sovelluksen nopeasti toimimaan sekä Android- että iOS-laitteilla, parhaimmillaan myös verkossa. Tällaisia ovat esimerkiksi tässä blogissa kuvaillut React Native ja Flutter. Suoraan suomennettuna ne ovat alustariippumattomia mobiilikehyksiä, joista yleisimmin käytetään niiden englanninkielistä nimitystä cross-platform mobile framework.

Mobiilisovelluksen kehityksestä puhuttaessa alustariippumattomuus tarkoittaa sitä, että sovellus voidaan kehittää Androidille, iOS:lle ja usein myös verkkoon käyttäen samaa koodipohjaa. Tämä taas tarkoittaa, että parhaimmillaan niin suunnittelu, kehitys kuin testauskin vievät vähemmän aikaa ja rahaa kuin kehitettäessä puhtaasti natiivia sovellusta. Natiivisovellus kas kehitetään toimimaan yhdellä alustalla alustan omaa kehitysympäristöä ja ohjelmointikieltä käyttäen, jolloin esimerkiksi Android- sekä iOS-laitteille suunniteltu sovellus pitäisi koodata ensin Androidille sitten iOS:ille. Se, onko yhden koodipohjan taktiikka sinun sovelluksellesi sopivin vaihtoehto, on oma kysymyksensä, mutta tämän kirjoituksen puitteissa sovitaan, että olet niin jo päättänyt. Seuraava kysymyksesi todennäköisesti on, että mikä cross-platform framework – tässä kehys – on paras. Lähdetään tutustumaan yhdessä kahteen tunnetuimpaan kehykseen, jotta saat kysymyksellesi vastinetta.

Kaksi käytetyintä mobiilikehystä

React Native ja Flutter ovat kaksi maailmalla eniten käytettyä mobiilikehystä, joiden avulla voidaan rakentaa mobiilisovelluksia useammalle eri alustalle. Molemmat ovat avoimen lähdekoodin kehyksiä, tukevat yhtä koodipohjaa Androidille ja iOS:lle, sekä sisältävät hot reload -ominaisuuden, joka yksinään jo nopeuttaa niin kehitystä kuin testaustakin.

Apps for everyone

Mikä on React Native?

Facebookin vuonna 2015 julkaisema React Native on avoimen lähdekoodin mobiilikehys, joka käyttää kunkin alustan natiivikomponentteja antaen sovelluksille niiden alustalle parhaiten istuvan ulkomuodon. Konepellin alla React Native käyttää JavaScriptiä ja JSX:ää (jälkimmäinen mahdollistaa HTML:n kirjoittamisen Reactilla), mikä tarkoittaa, että JavaScriptia osaavat kehittäjät oppivat sen yleensä melko nopeasti. React Nativelta löytyy myös suuri kehittäjäyhteisö ja sen avulla on kehitetty sovelluksia, kuten Discord, Instagram ja Pinterest.

Mikä on Flutter?

Googlen vuonna 2017 julkaisema Flutter on avoimen lähdekoodin mobiilikehys, joka käyttää Googlen omaa Dart-nimistä olio-ohjelmointikieltä. Sen kehittäjäyhteisö on kasvanut nopeasti, ja StackOverflow:n vuoden 2023 verkkokyselyssä se ohitti React Nativen suosituimpien teknologioiden kategoriassa Muut kehykset ja kirjastot. Flutterilla on kehitetty sovelluksia, kuten Google Pay, Etsy ja Phillips Hue.

Kuinka vaikeita React Native ja Flutter ovat oppia?

Tällä hetkellä Googlen Dart-ohjelmointikielellä ei ole muita suosittuja käyttötapauksia kuin Flutter. Siksi kehittäjän, jolla ei ole aiempaa kokemusta Dartista, täytyy Flutter-projektissa opetella täysin uusi kieli. Idention konsulttien kokemusten mukaan Dart-kielen oppimiskäyrä ei kuitenkaan ole niin jyrkkä kuin miltä se voi vaikuttaa. Huomattakoon, että Dartin syntaksi on samankaltainen kuin JavaScriptin, joten kehittäjä, joka osaa JavaScriptiä, ymmärtää luultavasti myös Dartsia hyvin pitkälle. Google on lisäksi pistänyt ekstrapaukkuja uuden projektin aloittamiseen sekä Flutterin dokumentaatioon tehdäkseen ensimmäisestä ripeän ja jälkimmäisestä sekä kattavan että helposti ymmärrettävän.

”Meillä oli Identiolla viikonlopun mittainen työpaja, jossa opettelimme Flutteria. Meitä oli kymmenen henkilöä, joilla ei ollut aiempaa kokemusta kyseisestä teknologiasta. Kaikilla oli tapahtuman päätteeksi toimiva sovellus.”

– Julius Rajala, Software Engineer

Vertailun vuoksi voidaan todeta, että kehittäjä, jolla on kokemusta ReactJS:stä, oppii React Nativen melko nopeasti. Todennäköisesti sinullakin on kehitystiimissäsi ohjelmistokehittäjiä, jotka ovat käyttäneet ReactJS:ää tai ainakin JavaScriptiä. React Nativen dokumentaatio kuitenkin kalpenee Flutteriin verrattuna sekä rakenteeltaan että sisällöltään. Dokumentaation osalta piste siis menee ehdottomasti Flutterille. Kokonaisuutena annan silti pisteet React Nativelle, sillä sen opettelu on kuitenkin selvästi helpompaa.

Onko sovelluksen käyttöliittymän rakentamisessa eroja?

React Native sisältää noin 25 käyttöliittymäkomponenttia. Kaikki ominaisuudet, joita ei voi rakentaa niiden avulla, on toteutettava joko käyttämällä kolmannen osapuolen kirjastoja tai kirjoittamalla ne alusta alkaen itse. Kolmannen osapuolen kirjastojen käyttö voi johtaa ongelmiin yhteensopivuuden kanssa, ja toisaalta ominaisuuksien luominen alusta alkaen on kallista. React Nativea pidetään kuitenkin vakaana kolmannen osapuolen komponenttien käyttämiseen esimerkiksi maksujen käsittelyyn tai geopaikannukseen ja tarjolla onkin laaja valikoima aktiivisesti ylläpidettyjä kirjastoja vastaaviin ominaisuuksiin. React Nativen etu piilee käyttöliittymän kannalta siinä, että se hyödyntää natiivikomponentteja. Natiivikomponentit on rakennettu juuri tiettyjä alustoja ja laitteita varten. Yksi esimerkki natiivikomponentista on jokaiselle tuttu kamerasovellus, joka näyttää erilaiselta ja käyttäytyy eri tavalla jokaisella alustalla.

Flutter taas pitää sisällään vielä kattavamman UI-komponenttikirjaston, sillä se on integroitu Googlen Material Designiin. Jos käyttöliittymä voidaan rakentaa tätä kirjastoa käyttämällä, yhteensopivuusongelmien kanssa ei tarvitse juurikaan taistella. Jos taas tarvetta on sellaiselle, mitä Material Design ei tarjoa, eivät vaihtoehdot kolmannen osapuolen kirjastojen suhteen ole yhtä laajat kuin React Nativella. Etuna tässä on silti se, että Material Design -kirjasto on hyvin suunniteltu ja vastaa useimpien modernien sovellusten tarpeisiin. Sovelluksen voi jopa suunnitella FlutterFlow’n avulla (lue erillinen blogitekstimme aiheesta), mikä tarkoittaa, että suunnittelussa käytetään näitä Flutterin sisäänrakennettuja UI-komponentteja. Se tekee toteutuksesta jo melko suoraviivaista.

Kumman suorituskyky on parempi?

Flutter ottaa suorituskyvyssä johdon, sillä Dartin tehokas käännösprosessi on suorituskyvyltään hieman parempi. Vaikutus käyttäjälle ei kuitenkaan ole niin merkittävä, että Flutterin käyttöä kannattaisi harkita vain tästä syystä. Mutta se on hyvä pitää mielessä.

Kumpi on helpompi ylläpitää?

Ylläpidon suhteen voitaisiin sanoa, että vallan mukana tulee vastuu, mutta tässä tapauksessa sanotaan, että kolmannen osapuolen kirjastojen myötä tulee päänsärky. No, vitsit sikseen. Kolmannen osapuolen kirjastojen käyttäminen tarkoittaa, että sinun on luotettava siihen, että näitä kirjastoja ylläpidetään aktiivisesti esimerkiksi tietoturva- ja yhteensopivuusongelmien välttämiseksi. Sinun on huomioitava myös kirjastojen viimeisimmät päivitykset ja se, pitävätkö nämä päivitykset kyseisen kirjaston yhteensopivana sovelluksesi kanssa. Tämä koskee sekä Flutteria että React Nativea. Itse React Nativen päivittäminen voi myös olla mielenkiintoinen kokemus, ja siitä vastaavalla kehittäjällä kannattaa olla lehmän hermot. Jotain hajoaa lähes aina, eikä vastaan tulleiden haasteiden korjaaminen ole yleensä nopeaa. Jos jätetäänkin huomiotta kolmannen osapuolen kirjastojen käyttö, React Native menettää pisteen ylläpidon suhteen.

Developing with React Native

Entä virheet ja sovelluspäivitykset?

Oletetaan, että sovelluksesi on saatavilla yleisimmissä jakelukanavissa eli sovelluskaupoissa kuten Google Play ja App Store. Silloin sovelluspäivitysten toimittaminen on melko samanlaista sekä Flutterissa että React Nativessa. Jos eroja huomaa, ne tulevat vastaan todennäköisimmin virheitä korjatessa tai testauksen yhteydessä, joten ne eivät näy niinkään käyttäjille vaan kehittäjille. Flutteriin sisälle on integroitu testausominaisuuksia, kun taas React Nativella ei ole erikseen virallista testauskehystä, vaan siinä käytetään Jestin kaltaisia testauskehyksiä.

Muita huomioitavia asioita React Nativen ja Flutterin välillä?

Tässä vaiheessa on syytä mainita, että emme koskaan tiedä, kuinka kauan nämä kehykset tulevat säilymään. Vain tästä näkökulmasta katsottuna natiivisovellusten kehittäminen voi olla “turvallisempi” vaihtoehto. Tämä ei kuitenkaan tarkoita, että cross-platform olisi millään lailla huono valinta. React Native on ollut olemassa jo lähes vuosikymmenen ajan ja joitakin maailman suosituimmista sovelluksista on kehitetty sen avulla. Flutterin takana taas on Google. Googlella ei ehkä ole paras mahdollinen maine teknologioidensa pitkäaikaisessa tukemisessa, mutta Flutterin tulevaisuus on kuitenkin näyttänyt erittäin lupaavalta.

Kumpi sopii paremmin tarpeisiini?

Riippuu täysin siitä, mitä olet tekemässä. Mikä on budjettisi ja aikataulusi? Onko sinulla jo valmis suunnitelma? Kuka tai ketkä työskentelevät sovelluksen parissa? Riippuen sovelluksesi toiminnallisuuksista, erot sen kehittämisessä React Nativella tai Flutterilla voivat olla joko merkittäviä tai merkityksettömiä. Voin luvata, että saat toimivan sovelluksen kummallakin, mutta tie siihen voi olla erilainen. Päätös on tehtävä aina tilannekohtaisesti. Jos päätöksenteko on vaikeaa, voit aina kysyä asiaa taholta, jolta löytyy aiheesta enemmän kokemusta.

Kirjoittajan huomiot

Koska monille teistä React Native saattaa olla se tutuin mobiilikehys, halusimme kollegojeni kanssa muistuttaa, että on olemassa toinenkin loistava vaihtoehto – Flutter. Olen itse käyttänyt React Nativea enemmän ja sen puutteista huolimatta nautin edelleen sen parissa työskentelystä. Samalla näen ehdottomasti Flutterin tarjoamat mahdollisuudet ja pidän sitä yhtä varteenotettavana vaihtoehtona mobiilikehitysmaailmassa. Pidäthän Flutterin siis mielessä oman sovellusprojektisi kohdalla, sillä tutuin ei ole aina paras – tärkeintä on se, minkälaista sovellusta kehität ja minkälainen kehitystiimi teiltä löytyy.


Lue myös: FlutterFlow – sovelluskehitystä ilman koodausta

Flat illustration containing the crab mascot of Rust language, and C++ logo.

Rust — vaihtoehto C++:lle

Rust on monipuolinen ohjelmointikieli

Vaikka Rustin suurimmat hyödyt tulevat esille ohjelmissa, joissa suorituskyky, sovellusten turvallinen monisäikeinen ajo sekä pieni muistijalanjälki ovat elintärkeitä, ja joissa esimerkiksi C ja C++ ovat olleet suosittuja vaihtoehtoja jo viimeiset liki 50 vuotta, on Rustista paljon muuhunkin. Muun muassa JavaScriptin ja Pythonin erilaisten kehittäjätyökalujen kirjoittaminen Rustilla on kasvattanut suosiotaan viime aikoina. Rustin laajan käyttäjäyhteisön ja suoraviivaisen paketinhallinnan myötä on Rustille luotu paketteja ja kirjastoja monenlaisiin käyttötarkoituksiin, aina web-ohjelmoinnista pelimoottoreihin ja työpöytäsovelluksiin. Näistä nostona uusi, nopeudestaan tunnettu, AI-avusteinen ja yhteistyöpohjainen koodieditori Zed, joka on kirjoitettu kokonaan Rustilla.

Rustin valttikortti on muistinhallinta

Rustin yksi keskeisimmistä ominaisuuksista on tehokas ja turvallinen muistinhallinta, joka perustuu muistin omistamisen, lainaamisen ja eliniän tarkkoihin sääntöihin, joita kääntäjä automaattisesti valvoo kääntämisvaiheessa. Omistamisen säännöt pähkinänkuoressa ovat:

  1. Jokaisen arvon omistaa jokin muuttuja.
  2. Jokaisella arvolla voi olla vain yksi omistaja kerrallaan.
  3. Kun arvon omistaja katoaa näkyvistä, arvo pudotetaan.

Esimerkkinä näistä säännöistä kaksi lyhyttä funktiota:

fn rules_one_and_two() {	
	let x: String = String::from("Sääntö 2: Jokaisella arvolla voi olla vain yksi omistaja kerrallaan.");

Luodaan muuttuja x ja annetaan sille arvo, joka on tyyppiä String.

let y = x;

Luodaan muuttuja y ja määritetään sille x :n arvo. String on Rustissa tyyppi, jota ei ole ‘halpa’ kopioida (tällaisia ovat tyypit, joiden koko tiedetään kääntämisvaiheessa kuten erilaiset primitiivityypit bool, i32 , char…) joten y:lle siirretään muuttujan x omistama arvo.

   println!("{x}");
}

Makro nimeltään println! yrittää tulostaa stdout:iin muuttujan x. Tämä kuitenkin epäonnistuu, sillä muuttujaa x ei ole enää olemassa arvonsa poissiirtämisen jälkeen eikä sitä voi enää käyttää.

   fn rule_three() {
	let x = 10;

Määritetään uusi funktio ja sen näkymässä määritetään muuttujalle x arvoksi 10.

{
	 println!("x: {x}");
	 let y = 50;
}

Määritetään kaarisuluilla uusi näkymä, jossa tulostetaan jo tutulla println! -makrolla muuttujan x arvo. Koska muuttuja on määritetty ulommassa näkymässä, se on olemassa myös tässä näkymässä ja tulostus tuottaa stdout:iin tekstin x: 10 . Määritetään tässä uudessa näkymässä myös muuttuja y , annetaan sille arvoksi 50 ja suljetaan näkymä.

      println!("y: {y}");
}

Funktion näkymässä muuttujaa y ei ole olemassa ja tulostus epäonnistuu. Tämä tapahtuu siksi, että sisemmän näkymän päätyttyä y on kadonnut näkyvistä ja sen arvo on pudotettu. Lopulta kun funktion näkymä päättyy, katoaa x näkyvistä ja sen arvo putoaa. Muuttujia voi määrittää globaaleina (yleensä) tiedoston alussa näkymien ulkopuolelle, jolloin ne luonnollisesti näkyvät kaikissa näkymissä (eli funktioissa).

Rustin muuttujat (let x = 42) ovat lähtökohtaisesti muuttumattomia. Muuttuja voidaan merkitä muuttuvaksi (let mut x = 42), jolloin sen arvoa voidaan muokata määrityksen jälkeen, mutta vain mikäli sitä ei ole lainattu. Muuttujia voidaan ‘lainata’ toisiin muuttujiin käyttämällä referenssiä muuttujaan. Referenssejä on kahdenlaisia: muuttumattomia referenssejä (let y = &x) tai muuttuvia referenssejä (let y = &mut x). Muuttujalla voi olla samanaikaisesti joko rajaton määrä muuttumattomia referenssejä TAI tasan yksi muuttuva referenssi. Rustin kääntäjä seuraa lainausten elinaikoja tarkasti, joten viittauksia vapautettuun arvoon ei myöskään voi käyttää. Nämä säännöt tekevät rinnakkaisajon tuomista ongelmista (looking at you data races 👀) historiaa!

Esimerkiksi Javasta tuttua roskankeruuta ei Rustissa myöskään ole. Tämä mahdollistaa C/C++ -tasoisen suorituskyvyn ilman manuaalisen muistinhallinnan tuomia ‘metkuja’ (nullpointterien tuoma undefined behaviour, buffer overflow, use-after-free anyone?), jotka satavarmasti ovat jossain välissä ilmaantuneet syvinä juonteina jokaisen C/C++ -kehittäjän otsalle. Mikäli ohjelmassa löytyy halua tai tarvetta sääntöjen rikkomiselle tai manuaaliselle muistinhallinnalle (Rust sisältää työkalut myös älykkäiden pointterien hallintaan), tyypillisesti esimerkiksi muiden kielten kanssa kommunikointiin tai erittäin matalan tason koodin kirjoittamiseen, myös tälle on keinonsa. Koodi voidaan määrittää unsafe -avainsanalla. Unsafe tosin on ehdottomasti viimeinen vaihtoehto, jota ennen tulisi testata tarkkaan, onko muussa koodissa mitään vikaa, sillä muutkaan kääntäjän turvatoimet eivät tässä enää päde ja ohjelmasi virheiden ja kaatumisten riski kasvaa huomattavasti.

Tiukat säännöt luovat kynnyksen Rustin käyttämiselle

Jotta tämä kirjoitus ei menisi vain puhtaaksi ylistyslauluksi, puhutaan myös Rustin huonommistakin (onko niitä oikeasti?) puolista. Näistä suurimpana on oppimiskynnys ja koodin kirjoittamiseen kuluva aika verrattuna muihin, ‘perinteisempiin’ koodikieliin. Kääntäjän valvomat omistajuus- ja elinaikasäännöt ovat sangen tiukat, joten ratkaisujen keksiminen kääntäjän miellyttämällä tavalla ei välttämättä ole suoraviivaista. Tämä johtaa myös siihen, ettei pienten, nopeiden koodinpätkien ja ohjelmien kirjoittaminen Rustilla ole kaikista mukavin kokemus. Myös kielen suhteellinen nuoruus kuvastuu kirjastojen kypsyydessä ja standardikirjaston ominaisuuksien laajuudessa. Mielestäni ehkä suurin näistä puutteista on hyvän GUI-kirjaston puute. Kielen nuoruus näkyy myös tekijöiden määrässä, sillä C- ja C++-osaajia on vuosien varrella ehtinyt kertymään jo reilusti, kun taas Rust-osaajia ei vielä niin monia ole. Mikäli Stack Overflow’n käyttäjäkyselystä voisi jotakin päätellä, kysyntä loisi myös tarjontaa tekijöistä, sillä halukkaita koodareita Rustia tekemään päivätyökseen olisi runsaasti.

Vaivannäkö palkitaan toimintavarmuudella

Olemassaolevan C- ja C++-koodin määrä maailmassa on valtava, eikä tätä kaikkea kukaan pysty, osaa tai halua kirjoittaa Rustilla uudestaan. Eikä tälle oikeastaan tarvetta olekaan, sillä vanhemman koodin bugit tulevat (pääsääntöisesti) korjatuksi ajan myötä. Rustin paikka mielestäni onkin juuri uusissa projekteissa, jossa etenkin koodin nopeudella ja muistiturvallisuudella on tärkeä rooli. Vaikka nykyaikainen C++ (etenkin versioista C++11/14/17 eteenpäin) onkin kehittynyt huomattavasti mm. muistinhallinnan (älykkäät pointterit ym.) ja moniajon (atomiset muuttujat, jopa STL sisältää niitä nykyään) saralla, on Rustilla ohjelman kirjoittamisen tuoman lisävaivan vastapainona kuitenkin Rust-kääntäjän takuu siitä, ettei määrittelemätöntä käytöstä tai kaatumisia tapahdu. Tämä vaihtokauppa on mielestäni täysin tekemisen arvoinen diili.

Parhaatkin kehittäjät tekevät varmasti virheitä ja bugeja eksyy jossain vaiheessa kaikkiin ohjelmiin. Miksi emme siis käyttäisi työkalua, joka auttaa havaitsemaan mahdolliset virheet jo koodia kirjoittaessa, eli mahdollisimman aikaisessa vaiheessa? Projektinhallinnan näkökulmasta tämä tulee halvemmaksi kuin bugien havaitseminen koodiarvioinnissa, joka tulee halvemmaksi kuin bugien havaitseminen (julkaisu)testaamisessa, joka taas tulee halvemmaksi kuin bugien havaitseminen tuotannossa…

Rust gud


Lue myös: React Native vs Flutter – usein kysytyt kysymykset

webin saavutettavuus

“Ei esteitä” – webin saavutettavuuden edut yrityksille ja käyttäjille

Miten Scrumin daily stand-upeista monelle ohjelmistokehittäjälle tuttu toteamus “ei esteitä” takaa esteettömyyden myös heidän tuottamissaan sovelluksissa? Digitalisaatio on muuttanut tapaamme kommunikoida, työskennellä, oppia ja seurustella. Se ei kuitenkaan ole oletuksena kaikille yhdenvertaista.

Kaikki eivät välttämättä erota kunnolla nettisivuilla olevia kuvia, videoita tai kirjoitusta, jota ei ole oikein merkitty vaihtoehtoisella tekstillä. Kaikki eivät välttämättä kuule tai ymmärrä äänisisältöä, jota ei ole tekstitetty tai kirjoitettu auki. Voi olla tilanteita, joissa henkilö ei pysty navigoimaan verkkosivustolla, jos sitä ei voi käyttää näppäimistöllä. Ihmiset, joilla on kognitiivisia rajoitteita, eivät välttämättä ymmärrä monimutkaista kieltä tai navigointijärjestelmiä. Käyttäjän rajoitteet voivat olla väliaikaisia tai pysyviä.

Webin saavutettavuuden toteutuminen ei ole vain sosiaalinen vastuu, vaan myös lakisääteinen vaatimus monissa maissa. Esteettömyyslakien noudattamatta jättäminen voi johtaa oikeustoimiin ja sakkoihin. Yrityksille se on mainehaitan lisäksi myös iso tappio, mikäli mahdolliset asiakkaat eivät pääse tutustumaan tarjontaan ja palveluihin. Tässä blogitekstissä kerron siitä, mitä saavutettava web on, mitä hyötyä siitä on ja miksi web-suunnittelijoiden ja kehittäjien on tärkeää priorisoida se.

Mitä on Webin saavutettavuus?

Saavutettavuudelle on asetettu standardi, WCAG, joka tulee englannin kielen sanoista Web Content Accessibility Guidelines. Standardi on kehitetty W3C-prosessin (The World Wide Web Consortium) kautta yhteistyössä yksilöiden ja organisaatioiden kanssa eri puolilla maailmaa. Tavoitteena vastata yksilöiden, organisaatioiden ja hallitusten tarpeita saavutettavuuden osalta kansainvälisesti. Tätä noudattamalla voidaan suunnitella ja kehittää verkkosivustoja ja digitaalista palveluita, jotka ovat kaikkien käytettävissä. Näin varmistetaan, että ihmiset, joilla on erilaisia näkö-, kuulo-, motorisia, kognitiivisia tai neurologisia rajoitteita, voivat navigoida eri sivustoja ja sovelluksia. On tärkeää, että myös he voivat olla vuorovaikutuksessa muiden käyttäjien kanssa sekä ymmärtää digitaalista sisältöä ilman esteitä.

Saavutettavuuden edut

Webin saavutettavuudella on useita etuja, jotka voivat vaikuttaa myönteisesti sekä käyttäjiin että yrityksiin.

Lisääntynyt kattavuus ja sitoutuneisuus
Suunnittelemalla esteettömiä verkkosivustoja yritykset voivat tavoittaa ja sitouttaa suuremman yleisön. Tämä ei ainoastaan lisää bränditietoisuutta, vaan osoittaa myös sitoutumista sosiaaliseen vastuuseen.

Parannettu käyttökokemus
Webin saavutettavuus voi parantaa yleistä käyttökokemusta kaikille. Helppokäyttöiset suunnittelukäytännöt, kuten selkeä navigointi, luettava teksti ja intuitiivinen suunnittelu, helpottavat verkkosivustojen käyttöä.

Pienempi oikeudellinen riski
Monissa maissa on lakeja, jotka edellyttävät, että verkkosivustot ovat kaikkien käytettävissä. Näiden lakien noudattamatta jättäminen voi johtaa oikeustoimiin, mukaan lukien sakot ja oikeusriidat.

Parempi hakukoneoptimointi
Helppokäyttöiset verkkosivustot voivat hyötyä paremmasta hakukoneoptimoinnista. Hakukoneet voivat ymmärtää ja indeksoida saatavilla olevaa sisältöä paremmin, jolloin se näkyy todennäköisemmin hakutuloksissa.

Parannettu brändin maine
Priorisoimalla verkkosivujen ja sovellusten esteettömyyden yritykset voivat rakentaa brändille myönteistä mainetta osallistavana ja sosiaalisesti vastuullisena yrityksenä. Tämä voi myös auttaa houkuttelemaan uusia asiakkaita, ja säilyttämään vanhoja, aiemmin mainituista syistä.

Miten parantaa saavutettavuutta?

Käytännössä saavutettavuutta parannetaan lisäämällä html-elementteihin erilaisia attribuutteja tuomaan tarvittavia lisätietoja.

Yhdistä lomakkeen jokainen ohjaus labelin kanssa
Käytä for-attribuuttia <label> elementissä, joka on linkitetty lomake-elementin id-attribuuttiin, tai vaihtoehtoisesti WAI-ARIA-attribuutteja.

Tietyissä tilanteissa voi olla hyväksyttävää piilottaa <label> elementit visuaalisesti, mutta useimmissa tapauksissa labeleita tarvitaan auttamaan kaikkia lukijoita ymmärtämään vaadittu syöte.

<html lang="fi">
	<label for="etunimi">Etunimi:</label>
	<input id="etunimi" type="text" name="etunimi" />
</html>

Sisällytä kuville vaihtoehtoinen teksti
Varmista, että kaikkiin informatiivisiin ja toiminnallisiin kuviin lisätään vaihtoehtoinen teksti kuville. Käytä tyhjää vaihtoehtoista tekstiä, alt=”” kuvituskuville tai sisällytä ne sen sijaan CSS:ään ns. Tooltippinä. Tooltippiä käytetään usein antamaan lisätietoja jostakin, kun käyttäjä siirtää hiiren osoittimen elementin päälle:

<div class="tooltip">
<img src="kuvatus.webp" alt="informatiivinen kuvaus kuvan sisällöstä tähän" />
<span class="tooltiptext">tooltipin muodossa oleva informatiivinen kuvaus kuvan sisällöstä tähän</span>
</div>
<style>
.tooltip {
position: relative;
display: inline-block;
}

.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: black;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
}

.tooltip:hover .tooltiptext {
visibility: visible;
}
</style>

Tunnista sivun kieli ja kielimuutokset

Ilmoita jokaisen sivun ensisijainen kieli käyttämällä lang-attribuuttia html-tunnisteessa, esimerkiksi

<html lang=”fi”>.

Käytä lang-attribuuttia tietyissä elementeissä, kun elementin kieli eroaa muusta sivusta.

Käytä merkintöjä merkityksen ja rakenteen välittämiseen
Käytä asianmukaisia merkintöjä otsikoissa, luetteloissa, taulukoissa ja muissa osioissa. HTML5 tarjoaa lisäelementtejä, kuten <main>, <nav> ja <aside>, jotka jäsentävät sisältöäsi paremmin. WAI-ARIA-roolit voivat tarjota lisämerkityksiä, esimerkiksi käyttämällä role=”search”-funktiota hakutoiminnon tunnistamiseen. Työskentele esim. suunnittelijoiden ja sisällöntuottajien kanssa sopiaksesi merkityksistä ja käytä niitä johdonmukaisesti.

Auta käyttäjää välttämään ja korjaamaan virheet
Anna selkeät ohjeet, virheilmoitukset ja muut ilmoitukset, jotka auttavat käyttäjää täyttämään sivustosi lomakkeita. Jos pakollinen kenttä ei sisällä vaadittuja tietoja voi aria-required -ominaisuuden avulla ilmaista syöttötiedon pakollisuuden.

Jos kentän tietojen on oltava tietyssä muodossa, voidaan käyttää aria-alert-dialogia virheiden tunnistamiseen ja antaa ohjeet vaadittujen korjausten tekemiseen. Auta käyttäjää löytämään, missä ongelma on.

Kirjoita koodia siinä järjestyksessä kun sivua luetaan
Varmista, että koodin elementtien järjestys vastaa esitettyjen tietojen loogista järjestystä. Yksi tapa tarkistaa tämä on poistaa CSS-tyylit kokonaan ja tarkistaa, onko sisällön järjestys järkevä ja sellainen mihin ollaan yleisesti totuttu.

Responsiivinen suunnittelu
Käytä responsiivista suunnittelua mukauttaaksesi näyttöä erilaisiin zoomaus-tiloihin ja näkymän kokoihin, kuten mobiililaitteissa ja tableteissa. Kun fonttikokoa suurennetaan vähintään 200 %, vältä vaakasuuntaista vierittämistä ja estä sisällön leikkaaminen. Käytä progressiivisia parannuksia varmistaaksesi, että ydintoiminnot ja sisältö ovat saatavilla käytetystä tekniikasta riippumatta.

Anna merkitys epätyypillisille interaktiivisille elementeille
Käytä WAI-ARIAa tarjotaksesi tietoja mukautettujen widgetien, kuten haitarien ja räätälöityjen painikkeiden, toiminnasta ja tilasta.

role="navigation" ja aria-expanded="true"

Lisäkoodia tarvitaan tällaisten widgetien toiminnan toteuttamiseen, kuten sisällön laajentamiseen ja kutistamiseen tai siihen, miten widget reagoi näppäimistötapahtumiin.

Varmista, että kaikki interaktiiviset elementit ovat näppäimistön käytettävissä

Ajattele näppäimistön käyttöä varsinkin kun kehität interaktiivisia elementtejä, kuten valikoita, hiiren osoitintietoja, kokoontaitettavaa haitari-elementtiä tai mediasoittimia.

Lisää tabindex=”0″ elementteihin, jotka eivät tavallisesti saa kohdistusta, kun niitä käytetään interaktiivisesti. Tällaisia elementtejä ovat esimerkiksi <div> ja <span>.

Lopuksi

Yhteenvetona voidaan todeta, että verkon saavutettavuus on välttämättömyys sen varmistamiseksi, että kaikilla on yhtäläinen pääsy verkon digitaaliseen sisältöön. Se on monissa maissa myös lakisääteinen vaatimus.

Webin saavutettavuus on olennainen osa web-suunnittelua ja -kehitystä, josta on hyötyä sekä käyttäjille että yrityksille. Se varmistaa, että kaikki voivat kyvystään riippumatta käyttää digitaalista sisältöä ja olla vuorovaikutuksessa sen kanssa. Verkkostandardeja ja ohjeita noudattamalla yritykset voivat tavoittaa suuremman yleisön, parantaa käyttökokemusta, hyötyä paremmasta hakukoneoptimoinnista, vähentää juridisia riskejä ja parantaa brändin mainetta. Verkkosuunnittelijoina ja -kehittäjinä meidän vastuullamme on priorisoida verkon saavutettavuus ja luoda kattavampi verkko kaikille käyttäjille.

Tarkemmat ja laajemmat esimerkit löydät standardin virallisilta kotisivuilta.

An Absolute Unit – ohjeita yksikkötestin suunnitteluun

Pidän itseäni pätevänä devaajana, joka on onnekkaan sattuman myötä ollut ensimmäiseksi IT-alan työkseen validointiharjoittelijana. Työ itsessään oli lähinnä automaatiotestien (useimmiten unit-testien) kirjoittamista, mutta saamani mentorointi oli ensiluokkaista. Olen viimeaikoina pureskellut näitä samoja periaatteita eteenpäin mentoroinnin muodossa ja ajattelin jakaa niitä nyt myös blogimme lukijoille.

Unit-testien tarkoitus projektissa on kaksijakoinen: toisaalta ne toimivat kuvauksena siitä, miten ohjelman osan tulee esitetyssä tilanteessa toimia, toisaalta ne toimivat ns. “sanity checkeinä” koodin muutoksille. Mikäli muutos aiheuttaa virheen aiemmin toimineessa unit-testissä, on aihetta varmistaa että muutos on todella haluttu. Testien tehokas suunnittelu on kotonaan jokaisen devaajan työkalupakissa.

Unit-testien kirjoittamisella on myös eräs piilohyöty: jos testin suunnittelu tuntuu vaikealta, tai lähes mahdottomalta, voi se johtua siitä, että testin kohde on suunniteltu huonosti ja että sitä tulisi ehkä refaktoroida.

TOIM. HUOM: Yleisesti on paljon mielipiteitä siitä, mikä lasketaan unit-testiksi ja mikä esimerkiksi integraatiotestiksi. Ei huolta. Alempia ohjeita voi helposti käyttää yleisenä ohjelmistotestien ohjenuorana.

Osa 1 – Testin sanoittaminen

Uusilla testaajilla on usein vaikeuksia hahmottaa, mikä testitapauksen pitäisi olla. Olipa testin kohde yksittäinen funktio tai isompi kokonaisuus, pitää testi pystyä pelkistämään simppeliksi testitapaukseksi. Testitapauksen muotoilu on helppoa, kun sen muotoilee seuraavan lauseen tyylisesti:

“Kun tila on X ja tapahtuu Y, seurauksena on Z

…jossa:

X = alkuoletukset*
Y = testin ajo
Z = ajon tuottamat tulokset

*testin kohteen tila ja kohteen ulkoiset oletetut tekijät95% testeistä voidaan hahmotella kyseisellä tavalla. Käytetään esimerkkinä seuraavaa testitapausta:

When getSocks() function returns red socks and putOnSocks() function is called, the color of footwear changes to red

Tämä yksinkertaistus on varsinkin aloittelevalle testin kirjoittajalle hyvä niksi hahmottaa millainen haluttu testitapaus oikeasti on. Tämä helpottaa pitämään testitapaukset selkeinä ja jakamaan monimutkaisemman toiminnallisuuden testauksen useampaan testiin.

Siirtyessämme seuraavaan osaan huomaamme myös, että tämänkaltaisesta sanoittamisesta on erityistä hyötyä kun rajaamme testiä.

Osa 2 – Testin kohteen rajaus

Testin suunnittelun kannalta on olennaista rajata, mitä halutaan testata ja mitä sulkea testauksen ulkopuolelle. Tämä rajaus kertoo meille suoraan, mikä toiminnallisuus on testin kannalta olennaista ja mikä on riippuvuus, joka voidaan yksinkertaistaa ja mallintaa (englanniksi “mock“) testin puitteissa. Matemaattisista todistuksista tuttu termi “alkuoletus” on enemmän, kuin omiaan kuvaamaan tällaista mallinnettavaa riippuvuutta.

Laajennetaan edellisen osan putOnSocks()-esimerkkiä ja oletetaan seuraavanlainen kuvaus:

getFootWearColor() {

returns the color of the worn footwear, otherwise null

}

putOnSocks() {getSocks();

[…]

}

getSocks() {

const socks = {

amount: 2,

color: randomColor()

};
return socks;

}

Kun mietimme, miten testi kannattaa kirjoittaa, kertoo oheinen kuvaus meille suoraan, mitä voimme mallintaa eli mockata, ja mikä on testin kannalta olennaista toiminnallisuutta.
Koska testitapauksessa on erikseen mainittu alkuoletuksessa, että getSocks()-funktion tulee palauttaa jotain tiettyä (punaiset sukat), on se jo rajattu testin ulkopuolelle. Tämä tarkoittaa, että se voidaan hyvin mockata palauttamaan testin ajan vain punaisia sukkia.

Alemmassa kuvassa on korostettuna, mikä on testin kannalta olennaista (eli testattavaa) toiminnallisuutta ja mockattu getSocks() funktionaalisuus, jotta se palauttaa testin kannalta halutun arvon.

getFootWearColor() {

returns the color of the worn footwear, otherwise null

}

putOnSocks() {getSocks();

[…]

}

getSocks = () => ({amount: 2, color: ‘red’ });

putOnSocks() ja getFootwearColor() funktiot tulee säilyttää muuttumattomina (mockaamattomina), sillä molemmat ovat testin kohteena. Näistä edellinen on testattava toiminnallisuus. Jälkimmäinen taas on tuloksen tarkistamisen kannalta olennaista säilyttää koskemattomana.

Sivuhuomio: Mikäli haluaisimme sisällyttää myös getSocks()-funktion testin kohteeseen, voisimme sen suoran mockaamisen sijaan mockata sen riippuvuutena olevan toiminnallisuuden:

randomColor = () => ‘red’

Rajauksen jälkeen meille on selvää, mitkä ominaisuudet ova testiin sisällytettäviä ja mitkä riippuvuuksia, jotka voidaan mallintaa. Nyt olemme valmiit kokoamaan testin.

Osa 3 – Testin rakenne

Kun ylemmät osiot ovat selviä, itse testin kokoaminen on huomattavan suoraviivaista. Hyvässä testissä on tapauksesta riippuen seuraavat olennaiset osat:

  1. Komponentin alustus oikeaan tilaan
  2. Ulkoisten riippuvuuksien mockaaminen halutunlaisiksi
  3. Testin ajo
  4. Ajon vaikutusten tarkistaminen

Vaikka testissä voi olla monenlaisia rakenteita, ovat ne yleensä lopunviimein erilaisia kombinaatioita ylemmistä neljästä osasta. On aivan mahdollista, että testin kulku on esimerkiksi seuraavanlainen:

Alustus → Mockaus → Ajo → Tarkistus → Mockaus → Ajo → Tarkistus → Alustus

Käyttäen edelleen esimerkkinä putOnSocks() -toiminnallisuutta, voimme hahmotella seuraavanlaisen testirakenteen:

  1. Alustetaan komponentti siten, että tällä hetkellä jalassa ei ole sukkia
  2. Mockataan getSocks() palauttamaan punaiset sukat (kts. ylempi kuva)
  3. Kutsutaan putOnSocks() toiminnallisuutta
  4. Tarkistetaan, palauttaako getFootwearColor() ‘red’, kuten odotettu

Kuten sanottu, kun kaksi aikaisempaa osaa on käyty ajatuksella läpi, on testin rakenteen kokoaminen suoraviivaista. Helppoa, eikö?

Osa 4 – Vaaran paikkoja

Testiä tehdessä on pidettävä seuraavat asiat mielessä:

Älä mockaa vääriä asioita:
Testiä tehdessä on helppo keskittyä liikaa testin läpiviemiseen ja mockata epähuomiossa vääriä asioita. Edellisessä esimerkissä putOnSocks()– tai getFootwearColor()-funktion mockaaminen olisi tehnyt testistä ilmeisen virheellisen, mutta myös riippuvuuksien kanssa kannattaa joskus olla tarkkana. Testiä tehdessäsi varmistu aina siitä, ettei mockaus vaikuta odottamattomalla tavalla ajoon tai tarkistukseen.

Onko testi järkevä:
Testitapausta sanoittaessasi osan 1 tapainen sanoitus (alkuoletus, toiminto, lopputulos) auttaa hahmottamaan kuinka järkevä testitapaus on, mutta se ei ole pakollinen.

Esimerkiksi testi, joka on sanoitettu seuraavasti…

lockForm() function should not disallow copyForm()
functionality…ei sisällä eksplisiittisesti alkuoletusta, mutta sisältää implisiittisen oletuksen, joka voidaan kirjoittaa auki seuraavasti…copyForm() should always be allowed after lockForm() has been called

…jossa always avainsana paljastaa, että alkutila voi olla mikä vain komponentin tila.

Vastaavasti seuraava sanoitus..

If formLocked = true, isFormLocked() returns true

…tuntuu testitapauksena jokseenkin tyhjältä. Jos alkuoletuksen pohjalta ollaan jo käytännössä halutussa lopputilassa, on testin mielekkyys kyseenalainen.

Tarkista asiat oikein:
Testissä tehdyt tarkistukset voivat olla sinänsä ihan oikeita, mutta joskus niiden pitää myös olla riittävän tarkkoja jotta ne todella todentavat halutun tuloksen. Alla esimerkki, joka avaa mitä tarkoitan.

Jos oletetaan, että formLocked() voi heittää tietyissä tapauksissa virheen, on ok tarkistaa, että virhe myös heitetään. Mikäli funktio voi kuitenkin heittää kahta erilaista virhettä tilanteesta riippuen, on järkevää myös tarkistaa, että heitetty virhe oli juuri odotetun kaltainen.

Mikäli esimerkiksi alustuksen pohjalta odotetaan virheviestiksi…

“ERROR: Form cannot be locked”

…mutta testissä saadaankin tuloksena…

“ERROR: Form already locked”

…on testin alkutila väärä ja testin voidaan katsoa olevan virheellinen.

Testiä tehdessä mitä tarkemmin tuloksen pystyy tarkistamaan, sitä parempi!

Osa 5 – Towards an Absolute Unit

Tässä blogitekstissä on esitetty periaatteita, joita seuraamalla uudemmankin testaajan on mahdollista suunnitella testi, joka on järkevä ja hyvin rakennettu. Identiota edustaessani haluan kuitenkin osoittaa osaavani viedä ajatuksen vielä askelta pidemmälle. Katsotaanpa siis, miten teemme esimerkin putOnSocks-testistä varmemman.

Testauksessa on hyvä olla pedantti, joten lisäämme testin alkuun ns. turhan tarkistuksen, jonka tehtävänä on todentaa että komponentin alkutila on todellakin sellainen, kuin haluamme:

  1. Alustetaan komponentti siten, että tällä hetkellä jalassa ei ole sukkia
  2. Tarkistetaan, että getFootwearColor() palauttaa arvon null
  3. […]

Tämä tarkistus ei ole tarpeellinen, mutta se antaa meille luottoa siitä, että testin tila todellakin on se, mitä ajattelimme, emmekä ole tehneet alustuksessa virhettä.

Tämän lisäksi voimme generalisoida testin! Aloitamme muokkaamalla testikuvauksen sanoitusta seuraavanlaiseksi:

“putOnSocks() function should cause the color of footwear to change based on the color of the received socks”

Oletetaan, että putOnSocks()-funktion pitäisi myös vaihtaa päällä olevia sukkia, joten lisätään tämä osaksi testiä:

  1. Alustetaan komponentti siten, että tällä hetkellä jalassa ei ole sukkia
  2. Tarkistetaan, että getFootwearColor() palauttaa arvon null
  3. Mockataan getSocks() palauttamaan punaiset sukat
  4. Kutsutaan putOnSocks() toiminnallisuutta
  5. Tarkistetaan, palauttaako getFootwearColor() ‘red’, kuten odotettu
  6. Mockataan getSocks() palauttamaan ruskeat sukat
  7. Kutsutaan putOnSocks() toiminnallisuutta
  8. Tarkistetaan, palauttaako getFootwearColor() ‘brown’, kuten odotettu

Vaikka testiin ylimääräisten kohtien lisäämisen arvo ei ole välttämättä ilmiselvä, luo se lisää varmuutta, että ensimmäinen tarkistustulos ei ollut sattumaa. Erityisesti kompleksisissa tapauksissa on parempi tehdä liikaa tarkistuksia, kuin liian vähän. Ylempi testi ei ole hirveän monimutkainen, mutta testaa melkoisella varmuudella haluttua toiminnallisuutta.

Mikäli olet lukenut tänne asti, niin omastani ja Idention puolesta haluan kiittää mielenkiinnosta ja toivottaa hyviä hetkiä testauksen parissa!

GitHub Copilot tekee työsi puolestasi

Elän ja hengitän ongelmanratkaisua. Tekniikan keinojen käyttäminen asiakkaan ongelmien ratkaisemiseen on erittäin mukavaa puuhaa ja leijonanosa työnkuvaani. Työhöni kuitenkin kuuluu myös paljon “tylsää” manuaalista hommaa, kuten koodin kirjoittamista. En jaksaisi naputella niin paljon koodia kuin työni vaatii. Onneksi sain pari viikkoa sitten käyttööni uudenkarhean GitHub Copilot -parikoodarin, joka tekee työni puolestani.

Mikä on Copilot?

Copilot on GitHubin kehittämä “tekoälyparikoodari” (engl. AI pair programmer), tai niin GitHub sitä markkinoi. Copilot siis auttaa ohjelmointityössä kirjoittamalla koodin puolestani.

Copilot on Visual Studio Code -plugari, joka on pellin alla oleva neuroverkko, johon on syötetty miljardeja rivejä koodia. Copilotin neuroverkko on siis koulutettu luomaan täysin uutta koodia. Käytännössä Copilot täydentää automaattisesti koodiani jopa pelottavan älykkäästi.

Copilotin “parikoodaus” tapahtuu automaattisilla koodiehdotuksilla editorini kursorin kohdalle. Ehdotuksen pystyn täydentämään olemassa olevaan koodiini tab-nappulaa painamalla. Vaihtoehtoisesti voin myös selata muita Copilotin keksimiä ehdotuksia koodini jatkeeksi.

Copilot osaa kirjoittaa joko rivini loppuun, ehdottaa kokonaista funktiomäärittelyä tai täydentää (englanninkielisen) kommenttini. Copilot “ymmärtää tusinoittain eri kieliä”, mutta eritoten hyvin se osaa Python-, JavaScript-, TypeScript-, Ruby- ja Go-kieliä.

Tässä ruudunkaapauksessa kirjoittelin käsin Employee-interfacen ja kommentin, joka kuvailee funktion. Näiden vinkkien perusteella Copilot osasi ehdottaa funktiolle määrittelyrivin ja toteutuksen. Copilotin koodiehdotukset osuivat nappiin, ja se vähensi tässä erittäin lavastetussa esimerkissä käsityötä huomattavasti. Hyvää duunia Copilot!

Copilotin vaikutus työntekoon

Olen käyttänyt Copilottia nyt parin viikon ajan enimmäkseen Java-, JavaScript-, Terraform- ja Elm-kielten kanssa. Copilot on onnistunut erittäin hyvin nopeuttamaan työskentelyäni tarjoamalla laadukkaita ja toimivia automaattitäydennyksiä. Copilot on parhaimmillaan triviaaleissa ja itseään toistavissa tilanteissa, kuten esimerkiksi testien kirjoittamisessa. Copilotin Terraform-osaaminen yllätti eniten – se on minua parempi Terraform-koodari. Arvelen sen johtuvan siitä, että Terraform on konffauskieli, joka jättää vähemmän tilaa luovuudelle.

Kannattaako sinun ottaa GitHub Copilot käyttöösi?

Copilot tarjoaa mainion työkalun nopeuttamaan koodarin rutiinityötä. Se on kuitenkin vielä kaukana täydellisestä ja välillä ehdotukset menevätkin kunnolla metsään. Uskallan kuitenkin väittää, että leijonanosan ajasta Copilot tarjoaa hyvin lähelle – ellei täsmälleen – sen mitä ajattelet. Usein tuntuu, että Copilot lukee ajatuksiani. Copilot on ehdottomasti paras tähän mennessä julkaistuista koodin täydentäjistä joka käyttää neuroverkkoa.

Copilotin käyttäjää saattaa kuitenkin pelottaa lisensointi- ja tietoturvaongelmat. GitHub sanoo, että kaikki Copilotin koulutukseen käytetty koodi on tarpeeksi avointa lisenssiä, jotta käyttäjä voi huoletta hyödyntää Copilotin kirjoittamaa koodia miten tahansa. Copilot on kuitenkin generoinut koodia, joka on suljettua lisenssiä. GitHub myös lupaa sensuroivansa Copilotin koulutusmateriasta mm. API-avaimet. Sinä saat itse päättää luotatko GitHubin sanaan.

Kaiken kaikkiaan GitHub Copilot on erittäin toimiva työkalu ohjelmointityöhön ja suosittelen lämpimästi kokeilemaan sitä. Copilot ja sen kaltaiset työkalut tulevat olemaan alamme tulevaisuus ja vaikuttamaan suuresti siihen, mitä ohjelmointityö tulevaisuudessa tarkoittaa. Ehkä emme kirjoita tulevaisuudessa lainkaan koodia itse, kun robotit korvaavat sen. Itse uskon, että tämänkaltaiset työkalut muuttavat ohjelmoinnin määritelmää enemmän korkean tason suunnittelu- ja ongelmanratkaisutyöksi.

Odotan innolla skenen uusia tuulia.