Arvostelu valmis, pisteet näkyvät Moodlessa. Huomaa, että Moodlessa tehtävän n pisteet näkyvät tehtävän n+1 kohdalla.

Tehtäviin liittyvä tarina

Kurssipalautejärjestelmä Kurppa on osoittautunut menestykseksi ja Helsingin yliopiston (HY) lisäksi sovelluksen ovat ottaneet käyttöön myös Tampereen yliopisto (TAU) ja Jyväskylän yliopisto (JYU). Sovellusta jatkokehitetään nykyään kolmen yliopiston voimin. Jokaisella yliopistolla on oma Kurppabacklog ja product owner. Kehitystyö on jaettu kolmen kuukauden mittaisiin sprintteihin. Sprintti alkaa viikon mittaisella suunnittelutilaisuudella, minkä aikana kukin product owner määrittelee tarkemmalla tasolla backloginsa tärkeimmät user storyt ja estimoi. Tämän jälkeen product ownerit äänestävät, mitkä user storyt otetaan työn alle seuraavaan sprinttiin.

Kehitystyö on organisoitu siten, että Kurpan frontendiä eli selainpuolen toiminnallisuutta toteutetaan HY:n tiimissä, backendiä eli palvelinpuolen koodia TAU:n tiimissä ja Sisu-järjestelmään tapahtuvasta integraatiosta vastaa JYU:n tiimi. Sprintin ensimmäiset kaksi kuukautta kukin tiimi kehittää omalla vastuualueellaan olevaa koodia. Jokaisella yliopistolla on oma Git-versionhallintajärjestelmänsä, johon koodi on synkronoitu sprintin alussa. Kehitys tehdään kunkin yliopiston omassa Gitissä.

Sprintin sisällä kunkin yliopiston tiimin työskentely tapahtuu siten, että tiimin Kurppamestari (tiimien käyttämä nimitys Scrum masterille) suunnittelee kunkin user storyn edellyttämät tekniset tehtävät eli taskit sekä niiden koodiin ja arkkitehtuuriin vaatimat muutokset. Hän myös määrää kullekin tehtävälle koodarin tiimin sisältä. Jos koodari ei ymmärrä hänelle määritellyn tehtävän sisältöä, hän kysyy asiasta omalta Kurppamestarilta, joka tarpeen mukaan varmistaa asian oman yliopistonsa Product ownerilta.

Toiminnan optimoimiseksi kukin koodari työskentelee tavallisesti samaan aikaan useamman teknisen tehtävän eli taskin parissa. Koodari luo kutakin taskia varten versionhallintaan ns featurebranchin, jotta sprintin aikana ei syntyisi sekaannuksia muiden koodareiden kanssa. Featurebranchit mergetään kunkin yliopiston omaan Gitiin sprintin niiden valmistuessa. Usein tämä tapahtuu aikalailla viime tingassa.

Sprintin viimeinen kuukausi käytetään koodin integrointiin ja testaamiseen. Tässä vaiheessa koodi kopioidaan kunkin yliopiston omasta versionhallinnasta HY:n Gitiin, minkä sisällä sprintin loppuajan työskentely tapahtuu. Testaus on ulkoistettu Rovaniemeltä ostetulle etänä työskentelevälle testaustiimille. Testaus tapahtuu pääosin käyttöliittymää klikkailemalla. Sprintin lopuksi Kurpasta julkaistaan uusi versio. Kussakin yliopistossa Kurpan tuotantoon viemisestä ja tuotannossa pyörittämisestä vastaa erillinen IT-tiimi. Esim HY:llä tämä tiimi on TIKE:n eli Tietotekniikkakeskuksen DevOps-tiimi. Uuden version julkaisun yhteydessä he saavat koodin oman yliopistonsa Kurppa-tiimiltä ja käynnistävät sen yliopistonsa palvelimella.

Joka neljäs Kurppasprintti on niin sanottu laatusprintti. Sen aikana järjestelmään ei toteuteta uusia ominaisuuksia (poislukien seuraavassa kappaleessa mainitut kiireelliset yllätysstoryt) ja työ keskittyy teknisen velan maksamiseen ja testaustiimin edellisen kolmen sprintin aikana havaitsemien bugien korjailuun.

Aika ajoin yliopistojen korkeimman johdon tietoisuuteen kantautuu Kurpan esim. Jodelissa tai jopa Helsingin Sanomissa saamaa vihaista palautetta. Tämä johtaa usein siihen, että Kurpan menossa olevaan sprinttiin otetaan erittäin kiireelliseksi määriteltyjä user storyjä, jotka on toteutettava välittömästi.

