Leaders Logo

Connascence em .NET: Como Reduzir Acoplamento Sem Perder Velocidade de Entrega

Introducao

Acoplamento excessivo continua sendo uma das principais causas de fragilidade em sistemas corporativos. Em plataformas modernas como .NET, o desafio nao e apenas construir rapido, mas permitir evolucao segura ao longo do tempo. O conceito de Connascence oferece um vocabulário tecnico para diagnosticar dependencias e orientar refatoracoes com criterio arquitetural (PAGE-JONES, 1992).

Neste artigo, exploramos como aplicar Connascence em APIs, servicos e fluxos orientados a eventos em .NET 10, mostrando praticas para deslocar acoplamento de areas distribuidas para pontos locais e mais controlaveis (EVANS, 2003).

Fundamentos de Connascence

Definicao e motivacao

Connascence descreve o grau de conhecimento compartilhado exigido entre partes de um sistema para que ele funcione corretamente. Quanto maior o conhecimento compartilhado e mais distante ele estiver no sistema, maior o risco de regressao em mudancas futuras (PAGE-JONES, 1992).

Principais tipos de Connascence

No dia a dia com .NET, os tipos mais comuns aparecem como:

  • Connascence of Name (CoN): dependencia de nomes exatos (metodos, propriedades, campos JSON).
  • Connascence of Type (CoT): dependencia de tipos e formatos especificos.
  • Connascence of Meaning (CoM): dependencia de convencoes implicitas, sem documentacao explicita.
  • Connascence of Execution/Timing (CoE/CoTg): dependencia de ordem e tempo de execucao.
  • Connascence of Algorithm (CoA): multiplos pontos replicando o mesmo algoritmo.
  • Connascence of Position (CoP): dependencia da posicao de argumentos ou campos.

O objetivo nao e eliminar toda connascence, mas reduzir suas formas mais nocivas e, quando inevitavel, mante-las em escopos locais e altamente testaveis (FOWLER, 2002).

Connascence em APIs .NET

Exemplo de acoplamento por posicao e significado

Um antipattern recorrente e expor APIs com parametros posicionais sem semantica explicita:

// Antipattern: alto risco de CoP e CoM
public sealed class PricingService
{
    public decimal Calculate(decimal value, decimal discount, decimal tax)
        => (value - discount) * (1 + tax);
}

// Chamada fragil: a ordem errada compila e falha apenas em runtime/logica
var total = pricing.Calculate(100m, 0.2m, 10m);

A refatoracao para um contrato explicito reduz ambiguidades e facilita evolucao:

public sealed record class PricingInput
{
    public required decimal GrossAmount { get; init; }
    public required decimal DiscountAmount { get; init; }
    public required decimal TaxRate { get; init; }
}

public sealed class PricingService
{
    public decimal Calculate(PricingInput input)
        => (input.GrossAmount - input.DiscountAmount) * (1 + input.TaxRate);
}

var total = pricing.Calculate(new PricingInput
{
    GrossAmount = 100m,
    DiscountAmount = 10m,
    TaxRate = 0.2m
});

Versionamento e connascence de nome

Alterar nomes de campos em contratos publicos cria CoN distribuida entre provedores e consumidores. Em .NET 10, o caminho mais seguro continua sendo evolucao aditiva com DTOs versionados por namespace e serializacao explicita, mantendo retrocompatibilidade (NEWMAN, 2021).

namespace Contracts.V1;

public sealed record class OrderDto
{
    public required Guid Id { get; init; }
    public required decimal TotalAmount { get; init; }
}

namespace Contracts.V2;

public sealed record class OrderDto
{
    public required Guid Id { get; init; }
    public required decimal TotalAmount { get; init; }
    public string? Currency { get; init; }
}

Connascence em Arquiteturas Distribuidas

Eventos e connascence de tempo

Em mensageria, assumir ordem fixa de eventos entre servicos diferentes e uma forma perigosa de CoE/CoTg. Em vez disso, prefira mensagens autoexplicativas, idempotencia e processamento orientado a estado, nao a sequencia estrita (VERNON, 2013).

