SOLID-pe­ri­aat­teet koostuvat viidestä ohjeesta, jotka koskevat puhtaita, yl­lä­pi­det­tä­viä ja joustavia koodeja ob­jek­ti­poh­jai­ses­sa oh­jel­moin­nis­sa. Pe­ri­aat­tei­den so­vel­ta­mi­nen ja nou­dat­ta­mi­nen johtaa helposti ym­mär­ret­tä­vään oh­jel­mis­to­suun­nit­te­luun pitkien ke­hi­tys­kausien aikana. Näiden pe­ri­aat­tei­den avulla voidaan paitsi kir­joit­taa parempia koodeja, myös ylläpitää olemassa olevia koodeja helpommin.

Mitkä ovat SOLID-pe­ri­aat­teet ja kuka ne on ke­hit­tä­nyt?

Hyvä läh­de­koo­di alkaa sään­nöis­tä, oh­jel­moin­ti­pa­ra­dig­mois­ta ja sopivasta oh­jel­moin­ti­tyy­lis­tä, jotta koodi on tehokasta ja siistiä. Juuri tämän takaavat Robert C. Martinin, Bertrand Meyerin ja Barbara Liskovin luomat viisi SOLID-pe­ri­aa­tet­ta. Nou­dat­ta­mal­la näitä pe­ri­aat­tei­ta olio-oh­jel­moin­nis­sa (OOP) kielillä kuten Python tai Java, kirjoitat paitsi parempaa koodia, myös varmistat te­hok­kaam­man koodin ylläpidon, kestävän ja joustavan oh­jel­mis­to­suun­nit­te­lun sekä paremman tur­val­li­suu­den pitkällä ai­ka­vä­lil­lä.

Nimi SOLID edustaa vankkaa oh­jel­moin­nin perustaa, joka jokaisen oh­jel­moin­tia oppivan tulisi hallita. Akronyymi on Michael Feat­her­sin luoma, ja se muodostuu viiden pe­ri­aat­teen en­sim­mäi­sis­tä kir­jai­mis­ta:

  • Yhden vas­tuu­alu­een periaate: Luokalla tulisi olla yksi ja vain yksi syy muu­tok­seen.
  • Avoin-suljettu-periaate: Oh­jel­mis­toen­ti­tee­tit (luokat, moduulit, funktiot jne.) tulisi olla avoimia laa­jen­nuk­sil­le, mutta sul­jet­tu­ja muu­tok­sil­le.
  • Liskovin kor­vaus­pe­ri­aa­te: Ala­luok­kien tulisi pystyä perimään ja to­teut­ta­maan kaikki yläluokan me­ne­tel­mät ja omi­nai­suu­det.
  • Ra­ja­pin­nan erot­ta­mi­sen periaate: Ra­ja­pin­nat eivät saa sisältää enempää me­ne­tel­miä kuin luokkien to­teut­ta­mi­nen edel­lyt­tää.
  • Riip­pu­vuu­den kään­tä­mi­sen periaate: Luokkien ei tulisi olla riip­pu­vai­sia muista luokista, vaan ra­ja­pin­nois­ta tai ab­strak­teis­ta luokista.

Mitä etuja SOLID-pe­ri­aat­teet tarjoavat?

Jos sääntöjä ei ole, seu­rauk­se­na on kaaos, mikä tulee erityisen selvästi esiin oh­jel­moin­nis­sa. Pienetkin virheet, epä­tark­kuu­det ja puutteet voivat tehdä hyvästä läh­de­koo­dis­ta täysin käyt­tö­kel­vot­to­man pitkällä ai­ka­vä­lil­lä, jos niitä ei korjata. Joskus riittää, että on mo­ni­mut­kai­sia luokkia, jotka vai­keut­ta­vat to­teu­tus­ta, tai ala­luok­kia, joilta puuttuu ylä­luok­kien yk­sit­täi­siä omi­nai­suuk­sia. SOLID-pe­ri­aat­teet var­mis­ta­vat, että re­fak­to­roin­tia tarvitaan mah­dol­li­sim­man vähän koodin kor­jaa­mi­seen.