Lupaavan alun jälkeen Kurpan kehitystyö on hidastunut pelottavaa tahtia, tuotteessa on myös havaittu ikäviä laatuongelmia. Myös koodareiden moraali on laskemaan päin, esim. ennen ylpeydellä pidettyjä Kurppa-huppareita ei oikein enää kukaan viitsi pitää päällä, ainakaan julkisilla paikoilla.

Tehtävä 1

Miten kehittäisit Kurpan sovelluskehityksen prosessia Scrumia, Lean-periaatteita, kurssin osassa 5 käsiteltyjä laajan skaalan ketteriä menetelmiä sekä ketterän manifestin periaatteita noudattaen? Perustele jokainen kehitysehdotus.

Tehtävän arvioi Ville Saastamoinen. Omasta arvioinnista voi tarvittaessa kysyä etunimi.sukunimi@helsinki.fi tai Discordissa

Tehtävän arvio perustuu seitsemään kohtaan/kehitysehdotukseen:

  • Liikaa product ownereita / Product ownerit määrittelevät storyt sprintille (1p)
  • Jokaisella yliopistolla omat backlogit / tiimit eivät ole cross-functional (0,5p)
  • Liian pitkät sprintit / sprintiin lisätään uusia user storyja kesken sprintin (0,5p)
  • Kurppamestari määrittelee user storyjen tekniset taskit / Kurppamestari määrää taskille tekijän (0,5p)
  • Usean taskin tekeminen samaan aikaan (0,5p)
  • Tuotantoonvienti useammin / CI/CD putki tiimeille käyttöön (1p)
  • Testaus ulkoistettu / testaus tapahtuu liian myöhään (0,5p)

Jokainen kohta tulee olla järkevästi perusteltu. Ilman perusteluja jokaisesta kohdasta on voinut saada maksimissaan puolet pisteistä. Perusteluksi ei riitä esim. “Sprinttien tulee olla 1-4vk, koska Scrum määrää niin”. Perusteluista tulisi tässä tapauksessa siis käydä ilmi, miksi Scrum määrää niin: “Sprinttien tulee olla 1-4vk, jotta asiakkaalle arvoa tuottavien ominaisuuksien julkaiseminen tapahtuisi mahdollisimman usein. Myös asiakkaan mahdollisesti muuttuvat tarpeet tulee huomioitua nopeammin ja väärän tuotteen kehittäminen saadaan minimoitua.”

Vastauksia on pyritty tulkitsemaan mahdollisimman hyvin. Pisteitä on voinut siis saada niin sanotusti “rivien välistä” tulkitsemisen jälkeen.

Kauttaviivalla erotelluissa kohdissa on vaadittu molempien kohtien maininta ja perustelu, jotta kohdasta saa täydet pisteet.

Mallivastausesimerkki:

Kurppaa kehittävät tällä hetkellä kolme eri tiimiä. Voimme harkita siirtymistä Large Scale Scrumiin eli LeSSiin, erityisesti sen versioon, joka on suunniteltu tilanteeseen, jossa tuotetta kehittää 2-8 tiimiä. LeSSin mukaisesti yhtä tuotetta kehitettäessä tulisi olla yksi product owner ja yksi product backlog. Tämä yksinkertaistaisi viestintää, priorisointia ja päätöksentekoa, ja mahdollistaisi keskittymisen arvon tuottamiseen asiakkaalle yhdenmukaisesti. Jokaisella tiimillä voisi kuitenkin edelleen olla omat sprint backlogit, jotka antavat heille joustavuutta ja mahdollisuuden keskittyä tiimin erityisiin tarpeisiin valitun user storyn parissa. Tiimien tulee kuitenkin edelleen harjoittaa kommunikointia ja yhteistyötä tarvittaessa.

User storyjen määrittely sprintille tulee tapahtua yhdessä tiimin kanssa eikä vain product ownerin toimesta. Product owner voi olla henkilö, jolla ei ole teknistä kokemusta ja tällöin hän ei myöskään osaa estimoida user storyyn kuluvaa aikaa ilman tiimin tukea.

LeSS:in mukaan tiimien tulisi olla cross-functional ja full-stack eli ne sisältävät kaiken tarvittavan kompetenssin kokonaisen tuotteen osan tekemiseen. Siirrytään siis pois mallista, jossa jokaisen yliopiston tiimi keskittyy yhteen osa-alueeseen ja tuodaan frontend-, backend- ja integraatiotaitajia jokaisen yliopiston tiimiin.Cross-functional tiimi mahdollistaa nopeamman ja tehokkaamman työskentelyn, parantaa projektin laatuja joustavuutta sekä vähentää riskejä ja riippuvuutta ulkopuolisista tekijöistä.

