Ohjelmien ylläpito ja käänteistekniikat

Lectio praecursoria (10.6.2000), Jyväskylän yliopisto, Informaatioteknologian tiedekunta

(C) Jussi Koskinen, 2000-

 

1. Ohjelmistotyön ongelmat

Ohjelmistoteknisillä menetelmillä pyritään aikaansaamaan luotettavia ohjelmistoja taloudellisesti. Frederick P. Brooks Jr. on klassisessa, vuonna 1987 julkaistussa artikkelissaan ‘No silver bullet - essence and accidents of software engineering’ [1], eritellyt ohjelmistotuotannon oleellisia ongelmia. Eräs ongelmista on se, että ohjelmisto on ns. näkymätön (invisible). Lähdekoodista ei voida suoraan nähdä kaikkia ohjelmistojen kehittämisessä ja ylläpidossa oleellisia seikkoja. Ohjelmiston kaikkia oleellisia aspekteja ei myöskään yleisesti ottaen voida esittää ohjelmoijille, suunnittelijoille, ja ylläpitäjille käyttäen yhtä ainoaa havainnollista esitystapaa, mikä on mahdollista useilla muilla teknisillä aloilla. Toisin kuin muiden teknisten alojen tuotteet, ohjelmistot yleensä myös koostuvat suurimmaksi osaksi ei-standardinomaisista komponenteista, mikä hankaloittaa ylläpitoa ja uusiokäyttöä. Pyrittäessä muodostamaan käsitys ohjelmiston toiminnasta ja sen rakenteesta, ylläpitoon liittyen, ohjelma joudutaan yleensä käsitteellisesti osittamaan monilla eri tavoilla. Sitä voi myös olla hyödyllistä tarkastella eri karkeustasoilla ja tarkastelun kohteeksi kannattaa tilanteesta riippuen ottaa erilaisia riippuvuuksia, joita ohjelmiston osien välillä vallitsee.

 

2. Ohjelmien ylläpito

Ohjelmistojen kehitystä on perinteisesti vaiheistettu käyttäen ns. vesiputousmallia. Ohjelmistoja kehitettäessä lähtökohtana ovat järjestelmälle asetettavat vaatimukset. Ohjelmiston kehitys etenee vesiputousmallin mukaisesti suoraviivaisesti analyysi- ja suunnitteluvaiheiden kautta varsinaiseen toteutukseen, joka sisältää lähdekoodin kirjoittamisen. Tätä seuraa ylläpitovaihe.

     Ohjelmien ylläpito on perinteisesti määritelty muutosten teoksi ohjelmistoon sen jälkeen, kun se on luovutettu asiakkaille. Toisaalta, iteraation ja prototyypityksen merkitys tunnustetaan nykyään yleisesti. Tällöin ohjelmiston kehittäminen ei ole suoraviivainen prosessi, vaan etenee vaatimuksia asteittain tarkentaen. Tällaista tarkastelutapaa edustaa Barry Boehmin vuonna 1988 esittämä ns. ohjelmistotuotannon spiraalimalli [2]. Mallin mukaisesti järjestelmän kehitykseen liittyy kiinteä vuorovaikutus asiakkaiden kanssa. Ohjelmistoon tehdään muutoksia paitsi välttämättömien muutostarpeiden, myös tarkentuvien asiakasvaatimusten seurauksena. Ylläpidon problematiikan kannalta oleellista on se, että ohjelmiston muuttamista ei voida välttää.

     Ohjelmien ylläpito on perinteisesti tapana jakaa neljään laajaan tehtäväluokkaan. Ensinnäkin, korjaava ylläpito käsittää tietokoneohjelmissa olevien virheiden diagnosoinnin, paikantamisen ja korjaamisen. Toiseksi, sopeuttava ylläpito sisältää ohjelmiston liittämisen muuttuvaan ympäristöön. Kolmanneksi, parantava ylläpito käsittää lisäyksien ja muutosten tekemisen perustuen muuttuviin käyttäjien tarpeisiin. Neljänneksi, ennaltaestävä ylläpito sisältää ohjelmiston kehittämisen, s.e. sitä on jatkossa helpompi ylläpitää. Tämä luokitus on peräisin 80-luvun alusta ja on esiintynyt mm. Roger S. Pressmanin ohjelmistotekniikan perusteoksessa [3]. Vastaavankaltaista luokittelua on käyttänyt myös mm. Ian Sommerville omassa ohjelmistotekniikan kirjassaan [4].

     Ohjelmien ylläpito on merkittävä osa tietojärjestelmien kehittämisestä. Ian Sommervillen mukaan [4] on arvioitu, että ylläpitoon kuluu n. 65-75% ohjelmiston elinkaaren aikaisista kustannuksista. Ohjelmien ylläpito on myös vaativaa työtä. Vaativuutta lisääviä tekijöitä ovat mm.: ylläpidettävien ohjelmistojen ja tehtävien muutosten laajuus, muutosten tekeminen koodiin, joka ei ole muutoksien tekijälle ennestään tuttua, sekä puutteellinen dokumentointi. Esimerkki ylläpidon ongelmista ja siihen liittyvistä kustannusvaikutuksista on ns. vuosi 2000 (Y2K) ongelma. Vaikka vuosi 2000 ongelma onnistuttiinkin ratkaisemaan ennakoitua paremmin [5], vaati ongelman ratkaiseminen paljon työtä. Esimerkiksi IT Viikon mukaan Nokia käytti vuosi 2000 ongelmaan, mm. ennaltaehkäisevään ylläpitoon, n. 450 Mmk [6].

 

