Kontraktbaseret programmering

Kontraktbaseret programmering er en tilgang til design af software. Den foreskriver at designere af software bør definere formelle, præcise og verificérbare specifikationer til softwarens grænseflader. Det er meningen at disse specifikationer skal udvide de sædvanlige definitioner for abstrakte datatyper med såkaldte forhåndsbetingelser, postconditions og invarianter, der kan betragtes som efterviselige, logiske udsagn som skal stemme overens med softwarens forventede adfærd. Disse specifikationer omtales som kontrakter og kan sammenlignes med betingelser og forpligtelser i juridiske kontrakter.

Formålet med kontraktbaseret programmering er at forsøge at garantere korrekt opførsel for software.

Historik

Begrebet blev først anvendt af Bertrand Meyer i forbindelse med designet af programmeringssproget Eiffel, og det blev først beskrevet i forskellige artikler i 1986 og uddybet i bogen Object-Oriented Software Construction i 1988 af samme. Begrebet Design by Contract er et varemærke i USA, hvorfor man på engelsk benytter en række varianter som Programming by Contract eller Contract Programming for at undgå problemer med varemærker.

Beskrivelse

Kernen i kontraktbaseret programmering hviler på en metafor, kontrakten, og analogien til hvordan dele af computersystemer samarbejder på basis af fælles forpligtelse og fælles fordele. Metaforen kommer fra forretningslivet hvor en klient og en leverandør laver aftaler på basis af en kontrakt. Disse kunne være:

  • Leverandøren er forpligtet til at levere et bestemt produkt (forpligtelse) og kan forvente at klienten har betalt for ydelsen (fordel).
  • Klienten er forpligtet til at betale for ydelsen (forpligtelse) og er berettiget produktet (fordel).

Betingelser i kontraktbaseret programmering opdeles i forhåndsbetingelser, postconditions og invarianter, der henholdsvis kan forklares ved spørgsmålene Hvilke udsagn forventes at være sande her?, Hvilket arbejde kan garanteres at have været udført her? og Hvilke tilstande er garanteret fastholdt her?

Et objekt-orienteret softwareeksempel kunne være:

  • at konstruktøren til en klasse forventer at en af parametrene, der definerer objekter af denne klasse, ligger inden for et bestemt interval af heltal (forhåndsbetingelse). Her kan den abstrakte datatype heltal levere en del af garantien, idet der kan tjekkes at typen er korrekt, men en eftervisning af at parametren ligger inden for det korrekte interval vil ofte afhænge af andre egenskaber i sproget end dem typesystemet tilbyder (assertions, guards m.v.).
  • at enhver ændring af parametren registreres (postcondition).
  • at parametren aldrig ændres til en værdi udenfor intervallet (invariant).

Kontraktbegrebet strækker sig her til funktions-/metode-/procedureniveau, og kontrakten for disse indeholder oftest informationer om:

  • Inputværdier og acceptable/uacceptable værdier og typer for dem
  • Returværdier, deres typer og betydningen af disse
  • Fejl og undtagelser, hvornår de må og bør forekomme og deres betydning
  • Sideeffekter, hvornår de må og kan forventes at forekomme
  • Forhåndsbetingelser, postconditions og invarianter
  • Ydelsesgarantier (fx tids- og hukommelsesforbrug)

Inden for kontraktbaseret programmering ses disse spørgsmål som så vigtige at tage stilling til, at man helst definerer kravene i designfasen samtidigt med udformningen af grænseflader, før man påbegynder programmeringen. Idet softwaren overholder kravene, kan en kontrakt ses som en del af softwarens dokumentation.

Ved brug af kontrakter er det desuden ikke meningen at verifikation af den samme del af kontrakten skal ske flere steder som en ekstra forsikring, men at softwaren fejler hårdt, altså udmelder en kørselsundtagelse, sådan at man ved fejlfinding kan drage nytte af fejlens placering i henhold til hvilken del af programmeringskoden der er ansvarlig for at fejlen ikke forekommer. Denne praksis står som modsætning til begrebet defensiv eller sikker programmering.