Perushahmotusta ohjelmointiin 4: ohjelmointityylit, hyvä ohjelmointitapa

Ohjelmointikielet ja -ympäristöt tukevat erilaisia ajattelu- ja työskentelytapoja.  Tarkoitukseen sopiva työväline vaikuttaa paljon sekä työn tekemiseen että tuloksen laatuun. Siksi ei ole samantekevää, miten ja millaisella välineellä ohjelmoidaan tai ohjelmointia opetetaan.

Millaista on hyvä ohjelmointi, riippuu paljolti siitä, mitä ollaan tekemässä. Toimintatapoja kutsutaan ohjelmointityyleiksi. Ohjelmoinnin alkeisopetuksessa korostuu usein tyyli, joka muistuttaa ruoanvalmistusreseptiä. Ohjelmassa kuvataan vaihe vaiheelta, mitä tietokoneen halutaan tekevän. Sellainen ohjelma on hyvä suorituskyvyltään. Toinen tyyli voisi olla pyrkiä mahdollisimman lyhyeen ja ilmaisuvoimaiseen ohjelmakoodiin, jonka merkitys on helposti nähtävissä ja ymmärrettävissä. Hyvä yleistajuinen johdatus ohjelmointityyleihin on Koiramaisessa ohjelmointikirjasessa [1].

Ammattilaiset kutsuvat ohjelmointityyliä ohjelmointiparadigmaksi. Yhtäältä se on tapa ajatella ja toteuttaa tietokoneohjelma sekä järjestää ohjauksen ja laskennan eteneminen. Toisaalta se vaikuttaa siihen, millaisista osista – olioista, funktioista, muuttujista jne. – ohjelma on luontevaa koota. Ohjelmointiparadigmoja on toista kymmentä. Ohjelmointikieliä voidaan luokitella niiden mukaan. Useat ohjelmointikielet eivät noudata vain yhtä paradigmaa, vaan tukevat useita. Silloin puhutaan moniparadigmaisesta tai hybridisestä ohjelmointikielestä. [2]

Vanhastaan tavallisin ja ohjelmoinnin alkeisopetuksessa vieläkin suosittu ohjelmointityyli on edellä kuvattu reseptinomainen ohjelman rakentaminen. Sitä kutsutaan imperatiiviseksi ohjelmointityyliksi [3], koska sen perusidea on ohjelman kokoaminen toisiaan seuraavista yksityiskohtaisista käskyistä. (Kieliopissa imperatiivi on verbin käskymuoto!) Se ei kuitenkaan ole ainoa ohjelmointityyli, johon oppilaat kannattaisi tutustuttaa. Se korostaa nimittäin pieniä yksityiskohtia, ongelman ratkaisemisen vaiheita, erillisinä käskyinä ja niiden muodostamisen määräävää lauseoppia eikä se niin ollen tue kovinkaan hyvin ongelman ratkaisemiseen tähtäävän algoritmisen ajattelun kehittymistä.

Kielen rakenteeseen voidaan sisällyttää ohjelmointia tehostavia piirteitä, jotta ohjelmoijan ei tarvitse itse huolehtia kaikista asioista. Tällaisia tyylejä ovat esimerkiksi olio-ohjelmointi ja logiikkapohjainen ohjelmointi. Python, Java ja C tukevat edellistä ja Prolog jälkimmäistä tyyliä. Itse olen mieltynyt funktionaaliseen ohjelmointityyliin [4] yhtäältä pitkän kokemuksen perusteella ja toisaalta siksi, että funktionaalisuus sopii erinomaisesti matemaattisten ongelmien ratkaisemiseen, koska sellaisen ohjelmointikielen tiedonesittämistapa on luonnostaan lähellä matematiikassa käytettyä. Funktionaalista ohjelmointityyliä tukevat muiden muassa erityisesti Mathematica ja Logo. Lisäksi funktionaalisella ohjelmointikielellä kirjoitettu koodi täyttää ensimmäisessä kappaleessa mainitut ilmaisuvoimaisuuden ja ymmärrettävyyden kriteerit.