3. Ohjelmien ymmärtäminen

Ohjelmien ymmärtämisprosessin tavoitteena on lisätä ylläpitäjän tietotasoa liittyen seikkoihin, jotka ovat tärkeitä ohjelmointi- tai ylläpitotehtävien suorittamiselle. Riittävä ohjelmien rakenteen ja toiminnan ymmärtäminen on välttämätöntä, jotta ohjelmistoon voidaan tehdä muutoksia ilman, että niistä seuraa ei-toivottuja sivuvaikutuksia. Periaatteessa, muutokset tulisi suunnitella ja niiden seuraukset selvittää. Muutosten teko perustuen riittämättömään ymmärrykseen aiheuttaa ohjelmiston laadun rapautumista (ripple-effect). Hyvä ymmärrys myös edesauttaa muutosten tekoa s.e. ohjelmiston ylläpidettävyys ei tarpeettomasti heikkene.

     Ohjelmien ymmärtämisprosessille on esitetty lukuisia teoreettisia malleja [7,8]. Ymmärtämiseen vaikuttavia tekijöitä ovat mm. käytettävät ymmärtämisstrategiat, ymmärtämisen tuloksena muodostettavat mentaaliset mallit, sekä käsitteelliset rakenteet, joita vastaavat lähdekoodin tietyt ohjelmarivit.

     Ymmärtämisstrategiat kuvaavat niitä tapoja, joilla ylläpitäjä pyrkii ymmärtämään ohjelmaa. Tyypillisesti ymmärtämispyrkimyksiin liittyy lähdekoodin edestakainen selaus, pyrkimyksenä löytää rakenteita, jotka auttavat hahmottamaan ohjelman tarkoituksen ja toimintalogiikan. Ohjelmaa voidaan selata noudattaen systemaattisia tai opportunistisia strategioita. Esimerkiksi, noudatettaessa ylhäältä-alaspäin etenevää (ns. top-down) strategiaa, ylläpitäjä pyrkii ensin ymmärtämään kutsuhierarkian ylimmän tason - pääohjelman. Vastaavasti noudatettaessa alhaalta-ylöspäin etenevää (ns. bottom-up) strategiaa, ylläpitäjä kiinnittää ensin huomionsa perustason “rakennuspalikoihin”, esimerkiksi aliohjelmiin, joita mahdollisesti kutsutaan montaa eri kautta ohjelmassa. Käytännössä strategioita sovelletaan ottaen huomioon tilannekohtaiset tekijät, eli toimitaan joustavasti ja opportunistisesti. Näin muodostuvissa mentaalisissa malleissa on kyse ylläpitäjän “sisäisistä” näkemyksistä koskien ohjelmiston oleellisia aspekteja.

     Lähdekoodin tietyt selkeästi havaittavat osat tai ohjelmarivit (beacons) voivat toimia lähtökohtina laajempien kokonaisuuksien ymmärtämiselle, kuten esimerkiksi C-kielisten ohjelmien pääfunktio, jota vastaa merkkijono ‘main’. Tietyt ohjelmarivit yhdessä tuottavat tietyn toiminnallisuuden vastaten ohjelmoijien alkuperäisiä, ns. ohjelmasuunnitelmia (program plan). Kyseessä voi olla esimerkiksi vakiintunut tapa toteuttaa tietoalkioiden lajittelu, eli järjestykseen asettaminen, käyttäen esimerkiksi yleisesti tunnettua ‘quick sort’ algoritmia. Ymmärtäminen on erityisen hankalaa silloin jos tietyn toiminnallisuuden toteuttavat ohjelmarivit ovat hajautuneet s.e. ymmärtämisen kannalta oleellisten ohjelmarivien välissä on tässä suhteessa epäoleellisia ohjelmarivejä. Tällöin on kyseessä ns. hajautunut ohjelmasuunnitelma (delocalized program plan) [9]. Käsitteellisesti yhteenkuuluvien rakenteiden ymmärtämistä voidaan pyrkiä tukemaan tarjoamalla ylläpitäjälle esitysmuotoja, jotka tuovat esiin mielekkäät kokonaisuudet ja niiden väliset oleelliset riippuvuudet.

     Ohjelmien ylläpitotehtäviin ja ohjelmien ymmärtämiseen liittyen ylläpitäjillä on tietotarpeita. Nämä tietotarpeet voidaan tyydyttää perustuen tietoon, jota saadaan joko tutkimalla lähdekoodia, dokumentaatiota tai alan kirjallisuutta tai kommunikoimalla kolleegojen kanssa. Lähdekoodin analyysi voi olla manuaalista tai automatisoitua. Esimerkki dokumentaatioon kohdistuvasta tietotarpeesta on kohdealueen, eli sovellusalueen, käsitteiden määrittelyt. Lähdekoodista tarvitaan usein tietoa ohjelman sisältämien tunnisteiden määrittely- ja käyttökohteista, ohjelman sisältämien aliohjelmien, proseduurien tai funktioiden välisistä kutsusuhteista sekä siitä miten ohjelman suoritus etenee ja tieto siirtyy muuttujalta toiselle. Tämän kaltainen tieto on yleishyödyllistä, liittyen moniin ylläpitotehtävätyyppeihin.

 

