Clean code on yksi software craftsmanship -liikkeen periaatteista ja eräänlainen manifesti hyvän ohjelmoinnin periaatteista koodin näkökulmasta katsottuna.

Kirjailija Mark Twain sanoi jo 1800-luvulla: ”Anteeksi pitkä kirjeeni, mutta en ehtinyt kirjoittaa lyhyesti”. Hän ei toki kirjoittanut ohjelmistokoodia, mutta sama totuus elää 2010-luvun ohjelmistokehityksessä. Hyvän, vain oleellisen sisältävän koodin kirjoittaminen vaatii työtä ja hyvää suunnittelua. Mitä tehokkaammin haluat kirjoittaa – oli kyseessä sitten koodi tai kirje – sitä enemmän pitää nähdä vaivaa.

Mitä on ”clean code” ja miten sitä tehdään? Kysymys on monimutkainen emmekä mekään pysty esittelemään kaikkia keskeisiä periaatteita yhdessä artikkelissa. Mutta tässä on muutamia näkökulmia, joihin paneutumalla voit aloittaa!

Hyvä koodi on helppolukuista

Puhdas koodi näyttää siistiltä ja on hyvin jäsennelty. Se on helppolukuista, selkeää ja helposti ymmärrettävää. Koodin instanssit on nimetty kielenomaisilla termeillä ja ne kuvaavat tarkoitusperänsä tai toimintonsa täsmällisesti. Hyvässä koodissa instansseja ei myöskään sekoita samassa kontekstissa oleviin toisiin eri asiaa tarkottaviin asioihin.

Helppolukuinen tarina etenee selkeästi yksi tapahtuma kerrallaan eikä niiden selvittämiseksi tarvitse lukea sivuhuomautuksia tai alaviitteitä. Sama pätee hyvään koodiin. Koodissa ei tule olla siihen liittymättömiä kirjailijan kirjoittamia sisäpiirivitsejä. Selkeälukuinen koodi on myös helpompi ja nopeampi katselmoida.

Hyvä koodi on vaivatonta ylläpitää

Nykyaikainen koodi liittyy usein kompleksiseen, useita sidosryhmiä yhteen liittävään järjestelmään ja koodia kehittää useampi kuin yksi kehittäjä tai kehitystiimi. Siksi on tärkeää, että moduulit toteuttavat vain yhden niille määritellyn toiminnon jolloin kehityksen aikaiset ja ylläpitovaiheessa tehtävät toimenpiteet on helppo toteuttaa (single responsibility principle).

Tämä ei välttämättä tarkoita joustamatonta rakennetta sillä esim. open/closed periaatteen mukaisesti toteutettujen moduulien toimintaa on mahdollista laajentaa ilman koodimuutoksia polymorphismin avulla, mikä vähentää ylläpitotarvetta.

Moniajoa vaativien sovellusten kehityksessä on myös paikkansa tarkasti rajatuilla, vain yhden tehtävän toteuttavilla moduuleilla ja metodeilla. Analogia ylläpidon dilemmasta voi löytyä esim. parkkipaikalta. Tulisiko auton voida vaihtaa polttimo ilman korin osien tai akun poistoa?

Hyvä koodi ei toista itseään

Edellisen kohdan periaate toistuu hieman eri muodossaan tässä kohdassa. Koska yksittäiset, vain yhden toiminnon toteuttavat moduulit on jaettu omiksi entiteeteikseen, samaa toimintoa ei tehdä kuin yhdessä paikassa. Koodi ei toista itseään. Tämä helpottaa ylläpitoa sekä toteuttaa esimerkiksi joidenkin software safety standardien vaatimuksia ja suosituksia.

Hyvää koodia on helppo käyttää

