Princípios de engenharia para construir sistemas financeiros
(substack.wasteman.codes)- A contabilidade não mudou muito ao longo dos últimos séculos
- Mesmo assim, ainda há muita confusão sobre a forma correta de construir software para sistemas financeiros
- Este texto compartilha lições baseadas na experiência de construir sistemas financeiros em grandes empresas
- Embora o foco seja a construção de sistemas contábeis, esses princípios também se aplicam a sistemas financeiros de forma mais ampla
Definições de termos financeiros básicos
- Livro razão geral (General Ledger, GL): o principal registro contábil de uma empresa, que resume todas as transações financeiras de um determinado período. Pode ser visto como a agregação dos respectivos sub-ledgers
- Sub-ledger: contém os detalhes de todas as transações individuais relacionadas a um GL específico. Os registros de um sub-ledger incluem dados muito mais granulares do que o livro razão geral (por exemplo, um cliente específico, um item específico de um pedido etc.). A diferença de dados entre o sub-ledger e o GL varia conforme o tipo de negócio e o volume de dados em processamento. Algumas pequenas empresas podem operar sem sub-ledgers, mas, nesse porte, é pouco provável que precisem de software sob medida
- Registro financeiro (Financial Record): termo coletivo para o livro razão geral e os sub-ledgers
- Materialidade (Material): indica se uma distorção nas informações das demonstrações financeiras influencia a tomada de decisão de uma parte interessada razoável. Essa definição é intencionalmente um pouco vaga, porque empresas diferentes têm critérios de materialidade diferentes. Por exemplo, algo importante para uma empresa com receita anual de US$ 250 mil pode não ser importante para uma empresa com receita anual de US$ 1 bilhão. Do ponto de vista de design, o principal valor desse conceito é classificar diferentes categorias de dados financeiros
High Level Data Flow
Business System --(Financial Events)--> Sub Ledger(s) --(Summarized Accounting Entries)--> General Ledger
Três objetivos principais de um sistema contábil
- Precisão (Accurate): os registros financeiros devem refletir o estado conhecido do negócio
- Ex.: se foram vendidos 10 produtos de US$ 9,99, o total nesses registros financeiros deve ser US$ 99,90
- Isso pode parecer óbvio, mas, ao agregar milhares ou milhões de transações, simples somas entre sistemas ou erros de arredondamento podem gerar imprecisões relevantes
-
Nota do Wasteman
- As pessoas dizem que naming é o problema mais difícil da ciência da computação, mas eu acho que soma vem logo depois
- Nos últimos anos trabalhando com sistemas financeiros de grande escala, vi incontáveis casos em que bugs minúsculos causaram grandes diferenças nos dados
- Nem comece a falar sobre somas com float. Aprendi da pior forma por que se deve sempre usar inteiros
- Os registros financeiros devem ser completos (complete)
- Mais especificamente, os sub-ledgers e o livro razão geral devem representar integralmente toda a atividade de negócio ocorrida em um determinado momento
- Se houve eventos que ocorreram, mas não estão nos registros financeiros, então o sistema não está completo
- Isso não significa que consistência eventual (eventual consistency) não seja permitida
- É preciso saber quando os dados estarão completos para poder informar às partes interessadas que os dados foram fechados
-
Nota do Wasteman
- Garantir completude também é um problema surpreendentemente difícil
- À medida que o sistema cresce, os dados podem ser alterados por engano ou perdidos ao passar por vários sistemas
- Auditabilidade (Auditable): os registros financeiros devem ser fáceis de auditar, para que as partes interessadas consigam detectar erros e medir com precisão o desempenho do negócio
- Pontualidade (Timely): o sistema contábil deve atender às necessidades específicas do negócio
- Para empresas pequenas, despejar todos os números no fim do mês pode ser suficiente, mas empresas grandes normalmente querem sistemas quase em tempo real
- Isso permite monitorar a saúde financeira ao longo de todo o mês, tomar decisões baseadas em dados financeiros com mais rapidez e reduzir a correria para fechar o mês/trimestre no começo do período seguinte
- Seja qual for a necessidade, nosso sistema contábil deve atender aos requisitos do negócio, exatamente no sentido em que pontual significa para ele
-
Nota do Wasteman
- As pessoas tendem a se perder em discussões sobre sistemas batch versus streaming quando falam de pontualidade
- Na minha visão, para a maioria dos sistemas isso não é uma distinção importante
- Isso importa se você se preocupa com latências muito curtas, na faixa de segundos a minutos
- Mas é surpreendentemente comum ouvir gente discutindo o que fazer quando o consumidor nem precisa ver atualizações mais do que algumas vezes por dia
- Só porque alguém pediu não significa necessariamente que isso seja necessário
Três princípios de engenharia fundamentais que um sistema contábil deve seguir
- Imutabilidade (Immutability) e durabilidade (Durability) dos dados
- Isso permite auditabilidade, ajudando na depuração e na precisão
- Quando os dados são imutáveis, é possível registrar o estado do sistema a qualquer momento
- Isso torna muito fácil recalcular o mundo a partir de um estado anterior, porque nenhum estado se perde
- Uma vez que um dado esteja explicitado no registro financeiro, ele não pode ser apagado
- Toda correção no sistema deve ser representada como uma nova transação financeira
- Ex.: se houver um bug no sistema e um serviço que deveria ter sido vendido por US$ 900 tiver sido registrado por engano como vendido por US$ 1000
- Para corrigir esse erro, primeiro é preciso estornar o lançamento contábil correspondente ao erro e depois refazer o lançamento com o valor correto
- Os dados devem ser registrados no menor nível de granularidade possível (Data recorded at the smallest grain)
- Assim como o princípio acima, isso também é extremamente importante para permitir uma trilha de auditoria clara
- Mesmo que os relatórios financeiros e o livro razão geral sejam agregados, eles são calculados a partir de eventos mais granulares
- Quando os dados não fazem sentido, é preciso ter os dados mais granulares para depurar qual foi o problema
- Armazenar os dados no menor nível de granularidade também facilita muito corrigir os dados derivados desse dataset
- Se um único dataset imutável for a fonte central da verdade para todas as visões desses dados,
- para corrigir uma visão, basta corrigir os dados e executar novamente o pipeline que gera essa visão
- De forma semelhante, quando os contadores se preparam para fechar os livros,
- eles conciliam todas as transações ocorridas e os saldos das contas para verificar se os livros estão corretos
- se encontrarem divergências, podem investigar a transação exata que está causando o problema
- Deve haver idempotência (Idempotency)
- Todo evento financeiro deve ser processado apenas uma vez, e duplicações nos registros financeiros causarão imprecisões óbvias
- Por isso, todo código que gera registros financeiros deve ser idempotente
- Idempotente significa que aplicar uma operação várias vezes não altera o resultado
- Ou seja, mesmo que um evento financeiro seja processado várias vezes, o resultado deve ser igual ao do primeiro processamento
Boas práticas
- Prefira inteiros para representar valores financeiros: as operações aritméticas ficam muito mais simples. Evite float
- Dê suporte à granularidade de valores financeiros para minimizar perda de precisão em conversões cambiais
- Se você lida apenas com dólares, representar em centavos pode ser suficiente
- Para negócios globais, prefira microunidades ou números decimais como
DECIMAL(19, 4) - Embora o uso de decimais seja popular em sistemas financeiros, microunidades são o padrão em sistemas financeiros de publicidade
- Use um método de arredondamento consistente: dependendo da forma de arredondar, pode haver diferenças relevantes em relação ao valor esperado
- Arredondar todos os valores de 5 para cima para o próximo dígito significativo e de 4 para baixo
- Sempre arredondar para cima, etc.
- O importante é manter consistência em todo o sistema (se a diferença for de 1 centavo por transação, em 10 milhões de transações isso vira US$ 100 mil)
- Adie a conversão de moeda o máximo possível: converter moeda cedo demais pode causar perda de precisão
- Adie a conversão cambial até depois que as agregações tiverem ocorrido na moeda local
- Use representação inteira para tempo: é um pouco controverso, mas fortemente recomendado
- Diferentes bibliotecas que fazem parsing de timestamps como objetos lidam com isso de formas diferentes
- É melhor evitar essa dor de cabeça e usar inteiros
- Unix timestamps ou datetimes inteiros baseados em UTC também funcionam perfeitamente
- Quanto menos transformação de dados entre sistemas, melhor
-
Nota do Wasteman
- Nem cheguei a mencionar bugs relacionados a horário de verão. Usar inteiros crescentes evita isso completamente
- Se você insistir em datetime, use pelo menos UTC. É surpreendentemente comum ver empresas enormes usando timestamps que não estão em UTC
2 comentários
Isso é realmente muito útil. Se você fizer conversões de tipo (
decimal,float,double) e arredondamentos sem pensar, sem discutir isso no contexto do trabalho, pode dar um problemão.Comentários do Hacker News
Ênfase na importância de usar uma metodologia de arredondamento consistente
Recomendação de representar o tempo como inteiro
Recomendação de usar banco de dados relacional em sistemas contábeis
Os principais objetivos de um sistema contábil são exatidão, auditabilidade e pontualidade
Opinião sobre a completude dos sistemas contábeis
Para negócios globais, recomenda-se usar pelo menos 8 casas decimais
Menção à importância da interface do usuário (UI)
Explicação da diferença entre processamento em lote e processamento em streaming
Compartilha experiência na construção de um sistema de faturas com TypeScript
Recomendação de usar classes da biblioteca padrão
BigDecimaldo Java eDecimaldo PythonExplica as dificuldades de arredondamento e compartilhamento de dados
Compartilha experiência trabalhando com APIs dos 10 maiores bancos dos EUA
Recomendação de "Accounting Patterns", de Martin Fowler