Não faltam relatórios sobre como assistentes de codificação de IA, agentes e frotas de agentes escreveram grandes quantidades de código em um curto espaço de tempo, código que supostamente implementa os recursos desejados. É raro que as pessoas falem sobre requisitos não funcionais, como desempenho ou segurança nesse contexto, talvez porque isso não seja uma preocupação em muitos dos casos de uso dos autores. E é ainda mais raro que as pessoas avaliem a qualidade do código gerado pelo agente. Eu diria, porém, que a qualidade interna é essential para que o desenvolvimento proceed a um ritmo sustentável ao longo dos anos, em vez de entrar em colapso sob o seu próprio peso.
Então, vamos dar uma olhada mais de perto no desempenho das ferramentas de IA quando se trata de qualidade do código interno. Adicionaremos um recurso a um aplicativo existente com a ajuda de um agente e veremos o que está acontecendo ao longo do caminho. Claro, isso faz com que seja “apenas” uma anedota. Este memorando não é de forma alguma um estudo. Ao mesmo tempo, muito do que veremos se enquadra em padrões e pode ser extrapolado, pelo menos na minha experiência.
O recurso que estamos implementando
Estaremos trabalhando com a base de código para CCMenuum aplicativo Mac que mostra o standing das compilações de CI/CD na barra de menus do Mac. Isso adiciona um certo grau de dificuldade à tarefa porque os aplicativos Mac são escritos em Swift, que é uma linguagem comum, mas não tão comum quanto JavaScript ou Python. É também uma linguagem de programação moderna com uma sintaxe complexa e um sistema de tipos que requer mais precisão do que, novamente, JavaScript ou Python.

