10. Kohti suurempia sulautettuja ohjelmistoja



Samankaltaiset tiedostot
10. Luento: Kohti suurempia sulautettuja ohjelmistoja. Tommi Mikkonen,

OHJ-4301 Sulautettu Ohjelmointi

10. Luento: Kohti suurempia sulautettuja ohjelmistoja. Arto Salminen,

11/20: Konepelti auki

Concurrency - Rinnakkaisuus. Group: 9 Joni Laine Juho Vähätalo

Ohjelmiston testaus ja laatu. Ohjelmistotekniikka elinkaarimallit

Agenda. Johdanto Ominaispiirteitä Kokonaisjärjestelmän määrittely Eri alojen edustajien roolit Sulautetut järjestelmät ja sulautettu ohjelmointi

ELM GROUP 04. Teemu Laakso Henrik Talarmo

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

Ohjelmistojen mallintaminen, mallintaminen ja UML

15. Ohjelmoinnin tekniikkaa 15.1

Simulaattorin asennus- ja käyttöohje

9. Luento: Ohjelmistotyö. Tommi Mikkonen,

ohjelman arkkitehtuurista.

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. X Poikkeusten käsittelystä

Ohjelmointi 1 / syksy /20: IDE

1 Kannat ja kannanvaihto

Ohjelmistojen suunnittelu

Arkkitehtuurikuvaus. Ratkaisu ohjelmistotuotelinjan monikielisyyden hallintaan Innofactor Oy. Ryhmä 14

Chapel. TIE Ryhmä 91. Joonas Eloranta Lari Valtonen

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

8/20: Luokat, oliot ja APIt

Ohjelmoinnin perusteet Y Python

Algoritmit 1. Luento 3 Ti Timo Männikkö

C-kielessä taulukko on joukko peräkkäisiä muistipaikkoja, jotka kaikki pystyvät tallettamaan samaa tyyppiä olevaa tietoa.

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

Uudelleenkäytön jako kahteen

Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä. Tiedonkätkentä. Aksessorit. 4.2

Digi-tv vastaanottimella toteutetut interaktiiviset sovellukset

Merkkijono määritellään kuten muutkin taulukot, mutta tilaa on varattava yksi ylimääräinen paikka lopetusmerkille:

Web-palvelu voidaan ajatella jaettavaksi kahteen erilliseen kokonaisuuteen: itse palvelun toiminnallisuuden toteuttava osa ja osa, joka mahdollistaa k

TIETOKONE JA TIETOVERKOT TYÖVÄLINEENÄ

Osoitin ja viittaus C++:ssa

Sulautettujen järjestelmien skaala on niin laaja, että on erittäin vaikea antaa yleispätevää kuvausta siitä millainen on sulautettu järjestelmä.

Oliosuunnitteluesimerkki: Yrityksen palkanlaskentajärjestelmä

Sisällys. JAVA-OHJELMOINTI Osa 7: Abstrakti luokka ja rajapinta. Abstraktin luokan idea. Abstrakti luokka ja metodi. Esimerkki

Olion elinikä. Olion luominen. Olion tuhoutuminen. Olion tuhoutuminen. Kissa rontti = null; rontti = new Kissa();

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä ja ulkopuolelta. Attribuuttien arvojen käsittely aksessoreilla. 4.2

Ohjelmointi 1. Kumppanit

Taulukot. Jukka Harju, Jukka Juslin

Tietorakenteet ja algoritmit

Java-kielen perusteet

Sisällys. 7. Oliot ja viitteet. Olion luominen. Olio Java-kielessä

2 Konekieli, aliohjelmat, keskeytykset

Rekursiolause. Laskennan teorian opintopiiri. Sebastian Björkqvist. 23. helmikuuta Tiivistelmä

Matematiikan tukikurssi, kurssikerta 2

Tutoriaaliläsnäoloista

OHJELMISTOKEHITYS -suuntautumisvaihtoehto

12. Näppäimistöltä lukeminen 12.1

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla

13/20: Kierrätys kannattaa koodaamisessakin

Ohjelmistojen mallintaminen

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Tietorakenteet ja algoritmit

1. Mitä tehdään ensiksi?

Lyhyt kertaus osoittimista

7. Näytölle tulostaminen 7.1

Pong-peli, vaihe Aliohjelman tekeminen. Muilla kielillä: English Suomi. Tämä on Pong-pelin tutoriaalin osa 3/7. Tämän vaiheen aikana

Tietotekniikan valintakoe

Tietueet. Tietueiden määrittely

4. Lausekielinen ohjelmointi 4.1

Liite 1: KualiKSB skenaariot ja PoC tulokset. 1. Palvelun kehittäjän näkökulma. KualiKSB. Sivu 1. Tilanne Vaatimus Ongelma jos vaatimus ei toteudu

TIE Tietorakenteet ja algoritmit 1. TIE Tietorakenteet ja algoritmit

C-ohjelmoinnin peruskurssi. Pasi Sarolahti

Agenda. Läpäisyvaatimukset Henkilökunta Luennot ja aikataulu Kurssimateriaali Harjoitustyöt Demoharjoitus Tentti ja arvostelu Muuta?

Palomuurit. Palomuuri. Teoriaa. Pakettitason palomuuri. Sovellustason palomuuri

Software product lines

15. Ohjelmoinnin tekniikkaa 15.1

Ohjelmistojen mallintaminen. Luento 11, 7.12.

Virtualisointiympäristössä on kolme pääosaa: isäntä (host), virtualisointikerros ja vieras (guest).

BlueJ ohjelman pitäisi löytyä Development valikon alta mikroluokkien koneista. Muissa koneissa BlueJ voi löytyä esim. omana ikonina työpöydältä

Hyvän salasanan tunnusmerkit Hyökkääjästä salasanan pitää näyttää satunnaiselta merkkijonolta. Hyvän salasanan luominen: Luo mahdollisimman pitkä

etunimi, sukunimi ja opiskelijanumero ja näillä

5. Luento: Rinnakkaisuus ja reaaliaika. Tommi Mikkonen,

Android ohjelmointi. Mobiiliohjelmointi 2-3T5245

Ohjelmien automaattisen verifioinnin reunamailla

Matematiikan tukikurssi

Ylläpito. Ylläpito. Ylläpidon lajeja Ohjelmistotuotanto, syksy 1998 Ylläpito

Ohjelmoinnin perusteet Y Python

