---
title: "O atalho de chamar métodos públicos entre si e o colapso dos invariantes"
author: "Pedro Dalben"
date: "2026-11-02T11:04:01Z"
category: "Arquitetura & CTO"
reading_time: "6 min"
canonical: "https://pedrodalben.com.br/blog/o-atalho-de-chamar-metodos-publicos-entre-si-e-o-colapso-dos-invariantes"
---

# O atalho de chamar métodos públicos entre si e o colapso dos invariantes

> Permitir que métodos públicos chamem uns aos outros quebra garantias de transação, polui rastreamentos e corrompe os invariantes da classe.

**Autor:** Pedro Dalben (CTO no Integrar Plus)  
**Publicado em:** 02 de November de 2026  
**URL Canônica Oficial:** [https://pedrodalben.com.br/blog/o-atalho-de-chamar-metodos-publicos-entre-si-e-o-colapso-dos-invariantes](https://pedrodalben.com.br/blog/o-atalho-de-chamar-metodos-publicos-entre-si-e-o-colapso-dos-invariantes)  

---


Toda vez que vejo um método público invocando outro método público dentro do mesmo objeto de serviço ou modelo de domínio, sei que a depuração daquele módulo vai custar caro. O sintoma inicial parece inofensivo. Um desenvolvedor precisa executar uma rotina completa de fechamento financeiro, percebe que já existe um método público para conciliar uma fatura e outro para emitir o recibo, e simplesmente escreve o terceiro chamando os dois primeiros em sequência. Parece reaproveitamento elegante de código. Na prática, você acabou de implodir a barreira de entrada da sua classe.

A discussão técnica recente em torno do princípio de evitar funções públicas chamando outras funções públicas expôs uma divisão clara entre os desenvolvedores. De um lado, defensores de APIs em camadas sustentam que métodos de alto nível devem funcionar como atalhos de conveniência sobre métodos primitivos também públicos. O argumento é que expor os dois níveis documenta o uso esperado da biblioteca e dá flexibilidade a quem precisa compor chamadas customizadas. Do outro lado, engenheiros de compiladores e sistemas notam que quando uma função pública chama outra, os limites operacionais somem. O rastreamento de pilha perde o ponto exato de origem da intenção do usuário, métricas de telemetria disparam duas vezes e o estado intermediário do objeto fica desprotegido.

Eu discordo frontalmente da visão permissiva das camadas abertas no mesmo componente. No desenvolvimento de sistemas web com persistência transacional em PostgreSQL e regras de negócio densas, a tese da conveniência desaba no primeiro incidente de concorrência.

### O falso atalho da conveniência

A ideia de que uma classe pode oferecer operações atômicas públicas e operações compostas públicas chamando as primeiras ignora a responsabilidade de manter invariantes. Quando uma requisição atinge um método público, ela atravessa uma fronteira de confiança. Naquele instante exato, o sistema espera validar premissas: autenticar a transação, verificar o estado atual do registro, abrir um bloco de banco de dados e registrar a auditoria.

Se esse método chama outro método público internamente, ocorrem anomalias graves:

* Transações aninhadas desnecessárias ou pontos de salvamento artificiais que degradam a performance do banco.
* Duplicação de validações ou, pior, a suposição errônea de que a segunda operação não precisa checar nada porque a primeira já checou.
* Poluição no rastreamento de eventos e logs, onde uma única ação do usuário parece ter gerado múltiplos comandos independentes.
* Testes unitários viciados em dublês, nos quais o desenvolvedor começa a verificar se o próprio objeto chamou a si mesmo com mocks internos.

Quando você chega ao ponto de usar um dublê de teste para espionar se o método A chamou o método B do mesmo objeto, o design da sua classe faliu. Esse padrão de teste não mede comportamento externo nem protege contra regressões. Ele apenas congela a estrutura interna e impede qualquer refatoração futura.

### A degradação silenciosa da interface pública

Existe um argumento comum de que o problema real não é a chamada entre métodos públicos, mas sim o hábito de adulterar a assinatura de um método existente para atender ao novo atalho. Há quem diga que bastaria disciplina para não degradar a API pública.

Essa postura me parece ingênua sobre como bases de código reais envelhecem. Em um time sob pressão de prazos, a disciplina evapora na primeira exceção de regra de negócio. Veja um exemplo clássico em Ruby:

```ruby
class SubscriptionManager
  def activate(account)
    validate_billing!(account)
    account.update!(status: :active)
    notify_user(account)
  end

  def reactivate(account)
    # Atalho perigoso: chamando metodo publico com um parametro improvisado
    activate(account)
    reset_grace_period(account)
  end
end
```

Em pouco tempo, alguém percebe que `reactivate` não deveria enviar o e-mail padrão disparado por `notify_user` dentro de `activate`. Como `activate` é público e já é usado em controladores por toda a aplicação, o desenvolvedor raramente quebra a assinatura para extrair a lógica. Em vez disso, ele adiciona um parâmetro opcional: `def activate(account, skip_notification: false)`. 

A partir daí, a interface pública virou refém de um detalhe interno. Uma flag booleana foi colocada na porta da frente da classe apenas para atender a uma chamada que veio dos fundos da própria casa. O método primitivo perdeu a coesão semântica e ganhou complexidade acidental.

### A solução estrutural com núcleos privados

A saída para esse impasse não exige abstrações complexas nem dezenas de classes intermediárias. A regra é simples: métodos públicos compõem o fluxo de entrada; a execução real pertence a rotinas privadas que expressam intenções atômicas.

Se duas operações públicas compartilham etapas, ambas devem delegar para métodos privados focados, nunca uma depender da outra diretamente.

```ruby
class SubscriptionManager
  def activate(account)
    ApplicationRecord.transaction do
      validate_billing!(account)
      execute_activation(account)
      send_activation_notice(account)
    end
  end

  def reactivate(account)
    ApplicationRecord.transaction do
      validate_billing!(account)
      execute_activation(account)
      reset_grace_period(account)
      send_reactivation_notice(account)
    end
  end

  private

  def execute_activation(account)
    account.update!(status: :active)
  end

  def validate_billing!(account)
    raise InvalidStateError unless account.payment_method_valid?
  end

  def send_activation_notice(account)
    # despacho de evento assincrono
  end

  def send_reactivation_notice(account)
    # despacho de evento assincrono
  end

  def reset_grace_period(account)
    account.update!(grace_period_ends_at: nil)
  end
end
```

Observe a diferença de postura. Nenhuma das rotinas públicas precisa saber que a outra existe. Se amanhã a reativação exigir um recálculo de cobrança antes da ativação, eu altero o corpo de `reactivate` sem tocar em uma linha sequer de `activate`. Os invariantes de cada ponto de entrada permanecem intactos.

Há quem questione se essa abordagem não gera repetição de código. Ela gera uma pequena duplicação de chamadas orquestradoras, o que é muito diferente de duplicar lógica de negócio. A lógica de alteração de estado reside nos métodos privados. A sequência em que esses métodos são convocados é a definição explícita do caso de uso.

### Casos de uso versus primitivas

Há uma ressalva legítima quando pensamos em bibliotecas de baixo nível, como clientes de rede ou analisadores de protocolo. Nesses cenários, separar uma API em camadas onde módulos utilitários de alto nível encapsulam chamadas a primitivas expostas faz sentido. Mas essa relação deve existir entre objetos ou módulos diferentes, nunca dentro do mesmo escopo fechado.

Se você realmente precisa de um método facilitador que agregue várias operações públicas, construa um coordenador separado. Não faça a classe canônica agir como seu próprio orquestrador informal.

Manter a superfície pública estrita evita a tentação de contornar validações e protege a previsibilidade do seu software em produção. Quando cada método público é uma barreira intransponível e definitiva para o mundo externo, rastrear falhas deixa de ser um exercício de adivinhação.

## Fontes

- [https://matklad.github.io/2026/10/29/pub-calls-pub.html](https://matklad.github.io/2026/10/29/pub-calls-pub.html)
