Files
rkt-web-player/skill/racket-skill.md
T
2026-08-28 14:08:51 +02:00

8.7 KiB

name, description
name description
racket-programmeer-skill Hiermee wordt mijn voorkeur racket programmeerstijl aangegeven.

name: racket-programmeerstijl description: Gebruik deze skill wanneer je Racket-code voor Hans schrijft, wijzigt, refactort of beoordeelt. Pas de bestaande, eenvoudige en procedurele programmeerstijl toe; voorkom over-engineering en onnodige abstracties. Gebruik deze skill niet voor algemene uitleg over Racket waarbij geen code voor zijn projecten wordt gemaakt of aangepast.

Racket-programmeerstijl

Gebruik deze stijl wanneer je Racket-code voor Hans schrijft of aanpast.

Uitgangspunt

Het allerbelangrijkste uitgangspunt is dat je de programmerstijl van aangeleverde code volgt. Als je een zip met een package aangeleverd krijgt via de prompt dan volg je de programmeerstijl die je in de aangeleverde code vindt. Wanneer bestaande broncode beschikbaar is, heeft de stijl van die broncode voorrang. Sluit daar zo nauw mogelijk op aan.

Schrijf eenvoudige, directe en goed leesbare Racket-code. Kies de kleinste oplossing die het huidige probleem netjes oplost. Bouw geen abstraheringslaag voor mogelijk toekomstig gebruik. En maak geen helpers die alleen maar in de weg staan.

Structuur

  • Houd modules klein en doelgericht.
  • Splits functionaliteit alleen af naar een private module wanneer die een duidelijk eigen doel heeft.
  • Gebruik voor duidelijke secties bij voorkeur commentaar in deze vorm:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Supporting functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

of, wanneer dat beter bij de module past:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Internal state / functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Voor publieke functies:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Provided functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  • Houd provide en require eenvoudig en overzichtelijk.
  • Voeg geen extra framework, wrapperlaag of generieke infrastructuur toe zonder concrete noodzaak.

pre/postcondities

Geëxporteerde functies/procedures/classes of functies/procedures/classes die daarvoor duidelijk in aanmerking komen, d.w.z. die die provided zijn of naar verwachting zullen worden, moeten gedocumenteerd worden. Zowel in een module scribble als in de code zelf. In het engels.

In de code zelf: minimaal:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; goal : ; pre : <preconditie(s)> ; post : <postconditie(s)> ; [result:]

Over het algemeen wil je de internals van een functie weten. Hoe werkt het en waarom werkt het zo.

; [internals:] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Als een functie/procedure/class overduidelijk in aanmerking komt voor 'provide' en hij staat er nog niet in. Verzamel dan de lijst en vraag of je ze moet toevoegen.

Procedures en control flow

  • Geef de voorkeur aan gewone procedures met een direct leesbare control flow.
  • Gebruik let, if, when, unless, begin en cond expliciet wanneer dat de code duidelijker maakt.
  • Maak niet voor iedere kleine stap een aparte helperprocedure.
  • Introduceer geen hogere-orde of functionele constructies alleen omdat dat compacter kan.
  • Gebruik recursie of een named let wanneer dat de meest directe oplossing is.
  • Gebruik bij cond bij voorkeur deze vorm:
(cond 
  ([condition] korte body)
  ([other-condition]
   langere body))
  (else ... alleen als het nodig is)

Mate van abstractie vs leesbaarheid

Liever concreet dan abstract.

Geef expliciete, goed leesbare constructies de voorkeur boven compacte abstracte idiomen.

