{"id":1073,"date":"2026-09-07T08:00:00","date_gmt":"2026-09-07T11:00:00","guid":{"rendered":"https:\/\/adrianosantostreina.com.br\/blog\/?p=1073"},"modified":"2026-08-13T14:26:53","modified_gmt":"2026-08-13T17:26:53","slug":"spec-driven-development-o-que-e-por-que-adotar","status":"publish","type":"post","link":"https:\/\/adrianosantostreina.com.br\/blog\/spec-driven-development-o-que-e-por-que-adotar\/","title":{"rendered":"Spec Driven Development: o que \u00e9 e por que adotar quando a IA escreve c\u00f3digo com voc\u00ea"},"content":{"rendered":"<p>Voc\u00ea j\u00e1 recebeu uma tarefa assim: &#8220;implementa um sistema de notifica\u00e7\u00f5es para os usu\u00e1rios&#8221;? Voc\u00ea abre o editor, come\u00e7a a codar, cria uma tabela, um servi\u00e7o, um endpoint. Dois dias depois, em uma reuni\u00e3o de revis\u00e3o, descobre que o time de produto queria notifica\u00e7\u00f5es por e-mail e push, com prefer\u00eancias configur\u00e1veis por usu\u00e1rio, rate limiting e um hist\u00f3rico de auditoria. Nada disso estava na frase original. Voc\u00ea reescreve metade do c\u00f3digo, refaz a modelagem do banco e perde uma semana inteira revisando decis\u00f5es que poderiam ter sido esclarecidas antes de a primeira linha de c\u00f3digo existir.<\/p>\n<p>Esse cen\u00e1rio se repete em praticamente toda equipe de desenvolvimento, independentemente da linguagem ou do dom\u00ednio. E ele se agrava quando voc\u00ea passa a delegar parte da implementa\u00e7\u00e3o para ferramentas de IA generativa. Um agente como o Claude Code ou o Cursor n\u00e3o tem contexto sobre as regras de neg\u00f3cio da sua empresa, sobre decis\u00f5es de arquitetura tomadas h\u00e1 dois anos ou sobre o que &#8220;sistema de notifica\u00e7\u00f5es&#8221; realmente significa para o seu time. Ele preenche as lacunas com suposi\u00e7\u00f5es \u2014 e suposi\u00e7\u00f5es erradas em escala geram retrabalho em escala.<\/p>\n<h2>O que \u00e9 Spec Driven Development<\/h2>\n<p>Spec Driven Development (Desenvolvimento Orientado por Especifica\u00e7\u00e3o, ou SDD) \u00e9 uma abordagem em que a especifica\u00e7\u00e3o \u2014 um documento estruturado descrevendo o que o software deve fazer, suas restri\u00e7\u00f5es, casos de borda e crit\u00e9rios de aceita\u00e7\u00e3o \u2014 \u00e9 escrita e validada <strong>antes<\/strong> da implementa\u00e7\u00e3o, e passa a ser o artefato central do processo, n\u00e3o um anexo esquecido em uma pasta do Confluence.<\/p>\n<p>A ideia n\u00e3o \u00e9 nova. Ela tem ra\u00edzes em pr\u00e1ticas como Design by Contract, proposto por Bertrand Meyer na linguagem Eiffel, e em m\u00e9todos formais de especifica\u00e7\u00e3o usados em sistemas cr\u00edticos (avia\u00e7\u00e3o, sa\u00fade, sistemas financeiros). O que mudou \u00e9 o contexto: com agentes de IA gerando c\u00f3digo em minutos, a especifica\u00e7\u00e3o deixou de ser burocracia e passou a ser a \u00fanica forma confi\u00e1vel de guiar o que a IA produz.<\/p>\n<blockquote><p><strong>\ud83d\udca1 Dica do Mestre:<\/strong> Bertrand Meyer definiu o Design by Contract nos anos 1980 como forma de tornar expl\u00edcitas as pr\u00e9-condi\u00e7\u00f5es, p\u00f3s-condi\u00e7\u00f5es e invariantes de cada componente de software \u2014 a ideia central do SDD moderno j\u00e1 estava l\u00e1. Veja mais em <a href=\"https:\/\/www.eiffel.org\/doc\/eiffel\/Design_by_Contract_and_Assertions\" target=\"_blank\">eiffel.org<\/a>.<\/p><\/blockquote>\n<h3>Spec Driven Development n\u00e3o \u00e9 documenta\u00e7\u00e3o tradicional<\/h3>\n<p>\u00c9 importante diferenciar SDD de documenta\u00e7\u00e3o de requisitos tradicional. Documentos de requisitos costumam ser escritos uma vez, aprovados em comit\u00ea e esquecidos assim que a implementa\u00e7\u00e3o come\u00e7a. No SDD, a especifica\u00e7\u00e3o \u00e9:<\/p>\n<ul>\n<li><strong>Viva<\/strong>: evolui junto com o entendimento do problema, n\u00e3o \u00e9 um artefato congelado.<\/li>\n<li><strong>Execut\u00e1vel ou verific\u00e1vel<\/strong>: idealmente, voc\u00ea consegue derivar testes automatizados diretamente dela.<\/li>\n<li><strong>Precisa o suficiente para eliminar ambiguidade<\/strong>, mas sem descrever a implementa\u00e7\u00e3o t\u00e9cnica linha a linha.<\/li>\n<li><strong>Usada como prompt estruturado<\/strong> quando voc\u00ea trabalha com IA generativa \u2014 \u00e9 o contrato entre voc\u00ea e o agente.<\/li>\n<\/ul>\n<h2>Por que o SDD se tornou relevante agora<\/h2>\n<p>Antes da IA generativa, quem interpretava requisitos amb\u00edguos era um desenvolvedor humano, com contexto acumulado sobre o projeto, mem\u00f3ria das decis\u00f5es passadas e capacidade de perguntar &#8220;isso inclui X?&#8221; no corredor. Um agente de IA n\u00e3o tem esse contexto impl\u00edcito. Ele trabalha com o que est\u00e1 na janela de contexto \u2014 e se a especifica\u00e7\u00e3o for vaga, o resultado ser\u00e1 plaus\u00edvel, bem escrito, sintaticamente correto e, com frequ\u00eancia, errado em rela\u00e7\u00e3o \u00e0 inten\u00e7\u00e3o real.<\/p>\n<p>Isso cria um efeito perverso: c\u00f3digo gerado por IA &#8220;parece&#8221; pronto porque est\u00e1 bem formatado e sem erros de sintaxe, mas pode estar resolvendo o problema errado. Revisar esse tipo de erro \u00e9 mais caro do que revisar um bug de sintaxe, porque exige reconstruir a inten\u00e7\u00e3o original \u2014 algo que a especifica\u00e7\u00e3o deveria ter deixado claro desde o in\u00edcio.<\/p>\n<blockquote><p><strong>\ud83d\udca1 Dica do Mestre:<\/strong> &#8220;Se voc\u00ea n\u00e3o sabe para onde vai, qualquer caminho serve.&#8221; A frase, atribu\u00edda a Lewis Carroll em <em>Alice no Pa\u00eds das Maravilhas<\/em>, resume bem o risco de gerar c\u00f3digo sem especifica\u00e7\u00e3o clara \u2014 o agente de IA vai produzir algo, mas n\u00e3o necessariamente o que voc\u00ea precisa.<\/p><\/blockquote>\n<h2>Anatomia de uma boa especifica\u00e7\u00e3o<\/h2>\n<p>Uma especifica\u00e7\u00e3o eficaz para orientar desenvolvimento (humano ou assistido por IA) costuma conter, no m\u00ednimo:<\/p>\n<ul>\n<li><strong>Contexto e objetivo<\/strong>: por que essa funcionalidade existe, qual problema de neg\u00f3cio resolve.<\/li>\n<li><strong>Comportamento esperado<\/strong>: descrito de forma declarativa, preferencialmente com exemplos concretos de entrada e sa\u00edda.<\/li>\n<li><strong>Restri\u00e7\u00f5es e n\u00e3o-objetivos<\/strong>: o que explicitamente n\u00e3o deve ser feito nesta etapa.<\/li>\n<li><strong>Crit\u00e9rios de aceita\u00e7\u00e3o<\/strong>: condi\u00e7\u00f5es verific\u00e1veis que determinam se a implementa\u00e7\u00e3o est\u00e1 correta.<\/li>\n<li><strong>Casos de borda conhecidos<\/strong>: erros, limites, condi\u00e7\u00f5es de concorr\u00eancia, dados inv\u00e1lidos.<\/li>\n<\/ul>\n<h3>Exemplo pr\u00e1tico: especificando uma fun\u00e7\u00e3o de valida\u00e7\u00e3o de CPF<\/h3>\n<p>Vamos comparar uma instru\u00e7\u00e3o vaga com uma especifica\u00e7\u00e3o estruturada, e ver o impacto no c\u00f3digo gerado.<\/p>\n<p><strong>Instru\u00e7\u00e3o vaga:<\/strong> &#8220;cria uma fun\u00e7\u00e3o para validar CPF.&#8221;<\/p>\n<p><strong>Especifica\u00e7\u00e3o estruturada (formato Given-When-Then, popularizado pelo BDD de Dan North):<\/strong><\/p>\n<pre><code>## Especifica\u00e7\u00e3o: Valida\u00e7\u00e3o de CPF\n\n### Objetivo\nValidar se uma string representa um CPF v\u00e1lido segundo o algoritmo\noficial da Receita Federal, para uso em formul\u00e1rio de cadastro.\n\n### Comportamento esperado\n- Given uma string com 11 d\u00edgitos num\u00e9ricos e d\u00edgitos verificadores corretos\n  When a fun\u00e7\u00e3o for chamada\n  Then deve retornar true\n\n- Given uma string com todos os d\u00edgitos iguais (ex: \"11111111111\")\n  When a fun\u00e7\u00e3o for chamada\n  Then deve retornar false (CPF inv\u00e1lido por regra da Receita)\n\n- Given uma string com m\u00e1scara (ex: \"123.456.789-09\")\n  When a fun\u00e7\u00e3o for chamada\n  Then deve normalizar e validar corretamente\n\n- Given uma string vazia, nula ou com menos de 11 d\u00edgitos\n  When a fun\u00e7\u00e3o for chamada\n  Then deve retornar false, sem lan\u00e7ar exce\u00e7\u00e3o\n\n### N\u00e3o-objetivos\n- N\u00e3o valida se o CPF existe na base da Receita Federal (isso \u00e9 outra fun\u00e7\u00e3o)\n- N\u00e3o faz chamada de rede\n\n### Crit\u00e9rio de aceita\u00e7\u00e3o\nTodos os casos acima cobertos por testes automatizados passando.\n<\/code><\/pre>\n<p>Agora observe a diferen\u00e7a ao usar essa especifica\u00e7\u00e3o como prompt para um agente de IA em Python:<\/p>\n<pre><code>def validar_cpf(cpf: str) -&gt; bool:\n    cpf = ''.join(filter(str.isdigit, cpf or ''))\n\n    if len(cpf) != 11 or cpf == cpf[0] * 11:\n        return False\n\n    def calcular_digito(cpf_parcial: str, peso_inicial: int) -&gt; int:\n        soma = sum(int(d) * peso for d, peso in\n                   zip(cpf_parcial, range(peso_inicial, 1, -1)))\n        resto = soma % 11\n        return 0 if resto &lt; 2 else 11 - resto\n\n    digito1 = calcular_digito(cpf[:9], 10)\n    digito2 = calcular_digito(cpf[:9] + str(digito1), 11)\n\n    return cpf[-2:] == f&quot;{digito1}{digito2}&quot;\n<\/code><\/pre>\n<p>O c\u00f3digo j\u00e1 nasce alinhado com os casos de borda documentados, porque eles estavam expl\u00edcitos na especifica\u00e7\u00e3o. Sem isso, \u00e9 comum receber uma implementa\u00e7\u00e3o que valida apenas o tamanho da string, ignorando o algoritmo de d\u00edgitos verificadores ou o caso de d\u00edgitos repetidos.<\/p>\n<h3>Escrevendo testes a partir da especifica\u00e7\u00e3o<\/h3>\n<p>Uma das maiores vantagens do SDD \u00e9 que a especifica\u00e7\u00e3o, quando bem escrita, se traduz quase diretamente em testes automatizados \u2014 o que tamb\u00e9m serve como harness de verifica\u00e7\u00e3o para c\u00f3digo gerado por IA:<\/p>\n<pre><code>import pytest\nfrom validacao import validar_cpf\n\ndef test_cpf_valido():\n    assert validar_cpf(\"52998224725\") is True\n\ndef test_cpf_todos_digitos_iguais():\n    assert validar_cpf(\"11111111111\") is False\n\ndef test_cpf_com_mascara():\n    assert validar_cpf(\"529.982.247-25\") is True\n\ndef test_cpf_vazio():\n    assert validar_cpf(\"\") is False\n\ndef test_cpf_none():\n    assert validar_cpf(None) is False\n<\/code><\/pre>\n<p>Esse fluxo \u2014 especifica\u00e7\u00e3o em linguagem estruturada, c\u00f3digo gerado a partir dela, testes derivados dos mesmos crit\u00e9rios \u2014 \u00e9 o n\u00facleo pr\u00e1tico do SDD aplicado ao desenvolvimento assistido por IA.<\/p>\n<h2>SDD na pr\u00e1tica com ferramentas de IA generativa<\/h2>\n<p>Ferramentas como Claude Code, Cursor e GitHub Copilot Workspace t\u00eam incorporado, cada uma \u00e0 sua maneira, fluxos que se aproximam do SDD: primeiro voc\u00ea descreve o que precisa em um arquivo de especifica\u00e7\u00e3o (ou em um plano gerado pela pr\u00f3pria ferramenta), revisa esse plano, e s\u00f3 depois autoriza a gera\u00e7\u00e3o do c\u00f3digo.<\/p>\n<p>Isso \u00e9 fundamentalmente diferente de simplesmente digitar um prompt e aceitar o primeiro resultado. O ganho est\u00e1 em transformar a etapa de &#8220;pensar sobre o problema&#8221; em algo expl\u00edcito e revis\u00e1vel \u2014 por voc\u00ea e, se necess\u00e1rio, por outros membros do time \u2014 antes que qualquer c\u00f3digo exista.<\/p>\n<blockquote><p><strong>\ud83d\udca1 Dica do Mestre:<\/strong> o GitHub mant\u00e9m uma iniciativa chamada Spec Kit, com templates e ferramentas open source para praticar Spec Driven Development junto com agentes de IA. Vale explorar em <a href=\"https:\/\/github.com\/github\/spec-kit\" target=\"_blank\">github.com\/github\/spec-kit<\/a>.<\/p><\/blockquote>\n<h3>Exemplo em uma stack diferente: especifica\u00e7\u00e3o para uma API REST em Node.js<\/h3>\n<p>SDD n\u00e3o \u00e9 exclusivo de fun\u00e7\u00f5es isoladas. Funciona igualmente bem para especificar endpoints antes de implement\u00e1-los:<\/p>\n<pre><code>## Especifica\u00e7\u00e3o: POST \/api\/pedidos\n\n### Objetivo\nCriar um novo pedido para um cliente autenticado.\n\n### Request\n- Body: { \"clienteId\": string, \"itens\": [{ \"produtoId\": string, \"quantidade\": number }] }\n- Header: Authorization Bearer token v\u00e1lido\n\n### Comportamento esperado\n- Se o token for inv\u00e1lido, retornar 401\n- Se \"itens\" estiver vazio, retornar 400 com mensagem \"Pedido deve ter ao menos um item\"\n- Se algum produtoId n\u00e3o existir, retornar 404 com o id inv\u00e1lido na mensagem\n- Se algum item tiver estoque insuficiente, retornar 409 (conflito)\n- Em caso de sucesso, retornar 201 com o pedido criado, incluindo id gerado\n\n### N\u00e3o-objetivos\n- N\u00e3o processa pagamento nesta etapa (endpoint futuro)\n- N\u00e3o calcula frete\n<\/code><\/pre>\n<p>Com essa especifica\u00e7\u00e3o em m\u00e3os, um agente de IA (ou um colega de equipe) tem contexto suficiente para implementar o endpoint em Express, Fastify, NestJS ou qualquer outro framework, sem depender de suposi\u00e7\u00f5es sobre casos de erro que s\u00f3 apareceriam em produ\u00e7\u00e3o.<\/p>\n<pre><code>app.post('\/api\/pedidos', autenticar, async (req, res) =&gt; {\n  const { clienteId, itens } = req.body;\n\n  if (!itens || itens.length === 0) {\n    return res.status(400).json({ erro: 'Pedido deve ter ao menos um item' });\n  }\n\n  for (const item of itens) {\n    const produto = await buscarProduto(item.produtoId);\n    if (!produto) {\n      return res.status(404).json({ erro: `Produto ${item.produtoId} n\u00e3o encontrado` });\n    }\n    if (produto.estoque &lt; item.quantidade) {\n      return res.status(409).json({ erro: `Estoque insuficiente para ${item.produtoId}` });\n    }\n  }\n\n  const pedido = await criarPedido(clienteId, itens);\n  return res.status(201).json(pedido);\n});\n<\/code><\/pre>\n<h2>SDD tamb\u00e9m funciona fora do universo web<\/h2>\n<p>Vale refor\u00e7ar que essa disciplina n\u00e3o \u00e9 restrita a APIs ou aplica\u00e7\u00f5es web. Em sistemas desktop legados, como aplica\u00e7\u00f5es Delphi mantidas h\u00e1 anos em empresas de m\u00e9dio porte, especificar antes de alterar uma rotina cr\u00edtica de faturamento \u00e9 igualmente valioso \u2014 talvez ainda mais, dado o custo de regress\u00f5es em sistemas que rodam h\u00e1 d\u00e9cadas sem cobertura de testes robusta. A especifica\u00e7\u00e3o, nesses casos, funciona como uma rede de seguran\u00e7a documental que reduz a depend\u00eancia de &#8220;conhecimento tribal&#8221; concentrado em poucas pessoas do time.<\/p>\n<h2>Riscos de exagerar no SDD<\/h2>\n<p>Como toda pr\u00e1tica, o SDD tem limites. Especificar excessivamente cada detalhe de implementa\u00e7\u00e3o recria os mesmos problemas dos documentos de requisitos burocr\u00e1ticos do passado: processos lentos, especifica\u00e7\u00f5es que ficam desatualizadas em rela\u00e7\u00e3o ao c\u00f3digo e desenvolvedores que passam mais tempo escrevendo documentos do que resolvendo problemas.<\/p>\n<p>O equil\u00edbrio est\u00e1 em especificar o <strong>comportamento e as restri\u00e7\u00f5es<\/strong>, n\u00e3o a implementa\u00e7\u00e3o t\u00e9cnica. A especifica\u00e7\u00e3o deve responder &#8220;o que&#8221; e &#8220;por qu\u00ea&#8221;, deixando o &#8220;como&#8221; para quem (ou o que) vai implementar \u2014 seja um desenvolvedor humano, seja um agente de IA.<\/p>\n<h2>Participe da Comunidade Dev&#8217;s AI<\/h2>\n<p>Se voc\u00ea quer discutir Spec Driven Development, ver exemplos reais de especifica\u00e7\u00f5es usadas com Claude Code, Cursor e outros agentes, e trocar experi\u00eancias com outros desenvolvedores que est\u00e3o adaptando seus processos para a era da IA generativa, venha para a <a href=\"https:\/\/adrianosantos.link\/ComunidadeDevAI\" target=\"_blank\">Comunidade Dev&#8217;s AI<\/a>. \u00c9 o espa\u00e7o certo para compartilhar templates de especifica\u00e7\u00e3o, discutir casos pr\u00e1ticos e evoluir junto com quem enfrenta os mesmos desafios no dia a dia de desenvolvimento.<\/p>\n<h2>Conclus\u00e3o<\/h2>\n<p>Spec Driven Development n\u00e3o \u00e9 sobre burocratizar o desenvolvimento de software \u2014 \u00e9 sobre reconhecer que, quanto mais delegamos a escrita de c\u00f3digo para agentes de IA, mais cr\u00edtico se torna comunicar inten\u00e7\u00e3o de forma precisa e verific\u00e1vel. Uma especifica\u00e7\u00e3o bem escrita economiza retrabalho, reduz ambiguidade, serve como base para testes automatizados e se torna o contrato que orienta tanto humanos quanto m\u00e1quinas na constru\u00e7\u00e3o do software certo.<\/p>\n<p>A pr\u00f3xima vez que voc\u00ea for delegar uma tarefa a um agente de IA \u2014 ou a um colega de equipe \u2014, pare antes de escrever a primeira linha de c\u00f3digo e escreva primeiro a especifica\u00e7\u00e3o. O tempo investido nessa etapa costuma ser recuperado, com juros, na quantidade de retrabalho que voc\u00ea deixa de ter depois.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Voc\u00ea j\u00e1 recebeu uma tarefa assim: &#8220;implementa um sistema de notifica\u00e7\u00f5es para os usu\u00e1rios&#8221;? Voc\u00ea abre o editor, come\u00e7a a codar, cria uma tabela, um servi\u00e7o, um endpoint. Dois dias depois, em uma reuni\u00e3o de revis\u00e3o, descobre que o time de produto queria notifica\u00e7\u00f5es por e-mail e push, com prefer\u00eancias configur\u00e1veis por usu\u00e1rio, rate limiting [&hellip;]<\/p>\n","protected":false},"author":127,"featured_media":1074,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1073","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/1073","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/users\/127"}],"replies":[{"embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/comments?post=1073"}],"version-history":[{"count":1,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/1073\/revisions"}],"predecessor-version":[{"id":1075,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/1073\/revisions\/1075"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/media\/1074"}],"wp:attachment":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/media?parent=1073"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/categories?post=1073"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/tags?post=1073"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}