Viime vuosina eteen on tullut sovelluksia jotka ovat ajautuneet frameworkin vangeiksi. Näissä sovelluksissa esimerkiksi kriittiset bugifixit tai tietoturvapäivitykset eivät enää ole mahdollisia järjellisellä effortilla koska framework on kaapannut vallan ja määrittää miten sovellusta ylläpidetään ja päivitetään. Ja tämä tulee kalliiksi.
Voi sentään! Miten tässä nyt näin on päässyt käymään?
Valta
Valta on koodarilla ja sovelluksella. Tai näin sen ainakin tulisi olla.
Koodari voi kuitenkin delegoida valtaa esimerkiksi frameworkeille ja ulkoistaa monia asioita kirjastojen hoidettavaksi. Ja näin usein kannattaakin tehdä. Delegoidaan. Frameworkeistä ja kirjastoista on paljon apua moneen ongelmaan. Oli se sitten ORM tai dependency injection tai web framework.
Mutta voiko valtaa delegoida liikaa?
Firman Frameworkin mies
Näinhän näissä usein käy. Valtaa delegoida liikaa.
Me tehään Springillä!1!
Just just. Firman Frameworking miehiä.
Näissä tapauksissa koko sovellus on yleensä kirjoitettu lähtien jo build filestä frameworkin ehdoilla. Ja vähintään sovelluksen main metodi on ulkoistettu frameworkille.
Sovellukset on kirjaimellisesti pultattu frameworkiin. Hitsattu kauttaaltaan yhteen intiimisti ja tiukasti. Kaikki frameworkin featuret joita suinkin voi hyödyntää on käytössä. main metodi, testit, dependency injection, persistence, web rajapinnat, jne. Ja codebase suorastaan hehkuu frameworkia ja sen voimaa.
Ja miksikäs ei. Jos kerran frameworkkiä käytetään niin tottakai siitä pitää ottaa kaikki mehut irti? Ja frameworkkien suurimpia lupauksia on buustata devaajien tuottavuutta. Keskityt vain oleelliseen ja framework hoitaa loput!
Kuulostaa mahtavalta! Vai kuulostaako?
Kontrolli
Frameworks are details - Uncle Bob
Jotta sovellus ja koodari voivat olla täydessä kontrollissa ei main metodia voi hallita mikään framework. Ja tämä on tärkeää.
Mutta mitä pahaa on antaa frameworkin antaa kontrolloida asioita?
Riippuvuus
Ongelema on frameworkkien tarjoamien featureiden riippuvuudet ja tapa kuinka frameworkkejä hyödynnetään. Mitä enemmän riippuvuuksia, mitä useampaa featurea hyödyntää ja mitä useammassa paikassa frameworkkiä käytetään niin sitä tiukemmin siinä ollaan myös kiinni.
Injektointi
Dependency Injection. Tämä oli ehkä suurin myynti argumentti jonka avulla esimerkiksi Spring löi itsensä läpi. Toki mukana oli paljon muutakin mutta dependency injection näytteli suurinta osaa.
Tarkkaavaiset lukijat saattavat tässä kohtaa oivaltaa että dependency injection on vain yksi ilmentymä inversion of controllista. Ja jos control on invertoitu main metodista alkaen niin..?
Karkki
Fraworkeillä on usein tarjolla omat karkkinsa. Ja tämä on sitä pahinta douppia. Oli sitten kyseessä tiedon tallennuksesta tai muista integraatioista. Useimmissa isoimmissa frameworkeissa on saatavilla useita “karkki” -rajapintoja moniin kirjastoihin. Hyvä esimerkki voisi olla vaikka Repository pattern joka käyttää usein Hibernatea konepellin alla.
Mutta kuten kaikessa, kohtuus on hyvä muistaa.
Yksi tarkkaan harkittu namu ei vielä välttämättä ole kovin vaarallista mutta useampi voi aiheuttaa ongelmia. Varsinkin jos menee mässäilyn puolelle.
Liikaa karkkia
Ja tässä kohtaa ongelmat alkavat yleensä konkretisoitua ja panttivankidraama voi alkaa.
Ongelma liittyy käytännössä frameworkin käyttämiin kolmansiin kirjastoihin joita ei enää voi päivittää koska frameworkin karkkikerros hajoaa näiden api muutoksiin.
Karikatyyrisesti tarina menee jotenkin näin:
"Kirjaston X päivitys vaatisi version 5 frameworkista mutta se on taas epäyhteensopiva frameworkin version 3 kanssa jota käytetään komponentin Y kanssa joka taas on epäyhteensopiva frameworkin version 5 kanssa."
Kyllä, nyt voi vapaasti huutaa, heittää television parvekkeelta tai muuten vaan päästää höyryjä. Useimmat meistä ovat törmänneet tähän muodossa tai toisessa uransa varrella.
Huonosti koodattu softa joka on tiukasti kiinni frameworkeissa voi aiheuttaa rankkaa päänsärkyä kun versioita pitää nostaa. Varsinkin jos koodia on paljon.
Efektiivisesti tässä on kyseessä jar hell / dll hell ilmiöstä.
Vieroitus
Pitäisikö sitten frameworkkien käytöstä luopua? Ei välttämättä. Frameworkit ovat hyödyllisiä ja niiden avulla on helppo ratkaista monta ongelmaa. Mutta niitä kannattaa hyödyntää vasta kun niistä saatavat hyödyt ovat suuremmat kuin niistä aiheutuvat haitat.
Kyse on ennenkaikkea siitä miten frameworkkejä käytetään.
Frameworkkien ja muidenkin riippuvuuksien käyttö kannattaa:
- Minimoida.
- Ottaa vain se mitä tarvitaan ja ne jotka aidosti tuovat arvoa.
- Varmistaa että hyödyt ovat suuremmat kuin haitat.
- Poimia yksitellen harkiten ja vasta viime hetkellä kun tarve realisoituu.
- Välttää frameworkkien tarjoamien “karkki”-rajapintojen käyttämistä.
- Valita konservatiivisesti ja käyttää vakaita, defacto ratkaisuja viimeisimpien trendivillitysten sijasta.
- Rajata tiettyihin moduuleihin tai luokkiin.
- Varmistaa että domain pysyy puhtaana ja irrallaan frameworkista.
Myös riskianalyysin tekeminen voi olla äärimmäisen arvokasta, etenkin jos käytössä on framework ja useampi sen tarjoamia karkkikerroksia. Tämä on tärkeää siksi että sovellukset ovat usein tuotannossa ajossa vielä pitkään sen jälkeen kun ne on kirjoitettu. Maailma muuttuu, mutta pysyvätkö sovellukset vauhdissa ja millä hinnalla?
Arkkitehtuurillisesti hyvä lähtökohta on käyttää domain keskeistä arkkitehtuuria kuten Hexagonal Architecturea. Domain Driven Design myös ohjaa ratkaisuihin jotka eivät ole framework keskeisiä.
Ja sanomattakin selvää että sovelluksen main metodi kannattaa pitää tiukasti omissa käsissä.
Yhteenveto
Moni framework tarjoaa mahdollisuuden ulkoistaa lähes kaikki sovelluksen tarvitsemat toiminnot frameworkin kautta tapahtuvaksi. Tähän ansaan ei kannata langeta vaan pitää ohjat tiukasti omissa käsissä ja olla tietoinen jokaisen riippuvuuden aiheuttamasta taakasta.
Hyvin rakennetussa modulaarisessa sovellusarkkitehtuurissa sovelluksen eri osat ovat helposti vaihdettavissa. Frameworkit ja muut riippuvuudet kannattaa ottaa huomioon kun tarkastelee sovelluksen modulaarisuutta.
Frameworkkien suurimpia haittoja on että ne lukitsevat helposti suuren määrän riippuvuuksia. Tällöin yksittäisen riippuvuuden päivittäminen ei enää välttämättä onnistu vaan koko framework tulee päivittää kerralla. Tämän takia frameworkkien ja muidenkin riippuvuuksien määrän minimointi sekä kapselointi on tärkeää jotta mahdollinen blast radius pysyisi mahdollisimman pienenä.
Domain keskeiset arkkitehtuurit ja Domain Driven Design tarjoavat hyvät lähtökohdat pitää frameworkkien aiheuttamat riskit hiukan helpommin hallittavissa.
Mutta lopulta vastuu on meillä kehittäjillä. Meidän tulee ymmärtää myös riskejä joita frameworkkien käyttöön liittyy.
Jos aihe kiinnostaa enemmänkin niin Uncle Bobin kirjassa Clean Architecture on paljon hyviä nostoja miten sovellukset saa pidettyä omissa käsissä.
Ja myös me Bytecraftilla olemme mielellämme auttamassa sinua tai kumppaneitasi löytämään aikaa kestäviä kustannustehokkaita ratkaisuja. Oli sitten kyseessä vain pienempi sparrailu, koulutus tai kokonainen projekti. Ota rohkeasti yhteyttä!