SUUNNITTELU
Yleistä
Suunnittelun tuloksena saadaan kehykset ja menettelytavat työn toteutukselle. Tarkka ja yksityiskohtainen suunnittelu nopeuttaa toteutusta. Ilman hyvää suunnitelmaa toteutus tehdään helposti tehottomalla tavalla, esimerkiksi toteutuksen aikana kuluu turhaan aikaa jokaisen vaiheen uudelleensuunnitteluun. Suunnitelman avulla tiedetään koko ajan mitä pitää tehdä seuraavaksi ja miten.
Käytettävä suunnittelumenetelmä tai apuväline on kuvattava projektisuunnitelmassa. Menetelmän on johdettava suunnitelmaan, jossa on huomioitu modulaarisuus, testattavuus, ylläpidettävyys yms. laatukriteerit ja suunnitelma on tarkastettava.
Erilaisia suunittelumenetelmiä ja automatisoituja apuvälineitä on runsaasti. Seuraavassa annetaan joitakin esimerkkejä ja tarkastellaan luotettavuuden asettamia vaatimuksia.
Terminologiaa
- Funktio on aliohjelma, jolla on parametreja ja tietty kutsumuoto.
- Moduuli on kokoelma funktioita. Moduuli voidaan kääntää itsenäisesti. Eräillä kirjoittajilla moduuli on sama kuin funktio.
- Komponentti voi olla moduuli (funktio), olio tai luokka.
Suunitteluperiaatteita
Suunnittelun kolme päälähestymistapaa ovat tietovirtakeskeinen suunnittelu, tietorakennekeskeinen suunnittelu ja oliokeskeinen suunnittelu. Lähestymistavoista on valittava kulloisestakin tilanteesta riippuen soveliain.
Tietovirtakeskeisessä suunnittelussa järjestelmän jaon osiinsa määräävät järjestelmän toiminnot (rakenteinen suunnittelu, askelittainen tarkentaminen).
Tietorakennekeskeisessä suunnittelussa järjestelmän jako osiinsa määräytyy käsiteltävien tietojen rakenteen avulla (Jacksonin rakenteinen ohjelmointi (JSP), Warnier-Orr menetelmä).
Oliokeskeisessä suunnittelussa järjestelmä nähdään joukkona olioita, joilla on omat operaationsa ja jotka lähettävät viestejä toisilleen (OMT, OOSE, UML). Oliokeskeistä suunnittelua ei pidä sotkea oliosuuntautuneeseen ohjelmointiin: oliokeskeistä suunnittelua voidaan käyttää riippumatta siitä, millä kielellä toteutus tehdään.
Hierarkkisuus
Hierarkkisuus on olennainen keino hallita monimutkaisuutta. Komponenttien liittyminen toisiinsa toteutetaan hierarkkisena rakenteena (Kuva 1), ja tällä rakenteella on seuraavia ominaisuuksia:
- Alempi taso ei tiedä mitään ylemmän tason ominaisuuksista eikä edes sen olemassaolosta.
- Mikään taso ei tiedä mitään toisen tason sisäisistä asioista. Kaikki kommunikointi tasojen välillä tapahtuu ennalta tarkasti määritellyn rajapinnan kautta.
- Kukin taso koostuu joukosta moduuleita, joista osa on sisäisiä. Sisäisiin moduuleihin ei voi viitata muilta tasoilta.
- Kukin taso koostuu tietyistä resursseista. Taso voi piilottaa osan resursseista muilta tasoilta ja tarjota tietyn abstraktiotason muiden tasojen käyttöön.
- Muista tasoista tehtävät olettamukset on minimoitava. Tällaiset olettamukset voivat koskea esimerkiksi tiedon esitystapaa tai käyttöympäristöä.
- Eri tasot eivät käytä yhteistä globaalia dataa. Tiedonvälitys eri tasojen välillä tapahtuu parametrien kautta.
Kuva 1. Abstraktiotasot
Komponenttijaon ominaisuuksia
Kiinteys on komponentin (moduulin, olion) sisäinen ominaisuus. Kiinteys kuvaa sen, millä tavalla komponenttiin kuuluvat osat (funktiot, olion ominaisuudet ja operaatiot) liittyvät toisiinsa:
- Toiminnallinen kiinteys: jokainen osa on välttämätön muiden osien toiminnan kannalta.
- Peräkkäiskiinteys: yhden osan tulos on toisen osan lähtöarvo.
- Tiedollinen kiinteys: kaikki osat käyttävät samoja tietoja.
- Proseduraalinen kiinteys: komponentin osat muodostavat tietyn tehtävän suorittamisessa tarvittavat vaiheet.
- Looginen kiinteys: osat huolehtivat samankaltaisista toiminnoista.
- Ajallinen kiinteys: komponentin osat suoritetaan toiminnan samassa vaiheessa.
- Satunnainen kiinteys: osilla ei ole mitään tekemistä toistensa kanssa.
Komponentin kiinteyden pitäisi olla mahdollisimman suuri (ts. mahdollisimman ylhäällä yo. asteikolla).
Kytkentä on komponenttien välinen ominaisuus. Kytkentä kuvaa komponenttien keskinäistä riippuvuutta toisistaan:
- Sisältökytkentä: komponentti viittaa suoraan toisen komponentin sisältöön.
- Kytkentä yhteisen tietoalueen kautta: kaksi komponenttia käyttää yhteistä globaalia tietoaluetta, jonka rakenteen kumpikin tuntee.
- Ohjauskytkentä: komponentti välittää toiselle parametrina ohjausinformaatiota, joka edellyttää toisen komponentin toiminnan tai rakenteen tuntemista.
- Tietuekytkentä: komponentti välittää toiselle parametrina tietoa, jonka rakenteen kummankin on tunnettava.
- Parametrikytkentä: komponentti välittää toiselle parametreina vain yksinkertaisia arvoja tai abstraktin tietotyypin mukaisia arvoja.
- Kytkentää ei ole.
Komponenttien kytkennän pitäisi olla mahdollisimman heikko (ts. mahdollisimman alhaalla yo. asteikolla). Lisäksi on pyrittävä siihen, että kukin komponentti on
- helppolukuinen (funktiot 10-100 LOC, komponentti korkeintaan 10 sivua) ja
- ymmärrettävä aiempien määritysten valossa.
Huonon jaon tunnusmerkkejä ovat esimerkiksi seuraavat:
- Funktio tekee liian monta toisiinsa liittyvää mutta kuitenkin selvästi erilaista toimintoa (esim: sama funktio lukee näppäimistöä ja kirjoittaa vastauksia näytölle): jokaisen funktion tulee käsitellä vain yhden "tason" (syöttömuoto, sisäinen esitys, tulostusmuoto) tietoa tai olla konversiofunktio kahden muodon välillä.
- Yleiskäyttöiset funktiot sijaitsevat hajallaan eri moduuleissa.
- Moduulit käyttävät yhteisiä tietoalueita yllättävillä tavoilla.
Funktioiden ulkoinen suunnittelu
Käytettävän funktio- ja moduulijaon selvittyä suoritetaan funktioiden ulkoinen suunnittelu. Ulkoisessa suunnittelussa määritellään yksityiskohtaisesti ne asiat, jotka on tiedettävä funktiota kutsuttaessa (mutta ei mitään funktion sisäisiä asioita: ei toimintalogiikkaa, ei sisäisiä tietorakenteita). Suunnittelussa on pyrittävä yleistämään funktioiden toimintaa: parempi liikaa parametreja kuin liian vähän.
Tarpeetonta vakioiden käyttöä pyritään välttämään. Tarvittavat vakiot
- määritellään #define:illä tai const:eilla => funktioiden sisäisen suunnittelun asia tai
- luetaan ohjelman alussa tiedostoista => funktioiden ulkoisen suunnittelun asia.
Luotettavuuteen pyrkiminen
Testaamisen päätarkoitus on tuotteen hyväksyminen eikä sen korjaaminen. Virheet pitäisi siis löytää ja korjata jo ennen testausvaihetta. Tavoitteena tulee olla mahdollisimman virheetön tuote, johon käyttäjät ovat tyytyväisiä. Tätä tavoitetta voidaan saavuttaa käyttämällä sellaisia menetelmiä, jotka edistävät vaatimusmäärittelyä vastaavan suunnitelman ja suunnitelmaa vastaavien ohjelmien syntymistä. Tuotteen monimutkaisuus lisää virheiden todennäköisyyttä, joten monimutkaisuutta on pyrittävä minimoimaan ja hallitsemaan.
Kuitenkaan kaikkia virheitä ei pystytä välttämään, joten virheet on pyrittävä havaitsemaan esimerkiksi suunnitelmien ja ohjelmakoodien tarkastusten ja katselmusten avulla. Virheitä voidaan pyrkiä havaitsemaan myös erilaisten ohjelmistoon sijoitettavien "turhien" testien avulla.
Tarkastuksista ja katselmuksista huolimattakin ohjelmiin jää vielä virheitä. Ohjelman on siksi siedettävä virheitä, esimerkiksi virheen sattuessa ohjelma on lopetettava siististi. Virheen vaikutukset on pystyttävä korjaamaan, esimerkiksi virheen mahdollisesti tuhoamat tiedot on pystyttävä palauttamaan ennalleen.
Järjestelmä on rakennettava siten, että virheet havaitaan normaalin toiminnan yhteydessä. Eräs keino virheiden havaitsemiseksi on keskinäinen epäluulo, esimerkiksi
- Funktioiden on syytä tutkia parametriensa kelvollisuus, älykkyys ja konsistenssi.
- Funktioiden tulee tutkia parametriensa kelvollisuus olemassaoleviin tietoihin nähden.
- Tiedostoihin lisätään tunnistekentät.
- Kaikki arvot on tarkistettava, esimerkiksi jos arvot voivat olla 1, 2 ja 3, niin ohjelma ei saa olettaa, että jos arvo ei ole 1 eikä 2 niin se on 3.
- Eri vakioille on syytä antaa eri arvot (esim: SEKUNTI=81 ja SADASOSASEKUNTI=82 (eikä 1 ja 2), jolloin aivan muualle tarkoitetun vakion käyttö paljastuu).
Käyttäjän tekemiä toimintoja on syytä epäillä, esimerkiksi kaikki syöttötiedot on tarkistettava. Muita käyttäjän tekemien toimintojen varmistuskeinoja ovat esimerkiksi tiedostojen päällekirjoittamisesta kieltäytyminen ja koneelta toiselle siirrettävien aineistojen numeroiminen.
Paitsi käyttäjää, myös käytettyjä tietovälineitä on syytä epäillä. Toimintojen oikeellisuutta voidaan varmistaa esimerkiksi erilaisten tarkistussummien avulla.
Virheitä voidaan pyrkiä havaitsemaan myös erillistoimintona esimerkiksi erillisen ohjelman avulla, joka ajetaan määräajoin tai on jatkuvasti aktiivisena pienellä prioriteetilla. Erillisellä ohjelmalla voidaan esimerkiksi tutkia tietorakenteiden (tai tietokannan) eheyttä tai muiden prosessien hengissäoloa. Erillinen ohjelma voi myös antaa järjestelmälle "valetapahtumia" ja seurata, että niiden käsittely menee oikein.
Havaittu virhe on välittömästi ilmoitettava ja virheestä toipuminen on järjestettävä mahdollisimman siistiksi.
Vain jäsenille: