Guia de Performance¶
Este documento descreve otimizações e boas práticas de performance para o Billings Ease.
Índice¶
Backend¶
Otimizações de Queries¶
1. Eager Loading (Preload)
// ❌ N+1 queries
cycles := []Cycle{}
db.Find(&cycles)
for _, cycle := range cycles {
db.Model(&cycle).Association("Observations").Find(&cycle.Observations)
}
// ✅ Uma query com joins
cycles := []Cycle{}
db.Preload("Observations").Find(&cycles)
2. Seleção de Campos
// ❌ Busca todos os campos
db.Find(&users)
// ✅ Busca apenas campos necessários
db.Select("id", "name", "email").Find(&users)
3. Índices no Banco
CREATE INDEX idx_cycles_user_id ON cycles(user_id);
CREATE INDEX idx_observations_cycle_id ON observations(cycle_id);
CREATE INDEX idx_observations_date ON observations(date);
Cache¶
Estratégias: - Cache de símbolos permitidos (5 minutos) - Cache de regras do método (configuração) - Cache de planos (público)
Implementação Futura: - Redis para cache distribuído - Cache de queries frequentes
Concorrência¶
Goroutines para operações independentes:
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
// Operação 1
}()
go func() {
defer wg.Done()
// Operação 2
}()
wg.Wait()
Frontend Web¶
React Query¶
Configuração:
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000, // 5 minutos
cacheTime: 10 * 60 * 1000, // 10 minutos
},
},
})
Uso:
// Cache automático
const { data } = useQuery({
queryKey: ['cycles'],
queryFn: fetchCycles,
staleTime: 5 * 60 * 1000,
})
Code Splitting¶
Lazy Loading de Rotas:
import { lazy, Suspense } from 'react'
const Cycles = lazy(() => import('./pages/cycles/Cycles'))
<Suspense fallback={<Loading />}>
<Cycles />
</Suspense>
Memoização¶
React.memo para componentes:
export const CycleCard = React.memo(({ cycle }) => {
return <div>{cycle.name}</div>
})
useMemo para cálculos:
const filteredCycles = useMemo(() => {
return cycles.filter(c => c.is_active)
}, [cycles])
Imagens¶
Otimizações: - Lazy loading de imagens - WebP quando possível - Tamanhos responsivos
Banco de Dados¶
Índices¶
Índices essenciais:
-- Foreign keys
CREATE INDEX idx_cycles_user_id ON cycles(user_id);
CREATE INDEX idx_observations_cycle_id ON observations(cycle_id);
-- Queries frequentes
CREATE INDEX idx_observations_date ON observations(date);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_user_type ON users(user_type);
Queries Otimizadas¶
Evitar N+1:
// ✅ Preload
db.Preload("User").Preload("Observations").Find(&cycles)
Paginação:
db.Offset((page - 1) * limit).Limit(limit).Find(&items)
API¶
Rate Limiting¶
Implementado: - OAuth: 5 requisições / 5 minutos - Geral: 100 requisições / minuto
Configuração:
rateLimitMiddleware := ratelimit.NewRateLimitMiddleware(100, time.Minute)
Compressão¶
Gzip para respostas grandes:
e.Use(middleware.Gzip())
Headers de Cache¶
Para recursos estáticos:
e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
Root: "static",
Browse: false,
Index: "index.html",
}))