Engenharia

"Está funcionando?" Tem uma resposta diferente em cada camada da stack

Uma feature pode ser verdadeira no banco de dados, verdadeira na API, e uma mentira na tela, responda por camada.

ASR

Apollo Space Research

Apollo Space

· 10 min de leitura

Alguém nos faz uma pergunta de quatro palavras que parece que deveria ter uma resposta de quatro palavras: “A feature está funcionando?” Nós abrimos o banco de dados, rodamos uma query, e lá está, a linha existe, o dado está formatado exatamente certo, o relacionamento com o usuário está correto. Quase dizemos sim. Aí abrimos o produto de verdade do jeito que um cliente abriria, clicamos até onde aquela feature deveria viver, e não encontramos nada. Nenhum botão. Nenhuma tela. A coisa é inconfundivelmente real uma camada abaixo e inconfundivelmente ausente onde um humano a alcançaria.

Ambas as observações são verdadeiras ao mesmo tempo. Essa contradição é todo o assunto deste post.

Uma feature pode ser verdadeira no banco de dados, verdadeira na API, e uma mentira na tela. A resposta honesta para “está funcionando” nunca é uma palavra, é uma resposta por camada.

Aprendemos isso do jeito que a maioria das lições desconfortáveis se aprende: dizendo sim com confiança e estando errados na frente da pessoa que perguntou.

A pergunta de quatro palavras com uma armadilha de quatro palavras

A pergunta parece binária porque a maioria das perguntas no resto da vida é. A luz está acesa? A porta está trancada? Sim ou não, um lugar para olhar.

Software não é um lugar. Uma única feature, digamos, “um usuário pode criar um agent”, não é uma coisa. É uma pilha de coisas que cada uma tem de ser verdadeira, sentadas umas sobre as outras: um requisito de negócio, uma regra de backend que o impõe, uma rota de API que o expõe, uma tabela de banco de dados que o armazena, a lógica que faz com que ele se comporte, os testes que provam o comportamento, e finalmente a tela onde um humano de fato o faz. Sete andares, mais ou menos. “Está funcionando?” é na verdade sete perguntas usando uma capa de chuva.

Aqui está a armadilha. Qualquer um desses andares pode estar sólido enquanto o andar acima dele está faltando, e de dentro daquele andar tudo parece pronto. Você pode estar de pé no banco de dados, ver o dado, e ter toda razão para acreditar que o prédio está pronto, enquanto a porta da frente ainda não existe. A vista de cada camada é honesta e incompleta exatamente no mesmo fôlego.

Então a resposta ingênua, checar a camada em que você por acaso está de pé e reportar isso como a resposta para a coisa inteira, não é preguiça. É o erro mais natural do ofício. Você olhou. Você viu verdade. Você reportou verdade. Você ainda estava errado, porque a pergunta não era sobre o seu andar.

A versão ingênua: cheque a camada que você consegue ver

Vamos encenar a versão burra, porque já a entregamos, e a dor sentida é todo o ponto.

Você constrói uma feature de trás para frente, do jeito que a maioria das features é construída. O modelo de dados entra primeiro, é a fundação, é satisfatório, você consegue ver linhas aparecerem. Você escreve a regra que o governa. Adiciona a rota. A cada passo você verifica o passo: a migração rodou, a rota retorna o formato certo, um script consegue criar a coisa. Cada check está verde. Cada check é real.

Aí alguém pergunta se está funcionando, e você responde de onde tem morado, lá embaixo no dado, onde tudo é comprovadamente verdadeiro. Sim, funciona. Você consegue criar a coisa. Você acabou de fazer isso, duas vezes, de um script.

O que você não notou é que “de um script” está fazendo um enorme trabalho load-bearing naquela frase. Você criou a coisa alcançando diretamente um andar em que nenhum cliente consegue ficar de pé. O caminho que uma pessoa real tomaria, abrir o app, achar a tela, clicar no botão, nunca foi construído, ou foi construído e nunca ligado ao andar abaixo dele. A feature está genuinamente, comprovadamente completa em todo lugar exceto no único lugar que um humano consegue alcançar.

Uma feature que você só consegue disparar do banco de dados é uma feature que nenhum cliente tem.

Essa lacuna não se anuncia. Ela se esconde dentro da palavra “funciona”, que silenciosamente significa algo diferente em cada andar. Funciona no banco de dados significa que o dado está correto. Funciona na API significa que a rota responde. Funciona na tela significa que uma pessoa, que não sabe nada sobre seu modelo de dados, consegue sentar e fazer a coisa. Essas são três alegações diferentes, e o custo de tratá-las como uma é que você diz a alguém sim e ela vai olhar e não há nada lá.

Duas formas de responder "está funcionando". À esquerda, um único check verde na camada de banco de dados é reportado como um sim de stack-inteira, enquanto a camada de tela acima dele está silenciosamente vazia. À direita, cada camada carrega seu próprio veredito e a tela faltante torna a resposta geral um não.

A falha não é que as camadas inferiores mentiram. Elas disseram a verdade sobre si mesmas. A falha é a extrapolação, pegar um veredito verdadeiro de um andar e carimbá-lo na stack inteira.

Por que “passa nos testes” é sua própria versão dessa armadilha

Há uma correção tentadora que parece rigorosa e não é suficiente: apoiar-se nos testes. Se os testes estão verdes, certamente a feature funciona.