Ongelma(t): Miten mikro-ohjelmoitavaa tietokonetta voisi ohjelmoida kirjoittamatta binääristä (mikro)koodia? Voisiko samalla algoritmin esitystavalla

Vasen johto S AB ab ab esittää jäsennyspuun kasvattamista vasemmalta alkaen:

Tietorakenteet ja algoritmit

16. Ohjelmoinnin tekniikkaa 16.1


Yhtälönratkaisusta. Johanna Rämö, Helsingin yliopisto. 22. syyskuuta 2014

AS C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin

2. Lisää Java-ohjelmoinnin alkeita. Muuttuja ja viittausmuuttuja (1/4) Muuttuja ja viittausmuuttuja (2/4)

Sisällys. 16. Ohjelmoinnin tekniikkaa. Aritmetiikkaa toisin merkiten. Aritmetiikkaa toisin merkiten

Hahmon etsiminen syotteesta (johdatteleva esimerkki)

12. Javan toistorakenteet 12.1

16. Ohjelmoinnin tekniikkaa 16.1

Vaatimusmäärittely Ohjelma-ajanvälitys komponentti

4. Luokan testaus ja käyttö olion kautta 4.1

1. Miten tehdään peliin toinen maila?

Yksikkötestaus. import org.junit.test; public class LaskinTest public void testlaskimenluonti() { Laskin laskin = new Laskin(); } }

Ylläpito. Ylläpidon lajeja

P e d a c o d e ohjelmointikoulutus verkossa

Pertti Pennanen DOKUMENTTI 1 (5) EDUPOLI ICTPro

Transkriptio:

164 Sulautettu ohjelmointi 10. Kohti suurempia sulautettuja ohjelmistoja Monet sulautetut järjestelmät ovat ajan myötä muodostuneet paljon monimutkaisemmiksi kuin mitä alun perin suunnittelijoilla on alun perin ollut mielessä. Esimerkkejä tällaisista järjestelmistä ovat esimerkiksi kännykät, joissa voi nykyisin olla varsin suorituskykyinen suoritin (tai jopa useita suorittimia) sekä gigatavuittain muistia. Vaikka kyseessä ehkä onkin edelleen pohjimmiltaan sulautettu järjestelmä, ohjelmoijan kannalta tilanne on kuitenkin toinen kuin aivan pienten ohjelmistojen tapauksessa. Yhtäältä muistia, suorituskykyä ja muita resursseja ohjelmistoteknisesti kestävän ratkaisun saavuttamiselle on yleensä merkittävästi enemmän, mutta toisaalta tavoitteena on toteuttaa ohjelmistolla paljon suurempi osa kuin mitä aiemmin oli tavoitteena, sillä hyvin pienissä sulautetuissa järjestelmissä ohjelmiston rooli on usein vähäinen. Käymme seuraavassa läpi jotakin vähän suuremman sulautetun ohjelmiston rakentamisen haasteita. 10.1 Ohjelmistopino Erilaiset ohjelmistokokonaisuudet, joita sulautettujen järjestelmien rakentamiseen on tarjolla useita, saattavat sisältää tukea sovelluskehitykselle. Tilanteesta riippuen käyttöjärjestelmän mukana saattaa tulla laajojakin kirjastoja, joiden varaan sovellusohjelmia on helppo rakentaa kohtuullisen nopeasti. Tällaisessa tilanteessa käytetään usein termiä ohjelmistopino (software stack) kuvaamaan ohjelmiston eri komponentteja. Eräs sulautetuissa järjestelmissä (OMAP4-ympäristö) käytetty ohjelmistopino on esitetty kuvassa 10.1.

Kohti suurempia sulautettuja ohjelmistoja 165 3D grafiikka- ja sovellusympäristö Sovelluskehys Symbian/Linux/Windows -sovellukset Selain Puhelin Kamera Multimedia Tietoturvallisuus 3D API Peruslaiteajurit Grafiikkakiihdytin DSPliityntä Virranhallinta Käyttöjärjestelmä (Symbian, Linux, Windows) Laitteisto Kuva 10.1 OMAP4-ohjelmistopino Varsinkin suuria järjestelmiä rakennettaessa on oikeastaan pakko myöskin hyödyntää jonkinlaisia kirjastoja (tai kokonaista valmista ohjelmistopinoa), sillä muussa tapauksessa kehitystyöstä tulisi liian pitkäkestoinen projekti. Toisin sanoen myös sulautettujen järjestelmien tapauksessa ollaan menossa kohti tilannetta, jossa ohjelmoijan on osattava ottaa huomioon oikeat kirjastot ja niiden tarjoamat rajoitukset ohjelmointivirheineen ja suorituskykyoletuksineen. Valitettavasti valmiiden kirjastojen käyttö sulautetussa ympäristössä ei aina ole aivan helppoa. Monet avoimen lähdekoodin ohjelmistot ovat periaatteessa helposti hyödynnettävissä, mutta esimerkiksi lisenssiehdot voivat asettaa rajoituksia, jotka eivät ole hyväksyttävissä sulautettujen järjestelmien toteutuksessa. Saattaa jopa olla niin, että valmiiden kirjastojen käyttö voi pakottaa sulautetun laitteen toteuttajan julkaisemaan kaiken laitekohtaisen ohjelmakoodin, varsinkin jos käytetyn kirjaston lisensseissä on voimakas copyleft-vaikutus 22. Toinen mahdollinen, valmiisiin kirjastoihin liittyvä ongelma on, että sulautetut järjestelmät ovat usein laitteistoltaan pitkälle optimoituja

