Un detalle importante para comprender las cuentas basadas en transacciones: el balance
atributo de account
es en realidad una instancia de desnormalización. Está ahí por conveniencia. En realidad, el saldo de una cuenta es la suma de sus transacciones, y realmente no necesita que la cuenta misma tenga un saldo.
Teniendo esto en cuenta, el acto de transferir un dinero no debe ser actualizar account
sino insertar transaction
.
Dicho esto, hay otra regla importante: el acto de agregar un transaction
debe ser atómico con una actualización del (campo de equilibrio desnormalizado de) account
.
Ahora, si entiendo el concepto DDD de agregados, lo siguiente parece relevante:
El agregado es un límite lógico para cosas que pueden cambiar en una transacción comercial de un contexto dado. Un agregado puede ser representado por una sola clase o por una multitud de clases. Si más de una clase constituye un agregado, una de ellas es la llamada clase o entidad raíz. Todo el acceso al agregado desde el exterior debe realizarse a través de la clase raíz.
Entonces, en términos de diseño DDD, sugeriría:
Hay un agregado para representar la transferencia
El agregado se compone de los siguientes objetos: la transferencia (el objeto raíz); el objeto raíz está vinculado a dos listas de transacciones (una para cada cuenta); y cada lista de transacciones está vinculada a una cuenta.
Todo el acceso a la transferencia debe ser meditado por el objeto raíz (el transfer
).
Si está intentando implementar el soporte de transferencia asíncrono, entonces su código principal debería preocuparse por crear la transferencia, en un estado "pendiente". Es posible que tenga otro hilo o un trabajo que realmente mueva el dinero (insertándolo en el historial de transacciones y, por lo tanto, actualizando los saldos) y establezca la transferencia en "contabilizada".
Si está buscando implementar una transacción de transferencia de bloqueo en tiempo real, entonces la lógica de negocios debería crear un transfer
objeto que coordinaría las otras actividades en tiempo real.
En términos de prevención de problemas de concurrencia, el primer orden comercial debe ser insertar la transacción de débito en la lista de transacciones de la cuenta de origen (actualizando el saldo, por supuesto). Esto debería realizarse atómicamente a nivel de la base de datos (a través de un procedimiento almacenado). Después de que se haya producido el débito, el resto de la transferencia debería poder tener éxito independientemente de los problemas de concurrencia, ya que no debería haber ninguna regla comercial que impida un crédito en la cuenta objetivo.
(En el mundo real, las cuentas bancarias tienen el concepto de una publicación de notas que respalda el concepto de una confirmación diferida de dos fases. La creación de la publicación de notas es liviana y fácil, y también puede revertirse sin problemas. la publicación de la nota en una publicación dura es cuando el dinero realmente se mueve, esto no se puede revertir, y representa la segunda fase de la confirmación de dos fases, que ocurre solo después de que se hayan verificado todas las reglas de validación).