- En lugar de llamar directamente a la API de pagos en distintas partes de la lógica del producto, exe registra los cambios de estado como hechos facturables (billable facts) y luego reconcilia el estado confirmado con Stripe
- En la estructura anterior, las transacciones de base de datos y las llamadas a la API de pagos estaban entrelazadas, así que excepciones como fallas parciales, estados anómalos de suscripción y rechazos de pago terminaban afectando también el flujo del producto
- Cuando se agregan asientos de equipo, el estado se marca como dirty, y un worker posterior calcula la cantidad según las reglas de negocio y solo actualiza la cantidad de la suscripción en Stripe si hubo cambios
- Al separar los pagos, el onboarding de nuevos miembros del equipo deja de depender del código de facturación, y aunque cambien las reglas para calcular asientos, eso no afecta los flujos de invitación y registro
- La misma estructura de reconciliación también se aplica a la facturación por uso de elementos como VMs activas y uso de disco, así como a las compras dentro de la app en iOS, de modo que se pueden mantener los eventos del producto y cambiar solo la integración de cada proveedor de pagos
Separar la lógica de pagos del flujo del producto
- Cuando la lógica de pagos se mezcla con la lógica normal del negocio, el código relacionado termina esparcido por todas las rutas críticas que requieren facturación, y la estructura de precios también se vuelve frágil y difícil de cambiar
- exe busca que el conocimiento de pagos no quede concentrado en una sola persona y que cualquiera pueda modificar el código relacionado, mientras los casos excepcionales complejos quedan en manos de especialistas
- Al inicio, la facturación de asientos de equipo estaba unida desde la aceptación de la invitación hasta el cobro como un solo flujo grande
- El usuario aceptaba la invitación, verificaba su cuenta y luego se unía al equipo
- Recibía acceso a la VM compartida y recursos de cómputo según el plan
- En ese proceso también se llamaba a la API de pagos
- Al combinar cambios en la base de datos con llamadas a APIs externas, pueden ocurrir fallas parciales donde solo una parte tiene éxito
- El estado de la suscripción del equipo puede quedar anómalo
- El cobro por asientos adicionales puede ser rechazado
- Mientras más excepciones se acumulan, más frágil se vuelve toda la estructura
Hechos facturables y reconciliación posterior
- Un hecho facturable es una operación atómica que indica que cambió un estado específico
- Primero se ejecuta la lógica del producto para confirmar el nuevo estado de los recursos
- Después, con base en ese hecho confirmado, se reconcilia el estado del proveedor de pagos
- Stripe no necesita saber cómo se llegó a ese estado, sino solo la cantidad final
-
Reconciliación de asientos de equipo
- Cuando se acepta una invitación, el estado de los asientos del equipo se marca como dirty
- Un worker posterior detecta ese estado dirty y calcula el aumento o disminución de asientos según las reglas de negocio
- Solo si la cantidad cambió se actualiza en Stripe la cantidad de la suscripción
- Como agregar miembros del equipo y el código de pagos están separados, aunque se reescriba el flujo de invitaciones la facturación no se rompe al mismo tiempo, y la forma de calcular asientos también puede cambiarse de manera independiente
-
Facturación por uso y compras dentro de la app
- El mismo proceso de reconciliación se aplica a toda la facturación por uso
- El sistema registra hechos sobre VMs activas y uso de disco
- Un worker de medición los reconcilia con el estado del proveedor de pagos
- Incluso si se agrega un nuevo método de facturación, los hechos se mantienen iguales y solo cambia la forma de reconciliarlos con cada API
- La app de iOS igualmente solo transmite el hecho de que alguien se suscribió mediante una compra dentro de la app, y el estado real del pago se reconcilia después
- La estructura de pagos pasó a ser un área que otros miembros del equipo también pueden manejar, y también disminuyó la probabilidad de que cambios en funciones del producto, como el flujo de invitaciones, dañen el sistema de facturación
- El mismo proceso de reconciliación se aplica a toda la facturación por uso
1 comentarios
Opiniones en Lobste.rs
El punto central del artículo, detectar y procesar cambios de forma asíncrona, es bueno para reducir el acoplamiento e implementar efectos secundarios.
Pero los LLM, más que evitar que el código se disperse por todas partes, son una herramienta que acelera ese fenómeno, así que fácilmente se convierten en deuda arquitectónica. También queda la duda de cómo se puede revisar código que se genera más rápido de lo que se puede entender; y la parte donde Exe ni siquiera hace revisión de código da todavía más miedo.
Aunque esta arquitectura es interesante, no queda claro cómo resuelve el problema planteado al inicio del artículo. Si un pago es rechazado, parece que terminaría entregando primero los recursos no pagados, en vez de garantizar el pago de todos los recursos.
Un worker de facturación podría publicar el hecho
declinedpara recuperar los recursos, pero comparado con un flujo unidireccional limpio, eso se vuelve una estructura circular. Puede encajar bien en un servicio de cómputo que factura mensualmente como Exe, pero para un negocio que envía equipo físico o revende puestos de otros servicios, es una concesión difícil de aceptar.Sin embargo, no responde directamente cómo manejar fallas en llamadas de API o transacciones de base de datos, estados anómalos de suscripción o rechazos de pago de puestos. También siguen presentes problemas como que un refactor rompa la recolección de analíticas, que cierta fila deje de marcarse como modificada o que en una ruta nueva se olvide marcar el cambio.
Tampoco resuelve el estado relacionado con facturación que existe dentro del producto, como límites de puestos y cuotas gratuitas, topes de gasto máximo o deducción de saldos prepagados. El servicio de producto puede emitir eventos y el servicio de facturación puede reflejar de vuelta el estado de cumplimiento en el producto, pero entonces tienes dos actores en un sistema distribuido con estado.
Parece que Stripe solo quiere un número, pero a cierta escala, proporcionar también las partidas detalladas del pago puede reducir las comisiones de intercambio y aumentar la tasa de aprobación.
Es refrescante que Exe adopte un enfoque de no hacer revisión de código. En ese caso, me da curiosidad cómo gestionan los releases y las pruebas.