De bron aan de lezer geven
Vul run_report in. Roep de meegegeven reader precies eenmaal met source aan. Behandel haar echte teruggegeven bron als invoer voor de volgende stap; lees of kopieer die bron niet zelf vooruit.
De eerste parser zet een rij tekst om naar een registratie. Een compleet urenrapport moet daarnaast een bestand lezen, registraties selecteren en uitvoer publiceren. Wanneer al dat werk in één functie terechtkomt, wordt het lastig om een fout aan de juiste verantwoordelijkheid te koppelen.
Onze leesmodule beheert CSV en het invoerbestand. De rekenmodule maakt uit registraties een samenvatting, zonder zelf bestanden te openen. De uitvoermodule verzorgt de gekozen tekstvorm en de bestemming.
De regiefunctie verbindt die onderdelen in de juiste volgorde. Zij hoeft geen CSV-citaten te begrijpen of teamtotalen nogmaals uit te rekenen. Daardoor kun je een component verbeteren zonder de andere verantwoordelijkheden opnieuw te schrijven.
def load():
print('lezen')
return [20, 35]
def calculate(values):
print('rekenen')
return sum(values)
values = load()
answer = calculate(values)
print(answer)lezen rekenen 55
Het voorbeeld geeft de werkelijk gelezen waarden door aan de berekening. De regie zit in de twee opeenvolgende aanroepen. De uitvoer laat zien wanneer iedere taak gebeurt en welke echte uitkomst de tweede stap oplevert.
De onderdelen staan onder hetzelfde hours-pakket. Een relatieve import zoals from .reader import read_sessions verwijst naar de buurmodule. Je voert dit bestand daarom als pakketmodule uit, zoals je in de toolingmodule hebt geleerd.
In application.py staan de imports en de nog in te vullen run_report. De andere projectbestanden zijn meegeleverd, zodat je nu alleen de verbinding hoeft te bouwen. Latere lessen behandelen het model en de afzonderlijke I/O-taken opnieuw als eigen verantwoordelijkheid.
Een lezer kan een lijst teruggeven, maar ook een iterator. Die iterator alvast met list uitputten is geen noodzakelijke regietaak. Geef het ontvangen bronobject door aan de samenvatter, die verantwoordelijk is voor haar eigen bronronde.
Hetzelfde geldt voor het berekende rapport. De schrijver krijgt dat echte object; je maakt geen tweede rapport met mogelijk afwijkende waarden. De aanroeper ontvangt uiteindelijk de echte bestemming en datzelfde rapport samen als tuple.
De parameter reader bevat een functie, geen al gelezen bestand. Bij de gewone aanroep gebruiken reader, summarizer en writer de geïmporteerde projectfuncties als standaard. Met keywordargumenten kan een test gecontroleerde functies meegeven die hun ontvangen argumenten vastleggen.
Die kleine testfuncties bewijzen hier de samenwerking en foutdoorgifte. Zij zijn geen bewijs dat een echt CSV-bestand correct is gelezen of een rapport veilig is vervangen. Die onderdelen krijgen afzonderlijke uitvoeringsproeven.
Ook start, end en kind blijven expliciete argumenten. None betekent hier dat de aanroeper geen datumgrens koos. Een regiefunctie mag daar niet ongemerkt een vaste periode of altijd JSON van maken.
Een algemene handler die na iedere fout een leeg rapport teruggeeft, doet lijken alsof het programma geslaagd is. Misschien mislukte juist het lezen of schrijven. De aanroeper moet dat kunnen onderscheiden van een geldige samenvatting zonder registraties.
events = []
def load():
events.append('lezen')
raise ValueError('bron ontbreekt')
try:
values = load()
events.append('rekenen')
except ValueError as error:
print(type(error).__name__, str(error))
print(events)ValueError bron ontbreekt ['lezen']
Het voorbeeld laat zien dat gewone opeenvolgende code vanzelf stopt wanneer een aanroep een fout opwerpt. Een extra vlag voor iedere fase is daarvoor niet nodig. Het oorspronkelijke exceptionobject kan op een hoger niveau een begrijpelijke melding krijgen.
De lees- en uitvoermodule blijven verantwoordelijk voor hun eigen geopende bestanden en tijdelijke uitvoer. De regiefunctie herhaalt een mislukte fase niet zomaar: schrijven kan al een gedeeltelijk effect hebben gehad. Zo blijft de grens tussen samenwerken en opruimen zichtbaar.
Vul run_report in. Roep de meegegeven reader precies eenmaal met source aan. Behandel haar echte teruggegeven bron als invoer voor de volgende stap; lees of kopieer die bron niet zelf vooruit.
Roep summarizer eenmaal met diezelfde bron aan, met de werkelijke start en end als keywordargumenten. Laat ook None ongewijzigd door. Bewaar het echte berekende rapport.
Roep writer eenmaal aan met root, name, het berekende rapportobject en kind, in die volgorde. Wijzig of vervang het rapport niet. Geef (destination, report) als tuple terug met de echte retourwaarde van writer en hetzelfde rapportobject.
Geef een fout uit reader, summarizer of writer als hetzelfde exceptionobject door. Voer na een fout geen latere fase uit, herhaal een mislukte fase niet automatisch en geef geen gedeeltelijk succes terug.
Voer je code uit en ontdek
wat je hebt gemaakt.
Je hoeft het niet in één keer goed te doen. Na het uitvoeren zie je hier welke stappen al kloppen.