Toekomstige toepassingsprogramma’s zullen niet veel meer dan schillen zijn, die hun functionaliteit voornamelijk halen uit de in hun omgeving aanwezige softwarecomponenten. In navolging van hardware wordt software opgebouwd uit componenten. De technologie van softwarecomponenten, zoals toegepast bij Activex en Javabeans, mist een aantal nadelen van de objectgeoriënteerde aanpak. Alleen de coördinatie is nog voor verbetering vatbaar, meent een software-specialist van Philips Semiconductors.
De voornaamste reden dat de term ‘zachte waar’ (software) gekozen is voor programmatuur, is de tegenstelling met de meer grijpbare hardware. Al in een vroeg stadium werd hardware gemaakt met behulp van componenten. Software daarentegen werd opgebouwd uit functies. Pas de laatste jaren begint het besef door te breken dat ook software met succes uit componenten is samen te stellen. Het verschil in aanpak wordt duidelijk, wanneer een groot en complex automatiseringssysteem – bestaande uit hard- en software – neergezet wordt. De hardware-installatiebedrijven werken doorgaans volgens een strak planningsschema, waarbij zij voorgefabriceerde componenten op een passende infrastructuur samenvoegen tot een werkend geheel.
Ook de programmeurs hebben het nodige voorbereid. Als de hardware reeds lang geïnstalleerd is, zijn zij vaak nog lange tijd bezig om al testend het gehele systeem op gang te brengen.
De reden dat men in het verleden met software anders omging dan met hardware, ligt in de wijze waarop de programmeerhulpmiddelen tot stand zijn gekomen. De allereerste computers waren niet veel meer dan eenvoudige rekenmachines. Naast de typische rekenopdrachten konden deze apparaten nog een klein aantal extra deelopdrachten uitvoeren. Deze instructies beïnvloeden de voortgang van de procedure, halen gegevens of nieuwe opdrachten binnen, of slaan de resultaten van het werk op.
Aanvankelijk werd de computer rechtstreeks met behulp van deze instructies in een direct voor de machine begrijpelijke code geprogrammeerd. Machinetaal is erg gebruiksonvriendelijk. Daarom ontstond al snel een codering in assembleertaal. Deze is vriendelijker voor de programmeur, maar voor de machine niet meer direct leesbaar. Om regelmatig terugkerende instructiereeksen eenmalig te kunnen invoeren en vervolgens herhaaldelijk te gebruiken, zijn extra instructies nodig. Dit leidde tot de derde-generatietalen, zoals Cobol, Algol, Fortran, Pascal, C, enzovoort.
Voor het aanpakken van grote en complexe projecten zijn analyse- en ontwerpmethodieken ontwikkeld, die in eerste instantie voortgaan op de ingeslagen weg. De aandacht richt zich volledig op de functionaliteit van het systeem. Tijdens de analyse wordt een ingewikkelde taak opgesplitst in eenvoudiger deeltaken, die nogmaals worden opgesplitst totdat zij door iedere programmeur gemakkelijk in een routine om te vormen zijn. Deze routines worden daarna weer samengevoegd tot meer complexe functies. Dit lijkt op het eerste gezicht een zinvolle aanpak. Door echter de nadruk te leggen op de functionaliteit worden andere aspecten, zoals de toestand van de objecten die de functies uitvoeren, genegeerd. De geschetste aanpak geeft dan ook problemen bij toepassing op grote en complexe projecten.
Programmeren is modelleren
Programmeren is een creatieve bezigheid die overeenkomsten vertoont met andere creatieve activiteiten, zoals schilderen en beeldhouwen. Een kunstschilder legt een abstractie van een natuurlijke of verzonnen omgevingswereld vast op canvas. Hij gebruikt vormen en kleuren als modelleringselementen.
Een programmeur bouwt een abstractie van een kunstmatige of natuurlijke omgevingswereld en legt die vast in een programma. Hij gebruikt eigenschappen, gedragsaspecten, relaties, communicatie, inkapseling en coördinatie als modelleringselementen. Zijn hulpmiddelen helpen hem bij het modelleren van de eerste vier elementen. De derde-generatie hulpmiddelen laat het echter afweten bij het betrouwbaar modelleren van de laatste twee elementen.
Eigenschappen en relaties vormen tezamen de attributen die de toestand van een object bepalen. Programmeurs leggen attributen vast in velden van gegevensstructuren, die op hun beurt vastgelegd worden in stukken van het beschikbare computergeheugen. De lengte van een veld hangt af van het type attribuut.
Verder leggen programmeurs gedragsaspecten vast in routines. Communicatie wordt omgezet in de aanroep van routines, waarbij de afzender de aanroep activeert en de ontvanger de aanroep uitvoert. Het verzonden bericht wordt in de vorm van parameters bij de aanroep aan de ontvanger overgedragen. De aanroep veroorzaakt een reactie bij de ontvanger. Deze reactie kan zich beperken tot een verandering van de interne toestand van de ontvanger. Een eventuele externe reactie wordt als resultaat van de routine aan de afzender geleverd.
Als voorbeeld een vergelijking met de natuur. Vogels kunnen vliegen. Ze vliegen echter niet even snel, en ook in verschillende richtingen. Dit verschil wordt bepaald door hun ‘interne toestand’. Toch is vliegen een voor vogels kenmerkend gedrag. Bij gedrag kan men dus onderscheid maken tussen een klassenwijd aspect (het vliegen) en een individueel aspect (de wijze waarop gevlogen wordt). Routines kunnen op twee verschillende wijzen gebouwd worden. De eerste manier vermengt de code met de toestandsgegevens. De tweede aanpak haalt de toestandsgegevens via parameters binnen en houdt daardoor de code onafhankelijk van de toestand van het individu. Het is dus mogelijk om gedrag klassenwijd te modelleren.
Bij communicatie spelen klassenwijde en systeemwijde aspecten een rol. Immers, als niet volgens een vooraf overeengekomen protocol gecommuniceerd wordt, zal de communicatie niet de gewenste reactie uitlokken. Dit betekent dat klassenwijd en liefst systeemwijd dezelfde wijze van aanroep van routines gebruikt moet worden. Om klassenwijd gedrag te modelleren, moet een referentie naar de toestandsgegevens van het individu met de aanroep van routines meegegeven worden.
Inkapseling
Bij het ontwerpen van grote en complexe programma’s is het verstandig om niet alleen rekening te houden met de gedragsaspecten, maar ook met alle andere modelleringselementen. Bij een goed ontwerp hoeven klassenwijde zaken maar één keer gebouwd te worden. Beschouwing van alle modellen en deelmodellen in een bepaald toepassingsgebied leert dat complexe modellen gewoonlijk uit eenvoudiger modellen zijn af te leiden of samen te stellen. Programmacode die voor een eenvoudig model ontwikkeld is, kan dus ook gebruikt worden bij het verwezenlijken van ingewikkelder modellen.
De wijze waarop programma’s tot stand komen, hangt dus sterk af van de wijze waarop het toepassingsgebied geanalyseerd wordt. Ontwerpt men programma’s door opsplitsing van ingewikkelde taken in eenvoudiger taken, dan raken andere modelleringselementen verstrooid. Naarmate programma’s groter en complexer worden, wordt het moeilijker om de relatie tussen routines en de gegevens waarop deze functies werken, in stand te houden.
De beste oplossing is om bij elkaar horende modelleringselementen als groep in te kapselen. Zo is te voorkomen dat externe invloeden de interne toestand van een individu op ongecontroleerde wijze veranderen. Een individu heeft een relatie met de klasse waartoe hij behoort. Deze relatie behoort tot de toestandsgegevens van het individu en betrekt de klassenwijde aspecten bij het individu. Klassenwijd gedrag hoeft slechts eenmalig gebouwd te worden. De klasse heeft een relatie met deze routine. De meeste klassen beschikken over een hele reeks van dergelijke relaties. Zo ontstaat een cluster. Door inkapseling wordt rechtstreekse toegang tot de toestandsgegevens van het individu afgeschermd. Daardoor kan dit cluster volledig verantwoordelijk gesteld worden voor het gedrag van het individu.
Het volgende voorbeeld dient om het bovenstaande te verhelderen. Op een bank kan men aan een loket geld opnemen en storten. Andere loketten waar men andere handelingen kan verrichten zoals leningen afsluiten en informatie inwinnen, laten we even buiten beschouwing. Veel banken verlenen dit soort diensten. Er is dus een klasse van instanties die gelijksoortig gedrag vertonen. Een individuele bank in deze klasse beschikt over zijn eigen kasgeld en berekent vaste vergoedingen voor zijn diensten. Deze vergoedingen verschillen per bank. Een dergelijke bank beschikt onder andere over de volgende attributen:
Attribuut | Waarde | Soort |
Lid | Bankenklasse | relatie |
Kasgeld | 1000 | guldens |
Klantenlijst | Lijst Van Tegoeden | relatie |
Stortingskosten | 1 | % |
Opnamekosten | 2 | % |
Het eerste loket levert als diensten:
Dienst | Parameters | Resultaat |
Opname | Klant, Bedrag | Goedkeuring |
Inleg | Klant, Bedrag | Saldo |
Tegoed | Klant | Saldo |
Het dienstverleningsvoorschrift voor deze diensten hoeft maar één keer gemaakt te worden. Via zijn lidmaatschap van de bankenklasse kan de bank over dit voorschrift beschikken. De kasgelden en de tegoeden van klanten verschillen per bank en per klant. Tezamen bepalen bovenstaande tabellen het gedrag van een bank aan het geldopname- of inlegloket.
De implementatie van het individu beschikt over een referentie naar een klasse, waarvan hij lid is. Deze referentie is onderdeel van de verzameling van attributen die de interne toestand van het individu weergeven. De verzameling wordt opgeslagen in een gegevensstructuur. Een klasse beschikt ook over een gegevensstructuur. Hierin zijn de klassenwijde attributen opgeslagen. De klassenwijde attributen omvatten onder andere een lijst met wijzers naar routines, die het klassenwijde gedrag implementeren.
Objectgeoriënteerd ontwerpen
De functioneel gerichte analyse- en ontwerpmethodiek heeft zin wanneer relatief weinig klassen van equivalent gedrag in modellen en deelmodellen ontdekt worden. Dit gebeurt doorgaans bij de wat eenvoudigere toepassingen.
Verzorgt men een compleet toepassingsgebied of bouwt men een groot en complex systeem, dan is het zinvol om individuele en klassenwijde aspecten te scheiden. Hierop richt zich de objectgeoriënteerde analyse- en ontwerpmethodiek. Deze werkwijze optimaliseert hergebruik van eenmaal gebouwde programmacode door ingewikkelde modellen zoveel mogelijk uit eenvoudiger modellen af te leiden. Een ingewikkeld model verschilt van zijn eenvoudiger voorganger doordat zijn lijst met attributen langer is. Tegelijkertijd kan ook de lijst met referenties naar routines langer zijn. Bovendien kunnen de bestaande routines vervangen zijn door meer kundige of meer effectieve routines. Dit laatste betekent dat in de oude lijst van referenties naar routines een of meer referenties naar andere routines worden omgeleid. Veel van de bestaande implementatie blijft intact en wordt zonder wijziging opnieuw gebruikt.
Het eerder gegeven voorbeeld wordt benut om het bovenstaande toe te lichten. Een deelgroep van de banken breidt de diensten aan het eerste loket uit door ook het wisselen van geld mogelijk te maken. Bovendien mag de klant in het vervolg tot een bepaald bedrag rood staan. De lijst van attributen van deze banken moet dus aangepast worden:
Attribuut | waarde | soort |
Lid | Bankenklasse | relatie |
Kasgeld | 10000000 | guldens |
Klantenlijst | Lijst Van Tegoeden | relatie |
Stortingskosten | 1 | % |
Opnamekosten | 2 | % |
Koerslijst | Lijst Van Koersen | relatie |
Maximumschuld | 500 | guldens |
Het eerste deel van de lijst is gelijk gebleven. Dit deel is voor de bestaande routines nog steeds bruikbaar. Het eerste loket levert extra diensten:
Dienst | Parameters | Resultaat |
Opname | Klant, Bedrag | Goedkeuring |
Inleg | Klant, Bedrag | Saldo |
Tegoed | Klant | Saldo |
Wissel | Geldsoort, Bedrag | Saldo |
De wisselroutine is toegevoegd. De opnameroutine is vervangen door een routine met dezelfde aanroep, die toelaat dat klanten tot het maximumschuld-bedrag rood staan. Alle andere routines worden ongewijzigd gebruikt.
Ingewikkelde klassen worden op deze wijze uit eenvoudiger klassen afgeleid. Dit bespaart veel programmeerwerk. Aldoende ontstaat een bibliotheek van herbruikbare klassen. Met behulp van een bestaande klassenbibliotheek kunnen verschillende toepassingsprogramma’s gebouwd worden. Gedurende dat proces wordt de klassenbibliotheek steeds verder uitgebouwd en bestrijkt hij een groeiend deel van het toepassingsgebied. Het zou dus steeds eenvoudiger moeten worden om nieuwe toepassingsprogramma’s te bouwen. Doordat de bibliotheek groeit, wordt deze echter moeilijker te beheren en te doorzoeken. Zonder hulp van passende hulpmiddelen verhindert dit op den duur het effectieve gebruik van de klassenbibliotheek.
Om het bouwen van objectgeoriënteerde systemen te vergemakkelijken zijn verschillende, speciaal daarop gerichte programmeertalen ontwikkeld, zoals Smalltalk, Eiffel, C++ en Java. Daarnaast bestaan er geïntegreerde ontwikkelomgevingen die het werken met klassenbibliotheken sterk vereenvoudigen. De objectgeoriënteerde methodiek brengt voor grote en complexe systemen een aanzienlijke verbetering ten opzichte van de functioneel gerichte methodiek. Bovendien maakt deze wijze van werken het mogelijk om een steeds sneller groeiende hoeveelheid bruikbare producten af te leveren. Toch levert deze aanpak nog niet dezelfde voordelen als de methodiek die hardware-installateurs tot hun beschikking hebben.
Softwarecomponenten
Vrijwel alle objectgeoriënteerde programmeertalen springen slordig om met de inkapseling van de individuele modellen. Dit gebeurt deels om de toegang tot de individuele attributen te vereenvoudigen en te versnellen. Het verhindert de toepassing van een uniform communicatieprotocol. Maar – en dat is erger – het neemt ook de mogelijkheid weg om het individu volledig verantwoordelijk te maken voor zijn eigen gedrag. Kortom, het verhindert het modelleren van zich op natuurlijke wijze gedragende individuen.
Een eventueel te ver doorvoeren van het overerven van functionaliteit van eenvoudige naar complexe klassen veroorzaakt ook problemen. Door vererving ontstaat een afhankelijkheid tussen nazaten en hun voorvaderen. Deze afhankelijkheid belemmert het op een simpele wijze toevoegen of verwijderen van de implementatie van individuele modellen.
De meeste computers beschikken over een vluchtig werkgeheugen met een beperkte omvang. Daarom moet de toestand van individuele modellen tijdelijk in een meer permanent geheugen opgeslagen kunnen worden. Ook zou men dergelijke gegevens naar andere computers willen oversturen. Dit levert problemen wanneer de in de attributenlijsten opgenomen relaties met behulp van wijzers naar geheugenadressen geïmplementeerd zijn. Dergelijke wijzers verliezen hun betekenis in een andere of vernieuwde geheugenconfiguratie. Daarom moeten voor het opslaan of overzenden van individuele softwarecomponenten speciale voorzieningen getroffen worden. Als iedere ontwerper dit op zijn eigen wijze oplost, zullen door verschillende ontwerpers gebouwde systemen niet met elkaar kunnen samenwerken. De enige oplossing is gebruikmaken van een overeengekomen standaard.
Softwarecomponenten die aan de gewenste eisen voldoen, zijn met bestaande programmeertalen te bouwen. Daarbij moeten strikte regels in acht genomen worden. Inmiddels is een aantal standaarden voor het bouwen en gebruiken van softwarecomponenten tot stand gekomen. De meest bekende zijn Activex, die zich baseert op het taalonafhankelijke ‘component object model’ (COM) en Javabeans, die gebruik maakt van het objectmodel van de programmeertaal Java.
Correct ontworpen softwarecomponenten zijn zodanig ingekapseld dat hun interne samenstelling van buitenaf onzichtbaar is. De in deze componenten geïnvesteerde kennis blijft voor de buitenwereld verborgen. Dit is een grote tegenstelling met de objectgeoriënteerde technologie. Wil men met vrucht van een klassenbibliotheek gebruikmaken, dan moet men kunnen beschikken over de broncode van de klassenbibliotheek. Daarmee ligt meteen alle daarin geïnvesteerde kennis bloot.
Zowel Activex-componenten als Javabeans leveren hun functionaliteit via zogenaamde interfaces. Een interface issoort een wijzer naar een deel van de implementatie van een klasse, waarin een aantal bij elkaar horende functies zijn samengebracht. Het is als het ware een loket, waar verschillende bij elkaar passende diensten aangeboden worden. Een softwarecomponent kan een hele reeks van dergelijke interfaces aanbieden. Als interfaces van dezelfde soort in verschillende soorten componenten gebruikt worden, heeft deze service een gunstige invloed op de gebruiksvriendelijkheid. De programmeur en uiteindelijk ook de eindgebruiker ondervindt daardoor een consistente en intuïtief toegankelijke toegangslaag. Activex-interfaces zijn in machinecode gedefinieerd en zijn daardoor vanuit verschillende programmeertalen te benaderen.
De beschikbaarheid van een passende infrastructuur is een strikte voorwaarde voor de toepasbaarheid van softwarecomponenten. Voor Activex is deze infrastructuur aanwezig in de nieuwe Windows-versies van Microsoft; zij is in opkomst in andere systemen, zoals Unix en het Mac OS. Javabeans zal ondersteund worden op systemen waarop Java kan draaien. Javabeans richt zich voornamelijk op Internet-toepassingen. De Activex-technologie richt zich ook op lokale toepassingen en is daarom meer schaalbaar dan de Javabeans-technologie.
Inmiddels zijn er voor verschillende programmeertalen krachtige hulpmiddelen, waarmee op relatief eenvoudige wijze softwarecomponenten te bouwen zijn. Softwarecomponenten zijn producten die onafhankelijk van hun werkomgeving geleverd kunnen worden. Inmiddels zijn honderden bedrijven actief om softwarecomponenten te ontwikkelen. De grootte van de markt werd het afgelopen jaar geschat op een kleine half miljard dollar. De voorspelling is dat deze markt in 2001 zal uitgroeien tot drie miljard dollar.
De toekomst
Microsoft heeft via de op COM gebaseerde Activex- technologie de derde-generatietalen en de objectgeoriënteerde talen aan elkaar gekoppeld. Via hun eigen versie van de virtuele machine die Javacode omzet in machinecode hebben ze bovendien kans gezien om de Activex-technologie te koppelen aan zowel de taal Java als de op deze taal gebaseerde Javabeans-softwarecomponenten. Dit gaat zover, dat men nieuwe Java-klassen kan afleiden van in andere talen gebouwde Activex-componenten. Hieruit blijkt dat Microsoft het verst gevorderd is met de softwarecomponent-technologie. De verwachting is dat hun aanpak tot een algemeen aanvaarde standaard verheven wordt. Het maakt bovendien duidelijk waarom Microsoft er zo op gebeten is om de Java-taal naar zijn hand te zetten. Alleen op Microsoft-technologie gebaseerde Java-virtuele-vertaalmachines voldoen aan de voorwaarde dat Java verenigbaar is met de Activex-technologie. Microsoft zal zowel zijn superieure softwarecomponent-technologie als zijn commerciële kracht inzetten om het beoogde doel te bereiken. Daarbij zal Microsoft desnoods een van de interessantste beloften van Java, de platformonafhankelijkheid, opofferen. Dit tij laat zich alleen keren als ook de Activex-technologie platformonafhankelijk gemaakt kan worden. Door deze technologie aan de Open Group over te dragen heeft Microsoft dit proces in gang gezet.
Het bedrijf Sun Javasoft is de ontwerper van Java en probeert uit alle macht te voorkomen dat Microsoft de toekomst van Java volledig gaat beheersen. Als de softwarecomponent-technologie een hoge vlucht neemt, zal dat een grote invloed hebben op de daarmee samengestelde toepassingsprogramma’s. Softwarecomponenten kunnen dynamisch aan een reeds lopend programma worden toegevoegd en zijn er na gebruik weer uit te verwijderen. Toekomstige toepassingsprogramma’s zullen niet veel meer dan schillen zijn, die hun functionaliteit voornamelijk halen uit de in hun omgeving aanwezige softwarecomponenten. Een tekstverwerker zal bijvoorbeeld niet meer zelf beschikken over een spellingscontrole en ook niet zelf in staat zijn om grafieken te genereren. Het maakt voor deze functies gebruik van tijdelijk binnengehaalde softwarecomponenten. Diezelfde componenten leveren hun diensten ook aan andere toepassingsprogramma’s, zoals een presentatieprogramma.
Toch ontstaat op deze wijze voor programmeurs nog steeds geen ideale situatie. De softwarecomponent-technologie verzorgt immers nog maar vijf van de zes genoemde modelleringselementen. Het zesde element, coördinatie, wordt noch door Activex, noch door Javabeans op consistente wijze neergezet. De collega’s die hardware-componenten ontwikkelen, beschikken juist wel over hulpmiddelen die dit modelleringselement ondersteunen. Zowel in de Activex-technologie als in Java zijn aanzetten te vinden die in de richting van een meer consistente aanpak van coördinatie gaan. In geen van beide is dit nog voldoende uitgewerkt. Na C, C++, Java, Activex en Javabeans zal er dus nog wel een andere taal of andersoortig hulpmiddel komen dat nog weer een stap verder gaat in het ondersteunen van het modelleringsproces.
Hans van Leunen is werkzaam als senior system software architect bij Philips Semiconductors te Eindhoven.
Welke softwaretechnologie?
De functioneel gerichte methodiek is geschikt voor relatief kleine toepassingen.
De objectgeoriënteerde aanpak is geschikt voor het bouwen van grote complexe toepassingen, waarbij alle programmeurs over de broncode van de klassenbibliotheek kunnen beschikken.
De softwarecomponententechnologie geniet voorkeur indien een aantal onafhankelijke instanties gezamenlijk aan een groot en complex project werken. Doeltreffende bescherming van de in ontwerp en bouw geïnvesteerde kennis en toepasbaarheid van softwarecomponenten als herbruikbare bouwstenen vormen een verklaring voor de snel groeiende belangstelling voor deze technologie. Microsoft laat zijn toekomst voor een belangrijk deel van deze aanpak afhangen.