Introdução
O Hollywood Principle é um princípio de design de software resumido na frase "Don't call us, we'll call you" — não nos chame, nós chamaremos você. É a mesma frase clássica usada por produtores em Hollywood para dispensar atores em audições sem se comprometer a retornar contato.
Em código tradicional, o seu programa controla o fluxo: ele chama bibliotecas, decide a ordem das operações e "puxa" o que precisa. No Hollywood Principle isso se inverte — um componente de nível mais alto (um framework, por exemplo) mantém o controle do fluxo, e é ele quem chama o seu código, no momento que julgar apropriado, e não o contrário.
Por isso o princípio é praticamente sinônimo de Inversão de Controle (IoC): você não chama o framework, o framework chama você.
Biblioteca vs. framework
Essa é a forma mais prática de sentir o princípio no dia a dia:
-
Biblioteca: você importa, você chama os métodos, você está no comando. Ex.: usar
Math.Sqrt()ou uma lib de parsing de JSON. -
Framework: ele define a estrutura da aplicação, e o seu código só "encaixa" nos pontos que ele espera. Ex.: você escreve um método
OnClick()e o WinForms decide quando chamá-lo; você escreve uma classeControllerno ASP.NET Core e o runtime decide quando instanciá-la e invocar seus métodos.
Resumindo em uma frase: não chame o framework, o framework chama você.
Exemplos em C
1. Loop manual vs. evento
// Fluxo tradicional: você fica perguntando, você está no comando
while (true)
{
var evento = filaDeEventos.PegarProximo(); // você decide quando pegar
if (evento.Tipo == TipoEvento.Clique)
{
TratarClique(evento); // você chama sua própria função
}
}
// Hollywood principle: você registra e espera ser chamado
void TratarClique(object sender, EventArgs e)
{
Console.WriteLine("botão clicado!");
}
botao.Click += TratarClique; // "não me chame, eu te chamo"
Application.Run(formulario); // o framework entra em loop e chama
// TratarClique quando o clique acontecer
No primeiro caso, TratarClique aparece no seu código sendo chamada por você. No segundo, ela nunca é chamada por você em lugar nenhum — só é passada como referência (um delegate). Quem decide quando ela roda é o Application.
2. OrderBy com seletor: um mini-Hollywood dentro do LINQ
int Prioridade(Pessoa p) => p.Idade;
var pessoasOrdenadas = pessoas.OrderBy(Prioridade);
Você nunca escreve Prioridade(pessoas[0]), Prioridade(pessoas[1])... Quem chama Prioridade, quantas vezes e em que ordem, é o algoritmo de ordenação dentro do OrderBy. Isso já é o princípio agindo, mesmo dentro de um método LINQ comum.
3. xUnit (framework de testes)
public class CalculadoraTests
{
[Fact]
public void Soma_DeveRetornarQuatro()
{
Assert.Equal(4, 2 + 2);
}
[Fact]
public void Subtracao_DeveRetornarDois()
{
Assert.Equal(2, 5 - 3);
}
}
Você roda dotnet test — nunca chama Soma_DeveRetornarQuatro() você mesmo. É o xUnit que varre a classe por reflection, encontra métodos marcados com [Fact] e os chama um por um, decidindo ordem, capturando falhas, etc.
Compare com uma versão "biblioteca", onde você está no controle:
void RodarTestes()
{
TestarSoma();
TestarSubtracao();
Console.WriteLine("tudo passou!");
}
RodarTestes(); // você chama, você decide a ordem
4. Template Method: o princípio dentro de uma única classe
public abstract class Relatorio
{
public string Gerar() // o "molde" — fica no controle
{
var dados = BuscarDados(); // chama método que a subclasse define
return Formatar(dados);
}
protected abstract List<int> BuscarDados();
protected abstract string Formatar(List<int> dados);
}
public class RelatorioVendas : Relatorio
{
protected override List<int> BuscarDados() => new() { 100, 200, 150 };
protected override string Formatar(List<int> dados) => $"Total: {dados.Sum()}";
}
new RelatorioVendas().Gerar();
BuscarDados e Formatar são definidos na subclasse, mas quem os chama é o método Gerar lá na classe base. A subclasse nunca se auto-chama — ela só fornece as peças que a classe base vai encaixar quando quiser.
5. Socket cru vs. ASP.NET Core
// Baixo nível: você escreve o loop, você está no controle
var servidor = new TcpListener(IPAddress.Any, 8080);
servidor.Start();
while (true)
{
var cliente = servidor.AcceptTcpClient(); // você chama AcceptTcpClient
var stream = cliente.GetStream();
var buffer = new byte[1024];
stream.Read(buffer, 0, buffer.Length); // você chama Read
TratarRequisicao(buffer); // você chama sua própria função
}
// Framework: ASP.NET Core está no controle
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/ola", () => "Olá, mundo!");
app.Run();
A lambda passada a MapGet nunca é chamada em nenhuma linha que você escreveu. O ASP.NET Core recebe a requisição HTTP e decide chamar esse handler quando a rota /ola é acessada.
6. Injeção de dependência: o Hollywood Principle institucionalizado
public class PedidoService
{
private readonly IPedidoRepository _repositorio;
public PedidoService(IPedidoRepository repositorio) // você não faz "new PedidoRepository()"
{
_repositorio = repositorio; // o container injeta a implementação
}
}
builder.Services.AddScoped<IPedidoRepository, PedidoRepository>();
Você nunca escreve new PedidoService(new PedidoRepository()). O container de DI do ASP.NET Core resolve as dependências e chama o construtor de PedidoService por você, no momento em que a classe é necessária.
O padrão nos seis exemplos
| Situação | Quem chama quem |
|---|---|
| loop manual | você chama TratarClique
|
evento (botao.Click += ...) |
o framework/runtime chama TratarClique
|
OrderBy(lista) sem seletor |
não há callback |
OrderBy(lista, p => p.Idade) |
OrderBy chama o seletor |
RodarTestes() manual |
você chama TestarSoma
|
xUnit ([Fact]) |
o test runner chama o método de teste |
| classe abstrata chamando método virtual | a classe base chama, a subclasse implementa |
TcpListener cru |
você chama AcceptTcpClient/Read
|
ASP.NET Core (MapGet) |
o framework chama o handler |
| container de DI | o container chama o construtor |
Repare que isso aparece muito mais em OOP (polimorfismo, herança, interfaces) do que em programação estruturada pura — é por isso que frameworks orientados a objetos (ASP.NET Core, Spring, Angular, React) são o habitat natural do Hollywood Principle: eles dependem de você implementar um "contrato" (uma interface, uma classe abstrata, um delegate com assinatura esperada) para poderem chamá-lo de volta.
Relação com SOLID
O Hollywood Principle é primo próximo do Dependency Inversion Principle (o "D" do SOLID): módulos de alto nível não devem depender de módulos de baixo nível — ambos devem depender de abstrações. A ideia de "inverter" quem depende de quem é a mesma raiz conceitual por trás dos dois.
Vantagens e custos
Vantagem: baixo acoplamento — seu código não precisa saber os detalhes de quando ou como é chamado, só precisa implementar o contrato esperado (uma interface, um delegate, um método abstrato).
Custo: o fluxo de controle fica menos explícito. Ao ler o código isoladamente, não é óbvio quando uma função vai ser executada — isso pode dificultar o debugging, já que você precisa entender o framework para saber a ordem das chamadas. Esse "fluxo invertido" costuma ser citado como uma das razões pelas quais frameworks têm curva de aprendizado maior que bibliotecas.
Top comments (0)