Ohjelmistotuotanto

Oppilasrekisteriesimerkki

Tämä esimerkki näyttää, miten oppilasrekisterin toiminnallinen määrittely etenee tekniseksi määrittelyksi. Samalla se havainnollistaa, miten kaavioita tehdään Mermaidilla. Kuvattu sovellus on tarkoituksella yksinkertaistettu, jotta määrittelyjen ja kaavioiden yhteys on helppo nähdä. Tässä esimerkissä tarkastelu rajataan opiskelijan käyttämiin toimintoihin.

Sivua voi käyttää myös oman määrittelyn oppaana: kuvaa ensin tarve ja vaatimukset, havainnollista niitä sopivilla kaavioilla ja suunnittele vasta sitten toteutus. Kaikki projektit eivät tarvitse kaikkia tässä esitettyjä kaavioita. Valitse ne, jotka auttavat ymmärtämään juuri oman järjestelmäsi toimintaa tai rakennetta. Kaavioiden Mermaid-koodit voi avata niiden alta.

Dokumenttien otsikointi

Vaatimusmäärittelylle ja tekniselle määrittelylle ei ole yhtä kaikkialla käytettyä alaotsikkorakennetta. Organisaatiolla, asiakkaalla tai oppilaitoksella voi olla oma dokumenttipohjansa. Tässä esitetty otsikointi on yksi mahdollinen tapa jäsentää sisältö. Sovella rakennetta projektin tarpeisiin ja mahdolliseen annettuun dokumenttipohjaan. Olennaista on, että tarvittavat asiat kuvataan selkeästi ja ristiriidattomasti.

Tässä ohjelmoijien opetukseen tarkoitetussa oppaassa käytetään myös kaavioiden nimiä otsikkoina, jotta kaaviotyypit ja niiden esimerkit löytyvät helposti. Samalla opit yhdistämään kaavion nimen sen tarkoitukseen. Voit käyttää omassa dokumentissasi samaa tapaa tai nimetä luvut käsiteltävän asian mukaan. Otsikkoa voi myös täsmentää, esimerkiksi ”Käyttöönottokaavio : sovelluksen sijoittuminen”, ”Viestiyhteyskaavio : kirjautuminen” tai ”Luokkakaavio : Qt-sovelluksen rakenne”.

Kerro kaavion yhteydessä lyhyesti, mitä se kuvaa juuri tässä järjestelmässä, ja selitä tarvittavat ratkaisut ja perustelut. Kaikkien alaotsikoiden ei tarvitse olla kaavioiden nimiä: esimerkiksi tavoitteet ja rajaus, hyväksymiskriteerit sekä rajapintojen kuvaukset tarvitsevat myös sanallista käsittelyä.

Kaavioiden selitteet ja toimintojen kuvaukset ovat suomeksi. Toteutuksen tunnisteet, kuten luokkien, moduulien, muuttujien, metodien ja tietokantataulujen nimet, ovat englanniksi. Myös Mermaid-koodin tunnisteet ovat englanniksi, vaikka kaaviossa näkyvä selite olisi suomeksi.

> Muistutus: Määrittelyvaiheessa kerrotaan, MITÄ tehdään, ja suunnitteluvaiheessa, MITEN tehdään.

Määrittelyvaihe (Vaatimusmäärittely)

Toiminnallinen määrittely kuvaa asiakkaan ja käyttäjän näkökulmasta, mitä järjestelmän pitää tehdä. Tässä vaiheessa kuvataan toiminnot ja käyttöliittymän perusidea ilman teknisiä toteutusvalintoja.

Vaatimusmäärittely on tätä laajempi kokonaisuus: siihen kuuluvat myös tavoitteet, rajaus, käyttöoikeudet, laatuvaatimukset ja hyväksymiskriteerit. Kaaviot täydentävät sanallisia vaatimuksia. Ne eivät yksin kerro esimerkiksi sitä, kuka saa nähdä henkilötiedot tai miten onnistunut toteutus todetaan.

Tavoite, käyttäjät ja rajaus

Aloita kertomalla, mikä ongelma ratkaistaan ja keitä ratkaisu palvelee. Tämän esimerkin tavoitteena on, että opiskelija voi tarkistaa omat tietonsa ja ilmoittautua kursseille itsenäisesti. Käyttäjä on opiskelija ja oppilaitos puolestaan määrittelee, mitä tietoja ja kursseja palvelussa tarjotaan.

Tässä rajauksessa mukana ovat kirjautuminen, uloskirjautuminen, istunnon vanheneminen, omien henkilötietojen ja arvosanojen katselu sekä kurssille ilmoittautuminen. Arvosanojen syöttäminen, opiskelijatietojen ylläpito ja maksaminen jäävät esimerkin ulkopuolelle. Oletuksena on, että opiskelija-, kurssi- ja suoritustiedot ovat jo olemassa. Kirjaa vastaavat oletukset omaan määrittelyysi ja varmista ne tilaajalta.

Vaatimukset ja hyväksymiskriteerit

