Sunday 28 November 2010

Koodaustavat, koodin laatu ja oliot

Sitä sanotaan että koodin laatua kannattaa tarkkailla. Oliokoodin sanotaan olevan helppolukuista. Koodin lohkoja kannattaisi eritellä. Kaikki nämä ovat myyttejä joita itseoppinut, monta vuotta proseduaalisella kielellä leikkinyt, koodari on kuullut. Onko näissä myyteissä todenperää?

Otetaanpa nyt aluksi käsittelyyn tuo koodin laatu. Esimerkkinä elävästä elämästä, koodari toteuttaa kokeiluaan pienen skaalan skriptimoottorista. Hän kääntää päänsä sisällä innoissaan suunnitelmiaan pseudoksi ja pseudoa lopulliseksi koodiksi. Ympäristö on proseduaalinen, kuten jo aiemmin sanoin, ja koodari on toteuttanut moottorinsa kaikkien taiteen sääntöjen mukaan muutaman, riippuvuussuhteita omaavan funktion sisään. Hänellä on iteraatiorakenne, jonka sisällä hän läpikäy tulkattavaa skriptiään läpi rivi riviltä. Tämän sisällä hänellä on Select- tai Switch – rakenne, jossa hän tarkistaa jokaisen rivin ensimmäisen sanan sisällön.

Projektin alkuvaiheessa homma kulkee helposti. Koodari kirjoittaa ’Case ”print”’ ja sen alle tulee tulostuskomennon toteutus. Komento tukee tietysti muuttujien tulostusta, joten se tarvitsee jonkinlaisen muuttujarajapinnan. Koodari ei ikävä kyllä ole vielä suunnitellut sellaista, mutta äkkiäkös sen tulostuskomennon kylkeen kasaa. Tämä luo 4-6 apumuuttujaa moottorin toteutukseen.
Koodari toteuttaa innoissaan uusia ominaisuuksia moottoriinsa oivallettuaan iteraatiorakenteen ja Select/Switchin yhteiskäytön tarjoamat riemut. ”Jatka painamalla mitä tahansa nappia” – ominaisuus ja ruudunpäivitys etenkin ovat kivoja toteutettavia, molemmat vaativat Case – avainsanan lisäksi tasan yhden rivin koodaajan käyttämässä ympäristössä.

Koodari toteutti nämä helpot jutut ensin, koska yleinen käytäntö on että vaikeat asiat jätetään päähän hautumaan ja helpot hoidetaan alta pois. Helppojen jälkeen on vuorossa vaikeista toteutuksista helpoin: kehittyneempi tekstintulostus. Koodari ajattelee kloonaavansa Printin kanssa käyttämänsä muuttujatsydeemin Text – komentoon. Asia ei ollutkaan aivan niin yksinkertainen, sillä Print välittää itselleen jostain kumman syystä iteraatioiden välissä dataa apumuuttujassa nimeltä apumuuttuja. Jos Text tulee tähän Printien väliin, niin yllätys on suuri kun printit eivät kommunikoi keskenään ja syntyy täysin odottamattomia bugeja.

Miten tämä olisi pitänyt hoitaa? Noh, kuten sanoin, tapaus on elävästä elämästä ja tuo koodari olin minä. Alun perin ratkaisin tapauksen kirjoittamalla moottorin seuraavaan versioon muuttuja-apin, järjestelmälle annetaan muuttujan nimi ja arvo ja se säilyttää muuttujia isossa läjässä. Myöhempi kokemus on osoittanut että homman olisi voinut toteuttaa myös niin, että toteuttaa moottorin luokkana niin, että mm. skriptin rivi ja muuttujasäilön osoite säilytetään privaatissa muuttujassa, skriptin komennot (kuten Text ja Print) toteutetaan luokan yksityisinä metodeina, ja julkinen Aja() – metodi tulkkaisi skriptin rakenteet, ja rivin ensimmäisen sanan perusteella kutsuisi näitä yksityisiä Text() tai Print() – metodeja. Näin voitaisiin käyttää Print()n kylkeen rakennettua muuttujapurkkaa myös Text()ssä. Tietysti kaikkein paras menettelytapa olisi toteuttaa jokainen skriptimoottorin tukema toiminto omana metodinaan, ja iskeä tähän rinnalle joku muuttujaolio, johon on toteutettu se muuttuja-api.