4. Käänteistekniikat

Käänteistekniikalla (reverse engineering) tarkoitetaan ohjelmiston sisältämien komponenttien ja niiden välisten suhteiden tunnistamista ja vaihtoehtoisten - usein abstrahoitujen - esitysmuotojen luomista [10]. Tämä on erityisen tärkeää, jos ohjelmistoa ei ole dokumentoitu lainkaan, tai sen dokumentointi on puutteellista tai epäajantasalla. Käänteistekniikassa pyrkimyksenä on luoda lähdekoodi syötteenä esitysmuotoja, jotka tuovat esiin järjestelmän oleelliset piirteet. Täten prosessi etenee käänteisesti suhteessa perinteisen ohjelmiston kehityksen vesiputousmallin mukaiseen järjestykseen. Parhaimmassa tapauksessa voidaan automaattisesti tuottaa edeltävien vaiheiden keskeisten dokumenttien runkoja. Käänteistekniikoita voidaan soveltaa useilla eri tasoilla. Usein ohjelmistojen esittämiseen käytettyjä tapoja ovat mm. kutsukaaviot ja (kontrolli)vuokaaviot. Kutsukaavio koostaa tiedon siitä, miten ohjelman sisältämät aliohjelmat, proseduurit tai funktiot kutsuvat toisiaan, eli miten ne käynnistävät toistensa toiminnan. Vuokaavio taas kuvaa ohjelman suorituksen etenemistä ja etenemisen vaihtoehtoisia reittejä.

     Jotta ylläpidon tuki olisi asianmukaisesti kohdennettua, tulisi ylläpitäjälle tarjota välineistö, jolla hän voi saada tietoa kullakin hetkellä oleellisista tietoalkioista. Näitä voivat olla ohjelmanosat tai dokumentit tai niiden osat. Käänteistekniikat perustuvat ohjelmien automaattiseen analyysiin. Automaattinen ohjelma-analyysi voi olla staattista, jolloin käytetään ainoastaan tietoa, joka on saatavilla ohjelman käännösaikana tai dynaamista, jolloin hyödynnetään myös ohjelman suoritukseen liittyvää tietoa. Ohjelmien automaattiseen analyysiin on käytettävissä lukuisia tekniikoita.

     Lähdekoodin analyysissä eräs tekniikka, jolla voidaan edesauttaa tietyssä tilanteessa relevanttien näkymien muodostamista on ns. ohjelmien siivuttaminen (jota myös joskus viipaloinniksi kutsutaan). Siivutus on alunalkaen Mark Weiserin vuonna 1982 esittämä tekniikka [11]. Epäformaalisti ilmaisten, siivuun sisällytetään ne ohjelmanosat, joilla on merkitystä suhteessa valittuun lähtökriteeriin. Lähtökriteeri on tyypillisesti muuttujan esiintymä tietyssä kohtaa ohjelmaa. Käytännössä, siivuun sisällytettävät ohjelmanosat saadaan määriteltyä suorittamalla ohjelmalle tietovirta- ja kontrollivirta-analyysi. Esimerkiksi, korjaavan ylläpidon tapauksessa, ylläpitäjän tehtävänä voi olla ohjelmointivirheen jäljittäminen. Virheen olemassaolo havaitaan yleisesti sitä kautta, että ohjelma tuottaa tietyssä kohtaa virheellisen tulosteen. Tuloste määrittyy muuttujien arvojen kautta. Seuraamalla ohjelman suorituksen vaihtoehtoisia reittejä taaksepäin saadaan virheelliseen tulokseen vaikuttavat tekijät selville. Automatisoitu siivutus auttaa tätä prosessia esittämällä ylläpitäjälle näkymän, jossa vain ko. tehtävään liittyen oleelliset ohjelmanosat ovat mukana.

     Edellisen kaltaiset, virheenjäljitykseen liittyvät apuvälineohjelmistot on usein integroitu esim. kääntäjäympäristöön. Yleisempi integroitu ratkaisu on ns. CASE (Computer Assisted/Aided Software/System Engineering) ympäristö tai työkalupaketti (tietokoneavusteinen systeemi- tai ohjelmistotyöpaketti), joka sisältää monia ohjelmien kehittämisen tai ylläpidon kannalta hyödyllisiä apuvälineitä. Integroinnin ja apuvälineiden yhteistoiminnan perustana on usein tietointegraatio, joka perustuu usein siihen, että apuvälineet käyttävät yhteistä tietomallia. Tämän tietomallin perustana on usein erityisesti ylläpidon tukeen soveltuvien ns. lower-CASE -työkalujen osalta ohjelman jäsennyspuu ja symbolitaulu. Jäsennyspuu sisältää tiedon ohjelman hierarkkisesta, syntaktisesta rakenteesta ja symbolitaulu mm. tiedon ohjelman sisältämien nimettyjen symbolien, kuten muuttujien, määrittely- ja käyttökohteista.

     Nykyaikaisiin apuvälineisiin liittyy oleellisena osana tiedon esittäminen käyttäjälle havainnollisessa ja käyttökelpoisessa muodossa. Esimerkiksi Borlandin C/C++ kääntäjäympäristössä käytetään värejä erottamaan lähdekoodin erilaiset osat. Esimerkiksi kielen varatuilla sanoilla, operaattoreilla, vakioilla, makroilla ja kommenteilla on oma korostustapansa. Usein CASE-välineissä käytetään graafisia näkymiä täydentämään tekstuaalista esitystä. Tyypillisesti graafiset näkymät edesauttavat kokonaiskuvan muodostamisessa. Esimerkiksi nykyaikaisessa Imagix -työkalussa [12] voidaan ohjelmakoodin osien välisiä suhteita tarkastella haluttaessa myös käyttäen kolmiulotteista esitysmuotoa sekä valita tarkastelun karkeustaso, esimerkiksi se näytetäänkö moduulit, aliohjelmat, muuttujat, makrot jne. Eräs graafisiin esitysmuotoihin liittyvä ongelma on se, että laajojen ohjelmien ollessa kyseessä, myös tarvittavat graafiset näkymät ovat laajoja. Näitä ongelmia on omalta osaltaan helpottanut se, että näytöt ovat kehittyneet sekä kooltaan, että laadultaan. Valintojen tekomahdollisuudet ja abstrahointi ovat tärkeitä, jotta graafisia näkymiä voidaan hyödyntää täysipainoisesti. Koska ohjelman eri aspektien esittämiseen joudutaan käyttämään erilaisia esitystapoja, mm. erilaisia kaavioita, hyödyllistä on myös näissä kaavioesityksissä esiintyvien vastinparien väliset ristiinviittaukset, jotka mahdollistavat nopean siirtymisen esitysmuodosta toiseen.

 