Kolmen kuukauden pituiset sprintit ovat liian pitkiä. Sprinttien tulee olla pituudeltaan 1-4 viikkoa, jotta asiakkaalle arvoa tuottavien ominaisuuksien julkaiseminen tapahtuisi mahdollisimman usein. Myös asiakkaan mahdollisesti muuttuvat tarpeet tulee huomioitua nopeammin ja väärän tuotteen kehittäminen saadaan minimoitua. Kesken sprinttiä ei tulisi myöskään ottaa mukaan vihaisen palautteen myötä tulleita huonosti määriteltyjä user storyja. Nämä tulisi siirtää product backlogiin odottamaan perusteellista määrittelyä ja turvata täten tiimien työrauha.

Kehitysehdotuksena on siirtyä kohti itseohjautuvia tiimejä, joissa tiimin jäsenet saavat itse valita tehtävänsä ja määrittää niihin liittyvät tekniset yksityiskohdat yhdessä. Kurppamestari voisi toimia tiimin tukihenkilönä, joka auttaa ratkaisemaan mahdollisia ongelmia ja tarjoaa tukea tarvittaessa. Tämä muutos antaisi tiimin jäsenille enemmän vastuuta ja päätäntävaltaa oman työnsä suunnittelussa ja toteuttamisessa. Kurppamestarin rooli painottuisi enemmän Scrum-prosessin ja tiimin toiminnan koordinointiin kuin tekniseen työhön. On myös tärkeää huomata, että Kurppamestarilla ei välttämättä tarvitse olla syvällistä teknistä osaamista, vaan hänen vahvuutensa voivat olla prosessin hallinnassa ja tiimiyhteistyössä.

Siirrytään käyttämään yksittäisten taskien käsittelyä kerrallaan, jotta vältetään liiallinen multitasking ja varmistetaan laadukas työn suoritus. Lisäksi voitaisiin harkita Kanbanin “Work In Progress” (WIP) -rajoitteiden käyttöönottoa tiimissä. Esimerkiksi asettamalla WIP-rajoitus 1-2 tehtävään kullekin tiimin jäsenelle varmistetaan, että jokainen voi keskittyä yhteen tehtävään kerrallaan ja vältetään työmäärän ylikuormittaminen.

Kurpan uusien versioiden julkaisu on hidasta ja vaatii paljon manuaalista siirtelyä. Tämä tarkoittaa, että uusien ominaisuuksien ja parannusten saaminen asiakkaiden käyttöön kestää usein liian kauan, kun uusia versioita julkaistaan vain kolmen kuukauden välein. Tämä pitkä julkaisusykli rajoittaa tiimin kykyä reagoida nopeasti asiakastarpeisiin ja saattaa johtaa siihen, että asiakkaat joutuvat odottamaan liian kauan haluamiaan parannuksia. CI/CD-putken käyttöönotto auttaa vähentämään näitä viiveitä merkittävästi. Kun uusia versioita voidaan julkaista automaattisesti ja useammin, tiimi voi keskittyä enemmän itse kehitystyöhön ja vähemmän manuaaliseen testaukseen ja julkaisun valmisteluun. Tämä mahdollistaa nopeamman reagoinnin asiakastarpeisiin ja varmistaa, että asiakkaat saavat uudet ominaisuudet ja korjaukset käyttöönsä mahdollisimman pian. Testausta tulisi tapahtua sovelluksen kehityksen aikana eikä vasta lopuksi ulkoisen tiimin toimesta käyttöliittymää klikkailemalla. Jokainen tiimi voisi siirtyä Test-Driven Development (TDD) -malliin, jotta testaus saadaan integroitua tiiviisti kehitysprosessiin ja varmistetaan, että koodi testataan varhaisessa vaiheessa ja säännöllisesti. TDD:n etuna on, että se pakottaa testien kirjoittamisen ennen varsinaisen koodin kirjoittamista, mikä takaa testien integroitumisen tiiviisti kehitysprosessiin. Tämä auttaa havaitsemaan virheet ja ongelmat varhaisessa vaiheessa, mikä voi vähentää testaukseen liittyviä viiveitä.

