A IA, com o hype do LLM, já gera CRUDs, telas, resolve bugs e até propõe um conjunto de classes, métodos e funções para criar uma aplicação completa.
Mas há uma habilidade que máquinas não replicam: o design estratégico de código.
Imagine um arquiteto que não apenas coloca tijolos, mas decide onde colocá-los, por quê, e como isso afetará quem morará ali daqui a 10 anos. O Designer de Código é esse arquiteto digital.
Neste artigo, compartilho uma opinião sobre o impacto do IA no design de código e como aproveitar o máximo a codificação, junto com IA.
O objetivo do desenvolvedor#
O principal objetivo não é escrever código, mas criar soluções para problemas reais enfrentados pelo usuário a ponto de querer pagar pela solução.
O código é uma ferramenta que ajuda o desenvolvedor e a empresa atingir este objetivo.
E não basta somente fazer funcionar. Precisamos codificar de tal maneira que facilite as futuras manutenções e alterações para que o custo para a empresa seja o menor possível.
Para manter o custo baixo da manutenção e alteração, precisamos ter um design com baixo acoplamento e alta coesão.
Esta é uma habilidade que poucos desenvolvedores adquirem ao longo da experiência profissional dentro de uma empresa.
A habilidade que poucos desenvolvem#
A habilidade de criar um design de código que possui baixo acoplamento e alta coesão é difícil de adquirir.
O primeiro motivo é que, para adquirir esta habilidade, uma das experiências importante e necessária para ganhar esta habilidade é a refatoração.
A refatoração é uma experiência técnica importante para qualquer desenvolvedor, pois nenhum desenvolvedor escreve um código perfeito ou quase perfeito na primeira tentativa.
Ou seja, não sabe onde colocar o tijolo e por que colocar aquele tipo de tijolo.
E também não sabe como o código pode afetar positivamente no futuro.
O segundo motivo é a falta de incentivo das empresas para adquirir esta habilidade.
Normalmente desenvolvedores se tornam destaques na empresa e começam a ocupar cargos de liderança e gestão.
Só que estas mesmas pessoas sabem que é importante refatorar mas não a ponto de investir nisso.
Já que a maioria dos desenvolvedores não sabem mostrar ou incentivar a importância da refatoração na sua empresa, a empresa e a sua liderança não vê sentido em criar incentivos para isso.
O foco da empresa e da liderança se torna então codificar o mais rápido possível. Seja para resolver bugs, criar novas funcionalidades e realizar alterações.
E IA, especificamente os LLM (Large Language Model), tem ajudado empresas e equipes a escreverem código mais rápido.
Entra IA para acelerar a codificação#
Muitas tarefas cotidianas de um desenvolvedor como:
- Tirar dúvidas sobre uma tecnologia, linguagem ou projeto
- Cenários de teste
- Boilerplate code
- Auto-complete mais inteligente
- Documentação
Tem sido facilitado com a ajuda dos LLM.
Mas estas tarefas são os passos que damos quando temos o design estratégico da solução em nossa mente.
Quando precisamos criar algo, por exemplo:
- Refatoração: Criação de uma nova estrutura, sem alterar o comportamento que atinja um certo requisito de qualidade
- Novas funcionalidades: Criar um conjunto de código que satisfaça a necessidade do cliente
Precisamos de criatividade e análise crítica das soluções, pois não basta somente funcionar. Deve funcionar em um contexto muito específico.
Por exemplo:
- O código gerado pode funcionar para um usuário. Mas e se tiver muitos usuários continua funcionando?
- O código gerado pode ter problema de desempenho quando você utiliza o banco de dados em produção
- O código refatorado não melhorou a legibilidade ou a facilidade de adicionar novas features
Vamos ver um exemplo de uma refatoração.
IA, ajuda na refatoração#
Vou utilizar o DeepSeek R1 para me ajudar a refatorar. E vamos supor que temos teste para cada cenário do código.
Vou utilizar o Gilded Rose onde as especificações são estão no link abaixo:
O código original do Gilded Rose está logo abaixo:
package br.com.youready.article.d_2025_01_27.image1;
class GildedRoseOriginal {
Item[] items;
public GildedRoseOriginal(Item[] items) {
this.items = items;
}
public void updateQuality() {
for (int i = 0; i < items.length; i++) {
if ((!items[i].name.equals("Aged Brie")
&& !items[i].name.equals("Backstage passes to a TAFKAL80ETC concert"))) {
if (items[i].quality > 0) {
if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
items[i].quality = items[i].quality - 1;
}
}
} else {
if (items[i].quality < 50) {
items[i].quality = items[i].quality + 1;
if (items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
if (items[i].sellIn < 11) {
if (items[i].quality < 50) {
items[i].quality = items[i].quality + 1;
}
}
if (items[i].sellIn < 6) {
if (items[i].quality < 50) {
items[i].quality = items[i].quality + 1;
}
}
}
}
}
if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
items[i].sellIn = items[i].sellIn - 1;
}
if (items[i].sellIn < 0) {
if (!items[i].name.equals("Aged Brie")) {
if (!items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
if (items[i].quality > 0) {
if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
items[i].quality = items[i].quality - 1;
}
}
} else {
items[i].quality = items[i].quality - items[i].quality;
}
} else {
if (items[i].quality < 50) {
items[i].quality = items[i].quality + 1;
}
}
}
}
}
}
Este código tem coesão baixa e alto acoplamento por ter todas as regras de todos os itens implementadas em um método.
Pedi para o DeepSeek R1 refatorar para aumentar a coesão e diminuir o acoplamento dos itens. A seguinte refatoração foi sugerida:
package br.com.youready.article.d_2025_01_27.image2;
class GildedRose {
Item[] items;
public GildedRose(Item[] items) {
this.items = items;
}
public void updateQuality() {
for (Item item : items) {
ItemUpdater updater = ItemUpdaterFactory.getUpdaterForItem(item);
updater.update(item);
}
}
}
Parece bom!
O código gerado aproveita a ideia de cada item ter uma regra e cria uma classe Updater para cada tipo de item especial e um normal.
Mas o nome ItemUpdaterFactory faz sentido para você? Estamos usando algum padrão de factory?
Será que não é um Strategy Pattern?
O que você acha?
Eu pedi mais duas sugestões de refatoração:
package br.com.youready.article.d_2025_01_27.image3;
import java.util.HashMap;
import java.util.Map;
class GildedRose {
Item[] items;
private final Map<String, UpdateStrategy> strategies = new HashMap<>();
public GildedRose(Item[] items) {
this.items = items;
strategies.put("Aged Brie", new AgedBrieStrategy());
strategies.put("Backstage passes to a TAFKAL80ETC concert", new BackstagePassStrategy());
strategies.put("Sulfuras, Hand of Ragnaros", new SulfurasStrategy());
strategies.put("default", new DefaultStrategy());
}
public void updateQuality() {
for (Item item : items) {
UpdateStrategy strategy = strategies.getOrDefault(item.name, strategies.get("default"));
strategy.update(item);
}
}
}
O design deste código parece com a primeira sugestão mas tem algumas diferenças.
O nome virou de factory para strategy! E a estrutura interna do código é um pouco diferente também. Por exemplo, vemos um uso do static nas classes. Por que ele fez isso?
É melhor este design?
E a terceira sugestão:
package br.com.youready.article.d_2025_01_27.image4;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
class GildedRose {
Item[] items;
private final Map<String, Consumer<Item>> rules = new HashMap<>();
public GildedRose(Item[] items) {
this.items = items;
rules.put("Aged Brie", this::updateAgedBrie);
rules.put("Backstage passes to a TAFKAL80ETC concert", this::updateBackstagePass);
rules.put("Sulfuras, Hand of Ragnaros", item -> {});
rules.put("default", this::updateDefaultItem);
}
public void updateQuality() {
for (Item item : items) {
Consumer<Item> rule = rules.getOrDefault(item.name, rules.get("default"));
rule.accept(item);
}
}
// Regras como métodos separados
private void updateAgedBrie(Item item) {
increaseQuality(item);
item.sellIn--;
if (item.sellIn < 0) increaseQuality(item);
}
private void updateBackstagePass(Item item) {
/* Similar à versão 1 */
}
private void updateDefaultItem(Item item) {
/* Similar à versão 1 */
}
private void increaseQuality(Item item) {
if (item.quality < 50) {
item.quality++;
}
}
}
Novamente um design parecido mas com algumas diferenças. A principal diferença é o uso das funções no lugar de classes. Mas parece difícil de testar por ter funções privadas. E agora?
Qual é o design mais adequado para o seu momento e seu contexto?
Se você não consegue responder, provavelmente um LLM também não consegue e vai sugerir a solução mais comum e frequente.
Então a habilidade de criar e entender um design se torna importante, mesmo com ferramentas de IA como DeepSeek R1.
Para você poder orientar melhor o modelo, você deve saber o que pedir. Em detalhes sobre o design estratégico adequado para o seu contexto.
Como eu uso DeepSeek R1 e outros modelos para design#
Eu peço para ele criar algo mas nunca somente copio e não aceito a primeira solução.
Eu sempre peço três ou quatro variantes da solução e tento encontrar uma solução que une todas as sugestões e ainda com adição da minha ideia de design.
Quando você sugere três ou mais sugestões, você tem a oportunidade de aprender com as variantes da solução e tentar criar uma solução própria com seu conhecimento e dentro do seu contexto.
Dicas finais de Design de Código e LLM#
Você deve saber avaliar o código gerado pelo LLM. Mas a sua avaliação não pode ser baseada em se funciona ou não o código.
A sua avaliação deve responder pelo menos as seguintes perguntas:
- O código gerado tem um design bom o suficiente para facilitar a alteração futura?
- O código gerado tem um design bom o suficiente para facilitar a compreensão do código de qualquer um da equipe?
- O código gerado tem um design bom o suficiente para facilitar a escrita de testes?
- O código gerado, além de funcionar, atende a outros requisitos de qualidade como concorrência, desempenho, carga, segurança e etc?
Basicamente você deve se tornar o Code Reviewer do código gerado. A única diferença é que você pode fazer as alterações necessárias em vez de pedir as alterações.
Outras dicas para 2025#
- Aprenda a fazer design e não fique só na codificação
- Estude um pouco sobre padrões e princípios
- Leia livros sobre design
- Aprenda a fazer análises mais amplas, como por exemplo: Como meu código pode afetar o deploy? Como afeta a manutenção do código?
- Domine as ferramentas de IA mas não dependa delas
- Use o modelo de sua preferência e utilize as respostas como esboço inicial da sua solução.
Conclusão#
Enquanto IA pode automatizar a escrita do código, o desenvolvedor ainda tem a responsabilidade de pensar em qual o melhor design de código para o momento do projeto, produto e empresa.
Um desenvolvedor que conseguir evoluir a habilidade de design, será um profissional que conseguirá trazer mais benefícios para a equipe e empresa do que um modelo de LLM qualquer.
Aprender e saber trabalhar o design do código, junto com LLM para gerar esboço rápido, é um ganho fantástico.
E você? Quais modelos tem utilizado no dia a dia?
Se tiver curiosidade sobre o assunto, pode falar comigo!
🥒🥒 Espero que tenham curtido e até o próximo artigo! 🥒🥒