Anna tärkeille vaatimuksille tunnisteet, jotta niihin voi viitata suunnittelussa ja testauksessa. Kirjoita jokainen vaatimus niin täsmällisesti, että sen toteutuminen voidaan todentaa. Hyväksymiskriteeri kertoo, millä havaittavalla tuloksella vaatimus katsotaan täytetyksi.

  • V-01: Opiskelija saa nähdä vain omat arvosanansa. Hyväksymiskriteeri: kirjautunut opiskelija näkee omat suorituksensa, eikä toisen opiskelijan tietojen pyytäminen palauta tämän arvosanoja.
  • V-02: Opiskelija voi ilmoittautua tarjolla olevalle kurssille. Hyväksymiskriteeri: onnistunut ilmoittautuminen tallentuu ja opiskelija saa vahvistuksen mutta tallennuksen epäonnistuessa näytetään virheilmoitus.
  • V-03: Opiskelija voi kirjautua oikeilla tunnuksilla. Hyväksymiskriteeri: hyväksytyt tunnukset avaavat opiskelijan valikon ja hylätyt tunnukset tai tarkistuksen epäonnistuminen näyttävät virheilmoituksen ja mahdollistavat uuden yrityksen avaamatta suojattuja toimintoja.
  • V-04: Opiskelija voi kirjautua ulos. Hyväksymiskriteeri: uloskirjautuminen poistaa käyttöliittymästä opiskelijan tiedot ja palauttaa kirjautumisnäkymään. Suojattujen toimintojen käyttö sovelluksessa vaatii uuden kirjautumisen.
  • V-05: Istunto on voimassa rajatun ajan. Hyväksymiskriteeri: sovitun voimassaoloajan päätyttyä suojattu tietopyyntö hylätään ja käyttöliittymä pyytää kirjautumaan uudelleen viimeistään seuraavan suojatun toiminnon yhteydessä. Voimassaoloaika ja sen laskentaperuste sovitaan tilaajan kanssa ennen toteutusta.
  • L-01: Arvosanojen katselun tulee olla riittävän nopeaa. Esimerkki mitattavasta tavoitteesta: vähintään 95 prosenttia arvosanahauista valmistuu kahdessa sekunnissa 50 samanaikaisen käyttäjän testissä. Kuormitus, tietomäärä ja mittausympäristö sovitaan ennen testausta.

Laatuvaatimuksia voivat olla myös käytettävyys, saavutettavuus ja saatavuus. Valitse projektillesi olennaiset vaatimukset ja sovi niiden tärkeys tilaajan kanssa. Yllä olevat tavoitteet ovat opetusesimerkin valintoja, eivät kaikkien järjestelmien yleisiä raja-arvoja.

Järjestelmän toiminnan kuvaus

Sovellukseen toteutetaan seuraavat toiminnot:

  • Voidakseen katsoa henkilötietonsa opiskelijan on kirjauduttava sovellukseen.
  • Voidakseen katsoa arvosanansa opiskelijan on kirjauduttava sovellukseen.
  • Voidakseen ilmoittautua kurssille opiskelijan on kirjauduttava sovellukseen.
  • Jos kirjautuminen onnistuu, opiskelijalle avautuu valikko, josta hän voi valita henkilötietojen katselun, arvosanojen katselun tai kurssille ilmoittautumisen.
  • Kirjautumisen tarkistuksen aikana odotetaan tulosta eikä suojattuja toimintoja voi käyttää.
  • Mikäli kirjautuminen ei onnistu tai tarkistus epäonnistuu esimerkiksi yhteysvirheen vuoksi, näytetään virheilmoitus ja palataan kirjautumisruudulle.
  • Opiskelija voi kirjautua ulos, jolloin hänen tietonsa poistetaan käyttöliittymästä ja palataan kirjautumisruudulle.
  • Istunnon vanhennuttua suojattuja toimintoja ei voi käyttää. Käyttöliittymä poistaa opiskelijan tiedot näkyvistä ja pyytää kirjautumaan uudelleen viimeistään seuraavan suojatun toiminnon yhteydessä.

Käyttöönottokaavio

Tämä yleistasoinen kaavio näyttää, että opiskelija käyttää oppilasrekisteriä omalla laitteellaan verkkoyhteyden kautta. Se ei vielä määrittele sovelluksen toteutusteknologioita eikä palveluympäristön sisäistä rakennetta. Kaavio on havainnollistettu Mermaidin vuokaaviosyntaksilla.

flowchart LR
    subgraph StudentDevice["Opiskelijan laite"]
        UserInterface["Oppilasrekisterin käyttöliittymä"]
    end

    subgraph ServiceEnvironment["Palveluympäristö"]
        RegistryService["Oppilasrekisteri"]
    end

    UserInterface <-->|"Verkkoyhteys"| RegistryService
Näytä Mermaid-koodiPiilota Mermaid-koodi
```mermaid
flowchart LR
    subgraph StudentDevice["Opiskelijan laite"]
        UserInterface["Oppilasrekisterin käyttöliittymä"]
    end

    subgraph ServiceEnvironment["Palveluympäristö"]
        RegistryService["Oppilasrekisteri"]
    end

    UserInterface <-->|"Verkkoyhteys"| RegistryService
```

Käyttötapauskaavio

Käyttötapauskaavio kokoaa käyttäjän tavoitteet ja järjestelmän tarjoamat toiminnot. Aloita tunnistamalla käyttäjäroolit ja se, mitä kukin haluaa saada aikaan. Tarkemmat etenemisvaiheet ja poikkeukset kuvataan käyttötapauskorteissa.

usecase-beta
    direction LR
    actor Student("Opiskelija")
    systemBoundary Application["Oppilasrekisteri"]
        Login("Kirjaudu sisään")
        ViewInfo("Katso henkilötiedot")
        ViewGrades("Katso arvosanat")
        RegisterCourse("Ilmoittaudu kurssille")
        Logout("Kirjaudu ulos")
    end

    Student --> Login
    Student --> ViewInfo
    Student --> ViewGrades
    Student --> RegisterCourse
    Student --> Logout
    ViewInfo ..> : include Login
    ViewGrades ..> : include Login
    RegisterCourse ..> : include Login
Näytä Mermaid-koodiPiilota Mermaid-koodi
```mermaid
usecase-beta
    direction LR
    actor Student("Opiskelija")
    systemBoundary Application["Oppilasrekisteri"]
        Login("Kirjaudu sisään")
        ViewInfo("Katso henkilötiedot")
        ViewGrades("Katso arvosanat")
        RegisterCourse("Ilmoittaudu kurssille")
        Logout("Kirjaudu ulos")
    end

    Student --> Login
    Student --> ViewInfo
    Student --> ViewGrades
    Student --> RegisterCourse
    Student --> Logout
    ViewInfo ..> : include Login
    ViewGrades ..> : include Login
    RegisterCourse ..> : include Login
```

Viestiyhteyskaavio

