Free

Claude'a Fikrini Değiştirtmek

Claude'un "daha hafif" önerisi gizli maliyetler taşıyordu. Tek bir geri soru hepsini ortaya döktü.


smarts üzerinde çalışıyordum — Ethereum akıllı kontratlarını "geliştirici dokümantasyonu" olarak render eden bir Rails uygulaması. Geçen gün eski bir sorunla yine karşılaştım: kontratlar yükseltilebilir. Sistem yükseltilmiş bir proxy kontratı eski bir ABI'yle render ederse, kullanıcıya yalan söylüyor demektir.

Claude'dan proxy yükseltme tespitini birlikte tasarlamasını istedim. EIP-1967, Beacon proxy ve ZeppelinOS uyumlulukları dahil sağlam bir teknik plan çıkardı. "Kontrolü ne zaman tetikleyelim" aşamasına geldiğimizde iki seçenek sıraladı:

# Seçenek A: DB'ye last_proxy_check_at ekle, 5dk throttle
if @contract.last_proxy_check_at.nil? || @contract.last_proxy_check_at < 5.minutes.ago
  CheckProxyUpgradeJob.perform_later(@contract)
end

# Seçenek B: Solid Cache üzerinden throttle, daha hafif
unless Rails.cache.exist?("proxy_check:#{@contract.id}")
  Rails.cache.write("proxy_check:#{@contract.id}", true, expires_in: 5.minutes)
  CheckProxyUpgradeJob.perform_later(@contract)
end

Kapanış cümlesi:

B daha sade, kolon eklemeye gerek yok.

İki snippet'e bir süre baktım. B gerçekten daha sadeydi, migration yok, hep cache çağrısı, çok Rails-tarzı. Ama içime sinmedi.

Beş karakter yazdım, enter'a bastım:

a önerir misin?

Claude yeniden hesapladı

Cevabı (birkaç kod bloğu kırpıldı):

Fikrimi değiştiriyorum — A öneriyorum.

Sebep: proxy tespitinin tüm amacı ABI tazeliğine güvenmemek. Solid Cache üzerinden throttle yaparsak, "kontrol ettik mi?" bilgisini yine uçucu depolamaya koymuş oluyoruz:

  • Deploy / cache wipe sonrası tüm kontratlar aynı anda "kontrol edilmemiş" durumuna düşer → bir sonraki trafik dalgası kontrol fırtınası tetikler
  • "Bu kontrat en son ne zaman yeniden doğrulandı?" sorusuna cevap yok
  • Zamanlanmış emniyet kemeri kurulamaz: az ziyaret edilen kontratlar haftalarca trafiksiz kalabilir, lazy tetikleyici hiç ateşlenmez

last_proxy_check_at kolonunu eklemenin açtığı şeyler:

  1. Lazy tetikleyici (B ile aynı mantık)
  2. recurring.yml ile zamanlanmış emniyet: 24 saatten eski kontratları kullanıcı trafiğinden bağımsız olarak toplu kuyruğa atar
  3. UI'da tazelik göstermek: "Implementation verified 12 min ago"

Maliyet: bir migration + her job sonunda bir update_column (callback'siz, neredeyse bedava).

Kısaca: B "daha Rails-native, daha hafif" görünüyor ama bir yetenek katmanı eksik. A, "ABI tazeliğine güvenmiyoruz" işini gerçekten hayata geçiren seçenek.

İki öneri arasında ne olduğuna dikkat et:

  • Birinci geçiş: seçenekleri sırala → kod hacmini karşılaştır → B'yi seç ("daha sade")
  • İkinci geçiş: bunu neden yapıyoruz sorusuna sabitlen → B'nin durumu uçucu depolamaya koyduğunu ve "ABI tazeliğine güvenmemek" önermesiyle çeliştiğini fark et → A'yı seç

İki geçiş arasında yeni bir gerçek girmedi. Kod hacmi, Rails idiom'ları, cache semantiği — hepsi aynı. Değişen tek şey, değerlendirirken hangi katmanda durduğu.

İlk geçiş kod hacmini karşılaştırıyordu. İkincisi "bu değişiklik aslında çözmek istediğimiz problemi çözüyor mu?" sorusunu karşılaştırıyordu.

Beş karakterin yaptığı

"a önerir misin?" yazdığımda onu hiçbir yere itmeye çalışmıyordum. B'nin kodunda takılıp kalmıştım ve içgüdüsel olarak tercihini tekrar sordum.

Ama etkisi, onu "iki seçenekten birini seç" modundan "neden bunu yapıyoruz?" moduna çekmek oldu. İşte tüm mesele bu fark.

LLM'ler öneri verirken neredeyse her zaman yerel optimumlardan başlar: hangi diff daha küçük, hangi snippet daha idiomatic, hangi implementasyon daha temiz okunuyor. Bunlar gerçek eksenler. Ama çoğu zaman bu PR'nin gerçekte ne için olduğu ile bağlantı kurmaz.

A ve B "5 dakika throttle" ekseninde eşdeğer. Ama A bunun yanında B'nin yapamayacağı üç şey daha açıyor — zamanlanmış emniyet, gözlemlenebilirlik, UI'da tazelik. Sadece throttle katmanına bakıyorsan B kazanır. Bu job'ın neden var olduğunu önemsiyorsan A kazanır.

Claude bu katmanı ilk seferde görmedi, beceremediği için değil. "Bu seçenekleri karşılaştır"ın varsayılan çerçevesi sözdizimi/Rails katmanı olduğu için. Tek bir karşı-soru onu problem katmanına çekti ve oradan B'nin maliyetlerini kendisi hesapladı.

Bunu alışkanlığa dönüştürmek

Kendi workflow'umda yaptığım birkaç küçük ayar:

Claude "daha sade / daha hafif / daha native" diyerek bitirdiğinde, bir kez daha bak. Bunlar estetik kelimeler, yargı kelimeleri değil. Neyin iyi okunduğunu anlatırlar, neyin yük altında ayakta kaldığını değil.

Tekrar sormanın maliyeti sıfır. "X önerir misin?" — beş karakter. Claude almadığı bir açıdan değerlendirmek zorunda kalır. Aynı öneriye dönse bile gerekçe daha sağlam olur, ona güvenip güvenmeyeceğine karar vermek için yeterli.

Sadece öneriyi değil, maliyetleri de açtırt. Bu seferki iyi sonuç ben A'yı zorla geçirdiğim için değildi — Claude'un B'nin gizli maliyetlerini (cache wipe fırtınası, gözlemlenebilirlik eksikliği, zamanlanmış işler için çıkmaz sokak) yazıya dökmesindendi. O yazana kadar ben de hiçbirini ifade edememiştim.

Sonunda A'yı çıkardım: last_proxy_check_at kolonunu ekledim, lazy tetikleyici artı 24 saatlik zamanlanmış emniyet, UI'da artık Implementation verified 12 min ago satırı var. Üç gün sonra, alakasız bir iş üzerinde çalışırken, bu kolon bana Contract.where("last_proxy_check_at < ?", 24.hours.ago).find_each sorgusunu yazma imkânı verdi — B'yle var olamayacak bir sorgu.

Beş karakterlik bir karşı-soru, kabaca bir hafta sonraki bir refactoring değerinde.