Rutas
/
Roc
Roc
/
Ejercicios
/
Cuenta bancaria
Cuenta bancaria

Cuenta bancaria

Fácil

Introducción

Después de años rellenando formularios y esperando, por fin has conseguido tu licencia bancaria. Esto significa que ahora puedes abrir oficialmente tu propio banco, ¡hurra!

Tu primera prioridad es poner en marcha los sistemas informáticos. Después de un día de duro trabajo, ya puedes abrir y cerrar cuentas, además de gestionar ingresos y reintegros.

Como no tenías ganas de escribir tests, invitas a unos amigos para que te ayuden a probar el sistema. Sin embargo, a los cinco minutos, uno de tus amigos afirma que ha perdido dinero. Aunque confías en que tu código no tiene errores, empiezas a revisar los registros para investigar.

Ah, sí, justo como sospechabas, ¡tu amigo tiene la culpa! Compartió sus credenciales de prueba con otro amigo y, juntos, conspiraron para hacer ingresos y reintegros desde la misma cuenta en paralelo. ¿A quién se le ocurriría hacer algo así?

Mientras argumentas que es físicamente imposible que alguien acceda a su cuenta en paralelo, tu amigo te informa con suficiencia de que las normas bancarias exigen que lo soportes. Así que, sin soporte para la banca en paralelo, no hay señal de lanzamiento. Suspiras y te apuntas mentalmente que mañana te pondrás con ello. Esto retrasará tu fecha de lanzamiento al menos un día más, pero bueno...

Instrucciones

Tu tarea consiste en implementar cuentas bancarias que admitan aperturas y cierres, retiradas e ingresos de dinero.

Como se puede acceder a las cuentas bancarias de muchas maneras distintas (internet, teléfonos móviles, cargos automáticos), tu software bancario debe permitir acceder a las cuentas de forma segura desde varios hilos o procesos en paralelo (la terminología depende de tu lenguaje de programación). Por ejemplo, puede haber muchos ingresos y retiradas ocurriendo en paralelo; debes asegurarte de que no haya condiciones de carrera entre el momento en que lees el saldo de la cuenta y aquel en que estableces el nuevo saldo.

Debe ser posible cerrar una cuenta; las operaciones sobre una cuenta cerrada deben fallar.

Responsabilidades de Roc y del host

En el código de Roc, normalmente nos centramos en la lógica de negocio mientras la plataforma se encarga de la concurrencia y del estado compartido. Por eso, en este ejercicio solo tienes que implementar las operaciones de la cuenta en BankAccount.roc sin preocuparte por la concurrencia. Las cuentas empiezan cerradas, reabrir una cuenta restablece el saldo, y los depósitos y las retiradas deben ser positivos.

Demostración opcional del servidor

El archivo bank-account-demo.roc incluido muestra cómo se puede usar tu implementación en un pequeño servicio web. Puedes leerlo en el editor, pero es independiente de las pruebas y no forma parte de tu solución.

Para ejecutar la demostración, tienes que instalar Roc en tu máquina, instalar la CLI de Exercism y después ejecutar este comando en una terminal:

exercism download --exercise=bank-account --track=roc

A continuación, implementa BankAccount.roc y pruébalo con el siguiente comando (cambia la ubicación de descarga que muestra la CLI si no coincide con la ruta de abajo):

cd ~/Exercism/roc/bank-account
roc test bank-account-test.roc

Cuando pasen todas las pruebas, puedes iniciar el servidor de la demostración con el siguiente comando:

roc bank-account-demo.roc

El servidor usa la plataforma basic-webserver y su compatibilidad integrada con SQLite (Roc descarga la plataforma la primera vez que se ejecuta). No hace falta un servidor de base de datos aparte. El servidor escucha en http://127.0.0.1:8000 y crea bank-account-demo.db en tu directorio actual (define DB_PATH para usar otro fichero de base de datos). Detén el servidor con Ctrl-C. Los datos se conservan entre reinicios.

En otra terminal, puedes llamar al servicio web con curl (en Windows, usa curl.exe en todos los casos para evitar el alias curl de PowerShell). Por ejemplo, así puedes abrir la cuenta n.º 123, depositar 50, retirar 10 y consultar su saldo:

curl -X POST http://127.0.0.1:8000/accounts/123/open
curl -X POST http://127.0.0.1:8000/accounts/123/deposit/50
curl -X POST http://127.0.0.1:8000/accounts/123/withdraw/10
curl http://127.0.0.1:8000/accounts/123/balance

El saldo es 40. Los identificadores de cuenta y las cantidades deben ser enteros sin signo. Las actualizaciones devuelven OK si tienen éxito o un error de tu implementación de la cuenta si fallan. Para cerrar la cuenta n.º 123:

curl -X POST http://127.0.0.1:8000/accounts/123/close

Para probar peticiones concurrentes en Linux/macOS, usa un identificador de cuenta nuevo y envía 100 depósitos desde ocho clientes:

curl -X POST http://127.0.0.1:8000/accounts/456/open
seq 100 | xargs -P 8 -I '{}' curl --fail --silent --show-error -X POST http://127.0.0.1:8000/accounts/456/deposit/1
curl http://127.0.0.1:8000/accounts/456/balance

En Windows, usa PowerShell 7+ para el ejemplo en paralelo:

curl.exe -X POST http://127.0.0.1:8000/accounts/456/open
1..100 | ForEach-Object -Parallel { curl.exe --fail --silent --show-error -X POST http://127.0.0.1:8000/accounts/456/deposit/1 } -ThrottleLimit 8
curl.exe http://127.0.0.1:8000/accounts/456/balance

Todos los depósitos deberían tener éxito y el saldo debería ser 100.

Cómo gestiona la concurrencia la demostración

Cada petición lee la cuenta, llama a tus funciones de Roc y guarda el resultado dentro de una transacción Immediate de SQLite. Las operaciones fallidas se revierten sin modificar la cuenta. SQLite permite un solo escritor a la vez, lo que evita que las peticiones concurrentes sobrescriban las actualizaciones de las demás (incluso entre cuentas distintas).

Nota: el ejercicio usa U64, pero la demostración guarda los saldos como enteros de SQLite y rechaza las actualizaciones que superan el valor máximo de I64 (9223372036854775807).

Para ver un ejemplo de cómo ejecutar cálculos independientes en paralelo, prueba el ejercicio parallel-letter-frequency.

Pistas

Mostrar pistas

Usa match para distinguir Closed de Open(balance). Una operación devuelve una cuenta actualizada en lugar de modificar la cuenta que recibe. Usa Ok(updated_account) para una actualización correcta y Err(...) para una operación rechazada.

Editar en GitHub El enlace se abre en una ventana o pestaña nueva
Roc Exercism

¿Listo para empezar Cuenta bancaria?

Regístrate en Exercism para aprender y dominar Roc con 135 ejercicios y mentoría humana real, todo gratis.