Free

Tek commit'te 3.000 satır: karmaşık özellikler neden önce plan mode ister

Karmaşık özellikler karşısında içgüdü "bir şeyler deneyeyim"dir — ama mimari kararlar 3. modelde, 5. edge case'de gizlidir. Plan mode'un gerçek değeri mimari seviyedeki konuşmayı koddan önce metne taşımaktır. Gerçek vaka: Pickful'un topluluk jüri sistemi — 3.032 satır, 119 spec yeşil, tek commit, sonrasında sıfır mimari yeniden çalışma.


Karmaşık bir özellikle karşılaşınca çoğu kişinin içgüdüsü "bir şey deneyeyim" olur.

Sorun şu: karmaşık sistemlerin bir özelliği var — mimari kararlar 3. modelin içinde, 5. edge case'de, 8. puan kuralında saklı. Koda kafayı gömüp o kararlara ortada çarpınca, geri dönüp değiştirmek, başlangıçta metin düzeyinde konuşup çözmekten 10× daha pahalıya mal olur.

Claude Code'un plan mode'unu Pickful'daki TopicReview topluluk jüri sistemini kurmak için kullandım ve bu eşitsizliğin uç versiyonunu gördüm: tek commit, 3.032 satır, 119 spec yeşil, tek seferde yayına. Sonra gelen on küsur commit'ten hiçbiri mimari yeniden yapım değil — hepsi parametre ince ayarı, UI cilalama, edge case yamaları. Sistem o zamandan beri düzenli çalışıyor ve artık topluluğun kendini nasıl modere ettiğinin merkezi.

Bu yazı şunu anlatıyor: karmaşık özellikler neden önce plan mode ister, plan aşaması aslında ne yapıyor ve konuşma ne kadar olgunlaşınca kod yazmaya başlamak doğru olur.

Sistem ne kadar karmaşık

TopicReview, düşük kaliteli bir gönderinin kaldırılıp kaldırılmayacağına karar veren bir topluluk oylamasıdır. Bir cümleyle özet — ama spec katman katman açılır:

  • 5 durum: open → voting → decided → appealed → closed
  • 3 karar: remove / warn / keep
  • 2 aşama: ilk derece 12 jüri üyesinin oyu; itiraz 5 yargıç tarafından (puanca ilk 20 kullanıcı arasından çekilir)
  • Çok boyutlu puan akışı: 10 pt geçici ceza, 10 pt itiraz stake'i, çoğunlukla oy vermiş jüri için +5, çoğunlukla oy vermiş yargıç için +10, raporu haklı çıkan rapor eden için +3, kazanılan itirazda iade = stake + bonus + geçici ceza
  • 4 tür zamanlanmış iş: 24h ilk oylama penceresi, 24h itiraz penceresi, 24h itiraz inceleme penceresi ve — remove kararından sonra jüri puanları 24h ertelenir (çünkü itiraz bozabilir)
  • Paralel akışlar + rollback: geçici kaldırma sırasında oylar dönerse, gönderi geri yüklenip geçici ceza iade edilir; itiraz kararı bozarsa stake artı bonus iade edilir, belki geçici ceza da döner, ve jüriler yeni karara göre yeniden puanlanır

Karmaşıklığın özü herhangi bir tekil kuralda değil — kuralların birbiriyle nasıl etkileştiğinde. Eklenen her kural başka bir yerde rollback tetikleyebilir.

Plan olmadan çarpacağın duvarlar

Düz düz yazdığında en zor problemler görünen gerçekler değildir — sormayı akıl etmediğin sorulardır. TopicReview'un kodunu tersten okuyunca, plan'ı atlarsan kesinlikle çarpacağın en az dört duvar vardır:

Jüri uygunluk kuralları. Yüzeyde sadece User.jurors_and_judges.sample(12) gibi görünür. Ama gerçek kurallar şunlar: gönderi yazarını dışla, gönderiyi raporlayanı dışla, ilk turda oy vermiş olanı dışla (aynı kişinin itirazda da oy vermemesi için). Üç katmanlı dışlama. Modeli tek seferde yazarsan, birini ikisini kaçırırsın.