Valmista ohjelmistomoduulia on helpompi käyttää, jos edellä mainittujen asioiden lisäksi sen rajapinta on selkeästi kuvattu ja sitä käyttäessä ei tarvitse tietää moduulin sisäisistä rakenteista tai sidoksista muihin moduuleihin (Law of Demeter). Hyvä koodi siis paljastaa tietorakenteidensa datan ja piilottaa toiminnallisuuden ja toisaalta paljastaa objektien toiminnallisuuden ja piilottaa datan.

Hyvässä koodissa on vähän kommentteja

Hyvä koodi dokumentoi itse itseään eikä välttämättä tarvitse toiminnalisuuden ja rakenteidensa selvittämiseen kommentteja. Kommenteilla kannattaa tehdä lisäselvityksiä mm. joistakin suunnitteluvalinnoista, varoituksista, poikkeuksista tai juridisista asioista.

Koodin eläessä ja muuttuessa, kommentit usein jäävät vähemmälle huomiolle josta seuraa kommenttien suurin ongelma — niiden paikkaansapitämättömyys, ristiriitaisuus ja redundanttisuus toteutetun koodin kanssa.

Robert C. Martinin mukaan, kommentti tuotantokoodissa on usein osoitus kyvyttömyydestä selvittää toiminnallisuutta muulla tavoin. Hyvässä koodissa tapahtumat ja niihin liittyvät instanssit eivät myöskään vaadi lisädokumentaatiota kuin poikkeustapauksissa.

Hyvässäkin koodissa tapahtuu virheitä

Clean code näyttää hyvältä, mutta sen tulee olla myös robustia, joten ohjelmiston itse aiheuttaviin sekä ulkoa tuleviin virheisiin tulee varautua suunnittelemalla niiden havaitsemis- ja käsittelyrakenteet. Nykyaikaisten ohjelmointikielien try – catch-rakenteet mahdollistavat virheen käsittelyn myös siistillä tavalla ilman, että kutsuvien metodien tarvitsee huolehtia virheenkäsittelystä.

Havaitsemisen ja kiinni saamisen lisäksi virheet tulee käsitellä järkevästi ja informatiivisesti. Testausta ja ylläpitoa helpottamaan virheenkäsittelyn olisi hyvä palauttaa ajonaikaista lisätietoa virheeseen johtaneista syistä.

Hyvä koodi on testattu

Jotta koodia voidaan sanoa hyväksi koodiksi tulee sen olla helposti luettavan, ymmärrettävän, ylläpidettävän jne. lisäksi testattu. Nykyisen käsityksen mukaan yksikkötestit ja testivetoinen kehitys (TDD) tarjoavat parhaimman lähestymistavan testaamiseen. Yksikkötestit ovat oleellinen osa tuotantokoodia, joten niihin pätevät samat clean-vaatimukset kuin testattavaan koodiinkin ylläpidettävyyden, luotettavuuden ja selkeyden osalta.

Yhteenveto

Hyvän koodin moduulit ovat siis heikosti kytkeytyneet toisiin moduuleihin ja niiden sisäiset rakenteet ovat liittyneet vahvasti yhteen, toteuttaen loose coupling / high cohesion -periaatetta. Hyvässä toteutuksessa moduulien käyttämät rajapinnat on kuvattu tarkasti ja ne piilottavat taakseen tiedon, jota ei tarvita ohjelman suorittamiseen (encapsulation). Jos koodi on em. asioiden lisäksi helppo ylläpitää ja ymmärtää on koodissa jo paljon hyvän koodin aineksia. Hyvälle koodille ei ole editorissa tai kääntäjässä clean code -vipuja eikä sen toteuttamiselle ole yhtä selkeää ohjeistusta. Hyvä koodi ei myöskään välttämättä synny ensimmäisellä yrityksellä vaan voi vaatia iterointia, työtä ja aikaa.

Lähteet

Jani Repo on ohjelmistoasiantuntija OCTO3 Lappeenrannan toimistolla. Jani on erityisen kiinnostunut sulautetuista järjestelmistä ja laiteläheisestä ohjelmoinnista.