Esta é a mesma armadilha com roupas melhores. Um teste, como uma query de banco de dados, vive num andar específico. Um teste unitário prova que uma função faz o que a função foi escrita para fazer. Um teste de integração prova que dois componentes concordam na sua costura. Ambos podem ser impecáveis enquanto a tela que um cliente usa não existe, porque os testes, como o script, alcançam as camadas abaixo do humano, não através da porta por onde o humano caminha. Testes verdes escritos abaixo do front end te dizem que o encanamento é sólido. Eles não te dizem que o prédio é habitável.

Isso acontece com todo time tocando uma frota rápida de construtores, humanos ou agents, e acontece precisamente porque todo mundo é diligente. Diligência na camada em que você está produz um verde confiante que não generaliza para cima. Quanto mais minucioso você é dentro de um andar, mais convincente o “pronto” daquele andar parece, e mais fácil é esquecer que há um andar acima dele que ninguém caminhou.

A disciplina que mata isso é quase insultantemente simples, e vamos enunciá-la o mais claramente que pudermos: o único veredito que conta para a feature inteira é o tomado do andar de cima. Um humano, ou um agent fazendo as vezes de um, abre o produto deployado, toma o caminho que um cliente tomaria, e a feature se comporta. Essa é a resposta. Tudo abaixo dela é necessário, todo check verde importa, e nenhum deles tem direito de falar pela camada acima. Você verifica cada andar nos seus próprios termos, e deixa a porta da frente dar o voto de minerva.

Responda por camada, em voz alta, toda vez

Então quando alguém nos pergunta “está funcionando” agora, nos treinamos para fora da resposta de uma palavra. A resposta honesta caminha a stack, andar por andar, e diz o que é verdadeiro e o que não é em cada um.

O requisito está claro: sim. A regra de backend o impõe: sim. A rota o expõe: sim. O dado o armazena corretamente: sim. O comportamento está testado: sim. E a tela que um cliente usa para fazê-lo: ainda não, o que significa, para a única pergunta que de fato importa a um cliente, que a resposta é não. Seis sins e um ainda-não ainda somam “uma pessoa não consegue fazer isto”, porque os andares são empilhados, não tirada a média. Uma corrente não é tão forte quanto seu elo médio.

Uma feature pode ser verdadeira no banco de dados, verdadeira na API, e uma mentira na tela. Dito do jeito longo: a verdade de uma feature não é um único valor, é uma coluna de valores, e o cliente só experimenta o topo da coluna. Tudo por baixo é como você chegou lá. Nada disso é a chegada.

Uma feature traçada como uma pilha vertical de camadas, requisito, backend, rota, dado, testes, comportamento, tela, cada uma carregando seu próprio veredito de aprovado ou pendente, com uma regra de que o cliente só experimenta a camada mais ao topo, então o veredito mais ao topo é a resposta real.

O que isso compra é o fim de uma mentira específica e recorrente, o sim alegre que manda alguém para uma tela que não está lá. O que isso custa é o conforto de uma resposta curta. Você não pode mais dizer “pronto” até ter ficado de pé no andar de cima e caminhado pela porta você mesmo. Essa é uma régua mais alta, e é mais lenta, e é a única régua que bate com o que a palavra “funcionando” significa para a única pessoa que conta.

“Pronto” é um veredito que você ganha na porta da frente, não uma soma de checks verdes atrás dela.

É por isso que, quando construímos com uma frota de agents que se movem rápido, “está funcionando?” nunca é respondido por extrapolação da camada que um construtor por acaso verificou. A vertical é caminhada, de cima a baixo, e cada andar reporta por si. Um agent que cria uma linha e reporta a feature como entregue fez trabalho de verdade e cometeu o erro mais antigo do ofício: respondeu por um andar em que não estava de pé.

A virada: a pergunta é na verdade “uma pessoa já consegue fazer isto?”

Queremos terminar no humano debaixo da stack, porque é disso que toda camada finalmente trata.

Quando a pessoa perguntando “está funcionando?” imagina a resposta, ela não está imaginando uma linha numa tabela ou um ponto verde num test runner. Ela está se imaginando, ou um cliente, ou um colega que está tendo uma semana difícil, sentado na frente do produto e tentando fazer algo. Essa imagem é a especificação real. O banco de dados, a rota, os testes: tudo isso existe para entregar àquela pessoa uma tela que faz o que ela veio fazer. Quando respondemos do banco de dados, silenciosamente trocamos a pergunta dela por uma mais fácil que conseguimos vencer. A versão honesta recusa a troca. Ela mantém o humano no topo da stack em quadro e reporta contra a experiência dele, mesmo quando isso transforma nossos satisfatórios seis-sins num não.

Há um tipo de respeito nessa recusa. Ela diz: não vamos te dizer que uma coisa é sua até você de fato conseguir alcançá-la. A maior parte da disciplina na boa engenharia é alguma versão dessa promessa, não confundir o trabalho que você consegue ver com o desfecho pelo qual outra pessoa está esperando. As camadas são como o sistema é construído. A pessoa no topo é para quem ele é construído, e ela não experimenta nenhuma camada além da última.

Uma feature pode ser verdadeira no banco de dados, verdadeira na API, e uma mentira na tela. O que só é um problema se você esquecer quem a verdade deveria alcançar.


Esse é o padrão que mantemos na Apollo Space, uma feature não está funcionando até alguém conseguir fazer a coisa pela porta da frente, e “sim” é uma frase que você ganha uma camada de cada vez. Se você já foi avisado de que algo estava pronto e então encarou uma tela que não o tinha, você já sabe qual camada estava dizendo a verdade, e qual estava te dizendo a resposta.

A Apollo cuida da operação repetitiva da sua empresa pro seu time não precisar.

Entre na lista de espera: acesso antecipado, preço de usuário fundador e um lugar na primeira fila enquanto a gente constrói.

Entrar na lista de espera