Lisäksi testit tulisi sisällyttää osaksi CI/CD-putkea. Tämä tarkoittaa, että automatisoidut testit suoritetaan jokaisessa uuden koodin päivityksessä ja ennen uusien versioiden julkaisua. Näin varmistetaan, että koodi testataan jatkuvasti ja mahdolliset virheet havaitaan nopeasti ja voidaan korjata välittömästi. Yhdistämällä TDD ja CI/CD-putki voimme varmistaa korkean laadun ja vakauden sovelluksen kehityksessä ja julkaisussa.

Tehtävä 2

Miten kehittäisit Kurpan sovelluskehitystyön teknisiä käytänteitä sekä laadunhallinnan menetelmiä kurssilla esitettyjä periaatteita noudattaen? Perustele jokainen kehitysehdotuksesi. Älä viittaa tässä vastauksessasi edellisen tehtävän vastaukseesi, tehtävät tarkastaa eri henkilö.

Tehtävän arvioi Matti Luukkainen. Omasta arvioinnista voi tarvittaessa kysyä etunimi.sukunimi@helsinki.fi tai Discordissa

Arvosteluperusteet

Tehtävästä annettiin pisteitä seuraavilla kehitysehdotuksilla:

  • Kaikille yliopistoille yhtenen versionhallinta (0.5p)
  • Jatkuva integraatio käyttöön (1.5p)
    • Koodi integroidaan päähaaraan tiheästi
    • Eritasoista automatisoitua testausta (yksikkö-, integraatio-, järjestelmätestaus)
    • Järkevämpi branchayskäytäntö (joko Trunk-perustainen tai lyhytikäiset featurebranchit)
  • Testauksesta vastuu kehittäjätiimeille (0.5p)
  • Sovelluksen julkaisutavan parantaminen (1.5p)
    • CD-pipelinen käyttö
    • Julkaisu tiimien vastuulle (eli “DevOps”-tiimien eliminointi)
    • Tuotannossa tapahtuva laaduntarkkailu (A/B-testaus, tai canary release)
  • Jatkuva huomio koodin sisäiseen laatuun ja laatusprintin eliminointi (0.5p)
  • Maininta jonkinlaisesta katselmointikäytänteestä (0.5p)
    • joko manuaalinen esim. pull requestit tai automatisoitu kuten Pylint
  • Tiimirakenteen muokkaaminen siten että tiimit ovat cross functional eli monitaitoisia (0.5p)
  • Koodareiden rinnakkaisen työn minimointi (0.5p)
  • Hyvin määritelty Definition of Done (0.5p)
  • Tiimien autonomian kasvatus mm. ohjelmiston arkkitehtuurin suhteen (0.5p)

Lisäksi muista hyvistä ajatuksista saattoi saada pisteitä.

Perustelujen laatu vaikuttaa pisteisiin. Koska tehtävän maksimipistemäärä on 4.5, ei kaikkia yllämainittuja kohtia tarvitse huomioida täysiin pisteisiin päästäkseen.

Tehtävä 3

Kuvitellaan, että ollaan Kurppa-järjestelmän kehityksen alkuvaiheessa. Sinut on nimetty Kurpan product owneriksi. Kirjoita kaksi hyvää user storyä Kurpalle. Saat keksiä niiden kuvaaman toiminnallisuuden itse. Toinen user storyistä on sellainen, että sen kuvaama toiminnallisuus tullaan toteuttamaan seuraavassa sprintissä. Toinen storyistä tullaan toteuttamaan aikaisintaan kahden vuoden päästä.

Perustele, miksi kirjoittamasi storyt ovat hyviä.

Tehtävän arvioi Hannah Leinson. Omasta arvioinnista voi tarvittaessa kysyä etunimi.sukunimi@helsinki.fi tai Discordissa

Arvosteluperusteet

Tehtävässä annettiin seuraavalla tavalla pisteitä:

  • User story 1 seuraavaan sprinttiin (3,7p):
    • Prioriteetiltään korkea story (0,5p)
    • Story on kirjoitettu selkeästi ja asiakkaan kielellä. Ei teknistä jargonia. (0,3p)
    • Hyväksymiskriteerit olemassa. Järkevät storyn suhteen, testattavat. (1p)
    • INVEST mainittu (0,4p)
    • INVEST osa-alueet toteutuvat kirjoitetussa storyssa (1,2p)
    • Tekniset taskit mainittu, taskeihin jako kehittäjätiimin vastuulla (0,3p)
  • User story 2 kahden vuoden päähän (2p):
    • Laajempi story (epiikki tasolla) ja tarkkuudeltaan löyhempi kuin story 1, mutta kuitenkin järkevä. Jos on hyväksymiskriteerit, ne ovat karkeat. (1p)
    • Ei korkean prioriteetin story (esim DEEP kriteerien mukaisesti) (0,3p)
    • Ei estimointia / epämääräinen työmääräarvio (0,2p)
    • Ei vielä testattava (0,2p)
    • Ei INVEST (0,3p)
  • Perustelujen laatu vaikuttaa pisteisiin.

