Tietokannan rakenteen versiointi sovelluskehityksessä

images/apple-1854101_640.jpg

Useimmat sovellukset tallentavat tarvitsemiaan tai käyttäjänsä luomia tietoja johonkin tietovarastoon. Vaihtoehtoja tietovaraston toteutukselle on muutamia, mutta usein tietovarastoksi valikoituu relaatiokanta. Tietokanta huolehtii tiedon eheydestä ja rakenteesta relaatiomallin avulla. Relaatiotietokantoja löytyy niin nettisovellusten kuin isojen pankkijärjestelmien taustalta.

Sovelluskehityksen aikana joko sovelluksen tai tietokantasuunnitteluun erikoistuneet kehittäjät suunnittelevat tietokannan rakenteen. Sovelluksen kehityksen aikana tietokantarakenne elää ja sitä joudutaan muokkaamaan sovelluksen ominaisuuksien ja vaatimusten muuttuessa. Sovelluksen ylläpidossa joudutaan tekemään bugikorjauksia ja muutoksia sovellukseen ja sen tietokantarakenteeseen.

Tietokantarakenteen hallinta sovelluskehityksen aikana

Sovelluskehitysprojektissa sovelluksen lähdekoodin muutoksia hallitaan lähes aina versionhallinnan avulla. Usein luonteva ratkaisu tietokantarakenteen luomiseen käytettävien SQL-lauseiden tallentamiseen on käyttää versionhallintaa.

Tietokantarakenteen hallintaan liittyvät ongelmat

Sovelluksen vaatimien tietokantataulujen, proseduurien ja muiden tietokantarakenteiden määrä yleensä kasvaa mitä isompi ja pitkäkestoisempi sovellusprojekti on kyseessä. Tällöin tarvittavien tietokantaskriptien määrä ja koko myös kasvavat, jolloin niiden hallinta muuttuu myös haastavammaksi. Jos skriptien nimeämisen kanssa ei toimita kurinalaisesti ja noudateta yhteisesti sovittuja käytäntöjä, voi olla hyvinkin työlästä palauttaa mieleen, että missä järjestyksessä skriptit tulee ajaa.

Kun sovellus on ylläpitovaiheessa, joudutaan sovelluspäivitysten yhteydessä usein tekemään skriptejä, joilla muokataan tietokannassa olevaa dataa. Jos sovelluksesta on useampia instansseja asennettuna, on oltava tarkkana, kun tekee sovelluspäivitystä, että ajaa varmasti juuri kyseiseen sovellusversion tarvitsemat tietokantapäivitykset ja -migraatioskriptit. Tämä on virhealtista ja lisäksi mahdolliset ongelmat tai virheet tulevat esiin vasta sovellusta käynnistettäessä.

Sovelluspäivitystä on myös vaikea automatisoida, jos sovelluksen tarvitsemat tietokanta- ja migraatioskriptit täytyy ajaa manuaalisesti tai sovelluksen versiosta riippuen.

Mikä avuksi?

Sovelluskehittäjän ja -ylläpitäjän näkökulmasta olisi mukavaa jos ikuiseen tietokantaskriptien kanssa puljaamiseen olisi ratkaisu, jolla asia hoitusi niin ettei sitä tarvitsisi aina murehtia. Helpointa olisi jos sovelluspäivityksen voisi tehdä “vain” sovelluksen binääriä päivittämällä ja sovellus huolehtisi itse siitä, että tietokannasta on yhteensopiva versio ja ajaisi tarvittavat tietojen migraatioskriptit.

Omassa työssäni teen ohjelmistosuunnittelua yleensä JVM:lle ja useimmiten joko Javalla tai Scalalla. Esimerkiksi näille alustoille on tarjolla erilaisia ratkaisuja tämän ongelman ratkaisemiseksi. Javalle on tarjolla Liquibase-kirjasto, jonka avulla voi hoitaa koko tietokantarakenteen asentamisen tai muokkaamisen.

Scalalle (ja Javalle) on tarjolla [PlayFrameworkissä] (https://www.playframework.com/documentation/2.5.x/Evolutions) suoraan tietokantaevoluutiot tai halutessaan olisi mahdollista integroida Liquibase suoraan sovellukseen, jos ei käytä PlayFramework-kirjastoa.

Automaation hyödyt?

Tällainen ratkaisu helpottaa sovelluspäivityksen asentamisen automatisointia, koska sovelluksen käyttämän tietokantarakenteen ja tarvittavat tietojen migraatioskriptit voi paketoida suoraan asennettavaan binääriin. Näin päästään lähemmäs sitä, että sovelluksen asennuspaketin voi testata ja asentaa sellaisenaan, jolloin ei tarvitset etsiä “kadonneita” tietokantaskriptejä tai muistella missä järjestyksessä ne pitikään suorittaa.

Sovelluskehitys helpottuu, koska tietokantarakenteita on helpompi muokata ja siitä tulee luonteva osa kehitysprosessia. Ei tarvitse enää yrittää arvata mahdollisimman lähelle lopullista tietokantarakennetta jo projekti alkuvaiheessa. Tietokantarakenne voi elää vaatimusten muuttuessa projektin aikana samalla tavalla kuin lähdekoodi.

Uuden sovelluspalvelimen tai kehitysympäristön asentaminen helpottuu, jos sovelluksen voi ottaa suoraan versionhallinnasta ja käynnistää, jolloin haetaan riippuvuudet ja luodaan tarvittavat tietokantarakenteet. Tämä helpottaa myös uusien kehittäjien liittymistä tiimiin.

Sovelluksen tuotantopäivitysten asennustestaus helpottuu ja se on mahdollista automatisoida, koska päivityksen voi testata suoraan tuotantotietokannan varmuuskopiota vasten, jolloin myös tietojen migraatiot saadaan testattua. Näin voidaan vähentää tietokantojen muokkaamiseen liittyvää inhimillisten erehdysten riskejä.

Ohjelmistokehitystiimin ja tuotantoympäristöjä ylläpitävän tiimin työskentelytapoja voidaan tuoda DevOps-filosofian mukaisesti lähemmäs toisiaan, jolloin eri tiimien välinen rajanveto ja asioiden pallottelu tiimiltä toiselle vähenee. Työtavoissa päästään lähemmäs yhtä tiimiä ja ylläpitotiimin päänsärky tietokantamigraatioihin liittyen vähenee. Ei tarvitse käydä niin usein kädenvääntöä siitä, onko vika tuotantoympäristössä vai sovelluksen päivityspaketissa.

Ohjelmistoprojekteissa lähdekoodin ja tarvittavien riippuvuuksien, sekä kirjastojen versiointi ja hallinta on automatisoitu hyvin pitkälle erilaisilla työkaluilla.

Miksi ei siis myös tietokantarakenteen hallinta??

Viitteet:

Liquibase [http://www.liquibase.org/]

Playframework [https://www.playframework.com/documentation/2.5.x/Evolutions]

DevOps [https://en.wikipedia.org/wiki/DevOps]

Julkaistu 27.01.2017 – Jarkko Rantamäki

Lue myös