166 Sulautettu ohjelmointi johonkin tiettyyn ja spesifiin tarkoitukseen. Tästä syystä ohjelmistotekniset ratkaisut, jotka toimivat hyvin esimerkiksi silloin, kun ohjelmistoa käytetään PC-ympäristössä, eivät olekaan toimivia silloin, kun laitteessa on vähän muistia tai erilainen suoritinarkkitehtuuri. Esimerkkinä mainittakoon vaikka Linux-käyttöjärjestelmän ydin, jossa on useita sellaisia ominaisuuksia, joista ei ole välttämättä hyötyä (pienten) sulautettujen järjestelmien toteutuksessa, mutta joiden poistaminen ytimestä yhden laitteen vuoksi ei välttämättä ole tarkoituksenmukaista, ainakaan jos tarkastellaan koko Linux-ytimen elinkaarta ja kaikkia mahdollisia käyttäjiä. Tästä syystä valmistaja voi joutua tekemään poistotyön aina uudelleen, kun ytimestä julkaistava uusi versio halutaan sisällyttää laitteeseen. 10.2 Ohjelmistojen siirrettävyydestä Jopa sellaisessa tilanteessa, jossa kohdelaitteita on vain yksi, voidaan joutua hallitsemaan eri ympäristössä toimivia ohjelmia. Mitä enemmän erilaisia kohdelaitteita on tarkoitus rakentaa, ja mitä enemmän käyttöympäristöjä ohjelmalle on odotettavissa, sitä enemmän ohjelmoija joutuu panostamaan ohjelmiston siirrettävyyteen. Lisäksi voi olla niin, että siirrettävyyteen halutaan panostaa, jotta ei jäätäisi yhden ainoan valmistajan loukkuun, vaan uuteen laite- ja ohjelmistoympäristöön siirtyminen olisi helppoa. Mikäli mahdollista, tulisi ohjelma kirjoittaa niin, että se on siirrettävissä ympäristöstä toiseen muutoksitta. Näin ei kuitenkaan voida aina tehdä. Seuraavassa käydään läpi joitakin vaihtoehtoja ongelman ratkaisemikseksi. Mikään ratkaisuista ei täytä kaikkia tarpeita. Niinpä eri vaihtoehtoja on käytettävä rinnan. Lisäksi joskus on vain yksinkertaisesti hyväksyttävä, että ohjelma ei kerta kaikkiaan ole siirrettävissä toiseen ympäristöön, vaan tällöin on rakennettava kokonaan uusi toteutus. Näin saattaa käydä esimerkiksi silloin, kun tehokkuussyistä joudutaan optimoimaan ohjelmaa tiettyyn ympäristöön. 10.2.1 Ehdollinen käännös Ehdollinen käännös on mahdollinen joissain ohjelmointikielissä. Sulautetuissa järjestelmissä yleisin toteutuskieli on C, jonka esikääntäjä osaa 22. Copyleft on sanaleikki termistä copyright, ja tarkoittaa, että koodin muutosten tekijällä on tietynlainen velvollisuus jakaa tekemiään muutoksia. Tarkat vaatimukset vaihtelevat lisenssikohtaisesti.

Kohti suurempia sulautettuja ohjelmistoja 167 toteuttaa ehdollisen kääntämisen. Ehdollinen kääntäminen on yleensä mahdollista myös symbolisella konekielellä kirjoitetuissa ohjelmissa ja monissa C:n sukulaiskielissä kuten C++:ssa. Ehdollisessa kääntämisessä voidaan käännösaikaisten symbolien avulla hallita käännöstä. Jollain symbolilla voidaan kertoa kohdekoneen käyttöjärjestelmä, jolloin sopivilla testeillä voidaan generoida tälle käyttöjärjestelmälle sopivaa ohjelmakoodia. Vastaavalla tavalla voidaan asettaa ehdon taakse testausaikaisia välitulostuksia tai muuta vastaavaa. Tarvittavat symbolit voidaan määritellä joko erillisessä ympäristökohtaisessa otsikkotiedostossa (esimerkiksi header.h) tai sitten ne voidaan asettaa kääntäjälle komentorivin määreinä tai osana esimerkiksi makefilen sisältämiä määreitä. Ehdollinen käännös on kyllä toimiva tapa, mutta se tekee ohjelmakoodista helposti sotkuista luettavaa, ja muutosten ja korjausten tekeminen vaikeutuu. Tämän takia ehdollista käännöstä ei pidetä parhaana tapana huolehtia siirrettävyydestä. 10.2.2 Ohjelmamakrot Makrot korvaavat pieniä aliohjelmia. Aliohjelmakutsun asemesta kääntäjä generoi makron ohjelmakoodin sen kutsun paikalle. Esimerkiksi C-kielen printf-funktio onkin itse asiassa makro. Joissain kielissä ei ole makroja lainkaan, mutta niiden asemesta aliohjelma voidaan määritellä inline-tyyppiseksi. Tällöin kääntäjä voi generoida kutsusta joko aidon kutsun tai sitten laajentaa ohjelmakoodin kutsun paikalle. On myös mahdollista antaa kääntäjän itse päättää, milloin se toteuttaa jokin aliohjelman makroamistekniikalla. Makrojen sisältö voidaan toteuttaa ympäristökohtaisesti, esimerkiksi niin, että makrokirjasto on erillinen eri ympäristöissä. Toinen vaihtoehto on käyttää makrojen sisällä ehdollista kääntämistä, jolloin ohjelmakoodissa ehdollisuus ei näy, mutta sen tarjomat hyödyt ovat käytettävissä. Makrot voivat olla vaarallisia käyttää, sillä niiden ohjelmointi vaatii erityistä tarkkuutta varsinkin C-kielen ja sen sukulaisten yhteydessä. Esimerkiksi määritelmä #define nelio(x) x * x näyttäisi määrittelevän makron, joka palauttaa parametrina annetun luvun toisen potenssin. Näin onkin, jos parametrina annetaan yksittäinen muuttuja tai luku. Mutta tuloskoodi voi yllättää, jos parametriksi laitetaan vaikkapa lauseke b - 1. Näin ohjelma