Koska kyseessä kuitenkin oli proseduaalinen ympäristö, ei voitu konstruktoida ajettavasta skriptistä yhtä fyysistä oliota. Jos proseduaalisuus otetaan huomioon, lieneee fiksuinta kasata moottori joka tukee yhden skriptin muistissaoloa kerrallaan, ja mahdollistaa nopean skriptien poistamisen ja lataamisen. Tämän päälle moottorin sisäiset funktiot jokaiselle skriptin komennolle ja yhtenäinen muuttuja-API.

Tämä oli erittäin kehittynyttä koodin laadun tarkkailua, taisi mennä ajoittain jopa oliokoodin hehkutuksen puolelle. Yleistettynä ensiaskeleitaan ottava koodaaja ottaa koodin laadun huomioon kun hän tajuaa kuinka pääsilmukassa on 3-4 sisäistä silmukkaa ja sisentämättömän ja kommentoimattoman koodin vuoksi hän ei löydä salaperäisen kaatumisen syytä. Jos koodajan tapana olisi C:n sukuisissa jokaisen {-merkin jälkeen painaa tabia ja ennen jokaista }-merkkiä vähentää sisennystä noin tabin tai neljän välilyönnin verran, tai hänellä olisi Basicissa tapana jokaisen Whilen/Repeatin/Forin/Ifin/Functionin/Classin ja tälläisten rakenteiden aloitusavainsanan jälkeen painaa tabia ja vähentää sisennystä ennen näiden lopetusavainsanoja, olisi hänen helpompi lukea koodiaan. Sisennyssääntöjä kannattaa tarkemmin lukea vaikka täältä (http://www.coolbasic.com/phpBB3/viewtopic.php?f=12&t=2307 jos linkki ei toimi).

Jatketaan saman esimerkin kanssa. Sisennys auttaisi häntä lukemaan koodiaan, mutta etenkin jos hän on erehtynyt käyttämään taulukoita koodissaan, kannattaisi hänen lisätä aina taulukon käsittelylohkoon kommenttina kuinka taulukkoindeksit juoksevat (taulukko[0] == taulukko – nimisen taulukon ensimmäinen arvo, taulukko[TAULUKONKOKO-1]==taulukko – nimisen taulukon viimeinen arvo). Muutenkin vaikeammissa rakenteissa kannattaa viljellä kommentteja jotka A) helpottavat lukemista kun lukijan ei itse tarvitse arvailla että palauttaakohan se OBJWX(objekti) objektin maailma- vai ruutukoordinaatin ja B) antavat kommentoijan kertailla rakenteiden toimintaa.
Myöhemmin koodaajan uralla hän tulee kohtaamaan sen, ettei kaikkia muuttujia todellakaan kannata säilyttää samassa avaruudessa. Alussa kertomani skriptimoottoriesimerkki demonstroi jo mitä haittaa siitä on kun saman funktion sisällä on neljä apumuuttujaXää. Proseduaalikielissä näiden muuttuja-avaruuksien rajaaminen on tietääkseni mahdollista vain funktioiden voimalla, mutta ainakin C++ tarjoaa namespace – avainsanan jolla voi perustaa muistaakseni jopa funktioiden ja metodien sisällä omia avaruuksiaan. Puhumattakaan koko ohjelmalle näkyvistä nimiavaruuksista, jotka kykenevät sisältämään olioita(ja muuttujia), luokkia ja funktioita.

