Ohjelmointivirhe

Ohjelmointivirhe (puhekielessä bugi) on tietokoneohjelman lähdekoodissa oleva virhe. Virheet jaetaan kahteen pääluokkaan: syntaksivirheet ja semanttiset virheet. Syntaksivirheet paljastuvat heti, koska kääntäjä ei pysty kääntämään sellaista ohjelmakoodia eikä ohjelmointikielen tulkki voi tulkaten suorittaa sellaista ohjelmakäskyä. Semanttinen virhe saa ohjelman toimimaan väärin jossain tilanteessa. Virheellinen toiminta saattaa johtua myös kääntäjän tai tulkin virheellisestä toiminnasta. Väärä toiminta määritellään tapauskohtaisesti ja joissain tapauksissa voi olla epäselvää, onko yllättävä toiminta virheellistä. Ohjelmointivirhe tapahtuu ohjelmointi- (implementointi eli toteutus) tai suunnitteluvaiheessa (speksaus) ja ilmenee ohjelmaa ajettaessa. Virheen korjaamisen kannalta on hankalaa, että se saattaa ilmetä vain jossain yksittäisessä ja harvinaisessa tilanteessa, jota on vaikea hahmottaa. Kaikissa hyödyllisissä tietokoneohjelmissa sanotaan olevan virheitä. 

Ohjelmankirjoituksessa pätee virheen suurusluokkaan seuraava: Mitä myöhemmässä ohjelmistonkehityksen vaiheessa virhe tehdään, sitä helpompi se on korjata. Jos virhe tapahtuu jo suunnittelu- ja määrittelyvaiheessa, korjaaminen on usein hankalaa ja jopa mahdotonta. Hyvin kirjoitetuissa ohjelmissa niitä on suhteellisen vähän, ja ne ovat niin lieviä, etteivät ne estä ohjelmaa täyttämästä tarkoitustaan. Ohjelman, jossa on paljon vakavia virheitä, sanotaan olevan buginen. Sana tulee englannin kielen ludetta ja hyönteistä tarkoittavasta sanasta bug (suom. ötökkä). Sana on vanha insinööritermi, jota esimerkiksi Edison käytti kirjoittaessaan vuonna 1878:

Ohjelmointivirheellä selitetään myös usein ohjelmistosodankäyntiin liittyviä ohjelmistojen ”ominaisuuksia”, esimerkiksi ohjelmistoon jääneitä takaportteja ja turvallisuusrakenteiden ohituksia tai puskurin ylivuotovirhettä (ohjelmointivirheitä). Käytännössä tarkoituksellisen vian ja tahattomasti syntyneen ohjelmointivirheen erottaminen on lähes mahdotonta. Ne voidaan erottaa vain tietämällä virheen tavoite.

Bugi-termin väitetään syntyneen vuonna 1946, kun Grace Hopper jäljitti virheen Harvard Mark II -tietokoneen releeseen jääneeseen yöperhoseen. Perhonen poistettiin ja liitettiin lokikirjaan. Hopper on sanonut, ettei ollut tapahtuma-aikana paikalla, mutta se oli yksi hänen mielikertomuksistaan. Hopper ja ryhmä vaikutti termin debugata () yleistymiseen.
Hopperin mukaan termiä bugi käytettiin kuvaamaan tutkaongelmia toisen maailmansodan aikana.