Gecikmeli puan dağıtımı. Remove kararı normalde jüri ödemelerini tetikler. Ama itiraz remove'u bozabilir — bozunca eski kararla oy verenler yanlış tarafta kalır ve ödemelerin yeni karara göre yeniden hesaplanması gerekir. Dolayısıyla remove kararı 24 saatlik itiraz penceresi kapanmadan jüri ödemesi yapmamalı. Bu kuralı yazmadan önce ödersen, sonra puan geri almak zorunda kalırsın — geciktirerek ödemekten 10× daha zahmetlidir.

Zamanlanmış iş arayüzü tasarımı. CloseTopicReviewJob "bir review'u bitir" gibi görünür. Pratikte üç durumu ele alır:

# İlk oylama penceresinin süresi dolar
CloseTopicReviewJob.set(wait_until: voting_ends_at).perform_later(review.id)
# Remove kararı sonrası gecikmeli jüri ödemesi
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, award_juror_points: true)
# İtiraz penceresinin süresi dolar
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, appeal_id: appeal.id)

Önceden planlamadan, ilk imzayı yazarsın, 2. durumda arayüzün değişmesi gerektiğini fark edersin.

En pahalı duvar: geçici kaldırma sırasında itiraz edilebilir mi? Remove oyları eşiği aşınca gönderi gizlenir (geçici), ama review hâlâ voting durumunda — decided değil. Kullanıcı şimdiden itiraz edebilir mi?

  • Edebilir → decided ile appealed arasındaki geçişleri genişletmek zorundasın
  • Edemez → UX kötü: gönderi gizli ve kullanıcı protesto için 24h beklemek zorunda
  • TopicReview'un gerçek tercihi: evet, geçici kaldırma sırasında itiraza izin veriliyor — ama review önce finalize → decided geçişinden geçmeli, ardından itiraz açılmalı

Bu tek karar geriye doğru open_appeal! içindeki parametre kontrollerini ve state machine mantığını değiştirir. Yarı yolda karar vermek = sistemin yarısını yeniden yazmak.

Plan aşaması aslında ne yapıyor

Claude Code'un plan mode'u, kod yazmanın yasak olduğu bir moddur — Claude repo'yu okuyabilir, yaklaşım düşünebilir, seninle tartışabilir; ama sen bir plan onaylayana dek dosya değişikliği hard-block'lanır.

O mekanik kısıt meselenin özü: mimari düzeydeki konuşmanın metinde gerçekleşmesini zorlar.

Plan aşamasının pratikte yaptıkları:

1. State machine ve rolleri çizmek. 5 durum, 4 rol (jüri / yargıç / gönderi yazarı / rapor eden), her rolün her durumda ne yapıp yapamayacağı — hepsi birkaç satır markdown. Birkaç satır vs. düzinelerce dosya. Değişiklik maliyeti iki büyüklük mertebesi farklı.

2. Her rolün akışını adım adım yürütmek:

  • Jüri: bildirim alır → review'u açar → gönderiyi ve nedeni okur → reasoning ile oy verir → puan alır
  • Gönderi yazarı: bildirim alır → kararı görür → remove ise itirazı düşünür → stake koyar → bekler
  • Yargıç: top-20'den çekilen itirazı alır → oy verir → puan alır

Yürüyüş nerede takılırsa gizli bir soru anında çıkar: "jüri üyeleri birbirlerinin oylarını görebilir mi?", "yazar geçici kaldırma sırasında ne yapabilir?"

3. Edge case sorgusu. Plan aşaması "normal yolu" tasarlamaz — bilerek normalde akla gelmeyen soruları sorar:

  • Pencere dolduğunda 0 oy varsa? (Nihai karar: varsayılan keep.)
  • İtiraz dolduğunda 0 oy varsa? (dismissed; stake yakılır.)
  • Bir yargıç kendi raporladığı post'a oy verebilir mi? (Hayır — aynı dışlama kuralı.)
  • Birden fazla jüri aynı anda finalize tetiklerse, race çift ödeme yapar mı? (İdempotans için bir juror_points_awarded alanı ekle.)