SOLID-pe­ri­aat­teet luovat koodin:

  • Selkeä, siisti ja hou­kut­te­le­va: Oh­jel­mis­tot ja koodit ovat helpommin ym­mär­ret­tä­viä, te­hok­kaam­pia ja yk­sin­ker­tai­ses­ti näyttävät pa­rem­mal­ta.
  • Helppo ylläpitää: Suora ja selkeä rakenne helpottaa useiden yh­teis­työ­kump­pa­nei­den työtä sekä uuden että vanhan koodin yl­lä­pi­dos­sa ja hal­lin­nas­sa.
  • Mu­kau­tet­ta­vis­sa, laa­jen­net­ta­vis­sa, uu­del­leen­käy­tet­tä­vis­sä: Pa­ran­ne­tun luet­ta­vuu­den, vä­hen­ty­neen mo­ni­mut­kai­suu­den ja vastuiden sekä luokista riip­pu­vuu­den vä­he­ne­mi­sen ansiosta koodia voidaan paremmin muokata, mukauttaa ja laajentaa ra­ja­pin­to­jen kautta sekä käyttää jous­ta­vas­ti uudelleen.
  • Vähemmän vir­heal­tis: Puhdas koodi, jolla on yk­sin­ker­tai­nen rakenne, tar­koit­taa, että muutokset koodin yhteen osaan eivät vaikuta va­hin­gos­sa muihin alueisiin tai toi­min­toi­hin.
  • Tur­val­li­sem­pi ja luo­tet­ta­vam­pi: Haa­voit­tu­vuuk­sien, yh­teen­so­pi­mat­to­muuk­sien ja virheiden vä­hen­tä­mi­nen tai pois­ta­mi­nen parantaa jär­jes­tel­män toi­mi­vuut­ta ja luo­tet­ta­vuut­ta, mikä puo­les­taan parantaa tur­val­li­suut­ta.

Mitä kukin SOLID-periaate tar­koit­taa?

SOLID-pe­ri­aat­teet kuuluvat hyvän oh­jel­moin­nin kul­tai­siin sään­töi­hin, ja niiden tulisi olla tuttuja kaikille, jotka työs­ken­te­le­vät ob­jek­ti­poh­jai­sen oh­jel­moin­nin parissa. Seu­raa­vas­sa selitämme kunkin pe­ri­aat­teen yk­si­tyis­koh­tai­ses­ti.

SRP: Yhden vas­tuu­alu­een periaate

Robert C. Martin loi tämän pe­ri­aat­teen al­ku­pe­räi­sen mää­ri­tel­män teok­ses­saan ”Agile Software De­ve­lop­ment: Principles, Patterns and Practices” (Ketterä oh­jel­mis­to­ke­hi­tys: pe­ri­aat­teet, mallit ja käytännöt) kir­joit­ta­mal­la:

Lainaus

”Jo­kai­sel­la oh­jel­mis­to­mo­duu­lil­la tulisi olla yksi ja ainoa syy muu­tok­seen”.

Yhden vas­tuu­alu­een periaate (SRP) tar­koit­taa, että jo­kai­sel­la luokalla olio-oh­jel­moin­nis­sa (OOP) tulisi olla vain yksi vas­tuu­alue. Tämä tar­koit­taa, että luokkaa tulisi muuttaa vain yhdestä syystä. Toisin kuin yleisesti tulkitaan, tämä ei tarkoita, että luokalla tai mo­duu­lil­la voi olla vain yksi tehtävä. Se tar­koit­taa pi­kem­min­kin, että sen tulisi olla vastuussa vain tietyistä teh­tä­vis­tä, jotka eivät ihan­ne­ta­pauk­ses­sa ole pääl­lek­käi­siä muiden alueiden kanssa.

Vas­tuu­aluei­den pääl­lek­käi­syys, kuten eri lii­ke­toi­min­ta­seg­ment­tien toi­min­to­jen tar­joa­mi­nen, voi vaikuttaa luokan toi­min­nal­li­suu­teen, kun yhteen seg­ment­tiin tehdään muutoksia. Useiden vas­tuu­aluei­den ja lukuisien riip­pu­vuuk­sien hallinta voi aiheuttaa yhden alueen muutoksen seu­rauk­se­na koo­di­vir­hei­tä tai li­sä­muu­tos­ten tarpeen.

Yhden vas­tuu­alu­een periaate (SRP) on suun­ni­tel­tu luomaan yh­te­näi­siä moduuleja, joilla on tarkasti mää­ri­tel­lyt toiminnot tai kohteet. Sen selkeän, jä­sen­nel­lyn rakenteen, vähäisten riip­pu­vuuk­sien ja it­se­näis­ten to­teu­tus­ten ansiosta muutokset ja säätöjä voidaan tehdä te­hok­kaam­min, nopeammin ja su­ju­vam­min.

Huomio