Kaavio näyttää kirjautumisen ja sitä seuraavan toimintovalinnan opiskelijan näkökulmasta. Oppilasrekisteri esitetään yhtenä kokonaisuutena, joten kaavio ei vielä ota kantaa käyttöliittymän, rajapinnan tai tietojen tallennuksen toteutukseen. Viestiyhteyskaavio näyttää, mitä viestejä osapuolet lähettävät toisilleen tapahtumien aikana.

sequenceDiagram
    actor Student as Opiskelija
    participant Registry as Oppilasrekisteri

    Student->>Registry: Kirjautuu
    alt Kirjautuminen onnistuu
        Registry-->>Student: Näyttää valikon
        alt Henkilötietojen katselu
            Student->>Registry: Valitsee henkilötiedot
            Registry-->>Student: Näyttää henkilötiedot
        else Arvosanojen katselu
            Student->>Registry: Valitsee arvosanat
            Registry-->>Student: Näyttää arvosanat
        else Kurssille ilmoittautuminen
            Student->>Registry: Valitsee kurssin ja ilmoittautuu
            Registry-->>Student: Näyttää vahvistuksen
        end
    else Kirjautuminen epäonnistuu
        Registry-->>Student: Näyttää kirjautumisen uudelleen
    end
Näytä Mermaid-koodiPiilota Mermaid-koodi
```mermaid
sequenceDiagram
    actor Student as Opiskelija
    participant Registry as Oppilasrekisteri

    Student->>Registry: Kirjautuu
    alt Kirjautuminen onnistuu
        Registry-->>Student: Näyttää valikon
        alt Henkilötietojen katselu
            Student->>Registry: Valitsee henkilötiedot
            Registry-->>Student: Näyttää henkilötiedot
        else Arvosanojen katselu
            Student->>Registry: Valitsee arvosanat
            Registry-->>Student: Näyttää arvosanat
        else Kurssille ilmoittautuminen
            Student->>Registry: Valitsee kurssin ja ilmoittautuu
            Registry-->>Student: Näyttää vahvistuksen
        end
    else Kirjautuminen epäonnistuu
        Registry-->>Student: Näyttää kirjautumisen uudelleen
    end
```

Tilakaavio

Tilakaavio kuvaa yhden kohteen mahdolliset tilat ja tapahtumat, jotka siirtävät sen tilasta toiseen. Samasta sovelluksesta voidaan laatia useita tilakaavioita eri kohteille. Laadi kaavioita tarpeen mukaan ja kerro kunkin yhteydessä, mitä kohdetta se kuvaa.

Tässä kohteena on käyttäjän kirjautuminen ja istunto: opiskelija on joko kirjautumatta, odottaa kirjautumisen tarkistusta tai on kirjautunut. Tilakaavio täydentää vaatimuksia V-03–V-05.

Tilojen nimet kertovat tilanteen ja nuolten tekstit siirtymän aiheuttavan tapahtuman. Musta alkupiste osoittaa alkutilan. Lopputilaa ei tarvita, koska opiskelija voi kirjautua uudelleen. Henkilötietojen katselu, arvosanojen katselu ja kurssille ilmoittautuminen tapahtuvat Kirjautunut-tilassa, mutta näkymän vaihtaminen ei itsessään muuta kirjautumisen tilaa.

stateDiagram-v2
    state "Ei kirjautunut" as LoggedOut
    state "Kirjautuminen<br/>tarkistetaan" as CheckingLogin
    state "Kirjautunut" as LoggedIn

    [*] --> LoggedOut
    LoggedOut --> CheckingLogin: Opiskelija lähettää tunnukset
    CheckingLogin --> LoggedIn: Tunnukset hyväksytään
    CheckingLogin --> LoggedOut: Tunnukset hylätään
    CheckingLogin --> LoggedOut: Tarkistus epäonnistuu
    LoggedIn --> LoggedOut: Opiskelija kirjautuu ulos
    LoggedIn --> LoggedOut: Istunnon voimassaoloaika päättyy
Näytä Mermaid-koodiPiilota Mermaid-koodi
```mermaid
stateDiagram-v2
    state "Ei kirjautunut" as LoggedOut
    state "Kirjautuminen<br/>tarkistetaan" as CheckingLogin
    state "Kirjautunut" as LoggedIn

    [*] --> LoggedOut
    LoggedOut --> CheckingLogin: Opiskelija lähettää tunnukset
    CheckingLogin --> LoggedIn: Tunnukset hyväksytään
    CheckingLogin --> LoggedOut: Tunnukset hylätään
    CheckingLogin --> LoggedOut: Tarkistus epäonnistuu
    LoggedIn --> LoggedOut: Opiskelija kirjautuu ulos
    LoggedIn --> LoggedOut: Istunnon voimassaoloaika päättyy
```

Käyttötapauskortit

Kustakin olennaisesta käyttötapauksesta laaditaan yleensä oma käyttötapauskortti, jossa kuvataan toiminnon tavoite, eteneminen ja poikkeukset tarkemmin kuin käyttötapauskaaviossa. Tässä esitetään malliksi vain yksi kortti, joka vastaa kaavion "Ilmoittaudu kurssille" -käyttötapausta.

TUNNISTE KT-0001 VERSIO 1.0
NIMI Ilmoittaudu kurssille
SUORITTAJAT Opiskelija, oppilasrekisteri
TAVOITE Opiskelija ilmoittautuu valitsemalleen kurssille.
ESIEHDOT Opiskelija on kirjautunut sovellukseen ja järjestelmässä on ilmoittautumiseen tarjolla oleva kurssi.
KUVAUS 1. Opiskelija valitsee valikosta kurssille ilmoittautumisen.
2. Järjestelmä näyttää ilmoittautumiseen tarjolla olevat kurssit.
3. Opiskelija valitsee kurssin ja painaa Ilmoittaudu-painiketta.
4. Järjestelmä tallentaa opiskelijan ilmoittautumisen. (P1)
5. Järjestelmä näyttää vahvistuksen ilmoittautumisesta.
LOPPUEHDOT Ilmoittautuminen on tallennettu ja opiskelija on saanut vahvistuksen.
POIKKEUKSET P1: Tallennus epäonnistuu – järjestelmä ilmoittaa virheestä eikä näytä onnistumisvahvistusta.
AVOIMET ASIAT Voiko opiskelija perua ilmoittautumisensa myöhemmin?