Bu soruların %95'i kod yazarken kendiliğinden gün yüzüne çıkmaz. Plan aşaması seni teker teker cevaplamaya zorlar.

4. Puan defteri. Puan sistemi tartışmayla yetinilemeyecek kadar karmaşık — gerçekten tablo çizmelisin: her puan akışını tetikleyici + miktar + rollback yolu ile. Defter denk gelince tüm edge case'ler (geçici iade, itiraz iadesi, bonus) uzlaşır.

Koda başlamak için ne kadar konuşmuş olmak yeterli

Sert bir kıstas:

  • Her yolu tıkanmadan adım adım yürüyebiliyorsun — review'u açmaktan closed'a her kombinasyon (keep / remove / warn × itirazlı / itirazsız × geçici / değil) — baştan sona anlatabiliyorsun
  • Her edge case için tanımlı davranış var — "duruma bakarız" değil, "0 oy varsayılan keep", "geçici sırasında itiraz izinli ama önce finalize"
  • "Ah, onu henüz düşünmedim" yok — formüle edebildiğin her sorunun cevabı hazır

O çıtaya ulaşınca kod yazmak planı Ruby'ye çevirmeye dönüşür.

Tek seferde yürütme fazının görünüşü

Bu sistemin ilk gönderimi:

d162f1e Add community moderation system with jury/judge review and appeals
  63 files changed, 3032 insertions(+)
  119 specs, 0 failures

63 dosya, 3.032 satır, 119 spec yeşil. Tek seferde yayına.

Sonraki on küsur commit mimarinin dayandığını kanıtlıyor:

Apply legacy penalty (1pt) for posts created before 2026-03-26
Fix topic review appeal bugs: window mismatch and verdict not updated
Add topic_removed status for posts removed by community review
Default to keep verdict when review expires with zero votes
Reduce provisional removal penalty to 1pt during trial period
Allow topic creator to withdraw active reviews
Add handled tab to jury dashboard, fix tabs styling

Her biri ince ayar / düzeltme / cilalama / küçük özellik. Hiçbiri "state machine'i yeniden tasarlayalım" veya "puan modeli değişmeli" değil. İskelet doğruydu.

Plan'ın gerçek getirisi bu: yürütme kesintisiz. "Dur, bu yol nasıl işliyor" yok — plan kapsamış. "Bu edge case'i düşünmedim" yok — plan aşaması sormuş. "Bu arayüz yeniden tasarlanmalı" yok — plan çözmüş.

Saatlerce kod yazma, tek bir iş yapma: net tasarımı klavyeye aktarma.

Plan'ı ne zaman kullanmamalı

Her görev plan'a değmez:

  • Basit bug düzeltmeleri — tespit + düzelt + regresyon testi ekle; önden tartışma gerekmez
  • Mekanik refactor'lar — ad değiştir, fonksiyon çıkar, dosya taşı; tek yol, plan ekstra adım
  • Yalnızca tek bir açık yol — bir GET endpoint eklemek, bir UI toggle; tartışılacak bir şey yok
  • Keşif amaçlı prototipler — ne istediğini kendin bilmiyorsun; kaba bir versiyonu çalıştırmak daha fazla düşünmekten iyi

Plan mode'un getirisi yeniden yazma maliyetini düşürmekten gelir. Görevde yeniden yazma riski yoksa, plan yalnızca yüktür.

Kapanış

"Önce düşün, sonra yap" bir karakter tavsiyesi gibi gelir. Plan mode bu değil.

Plan mode, mimari düzeydeki konuşmanın 10 kelimeyle değiştirilebilecek bir yerde olmasını sağlar — 30 dosya değiştirilmesi gereken yerde değil.

Karmaşıklık altında, yazılım endüstrisinin eski sözü "words are cheap, code is expensive" tersine çevrilmeli — "önce kod yaz, sonra görürüz" anlamına gelmez (bu yalnızca maliyet farkı küçükken geçerlidir). O maliyet farkını kullanmak demektir: pahalı konuşmayı öne, ucuz medyuma almak.

3.000 satırı tek commit'te yayına vermek harika bir his. Hızlı yazdığım için değil — plan "yazmayı" tamamen mekanik bir eyleme dönüştürdüğü için.