Luokat, joita kutsutaan myös ob­jek­ti­tyy­peik­si, ovat ob­jek­ti­suun­tau­tu­neen oh­jel­moin­nin (OOP) keskeisiä ele­ment­te­jä. Niitä voidaan pitää objektien suun­ni­tel­mi­na, joissa kuvataan niiden omi­nai­suu­det, jotta to­del­li­set objektit ja käsitteet voidaan luoda uudelleen oh­jel­mis­tois­sa. Luokkia, joita kutsutaan myös mo­duu­leik­si, verrataan usein tie­dos­to­tyyp­pei­hin.

OCP: Avoimen ja suljetun periaate

Robert C. Martinin ja Bertrand Meyerin teoksessa Object Oriented Software Con­struc­tion OCP mää­ri­tel­lään seu­raa­vas­ti:

Lainaus

”Oh­jel­mis­toen­ti­tee­tit (luokat, moduulit, toiminnot jne.) tulisi olla avoimia laa­jen­nuk­sil­le, mutta sul­jet­tu­ja muu­tok­sil­le”.

OCP varmistaa, että muutosten to­teut­ta­mi­sek­si ei tarvitse kir­joit­taa oh­jel­mis­ton ydintä uudelleen. Jos tarvitaan pe­rus­teel­li­sia koo­di­muu­tok­sia, on olemassa riski hie­no­va­rais­ten virheiden ja koo­dion­gel­mien syn­ty­mi­ses­tä. Hyvin jä­sen­nel­ty koodi tarjoaa ra­ja­pin­to­ja, joita voidaan käyttää sen laa­jen­ta­mi­seen li­sä­toi­min­noil­la. Avainsana tässä on luokkien pe­riy­ty­mi­nen.

Uudet omi­nai­suu­det ja laa­jen­nuk­set, joihin on lisättävä selkeitä uusia toi­min­to­ja ja me­ne­tel­miä, voidaan helposti lisätä su­per­luok­kaan ala­luok­kien muodossa olevan ra­ja­pin­nan kautta. Näin sinun ei tarvitse muuttaa kir­joi­tet­tua, vakaata koodia. Se yk­sin­ker­tais­taa oh­jel­mis­to­jen ylläpitoa ja huoltoa ja parantaa mer­kit­tä­väs­ti vakaiden koo­die­le­ment­tien uu­del­leen­käy­tön te­hok­kuut­ta ra­ja­pin­to­jen kautta.

LSP: Liskovin kor­vat­ta­vuus­pe­ri­aa­te

Barbara H. Liskovin ja Jeannette M. Wingin teoksessa ”Be­ha­vio­ral Subtyping Using In­va­riants and Con­straints” LSP:n mukaan:

Lainaus

“Olkoon q(x) tyypin T objektien x suhteen to­dis­tet­ta­vis­sa oleva omi­nai­suus. Silloin q(y) pitäisi olla to­dis­tet­ta­vis­sa tyypin S objektien y suhteen, jossa S on T:n alityyppi”.

Se saattaa kuulostaa sa­la­pe­räi­sel­tä, mutta se on itse asiassa melko helppo ymmärtää: lin­ki­te­tyt tai laa­jen­ne­tut alaluokat doivent toimia kuten niiden yläluokat tai pe­rus­luo­kat. Tämä tar­koit­taa, että jokaisen alaluokan on säi­ly­tet­tä­vä perintönä yläluokan omi­nai­suu­det, eikä näitä omi­nai­suuk­sia saa muuttaa ala­luo­kas­sa. Ne doivent olla pe­ri­aat­tees­sa kor­vat­ta­vis­sa, mistä johtuu kor­vat­ta­vuus­pe­ri­aa­te. Ylä­luok­kia sen sijaan voidaan muokata.

Sel­ven­tääk­sem­me asiaa, tar­kas­tel­laan Robert C. Martinin klassista esi­merk­kiä suo­ra­kul­miois­ta ja neliöistä. Geo­met­rian op­pi­tun­neil­la opimme seuraavan pe­ri­aat­teen: jokainen neliö on suo­ra­kul­mio, mutta kaikki suo­ra­kul­miot eivät ole neliöitä. Neliöllä on suo­ra­kul­mioi­den tavoin suorat sivut, mutta lisäksi sen kaikki sivut ovat yhtä pitkiä.