168 Sulautettu ohjelmointi int b = 3; int a = nelio(b - 1) * 3; ei sijoittaisi muuttujaan a odotettua arvoa 12, vaan arvon -3, koska alempi rivi laajentuisi muotoon int a = b - 1 * b - 1 * 3; Ratkaisu on kirjoittaa makroon tarpeeksi sulkeita: #define nelio(x) ((x) * (x)), jolloin esimerkki saa avattuna muodon: int a = ((b - 1) * (b - 1)) * 3; ja tulos on odotettu 12. Makroja tulee käyttää harkiten. Ne ovat varsinkin toistuvissa kohdissa kuten testausaikaisissa välitulostuksissa erinomaisia apuvälineitä, mutta eivät sovellu kovin monimutkaisiin tapauksiin. Toinen makrojen käyttöön liittyvä ongelma on se, että niiden määrän kasvaessa suureksi (niin kuin suuria ohjelmistokokonaisuuksia toteutettaessa helposti käy) tulee niiden hallinnoinnista käytännön välttämättömyys. Tämä on puolestaan osoittautunut käytännössä hankalaksi, sillä usein ainoa keino on pitää jokaisesta makrosta kirjaa erikseen. Lisäksi tällöin menetetään makrojen ehkä paras etu, ketteryys ja joustavuus pienessä mittakaavassa, sillä uuden makron luominen saattaa vaatia monimutkaisen allokointiprosessin läpikäyntiä kehitysorganisaatiossa. 10.2.3 Moduulinen erillinen toteutus Mikäli erot voidaan kerätä yhden rajapinnan taakse, voidaan toteutus vaihtaa eri ympäristöihin. Kyseessä on siis oikeastaan pikemminkin arkkitehtuuri- ja suunnittelutason ratkaisu kuin varsinainen siirrettävyyttä varten tehty muutos. Tällainen järjestelmä voidaan hallinta esimerkiksi konfiguraationhallintajärjestelmillä tai joukolla komentotiedostoja (skriptejä), joilla käännös eri kohteisiin toteutetaan. Toinen vaihtoehto on käyttää niin sanottua abstrakti tehdas -suunnittelumallia, jossa on erikseen moduuli, joka puolestaan osaa rakentaa erilaisia laillisia konfiguraatioita ajoaikaisesti. Jokaista näistä moduuleista voidaan käyttää yhteisen rajapinnan ylitse, joten järjestelmän toiminta riippuu siitä, millainen konfiguraatio rakennettiin. Suunnittelumallin heikkous pitkälle sulautettujen järjestelmien yhteydessä on se, että usein kaikkea ohjelmakoodia ei tarvita kaikissa laitteissa.

Kohti suurempia sulautettuja ohjelmistoja 169 Ylimääräisen koodin mukanaolo puolestaan kuluttaa muistia, ja voi aiheuttaa ongelmia esimerkiksi kaikkein korkeimpia testikattavuuksia tavoitellessa. Toisaalta suunnittelumalli on hyödynnettävissä myös esimerkiksi dynaamisten kirjastojen yhteydessä, mikäli muu osa järjestelmää sellaisia tukee. Erillinen toteutus joko erilaisten komentotiedostojen, skriptien tai suunnittelumallien avulla on usein koodin kannalta selkein ratkaisu. Toisaalta, jos erot eri ympäristöjen välillä on pienet, seuraa tästä turha saman koodin toistaminen useassa paikassa. Tämä puolestaan taas johtaa päivitysongelmiin, kun sama ohjelmakoodi pitää päivittää useaan kertaan. 10.2.4 Siirrettävyysongelmia Eivät pelkästään oheislaitteiden tai käyttöjärjestelmien erot vaikuta siirrettävyyteen. Suuri osuus siirrettävyysongelmaa on ohjelmiston kirjoittaminen siten, että ohjelmassa ei ole kääntäjästä riippuvia oletuksia. Tyypillinen tämänkaltainen oletus on se, että osoitteen pituuden odotetaan olevan saman kuin kokonaisluvun. Oletus pitää usein paikkansa, mutta ei aina. Toinen vastaava oletus on kokonaisluvun tai liukuluvun arvoalueen olettaminen joksikin tietyksi. Esimerkiksi C-kielen inttyyppi voi olla arvoalueeltaan mitä tahansa, kunhan siinä on vähintään 16 bittiä. Vastaavasti long-tyyppi on vähintään yhtä suuri kuin int, mutta voi olla suurempikin. Yksi tapa välttää tällaisia ongelmia on kääntää ja testata ohjelmisto jo kehitysympäristössä kahdella eri kääntäjällä. Näin suuri osa tällaisista oletuksista saadaan selville, samoin kääntäjien erilaiset toteutukset sellaisista ohjelmointikielen ominaisuuksista, joita kieli ei määrittele yksikäsitteisesti. Esimerkiksi C-kielen jakojäännös (%-operaattori) on hyvin määritelty vain, jos molemmat operandit ovat positiivisia. Tietysti myös virtuaalikonetta käyttämällä saadaan siirrettävyysongelmia pienennettyä olettaen, että virtuaalikone on saatavilla kaikkiin tarvittaviin ympäristöihin. Muussa tapauksessa virtuaalikoneen siirtäminen voi osoittautua paljon suuremmaksi työksi kuin mitä varsinaisen ohjelmiston siirto olisi ollut. 10.3 Vuotavat abstraktiot Abstraktiot ovat oikeastaan ainoa keino hallita ohjelmistojen kasvavaa monimutkaisuutta. Esimerkiksi koko olioparadigman voidaan ajatella

170 Sulautettu ohjelmointi hyödyntävän mahdollisuutta käyttää kohdealueen (domain) käsitteitä abstraktilla tavalla osana ohjelmistosuunnittelua. Vastaavasti modulaarisuus mahdollistuu vasta sitten, kun asiat voidaan tavalla tai toisella yhdistää abstraktisti toisiinsa. Samaten käyttöjärjestelmien tarjoamat palvelut ovat vain abstraktioita siitä, mitä lopulta tapahtuu fyysisen maailman tasolla esimerkiksi levypinnalle tiedostoa talletettaessa. Ohjelmistojen rakentamisessa käytettävät abstraktiot siis ovat käytännössä välttämättömiä, mutta niihin liittyy myös joitakin periaatteellisia ongelmia. Tarkastellaan esimerkiksi seuraavaa aliohjelmaa, jossa null-merkkiin päättyvä merkkijono kopioidaan toisen perään 23 : char* strcat(char* c1, char* c2) { char* apu = c1; while(*apu++); while(*c2) *apu++ = *c2++; *apu = 0; return c1; } Aliohjelma toimii siis siten, että se etsii ensin kohdan, jossa merkkijono c1 loppuu (eli löytyy merkkijonon päättävä 0), ja kopioi sitten merkkijonon c2 merkit yksi kerrallaan c1:n perään, kunnes c2:n loppumerkki tulee vastaan. Toiminnallisesti edellä esitetty aliohjelma täyttää sille annetut kriteerit, ehkä lukuunottamatta muistinvaraukseen liittyvää ongelmaa, mutta joissain käyttötapauksissa aliohjelman käyttö voi olla suorituskyvyn kannalta haitallista. On helppo huomata, että jos merkkijonon c1 pituus on esimerkiksi 1.000.000 merkkiä ja c2:n pituus 3 merkkiä, suurin osa aliohjelman tarvitsemasta ajasta kuluu c1:n loppua etsiessä. Samaan tapaan, jos luodaan uusi merkkijono laittamalla miljoona kertaa yhden merkin mittainen merkkijono edellisen perään, lienee selvää, että suorituskykyongelmia on odotettavissa. Toteutusta voisi parantaa muokkaamalla tietorakennetta siten, että merkkijonossa kulkisi mukana tieto sen pituudesta (mikä toteutus on käytössä joissakin ympäristöissä, kuten esimerkiksi Symbian-käyttöjärjestelmässä), mutta esitetty ongelma on oikeastaan väistämätön tällä tietorakenteella: Jos merkkijonon pituutta ei tunneta, vaan se pitää aina etsiä tunnistamalla loppumerkki, on merkkijonon läpikäynti ainoa tapa saada pituus selville. Kyseessä on siis eräänlainen ääritapaus, jonka kohdalla ei voida tällä toteutuksella välttää ongelmaa. 23. Huomaa, että aliohjelmassa tehdään vaarallinen oletus: merkkijonon c1 lopussa pitää olla riittävästi tilaa c2:n merkeille ja loppumerkille!