=5,7p / 4,5p. Eli kaikkea ei tarvitse sisällyttää vastaukseen saadakseen täydet pisteet.

Malliratkaisu

Seuraavan sprintin user story:

Oletetaan, että aiemmin on toteutettu sivuston runko ja projektin alustusta. Etusivulla näkyy lista kursseista, jotka ovat tallennettu tietokantaan.

  • Käyttäjänä voin nähdä sivustolla kurssipalautelomakkeen valitsemastani kurssista opiskelijanäkymässä (1 storypoint)

Hyväksymiskriteerit:

  • Sivusto aukeaa verkkosivulle
  • Kurssin nimeä klikkaamalla, pääsen kurssin palautesivulle
  • Palautteenantolomake olemassa, jossa on yksi monivalintakysymys ja yksi vapaa tekstikenttä
  • Lähetä nappi, joka tulostaa ruudulle “Lähetetty”, mutta ei lähetä tietoja eteenpäin.

Hyväksymiskriteerit toteutetaan Robot testeinä. Tekniset taskit ja niiden estimointi keskustellaan kehittäjätiimin kanssa.

Perustelu:

Story on prioriteetiltaan korkealla DEEP:iä noudattavalla backlogilla, ja se otetaan seuraavaan sprinttiin mukaan. Tämän vuoksi storyn täytyy olla tarpeeksi pieni ja noudattaa INVEST periaatteita. Story on lähtöisin isommasta “Opiskelijana voin antaa kurssipalautteen” epiikki-storysta, joka pilkottiin useampaan pieneen (Small) storyyn, jotka ovat itsenäisiä (Independent) toisistaan. Story on tarpeeksi tarkasti määritelty, ja toimii lupauksena (negotiable). Palautelomakkeen näkeminen karkeassa muodossa on arvokasta (valuable) asiakkaalle. Story on estimoitu (Estimable) kehittäjien kanssa verraten edeltävän sprintin storyyn joka vaikutti työmäärältään samalta. Storylle on annettu selkeät hyväksymiskriteerit, jotka toimivat samalla Robot Framework testeinä (Testability).

User story 2, kahden vuoden päähän:

Opettajana voin hyödyntää AI:tä yhdistämään saadut kurssipalautteet yhdeksi helposti tulkittavaksi raportiksi.

Perustelu:

Näin pitkälle tulevaisuuteen määritelty story saa olla laaja epiikin tasoinen. Se on hyvin matalalla prioriteetilla, alhaalla backlogissa DEEP:in mukaisesti. Storya ei tarvitse tämän takia vielä sen tarkemmin määritellä, estimoida taikka tehdä hyväksymiskriteerejä, ja sen ei tarvitse noudattaa INVESTiä.

Tehtävä 4

(a) Aloittelevaa ohjelmoijaa varoitellaan usein siitä, että samaa koodinpätkää ei kannata copypasteta moneen paikkaan yhden ohjelman sisällä. Mikä on syynä tälle ”kiellolle”? Onko olemassa myös tilanteita, joissa copypaste voi olla hyväksyttävää tai jopa kannatettavaa?

(b) Kurssilla puhutaan kahdesta erilaisesta tavasta versionhallinnan hyödyntämiseen: feature branchit ja trunk based development. Kerro, mistä on kyse. Kerro molempien hyvistä ja huonoista puolista.

(c) Ohjelmistossa on käytössä relaatiotietokanta. Lisäksi ohjelmisto hakee säätietoja Ilmatieteen laitoksen avoimesta rajapinnasta. Kerro, miten ohjelmiston automatisoidussa testauksessa tulisi toimia tietokannan ja rajapintojen suhteen.

Tehtävän arvioi Valtteri Kantanen. Omasta arvioinnista voi tarvittaessa kysyä etunimi.sukunimi@helsinki.fi tai Discordissa

Arvosteluperusteet