Oh­jel­moin­nis­sa oletetaan, että sa­man­kal­tai­set tai näen­näi­ses­ti ident­ti­set luokat ovat toisiinsa liittyviä tai toi­sis­taan riip­pu­vai­sia, mikä johtaa vir­hei­siin, vää­rin­kä­si­tyk­siin ja epä­sel­vään koodiin. Tästä syystä oh­jel­moin­nis­sa luokka “Rectangle” ei ole neliö, eikä luokka “Square” ole suo­ra­kul­mio. Molemmat ovat ir­ro­tet­tu­ja toi­sis­taan ja to­teu­tet­tu erikseen. Ilman in­tegroi­tua yhteyttä luokkien välillä vää­rin­kä­si­tyk­set eivät voi johtaa luokkien välisiin vir­hei­siin. Tämä parantaa tur­val­li­suut­ta ja vakautta, kun ala­luok­kien tai ylä­luok­kien to­teu­tuk­sia vaih­de­taan ilman seu­rauk­sia.

ISP: ra­ja­pin­nan erot­ta­mi­sen periaate

Robert C. Martinin teoksessa ”The Interface Segre­ga­tion Principle” ISP mää­ri­tel­lään seu­raa­vas­ti:

Lainaus

”Asiak­kai­ta ei pitäisi pakottaa käyt­tä­mään ra­ja­pin­to­ja, joita he eivät käytä”.

ISP toteaa, että käyt­tä­jien ei pitäisi joutua käyt­tä­mään ra­ja­pin­to­ja, joita he eivät tarvitse. Toisin sanoen: Jotta asiak­kail­le voidaan tarjota tiettyjen luokkien toiminnot, uusia, pienempiä ra­ja­pin­to­ja rää­tä­löi­dään eri­tyis­vaa­ti­muk­siin. Tämä estää ra­ja­pin­to­jen kas­va­mi­sen liian suuriksi ja varmistaa, että luokkien välille ei muodostu vahvoja riip­pu­vuus­suh­tei­ta. Etuna on, että oh­jel­mis­to, jossa on irrotetut luokat ja useita pieniä, eri­tyis­vaa­ti­muk­siin rää­tä­löi­ty­jä ra­ja­pin­to­ja, on helpompi ylläpitää.

DIP: Riip­pu­vuu­den kään­tä­mi­sen periaate

Robert C. Martinin teoksessa ”The De­pen­dency Inversion Principle” (Riip­pu­vuu­den kään­tä­mi­sen periaate) viides ja viimeinen SOLID-periaate on seuraava:

Lainaus

”A. Korkean tason moduulit eivät saisi olla riip­pu­vai­sia matalan tason mo­duu­leis­ta. Molempien tulisi olla riip­pu­vai­sia ab­strak­tiois­ta. B. Ab­strak­tiot eivät saisi olla riip­pu­vai­sia yk­si­tyis­koh­dis­ta”.

DIP varmistaa, että läh­de­koo­di­ker­ros­ten tietyt toiminnot ja riip­pu­vuu­det pe­rus­tu­vat ab­strak­tei­hin ra­ja­pin­toi­hin, eivät suoraan toisiinsa. Oh­jel­mis­toark­ki­teh­tuu­rit on tyy­pil­li­ses­ti jär­jes­tet­ty kor­keam­piin käyt­tä­jä­ta­soi­hin ja alempiin, ab­strak­tim­piin tasoihin. Loo­gi­ses­ti aja­tel­tu­na voisi kuvitella, että abstrakti perusta vaikuttaa ylempien tasojen toi­min­taan. DIP kuitenkin tunnistaa tässä po­ten­ti­aa­li­sen ongelman, koska se luo riip­pu­vuuk­sia ylemmille tasoille alemmista tasoista, mikä voi johtaa ongelmiin.

Sen sijaan, että kor­keam­mat tasot lin­ki­te­tään alempiin tasoihin, korkeiden ja matalien tasojen luokat tulisi perustaa ab­strak­tei­hin, vä­lit­tä­viin ra­ja­pin­toi­hin. Ra­ja­pin­nat hakevat alemmilta tasoilta kor­keam­mil­la tasoilla tar­vit­ta­vat toiminnot ja asettavat ne saa­ta­vil­le. Tällä tavoin voidaan välttää alhaalta ylöspäin suun­tau­tu­va riip­pu­vuus­hie­rar­kia, joka voi ajan mittaan johtaa vir­hei­siin koodissa. Tämä helpottaa moduulien uu­del­leen­käy­tet­tä­vyyt­tä ja mah­dol­lis­taa alempien luokkien muutokset vai­kut­ta­mat­ta kor­keam­piin tasoihin.