Kohti suurempia sulautettuja ohjelmistoja 171 Yleisemmin edellä esitetty ongelma tunnetaan abstraktion vuotamisena, eli tilanteena, jossa jonkun abstraktion toteutuksessa käytetty tekniikka ja toteutuksen yksityiskohdat näkyvät ohjelmoijalle tavalla tai toisella. Koska lähes kaikki abstraktiot ovat jossakin ääritilanteessa alttiita vuotamiselle, ei ongelmia voida koskaan täysin välttää. Joka tapauksessa ohjelmoijalla on oltava jonkinasteinen ymmärrys ilmiöstä sekä siitä, miten todennäköisesti käytetyt abstraktiot vuotavat tietyssä tilanteessa. Vuotavat abstraktiot ovat varsin tavallisia sulautettujen ohjelmistojen toteuttamisessa, sillä ilmiö liittyy useinmiten tavalla tai toisella järjestelmän kannalta äärimmäiseen tilanteeseen. Tällaisia tilanteita ovat esimerkiksi muistin loppuminen, raskas kuormitus esimerkiksi useiden prosessien suorituksen vuoksi tai ongelmat tietoliikenteessä. Koska sulautetut järjestelmät perustuvat usein vaatimattomaan laitteistoon verrattuna pöytäkoneisiin, tulevat äärimmäiset tilanteet vastaan huomattavasti aiemmin, kuin mitä ohjelmoija usein ehkä olettaa. Lisäksi myös monet siirrettävyyteen liittyvät ongelmat voidaan mieltää vuotaviksi abstraktioiksi. Tällöin esimerkiksi tarjolla olevat rajapinnat eivät peitä toteutusta riittävän hyvin. Yksi käytännön ohjelmistosuunnitteluun liittyvä, helposti niukkaresurssisessa ympäristössä vuotava abstraktio on muistinkulutus. Vaikka kaikki tietorakenteet tietysti kuluttavat muistia, on erilaisilla suunnitteluratkaisuilla merkittävä vaikutus ohjelman muistinkulutukseen. Tarkastellaan esimerkiksi kuvassa 10.2 esitettyjä Java-aliohjelmia, jotka kaikki tekevät toiminnallisesti saman asian. Ohjelmien taustalla olevalle ohjelmistoinfrastruktuurille ne kuitenkin aiheuttavat melkoisesti toisistaan eroavan kuorman. Aliohjelmien aiheuttama muistinkulutus sekä niiden luomien olioiden määrä on esitetty taulukossa 10.1. 24 Toteutusympäristöstä riippuen abstraktioiden vuotamiseen varautuminen voi vaatia erilaisia ratkaisuja. Ympäristöissä, joissa ohjelmoija muutenkin joutuu ottamaan vastuun kaikista toimenpiteistä, abstraktioiden vuotamiseen valmistautuminen on oikeastaan jo osa ohjelmiston suunnittelua joka tapauksessa, sillä ohjelmoija joutuu valmistautumaan 24. Esimerkkiohjelmat ja mittaustulokset ovat peräisin Vesa-Matti Hartikaisen diplomityöstä Java application and library memory consumption, Tietotekniikan osasto, Tampereen teknillinen yliopisto, 2005. Mittauksissa on käytetty mobiililaitteisiin sovitettua MIDP Java-ympäristöä.