Käyttöliittymän hahmotelma

Käyttötapausten pohjalta voidaan luonnostella sovelluksen näkymät. Onnistunut kirjautuminen avaa StudentInfo-valikon, josta opiskelija siirtyy haluamaansa toimintoon. Epäonnistuneen kirjautumisen jälkeen pysytään Login-näkymässä. Uloskirjautuminen palauttaa Login-näkymään. Myös vanhentuneen istunnon havaitseminen palauttaa tähän näkymään ja poistaa aiemmin näytetyt opiskelijan tiedot.

Mermaid ei sovellu varsinaisten käyttöliittymänäkymien luonnosteluun, vaikka sillä voi kuvata näkymien välisen kulun. Luonnokset voi piirtää esimerkiksi Excalidrawilla osoitteessa https://excalidraw.com/ ja ladata PNG- tai SVG-kuvatiedostoina. Alla olevat esimerkkinäkymät on hahmoteltu HTML:llä ja CSS:llä.

Näkymät ovat karkeita luonnoksia. Kentät ja painikkeet näyttävät suunnitellun sisällön ja kulun.

Login

Kirjaudu sisään
Opiskelijatunnus
opiskelija123
Salasana
••••••••
Kirjaudu

Virheellinen kirjautuminen palauttaa tähän näkymään.

StudentInfo

Opiskelijan valikko

Valitse, mitä haluat tehdä:

Omat tiedot → MyData
Kurssisuoritukset → MyGrades
Ilmoittaudu kurssille → EnrollToCourse
Kirjaudu ulos

MyData

Omat henkilötiedot
NimiEsimerkki Opiskelija
Opiskelijatunnusopiskelija123
Sähköpostiesimerkki@oppilaitos.fi
← Takaisin valikkoon

MyGrades

Kurssisuoritukset
KurssiArvosana
Ohjelmoinnin perusteet4
Tietokannat5
← Takaisin valikkoon

EnrollToCourse

Ilmoittaudu kurssille
OhjelmistotuotantoIlmoittaudu
VerkkopalvelutIlmoittaudu

Onnistunut ilmoittautuminen vahvistetaan tässä näkymässä.

← Takaisin valikkoon

Vaatimusmäärittelyn tarkistuslista

  • Ymmärtääkö tilaaja järjestelmän tavoitteen, käyttäjät ja rajauksen?
  • Onko tärkeimmille toiminnoille kuvattu onnistuminen, poikkeukset ja käyttöoikeudet?
  • Ovatko laatuvaatimukset ja hyväksymiskriteerit todennettavissa?
  • Kuvaavatko teksti, käyttötapauskortit ja kaaviot samaa toimintaa?
  • Onko avoimille asioille sovittu selvittäjä? Esimerkiksi ilmoittautumisen peruminen on vielä ratkaistava ennen sen toteuttamista.
Suunnitteluvaihe (Tekninen määrittely)

Tekninen määrittely kuvaa, miten toiminnallisessa määrittelyssä kuvatut toiminnot toteutetaan. Tässä esimerkissä valitaan sovelluksen osat, niiden välinen viestintä, luokkarakenne ja tietokannan rakenne.

Vaatimuksesta tekniseksi ratkaisuksi

Pidä vaatimusten tunnisteet mukana suunnittelussa. Näin toteutusratkaisulle löytyy peruste ja jokaiselle vaatimukselle voidaan suunnitella testi. Esimerkiksi vaatimus V-01 tarkentuu seuraavasti:

  • Vastuu: REST-rajapinta tarkistaa opiskelijan henkilöllisyyden ja oikeuden tietoihin jokaisella arvosanahaulla.
  • Rajapinta: GET /api/me/grades palauttaa kirjautuneen opiskelijan suoritukset. Opiskelijan tunniste johdetaan palvelimella varmennetusta tunnisteesta, eikä asiakkaan lähettämää opiskelijatunnusta käytetä käyttöoikeuden perusteena.
  • Tietojen haku: GradeModel rajaa parametrisoidun tietokantahaun tunnistetun opiskelijan tietoihin.
  • Virhetilanne: puuttuva tai virheellinen kirjautumistunniste tuottaa HTTP 401 -vastauksen. Käyttöliittymä pyytää kirjautumaan uudelleen.
  • Todentaminen: testissä käytetään kahta opiskelijaa ja varmistetaan, ettei toinen saa toisen arvosanoja myöskään muokkaamalla pyyntöä.

Tämä tarkentaa jäljempänä esitettyjä yleistasoisia kaavioita. Kuvaa omassa teknisessä määrittelyssäsi myös rajapintojen pyyntöjen ja vastausten tietosisältö sekä muut olennaiset virhevastaukset. Pelkkä nuoli osien välillä ei vielä määrittele niiden välistä sopimusta.

Vaatimusmäärittelyn tilakaavio ohjaa myös kirjautumisen teknistä toteutusta. Vaatimuksen V-03 mukaisesti Qt-käyttöliittymä odottaa kirjautumispyynnön vastausta ja avaa StudentInfo-näkymän vasta onnistuneen vastauksen jälkeen. Hylätyt tunnukset, yhteysvirhe tai pyynnön aikakatkaisu palauttavat kirjautumisnäkymän tilaan, jossa opiskelija voi yrittää uudelleen. Vaatimuksen V-04 mukaisesti uloskirjautuminen poistaa asiakkaan muistista kirjautumistunnisteen ja opiskelijan tiedot sekä sulkee suojatut näkymät. Vaatimuksen V-05 mukaisesti palvelin tarkistaa kirjautumistunnisteen voimassaolon jokaisella suojatulla pyynnöllä. Vanhentunut tunniste tuottaa HTTP 401 -vastauksen, jolloin käyttöliittymä tyhjentää kirjautumistiedot ja palaa Login-näkymään. Täsmennä teknisessä määrittelyssä tunnisteen voimassaoloaika sovitun vaatimuksen mukaan sekä se, miten tunniste mitätöidään palvelimella, jos uloskirjautumisen halutaan estävän myös aiemmin kopioidun tunnisteen käytön.

