Cópia estática
Copiado de docs/llm/clean-code.md em https://github.com/poppy-team/aipo-lang (MIT). Fixado na revisão ce47c4e070404fc41722ccd8e2b7b808b99062a8, blob 559aae2f0cf815b78f7b5f5642635e293d3ee5ee. O repositório de origem permanece canônico; esta cópia é atualizada por um pull request de sincronização, não em tempo real.
Aipo é desenhada sob o princípio de baixa sobrecarga cognitiva e acessibilidade neurodivergente (W3C COGA). Em Aipo, "Clean Code" não significa criar camadas desnecessárias de abstração (YAGNI estrito), mas sim código linear, previsível, com contratos explícitos e zero ambiguidade.
1 arquivo .aipo = 1 unidade coesa de domínio).Em Aipo, todas as declarações let e campos de struct não anotados com var são estritamente imutáveis.
with para produzir novos estados a partir de structs existentes.var em variáveis locais e campos de struct apenas quando mutação in-place for estritamente necessária por desempenho ou semântica.self implícito). Só utilize Tipo:metodo(var self) quando a mutação in-place for a intenção clara do design.Tipo:invariant { ... }.invariant.init) e antes/depois de métodos mutáveis. Em caso de violação dentro de um bloco attempt, as mutações são revertidas automaticamente.| Elemento | Convenção | Exemplos | Justificativa |
|---|---|---|---|
| Structs | PascalCase | Usuario, ItemPedido, ResultadoHttp | Diferenciação imediata de valores comuns. |
| Interfaces | PascalCase | Serializavel, Autenticador, Repositorio | Indica contratos estruturais. |
| Funções livres | snake_case | calcular_total, buscar_por_id | Leitura fluida sem atrito visual. |
| Métodos | snake_case | adicionar_item, esta_ativo, serializar | Consistência com funções livres. |
| Variáveis e campos | snake_case | limite_maximo, taxa_juros, var contador | Clareza e legibilidade. |
| Diretivas | #!nome | #!satisfies, #!test, #!deprecated, #!todo | Metadados lidos pelo compilador e analisador. |
campo: Tipo) é formalmente opcional, mas EXTREMAMENTE RECOMENDADA. Declarar os tipos das structs blinda o domínio contra corrupção de tipos em tempo de execução, melhora os diagnósticos do compilador e permite que a LLM compreenda o modelo de dados com precisão cirúrgica.export).interface).Em Clean Code Aipo, a evolução de código e débitos técnicos não devem ser deixados como comentários soltos (# TODO: arrumar). Use diretivas rastreáveis pelo compilador:
#!deprecated("use novo_metodo()"): Sinaliza com precisão para os consumidores que a API será descontinuada, emitindo warnings controlados em vez de breaking changes silenciosas.#!todo("implementar cache LRU"): Anota o item sem poluir a lógica de execução, permitindo que a CLI e agentes auditem pendências estruturadas.# Modelo de alta qualidade contratual: campos tipados e imutáveis por padrão
struct Pedido {
id: Int
cliente_id: Int
total: Float
var status: String = "pendente"
}# Recomendado em fronteiras públicas:
export calcular_frete
fn calcular_frete(peso_kg: Float, distancia_km: Float) -> Float {
if peso_kg <= 0.0 or distancia_km <= 0.0 {
fail "peso e distância devem ser positivos"
}
return (peso_kg * 1.5) + (distancia_km * 0.08)
}Em Aipo, a struct define apenas o formato dos dados. Comportamentos, validações e construtores são declarados via hooks e métodos associados logo abaixo da struct.
# 1. Estrutura pura de dados
struct Carrinho {
id: Int
usuario_id: Int
var itens: List = []
var total: Float = 0.0
}
# 2. Inicializador personalizado
Carrinho:init(id: Int, usuario_id: Int) {
self.id = id
self.usuario_id = usuario_id
self.itens = []
self.total = 0.0
}
# 3. Invariante de integridade
Carrinho:invariant {
self.id > 0
self.usuario_id > 0
self.total >= 0.0
}
# 4. Método imutável (leitura)
Carrinho:quantidade_itens() -> Int {
return len(self.itens)
}
# 5. Método mutável (alteração de estado in-place)
Carrinho:adicionar(var self, item_nome: String, preco: Float) {
if preco <= 0.0 {
fail "preço do item deve ser maior que zero"
}
self.itens.push({ nome: item_nome, preco: preco })
self.total += preco
}with Para evitar mutabilidade desnecessária, utilize a atualização funcional with:
struct Configuracao {
host: String = "localhost"
porta: Int = 8080
ssl: Bool = false
}
let padrao = Configuracao{}
# Produz uma nova instância com a porta e SSL modificados; 'padrao' permanece intacto
let prod = padrao with { porta: 443, ssl: true }:: Um dos princípios de Clean Code em Aipo é a separação entre lógica pura e conveniência ergonômica. Em vez de encapsular algoritmos complexos dentro de métodos acoplados, escreva funções que declarem self como primeiro parâmetro e promova-as a métodos em lote usando :::
# Funções puras declarando 'self' como primeiro parâmetro:
fn calcular_perimetro(self) -> Float {
return 2.0 * (self.largura + self.altura)
}
fn calcular_area(self) -> Float {
return self.largura * self.altura
}
# Promoção limpa: torna ambas acessíveis como métodos de Retangulo
Retangulo::[calcular_perimetro, calcular_area]Esse padrão elimina duplicação de código e preserva a clareza arquitetural.
enum Evite modelar estados finitos ou alternativas com strings mágicas (status: "ativo" | "inativo"). Em Aipo V1, utilize enum:
match.Estado:metodo()) e hooks (Estado:invariant).enum ResultadoOperacao {
Sucesso { dados: String },
Pendente,
Falha(codigo: Int),
}Aipo proíbe try / catch / throw e defer. O tratamento de erros é feito com um vocabulário enxuto e semântica transacional:
fail "mensagem" para sinalizar falhas recuperáveis na lógica de negócio.or_else para valores alternativos seguros.let timeout = obter_parametro("timeout") or_else 3000?: Semelhante a linguagens modernas, propaga Failure para a camada superior imediatamente:let usuario = buscar_usuario(id)?
let saldo = consultar_saldo(usuario.conta_id)?attempt / failed: Envolva blocos com efeitos colaterais atômicos em attempt:attempt {
estoque.reservar(produto_id, qtd)
pagamento.processar(cliente_id, valor)
notificacao.enviar_confirmacao(cliente_id)
} failed erro {
# Se pagamento falhar, as reservas em estoque são desfeitas pelo journal
log.error(f"Falha ao concluir pedido: {erro.message}")
return fail(f"Não foi possível processar o pedido: {erro.message}")
}class nem herança. Use composição de structs e interfaces estruturais.3.somar(4) é erro. Chame somar(3, 4) ou defina explicitamente.# RUIM: comentário que ecoa o código
# incrementa o contador
contador += 1
# BOM: comentário que explica a motivação de negócio
# Necessário para respeitar a cota horária da API externa
taxa_requisições += 1fn local() { ... }) ou funções livres auxiliares no módulo.var sem necessidade: Se uma variável não precisa ser reatribuída, sempre utilize let.