Mitä tapahtuu, jos SOLID-pe­ri­aat­tei­ta ei noudateta?

Puhtaan, luettavan ja ylläpitoa hel­pot­ta­van koodin luominen tulisi olla oh­jel­mis­to­ke­hi­tyk­sen en­si­si­jai­nen tavoite. Jos ke­hit­tä­jät lai­min­lyö­vät SOLID-pe­ri­aat­tei­den kaltaisia olen­nai­sia ohjeita, koodi voi heikentyä huo­mat­ta­vas­ti haa­voit­tu­vuuk­sien, pääl­lek­käi­syyk­sien, ker­ty­nei­den virheiden ja lii­al­lis­ten riip­pu­vuuk­sien vuoksi. Ää­rim­mäi­sis­sä ta­pauk­sis­sa koodi voi ajan myötä tulla käyt­tö­kel­vot­to­mak­si. Tämä on mer­kit­tä­vä ongelma ket­te­räs­sä oh­jel­mis­to­ke­hi­tyk­ses­sä, jossa monet ihmiset työs­ken­te­le­vät usein mo­ni­mut­kais­ten koo­daus­töi­den parissa.

Epä­puh­taan koodin tai huonon koodin ylläpidon seu­rauk­set ovat muun muassa:

  • Koodin haju: Kun koodia ei ole kir­joi­tet­tu tar­vit­ta­vien stan­dar­dien mu­kai­ses­ti, se voi aiheuttaa koodin hajua tai “haisevaa koodia”, mikä johtaa toi­min­nal­li­siin vir­hei­siin ja yh­teen­so­pi­mat­to­miin ohjelmiin.
  • Koodin rap­peu­tu­mi­nen: Jos koodia ei yl­lä­pi­de­tä tai korjata re­fak­to­ri­soi­mal­la tai kalliilla koodin tar­kis­tuk­sel­la, se voi ku­vaan­nol­li­ses­ti “rappeutua” ja menettää täysin toi­min­ta­ky­kyn­sä. Toinen termi lu­ku­kel­vot­to­mal­le, mo­ni­mut­kai­sel­le koodille on spa­get­ti­koo­di.
  • Tur­val­li­suus­ris­kit: Ongelmat eivät rajoitu vain käyt­tö­kat­koi­hin, mo­ni­mut­kai­seen yl­lä­pi­toon ja yh­teen­so­pi­vuuson­gel­miin. On myös tur­val­li­suusauk­ko­ja, jotka antavat hait­taoh­jel­mil­le mah­dol­li­suu­den hyödyntää koodia, mukaan lukien nol­la­päi­vä­hyök­käyk­set.

Kuka kehitti SOLID-pe­ri­aat­teet?

SOLID-pe­ri­aat­tei­den alkuperä juontaa juurensa useista pe­ri­aat­teis­ta, jotka Robert C. Martin (”Uncle Bob”), yksi ketterän oh­jel­moin­nin aloit­teen­te­ki­jöis­tä, esitteli en­sim­mäi­sen kerran vuonna 2000 es­sees­sään ”Design Principles and Design Patterns” (Suun­nit­te­lu­pe­ri­aat­teet ja suun­nit­te­lu­mal­lit). SOLID-pe­ri­aat­teet ovat Robert C. Martinin, Bertrand Meyerin ja Barbara Liskovin keksimiä. Tarttuvan ak­ro­nyy­min po­pu­la­ri­soi Michael Feathers, joka järjesti viiden keskeisen pe­ri­aat­teen al­ku­kir­jai­met mie­leen­pai­nu­vaan jär­jes­tyk­seen.

Mitä vastaavia oh­jel­moin­ti­pe­ri­aat­tei­ta on olemassa?

Oh­jel­mis­to­ke­hi­tyk­ses­sä pe­ri­aat­teet ovat yleisiä tai hyvin tarkkoja ohjeita ja suo­si­tuk­sia toi­min­nal­le. Ob­jek­ti­suun­tau­tu­nee­seen oh­jel­moin­tiin ke­hi­tet­ty­jen SOLID-pe­ri­aat­tei­den lisäksi muita puhtaan koodin oh­jel­moin­ti­pe­ri­aat­tei­ta ovat:

  • DRY-periaate (Don’t repeat yourself) toi­min­noil­le, joilla on yksi ainoa esi­tys­muo­to
  • KISS-periaate (Keep it simple, stupid) mah­dol­li­sim­man yk­sin­ker­tai­ses­ti ra­ken­ne­tul­le koodille
Siirry pää­va­lik­koon