5. Hypertekstiesitysmuodot

Ohjelmistotyön tukivälineissä on viime vuosikymmenellä yleistynyt myös ns. hypertekstiesitysmuoto. Hyperteksti koostuu solmuista, jotka sisältävät tekstiä sekä solmujen välisistä linkeistä, jotka mahdollistavat tekstin toisiinsa liittyvien osien nopean epälineaarisen läpikäynnin. Hypertekstin idean esitti aikoinaan Vannevar Bush jo vuonna 1945 [13]. Tämän jälkeen hypertekstiä on tutkinut mm. Theodore Holm Nelson 1960-luvulta lähtien. Yleisemmin hypertekstiä on alettu soveltaa 1980-luvun puolivälin jälkeen ja erityisesti World Wide Webin kasvun seurauksena. Hypertekstiesitysmuoto täydentää tekstihakujen ja kyselyjen käyttöä tarjoamiensa navigointimahdollisuuksien kautta.

     Ohjelmistotyön tukivälineissä hypertekstiesitysmuotoa on lähinnä käytetty dokumenttien (ja myös niiden osien) välisessä linkityksessä [14,15,16]. Automaattinen hypertekstin muodostus on lähinnä perustunut tilastollisiin ja dokumenttien ryhmittely (clustering) tekniikoihin [17]. Lähdekoodin sisältämiä osia ja niiden välisiä riippuvuuksia voidaan myös tarkastella hypertekstinä [18,19]. Tällaista hypertekstiä voidaan muodostaa automaattisesti, jolloin hyperteksti on eräs lähdekoodin esitysmuoto, jota voidaan käyttää mm. käänteistekniikkatyökaluissa täydentämään perinteistä lineaarista esitystapaa sekä graafisia esitysmuotoja. Systemaattiseen tiedonhakuun soveltuva, abstraktien syntaksipuiden ja ohjelmariippuvuuksien relaatio-ominaisuuksien käyttöön perustuva, lähestymistapa on esitetty väitöskirjassani [20].

 

