Prev Next Up Title Contents Index

Mutkikkuuden hallinta

Mutkikkuuden hallinnassa tärkein periaate on ison ongelman pilkkominen useisiin pienempiin. Tilanne on analoginen vaikkapa shakkipelin kanssa: ei yleensä ruveta miettimään ensimmäistä siirtoa sillä mielellä, että mitenköhän nyt tekisin vastustajasta matin. Sen sijaan ratkaistaan ongelma esimerkiksi kolmessa vaiheessa. Ensin yritetään soveltaa tunnettua tai itse kehitettyä avausteoriaa hyvän alkuaseman saavuttamiseksi. Keskipelissä yritetään erilaisilla sommitelmilla saavuttaa materiaaliylivoima, eli lyödä vastustajalta enemmän tärkeitä nappuloita kuin itse menettää. Loppupelissä voidaankin jo tukeutua melko valmiisiin algoritmeihin vastustajan matittamiseksi, mikäli on saavutettu riittävä ylivoima. Edelleen alku-, keski- ja loppupelissä voidaan muodostaa alitavoitteita ja näin pienentää ratkaistavaa tehtävää.

Ongelman ratkaisu voidaan pilkkoa myös meta- tasolla erilaisiin vaiheisiin. Shakkipelin voittamiseksi kannattanee ensin opiskella ja harjoitella runsaasti ja vasta sitten osallistua varsinaiseen kilpailuun. Vastaavasti ohjelmistotyössä olisi ensin pyrittävä kartoittamaan ongelma mahdollisimman tarkasti, ettei vahingossa ratkaista väärää ongelmaa. Sen jälkeen kannattaa suunnitella ratkaisu mahdollisimman yleisellä tasolla, ja asteittain tarkentaen lähestyä lopullista implementaatiota. Korkean tason suunnitelmaa on paljon helpompi muuttaa hyvinkin radikaalisti kuin jo valmiiksi väärin toteutettua ohjelmaa. Laajamittaisessa ohjelmakehityksessä suunnittelua seuraa hyvinkin yksityiskohtainen määrittely ja vasta sen jälkeen toteutusvaihe.

Useimmat käytetyt ohjelmointiparadigmat tarjoavat erilaisia tapoja ongelman osittamiseen. Esimerkiksi proseduraalisessa ohjelmoinnissa aliohjelmien avulla ratkaistaan osatehtäviä ja niiden osia.

Click here for Picture

Kuva . Proseduraalinen ohjelma

Osatehtäviin jakoa jatketaan niin pieniin osiin, että yksittäinen aliohjelma on helppo ymmärtää. Yleensä on eduksi, jos aliohjelma tulostumaan mahtuu yhdelle kirjoittimen sivulle tai jopa päätteen ruudulle. Kunkin aliohjelman sisäistä rakennetta voidaan pyrkiä selkiinnyttämään nk. rakenteisella ohjelmoinnilla (structured programming). Tällöin rajoitutaan ohjelmoinnissa peräkkäisyyteen, valintaan ja toistoon ja vältetään esimerkiksi goto-lauseiden käyttöä.

Aliohjelmista kannattaa tehdä mahdollisimman yleiskäyttöisiä siten, että samaa aliohjelmaa voidaan käyttää samassa ohjelmistossa eri osatehtävien ratkaisemisessa tai mahdollisesti myös eri sovelluksissa. Tämä pienentää ohjelmiston kokoa, vähentää ohjelmointityön määrää ja tekee siten ohjelmistosta yksinkertaisemman. Lisäksi jos samaa aliohjelmaa käytetään monissa eri paikoissa, on todennäköistä, että siinä mahdollisesti olleet virheet huomataan ja korjataan. Näinollen yleiskäyttöisyys ja etenkin uudelleenkäyttö pitemmän päälle vähentää virheitä.

Laajemmissa ohjelmistoissa aliohjelmien keskinäisiä kutsuja kuvaava puurakenne voi olla hyvinkin mutkikas, sillä sama aliohjelma voi esiintyä siinä monta kertaa ja lisäksi aliohjelmat saattavat rekursiivisesti kutsua toisiaan tai itseään. Jotta aliohjelman toiminta ohjelmiston osana olisi mahdollisimman helppo ymmärtää, ja jotta se olisi mahdollisimman yleiskäyttöinen, olisi sen mahdollisuuksien mukaan käsiteltävä ainoastaan parametreinaan saamaansa dataa, eikä globaaleja muuttujia. Jos aliohjelma on tällä tavoin sivuvaikutukseton, on mahdollista pelkkää parametrilistan määrittelyä tai kutsuriviä tarkastelemalla mahdollista selvittää, mihin tietoalkioihin se voi vaikuttaa ja mihin ei. Näin esimerkiksi ohjelmavirheitä haettaessa on mahdollista heti rajoittua niihin aliohjelmiin, jotka ovat käsitelleet virheellisiä arvoja saaneita muuttujia. Vastaavasti voidaan sivuvaikutuksetonta aliohjelmaa helposti testata itsenäisesti. Joissakin tapauksissa tosin parametrilistoista tulee kohtuuttoman pitkiä. Tällöin parametreja kannattaa sijoittaa tietueisiin.

Funktionaalisessa ohjelmoinnissa on sivuvaikutuksettomuus viety vielä pitemmälle. Puhdas funktio on aliohjelma, joka laskee parametreinaan saamastaan datasta arvon ja palauttaa sen kuten funktiot matematiikassa. Esimerkiksi funktio sin(x) laskee trigonometrisen sinus-funktion ja palauttaa sen, mutta ei muuta x:n eikä muidenkaan muuttujien arvoja. Puhtaasti funktionaalisen ohjelman testaaminen on siten vielä helpompaa ja virheettömyyden tutkimiseksi löytyy mielenkiintoisia lambda- kalkyyliin pohjautuvia teoreettisia menetelmiä. Haittapuolena on tietyn tyyppisten ongelmien ratkaisemisessa lisääntyvä koodin pituus ja sitä myötä havainnollisuuden katoaminen.

Havaitaan, että on kaksi vastakkaista lähestymistapaa ohjelmistojen parantamiseksi: Suuri kielen ilmaisuvoima =>

tiiviimpi ja lyhyempi ohjelmistototeutus, mutta vaikeammin ymmärrettävä.
Voimakkaasti rajoitettu ohjelmointiparadigma =>
ohjelmiston osat ja niiden väliset vuorovaikutukset ovat yksinkertaisempia, helpommin testattavia ja toivottavasti virheettömämpiä, mutta ohjelmakoodin määrä kasvaa.
Olisiko ratkaisu sellainen paradigma, joka mahdollistaisi tilanteen mukaan suuren ilmaisuvoiman käytön tai ohjelmiston osien kapseloinnin siten, että niiden väliset vuorovaikutukset ovat hyvin rajoitetut?


Prev Next Up Title Contents Index