Ratkaisujen valinta ja perustelut

Kirjaa keskeisistä ratkaisuista, mitä valittiin ja miksi. Tässä Qt-asiakas ja Node.js-rajapinta ovat opetusesimerkin teknologiavalintoja. Rajapinta keskittää käyttöoikeuksien tarkistamisen palvelimelle, ja relaatiotietokanta sopii opiskelijoiden, kurssien ja ilmoittautumisten välisten suhteiden tallentamiseen. Omassa projektissa perusteluja voivat olla myös kohdeympäristö, ylläpidettävyys ja tiimin osaaminen.

Sovi lisäksi tietojen validointi, virheiden käsittely ja tallennuksen eheys. Jos samalle kurssille saa ilmoittautua vain kerran, sääntö pitää ensin hyväksyä vaatimukseksi ja sen jälkeen toteuttaa esimerkiksi opiskelijan ja kurssin yhdistelmän yksikäsitteisyysrajoitteella. Tekninen ratkaisu ei saa huomaamatta päättää käyttäjää koskevaa toimintasääntöä.

Käyttöönottokaavio

Käyttöönottokaavio näyttää, missä laitteissa sovelluksen osat toimivat ja miten ne ovat yhteydessä toisiinsa. Asiakassovellus toteutetaan C++:lla ja Qt:lla, REST-rajapinta Node.js:llä ja Expressillä. Tiedot tallennetaan MySQL-tietokantaan. Kaavio on havainnollistettu Mermaidin vuokaaviosyntaksilla.

flowchart LR
    subgraph ClientMachine["Asiakkaan laite"]
        QtApp["Qt-sovellus (C++)"]
    end

    subgraph Server["Palvelin"]
        RestAPI["REST-rajapinta (Node.js / Express)"]
        Database[("StudentDb (MySQL)")]
    end

    QtApp <-->|"HTTPS / JSON"| RestAPI
    RestAPI <-->|"MySQL-protokolla"| Database
Näytä Mermaid-koodiPiilota Mermaid-koodi
```mermaid
flowchart LR
    subgraph ClientMachine["Asiakkaan laite"]
        QtApp["Qt-sovellus (C++)"]
    end

    subgraph Server["Palvelin"]
        RestAPI["REST-rajapinta (Node.js / Express)"]
        Database[("StudentDb (MySQL)")]
    end

    QtApp <-->|"HTTPS / JSON"| RestAPI
    RestAPI <-->|"MySQL-protokolla"| Database
```

Komponenttikaavio (yksinkertaistettu)

Qt-sovellus ja REST-rajapinta voidaan tässä tulkita ohjelmiston pääkomponenteiksi. MySQL-laatikko kuvaa niiden käyttämää tietokantaa, joka ei itsessään ole ohjelmistokomponentti. Sisäiset laatikot kuvaavat esimerkiksi näkymiä ja moduuleja. Mermaidin vuokaaviosyntaksilla tehty kuva havainnollistaa osien riippuvuuksia, mutta ei noudata UML-komponenttikaavion merkintöjä täsmällisesti.

Toteutuksessa on valittu MVC-mallia mukaileva työnjako: Qt-sovellus toteuttaa näkymät (View), Express.js-rajapinnan reittien käsittelijät hoitavat ohjaimen tehtävät (Controller) ja StudentModel-, GradeModel- ja CourseModel-moduulit vastaavat tietojen käsittelystä (Model). Näkymät sijaitsevat erillisessä Qt-asiakassovelluksessa.

flowchart TD
    subgraph frontend["Qt-käyttöliittymä"]
        MainWindow["MainWindow"]
        Login_Qt["Login"]
        StudentInfo_Qt["StudentInfo"]
        MyData_Qt["MyData"]
        MyGrades_Qt["MyGrades"]
        EnrollToCourse_Qt["EnrollToCourse"]
        MainWindow --> Login_Qt
        Login_Qt --> StudentInfo_Qt
        StudentInfo_Qt --> MyData_Qt
        StudentInfo_Qt --> MyGrades_Qt
        StudentInfo_Qt --> EnrollToCourse_Qt
    end

    subgraph backend["REST-rajapinta"]
        RouteLogin["RouteLogin"]
        RouteStudent["RouteStudent"]
        RouteGrade["RouteGrade"]
        RouteCourse["RouteCourse"]
        Student_model["StudentModel"]
        Grade_model["GradeModel"]
        Course_model["CourseModel"]
        DatabaseJs["database.js"]
        RouteLogin --> Student_model
        RouteStudent --> Student_model
        RouteGrade --> Grade_model
        RouteCourse --> Course_model
        Student_model --> DatabaseJs
        Grade_model --> DatabaseJs
        Course_model --> DatabaseJs
    end

    subgraph mysql["MySQL-tietokanta"]
        studentdb[("studentdb")]
    end

    Login_Qt -->|"HTTPS"| RouteLogin
    MyData_Qt -->|"HTTPS"| RouteStudent
    MyGrades_Qt -->|"HTTPS"| RouteGrade
    EnrollToCourse_Qt -->|"HTTPS"| RouteCourse
    DatabaseJs --> studentdb