Avaruuksilla kikkailu helpottaa isojen datamäärien hallintaa. Jossain melko yksinkertaisessa 2D-pelissä (jotain miinaharavan ja tetriksen väliltä) voisi datan ja rakenteet järjestellä seuraavasti. Avaruuteen KIRJASTO toteutetaan luokat grafiikan ja IO:n hallintaan. Avaruus PELIOBJEKTIT sisältäisi sitten luokkarakenteet esim. tetriksen palikoilla tai miinaharavan miinoille. Avaruuteen PELINHALLINTA kirjoitetaan luokat pelin rakenteille, kuten luokalle joka ohjaa pelimoottoria. Lisäksi jos kaikki pelin vaatimat vakiot piilotetaan yhteen, globaaliin luokkaan, niin rakenne on melko selkeä suuremmallekin tiimille.

Nettisivut hyötyvät myös viisaasta arkkitehtuurista. En usko että kukaan, joka ottaa itsensä vakavasti nettipuolella, tekee käsin jokaisen uuden ilmoituksen ja artikkelin omalle sivulleen. Itsenäisten julkaisijoiden, eli nykyisten blogaajien, keskuudessa 90-luvun tapa oli aloittaa artikkeli kopioimalla <html><head>.......</head> - osuudet vanhalta sivulta uudelle. Tämä oli äärimmäisen vaivalloista ja turhaa, etenkin jos käytti html 3:a, eli ei hyödyntänyt CSS:ää muotoilussa. 90-luvun loppupuolella CSS alkoi tulla mukaan kuvioihin, tuoden mukaan keskitetyn ulkoasunhallinnan.

Riittääkö tämä lapselle, joka haluaa kaiken helpoksi vaikka se vaatisi hieman taitoa? Ei todellakaan, kuten vanha sanonta kuuluu. Jos työpöytäsoftan puolella voi abstraktoida konkreettisen abstraktiokerroksen, niin miksi nettisivuilla pitäisi tyytyä silkkaan tyylejä tukevaan merkkaukseen? Ei tarvitsekaan! Avainsana on palvelinohjelmointi! Kun sivun muodostaa lennossa palvelimella, joka tukee PHP5:ttä, voi käyttää monia luokka-ominaisuuksia mitä työpöytä-OO-kielet omaavat. Sen sijaan että leikkisi html:llä ja FTP:llä aina päivittäessään sivua, voi kasata sivuilleen hallintatyökalun (CMS, content management system), johon syötettyyn materiaaliin palvelinskripti sitten lisää tarpeellisen merkkauksen.

Jos käyttää PHP5:ttä, voi palvelinarkkitehtuurin toteuttaa joko hyvin tai huonosti. Olen havainnut hyväksi tavaksi sen, että kirjoittaa lähes koko sivuston toiminnan luokkiin, ja sitten varsinaisilla sivuilla muodostaa sivut näitä luokkia hyväksikäyttäen. Sen sijaan siis että Include()ttaisi <head>in ja
<div id="navigoinni">n ulkoisista tiedostosta ja päälle kirjoittaisi<div class="leipäteksti"> Lorem ipsum.......................</div>:n, voisi Includettaa yhden, luokat sisältävän tiedoston, tehdä olion luokasta PALSTAT, ja syöttää leipätekstipalstan sisällön luokkadokumentaation mukaan. Pitkällä tähtäimellä uskon tämän helpottavan ylläpitoa erittäin paljon. Jos en sitä ole vielä tarpeeksi lujaa toitottanut, kokeilen tämän viimeisen kappaleen oppeja parhaillaan Pröngin ja Yoolin kanssa. Vain tulevaisuus näyttää mitä tästä lopulta tulee.

Tässä tekstissä ei ole yhtään täyttä faktaa, kaikki ovat subjektiivisia havaintojani. Jos jotain on väärin, en vastusta vaikka joku korjaisi käsitykseni.

No comments:

Post a Comment