| name | refactoring |
| description | Refactoring - Padrões e técnicas de refatoração segura e OBJETIVA |
| version | 2.0.0 |
| category | workflow |
| triggers | ["refactoring","refatoração","refatorar","código legado","legacy code","code smell","clean code","technical debt","dívida técnica","melhorar código"] |
| tools | [] |
| author | liquid-ai |
Refactoring - Melhorando Código Existente
Esta skill ajuda você a refatorar código de forma SEGURA e OBJETIVA.
Regra Fundamental: OBJETIVIDADE
┌─────────────────────────────────────────────────────────────┐
│ 🚨 REGRA MAIS IMPORTANTE: SEJA OBJETIVO E ÚTIL │
│ │
│ ❌ NUNCA RESPONDA ASSIM: │
│ "Existem várias formas de melhorar esse código..." │
│ "Depende do contexto..." │
│ "Você poderia considerar..." │
│ │
│ ✅ SEMPRE RESPONDA ASSIM: │
│ "Extraia esse bloco para função: extractPaymentLogic()" │
│ "Esse código tem 3 problemas: [lista específica]" │
│ "Refatore assim: [código exato]" │
│ │
│ DÊ O CÓDIGO REFATORADO, NÃO APENAS SUGESTÕES. │
└─────────────────────────────────────────────────────────────┘
Princípio Fundamental
┌─────────────────────────────────────────────────────────────┐
│ "Refactoring is the process of changing a software │
│ system in such a way that it does not alter the │
│ external behavior of the code yet improves its │
│ internal structure." - Martin Fowler │
│ │
│ COMPORTAMENTO IGUAL + ESTRUTURA MELHOR = REFACTORING │
│ │
│ Se muda comportamento → NÃO é refactoring │
│ Se não melhora estrutura → NÃO é refactoring │
└─────────────────────────────────────────────────────────────┘
Quando Usar Esta Skill
- Código difícil de entender ou modificar
- Code smells identificados
- Antes de adicionar nova feature
- Depois de testes passando
- Technical debt prioritizado
O Ciclo de Refactoring
┌─────────────────────────────────────────────────────────────┐
│ 1. GARANTA QUE TESTES EXISTEM E PASSAM │
│ → Se não tem testes, escreva primeiro │
│ → Testes são sua rede de segurança │
│ │
│ 2. FAÇA UMA PEQUENA MUDANÇA │
│ → Uma mudança por vez │
│ → Se algo quebrar, você sabe o quê │
│ │
│ 3. RODE OS TESTES │
│ → Todos devem passar │
│ → Se falhar: desfaça e tente de novo │
│ │
│ 4. REPITA │
│ → Pequenos passos seguros │
│ → Commit frequente │
│ │
│ "Make the change easy, then make the easy change." │
│ - Kent Beck │
└─────────────────────────────────────────────────────────────┘
Code Smells e Soluções
1. Função Muito Longa
async function processOrder(order: Order) {
if (!order.items) throw new Error('No items');
if (!order.customer) throw new Error('No customer');
let total = 0;
for (const item of order.items) {
total += item.price * item.quantity;
}
const payment = await chargeCard(order.customer.card, total);
await sendEmail(order.customer.email, 'Order confirmed');
return { orderId: order.id, total, payment };
}
async function processOrder(order: Order) {
validateOrder(order);
const total = calculateTotal(order);
const payment = await processPayment(order.customer, total);
await sendNotifications(order, payment);
return { orderId: order.id, total, payment };
}
function validateOrder(order: Order): void {
if (!order.items?.length) throw new Error('No items');
if (!order.customer) throw new Error('No customer');
}
function calculateTotal(order: Order): number {
return order.items.reduce((total, item) =>
total + item.price * item.quantity, 0);
}
async function processPayment(customer: Customer, total: number) {
return await chargeCard(customer.card, total);
}
async function sendNotifications(order: Order, payment: Payment) {
await sendEmail(order.customer.email, 'Order confirmed');
}
2. Código Duplicado
function getUserDisplayName(user: User): string {
if (user.firstName && user.lastName) {
return `${user.firstName} ${user.lastName}`;
}
return user.email.split('@')[0];
}
function getAdminDisplayName(admin: Admin): string {
if (admin.firstName && admin.lastName) {
return `${admin.firstName} ${admin.lastName}`;
}
return admin.email.split('@')[0];
}
interface HasName {
firstName?: string;
lastName?: string;
email: string;
}
function getDisplayName(person: HasName): string {
if (person.firstName && person.lastName) {
return `${person.firstName} ${person.lastName}`;
}
return person.email.split('@')[0];
}
getDisplayName(user);
getDisplayName(admin);
3. Muitos Parâmetros
function createUser(
firstName: string,
lastName: string,
email: string,
phone: string,
address: string,
city: string,
country: string
) {
}
interface CreateUserParams {
firstName: string;
lastName: string;
email: string;
phone?: string;
address?: Address;
}
interface Address {
street: string;
city: string;
country: string;
}
function createUser(params: CreateUserParams) {
const { firstName, lastName, email, phone, address } = params;
}
createUser({
firstName: 'João',
lastName: 'Silva',
email: 'joao@email.com',
address: {
street: 'Rua A',
city: 'São Paulo',
country: 'Brasil'
}
});
4. Condicionais Complexos
function getDiscount(user: User, order: Order): number {
if (user.isPremium) {
if (order.total > 1000) {
if (order.items.length > 5) {
return 0.25;
} else {
return 0.20;
}
} else {
return 0.15;
}
} else {
if (order.total > 1000) {
return 0.10;
} else {
return 0;
}
}
}
function getDiscount(user: User, order: Order): number {
if (!user.isPremium) {
return order.total > 1000 ? 0.10 : 0;
}
if (order.total <= 1000) {
return 0.15;
}
return order.items.length > 5 ? 0.25 : 0.20;
}
const DISCOUNT_RULES = [
{ premium: true, minTotal: 1000, minItems: 5, discount: 0.25 },
{ premium: true, minTotal: 1000, minItems: 0, discount: 0.20 },
{ premium: true, minTotal: 0, minItems: 0, discount: 0.15 },
{ premium: false, minTotal: 1000, minItems: 0, discount: 0.10 },
{ premium: false, minTotal: 0, minItems: 0, discount: 0.00 },
];
function getDiscount(user: User, order: Order): number {
const rule = DISCOUNT_RULES.find(r =>
r.premium === user.isPremium &&
order.total >= r.minTotal &&
order.items.length >= r.minItems
);
return rule?.discount ?? 0;
}
5. Feature Envy
class OrderService {
calculateShipping(order: Order): number {
const address = order.customer.address;
const city = address.city;
const state = address.state;
const isRemote = this.isRemoteArea(city, state);
const weight = order.items.reduce((w, i) => w + i.weight, 0);
if (isRemote) {
return weight * 2.5;
}
return weight * 1.5;
}
}
class Address {
city: string;
state: string;
isRemoteArea(): boolean {
return REMOTE_AREAS.includes(`${this.city}-${this.state}`);
}
}
class Order {
items: Item[];
customer: Customer;
getTotalWeight(): number {
return this.items.reduce((w, i) => w + i.weight, 0);
}
calculateShipping(): number {
const baseRate = this.customer.address.isRemoteArea() ? 2.5 : 1.5;
return this.getTotalWeight() * baseRate;
}
}
Refactorings Comuns
Extract Function
QUANDO USAR:
→ Bloco de código faz uma coisa específica
→ Código se repete
→ Comentário explica o que o código faz
COMO:
1. Crie função com nome descritivo
2. Copie o código
3. Identifique variáveis necessárias → parâmetros
4. Identifique variáveis modificadas → retorno
5. Substitua código original por chamada
6. Rode testes
Inline Function (oposto de Extract)
QUANDO USAR:
→ Função não adiciona clareza
→ Corpo é tão claro quanto o nome
→ Excesso de indireção
EXEMPLO:
// ❌ Indireção desnecessária
function isAdult(age: number): boolean {
return age >= 18;
}
function canVote(person: Person): boolean {
return isAdult(person.age);
}
// ✅ Inline quando óbvio
function canVote(person: Person): boolean {
return person.age >= 18;
}
Replace Temp with Query
function getPrice(order: Order): number {
const basePrice = order.quantity * order.itemPrice;
const discount = Math.max(0, order.quantity - 500) * order.itemPrice * 0.05;
return basePrice - discount;
}
function getPrice(order: Order): number {
return getBasePrice(order) - getDiscount(order);
}
function getBasePrice(order: Order): number {
return order.quantity * order.itemPrice;
}
function getDiscount(order: Order): number {
return Math.max(0, order.quantity - 500) * order.itemPrice * 0.05;
}
Replace Conditional with Polymorphism
function calculatePay(employee: Employee): number {
switch (employee.type) {
case 'hourly':
return employee.hoursWorked * employee.hourlyRate;
case 'salaried':
return employee.monthlySalary;
case 'commissioned':
return employee.baseSalary + employee.sales * employee.commissionRate;
}
}
abstract class Employee {
abstract calculatePay(): number;
}
class HourlyEmployee extends Employee {
constructor(private hoursWorked: number, private hourlyRate: number) {
super();
}
calculatePay(): number {
return this.hoursWorked * this.hourlyRate;
}
}
class SalariedEmployee extends Employee {
constructor(private monthlySalary: number) {
super();
}
calculatePay(): number {
return this.monthlySalary;
}
}
class CommissionedEmployee extends Employee {
constructor(
private baseSalary: number,
private sales: number,
private commissionRate: number
) {
super();
}
calculatePay(): number {
return this.baseSalary + this.sales * this.commissionRate;
}
}
Checklist de Refactoring
ANTES DE REFATORAR:
□ Testes existem e cobrem o código?
□ Todos os testes passam?
□ Você entende o que o código faz?
□ O refactoring vai melhorar algo mensurável?
DURANTE:
□ Uma mudança pequena por vez?
□ Rodando testes após cada mudança?
□ Commits frequentes?
□ Não mudando comportamento?
DEPOIS:
□ Todos os testes ainda passam?
□ Código está mais legível?
□ Menos duplicação?
□ Nomes são claros?
□ Funções são pequenas (<20 linhas)?
Exemplo de Resposta OBJETIVA
Usuário: "Como refatoro este código?"
function calc(items, user) {
let t = 0;
for (let i = 0; i < items.length; i++) {
t += items[i].p * items[i].q;
if (items[i].p * items[i].q > 100) {
t = t - (items[i].p * items[i].q * 0.1);
}
}
if (user.premium) {
t = t * 0.9;
}
return t;
}
Resposta:
Este código tem 4 problemas:
1. Nomes ruins (t, p, q, calc)
2. Cálculo duplicado (items[i].p * items[i].q)
3. Lógica misturada (subtotal + desconto + premium)
4. Loop imperativo em vez de funcional
CÓDIGO REFATORADO:
interface CartItem {
price: number;
quantity: number;
}
interface User {
isPremium: boolean;
}
function calculateCartTotal(items: CartItem[], user: User): number {
const subtotal = calculateSubtotal(items);
const itemDiscounts = calculateItemDiscounts(items);
const premiumDiscount = calculatePremiumDiscount(subtotal, user);
return subtotal - itemDiscounts - premiumDiscount;
}
function calculateSubtotal(items: CartItem[]): number {
return items.reduce(
(total, item) => total + getItemTotal(item),
0
);
}
function getItemTotal(item: CartItem): number {
return item.price * item.quantity;
}
function calculateItemDiscounts(items: CartItem[]): number {
const BULK_DISCOUNT_THRESHOLD = 100;
const BULK_DISCOUNT_RATE = 0.10;
return items.reduce((discount, item) => {
const itemTotal = getItemTotal(item);
if (itemTotal > BULK_DISCOUNT_THRESHOLD) {
return discount + itemTotal * BULK_DISCOUNT_RATE;
}
return discount;
}, 0);
}
function calculatePremiumDiscount(subtotal: number, user: User): number {
const PREMIUM_DISCOUNT_RATE = 0.10;
return user.isPremium ? subtotal * PREMIUM_DISCOUNT_RATE : 0;
}
MELHORIAS:
1. Nomes descritivos (calculateCartTotal, price, quantity)
2. Cálculo extraído (getItemTotal)
3. Responsabilidades separadas (3 funções de desconto)
4. Constantes nomeadas (BULK_DISCOUNT_THRESHOLD)
5. Funcional com reduce em vez de for loop
6. TypeScript para segurança de tipos
ORDEM DE REFACTORING:
1. Primeiro: renomeie variáveis (t→total, p→price, etc)
2. Rode testes
3. Extraia getItemTotal()
4. Rode testes
5. Extraia calculateSubtotal()
6. Rode testes
7. Continue passo a passo...
Regras Imutáveis
1. SEJA OBJETIVO — dê o código refatorado, não apenas dicas
2. Testes primeiro, refactoring depois
3. Pequenos passos, sempre
4. Não mude comportamento durante refactoring
5. Nomes claros > comentários
6. Funções pequenas (<20 linhas)
7. Uma responsabilidade por função
8. DRY (Don't Repeat Yourself)
9. Commit frequente
10. "Make the change easy, then make the easy change"
Esta skill ativa AUTOMATICAMENTE quando:
- Código precisa ser melhorado
- Code smells identificados
- Technical debt sendo tratado
- Antes de adicionar features
- Revisão de código com problemas