Näytä Mermaid-koodiPiilota Mermaid-koodi
```mermaid
flowchart TD
    subgraph frontend["Qt-käyttöliittymä"]
        MainWindow["MainWindow"]
        Login_Qt["Login"]
        StudentInfo_Qt["StudentInfo"]
        MyData_Qt["MyData"]
        MyGrades_Qt["MyGrades"]
        EnrollToCourse_Qt["EnrollToCourse"]
        MainWindow --> Login_Qt
        Login_Qt --> StudentInfo_Qt
        StudentInfo_Qt --> MyData_Qt
        StudentInfo_Qt --> MyGrades_Qt
        StudentInfo_Qt --> EnrollToCourse_Qt
    end

    subgraph backend["REST-rajapinta"]
        RouteLogin["RouteLogin"]
        RouteStudent["RouteStudent"]
        RouteGrade["RouteGrade"]
        RouteCourse["RouteCourse"]
        Student_model["StudentModel"]
        Grade_model["GradeModel"]
        Course_model["CourseModel"]
        DatabaseJs["database.js"]
        RouteLogin --> Student_model
        RouteStudent --> Student_model
        RouteGrade --> Grade_model
        RouteCourse --> Course_model
        Student_model --> DatabaseJs
        Grade_model --> DatabaseJs
        Course_model --> DatabaseJs
    end

    subgraph mysql["MySQL-tietokanta"]
        studentdb[("studentdb")]
    end

    Login_Qt -->|"HTTPS"| RouteLogin
    MyData_Qt -->|"HTTPS"| RouteStudent
    MyGrades_Qt -->|"HTTPS"| RouteGrade
    EnrollToCourse_Qt -->|"HTTPS"| RouteCourse
    DatabaseJs --> studentdb
```

Määrittelyvaiheessa laadittuja kaavioita ja luonnoksia voidaan joutua tarkentamaan suunnitteluvaiheessa. Määrittelyvaiheen viestiyhteyskaavio kuvaa opiskelijan ja oppilasrekisterin vuorovaikutusta yleisellä tasolla. Seuraavassa kaaviossa sama tapahtumakulku tarkentuu käyttöliittymän, rajapinnan ja tietokannan välisiksi viesteiksi. Myös käyttötapauskaavio ja käyttötapauskortti toimivat teknisen suunnittelun lähtökohtina.

Viestiyhteyskaavio

Viestiyhteyskaavio näyttää kirjautumisen ja opiskelijan toimintovalinnan etenemisen käyttöliittymän, REST-rajapinnan ja tietokannan välillä. Näin määrittelyvaiheen yleistasoinen kuvaus tarkentuu tekniseksi viestinnäksi.

sequenceDiagram
    actor Student as Opiskelija
    participant UI as Käyttöliittymä
    participant API as REST-rajapinta
    participant DB as Tietokanta

    Student->>UI: Syöttää tunnukset
    UI->>API: Lähettää kirjautumispyynnön
    API->>DB: Tarkistaa tunnukset
    DB-->>API: Tarkistuksen tulos
    alt Kirjautuminen onnistuu
        API-->>UI: Kirjautumistunniste
        UI-->>Student: Näyttää valikon
        alt Henkilötietojen katselu
            Student->>UI: Valitsee henkilötiedot
            UI->>API: Pyytää henkilötiedot
            API->>DB: Hakee henkilötiedot
            DB-->>API: Henkilötiedot
            API-->>UI: Henkilötiedot
            UI-->>Student: Näyttää henkilötiedot
        else Arvosanojen katselu
            Student->>UI: Valitsee arvosanat
            UI->>API: Pyytää arvosanat
            API->>DB: Hakee arvosanat
            DB-->>API: Arvosanat
            API-->>UI: Arvosanat
            UI-->>Student: Näyttää arvosanat
        else Kurssille ilmoittautuminen
            Student->>UI: Valitsee kurssille ilmoittautumisen
            UI->>API: Pyytää ilmoittautumista
            API->>DB: Tallentaa opiskelijan ilmoittautumisen kurssille
            DB-->>API: Vahvistus
            API-->>UI: Vahvistus
            UI-->>Student: Näyttää vahvistuksen
        end
    else Kirjautuminen epäonnistuu
        API-->>UI: Kirjautuminen epäonnistui
        UI-->>Student: Näyttää kirjautumislomakkeen uudelleen
    end
Näytä Mermaid-koodiPiilota Mermaid-koodi
```mermaid
sequenceDiagram
    actor Student as Opiskelija
    participant UI as Käyttöliittymä
    participant API as REST-rajapinta
    participant DB as Tietokanta

    Student->>UI: Syöttää tunnukset
    UI->>API: Lähettää kirjautumispyynnön
    API->>DB: Tarkistaa tunnukset
    DB-->>API: Tarkistuksen tulos
    alt Kirjautuminen onnistuu
        API-->>UI: Kirjautumistunniste
        UI-->>Student: Näyttää valikon
        alt Henkilötietojen katselu
            Student->>UI: Valitsee henkilötiedot
            UI->>API: Pyytää henkilötiedot
            API->>DB: Hakee henkilötiedot
            DB-->>API: Henkilötiedot
            API-->>UI: Henkilötiedot
            UI-->>Student: Näyttää henkilötiedot
        else Arvosanojen katselu
            Student->>UI: Valitsee arvosanat
            UI->>API: Pyytää arvosanat
            API->>DB: Hakee arvosanat
            DB-->>API: Arvosanat
            API-->>UI: Arvosanat
            UI-->>Student: Näyttää arvosanat
        else Kurssille ilmoittautuminen
            Student->>UI: Valitsee kurssille ilmoittautumisen
            UI->>API: Pyytää ilmoittautumista
            API->>DB: Tallentaa opiskelijan ilmoittautumisen kurssille
            DB-->>API: Vahvistus
            API-->>UI: Vahvistus
            UI-->>Student: Näyttää vahvistuksen
        end
    else Kirjautuminen epäonnistuu
        API-->>UI: Kirjautuminen epäonnistui
        UI-->>Student: Näyttää kirjautumislomakkeen uudelleen
    end
```

Luokkakaavio

Seuraavat kaaviot kuvaavat valittuja toteutuksen osia, niiden tietoja, toimintoja ja välisiä suhteita. Ne eivät esitä sovelluksen koko rakennetta.

