0%

Programma’s plannen, bouwen en testen · oefening

Bouw en test één onderdeel tegelijk

Een plan kan nog steeds groot aanvoelen wanneer je elke stap tegelijk probeert te implementeren. Bouw eerst een klein werkend deel.

Neem voor deze gerichte scoreberekening aan dat elk ingevoerd antwoord al niet-leeg is. Het resultaat "missing" uit de vorige les hoort bij de latere stap voor invoer en opnieuw proberen. Hier kan de scoreberekening zich richten op het vergelijken van geldige antwoordtekst.

Het quizprogramma moet hoofdletters en spaties aan de buitenkant negeren. Begin met het kleinste herbruikbare gedrag:

def clean_answer(text):
    return text.strip().lower()

Controleer het meteen:

assert clean_answer("  BLUE ") == "blue"

Bouw daarna het volgende onderdeel:

def answers_match(given, expected):
    return clean_answer(given) == clean_answer(expected)

Controleer dat afzonderlijk:

assert answers_match(" BLUE ", "blue") is True
assert answers_match("blue whale", "whale") is False

Gebruik het pas daarna in de scorelus:

def score_responses(responses):
    score = 0

    for response in responses:
        if answers_match(response["given"], response["expected"]):
            score += 1

    return score

Kleine controles beperken de zoekruimte bij fouten

Als de eindscore verkeerd is maar beide controles van hulpfuncties slagen, zit het probleem waarschijnlijk in de scorelus. Als de opschoningscontrole mislukt, heeft het nog geen zin om de lus te debuggen.

Elk voltooid onderdeel verkleint het gebied dat je moet onderzoeken.

Bouw in de volgorde van afhankelijkheden

Begin met functies die niet van je andere functies afhangen:

clean one answer
compare two cleaned answers
count matching response records
format the score

Zo ontstaat een natuurlijke volgorde. Latere functies kunnen vertrouwen op eerder gedrag waarvoor al bewijs bestaat.

Houd het programma uitvoerbaar

Na elke kleine wijziging:

  1. voer de gerichte controles uit;

  2. voer één voorbeeld van begin tot eind uit;

  3. sla de werkende toestand op of bewaar die;

  4. voeg het volgende gedrag toe.

Een half uur herschrijven gevolgd door één uitvoering aan het einde levert veel mogelijke oorzaken tegelijk op. Regelmatig kleine delen uitvoeren maakt het debuggen goedkoper en een stuk minder dramatisch.

Tijdelijke functies kunnen een plek vrijhouden

Tijdens het plannen kan een functieblok tijdelijk pass bevatten:

def score_responses(responses):
    pass

Zo kun je de grens benoemen en de aanroeper schetsen. Vervang deze tijdelijke invulling voordat je op het resultaat vertrouwt. Ze markeert onafgemaakt werk en is geen geslaagde implementatie.

Een quizscore hangt af van tekst opschonen en opgeschoonde waarden vergelijken. Welke bouwvolgorde geeft de duidelijkste feedback?

Opdracht

Bouw een quizscoreberekening in de volgorde van afhankelijkheden.

  1. Implementeer clean_answer(text) zodat de functie witruimte aan de buitenkant verwijdert en hoofdletters negeert.

  2. Implementeer answers_match(given, expected) zodat de functie clean_answer gebruikt en een booleaanse waarde teruggeeft.

  3. Implementeer score_responses(responses) zodat de functie één punt teruggeeft voor elk overeenkomend paar "given" en "expected".

Behoud de gerichte asserties na elke functie. Werk van boven naar beneden: zorg dat één functie en de bijbehorende controles slagen voordat je naar de volgende gaat. Behoud de voorbereide antwoorden en de laatste afdrukinstructie.

De antwoorden bevatten bewust spaties, verschillen in hoofdletters en één verkeerd antwoord. De uiteindelijke uitvoer moet zijn:

Score: 2/3