Tehtävässä sai pisteitä seuraavien asioiden mainitsemisesta:

  • a-kohta (1,5 p.):
    • Yksi perusteltu syy copypasten välttämiselle (0,5 p.)
    • Toinen perusteltu syy copypasten välttämiselle (0,5 p.)
    • Yksi tilanne, jossa copypaste saman ohjelman sisällä voi olla perusteltua (0,5 p.)
  • b-kohta (1,5 p.):
    • Feature branchien perusperiaate (0,25 p.)
    • Vähintään yksi perusteltu hyvä puoli feature branchien käytössä (0,25 p.)
    • Vähintään yksi perusteltu huono puoli feature branchien käytössä (0,25 p.)
    • Trunk based developmentin perusperiaate (0,25 p.)
    • Vähintään yksi perusteltu hyvä puoli trunk based developmentin käytössä (0,25 p.)
    • Vähintään yksi perusteltu huono puoli trunk based developmentin käytössä (0,25 p.)
  • c-kohta (1,5 p.):
    • Kerrottu testitietokannan käyttämisestä (0,25 p.)
    • Kerrottu vähintään yksi perusteltu syy testitietokannan käyttämiselle (0,25 p.)
    • Kerrottu stubien ja/tai mock-olioiden toimintaperiaate (0,25 p.)
      • Jos on mainittu stubien ja/tai mock-olioiden käyttämisestä, mutta ei kerrottu toimintaperiaatteesta, niin 0,125 p.
    • Yksi etu stubien ja/tai mock-olioiden käyttämisessä (0,25 p.)
    • Toinen etu stubien ja/tai mock-olioiden käyttämisessä (0,25 p.)
    • Mainittu eroista yksikkötestauksen ja integraatio- ja järjestelmätestauksen välillä tietokannan ja rajapintojen suhteen (0,25 p.)

Perustelujen laatu vaikuttaa pisteisiin. Kukin alakohta on erillinen, joten yhden alakohdan erinomaisella vastauksella ei voi kompensoida esimerkiksi toisen alakohdan vastauksen puuttumista.

Lähes kaikissa kohdissa hyväksyttiin hyvin monenlaisia vastauksia, kunhan ne olivat perusteltuja. Alla näkyvä malliratkaisu on yksi täydet pisteet tuova tapa vastata tehtävään.

Malliratkaisu

(a) Moneen paikkaan kopioidun koodin käyttö voi olla ongelmallista, jos kopioidun koodin toimintaa joudutaan muuttamaan. Tällöin muutokset pitää muistaa tehdä jokaiseen kohtaan erikseen, mikä hankaloittaa sovelluksen ylläpitoa ja on virhealtista. Jos toiminnallisuus olisi eristetty esimerkiksi omaan funktioonsa, niin riittäisi, että muutos tehdään vain yhteen paikkaan.

Toinen peruste copypasten välttämiselle on se, että runsas copypasten käyttö saattaa kertoa matalasta koheesion asteesta. Tällä tarkoitetaan sitä, että kunkin metodin, luokan tai komponentin tulisi keskittyä tietyn yksittäisen toiminnallisuuden toteuttamiseen. Lähes vastaava periaate on single responsibility -periaate.

Tietyissä tilanteissa copypasten käyttäminen voi kuitenkin olla perusteltua. Esimerkiksi rakennettaessa MVP-versiota (minimum viable product) voidaan copypastea käyttämällä nopeuttaa kehitystä. Tällöin otetaan niin sanottua teknistä velkaa. Jos koodi tulee pysyvään käyttöön, tulisi koodi refaktoroida myöhemmin. Vastaavasti jos koodi ei koskaan päädy tuotantoon, kehittäjät eivät ole joutuneet käyttämään aikaa refaktorointiin.

(b) Feature branchit ovat versionhallinnan menetelmä, jossa muutokset toteutetaan omiin versionhallinnan haaroihinsa (branch). Yksittäinen kehittäjä tai kehittäjätiimi tekee esimerkiksi yhteen user storyyn liittyvät muutokset yhteen haaraan, ja toiminnallisuuden valmistuessa kyseinen haara yhdistetään päähaaraan. Feature branchien hyvä puoli on se, että muutokset pysyvät aina omassa haarassaan ennen yhdistämistä, jolloin päähaara ei voi rikkoutua kehitysvaiheessa feature branchin muutosten vaikutuksesta. Yksi varjopuoli on se, että haarojen yhdistäminen aiheuttaa usein konflikteja. Tämä korostuu erityisesti silloin, kun haarat ovat pitkäikäisiä ja niitä on useita. Konfliktien ratkominen voi olla työlästä ja aikaa vievää: pahimmassa tapauksessa seurauksena voi olla pieni integraatiohelvetti eli merge hell.