REST API:n luokkakaavio

Edellä kuvattu MVC-mallia mukaileva työnjako näkyy reitti- ja Model-moduulien välisinä riippuvuuksina. Express-rajapinnan voi toteuttaa myös luokilla, mutta reitit ja väliohjelmistot rakennetaan usein funktioista ja moduuleista. Siksi tämä luokkakaavion merkintöjä käyttävä kuva havainnollistaa osien vastuita ja riippuvuuksia eikä vastaa yksi yhteen koodin luokkia. Esimerkiksi database.js on moduuli, joka vie connection-yhteysaltaan StudentModelin ja GradeModelin käyttöön. Qt-sovelluksen lomakkeet puolestaan on tässä mallinnettu C++-luokkina, joten niiden luokkakaavio vastaa suoremmin toteutuksen rakennetta.

classDiagram
    class App {
        -router: Router
        +authenticateToken(request, response, next) void
        +use(root) void
        +use(login) void
        +use(student) void
        +use(grade) void
    }

    class RouteLogin {
        -router: Router
        -bcrypt: bcryptjs
        -jwt: jsonwebtoken
        -config: dotenv
        -generateAccessToken(username) string
        +POST() void
    }

    class RouteStudent {
        -router: Router
        +GET() jsonArray
        +GET(username) jsonObject
        +POST(jsonArray) int
        +PUT(string, jsonArray) int
        +DELETE(string) int
    }

    class RouteGrade {
        -router: Router
        +GET(username) jsonArray
    }

    class StudentModel {
        -connection: Pool
        -query(string) void
        +getAll(callback) QueryResult
        +getOne(string, callback) QueryResult
        +add(jsonArray, callback) QueryResult
        +update(string, jsonArray, callback) QueryResult
        +delete(string, callback) QueryResult
    }

    class GradeModel {
        -connection: Pool
        +getByStudent(username, callback) QueryResult
    }

    class DatabaseJs["database.js (moduuli)"] {
        +connection: Pool
    }

    App --> RouteLogin
    App --> RouteStudent
    App --> RouteGrade
    RouteStudent --> StudentModel
    RouteLogin --> StudentModel
    RouteGrade --> GradeModel
    StudentModel ..> DatabaseJs
    GradeModel ..> DatabaseJs
Näytä Mermaid-koodiPiilota Mermaid-koodi
```mermaid
classDiagram
    class App {
        -router: Router
        +authenticateToken(request, response, next) void
        +use(root) void
        +use(login) void
        +use(student) void
        +use(grade) void
    }

    class RouteLogin {
        -router: Router
        -bcrypt: bcryptjs
        -jwt: jsonwebtoken
        -config: dotenv
        -generateAccessToken(username) string
        +POST() void
    }

    class RouteStudent {
        -router: Router
        +GET() jsonArray
        +GET(username) jsonObject
        +POST(jsonArray) int
        +PUT(string, jsonArray) int
        +DELETE(string) int
    }

    class RouteGrade {
        -router: Router
        +GET(username) jsonArray
    }

    class StudentModel {
        -connection: Pool
        -query(string) void
        +getAll(callback) QueryResult
        +getOne(string, callback) QueryResult
        +add(jsonArray, callback) QueryResult
        +update(string, jsonArray, callback) QueryResult
        +delete(string, callback) QueryResult
    }

    class GradeModel {
        -connection: Pool
        +getByStudent(username, callback) QueryResult
    }

    class DatabaseJs["database.js (moduuli)"] {
        +connection: Pool
    }

    App --> RouteLogin
    App --> RouteStudent
    App --> RouteGrade
    RouteStudent --> StudentModel
    RouteLogin --> StudentModel
    RouteGrade --> GradeModel
    StudentModel ..> DatabaseJs
    GradeModel ..> DatabaseJs
```

Qt sovelluksen luokkakaavio

Onnistuneen kirjautumisen jälkeen avautuu StudentInfo-lomake. Siitä opiskelija voi siirtyä MyData-lomakkeeseen katsomaan henkilötietoja, MyGrades-lomakkeeseen katsomaan kurssisuorituksia tai EnrollToCourse-lomakkeeseen ilmoittautumaan kurssille.

classDiagram
    class MainWindow {
        -objLogin: Login
        -on_btnStart_clicked() void
    }

    class Login {
        -postManager: QNetworkAccessManager
        -reply: QNetworkReply
        -response_data: QByteArray
        -objStudentInfo: StudentInfo
        -on_btnLogin_clicked() void
        -loginSlot(reply) void
    }

    class StudentInfo {
        -username: QString
        -myToken: QByteArray
        -objMyData: MyData
        -objMyGrades: MyGrades
        -objEnrollToCourse: EnrollToCourse
        -on_btnData_clicked() void
        -on_btnGrade_clicked() void
        -on_btnEnroll_clicked() void
        +setUsername(newUsername) void
        +setMyToken(newMyToken) void
    }

    class MyData {
        -username: QString
        -myToken: QByteArray
        -dataManager: QNetworkAccessManager
        -reply: QNetworkReply
        -response_data: QByteArray
        +loadPersonalData() void
        -dataSlot(reply) void
    }

    class MyGrades {
        -username: QString
        -myToken: QByteArray
        -gradeManager: QNetworkAccessManager
        -reply: QNetworkReply
        -response_data: QByteArray
        +loadGrades() void
        -gradeSlot(reply) void
    }

    class EnrollToCourse {
        -username: QString
        -myToken: QByteArray
        -enrollmentManager: QNetworkAccessManager
        -reply: QNetworkReply
        -response_data: QByteArray
        +enroll(courseId) void
        -enrollmentSlot(reply) void
    }

    MainWindow *-- Login
    Login *-- StudentInfo
    StudentInfo *-- MyData
    StudentInfo *-- MyGrades
    StudentInfo *-- EnrollToCourse
