Dopo anni passati a compilare moduli e ad aspettare, hai finalmente ottenuto la licenza bancaria. Questo significa che ora puoi aprire ufficialmente la tua banca, evviva!
La tua prima priorità è far funzionare i sistemi informatici. Dopo una giornata di duro lavoro, sai già aprire e chiudere conti, oltre a gestire prelievi e versamenti.
Siccome non avevi voglia di scrivere i test, inviti alcuni amici a dare una mano a collaudare il sistema. Però, dopo appena cinque minuti, uno dei tuoi amici sostiene di aver perso dei soldi! Anche se sei sicuro che il tuo codice sia privo di bug, inizi a spulciare i log per indagare.
Ah, già, proprio come sospettavi: la colpa è del tuo amico! Ha condiviso le sue credenziali di test con un altro amico, e insieme hanno cospirato per fare versamenti e prelievi dallo stesso conto in parallelo. Chi mai farebbe una cosa del genere?
Mentre sostieni che sia fisicamente impossibile accedere al proprio conto in parallelo, il tuo amico ti fa notare con aria di sufficienza che le regole bancarie ti impongono di supportarlo. Quindi niente supporto bancario in parallelo, niente via libera per il lancio. Sospirando, ti riprometti mentalmente di occupartene domani. Questo sposterà la data di lancio di almeno un altro giorno, ma vabbè...
Il tuo compito è implementare conti bancari che supportino l'apertura e la chiusura, i prelievi e i depositi di denaro.
Poiché è possibile accedere ai conti bancari in molti modi diversi (internet, telefoni cellulari, addebiti automatici), il software bancario deve permettere di accedere ai conti in modo sicuro da più thread/processi (la terminologia dipende dal linguaggio di programmazione che usi) in parallelo. Ad esempio, possono verificarsi molti depositi e prelievi in parallelo; devi assicurarti che non ci siano race condition tra il momento in cui leggi il saldo del conto e quello in cui imposti il nuovo saldo.
Dovrebbe essere possibile chiudere un conto; le operazioni su un conto chiuso devono fallire.
Python non supporta la concorrenza «vera» a causa del Global Interpreter Lock. Sebbene siano in corso lavori per creare il supporto al free-threading in Python, è ancora sperimentale. Le attuali soluzioni della libreria standard, come multiprocessing e threading, sono difficili da implementare con gli strumenti attuali del track.
Di conseguenza, il requisito di concorrenza è stato messo da parte per questo esercizio. Le operazioni sul conto sono sequenziali su un singolo thread, e non vengono eseguiti test di concorrenza o di «race condition».
Se vuoi sperimentare con il free-threading o con i test di concorrenza, ti chiediamo di farlo in locale. Per ricevere aiuto su come scaricare gli esercizi e lavorarci in locale, ti consigliamo la Exercism CLI.
A volte è necessario sollevare un'eccezione. Quando lo fai, dovresti sempre includere un messaggio di errore significativo che indichi qual è l'origine dell'errore. Questo rende il codice più leggibile ed aiuta molto durante il debug. Nei casi in cui sai che l'origine dell'errore sarà di un certo tipo, puoi scegliere di sollevare uno dei tipi di errore predefiniti, ma dovresti comunque includere un messaggio significativo.
Questo esercizio richiede in particolare che tu usi l'istruzione raise per «lanciare» un ValueError quando un conto è aperto o non è aperto, oppure quando gli importi di prelievo o deposito non sono corretti. I test passeranno solo se fai il raise dell'exception e ci includi anche un messaggio.
Per sollevare un ValueError con un messaggio, scrivi il messaggio come argomento del tipo exception:
# account is not open
raise ValueError('account not open')
# account is already open
raise ValueError('account already open')
# incorrect withdrawal/deposit amount
raise ValueError('amount must be greater than 0')
# withdrawal is too big
raise ValueError('amount must be less than balance')
Iscriviti a Exercism per imparare e padroneggiare Python con 17 concetti146 esercizi e il mentoring di persone reali, tutto gratis.