Samuli Siltasella on seitsenkohtainen opastus hyvään matemaattiseen ohjelmointitapaan [5]. Se sopii hyvin muuhunkin ohjelmointityöskentelyyn. Lainaan sitä siksi tähän suomeksi, sillä alkuperäisteksti on englanniksi:
0o    Kirjoita aina kommentti siitä, mitä koodisi tekee, ennen kuin kirjoitat koodin.
1o     Aloita yksinkertaisesta tilanteesta, mieluimmin tunnetusta ratkaisusta.
2o    Etene kohti monimutkaisempaa tavoitettasi pienin askelin ja testaa joka askel.
3o    Suhtaudu koodiisi epäluuloisesti koko ajan. Testaa jatkuvasti monin tavoin.
4o    Jos menee pieleen, niin palaa sellaiseen kohtaan, jonka tiedät varmasti toimineen.
5o    Säilytä koodisi vanhat versiot.
6o    Testaa ohjelmasi simuloidulla datalla ja käy todellisen datan kimppuun vasta,         kun olet varma siitä, että kokonaisuus toimii.

Siltasen lähestymistapa on selvästi helposta vaikeaan, yksittäisestä yleiseen, alhaalta ylös. Se voi tarkoittaa myös sitä, että pyritään jakamaan ongelma pienemmiksi osiksi, jotka ratkaistaan yksitellen ja vasta lopuksi kootaan yhdeksi toimivaksi ohjelmaksi. Ei siis ole ihme, että Mathematica on matemaatikkojen sekä Logo ja Geogebra ovat matematiikkaa opiskelevien koululaisten työvälineitä. Logo ei tee eroa valmiina olevien ja käyttäjän määrittelemien toimintojen ja funktioiden välillä. Niitä voidaan lisätä sitä mukaa kuin ongelman ratkaiseminen edistyy ohjelmoijan mielessä ja ohjelman kirjoittamiseen tarvitaan uusia käsitteitä tai toimintoja. Ohjelmoinnin oppimisen lähestymistapana siinä voisi olla näkevinään saman motivoivan ongelmakeskeisyyden häivähdyksen kuin Geogebrassa tai Mathematicassa.

Vertauskuvia

Tietokone ei ymmärrä ihmisten käyttämiä kieliä. Sen oma kieli on konekieli.  Ihminen taas ei opi käyttämään konekieltä kovinkaan sujuvasti. Siksi on kirjoitettu monenlaisia ihminen—kone-sanakirjoja ja -kielioppeja. Niitä sanotaan korkean tason ohjelmointikieliksi. Ihmisen ja koneen välille tarvitaan lisäksi tulkkeja ja kääntäjiä. Ne ovat ohjelmia, jotka tulkitsevat tai kääntävät ihmisen kirjoittaman tietokoneohjelman tietokoneen ymmärtämään muotoon. Niistä puhuttiin sarjan ensimmäisessä osassa. 

Sanakirjoista on älyllisesti enää pieni askel molemminpuoliseen ymmärtämiseen. Tietokone pystyy jo nykyään muuttamaan ihmisen kirjoittaman tai itse tuottamansa tekstin puheeksi. Tämähän toimii esimerkiksi suomenkielisten Dimensio-artikkelien kohdalla melkoisen sujuvasti esimerkiksi Microsoftin Edge-selaimessa. Myös tekstin kääntäminen suomeksi onnistuu monesta kielestä auttavasti esimerkiksi Google-kääntäjällä tai Edgellä, jossa se on vakiotoimintona.  Seuraavista lyhyistä käännöksistä [6] näkyy, että kääntäjänä on erilainen tekoäly (algoritmi).
Google translator: Kaikki oppilaat eivät pidä matematiikasta, mutta hyvällä matematiikan opettajalla on valta muuttaa sitä. Hyvä matematiikan opettaja voi auttaa opiskelijoita, jotka ovat perinteisesti taistelleet laskutoimituksen kanssa, rakentamaan luottamusta taitoihinsa.
Microsoft Edge: Kaikki oppilaat eivät pidä matematiikasta, mutta hyvällä matematiikan opettajalla on valta muuttaa se. Hyvä matematiikan opettaja voi auttaa perinteisesti aritmeettisen kanssa kamppailevia oppilaita rakentamaan luottamusta taitoihinsa.