CCMenu recupera periodicamente o standing dos servidores de construção com chamadas para suas APIs. Atualmente, ele oferece suporte a servidores que usam um protocolo legado implementado por empresas como Jenkins e oferece suporte a fluxos de trabalho do GitHub Actions. O servidor mais solicitado que não é suportado atualmente é o GitLab. Então essa é a nossa característica: implementaremos suporte para GitLab no CCMenu.
O wrapper da API
GitHub fornece o API de ações do GitHubque é estável e bem documentado. GitLab tem o API GitLabque também está bem documentado. Dada a natureza do espaço do problema, eles são semanticamente bastante semelhantes. Porém, eles não são iguais e veremos como isso afeta a tarefa mais tarde.
Internamente, o CCMenu possui três arquivos específicos do GitHub para recuperar o standing de compilação da API: um leitor de feed, um analisador de resposta e um arquivo que contém funções Swift que envolvem a API do GitHub, incluindo funções como as seguintes:
func requestForAllPublicRepositories(consumer: String, token: String?) -> URLRequest
func requestForAllPrivateRepositories(token: String) -> URLRequest
func requestForWorkflows(proprietor: String, repository: String, token: String?) -> URLRequest
As funções retornam URLRequest objetos, que fazem parte do Swift SDK e são usados para fazer a solicitação de rede actual. Como essas funções são estruturalmente bastante semelhantes, elas delegam a construção do URLRequest objeto a uma função interna compartilhada:
func makeRequest(technique: String = "GET", baseUrl: URL, path: String,
params: Dictionary = (:), token: String? = nil) -> URLRequest
Não se preocupe se você não estiver familiarizado com Swift, desde que reconheça os argumentos e seus tipos, você estará bem.
Tokens opcionais
A seguir, devemos olhar para o token argumento com um pouco mais de detalhes. As solicitações às APIs podem ser autenticadas. Eles não precisam ser autenticados, mas podem ser autenticados. Isso permite que aplicativos como o CCMenu acessem informações restritas a determinados usuários. Para a maioria das APIs, incluindo GitHub e GitLab, o token é simplesmente uma longa string que precisa ser passada em um cabeçalho HTTP.
Em sua implementação, CCMenu usa uma string opcional para o token, que em Swift é denotada por um ponto de interrogação após o tipo, String? nesse caso. Este é um uso idiomático, e o Swift força os destinatários de tais valores opcionais a lidar com a opcionalidade de maneira segura, evitando os clássicos problemas de ponteiro nulo. Existem também recursos de idioma especiais para tornar isso mais fácil.
Algumas funções não fazem sentido em um contexto não autenticado, como requestForAllPrivateRepositories. Estes declaram o token como não opcional, sinalizando ao chamador que um token deve ser fornecido.
Vamos
Tentei esta experiência algumas vezes, durante o verão usando Windsurf e Sonnet 3.5, e agora, recentemente, com Claude Code e Sonnet 4.5. A abordagem permaneceu semelhante: dividir a tarefa em partes menores. Para cada uma das partes, pedi ao Windsurf que elaborasse um plano antes de solicitar uma implementação. Com o Claude Code fui direto para a implementação, contando com seu planejamento interno; e no Git quando algo acabou indo na direção errada.
Como primeiro passo perguntei ao agente, mais ou menos textualmente: “Com base nos arquivos GitHub para API, leitor de feed e analisador de resposta, implemente a mesma funcionalidade para GitLab. Escreva apenas o equivalente para esses três arquivos. Não faça alterações na IU.”
Parecia um pedido razoável e, em geral, period. Até o Windsurf, com o modelo menos capaz, percebeu as principais diferenças e as tratou, por exemplo, reconheceu que o que o GitHub chama de repositório é um projeto no GitLab; ele viu a diferença na resposta JSON, onde o GitLab retorna o array de execuções no nível superior enquanto o GitHub tem esse array como uma propriedade em um objeto de nível superior.
Eu não tinha olhado os documentos da API do GitLab neste estágio e apenas com uma varredura superficial do código gerado tudo parecia muito bem, o código compilado e até mesmo os tipos de funções complexas foram gerados corretamente, ou não?
Primeira surpresa
Na próxima etapa, pedi ao agente para implementar a UI para adicionar novos pipelines/fluxos de trabalho. Pedi deliberadamente que não se preocupasse com a autenticação ainda, apenas implementasse o fluxo para informações acessíveis ao público. A discussão dessa etapa talvez seja para outro memorando, mas o novo código precisa de alguma forma reconhecer que um token pode estar presente no futuro
var apiToken: String? = nil
e então ele pode usar a variável na chamada da função wrapper
let req = GitLabAPI.requestForGroupProjects(group: title, token: apiToken)
var initiatives = await fetchProjects(request: req)
O apiToken variável é declarada corretamente como uma String opcional, inicializada para nil por agora. Posteriormente, algum código poderia recuperar o token de outro native, dependendo se o usuário decidiu entrar. Esse código levou ao primeiro erro do compilador:
![]()
O que está acontecendo aqui? Bem, acontece que o código para o wrapper da API na primeira etapa tinha um problema sutil: ele declarou os tokens como não opcionais em todos as funções do wrapper, por exemplo
func requestForGroupProjects(group: String, token: String) -> URLRequest
O subjacente makeRequest A função, por um motivo ou outro, foi criada corretamente, com o token declarado como opcional.
O código compilado porque da forma como as funções foram escritas, as funções wrapper definitivamente possuem uma string e isso pode, claro, ser passado para uma função que recebe uma string opcional, um argumento que pode ser uma string ou nada (nil). Mas agora, no código acima, temos uma string opcional e que não pode ser passada para uma função que precisa de uma string (definida).
A correção da vibração
Sendo preguiçoso, simplesmente copiei e colei a mensagem de erro no Windsurf. (Construir um aplicativo Swift em qualquer coisa que não seja Xcode é uma história totalmente diferente, e lembro-me de um experimento com Cline onde ele alternava entre adicionar e remover importações explícitas, por cerca de 20 centavos por iteração.) A correção proposta pela IA para esse problema funcionou: alterou o website de chamada e inseriu uma string vazia como valor padrão para quando nenhum token estava presente, usando o Swift’s ?? operador.
let req = GitLabAPI.requestForGroupProjects(group: title, token: apiToken ?? "")
var initiatives = await fetchProjects(request: req)
Isso compila e funciona: se não houver token, uma string vazia é substituída, o que significa que o argumento passado para a função é o token ou a string vazia, é sempre uma string e nunca nil.
Então, o que há de errado? O objetivo de declarar o token como opcional period sinalizar que o token é opcional. A IA ignorou isso e introduziu uma nova semântica: uma string vazia agora sinaliza que nenhum token está disponível. Isso é
- não idiomático,
- não autodocumentado,
- não suportado pelo sistema de tipos do Swift.
Também exigiu mudanças em todos os locais onde esta função é chamada.
A verdadeira solução
Claro, o que o agente deveria ter feito é simplesmente alterar a declaração da função wrapper para tornar o token opcional. Com essa mudança tudo funciona conforme o esperado, a semântica permanece intacta e a mudança se limita a adicionar um único ? ao tipo do argumento da função, em vez de espalhar ?? "" em todo o código.
Isso realmente importa?
Você pode perguntar se estou dividindo o cabelo aqui. Eu não acho que estou. Acho que este é um exemplo claro de que um agente de IA deixado por conta própria teria mudado a base de código para pior, e foi necessário um desenvolvedor com experiência para perceber o problema e direcionar o agente para a implementação correta.
Além disso, este é apenas um dos muitos exemplos que encontrei. Em algum momento, o agente quis introduzir um cache completamente desnecessário e, é claro, não conseguiu explicar por que havia sugerido o cache.
Ele também não percebeu que a sobreposição usuário/organização no GitHub não existe no GitLab e implementou uma lógica complicada para lidar com um problema inexistente. Foi preciso mais do que empurrar o agente para os lugares corretos na documentação para dissuadi-lo de insistir que a lógica period necessária.
Ele também “esqueceu” de usar funções existentes para construir URLs, replicando tal lógica em vários locais, muitas vezes sem implementar todas as funcionalidades, por exemplo, a opção de substituir a URL base para fins de teste usando o sistema padrão no macOS.
Então, nesses casos, e houve mais, o código gerado funcionou. Ele implementou a funcionalidade necessária. Mas o novo código também adicionaria complexidade completamente desnecessária e perderia funcionalidades não óbvias, diminuindo a qualidade da base de código e introduzindo problemas sutis.
Se trabalhar em grandes sistemas de software program me ensinou uma coisa é que investir na qualidade interna do software program, na qualidade da base de código, é um investimento que vale a pena. Não fique sobrecarregado por dívidas técnicas. Humanos e agentes acham mais difícil trabalhar com uma base de código complicada. Sem uma supervisão cuidadosa, porém, os agentes de IA parecem ter uma forte tendência para introduzir dívida técnica, dificultando o desenvolvimento futuro, para humanos e agentes.
Mais uma coisa
Se possível, CCMenu mostra o avatar da pessoa/ator que acionou a construção. No GitHub, o URL do avatar faz parte da resposta à chamada da API de standing de construção. O GitLab tem um design “mais limpo” e RESTful e mantém informações adicionais do usuário fora da resposta do construct. O URL do avatar deve ser recuperado com uma chamada de API separada para um /consumer ponto ultimate.
Tanto o Windsurf quanto o Claude Code tropeçaram nisso de uma forma importante. Lembro-me de uma longa conversa em que Claude Code queria me convencer de que a URL estava na resposta. (Provavelmente ficou confuso porque vários endpoints foram descritos na mesma página da documentação.) No ultimate, achei mais fácil implementar essa funcionalidade sem o suporte do agente.
Minhas conclusões
Durante os experimentos no verão, eu estava em cima do muro. A combinação Windsurf / Sonnet 3.5 acelerou a escrita de código, mas exigiu um planejamento cuidadoso com prompts, e tive que alternar entre Windsurf e Xcode (para construção, execução de testes e depuração), o que sempre pareceu um tanto desorientador e cansativo rapidamente. A qualidade do código gerado apresentava problemas significativos e o agente tendia a ficar preso tentando resolver um problema. Então, no geral, parecia que eu não estava aproveitando muito o uso do agente. E troquei fazer o que gosto, escrever código, por supervisionar uma IA com tendência a escrever código desleixado.
Com Claude Code e Sonnet 4.5 a história é um pouco diferente. Precisa de menos solicitações e o código tem melhor qualidade. Não é de forma alguma um código de alta qualidade, mas é melhor, exigindo menos retrabalho e menos solicitações para melhorar a qualidade. Além disso, conversar com Claude Code em uma janela de terminal junto com o Xcode parecia mais pure do que alternar entre dois IDEs. Para mim, isso inclinou a balança o suficiente para usar o Código Claude regularmente.