Patrón Money: Maneja correctamente el dinero en tu aplicación y prepárala para el escalado internacional

Trabajar con cantidades de dinero nunca ha sido un asunto sencillo: redondeos, cambios de divisa… una mala gestión puede derivar en perdidas para nuestra empresa o en cobrar de más a nuestros clientes, con el consiguiente perjuicio reputacional.

El patrón Money

Martin Fowler publicó en 2002 su famoso libro Patterns of Enterprise Application Architecture, donde uno de los patrones incluidos era el llamado patron Money. Con este patrón, Fowler pretende simplificar la gestión de cantidades monetarias y reducir los posibles riesgos que antes comentábamos.

El patrón Money se basa en otro patrón conocido como Value Object, y consiste en modelar un pequeño objeto que represente una cantidad monetaria. Para ello se usan dos atributos: la cantidad (amount), y la moneda (currency), y una serie de operaciones lógicas y matemáticas:

Diagrama UML del Patron Money
Diagrama UML del Patrón Money

Atributos

  • amount: es el importe, representado siempre en la unidad mínima de la moneda asociada. Esta representación es perfecta para realizar comparaciones entre cantidades de una misma moneda, ya que las comparaciones entre números en coma flotante siguen siendo un asunto sin resolver en cualquier lenguaje.

    Es importante saber que no todas las monedas son como el dólar o el euro, ya que no en todas la unidad mínima es el céntimo. Existen monedas donde la propia moneda es la unidad mínima, y otras donde no sólo tienen céntimos, sino que tienen unidades más pequeñas que el céntimo.

    Ejemplos de estos casos son el dinar de Bahrain, con milésimas partes del dinar, o el peso de Chile, donde no hay unidades inferiores al peso. Se puede consultar una lista con todas las monedas este enlace.
  • currency: es el código ISO-4217 de la moneda con la que estamos trabajando. Es un código de 3 letras que representa la moneda de forma internacional, por ejemplo EUR para Euros.

Métodos / Operaciones

  • +, -, *, / : operaciones matemáticas básicas, como la suma, resta, multiplicación, división…
  • allocate: una operación especial destinada a dividir una cantidad de dinero entre dos o más receptores. Luego entraremos más en detalle.
  • <, >, ≤, ≥, = : operaciones lógicas básicas, como menor quemayor quemenor igual quemayor igual queigual

Ejemplos

Queremos representar la cantidad 528.75€, cuya unidad mínima es el céntimo de euro:

  • amount: 52875
  • currency: EUR

Queremos representar la cantidad 528.75.د (dinares de Bahrain), cuya unidad mínima es la milésima parte de un dinar.

  • amount: 528750
  • currency: BHD

Para representar visualmente la cantidad, solo necesitamos aplicar la sencilla fórmula: amount / (10 x unidad mínima).

Implementación

Es sencillo realizar una implementación básica de este patrón, lo realmente tedioso es tener actualizada siempre la lista de monedas, con sus unidades mínimas o sus ratios de conversión.

Veamos una implementación sencilla en PHP:+

Patron Money basico en PHP
Patrón Money básico en PHP

A esta implementación básica le faltarían todos los métodos de las operaciones lógicas y matemáticas. He querido dejar de lado esta implementación para poder comentar que podemos hacerlo en dos versiones distintas:

  • Orientado a objetos: añadiendo los métodos addsubstractmultiplydivide… Este sería el estilo orientado a objetos clásico. Nos permitiría tomar dos enfoques: mutable (modifica la instancia actual) o inmutable (no modifica la instancia, devuelve una nueva). De esta manera podremos ejecutar cosas como:
Mangel 3
  • Sobrecarga de operadores: muchos lenguajes orientados a objetos, como Java, PHP, Python o Ruby permiten lo que llamamos sobrecarga de operadores, que no es más que permitir cambiar el comportamiento de los operadores aritméticos y lógicos cuando estos son aplicados a objetos de cierta clase, y no a tipos primitivos como se hace habitualmente.
    Esto nos permitiría sobrecargar los operadores de tal manera que podríamos ejecutar algo así como:
Mangel 4

La implementación básica de este patrón es realmente muy sencilla, pero si queremos sacarle el máximo provecho tenemos implementaciones en casi todos los lenguajes, que además cubren otros aspectos como la representación visual de la cantidad (situar el símbolo monetario a la derecha o a la izquierda), o la conversión entre divisas.

Algunas implementaciones conocidas:


Método allocate

Este método, como ya comentamos antes, es un método especial usado para distribuir adecuadamente una cantidad entre dos o mas receptores cuando no puede hacerse de forma exacta (sin sobras). Por ejemplo cuando lo hacemos basándonos en porcentajes o ratios.

Veamos un caso específico:

Queremos repartir 5cts de euro entre dos cuentas al 30%-70%. Esto implica un reparto de 1,5cts y 3,5cts. El problema es que el céntimo es la unidad mínima de la divisa euro, y no podemos partir un céntimo en dos, por lo tanto el reparto exacto no puede hacerse.

La solución más habitual es repartir 1 céntimo a cada recipiente mientras no hayan llegado a la cantidad justa. Una vez haya sobrepasado esa cantidad, deja de recibir dinero.

Recipiente A1.5cts
Recipiente B2.5cts
Reparto esperado
#Recipiente ARecipiente B
1+1cts.
Total: 1
1 < 1.5 ✅
+1cts
Total: 1
1 < 2.5 ✅
2+1cts
Total: 2
2 < 1.5 ❌
+1cts
Total: 2
2 < 2.5 ✅
3No recibe más
(2 < 1.5 ❌)
+1cts
Total: 3
3 < 2.5 ❌
Distribución
Recipiente A2cts
Recipiente B3cts
Reparto final

_ Bibliografía
Money Pattern. Martin Fowler
Patterns of Enterprise Application ArchitectureMartin Fowler (2002)
Lista de unidades mínimas de cada moneda
Lista de códigos ISO-4217
Money Pattern: The right way

Backend

Miguel Ángel Sánchez Chordi

Miguel Ángel Sánchez Chordi

Ingeniero de software. Me encanta que los planes salgan bien.
Miguel Ángel Sánchez Chordi

Miguel Ángel Sánchez Chordi

Ingeniero de software. Me encanta que los planes salgan bien.
2023 ©Secture Labs, S.L. Created by Madrid x Secture