status:pre-alpha
version:v0.1.0
devstation engineering

Projetado para extensibilidade: as decisões técnicas do DevStation

Hexagonal, DDD tático, CQRS, eventos internos e contratos JSON-RPC. Por que um conjunto que pode soar como overengineering virou a aposta central — e o que a evidência sobre IA e código complexo tem a dizer sobre isso.

28 de jun. de 2026 André Spineli
EN

Um CLI que toca infraestrutura real acumula responsabilidades depressa. O DevStation modela clusters, nodes, VMs, images, sizes, vault, provisionamento, stations e blueprints — e cada um desses carrega regras próprias. A lista de features que cabem num projeto assim é, na prática, ilimitada. Por isso a pergunta que orientou o design não foi “como entregar a feature de hoje”, e sim “como acomodar a próxima sem comprometer o que já existe”. O fio condutor é a extensibilidade.

Hexagonal: o domínio isolado do mundo

A arquitetura hexagonal — ports & adapters, proposta por Alistair Cockburn em 2005 — existe justamente para isolar a lógica de negócio da infraestrutura e permitir testá-la de forma independente. No DevStation, Proxmox, a TUI, o sistema de arquivos e o OpenTofu vivem na borda; o núcleo os enxerga apenas como ports. Testes de arquitetura validam essa fronteira a cada commit: o domínio não importa infraestrutura, e o lado de entrada nunca importa o de saída. O efeito prático é direto — adicionar um provider ou trocar a interface não toca a regra de negócio.

O desenho segue a Explicit Architecture, de Herberto Graça: um App Core — Domain envolvido pela Application — com os ports como fronteira e todas as dependências apontando para dentro. A nomenclatura aqui é inbound (driving) e outbound (driven), no lugar de primário/secundário.

DDD tático + CQRS: contextos pequenos que crescem sem fricção

Os recursos são organizados em bounded contexts isolados — cluster, vault, station, service, images, size, blueprint, auth — cada um com seus agregados, comandos e eventos. Leitura e escrita são separadas seguindo CQRS. Como Martin Fowler descreve o padrão, trata-se de usar modelos distintos para ler e para escrever; convém a precisão de que CQRS não exige banco separado nem event sourcing. Aqui é CQRS de store único, em que as queries projetam registros direto, sem passar pelos agregados.

O retorno aparece na manutenção. Extrair images para um contexto próprio foi replicar um padrão, não inventar um. Renomear definition para size no stack inteiro foi mecânico porque a fronteira era explícita. E renomear deploy → install e destroy → uninstall de ponta a ponta — contrato, domínio, eventos, persistência e UI — permaneceu uma operação disciplinada, precisamente porque cada contexto sabe o que é seu.

Eventos internos entre contextos

O DevStation é um binário único, não um sistema distribuído. Ainda assim, os contextos se integram por eventos de domínio: uma policy reage a um evento de outro contexto e dispara um comando do próprio. O context map do projeto registra isso como regra — a comunicação cross-context não é direta. Quando uma station conclui uma instalação, o contexto de cluster registra a projeção dos serviços na VM e o vault guarda os secrets publicados, ambos por policy, sem acoplamento direto entre os contextos.

Num binário único, isso pode soar exagerado. A justificativa é de prazo: separar os contextos desde o início, com comunicação eventual, mantém a porta aberta para extrair um backend no futuro — um serviço compartilhado, um PaaS — sem reescrever regra. É barato fazer agora e caro fazer depois.

Contratos JSON-RPC: a interface é destacável

O engine expõe uma fronteira JSON-RPC sobre stdio, e os contratos (OpenRPC, com código gerado a partir deles) são o limite de verdade. A migração para essa fronteira foi deliberadamente incremental: um único contexto primeiro, sem caminho duplo, com revisão formal antes de expandir aos demais — porque erros de modelagem de envelope e de contrato são caros de reverter depois de espalhados. O resultado é que a TUI em React Ink é apenas um cliente. Outra TUI, um app desktop ou até uma web são, do ponto de vista do engine, o mesmo contrato com outra tela. O contrato é o que importa; a interface é detalhe.

Complexidade, IA e o papel do harness

Vale reconhecer o trade-off: estrutura tem custo. Há evidências de que os ganhos de IA diminuem em projetos maduros que o time já domina e de que modelos perdem eficácia em bases muito grandes, com muitos arquivos e dependências cruzadas. Esse custo é real e foi considerado.

O que altera o resultado é a forma como a estrutura chega ao agente. O gargalo que esses cenários descrevem — ausência de estrutura, contexto espalhado, padrões implícitos — é exatamente o que um bom harness resolve: regras sempre carregadas, skills sob demanda e fronteiras explícitas que o agente segue por construção. Estrutura clara não atrapalha a IA; orienta. Com isso, o custo de manter a disciplina cai, e a complexidade do conjunto de práticas deixa de ser um peso para virar alavanca — é ela que permite adicionar um contexto, um provider ou uma UI com segurança.

Extensibilidade, no DevStation, não é enfeite de arquitetura. É a decisão que torna tudo o que vem depois mais barato — e por isso veio primeiro.

Referências