Sen sijaan trunk based developmentissa pitkäikäisiä feature brancheja ei käytetä, vaan muutokset tehdään suoraan pääkehityshaaraan (trunk). Julkaistuista versioista saatetaan tehdä oma release branch. Hyvänä puolena on se, että menetelmä pakottaa kehittäjät tekemään pieniä muutoksia, jotka on helppo yhdistää päähaaraan. Näin ollen feature branchien integroimiseen liittyviä ongelmia ei pääse syntymään. Haasteena on kuitenkin se, että kehittäjien tulee olla hyvin kurinalaisia ja systemaattisia, jotta päähaara pysyy jatkuvasti toimivana ja huonoa koodia ei päädy muille kehittäjille.

(c) Ohjelmiston yksikkötestauksessa voidaan hyödyntää tynkäkomponentteja, jotka voivat olla joko stubeja tai mock-olioita. Stubeihin on mahdollista kovakoodata esimerkiksi metodikutsujen paluuarvoja. Mock-olioiden avulla on mahdollista tarkkailla esimerkiksi sitä, kuinka monta kertaa ja millä arvoilla niiden määrittelemiä metodeja on kutsuttu.

Hyvä puoli stubien ja mock-olioiden käyttämisessä on se, että niiden avulla voidaan testata ohjelmiston toimintaa ilman, että testit ovat riippuvaisia ulkoisista tekijöistä (esimerkiksi tietoliikenneyhteyksien toimivuudesta). Tällöin testit ovat helposti toistettavissa ja niiden suorittaminen on nopeampaa. Lisäksi Ilmatieteen laitoksen rajapinnan jatkuvasti muuttuvat säätiedot on helppoa korvata kovakoodatuilla tiedoilla, jolloin voidaan testata laajasti erilaisia tilanteita ja testien tulokset ovat helposti ennustettavissa (toisin kuin jatkuvasti muuttuvat säätiedot).

Integraatio- ja järjestelmätestauksen tarkoituksena on testata yksittäisiä funktioita tai luokkia laajempia kokonaisuuksia. Tällöin testeissä, jotka tarvitsevat tietokantaa, on tärkeää käyttää erillään tuotantotietokannasta olevaa testitietokantaa. Tuotantotietokannan käyttäminen testauksessa voi johtaa esimerkiksi siihen, että testit muokkaavat tai poistavat oikeaa dataa. Samoin testitietokantaa käyttämällä testaaminen helpottuu huomattavasti, koska tietokannan tilaa on helpompi kontrolloida. Testitietokannan tulisi sisältää kattavasti realistista dataa, jotta erilaisia tilanteita voidaan testata mahdollisimman laajasti.

Tehtävä 5

Palataan ajassa hieman taaksepäin. Linkin https://gist.github.com/mluukkai/9093b1b3715b556ce85af32b571fb6de takana on koodia Kurpan kehityksen alkuajoilta. Kehitystiimin velositeetti oli projektin alussa huipputasoa, mutta Kurppamestari on huomannut vauhdin hiljenneen edellisten sprinttien aikana. Syyksi hidastumiseen diagnosoidaan koodiin pesiytynyt tekninen velka.

Refaktoroi koodissa olevaa luokkaa Kurssi sisäiseltä laadultaan paremmaksi soveltaen suunnittelumalleja tai muita tilanteeseen sopivia ratkaisuja.

Tehtävän arvioi Riku Rauhala. Omasta arvioinnista voi tarvittaessa kysyä etunimi.sukunimi@helsinki.fi tai Discordissa

Arvosteluperusteet

Koodin refaktoroinnissa on annettu pisteitä seuraavista asioista:

  • tiedoston käsittely
    • toiminnallisuus siirretty omaan luokkaan (2p)
    • toiminnallisuutta ei ole siirretty, mutta eriytetty metodeihin
      • tiedoston lukeminen tehty omassa metodissa (0.5p)
      • tiedostoon kirjoitus eriytetty metodiin (1p)
  • toisteisuuden eliminointi
    • palautteen hakeminen (1p)
    • yhteenvedon tulostus (1p)
  • muuttujien osuvampi nimeäminen (1p)
    • p -> palaute
    • x, y -> alaraja, ylaraja tms.
    • x -> summa tms.
    • täysiin pisteisiin vaadittu vähintään kahden näistä ottamista huomioon tai järkevää muuttujien nimeämistä mahdollisissa omissa funktioissa/luokissa