Voidaan tietysti kysyä, ymmärtääkö tietokone tai siis tarkemmin tekoäly käyttämäänsä kieltä. Ehkäpä ei, ainakaan samoin kuin ihminen. Itseoppivat algoritmit ”oppivat” kieltä kuitenkin samalla tavalla mallin mukaan kuin lapsi ”kuuntelemalla” ja ”lukemalla” luonnollista kieltä. Niiden aineistot ovat vain valtavan paljon suurempia, tuhansia dokumentteja sisältäviä kielikorpuksia. Tekoäly(algoritmie)n ”kielitaitoa” todistaa, että joidenkin suomalaisten yritysten palvelukyselyistä tekoäly hoitaa nykyään yli puolet. Näitä tekoälypalvelijoita sanotaan keskusteleviksi chatboteiksi. Sellainen on esimerkiksi JennyBot [7], jonka kanssa keskustellaan vielä kirjoittamalla. 

Tällainen chatbot läpäisee siis tavallaan Turingin testin. Ainakin sen heikon muodon, millä tarkoitan sitä, että vaikka ihminen tietää keskustelevansa tietokoneen (tekoälyn) kanssa, niin sen älykkyys riittää hänelle ihmisälyn korvikkeeksi, kunhan hän vain saa vastauksen kysymäänsä asiaan. – Puhutun kielen ”ymmärtäminen” ei ole tekoälylle yhtä helppoa kuin kirjoitetun ymmärtäminen. Vaikeutena ovat ihmisyksilöiden väliset puhutun kielen erot. Suomalainen Lahjoita puhetta -hanke [8] tähtää siihen, että tekoäly alkaisi ymmärtää myös puhuttua suomen kieltä yhä paremmin. Ala kehittyy nopeasti. Markkinoilla on jo useita suomeakin ymmärtäviä kaupallisia puheohjausjärjestelmiä erityistarkoituksiin.

Mikä sitten on koulun ohjelmoinninopetuksen merkitys?  Ihmisen ja tietokoneen vuorovaikutus nousi esille edellisellä vuosikymmenellä, kun ohjelmointi tuli opetettavaksi asiaksi perusopetuksen opetussuunnitelmiin alkuopetuksesta lähtien. Filosofisesti ohjelmoinnilla on koulussa paljon laajempi merkitys kuin vain tietokoneohjelman kirjoittamisen taito. Se edustaa tavallaan koko tietojenkäsittelytieteen alaa, vaikka suppeasti käsittäen kyse on vain tietokoneohjelmistoista (engl. software). Tämäkin käsite on jakautunut Stanfordin filosofian tietosanakirjan [9] mukaan kolmeen osaan: algoritmit, lähdekoodit ja ohjelmat. Lisäksi on syntynyt monia tietojenkäsittelytieteelle rinnakkaisia tieteenaloja kuten tietojärjestelmätiede, tekoälytiede ja datatiede.   

Sama lähde pitää kuitenkin jopa laitteiston ja ohjelmiston erottamista viime  kädessä vaikeana. Voidaan tietysti sanoa, että laitteisto on fyysinen olio ja ohjelmisto ei. Tarkemmassa katsannossa tietokoneohjelmaa ei ole edes olemassa ilman fyysistä tallennuslaitetta. Vastaavalla tavalla laitteisto on vain materiaalista romua ilman konekielistä ohjelmaa. Rajankäynti ei siis ole selvä ainakaan filosofisen olemassaolon mielessä. Vastaavan tapaista jaottelua on käytetty ohjelmistojen osaltakin niin, että algoritmit ovat ohjelmiston älyllinen puoli ja konekieliset ohjelmat niiden laitteenläheinen toteutuma (implementointi).

