Ottimizzazione del Codice con Claude Sonnet 3.5

Dopo aver esplorato le tecniche avanzate di pair programming, vediamo come sfruttare Claude per ottimizzare le performance del nostro codice. A differenza degli strumenti tradizionali di profiling, Claude può suggerire ottimizzazioni contestuali basate su pattern ricorrenti e best practice.
Analisi delle Performance
Ecco un dialogo reale con Claude per l’ottimizzazione di un endpoint REST:
Dev: Il mio endpoint /users sta diventando lento con l'aumentare degli utenti. Ecco il codice:
@Get('/users')
async getUsers(@Query() filters: UserFilters) {
const users = await this.userRepository.find({
where: filters,
relations: ['posts', 'comments', 'profile']
});
return users.map(user => ({
...user,
postCount: user.posts.length,
commentCount: user.comments.length
}));
}
Claude: Il codice presenta diverse aree di ottimizzazione:
1. State caricando tutte le relazioni anche quando servono solo i conteggi. Possiamo usare subquery per i conteggi:
@Get('/users')
async getUsers(@Query() filters: UserFilters) {
const users = await this.userRepository
.createQueryBuilder('user')
.select([
'user',
'(SELECT COUNT(*) FROM posts WHERE posts.userId = user.id) as postCount',
'(SELECT COUNT(*) FROM comments WHERE comments.userId = user.id) as commentCount'
])
.where(filters)
.getMany();
return users;
}
Questo riduce significativamente il carico di dati e migliora le performance. Vuoi che aggiunga anche paginazione e caching?
Dev: Sì, mostrami come implementare entrambi
Claude: Ecco la versione ottimizzata con paginazione e caching:
@Get('/users')
@CacheKey('users-list')
@CacheTTL(300) // 5 minuti
async getUsers(
@Query() filters: UserFilters,
@Query('page') page = 1,
@Query('limit') limit = 10
) {
const cacheKey = `users-${page}-${limit}-${JSON.stringify(filters)}`;
const cached = await this.cacheManager.get(cacheKey);
if (cached) {
return cached;
}
const [users, total] = await this.userRepository
.createQueryBuilder('user')
.select([
'user',
'(SELECT COUNT(*) FROM posts WHERE posts.userId = user.id) as postCount',
'(SELECT COUNT(*) FROM comments WHERE comments.userId = user.id) as commentCount'
])
.where(filters)
.skip((page - 1) * limit)
.take(limit)
.getManyAndCount();
const result = {
users,
meta: {
total,
page,
limit,
pages: Math.ceil(total / limit)
}
};
await this.cacheManager.set(cacheKey, result);
return result;
}
Dev: Come gestisco l'invalidazione della cache quando un utente viene modificato?
Claude: Ecco come gestire l'invalidazione della cache in modo intelligente:
@EventSubscriber()
class UserCacheInvalidator {
@OnEvent('user.updated')
@OnEvent('user.created')
@OnEvent('user.deleted')
async invalidateCache(payload: UserEvent) {
// Invalida solo le chiavi correlate all'utente specifico
const keys = await this.cacheManager.store.keys('users-*');
const userKeys = keys.filter(key =>
key.includes(`userId-${payload.userId}`)
);
await Promise.all(
userKeys.map(key => this.cacheManager.del(key))
);
// Invalida anche la lista principale
await this.cacheManager.del('users-list');
}
}
Memory Leaks e Debugging
Claude eccelle nell’identificare potenziali memory leaks. Ecco un esempio:
Dev: Ho un memory leak in questa WebSocket service:
@WebSocketGateway()
export class NotificationGateway {
private clients = new Map();
handleConnection(client: Socket) {
const userId = client.handshake.query.userId;
this.clients.set(userId, client);
}
handleDisconnect(client: Socket) {
// TODO: cleanup
}
}
Claude: Il problema è che non state rimuovendo i client disconnessi dalla Map. Ecco la versione corretta:
@WebSocketGateway()
export class NotificationGateway {
private clients = new Map();
handleConnection(client: Socket) {
const userId = client.handshake.query.userId;
this.clients.set(userId, client);
// Cleanup automatico
client.on('disconnect', () => {
this.clients.delete(userId);
});
}
// Aggiungi monitoraggio
@Interval(60000) // ogni minuto
async cleanupStaleConnections() {
for (const [userId, client] of this.clients.entries()) {
if (!client.connected) {
this.clients.delete(userId);
}
}
}
}
Aggiungi anche logging per tracciare le connessioni attive:
@Inject(Logger)
private logger: Logger;
handleConnection() {
// ...
this.logger.debug(
`Active connections: ${this.clients.size}`,
'NotificationGateway'
);
}
Query Optimization
Claude può analizzare piani di esecuzione delle query e suggerire ottimizzazioni:
Dev: Questa query sta diventando lenta:
SELECT p.*,
c.name as category_name,
COUNT(r.id) as review_count,
AVG(r.rating) as avg_rating
FROM products p
LEFT JOIN categories c ON c.id = p.category_id
LEFT JOIN reviews r ON r.product_id = p.id
WHERE p.price > 100
GROUP BY p.id, c.name
ORDER BY avg_rating DESC;
Claude: La query può essere ottimizzata in diversi modi:
1. Utilizzo di indici compositi:
CREATE INDEX idx_product_price ON products(price) INCLUDE (category_id);
CREATE INDEX idx_reviews_product ON reviews(product_id) INCLUDE (rating);
2. Query ottimizzata:
WITH product_reviews AS (
SELECT product_id,
COUNT(*) as review_count,
AVG(rating) as avg_rating
FROM reviews
GROUP BY product_id
)
SELECT p.*,
c.name as category_name,
COALESCE(pr.review_count, 0) as review_count,
pr.avg_rating
FROM products p
LEFT JOIN categories c ON c.id = p.category_id
LEFT JOIN product_reviews pr ON pr.product_id = p.id
WHERE p.price > 100
ORDER BY pr.avg_rating DESC NULLS LAST;
La CTE pre-aggrega i dati delle recensioni, riducendo il numero di join necessari. NULLS LAST migliora l'ordinamento per prodotti senza recensioni.
Dev: Posso vedere il piano di esecuzione prima e dopo?
Claude: Ecco l'analisi dei piani di esecuzione:
Query originale:
- Seq Scan su reviews
- Hash Join con products
- Sort per avg_rating
- Group By con sort
Costo stimato: 1245.67
Query ottimizzata:
- Index Scan su products (usando idx_product_price)
- Index Scan su reviews (usando idx_reviews_product)
- Hash Join con CTE
- Sort solo sul risultato finale
Costo stimato: 456.89
L'ottimizzazione riduce il costo del 63%. Vuoi che analizziamo anche i tempi di risposta reali?
Conclusione
L’ottimizzazione con Claude richiede un dialogo iterativo. Fornisci sempre metriche concrete e casi d’uso reali per ottenere suggerimenti più pertinenti. Nel prossimo articolo vedremo come utilizzare Claude nello sviluppo web.