Executando verificação de segurança...
2

Três Olhares sobre Arquitetura de Software: Fowler, Evans e Uncle Bob: 2.1 - Active Record: simplicidade que pode custar caro

Capa

Na primeira parte desta série exploramos como o domínio pode ser modelado, protegido e orquestrado. Mas todo domínio, por mais elegante que seja, precisa encarar uma realidade inescapável: os dados precisam ser persistidos. Não basta calcular, validar ou expressar regras de negócio; é preciso garantir que esse estado sobreviva ao tempo. É nesse momento que a arquitetura encontra a infraestrutura, e que padrões se tornam decisivos para equilibrar clareza do modelo e eficiência técnica.

Martin Fowler dedicou uma boa parte do seu catálogo de Patterns of Enterprise Application Architecture justamente a esse tema: Active Record, Data Mapper, Unit of Work, Identity Map, Lazy Load. Cada um deles enfrenta dilemas recorrentes: como salvar e recuperar o estado do domínio sem deixá-lo refém do banco de dados? Como coordenar mudanças de forma transacional? Como manter performance sem sacrificar consistência?

Eric Evans, no Domain-Driven Design, sempre reforçou que a persistência deve ser invisível ao domínio. Para ele, o modelo precisa refletir a linguagem do negócio, não o schema do banco. Repositórios, Application Services e agregados só cumprem bem seu papel quando o banco fica em segundo plano, um detalhe de implementação.

Robert C. Martin, em Clean Architecture, é ainda mais radical: o banco de dados é um detalhe de infraestrutura, nunca o centro da arquitetura. Ele insiste que o domínio e os casos de uso não devem ter dependência alguma de frameworks ou tecnologias de armazenamento. O dado pode estar em SQL, NoSQL, arquivo em disco ou até mesmo em memória; o que importa é que o domínio continue protegido.

Nesta segunda parte da série, vamos olhar para os padrões de persistência com esses três óculos: Fowler, Evans e Uncle Bob. Vamos ver onde eles brilham, onde tropeçam e que escolhas arquiteturais nos forçam a enfrentar. E, como sempre, vamos usar exemplos em C# para tornar o debate mais concreto.


Índice da Série

Parte 1 – A lógica do domínio

Parte 2 – Persistência e Infraestrutura

Parte 3 – Apresentação e Integração


Active Record: simplicidade que pode custar caro

Introdução

Entre todos os padrões de persistência descritos por Martin Fowler, nenhum desperta tanto amor e ódio quanto o Active Record. Sua proposta é de uma simplicidade quase ingênua: um objeto que carrega seus dados e sabe como se salvar ou se carregar do banco. Nada de camadas intermediárias, nada de mapeadores complexos — apenas um “tudo em um” que parece resolver o problema com poucas linhas de código.

É justamente essa simplicidade que o tornou tão popular em frameworks, tutoriais e sistemas pequenos. Mas, quando o domínio amadurece e ganha complexidade, essa conveniência se transforma em fardo: regras de negócio se misturam com infraestrutura, o acoplamento cresce, a testabilidade desaparece e a linguagem do negócio se perde. Fowler o reconhece como útil em contextos limitados, Evans o vê como um obstáculo para um Domain Model rico, e Uncle Bob o condena como uma violação direta da separação entre negócio e infraestrutura.

Um padrão de duas faces

Fowler descreve o Active Record como uma solução legítima para sistemas em que a lógica de negócio é essencialmente CRUD. Em sistemas administrativos pequenos ou protótipos, ter objetos que representam linhas de tabela e sabem se salvar reduz esforço, facilita onboarding de desenvolvedores e acelera entregas. “É simples e funciona” e, às vezes, isso basta.

Mas Eric Evans, em Domain-Driven Design, nos lembra que, quando o domínio é o coração do sistema, misturar persistência e regras de negócio é um erro conceitual. Uma entidade que sabe calcular descontos e, ao mesmo tempo, abrir uma conexão com o banco, está carregando responsabilidades de naturezas diferentes. Isso dissolve a linguagem ubíqua e empurra o sistema para o que Evans chamou de Anemic Domain Model: classes que representam dados, mas sem comportamento expressivo. O código passa a refletir mais a estrutura da base de dados do que a realidade do negócio.