Perusopetuksen tehtävä ei ole niinkään opettaa ohjelmointia, vaan harjaannuttaa ohjelmoinnilliseen ajatteluun ja antaa käsitys siitä, mistä ohjelmoinnissa on kyse. Perusymmärrys ohjelmoinnista on tärkeää, koska se antaa konkreettista käsitystä ihmisen ja tietokoneen vuorovaikutuksesta.  Tämän vuorovaikutuksen ymmärtämisestä on tullut yhä tärkeämpi osa koko maailmankuvaamme, koska tietokonemaailma ei ole enää vain koneita ja niitä ohjaavia ohjelmia, vaan myös tekoälyä, joka pystyy esimerkiksi visualisoimaan ihmisaistien ulottumattomissa olevaa tietoa [10]. Käytännölliseltä kannalta se, että tietokone osaa toteuttaa ihmisen kirjoittaman ohjelman komennot, ei eroa paljoakaan siitä, että se (hän?) ymmärtäisi, mitä ihminen on tarkoittanut. 

Siitä on sitten käsitteellisesti vain pieni, vaikka teknisesti suuri askel tekoälyltä odotettuun yleiseen ymmärrykseen. Edellä mainitut tekoälysovellukset, mutta myöskin esimerkiksi puettava tietotekniikka ja lisätty todellisuus (engl. augmented reality), edustavat toistaiseksi ns. kapeaa eli heikkoa tekoälyä. Yksimielisyyttä ei vallitse siitä, olisiko vahva tekoäly edes mahdollinen. Pystyisikö tekoäly tulevaisuudessa kaikkiin ihmiselle mahdollisiin kognitiivisiin suorituksiin tai jopa ylittämään ne? Entä emootiot? Järki ja tunteet? Monet tutkijat ja filosofit ovat sitä mieltä, että se ei toteudu ainakaan nähtävissä olevassa tulevaisuudessa. [11]

Esimerkkiprojekti

Joskus neuvotaan aloittamaan ohjelmoinnin oppiminen tutustumalla valmiisiin ohjelmiin. Tai sitten aloitetaan yksinkertaisista peruskomennoista. Ohjelmoinnin mahtavuus ei ole kuitenkaan valmiiden ratkaisujen tutkimisessa tai siinä, että saa tietokoneen tekemään jotain yksinkertaista, vaan siinä, että käyttäjä voi luoda nopeasti uutta – ja niin paljon uutta, että sitä ei jaksaisi tuottaa kynällä ja paperilla tai siveltimellä ja kankaalla. Ja olisiko ihan mahdoton ajatus, että komentoja ja rakenteita ei tarvitsisi opetella etukäteen irrallisina, mekaanisina toimintoina, vaan työskentelyn edetessä sitä mukaa, kun oppija tuntee niitä tarvitsevansa? Niinhän oppiminen usein menee muutenkin, että tietoja etsitään asiantuntijoilta tai käsikirjoista tarpeen mukaan.

Perusohjelman muuntelu olisi hyvä toimintatapa. Tästä on käytetty myös nimitystä esimerkkipohjainen ohjelmointi [12]. Käytän tässä esimerkkinä Logoa, vaikka sama voidaan tietysti tehdä Pythonilla ja monella muulla työvälineellä. Olkoon hankkeen nimi ”Metsä”. Aloitetaan puusta. Sitä voi tietysti ruveta suunnittelemaan järjestyksessä runko, oksa, haara, puu, metsikkö, metsä, mutta perusrakenne ei ole kiehtovin vaihe, vaan sen variointi. Olkoon siis valmiina perusohjelma ”Puu”:
     to puu :pituus :kulma
         if :pituus < 5 [stop] ; lopetusehto (latvahaaran pituus)
         forward :pituus ; runko
         left :kulma puu 0.62 * :pituus :kulma ; vasen haara
         right 2 * :kulma puu 0.62 * :pituus :kulma ; oikea haara
         left :kulma penup back :pituus pendown ; paluu alkuasemaan
     end