Lähteet

[1]   Brooks, F.P. Jr. 1987. No silver bullet - essence and accidents of software engineering. Computer 20 (4), 10-19.

[2]   Boehm, B. 1988. A spiral model of software development and enhancement. Computer 21 (5), 61-72.

[3]   Pressman, R. 1997. Software Engineering - A Practitioner's Approach (4th ed.). McGraw-Hill.

[4]   Sommerville, I. 1996. Software Engineering (5th ed.). Addison-Wesley.

[5]   ITV. 2000a. Suomalaiset välttivät Y2K-ongelmat. Vuosituhat vaihtui ilman suuria ongelmia. IT Viikko 5.1.2000.

[6]   ITV. 2000b. Y2K maksoi Nokialle 450 miljoonaa. IT Viikko, 10.2.2000.

[7]   Brooks, R. 1983. Towards a theory of the comprehension of computer programs. International Journal of Man-Machine Studies 18 (6), 543-554.

[8]   von Mayrhauser, A. & Vans, A.M. 1995. Industrial experience with an integrated code comprehension model. Software Engineering Journal 10 (5), 171-182.

[9]   Letovsky, S. & Soloway, E. 1986. Delocalized plans and program comprehension. IEEE Software 3 (3), 41-49.

[10]  Chikofsky, E. & Cross, J. H. II. 1990. Reverse engineering and design recovery: a taxonomy. IEEE Software 7 (1), 13-17.

[11]  Weiser, M. 1982. Programmers use slices when debugging. Communications of the ACM 25 (7), 446-452.

[12]  Imagix. 2000. Imagix 4D. Product information available (10-Mar-00) in www-form at <URL: http://www.imagix.com>. Company: Imagix. Description: a reverse engineering tool for C and C++.

[13]  Bush, Vannevar. 1945. As we may think. Atlantic Monthly 176 (1), 101-108.

[14]  Bigelow, J. 1988. Hypertext and CASE. IEEE Software 5 (2), 23-27.

[15]  Garg, P. 1989. Information Management in Software Engineering: A Hypertext Based Approach. Los Angeles: University of Southern California (Diss.).

[16]  Oinas-Kukkonen, H. 1997. Improving the Functionality of Software Design Environments by Using Hypertext. Univ. of Oulu, Finland. Acta Univ. Ouluensis, A 296 (Diss.).

[17]  Allan, J. 1995. Automatic Hypertext Construction. Ithaca, NY: Department of Computer Science, Cornell University (Diss.).

[18]  Brade, K., Guzdial, M., Steckel, M. & Soloway, E. 1994. Whorf: a hypertext tool for software maintenance. International Journal of Software Engineering and Knowledge Engineering 4 (1), 1-16.

[19]  Nørmark, K. & Østerbye, K. 1994. Representing programs as hypertext. In B. Magnusson, G. Hedin & S. Minör (Eds.) Proceedings of the Nordic Workshop on Programming Environment Research (NWPER'94). LU-CS-TR: 94-127. Lund, Sweden: Lund Univ., 11-24.

[20]  Koskinen, J. 2000. Automated Transient Hypertext Support for Software Maintenance. Univ. of Jyväskylä, Finland. Jyväskylä Studies in Computing 4 (Diss.).

 

Abstract of the related Ph.D. thesis (in English)

 

Updated: June 11, 2000, Sept. 28, 2004, Aug. 3, 2010 by Jussi Koskinen.