Hyvällä yrityksellä voi saada puolikkaan pisteen. Suoraan pisteytettävien asioiden lisäksi muista osuvista parannuksista on saanut maksimissaan yhden pisteen. Mahdollisia lisäansioita ovat esimerkiksi:

  • tyyppiannotaatiot
  • docstring
  • järkevät apufunktiot
  • paranneltu poikkeuskäsittely
  • erillisten luokkien luonti esim. Opiskelija tai Palaute

Jos koodia ei ole korjattu mutta puutteita listattu, on tehtävästä mahdollista saada maksimissaan yksi piste. Tehtävän maksimipistemäärä on 4.5, eli kaiken ei täydy olla täydellistä saadakseen täydet pisteet.

Malliratkaisu

Täydet pisteet tuova ratkaisu voi näyttää esimerkiksi tältä:

class Tiedostonkasittelija:
    def __init__(self, tiedoston_nimi):
        self.__tiedosto = f"{tiedoston_nimi}.csv"

    def lue(self):
        palautteet = []
        try:
            with open(self.__tiedosto, "r") as tiedosto:
                for rivi in tiedosto:
                    osat = rivi.split(";")
                    self.__palautteet.append({
                        "opiskelija": osat[0], 
                        "arvosana": int(osat[1]), 
                        "kommentti": osat[2]
                    })
        except FileNotFoundError:
            print("Tiedostoa ei löydy")
        except Exception:
            pass
        return palautteet

    def tallenna(self, palautteet):
        with open(self.__tiedosto, "w") as tiedosto:
            for palaute in palautteet:
                tiedosto.write(f"{palaute['opiskelija']};{palaute['arvosana']};{palaute['kommentti']};\n")

class Kurssi:
    def __init__(self, nimi, vuosi):
        self.__nimi = nimi
        self.__vuosi = vuosi
        self.__tiedostonkasittelija = Tiedostonkasittelija(nimi)
        self.__palautteet = self.__tiedostonkasittelija.lue()

    def anna_palaute(self, uusi_palaute):
        if self.hae_palaute(uusi_palaute["opiskelija"]):
            return False
        kommentti = uusi_palaute["kommentti"] if "kommentti" in uusi_palaute else ""
        self.__palautteet.append({
            "opiskelija": uusi_palaute["opiskelija"], 
            "arvosana": uusi_palaute["arvosana"], 
            "kommentti": kommentti
        })
        self.__tiedostonkasittelija.tallenna(self.__palautteet)
        return True

    def muuta_palautetta(self, muutettu_palaute):
        palaute = self.hae_palaute(muutettu_palaute["opiskelija"])
        if palaute is None:
            return False
        palaute["arvosana"] = muutettu_palaute["arvosana"]
        palaute["kommentti"] = muutettu_palaute["kommentti"] if "kommentti" in muutettu_palaute else ""
        self.__tiedostonkasittelija.tallenna(self.__palautteet)
        return True

    def hae_palaute(self, opiskelija):
        for palaute in self.__palautteet:
            if palaute["opiskelija"] == opiskelija:
                return palaute
        return None

    def hae_kriteerilla(self, kriteeri):
        return [palaute for palaute in self.__palautteet if kriteeri(palaute)]
    
    def hae_kommentin_sisaltavat_palautteet(self):
        return self.hae_kriteerilla(lambda palaute: len(palaute["kommentti"]) > 0)

    def hae_palautteet_joiden_arvosana(self, arvosana):
        return self.hae_kriteerilla(lambda palaute: palaute["arvosana"] == arvosana)

    def hae_palautteet_joiden_arvosana_valilla(self, alaraja, ylaraja):
        return self.hae_kriteerilla(lambda palaute: palaute["arvosana"] >= alaraja and palaute["arvosana"] <= ylaraja)

    def yhteenveto(self):
        print(f"{self.__nimi}, {self.__vuosi}")
        print("============")
        print("palautteita annettiin", len(self.__palautteet), "kappaletta")

        summa = sum([palaute["arvosana"] for palaute in self.__palautteet])
        
        print("keskiarvo ", summa / len(self.__palautteet))

        print("\njakauma")
        for arvosana in range(5, 0, -1):
            print(f"{arvosana}: {len(self.hae_palautteet_joiden_arvosana(arvosana)) * '*'}")

        print("\nkommentit")
        for palaute in self.__palautteet:
            if len(palaute["kommentti"]) > 0:
                print("  " + palaute["kommentti"])