Ohjelmakutsussa puulle annetaan pituus ja haarautumiskulma. Kilpikonnangrafiikan etenemis- ja kääntymiskomentojen merkitys selviää nopeasti, kun ohjelma suoritetaan useasti pituutta ja kulmaa vaihdellen. Sitten muukin ohjelmakoodi avautuu helposti. Ensimmäinen rivi, lopetusehdon valintarakenne, määrää, minkä pituisia ovat latvahaarat. Toinen rivi piirtää rungon. Seuraavat piirtävät haaran vasemmalle ja toisen oikealle. Viimeinen rivi palauttaa konnan alkuasentoonsa. Lopetusehtoa muuttamalla puusta saa tiheämmän tai sen saa jopa kukkimaan (oikeanpuolimmainen pikkukuva). Tällöin lopetusehto on
     if :pituus < 3 [setpencolor ”red fd 4 back 4 setpencolor ”black stop].
Lisää väriä puuhun saa tietysti lisäämällä koodiin setpencolor-komentoja mielen mukaan. Puun muotoa voi muuttaa myös vaihtamalla seuraavan haaran pituuskerrointa ohjelmakoodissa.

Entä sitten se metsä? Tarvitaan toinen ohjelma, joka piirtää puita haluttuun paikkaan. Se voi olla myös satunnainen:
     to metsä :määrä
         repeat :määrä [penup setpos (list random 450 random 50) pendown puu 40 30]
                    ; setpos-komento vie kohdistimen jokaisella toistokerralla uuteen paikkaan, 
                    jonka x-koordinaatti on välillä 0–450 ja y-koordinaatti välilllä 0–50

     end

Metsän tiheyden määrää ohjelmakutsussa annettava toistojen lukumäärä. Jos vielä satunnaistetaan puun koko ja muoto, niin näkymä alkaa olla vaihtelevampi.

Kynän paksuutta ja väriä vaihtamalla voidaan metsää kehittää edelleen. Kuvassa on sata puuta.

Lähteitä ja lisää luettavaa:

[1] Vuorinen, Juuso: Koiramainen ohjelmointikirjanen, luku 1, kappale Tyylillä on väliä. Ideal Learning Oy, Tampere 2020, osoitteessa https://www.ideallearning.fi/index.php/blogi/86-pieni-ohjelmointikirja

[2] Wkipedia-artikkeli Ohjelmointiparadigmat osoitteessa https://fi.wikipedia.org/wiki/Ohjelmointiparadigma

[3] Ohjelmointiparadigmat osoitteessa http://sange.fi/~atehwa/cgi-bin/piki.cgi/ohjelmointiparadigmat

[4] Wikipedia-artikkeli Funktionaalinen ohjelmointi osoitteessa https://fi.wikipedia.org/wiki/Funktionaalinen_ohjelmointi

[5] Siltanen, Samuli (2014): Basic Principles of Mathematical Programming osoitteessa https://blogs.helsinki.fi/smsiltan/2014/05/15/basic-principles-of-mathematical-programming/

[6] Zeiger, Stacy: 5 Important Characteristics to Become a Good Math Teacher (ote)  osoitteessa https://work.chron.com/5-important-characteristics-become-good-math-teacher-8926.html

[7] GetJenny Oy: What is a Chatbot? osoitteessa https://www.getjenny.com/what-is-a-chatbot
https://work.chron.com/5-important-characteristics-become-good-math-teacher-8926.html

[8] Lahjoita puhetta osoitteessa https://lahjoitapuhetta.fi/

[9] The Philosophy of Computer Science verkkojulkaisussa Stanford Encyclopedia of Philosophy https://plato.stanford.edu/entries/computer-science/

[10] Oulasvirta, Antti (toim.): Ihmisen ja tietokoneen vuorovaikutus. Gaudeamus, 2011.

[11] Coeckelbergh, Mark: Tekoälyn etiikka. Terra Cognita, 2021.

[12] Kalliokoski, Panu: Esimerkkipohjainen ohjelmointi osoitteessa http://sange.fi/~atehwa/cgi-bin/piki.cgi/esimerkkipohjainen%20ohjelmointi

Kirjoittaja