172 Sulautettu ohjelmointi static final int SIZE = 2000; private void arrayimp() { numbers = new int[size]; for (int i = 0; i < SIZE; i++) { numbers[i] = i; } } private void vectorimp() { numberv = new Vector(SIZE); for (int i = 0; i < SIZE; i++) { numberv.addelement(new Integer(i)); } } private void vectorimpsimple() { numberv2 = new Vector(); // Default size for (int i = 0; i < SIZE; i++) { numberv2.addelement(new Integer(i)); } } Kuva 10.2 Kolme erilaista toteutusta Taulukko 10.1: Aliohjelmien muistinkulutus Muistin kulutus tavuina Oliot arrayimp 8016 1 vectorimp 40000 2002 vectorimpsimple 52000 2010 muistin loppumiseen, suorituskyvyn kannalta äärimmäisiin tilanteisiin, ja niin edelleen. Yleisesti käytetty tapa huolehtia asiasta on varata ääritapauksen käsittelyn vaatimat resurssit etukäteen, mutta tämä voi kuitenkin olla hätävarjelun liioittelua. Äärimmilleen vietynä esimerkiksi kännykän pitäisi tällöin olla koko ajan tilassa, jossa laitteistolla on kaikki resurssit varattuna siihen, että hätäpuhelu voidaan soittaa milloin tahansa. Tämä ei kuitenkaan käytännössä ole mahdollista, sillä puhelimen pitäisi sallia usean puhelun samanaikainen tekeminen, mikä ei ole mahdollista kaikissa malleissa. Lisäksi akun kesto heikkenisi merkittävästi, kun

Kohti suurempia sulautettuja ohjelmistoja 173 Resurssi 1 Resurssin 1 ohjain Laitteen 1 ohjain Laite 1 Resurssi 2 Kuva 10.3 Resurssin 2 ohjain Laitteen 2 ohjain kaikki puhelussa tarvittava elektroniikka olisi koko ajan aktiivisessa tilassa. Tilanteessa, jossa käyttöjärjestelmä tai jonkinlainen välikerrosohjelmisto tarjoaa hallinnointipalveluita sovelluskehityksen yksinkertaistamiseksi, varautuminen abstraktioiden vuotamiseen voi olla äärimmäisen vaikeaa, sillä vuotava abstraktio saattaa olla juuri hallinnointipalvelu. Jo aiemmin todettiin, että esimerkiksi Javaa ohjelmointikielenä käytettäessä törmätään helposti ongelmiin, jos roskien keruu sattuu tapahtumaan väärään aikaan tai jos ohjelman käyttämät tietorakenteet syystä tai toisesta estävät roskien keruun toiminnan. Kyseessä on selvästi abstraktion vuoto automaattiseen muistinhallintaan liittyvän abstraktion sivutuote näkyy käyttäjälle hitaampana suorituksena. 10.4 Joitakin sulautetun järjestelmän suunnitteluratkaisuja Kuten monien muidenkin ohjelmistojen yhteydessä, on myös sulautetuissa järjestelmissä tavallista käyttää hyväksi havaittuja suunnitteluratkaisuja useassa eri ympäristössä. Käymme seuraavassa läpi pienen joukon tällaisia ratkaisuja. Tavoitteena ei ole niinkään kattavan suunnittelumallikokoelman esittely, vaan pikemminkin antaa esimerkkejä suunnittelutavoitteista ja siitä, miten ne on otettu huomioon osana ohjelmistosuunnittelua. 10.4.1 Kerrostaminen ja laitteiden kätkentä Laite 2 Laitteistoa mukaileva ohjelmistoarkkitehtuuri Usein sulautettuja järjestelmiä toteutettaessa päädytään ohjelmistoarkkitehtuuriin, jossa käytettävät laitteet ohjaavat suunnittelua. Tällöin jokainen erilainen rajapinta kätketään abstraktiorajapinnalla, mikä mahdollistaa käytettävän laitteiston muuntelun kohtuullisen helposti. Kuva 10.3 havainnollistaa suunnittelun lähtökohtaa.

174 Sulautettu ohjelmointi Laitteistoa mukailevaa ohjelmistoarkkitehtuuria on helppo pitää jonkinlaisena laitteistoa abstrahoivana kerroksena, joka tarjoaa palveluita muulle ohjelmistolle. Tällaisesta laiteabstraktiokerroksesta käytetään nimeä HAL (Hardware Abstraction Layer). Laiteabstraktiokerroksen ohjelmistotekniset edut on helppo nähdä. Periaatteessa ohjelmistot ovat siirrettävissä ympäristöstä toiseen, jos vain HAL pysyy samanlaisena, sillä ympäristön muutokset eivät ole ohjelmalle näkyvissä. Käytännössä jotkut yksityiskohdat on kuitenkin edelleen otettava huomioon ohjelmistoa suunnitellessa. Tällaisia seikkoja ovat esimerkiksi muistin kulutus, sillä erilaiset laitteistot saattavat sisältää eri määrät muistia ja niiden konfiguraatio saattaa muutenkin olla sisäisesti erilainen, ja suorituskykyyn liittyvät seikat, joita ovat esimerkiksi skeduloituvuus ja järjestelmän vasteajat. Ohjelmoijan kannalta edellä esitetyt erot tarkoittavat yleensä sitä, että vaikka varsinaisia uusia ominaisuuksia ei toteutettaisikaan, saatetaan ohjelmisto joutua testaamaan useita kertoja erilaisten laitteistokokoonpanojen yhteydessä. Toisaalta varsinainen ohjelmiston toteutustyö pysyy yleensä kohtuullisena. 10.4.2 Väyläabstraktio Noudattamalla yllä esitettyä periaatetta sulautetusta järjestelmästä muotoutuu yleensä kokoelma laitteistoriippuvaisia toimintoja. Koska toiminnot ovat usein tavalla tai toisella toisistaan riippuvaisia, niiden välinen kommunikointi on sallittava muodossa tai toisessa. Melko tavallinen tapa toteuttaa kommunikointi sulautetussa ympäristössä on käyttää väylärakennetta, jossa laitteistoa ohjaavat ohjelmiston osat voivat lähettää toisilleen viestejä käyttäen väylän tapaan toimivaa ohjelmistokomponenttia 25 viestinvälitykseen. Viestinvälityksessä käytettävä väylä tarjoaa useita merkittäviä etuja ohjelmistokehitykseen. Ensinnäkin viestit on mahdollista käsitellä siten, että niiden välitys eri komponenteille on nopeaa käyttämällä esimerkiksi hajautustaulua reititykseen, ainakin mikäli voidaan luottaa kohtuulliseen staattiseen reititysalgoritmiin. Toisekseen uusien toimintojen lisääminen on yleensä helppoa, sillä uusia toimintoja varten voidaan tarvittaessa varata kokonaan uusia viestejä, joiden käsittely ei 25. Hajautettujen sulautettujen järjestelmien yhteydessä samaa väylää käytetään usein myös yhdistämään laitteiston eri osat toisiinsa. Tällöin tarvitaan luonnollisesti myös jonkinlainen fyysinen väylä, kun taas yhden laitteen sisäisessä toteutuksessa voidaan käyttää puhtaasti ohjelmallista väylää.

Kohti suurempia sulautettuja ohjelmistoja 175 lainkaan vaikuta jo aiemmin käytössä olleiden viestien käsittelyyn. Lisäksi viestinvälityksen yhteydessä päästään melko usein yksinkertaistamaan myös poissulkemista, sillä jokainen ohjelmistokomponentti tyypillisesti käsittelee viestit loppuun saakka ennen seuraavan viestin käsittelyä. Tämä mahdollistaa myös lokin keräämisen käsiteltyjen viestien avulla, mikä puolestaan auttaa virheiden jäljittämisessä. Huonona puolena ohjelmistoväylään perustuvassa toiminnassa voidaan pitää sitä, että jatkuva viestien luominen voi johtaa muistin frakmentoitumiseen. Tästä syystä usein käytetään tilanteeseen sopivaa tietorakennetta, esimerkiksi rengaspuskuria, johon voidaan varata sopiva määrä viestejä käytettäväksi. Toinen joskus ongelmia aiheuttava osa on se, että koska ohjelmiston eri osien välinen kommunikointi tapahtuu kokonaan viestien ja viestinkäsittelijöiden kautta, ei missään vaiheessa välttämättä tehdä perinteistä rajapintamäärittelyä, joka ohjaisi pohtimaan komponentin toimintaa kokonaisuutena. Lisäksi ongelmia voi aiheuttaa se, että järjestelmän kannalta tärkeä viesti voi joutua odottamaan vähemmän tärkeiden viestien käsittelyä, samaan tapaan kuin mitä skeduloinnin ja poissulkemisen yhteydessä käänteisprioriteettiongelmana esitettiin. Jos ongelmat ovat suuria, viesteihin voidaan laittaa prioriteetti, jonka avulla eri viestinkäsittelijät (tai väylä) voivat ottaa huomioon viestien keskinäisen tärkeysjärjestyksen. 10.4.3 Käynnistysrutiinit Koska monet ohjelmistot ovat käytössä lähes samanlaisina erilaisissa ympäristöissä, kohdistuu niihin osin ristiriitaisia vaatimuksia. Yksi ristiriitaisuuksien lähde on se, miten jonkin laitteen ohjelmisto tai yleisemmässä tapauksessa koko laite kuuluu käynnistää, jotta kaikki sen toiminnot kytkeytyvät päälle sellaisessa vaiheessa, että tarvittava laitteistotuki suoritukselle on saatavilla. Koska laitteen eri versioiden laitteistokomponentit voivat olla erilaisia, tarvitaan usein hivenen erilaisia käynnistysrutiineja, jotka herättävät laitteiston eri komponentit vähän eri järjestyksessä ja vähän erilaisin ajoituksin. Ohjelmistoteknisessä mielessä kyseessä on siis selvästi muunneltavuuteen liittyvä ongelma, jonka ratkaisemiseksi käynnistysrutiini kannattaa rakentaa helposti muunneltavaksi tavalla tai toisella. Yksi melko usein käytetty tapa on käyttää jonkinlaista erillistä rutiinia, joka kutsuu eri käynnistysoperaatioita ohjelmallisesti. Toinen

176 Sulautettu ohjelmointi vaihtoehto olisi toteuttaa käynnistysvektori, jonka eri alkiot osoittavat sopiviin käynnistysrutiineihin. Kolmas vaihtoehto on rakentaa erillinen konfiguraatiotiedosto, jossa määritellään mitä laitteita on käytössä, ja miten ja missä järjestyksessä ne kuuluu herättää. Kaikissa yllä esitetyissä tapauksissa käynnistysrutiinien muuntelu on yksinkertaista, ja kahdessa jälkimmäisessä tapauksessa ei välttämättä edes tarvita käännöstä, vaan riittää että vektorin tai konfiguraatiotiedoston arvot asetetaan sopivasti. Toisaalta kääntäminenkään ei yleensä ole iso ongelma, sillä jos ollaan rakentamassa muista laitteistoista selvästi erilaista järjestelmää, myös monet muut pienet yksityiskohdat ovat saattaneet muuttua. 10.4.4 Vianjäljitysmoodi ja lokien keruu Koska sulautetut järjestelmät koostuvat sekä ohjelmistosta että laitteistosta, on niiden toiminnan tutkiminen suorituksen aikana usein vaikeaa. Kuten jo aiemmin todettiin, joudutaan usein turvautumaan erityisiin apuvälineisiin, joiden avulla voidaan selvittää mitä ohjelma missäkin kohtaa suoritusta tekee. Mitä suuremmasta järjestelmästä on kyse, sen todennäköisempää on, että järjestelmään kannattaa rakentaa sisään jonkinlaista kyvykkyyttä auttaa virheiden jäljittämisessä. Täten monia, muuten lähes mahdottomia tehtäviä voidaan yksinkertaistaa merkittävästi. Yksi keino auttaa virheiden jäljittämisessä on käyttää erityistä vianjäljitysmoodia. Tällöin esimerkiksi huoltomies voi asettaa tutkittavan järjestelmän tilaan, jossa se lähettää tilatietoa joko omalle näytölleen tai huoltomiehen tietokoneelle. Yhdistettynä muunneltavan käynnistysrutiinin kanssa tämä suunnitteluidiomi muodostaa varsin hyvän keinon jäljittää virheitä. Lisäksi lähes aina kun vain mahdollista kannattaa kerätä tietoa järjestelmän toimenpiteistä ja tilasta. Tämä tyypillisesti hoidetaan erilaisin lokimekanismein. Yleensä pyritään toimimaan siten, että loppukäyttäjä ei pääse käsiksi lokitietoon, vaikkapa sallimalla tiedon luku vain erityistä asennuskaapelia käyttäen, kuten monissa ajoneuvoissa on tapana. 10.4.5 Muisti- ja ajoitusbudjetti Muisti- ja ajoitusbudjetin laatiminen ennen ohjelman suunnittelua voi vaikuttaa melko vaikealle asialle, mutta käytännössä sellaisen laadinta on väistämätöntä, jos halutaan arvioida laitteen valmistuskustannukset

Kohti suurempia sulautettuja ohjelmistoja 177 edes jollakin kohtuullisen luotettavalla tasolla ennen kuin laitetta ryhdytään toteuttamaan. Muisti- ja ajoitusbudjetti on luonnollisesti vain suunnitelma siitä, miten suorituksen on ajateltu etenevän, mutta johtuen sen kiinteästä yhteydestä hintaan suuret poikkeamat voivat johtaa ongelmiin. Budjetin laatimiseksi tarvitaan luonnollisesti jonkinlaiset lähtöarvot. Huonoimmassa tapauksessa lähtökohdan muodostavat suuntaaantavat järjestelmävaatimukset, ja ohjelmistosuunnittelijan tehtäväksi annetaan ensin kokonaisuuden hahmottaminen, sitten alustavan arkkitehtuurisuunnitelman luonti, ja lopuksi muistinkulutuksen arviointi ja skedudoituvuusanalyysin teko perustuen arkkitehtuurisuunnitelmaan. Koska arvioihin liittyy paljon epävarmuustekijöitä, ei lopputuloskaan voi olla kovin tarkka. Voidaan jopa ajatella niin, että jos budjetti ennustaa ongelmia, ne ovat väistämättömiä, mutta jos budjetin mukaan näyttää hyvältä, ei siltikään vielä kannata olla huolehtimatta muistinkulutuksesta tai ajastuksista. Käytännössä budjetin laatimista helpottaa se, että yleensä aina on olemassa saman (tai vastaavan) järjestelmän aiempi versio, josta saadaan jonkin verran konkreettista mittausdataa arvojen asettamiseksi. Analysoimalla muutostarpeet aiempaan versioon verrattuna saadaan siksi aikaan hyvinkin täsmällisiä arvioita. 10.5 Formaali vai epäformaali menetelmä? Koska virhe on sitä kalliimpi, mitä aikaisemmassa vaiheessa se tehdään ja mitä myöhemmin se havaitaan, pyritään siihen, että jo ongelman kuvauksesta voisi päätellä, onko kaikki tarpeellinen otettu huomioon. Toisaalta kokonaisjärjestelmän hallitsemiseksi siitä pitäisi muodostaa kuvaus, joka abstrahoi pois yksityiskohtia. Koska formaalien esitystapojen ongelmana on usein juuri se, että kaikki yksityiskohdat on kerrottava, niiden käyttökelpoisuus on monesti asetettu kyseenalaiseksi. Formaalien menetelmien yksi ongelmista on sekin, että ne eivät toistaiseksi tue ohjelmistotyötä tarpeeksi, jotta ne olisivat houkuttelevia vaihtoehtoja. Lisäksi niiden esitysmuodot ovat usein ohjelmoijille liian matemaattisia, jotta niiden käyttöä pidettäisiin miellyttävänä. Tämä on todella vahinko, sillä formaaleissa määrittelymenetelmien voima on siinä, että kun jo määrittely on formaali, ominaisuuksien virheettömyys on helpompi verifioida jo määrittelyvaiheessa, ja testaukseen saadaan selkeitä kriteereitä. Määrittelyn oikeellisuuden toteaminen on tärkeää, sillä jos määrittely on virheellinen, on sen oikea toteutuskin virheellin-

178 Sulautettu ohjelmointi en. Oikeaksi toteaminen tarkoittaa tässä paitsi loogista järkevyyttä niin myös sitä, että määrittely täyttää järjestelmälle asetetut vaatimukset. Tämän takia myös asiakkaan tulisi voida lukea määrittelyä. Formalismien asemasta onkin esitetty useita puoliformaaleja järjestelmiä, joissa on yleensä jokin visuaalinen esitysmuoto ongelmalle. Näillä menetelmillä saadaan kuvattua järjestelmä suhteellisen helposti, mutta varjopuolena on se, että niistä ei välttämättä saada lähtötietoja testaustarkoituksiin. Tämä taas johtuu siitä, että esitys ei havainnollisuudestaan huolimatta ole täydellinen. Niinpä tällä hetkellä ei ole olemassa sellaista kuvausmenetelmää, joka ratkaisisi kaikki ongelmat. Lupaavimmilta näyttävät sellaiset formaalit menetelmät, joissa on pystytty nostamaan abstraktiotasoa niin korkealle, että sekä kokonaisnäkemys että tarpeellinen pohja testaukselle ovat olemassa. Korkea abstraktiotaso voidaan toteuttaa muun muassa siten, että menetelmässä kuvataan askeleittain pieniä kokonaisuuksia kerrallaan, ja peräkkäiset askeleet eivät voi rikkoa toistensa turvallisuusominaisuuksia (tällainen järjestelmä on muun muassa DisCo, Distributed Co-operation). Yksikään tällaiselta pohjalta tehty järjestelmä ei ole levinnyt teollisuuden normaalikäyttöön. Laitteistopuolella on hieman samantapainen järjestelmä olemassa (Bluespec). Ainoa tapa, jolla ohjelmien virheet voidaan edes teoriassa välttää, on todistaa ohjelmat oikeiksi. Ongelmana on se, että todistaminen on usein melkoisen vaikeaa: esimerkiksi vaihtuvan bitin protokolla on intuitiivisesti helppo, mutta suhteellisen vaikea todistettava. Käytännössä oikeaksi todistamista voidaan käyttää vain pienissä, suhteellinen monimutkaisissa, mutta syystä tai toisesta kriittisissä ohjelmanosissa. Oikeaksi todistamisen sijaan erilaisia tietokoneavusteisia mallintarkastimia on käytetty varsin menestyksekkäästi myös suurten ja monimutkaisten sulautettujen järjestelmien kehittämisessä. Näidenkin yhteydessä lienee tilanne oikeasti sellainen, että oikeastaan pieni osa järjestelmää kerrallaan on mielekästä mallintaa ja tarkastaa työkaluavusteisestikaan. Muussa tapauksessa tarkistimeen syötettyjen tietojen ja käytännön ohjelman vastaavuus kasvaa helposti niin monimutkaiseksi, että on vaikea sanoa, mitä mallintarkastimen ilmoittama tulos oikeastaan lopulta tarkoittaa. Lisäksi samaan tapaan kuin formaalin todistamisen yhteydessä ei ole aivan helppoa tehdä mallia, jossa kaikki todistamisen (tai mallintarkastamisen) kannalta olennaiset ominaisuudet olisivat mukana. Joidenkin sulautettujen järjestelmien toteutuksessa on myös kokeiltu koodin generointia kielestä, joka olisi lähempänä sovellusal-

Kohti suurempia sulautettuja ohjelmistoja 179 uetta kuin mitä C, C++ tai Java. Kokemukset tällaisista ympäristöistä ovat vaihtelevia, mutta usein näin on kyetty nostamaan tuottavuutta tai ainakin mahdollistamaan kehitysmalli, jossa osa kehittäjistä ei varsinaisesti ole ohjelmoijia vaan pikemminkin sovellusalueen asiantuntijoita. Vaikka käytetyllä korkeamman tason kielellä periaatteessa olisikin jonkinlainen formaali perusta, kehittäjät itse tuntuvat kuitenkin usein ajattelevan kirjoitettua koodia ensisijaisesti ohjelmana ja vasta sitten, jos on pakko, formaalina määrittelynä. Tästä syystä yleensä ohjelmistotuotannon hyväksi havaitut käytännöt ovat parempi tae laadusta kuin sinänsä hyvältä kuulostava lupaus teoreemantodistuksesta tai formaalista perustasta. Lisäksi ongelmia voi aiheuttaa se, että monesti tähän käytäntöön tarvittavat työkalut ovat syntyneet yrityksen omista tarpeista omaan tarpeeseen. Siksi niiden ylläpito voi osoittautua hankalaksi, ja osaavan henkilökunnan löytäminen voi olla vaikeaa. 10.6 Yhteenveto Painopiste laitteen hereille saamisesta laitteen pitkäaikaiseen käyttöön. Useita käyttökelpoisia tekniikoita ja uusia vaatimuksia: 1. Valmiit ohjelmistopinot. 2. Vuotavien abstraktioiden hallinta. 3. Joustavuutta tuovat suunnitteluratkaisut. 4. Määrittelyn oikeellisuus ja täsmällisyys.