Bijvoorbeeld combinaties als (filter values (list (and condition 'symbol) ...)). Schrijf dan liever expliciet (filter (lambda (x) x) (list (if condition 'symbol #f) ...)). Vermijd vooral het stapelen van meerdere impliciete idiomen wanneer dat de leesbaarheid vermindert.

Gebruik lambda.

Geef de voorkeur aan λ boven lambda.

Waarden en state

  • Gebruik #f als normale waarde voor "niet gevonden", "niet beschikbaar" of "nog niet geïnitialiseerd" wanneer dat natuurlijk past.
  • Expliciete vergelijkingen zoals (eq? value #f) zijn prima wanneer dat de bedoeling duidelijk maakt.
  • Houd state eenvoudig. Een gewone modulevariabele zoals cached-git-exe is prima wanneer daarvoor geen zwaarder mechanisme nodig is.
  • Gebruik geen parameters, structs, classes of objectlagen wanneer een gewone variabele of procedure voldoende is.

Publieke API

  • Gebruik define/contract voor publieke procedures wanneer een contract nuttige documentatie en controle geeft.
  • Houd publieke procedures klein en voorspelbaar.
  • Verander een bestaande publieke API niet zonder noodzaak.
  • Voeg geen extra publieke functies toe voor hypothetische toekomstige behoeften.

Fouten en interactie

  • Geef duidelijke en concrete foutmeldingen.
  • Los eenvoudige interactieve invoer lokaal en procedureel op.
  • Maak foutafhandeling niet generieker dan nodig.
  • Als een externe executable of voorziening ontbreekt, meld precies wat ontbreekt en wat de gebruiker kan doen.

Configuratie

  • Bewaar lokale configuratie in een kleine, afzonderlijke private module wanneer dat de hoofdmodule eenvoudiger maakt.
  • Gebruik bestaande projectvoorzieningen, zoals simple-ini, rechtstreeks in plaats van er een extra abstractielaag omheen te bouwen.
  • Dupliceer geen configuratie die al door een extern programma zelf wordt beheerd.

Naamgeving en leesbaarheid

  • Kies concrete, korte namen die passen bij de bestaande code.
  • Gebruik Engels voor identifiers en technische namen wanneer de bestaande code dat doet.
  • Schrijf comments alleen wanneer ze iets toevoegen dat niet al vanzelf uit de code blijkt.
  • Geef de voorkeur aan een paar duidelijke regels boven een compacte maar moeilijker leesbare expressie.

Vermijd

Vermijd zonder concrete noodzaak:

  • over-engineering;
  • generieke wrappers;
  • extra abstraheringslagen;
  • dynamische require-constructies;
  • classes wanneer procedures volstaan;
  • structs wanneer een eenvoudige waarde volstaat;
  • configuratie-objecten of dependency-injectionpatronen;
  • veel kleine helperprocedures die de control flow versnipperen;
  • refactors die alleen bedoeld zijn om code "slimmer" of abstracter te maken.

Werkwijze bij aanpassen van bestaande code

  1. Lees eerst de omliggende module(s).
  2. Neem naamgeving, inspringing, control-flow-stijl en module-indeling over.
  3. Wijzig alleen wat voor de gevraagde stap nodig is.
  4. Houd bestaande werkende code intact als er geen reden is die te veranderen.
  5. Voeg geen volgende architectuurstappen alvast toe.
  6. Controleer of de oplossing eenvoudiger is dan het probleem; zo niet, vereenvoudig.

Referentiestijl

Deze vorm is representatief:

(define cached-value #f)

(define/contract (get-value)
  (-> (or/c path? #f))
  (if (eq? cached-value #f)
      (let ((value (find-value)))
        (set! cached-value value)
        value)
      cached-value))

Een wat langere maar direct leesbare implementatie heeft de voorkeur boven een kortere oplossing met meerdere nieuwe abstracties.

Schrijven van testgevallen voor modules/packages

Een test die alleen werkt vanuit de development directory, op het development-OS of met de lokale shell/environment is geen geldige package-test.

Racket Package Index / build-service tests

Behandel de Racket Package Index/build service als een aparte, strikte en onbekende testomgeving.

Bij packagecode en tests gelden daarom altijd de volgende regels:

  • Maak nooit aannames over current-directory of de directory van waaruit code of tests worden uitgevoerd. Bepaal testdata en paden expliciet en relocatable, bijvoorbeeld met runtime paths en tijdelijke directories.

  • Maak nooit impliciete aannames over het besturingssysteem. Vermijd OS-specifieke paden, shells, executables en gedrag, of handel verschillen expliciet per platform af.

  • Maak tests onafhankelijk van lokale environment state. Benodigde environment variables moeten expliciet en bij voorkeur geïsoleerd worden ingesteld.

  • Een succesvolle test moet stil en ondubbelzinnig succesvol zijn. Laat geen verwachte foutmeldingen naar de echte stdout/stderr lekken, omdat raco test --drdr en de Package Index dergelijke output als een mogelijke test failure kunnen classificeren.

  • Verwachte foutoutput moet worden gecaptureerd en geassert.

  • Tests moeten hun eigen tijdelijke state en testbestanden aanmaken en mogen geen bestanden, processen, environment changes of andere state achterlaten.

  • Test packagewijzigingen waar mogelijk ook in een omgeving die lijkt op: raco setup --check-pkg-deps en raco test --drdr --package <package>.