Näytä Mermaid-koodiPiilota Mermaid-koodi
```mermaid
classDiagram
    class MainWindow {
        -objLogin: Login
        -on_btnStart_clicked() void
    }

    class Login {
        -postManager: QNetworkAccessManager
        -reply: QNetworkReply
        -response_data: QByteArray
        -objStudentInfo: StudentInfo
        -on_btnLogin_clicked() void
        -loginSlot(reply) void
    }

    class StudentInfo {
        -username: QString
        -myToken: QByteArray
        -objMyData: MyData
        -objMyGrades: MyGrades
        -objEnrollToCourse: EnrollToCourse
        -on_btnData_clicked() void
        -on_btnGrade_clicked() void
        -on_btnEnroll_clicked() void
        +setUsername(newUsername) void
        +setMyToken(newMyToken) void
    }

    class MyData {
        -username: QString
        -myToken: QByteArray
        -dataManager: QNetworkAccessManager
        -reply: QNetworkReply
        -response_data: QByteArray
        +loadPersonalData() void
        -dataSlot(reply) void
    }

    class MyGrades {
        -username: QString
        -myToken: QByteArray
        -gradeManager: QNetworkAccessManager
        -reply: QNetworkReply
        -response_data: QByteArray
        +loadGrades() void
        -gradeSlot(reply) void
    }

    class EnrollToCourse {
        -username: QString
        -myToken: QByteArray
        -enrollmentManager: QNetworkAccessManager
        -reply: QNetworkReply
        -response_data: QByteArray
        +enroll(courseId) void
        -enrollmentSlot(reply) void
    }

    MainWindow *-- Login
    Login *-- StudentInfo
    StudentInfo *-- MyData
    StudentInfo *-- MyGrades
    StudentInfo *-- EnrollToCourse
```

Tietokannan suunnittelu

Edellisistä käyttötapauksista, käyttöliittymäluonnoksista ja kaavioista voidaan etsiä tietoja, joita sovelluksen täytyy tallentaa. Tässä esimerkissä niitä ovat:

  • Opiskelija: opiskelijatunnus, nimi, sähköposti ja kirjautumista varten salasanan tiiviste.
  • Kurssi: kurssitunnus, nimi ja opintopisteet.
  • Ilmoittautuminen: tieto siitä, kuka opiskelija on ilmoittautunut mille kurssille sekä ilmoittautumisen ajankohta ja tila.
  • Suoritus: ilmoittautumiseen liittyvä arvosana ja suorituspäivä.

Tietotarpeista voidaan laatia esimerkiksi seuraava yksinkertaistettu ER-malli. Se näyttää myös tietojen väliset suhteet: opiskelija voi ilmoittautua usealle kurssille, ja ilmoittautumisesta voi syntyä yksi suoritus. Taulujen tunnisteet ja muut tarkemmat kentät ovat tietokantasuunnittelussa tehtäviä valintoja.

Mermaidin ER-syntaksi vaatii suhteen selitekentän. Koodissa käytetään tyhjää selitettä, jotta kaaviossa näkyvät vain yhteydet ja niiden lukumääräsuhteet. Kaaviokohtainen asetteluasetus jättää taulujen väliin enemmän tilaa, jotta suhteen merkit erottuvat.

---
config:
  layout: dagre
  er:
    rankSpacing: 140
---
erDiagram
    STUDENT {
        int student_id PK
        string student_number UK
        string name
        string email
        string password_hash
    }

    COURSE {
        int course_id PK
        string name
        int credits
    }

    ENROLLMENT {
        int enrollment_id PK
        int student_id FK
        int course_id FK
        date enrollment_date
        string status
    }

    COURSE_COMPLETION {
        int completion_id PK
        int enrollment_id FK, UK
        int grade
        date completion_date
    }

    STUDENT ||--o{ ENROLLMENT : ""
    COURSE ||--o{ ENROLLMENT : ""
    ENROLLMENT ||--o| COURSE_COMPLETION : ""
Näytä Mermaid-koodiPiilota Mermaid-koodi
```mermaid
---
config:
  layout: dagre
  er:
    rankSpacing: 140
---
erDiagram
    STUDENT {
        int student_id PK
        string student_number UK
        string name
        string email
        string password_hash
    }

    COURSE {
        int course_id PK
        string name
        int credits
    }

    ENROLLMENT {
        int enrollment_id PK
        int student_id FK
        int course_id FK
        date enrollment_date
        string status
    }

    COURSE_COMPLETION {
        int completion_id PK
        int enrollment_id FK, UK
        int grade
        date completion_date
    }

    STUDENT ||--o{ ENROLLMENT : ""
    COURSE ||--o{ ENROLLMENT : ""
    ENROLLMENT ||--o| COURSE_COMPLETION : ""
```

Teknisen määrittelyn tarkistuslista

  • Onko jokaisella olennaisella vaatimuksella toteutusratkaisu ja tapa testata se?
  • Ovatko osien vastuut, rajapintojen tietosisällöt ja virhetilanteet riittävän selviä toteuttajalle?
  • Vastaavatko tietokannan suhteet ja rajoitteet sovittuja toimintasääntöjä?
  • Onko tunnistautuminen ja käyttöoikeuksien tarkistus kuvattu palvelimen näkökulmasta?
  • Onko kuvattu, miten sovellus otetaan käyttöön ja miten asetukset, salaisuudet ja varmuuskopiointi hoidetaan?

Määrittelyjä tarkennetaan työn edetessä. Jos suunnittelussa havaitaan puuttuva sääntö tai ristiriita, päivitä ensin sovittu vaatimus ja sen jälkeen siihen liittyvät kuvaukset.

Tämä sivu on opetusesimerkki eikä valmis, kattava dokumentaatio. Esimerkin tarkoitus on esitellä, kuinka Mermaidilla luodaan tyypillisiä UML-kaavioita ja muita määrittelyssä ja suunnittelussa käytettäviä kaavioita, sekä antaa vinkkejä siihen, mitä määrittely- ja suunnitteluvaiheen dokumentteihin kirjoitetaan.



Toggle Menu