Robert C. Martin vai além. Na Clean Architecture, ele defende que o domínio deve permanecer puro, protegido no núcleo, isolado de frameworks e detalhes externos. Os círculos internos não podem depender de nada que esteja fora deles. O Active Record fura essa barreira ao trazer SQL e lógica de acesso a dados para dentro das entidades. O resultado é acoplamento: o domínio não pode ser testado sem banco, não pode ser usado em outro contexto sem arrastar junto a infraestrutura e muda a cada alteração no schema. Para Uncle Bob, esse é o oposto de uma arquitetura duradoura.

Exemplo prático em C#

Um exemplo simples ajuda a visualizar:

using System;
using System.Data.SqlClient;

// Active Record style entity
public class Customer
{
    public int Id { get; private set; }
    public string Name { get; private set; }

    public Customer(int id, string name)
    {
        Id = id;
        Name = name;
    }

    // Persistence logic inside the entity
    public void Save()
    {
        using var conn = new SqlConnection("connection-string");
        conn.Open();

        using var cmd = new SqlCommand("INSERT INTO Customers (Id, Name) VALUES (@Id, @Name)", conn);
        cmd.Parameters.AddWithValue("@Id", Id);
        cmd.Parameters.AddWithValue("@Name", Name);
        cmd.ExecuteNonQuery();
    }

    public static Customer Load(int id)
    {
        using var conn = new SqlConnection("connection-string");
        conn.Open();

        using var cmd = new SqlCommand("SELECT Id, Name FROM Customers WHERE Id = @Id", conn);
        cmd.Parameters.AddWithValue("@Id", id);

        using var reader = cmd.ExecuteReader();
        if (reader.Read())
        {
            return new Customer(reader.GetInt32(0), reader.GetString(1));
        }

        throw new InvalidOperationException("Customer not found.");
    }
}

A classe é pequena e clara, mas seu cheiro é forte: Customer conhece detalhes do banco, mistura lógica de domínio com infraestrutura e é difícil de testar. Imagine que queremos validar regras de fidelidade do cliente. Onde colocamos essa lógica? No mesmo objeto que abre SqlConnection? Em pouco tempo, a entidade vira um Frankenstein, carregando responsabilidades incompatíveis.

Um simples teste unitário já mostra o problema:

// Em teoria queremos apenas validar lógica de negócio...
var customer = new Customer(1, "Alice");
// ... mas qualquer teste real acaba pedindo banco de dados.
customer.Save(); // side-effect pesado e indesejado

Aqui, o domínio não é testável sem banco. A infraestrutura se tornou parte inseparável da regra de negócio.

O preço da conveniência

Fowler é pragmático: em alguns cenários, Active Record é suficiente. O problema não está no padrão em si, mas no mismatch entre problema e solução. Se o problema é simples, Active Record brilha. Mas se o domínio precisa refletir regras complexas, o padrão se torna um fardo.

Evans mostraria que, nesse caso, não temos um Domain Model, mas apenas uma camada de dados disfarçada de domínio. É a volta ao procedural, ainda que com objetos. Uncle Bob lembraria que, ao permitir isso, estamos comprometendo o futuro do sistema: mais frágil, difícil de testar, altamente acoplado. É exatamente o oposto do que buscamos em uma arquitetura limpa.

Conclusão

O Active Record é como um remédio de efeito rápido: ótimo para sintomas leves, perigoso quando o problema é mais profundo. Fowler o vê como aceitável em contextos simples. Evans o rejeita quando queremos modelos ricos. Uncle Bob o condena por comprometer a independência do core.

Isso nos leva a uma reflexão prática: quando você adota Active Record, está escolhendo conscientemente abrir mão de expressividade e de independência em troca de simplicidade inicial. É uma escolha que pode fazer sentido em protótipos, CRUDs descartáveis e sistemas auxiliares. Mas se o software é estratégico e precisa durar, esse atalho vira uma armadilha.

No próximo artigo, exploraremos justamente o contraponto: o Data Mapper, que tenta preservar a pureza do modelo ao custo de mais disciplina e complexidade. Será que vale pagar esse preço? Esse será o tema da nossa próxima discussão.

Carregando publicação patrocinada...