Ohjelmistoprojektin kasvaessa kirjoitetun koodin määrä vähenee suhteessa siihen, kuinka paljon aikaa kuluu olemassa olevan koodin lukemiseen. Tästä syystä koodin kirjoitusvaiheessa kannattaa panostaa koodin selkeyteen sekä luettavuuteen. Selkeä koodi vähentää ohjelmiston tulevia kehityskuluja sekä parantaa koodaajien viihtyvyyttä. Mitä vaikeaselkoisempaa ja sekavampaa koodi on, sitä ikävämpää sen parissa on tehdä töitä.
Ei nimi muuttujaa pahenna
Sujuvasti luettavan koodin keskeisin kulmakivi on selkeä ja järkevä nimeäminen. Muuttujille, metodeille ja luokille tulisi antaa mahdollisimman kuvaavat nimet. Nimissä ei saisi olla turhia täytesanoja, jotka eivät tarkoita mitään, eivätkä nimet saisi olla harhaanjohtavia. Nimissä tulisi käyttää standardeja ilmaisuja, ja vakiintuneita termejä tulisi käyttää kontekstin kannalta yleisimmässä merkityksessään. Esimerkiksi ohjelmoijalle Class tarkoittaa aina koodiluokkaa. Jos koodissa on luokka ClassFinder, joka etsiikin jonkinlaista luokitusta, eikä koodiluokkaa, on sekaantumisen vaara ilmeinen. Metodien tulee tehdä juuri se, mitä nimi sanoo, eikä metodeilla saa olla odottamattomia sivuvaikutuksia.
Koodin seassa olevien lukuliteraalien eli taikalukujen sijaan tulisi käyttää nimettyjä vakioita, joiden nimi kertoo luvun tarkoituksen. Jos vakiot, muuttujat ja metodit käsittelevät lukuja jossakin mittayksikössä, on mittayksikkö hyvä kirjoittaa nimeen, jotta koodin lukijan ei tarvitse arpoa yksikköä ja mahdollisilta muunnosvirheiltä vältytään.
🙁
public double calculate(final double m) {
return m * Math.pow(299792458, 2);
😊
public static final int SPEED_OF_LIGHT_METERS_PER_SECOND = 299_792_458;
public double transferMassToEnergyJoules(final double mass_kg) {
return mass_in_kg * Math.pow(SPEED_OF_LIGHT_IN_METERS_PER_SECOND, 2);
}
Pieni on kaunista
Kokemukseni mukaan toiseksi tärkein koodin selkeyttäjä on koodin pituus. Luokkien ja metodien tulisi olla mahdollisimman lyhyitä. Mitään minimimittaa on mahdoton sanoa, mutta hyvänä nyrkkisääntönä voi pitää, että metodi saisi tehdä vain yhden asian ja luokalla saisi olla vain yksi vastuu. Erityisesti luokkien osalta tämä tuntuu olevan vaikeaa, ja luokista tuppaa useasti tulemaan monipuolisia kuin Sveitsin armeijan linkkuveitsi.
Pienuuden teemaan soveltuu myös vaatimus rakentajien ja metodien parametrien määrän minimoimiseksi. Jos parametrien määrä kasvaa yli kolmen, voi parametrit niputtaa jonkin sopivan olion sisälle, joka annetaan sitten parametrina. Liian moni parametri aiheuttaa mm. vaaran, että parametrit menevät keskenään sekaisin. Jos esimerkiksi metodilla on kymmenen integer-parametria, on riski ilmeinen, että koodaaja syöttää epähuomiossa väärän integerin väärään kohtaan. Parametriolion sijaan voi myös käyttää builder-patternia, jolloin parametrien kuvaaminen selkeämmin on helpompaa.
🙁
final Line alertLine = new Line(0, 0, 100, 25, 3);
😊
final Line alertLine = new Line.Builder()
.startPointOnScreen(0, 0)
.endPointOnScreen(100, 25)
.lineWidth(3)
.build();
Copy-paste on pahasta
Jos kopioit koodia paikasta toiseen, syntyy kaksi ongelmaa. Ensinnäkin koodin pituus kasvaa turhaan ja toisekseen koodimassan ylläpito vaikeutuu. Jos kopioituun koodinpätkään tulee muutostarpeita esimerkiksi sen takia, että siinä on bugi, tulee korjaus tehdyksi helposti vain siihen paikkaan, jossa se havaittiin ja muut kopioimalla luodut instanssit jäävät korjaamatta.
Hyvät ja huonot kommentit
Hyvä koodi dokumentoi itse itsensä, eikä koodin toimintaa kuvaaville kommenteille pitäisi olla tarvetta. Jos joudut kommentoimaan koodisi toimintaa, olet luultavasti tehnyt jotakin väärin. Koodin toiminta tulee ilmetä kuvaavasti nimetyistä muuttujista, metodeista ja luokista. Jos esimerkiksi pitkään metodiin on laitettu kommentteja erottelemaan osuudet toisistaan: "Tässä tehdään asia A", "Tässä tehdään asia B", pilko pitkä metodi kahdeksi lyhyemmäksi metodiksi: teeAsiaA() ja teeAsiaB().
Turhia kommentteja tulisi välttää, koska ne vain vaikeuttavat koodin lukemista. Kommentista tulisi oikeasti olla jotakin hyötyä koodin lukijalle. Hyvin yleinen turha kommenttityyppi, joka tulee useasti vastaan, on gettereiden ja settereiden metodin nimen toistaminen ilman muuta lisäinformaatiota:
🙁
/** Gets name **/
public String getName();
Kommentti muuttuu paljon hyödyllisemmäksi, jos siinä esimerkiksi kuvataan, mitä rajoituksia nimellä on.
😊
/** Name can't be null or empty. **/
public String getName();
Virheelliset ja harhaanjohtavat kommentit ovat vaarallisia ja niitä tulisi välttää. Kommentit tulee pitää ajan tasalla, mutta tämä voi olla joskus vaikeaa, koska koodin muutos ei aiheuta mitään koodaajalle näkyvää virhettä siitä, ettei kommentti enää päde. En tunne kommenttien ajan tasalla pitämiseen mitään salaista reseptiä, mutta tässäkin auttaa se, että kommentit on rajattu vain oikeasti hyödyllisiin ja tarpeellisiin.
Kaikki kommentit eivät ole missään nimessä huonoja. Esimerkiksi välillä koodissa on hyvä avata asiaa laajemmassa kontekstissa, miksi jotakin tehdään, koska tätä tietoa ei välttämättä saa ujutettua osaksi muuttujien ja metodien nimiä.
😊
// The message receiver fails if there is no
// empty space at the end of the message.
// This is a known bug in the recieving system
// but it can’t be fixed because the system is EOL.
return message + " ";
Muista säännöllinen siivous
Ajan saatossa koodi tuppaa rämettymään, kun koodia muutetaan ja laajennetaan uusien ominaisuuksien ja vikakorjausten johdosta. Rämettymistä tapahtuu sitä helpommin, mitä vaikealukuisempaa alkuperäinen koodi on, mutta siisti ja hyvin tehty koodikaan ei ole ilmiölle täysin immuunia. Koodi alkaa muuttua spagetiksi, kun uusi tuotettu koodi ei sulaudukaan saumattomasti osaksi vanhaa toteutusta, vaan jää eräänlaiseksi epämääräiseksi paiseeksi sen kylkeen. Rämettymisen tahti kiihtyy, mitä enemmän epämääräisiä ulokkeita koodiin tulee.
Koodin monimutkaistuessa työtahti hidastuu ja ylläpitokulut lähtevät nousuun. Monesti sekava koodi johtaa siihen, ettei uusi koodaaja ymmärrä kokonaiskuvaa vanhan koodin takana, ja uusi koodi tulee lisätyksi sinne, minne sen voi upottaa helpoiten. Jotta koodi saadaan pysymään kunnossa, tarvitsee koodia refaktoroida säännöllisesti. Joskus hyvä toimintatapa voi olla ensin koodata uusi ominaisuus siten, että se toimii ja sitten pysähtyä katsomaan, mitä tuli tehtyä. Kun on tiedossa, mitä pitää tehdä, on uuden ja vanhan koodin muodostama kokonaisuus helpommin hahmotettavissa ja toteutus muokattavissa eheäksi loogiseksi kokonaisuudeksi. Refaktoroinnin kanssa pitää kuitenkin olla varovainen, ettei haukkaa kerralla liian isoa palaa. Joskus koodin koukerot saattavat ulottua odottamattomiin paikkoihin ja muutaman päivän refaktorointi muuttuukin viikkojen kärsimysnäytelmäksi.
Aina valmiina!
Suurempien refaktorointien lisäksi on hyvä myös tehdä pienempiä parannuksia koodiin partiolaismenetelmää noudattaen. Kun päädyt vanhan koodin lähimaastoon, jätä koodi jäljiltäsi parempaan kuntoon, mitä se oli ennen kuin sinne saavuit. Muuta nimeämistä fiksummaksi, pilko metodeja pienemmiksi, korjaa staattisen koodianalysaattorin huomautuksia tai paranna mitä tahansa muuta, mikä ikinä silmääsi pistääkään.
Lue myös Markon aiemmat blogipostaukset
7 vinkkiä turvalliseen ohjemistokehitykseenOhjelmistokehitystä PuolustusvoimilleMarko Latvala
Kirjoittaja työskentelee Instan puolustusliiketoiminnassa ohjelmistoarkkitehtina.