Miten koodin yhteensopivuusongelmia kannattaa hallita ohjelmistokehityksessä?
Ohjelmistoprojektissa tulee ennemmin tai myöhemmin vastaan tilanne, jossa jokin toimii kehitysympäristössä, mutta ei enää tuotannossa. Tai uusi kirjasto näyttää hyvältä idealta, kunnes vanha integraatio lakkaa toimimasta. Usein puhutaan bugista, vaikka todellinen ongelma liittyy yhteensopivuuteen.
Moni kehittäjä kohtaa tämän ensimmäisen kerran kirjastopäivityksen yhteydessä. Sovellus on toiminut pitkään ilman ongelmia, mutta yhden riippuvuuden uusi versio muuttaa rajapintaa, poistaa vanhan toiminnon tai käyttäytyy hieman eri tavalla kuin ennen. Muutos voi olla pieni, mutta vaikutus näkyy nopeasti koko järjestelmässä.
Yhteensopivuusongelmat eivät yleensä johdu huonosta koodista. Ne syntyvät siitä, että ohjelmistot eivät elä yksin. Jokainen järjestelmä käyttää kirjastoja, palveluita, tietokantoja, API-rajapintoja ja infrastruktuuria, jotka muuttuvat ajan myötä.
Miksi yhteensopivuusongelmia syntyy?
Ohjelmistokehityksessä muutokset ovat jatkuvia. Käyttöjärjestelmä päivittyy, selainversiot vaihtuvat, pilvipalvelut kehittyvät ja avoimen lähdekoodin kirjastot julkaisevat uusia versioita.
Paperilla kaikki näyttää yksinkertaiselta. Päivitetään komponentti uudempaan versioon ja jatketaan eteenpäin.
Käytännössä tilanne on harvoin näin suoraviivainen.
Uusi versio voi esimerkiksi vaatia eri version toisesta kirjastosta. Samalla vanha integraatio voi lakata toimimasta. Lopputuloksena yksittäinen päivitys käynnistää ketjun, joka vaikuttaa useisiin järjestelmän osiin.
Erityisesti pitkään käytössä olleissa yrityssovelluksissa ongelma korostuu. Vuosien aikana järjestelmään on voitu rakentaa kymmeniä integraatioita, joiden alkuperäisiä suunnitteluratkaisuja ei enää edes muisteta.
Yleinen virhe: kaikki päivitetään kerralla
☑️ Yksi riskialtteimmista päätöksistä on tehdä suuri tekninen päivitys yhdellä kertaa.
☑️ Ajatus kuulostaa tehokkaalta. Päivitetään ohjelmointikieli, kirjastot, framework ja infrastruktuuri samalla projektilla.
☑️ Todellisuudessa ongelmien syyn selvittäminen muuttuu lähes mahdottomaksi.
☑️ Jos järjestelmässä ilmenee virhe päivityksen jälkeen, mistä tiedetään mikä sen aiheutti?
☑️ Ongelma voi liittyä Java-versioon, uuteen tietokanta-ajuriin, muuttuneeseen API-rajapintaan tai johonkin täysin odottamattomaan riippuvuuteen.
☑️ Siksi monet kokeneet tiimit suosivat pienempiä muutoksia. Kun yksi asia muuttuu kerrallaan, myös vaikutukset on helpompi tunnistaa.
Rajapinnat aiheuttavat enemmän ongelmia kuin itse sovellus
➢ Kun yhteensopivuusongelmista keskustellaan, huomio kohdistuu usein sovelluksen omaan koodiin. Käytännössä ongelmat löytyvät kuitenkin usein järjestelmien väliltä.
➢ Esimerkiksi asiakashallintajärjestelmä voi lähettää tietoja laskutusjärjestelmälle. Molemmat toimivat moitteettomasti, mutta toinen osapuoli muuttaa kentän nimeä tai tietomuotoa.
➢ Teknisesti kyse ei ole suuresta muutoksesta.
➢ Liiketoiminnan näkökulmasta seuraukset voivat olla merkittäviä, jos tiedonsiirto keskeytyy eikä virhettä havaita heti.
➢ Tämän vuoksi integraatioiden testaaminen on usein yhtä tärkeää kuin itse sovelluksen testaaminen.
Takautuva yhteensopivuus säästää paljon työtä
Hyvin suunnitellussa ohjelmistossa vanhoja käyttäjiä ei pakoteta muuttamaan kaikkea kerralla.
Jos API-rajapintaan lisätään uusi toiminto, vanhojen kutsujen pitäisi yleensä toimia edelleen.
Tätä kutsutaan takautuvaksi yhteensopivuudeksi.
Käytännössä se tarkoittaa sitä, että uusia ominaisuuksia voidaan ottaa käyttöön ilman, että kaikki asiakkaat joutuvat päivittämään omia järjestelmiään saman tien.
Monessa yrityksessä juuri tämä erottaa hallitun kehityksen jatkuvista tuotanto-ongelmista.
Versiohallinta ei ratkaise kaikkea
☑️ Git on erinomainen työkalu, mutta se ei yksin estä yhteensopivuusongelmia.
☑️ Koodi voi näyttää täysin oikealta. Muutokset voidaan tarkistaa huolellisesti ja testit voivat mennä läpi.
☑️ Silti ongelmia voi syntyä vasta tuotannossa.
☑️ Syynä on usein ympäristöjen ero.
☑️ Kehittäjän koneella käytössä voi olla eri kirjasto, eri käyttöjärjestelmä tai eri konfiguraatio kuin palvelimella.
☑️ Tästä syystä modernissa ohjelmistokehityksessä pyritään rakentamaan mahdollisimman samanlaiset ympäristöt kehitykseen, testaukseen ja tuotantoon.
☑️ Mitä pienempi ero ympäristöjen välillä on, sitä vähemmän yllätyksiä ilmenee käyttöönoton jälkeen.
Testauksen rooli muuttuu
➢ Yhteensopivuusongelmien yhteydessä puhutaan usein automaattisesta testauksesta.
➢ Se on tärkeää, mutta pelkkä yksikkötesti ei välttämättä paljasta ongelmaa.
➢ Jos järjestelmä kommunikoi muiden palveluiden kanssa, tarvitaan myös integraatiotestejä.
➢ Jos ohjelmistoa käytetään eri selaimilla, tarvitaan käyttöliittymätestejä.
➢ Jos järjestelmä käsittelee suuria tietomääriä, tarvitaan kuormitustestausta.
➢ Moni yhteensopivuusongelma jää huomaamatta juuri siksi, että testaus kattaa vain oman sovelluksen eikä ympäröivää kokonaisuutta.
Dokumentaatio on usein aliarvostettu ratkaisu
Yllättävän moni ongelma liittyy siihen, ettei kukaan tiedä tarkasti, miten järjestelmän pitäisi toimia.
Kun projekti on ollut käytössä vuosia, alkuperäiset suunnittelijat eivät välttämättä enää työskentele yrityksessä.
Uusi kehittäjä joutuu tekemään muutoksia järjestelmään, jonka riippuvuuksia, integraatioita ja teknisiä päätöksiä ei ole dokumentoitu.
Tällöin yhteensopivuusongelmien riski kasvaa huomattavasti.
Hyvä dokumentaatio ei ole vain käyttöohje. Se kertoo myös, miksi jokin ratkaisu on tehty tietyllä tavalla ja mitä vaikutuksia muutoksilla voi olla.
Pilviympäristöt ovat lisänneet uuden kerroksen haasteita
☑️ Pilvipalvelut ovat helpottaneet ohjelmistojen käyttöönottoa, mutta samalla ne ovat tuoneet uusia yhteensopivuushaasteita.
☑️ Sovellus voi olla riippuvainen useista hallituista palveluista, tietokannoista, viestinvälitysjärjestelmistä ja ulkoisista API-rajapinnoista.
☑️ Kun jokin näistä muuttuu, vaikutus voi näkyä koko järjestelmässä.
☑️ Tämän vuoksi yhteensopivuutta ei enää tarkastella vain sovelluksen sisällä. Mukana ovat myös infrastruktuuri, palvelualustat ja kolmannen osapuolen palvelut.
Mitä kannattaa tehdä, kun ongelma löytyy?
➢ Ensimmäinen reaktio on usein alkaa korjata koodia välittömästi.
➢ Se ei aina ole paras ratkaisu.
➢ Ennen muutoksia kannattaa selvittää kolme asiaa:
Mikä muuttui?
Milloin ongelma alkoi?
Mihin järjestelmän osaan vaikutus kohdistuu?
➢ Kun nämä kysymykset saavat vastauksen, itse korjaus löytyy yleensä paljon nopeammin.
➢ Moni tuntikausien vianetsintä päättyy lopulta siihen, että ongelma ei ollutkaan sovelluksen logiikassa, vaan muuttuneessa riippuvuudessa, rajapinnassa tai ympäristöasetuksessa.
Lopuksi
Koodin yhteensopivuusongelmat ovat osa lähes jokaista ohjelmistoprojektia. Niitä ei voi poistaa kokonaan, mutta niiden vaikutuksia voidaan pienentää merkittävästi.
Yleensä parhaat tulokset eivät synny monimutkaisista teknisistä ratkaisuista. Ne syntyvät hallituista muutoksista, hyvistä testeistä, selkeistä rajapinnoista ja siitä, että järjestelmän riippuvuudet tunnetaan riittävän hyvin.
Kun ohjelmisto kasvaa, yhteensopivuus muuttuu vähitellen yhtä tärkeäksi kuin itse toiminnallisuus. Käyttäjälle sillä ei ole merkitystä, kuinka hienosti uusi ominaisuus on toteutettu, jos vanhat osat lakkaavat toimimasta sen seurauksena.