public sealed record class PaymentReceivedV1
{
    public required Guid OrderId { get; init; }
    public required decimal Amount { get; init; }
    public required DateTimeOffset OccurredAt { get; init; }
    public required string EventId { get; init; }
}

public sealed class PaymentProjection
{
    private readonly HashSet<string> _processed = [];

    public bool TryApply(PaymentReceivedV1 evt)
    {
        if (!_processed.Add(evt.EventId))
        {
            return false; // Idempotencia evita dependencia de timing e repeticao
        }

        // Atualiza estado de forma deterministica
        return true;
    }
}

Contratos canonicos como redutores de acoplamento

Quando varios sistemas trocam dados com semanticas proximas, um modelo canonico reduz CoM e CoN porque explicita linguagem ubíqua e regras de transformação em pontos conhecidos. Esse arranjo costuma funcionar melhor quando combinado com mapeadores dedicados e testes de contrato automatizados (EVANS, 2003).

Estrategias Praticas para Times .NET

1. Medir connascence nas revisoes tecnicas

Durante code review, questione: esta mudanca adiciona dependencia de nome, ordem, tipo ou tempo entre modulos distantes? Se sim, reavalie o desenho antes de escalar para producao.

2. Localizar connascence forte dentro do mesmo modulo

Connascence forte e menos danosa quando confinada ao mesmo componente, pois a mudanca coordenada ocorre no mesmo ciclo de deploy. Esse principio alinha com a recomendacao de aumentar coesao e reduzir acoplamento transversal (MARTIN, 2017).

3. Automatizar verificacoes de contrato

Em pipelines .NET, testes de serializacao e compatibilidade entre versoes previnem regressao silenciosa:

public sealed class ContractCompatibilityTests
{
    [Fact]
    public void V2_Should_Deserialize_V1_Payload()
    {
        var v1Json = """
        {
          "Id": "7a6a16de-31c0-4770-9413-6f6cefcf7a3a",
          "TotalAmount": 125.50
        }
        """;

        var dto = JsonSerializer.Deserialize<Contracts.V2.OrderDto>(v1Json);

        Assert.NotNull(dto);
        Assert.Equal(125.50m, dto!.TotalAmount);
        Assert.Null(dto.Currency);
    }
}

4. Reduzir connascence de algoritmo com servicos unicos

Quando a mesma regra aparece em varios pontos, centralize em um unico servico de dominio para evitar CoA distribuida e divergencia semantica entre times.

Conclusao

Connascence oferece uma lente pragmatica para evoluir sistemas .NET com menos regressao e mais previsibilidade. Ao identificar dependencias por nome, tipo, significado, tempo e algoritmo, equipes tecnicas tomam decisoes de design com base em risco real de manutencao, nao apenas em preferencia estilistica.

Em cenarios corporativos, combinar contratos canonicos, versionamento aditivo, idempotencia e testes de compatibilidade transforma o acoplamento de um problema oculto em um ativo gerenciavel. O resultado e uma arquitetura mais resiliente, capaz de crescer sem sacrificar autonomia dos times nem estabilidade de integracoes existentes.

Referências

  • PAGE-JONES, Meilir. The practical guide to structured systems design. 2. ed. Englewood Cliffs: Yourdon Press, 1992. reference.Description
  • EVANS, Eric. Domain-driven design: tackling complexity in the heart of software. Boston: Addison-Wesley, 2003. reference.Description
  • FOWLER, Martin. Patterns of enterprise application architecture. Boston: Addison-Wesley, 2002. reference.Description
  • NEWMAN, Sam. Building microservices: designing fine-grained systems. 2. ed. Sebastopol: O'Reilly Media, 2021. reference.Description
  • VERNON, Vaughn. Implementing domain-driven design. Boston: Addison-Wesley, 2013. reference.Description
  • MARTIN, Robert C. Clean architecture: a craftsman's guide to software structure and design. Boston: Pearson, 2017. reference.Description
Sobre o autor