Virheiden estäminen 
Ohjelmistoja tuottaessa on monia erilaisia tapoja estää virheiden eli bugien syntymistä ja niiden pääsyä tuotantoon asti. Tässä on lueteltu niistä muutama:

 Hyvä suunnittelu ja vaatimusten määrittely: Hyvät vaatimukset vähentävät erityisesti speksausvirheiden mahdollisuutta, sillä ohjelmoijilla on parempi käsitys siitä, miten ohjelman tulee toimia.
 Ohjelman analysointityökalut: Lähdekoodia voidaan yleensä analysoida ulkoisten ohjelmien avulla, esimerkiksi kirjoitus- ja rakennevirheiden varalta, suoraan ohjelmointiympäristössä.
 Koodikatselemukset: Lähdekoodin lukeminen erityisesti ulkoisen, tuoreen silmäparin, toimesta saattaa mahdollistaa virheiden löytämisen hyvin kustannustehokkaasti.
 Standardien noudattaminen: Koodausstandardien mukainen rakenne ja komennot mahdollistavat virheiden havaitsemisen mahdollisimman aikaisessa vaiheessa.
 Kattava testaus: Monipuolisella testaamisella varmistetaan, että ohjelmisto toimii halutulla tavalla ja havaitaan funktionaalisten ongelmien lisäksi myös esimerkiksi suorituskyky- ja käytettävyysongelmat.
 Regression testaus: Muutosten tekeminen ohjelmistoon voi vaikuttaa aiemmin toimineisiin osiin. Siksi on tärkeää testata myös aiemmin läpikäytyjä koodiosia, sillä uudet muutokset voivat rikkoa ne.
 Ketterät käytännöt: Lyhyet tuotantosyklit mahdollistavat sekä virheiden havaitsemisen aikaisin että nopean reagoinnin niihin.
 Versionhallinta ja varmuuskopiot: Haarojen käyttö mahdollistaa kunnollisen testauksen ennen kuin ne on testattu tarpeeksi kattavasti. Säännölliset varmuuskopiot auttavat palauttamaan järjestelmän toimintakunnon nopeasti, mikäli virheitä pääsee tuotantoon asti.

Debuggaus 
Debuggaus eli virheenjäljittäminen on prosessi, jossa ohjelmointivirheitä eli bugeja paikallistetaan ja korjataan. Usein virheen löytäminen on esimerkiksi helppoa, mutta yksittäinen koodirivi, jossa virhe ilmenee, voi olla hyvin vaikea löytää.

Debuggauksessa käytetään apuna debuggeria, joka suorittaa koodia rivi riviltä, jolloin ohjelmistokehittäjän on mahdollista nähdä, missä järjestyksessä koodia ajetaan ja tarkastella muuttujien arvoja jokaisessa koodin ajon vaiheessa. Tavallisesti tarkasteltavalle koodiriville asetetaan "breakpoint", johon koodin ajo pysähtyy ja tämän jälkeen koodia ajetaan rivi kerrallaan.

Debuggaaminen on myös mahdollista ilman debuggeria esimerkiksi kirjoittamalla muuttujien arvoja konsoliin tai erilliseen lokitiedostoon (eng. tracing).

Debuggaus ja testaus ovat toisilleen komplementaarisia prosesseja. Testauksen tarkoitus on selvittää, mitä tapahtuu, kun ohjelman lähdekoodeissa on virhe. Debuggauksen tehtävä on paikallistaa virhe ja korjata se. Testauksesta ei selviä, mikä virhe ohjelmassa on, se ainoastaan paljastaa minkälaisia seurauksia virheellä on. Kun virhe on tunnistettu, debuggauksella virhe voidaan selvittää ja korjata.

Debuggauksen haasteet 
Debuggaus voi olla työlästä ja mahdollisesti vaatia jopa enemmän aikaa kuin itse koodin kirjoittaminen. Debuggaus voi olla erityisen haasteellista, kun

 Virheestä aiheutuva ongelma on selvä, mutta sen aiheuttaja ei.
 Virhe on vaikea saada toistettua. Esimerkiksi ei ole tiedossa, millä inputilla virhe on saatu aikaiseksi tai sen aikaansaaminen on hankalaa.
 Koodin riippuvuussuhteet eivät ole selviä, jolloin koodivirheen korjaaminen yhdessä paikassa koodia voi aiheuttaa virheitä toisaalla koodissa.

Katso myös
 Puskurin ylivuotovirhe
 Ohjelmistosodankäynti
 Beetatestaus
 Profilointi

Lähteet

Aiheesta muualla

 Why are there Bugs in Software?