Vibe Coder #4.3: Iterative Development – Fili Dilim Dilim Yemek
Ajanla çalışırken mesaj iki yerde bozuluyor: üst üste düzeltmelerde ve bağlam sıkıştırmasında. Çaresi işi tek cümlelik, kontrolü olan ve commit'le kapanan dilimlere bölmek; planı da sohbette değil diskte tutmak.
Bu yazının İngilizcesi de var →
Kod Medyumluğu yazısındaki on bir maddeden onuncusunu hatırlayın: kulaktan kulağa döngüsü. Ajan kod verir, kod hata verir, hatayı yapıştırırsınız, ajan düzeltir ama başka yeri bozar. Beşinci turdan sonra baştaki mantıktan eser kalmaz; login sayfası istemişsinizdir, elinizde hava durumu gösteren bir login sayfası vardır. O yazıda teşhisi koyup geçmiştik. Bu bölüm tedaviyi konuşuyor: iterative development, yani işi ajana küçük, doğrulanabilir dilimler hâlinde yaptırmak.
Bir önceki bölümde kuralları diske yazdık: anayasa kökte, iç tüzük klasörde, bekçi kapıda. Şimdi o kuralların altında işin kendisini nasıl böleceğimize bakıyoruz. Metafor eski bir şakadan: "Fil nasıl yenir? Dilim dilim." Filin tamamını tek lokmada ağza sokmaya çalışan ajan boğulmaz, daha kötüsünü yapar. Yuttuğunu sanır ve size "bitti" der.
Kulaktan kulağa nerede başlıyor?#
Çocuk oyununda mesaj her kulakta biraz bozulur ve sondaki çocuk bambaşka bir cümle söyler. Ajanla çalışırken bu bozulmanın iki kaynağı var ve ikisi de araçların kendi dokümanında yazıyor.
Birincisi düzeltme döngüsü. Claude Code'un en iyi uygulamalar sayfası bunu açıkça kural hâline getirmiş: aynı konuda bir oturumda ikiden fazla düzeltme yaptıysanız bağlam başarısız denemelerle dolmuştur; /clear ile temizleyip öğrendiklerinizi içeren daha net bir istemle baştan başlayın. Aynı sayfanın cümlesi: temiz bir oturum ve daha iyi bir istem, birikmiş düzeltmelerle dolu uzun bir oturumu neredeyse her zaman geçer.
İkincisi sıkıştırma. Bağlam penceresi dolmaya yaklaşınca Claude Code konuşma geçmişini kendiliğinden özetliyor. Codex'te /compact komutu görünen sohbeti özetleyip yer açıyor. Yani kırkıncı turda ajanın elindeki talimat, sizin yazdığınız cümle değil, o cümlenin özeti. Bir sıkıştırma daha olursa özetin özeti. Kulaktan kulağa oyununun ta kendisi; bu kez kulaklar aynı modelin ardışık hâlleri.
Teknik Detay: Claude Code dokümanı sıkıştırmanın neyi koruyacağını CLAUDE.md içine yazabileceğinizi söylüyor, örnek cümlesi de şu: sıkıştırırken değiştirilen dosyaların tam listesini ve test komutlarını her zaman koru. Faydalı, ama bir özetin içine "şunu unutma" yazmak, oyunu kazanmak değil, sadece kaybı yavaşlatmak. Lokal LLM bölümünde gördüğümüz 4.096 tokenlik sessiz pencereyi de ekleyin: pencere küçüldükçe aynı oyun daha az turda bozuluyor.
Bozulmayan tek mesaj diskte duran mesaj. Ajan onu kulağından değil, dosyadan okuyor.
Fil nasıl dilimlenir?#
Dilimin ölçüsünü yine Claude Code dokümanından alıyorum, çünkü bulduğum en net tanım orada: diff'i tek cümleyle anlatabiliyorsanız plana gerek yok, doğrudan yaptırın. Ben bunu tersinden kullanıyorum. Bir dilim, tek cümleyle anlatılabilen bir diff'tir. Anlatamıyorsanız dilim değil, fildir.
Her dilimin üç parçası var:
- Tek cümlelik amaç. "Ürün listesine sayfalama ekle", "ve filtre de olsun" değil.
- Çalıştırılabilir bir bitti kontrolü. Test,
php -l, bircurlçağrısı, bir SQL sorgusunun beklenen satır sayısı. Ajanın "baktım, oldu" demesi kontrol değil. - Bir commit. Kontrol geçince dilim kapanır, bir sonraki dilim temiz bir noktadan başlar.
Örnek fil: çerçevesiz PHP ile yazılmış bir yönetim panelinde ürün listesine filtre, sayfalama ve CSV dışa aktarma eklemek. Tek istemle verilince ajan sorguyu, şablonu, rotayı ve dışa aktarmayı aynı anda değiştirir; bir yer bozulduğunda hangi değişikliğin bozduğunu ne siz bilirsiniz ne o. Dilimlenmiş hâli projenin kökünde bir PLAN.md dosyası:
# Ürün listesi: filtre, sayfalama, CSV
Kural: her dilim ayrı commit. Kontrol geçmeden sonraki dilime geçilmez.
## Dilim 1: Sorguyu repository'ye taşı
- Bitti: tests/UrunRepositoryTest.php geçiyor, liste sayfası aynı 20 satırı veriyor.
## Dilim 2: Sayfalama (LIMIT/OFFSET, sayfa başına 20)
- Bitti: ?sayfa=3 iken 41-60 arası; toplam sayı tek COUNT(*) sorgusundan.
## Dilim 3: Kategori ve durum filtresi (PDO prepared statement)
- Bitti: filtre testleri geçiyor; ANALYZE çıktısında r_rows tahmine yakın.
## Dilim 4: CSV dışa aktarma (aynı filtreyle, akışla)
- Bitti: 10.000 satırlık dışa aktarma bellek tavanını aşmıyor.
## Öğrenilenler
- (Her temizlikten önce buraya bir satır yazılır.)
Son başlık önemli, birazdan geri döneceğim. Dilim 3'teki ANALYZE kontrolünü neden rows ile değil r_rows ile yaptığımı MariaDB index yazısında anlatmıştım.
Planı kim yazar, kim onaylar?#
Dört aracın dördünde de "önce plan, sonra kod" ayrımı için ayrı bir mod var. Adları farklı, fikir aynı: ajan okur ve önerir, siz onaylamadan dosyaya dokunmaz.
- Claude Code: plan modu.
Shift+Tabile durum çubuğunda plan modu görünene kadar geçiliyor ya da oturumclaude --permission-mode planile açılıyor. Ajan dosyaları okuyup soruları cevaplıyor, değişiklik yapmıyor.Ctrl+Gplanı metin editörünüzde açıyor; ajan başlamadan önce elle düzeltebiliyorsunuz. - Codex:
/plankomutu plan moduna geçiyor; komut tablosundaki tarif "uygulamaya başlamadan önce bir yürütme planı önermesini isteyin". - Cursor: Plan Mode kod tabanını araştırıyor, netleştirici sorular soruyor ve düzenleyebileceğiniz bir plan üretiyor. Planlar varsayılan olarak ev dizininizde saklanıyor; "Save to workspace" ile projeye taşınıyor.
- Antigravity: implementation plan bir artifact olarak geliyor. Plana yorum bırakıyorsunuz (kapsamı daralt, yığını değiştir), sonra Proceed ile devam ediyor ya da Review ile yorumları geri bildirim olarak gönderiyorsunuz.
Gizli Hazine: Cursor ve Antigravity'deki iki ayar tam da kulaktan kulağa meselesine dokunuyor. Cursor'un planı varsayılan olarak projenin dışında duruyor; "Save to workspace" demezseniz ekibin geri kalanı ve bir sonraki oturum o planı görmüyor. Antigravity dokümanı ise ajanın uygulamadan önce "genellikle" onay istediğini, ama artifact inceleme politikası "Always proceed" ise beklemediğini yazıyor. Plan kapısını bir ayarla kendiniz sökebiliyorsunuz.
Acı Gerçek: plan modu da bir ek yük. Claude Code dokümanı yazım hatası düzeltmek, log satırı eklemek, değişken adı değiştirmek gibi işlerde planı atlayıp doğrudan yaptırmayı öneriyor; plan, yaklaşımdan emin olmadığınızda, değişiklik birden fazla dosyaya dokunduğunda ya da kodu tanımadığınızda işe yarıyor. Her dilime plan modu açmak, her lokmadan önce menüyü baştan okumak gibi.
Her dilimin sonunda bir geri dönüş noktası#
Dilimin asıl değeri bozulduğunda ortaya çıkıyor: geri dönülecek temiz bir nokta var. Araçların kendi geri alma mekanizmaları var, ama sınırları dokümanda küçük puntoyla yazılmış.
| Araç | Geri dönüş | Sınırı |
|---|---|---|
| Claude Code | Her isteminizde otomatik checkpoint, /rewind ya da iki kez Esc |
Bash komutlarının değiştirdiği dosyaları izlemiyor; son 100 checkpoint; varsayılan saklama yaklaşık 30 gün |
| Cursor | Ajan önemli değişiklikten önce checkpoint alıyor, "Restore Checkpoint" | Yalnızca ajanın değişiklikleri; elle yaptıklarınız izlenmiyor; geri yükleme sohbeti değil yalnızca dosyaları geri alıyor |
| Aider | Her düzenlemeden sonra açıklamalı git commit'i, /undo |
Kapatmak için --no-auto-commits; commit atmadan çalışırsanız güvence de gider |
| Codex | /diff ile git farkı (izlenmeyen dosyalar dahil), /fork ile ayrı dal sohbet |
Komut tablosunda geri alma komutu yok; geri dönüş noktanız doğrudan git |
Teknik Detay: Claude Code dokümanındaki örnek tam olarak dilimi bozan türden: ajan rm, mv ya da cp çalıştırdıysa o değişiklik /rewind ile geri gelmiyor, çünkü checkpoint yalnızca ajanın dosya düzenleme araçlarıyla yaptığı değişiklikleri izliyor. Cursor dokümanı da aynı cümleyi farklı kelimelerle kuruyor: checkpoint sürüm kontrolü değil.
Bu tabloda tek ortak payda git. Aider bunu baştan tasarımına koymuş: her düzenleme bir commit, yani her dilim kendiliğinden bir geri dönüş noktası. Diğer araçlarda bu disiplini siz getiriyorsunuz: kontrol geçti, commit; kontrol geçmedi, git restore ve dilimi daha küçük kur.
Dilim büyüdü mü? Ölçün#
"Tek cümlelik diff" iyi bir kural, ama ajan çalışırken kimse satır saymıyor. Dilimin şiştiğini çoğu zaman commit mesajını yazmaya çalışırken fark ediyorsunuz: mesaj iki "ve" içeriyorsa geç kalmışsınız. Bunu göze bırakmamak için son commit'ten bu yana değişen dosya ve satırı sayan küçük bir betik yazdım. Çerçeve yok, düz PHP 8.3:
<?php
declare(strict_types=1);
/**
* Dilim ölçer: son commit'ten bu yana değişen dosya ve satırı sayar,
* dilim bütçesini aşınca 1 koduyla çıkar.
* Kullanım: php dilim-olcer.php [--dosya=6] [--satir=200]
*/
$secenek = getopt('', ['dosya::', 'satir::']);
$dosyaSiniri = (int) ($secenek['dosya'] ?? 6);
$satirSiniri = (int) ($secenek['satir'] ?? 200);
function git(string $komut): array
{
exec('git ' . $komut . ' 2>/dev/null', $cikti, $kod);
if ($kod !== 0) {
fwrite(STDERR, "git $komut başarısız (kod $kod). Bir git deposunda mısınız?\n");
exit(2);
}
return $cikti;
}
$dosyalar = [];
// İzlenen dosyalar: eklenen ve silinen satırlar (ikili dosyada "-" gelir).
foreach (git('diff --numstat HEAD') as $satir) {
[$eklenen, $silinen, $yol] = explode("\t", $satir, 3);
$dosyalar[$yol] = $eklenen === '-' ? 0 : (int) $eklenen + (int) $silinen;
}
// Henüz git'e eklenmemiş yeni dosyalar: bütün satırları yeni sayılır.
foreach (git('ls-files --others --exclude-standard') as $yol) {
$dosyalar[$yol] = is_file($yol) ? count(file($yol)) : 0;
}
$toplam = array_sum($dosyalar);
arsort($dosyalar);
printf("Dilim: %d dosya, %d satır (bütçe %d dosya / %d satır)\n", count($dosyalar), $toplam, $dosyaSiniri, $satirSiniri);
foreach (array_slice($dosyalar, 0, 5, true) as $yol => $adet) {
printf(" %5d %s\n", $adet, $yol);
}
if (count($dosyalar) > $dosyaSiniri || $toplam > $satirSiniri) {
echo "Bütçe aşıldı: bu dilim fazla büyük. Commit etmeden önce böl ya da geri al.\n";
exit(1);
}
echo "Dilim bütçe içinde. Testi çalıştır, geçerse commit et.\n";
exit(0);
Dört sınıflık bir deneme deposunda iki senaryoyla çalıştırdım. Bir sınıfta altı satırı değiştirip bir test dosyası ekleyince "2 dosya, 15 satır" deyip 0 ile çıktı. Üç sınıfı baştan sona değiştirip 120 satırlık yeni bir dosya ekleyince "6 dosya, 435 satır" deyip 1 ile çıktı. Git deposu dışında çağrılınca 2 ile çıkıyor. Teknik Detay: git diff --numstat değişen bir satırı bir silinen artı bir eklenen olarak sayıyor; altı satırlık değişiklik 12 görünüyor. Bütçeyi koyarken bunu hesaba katın. Betiği deponun kökünden çalıştırın, yollar oraya göre.
Betiği ajana nasıl taşıyacağınız 4.2'de konuştuğumuz anayasanın işi. Kökteki AGENTS.md dosyasına iki satır yetiyor:
## Dilim disiplini
- Her dilimden sonra `php dilim-olcer.php` çalıştır. 1 dönerse commit etme; dur ve dilimi bölmeyi öner.
- PLAN.md'deki "Bitti" kontrolü geçmeden sonraki dilime geçme.
Elle çalışırken de aynı kapı tek satır:
php dilim-olcer.php --dosya=6 --satir=200 && git commit -am "Dilim 2: sayfalama"
Sayılar benim keyfî seçimim, bir ölçüm değil. Beş satırlık bir yapılandırma dosyası değişikliği ile 200 satırlık bir sınıf aynı riski taşımıyor. Betik bir terazi, hâkim değil; size "bu lokma büyük" der, "yeme" demez.
İki düzeltmeden sonra temiz sayfa#
Kulaktan kulağa döngüsünü kıran asıl hamle, oyunu yeniden başlatmak. Claude Code'da /clear, Codex'te /new ya da /clear, Cursor ve Antigravity'de yeni bir sohbet. Ama boş bir sayfayla değil.
Temizlemeden önce PLAN.md dosyasındaki "Öğrenilenler" başlığına tek satır yazın: "Dilim 3'te ajan iki kez mysqli önerdi, projede yalnızca PDO var." Yeni oturum planı diskten okuyor, öğrenilen ders artık bir özetin içinde değil, dosyada. Claude Code dokümanının büyük işler için önerdiği akış da bu: önce ajanla tartışıp bir şartname dosyası yazdırmak, sonra uygulamayı temiz bağlamlı yeni bir oturumda başlatmak. Bu, 4.1'de konuştuğumuz şartnamenin dilim ölçeğindeki hâli.
Sonuç: sohbet geçmişi kısa süreli bellek, PLAN.md uzun süreli bellek. Kısa süreli bellek her sıkıştırmada biraz daha bulanıklaşıyor; dosya ise siz değiştirmedikçe aynı kalıyor.
Ne zaman işe yarar, ne zaman yaramaz?#
Yarar: birden fazla dosyaya dokunan her işte; tanımadığınız ya da eski bir kod tabanında; ajanı uzun süre gözetimsiz çalıştıracaksanız. Ne kadar uzun bırakıyorsanız dilimler o kadar küçük ve kontrolleri o kadar otomatik olmalı.
Yaramaz: tek cümlelik işlerde, yani zaten dilim olan işlerde. Keşif yaparken de yaramaz: "bu dosyada neyi iyileştirirdin?" gibi açık uçlu bir soruyu dilimlemeye çalışmak, ajanın size göstereceği beklenmedik yolu baştan kapatır. Planı keşiften sonra yazın, önce değil.
Bir de tuzak var: dilimleri o kadar küçültürsünüz ki her biri kendi içinde doğru, toplamı yanlış olur. On küçük commit, hiçbiri kötü değil, ama mimari kimsenin karar vermediği bir yere kaymış. Buna teknik borç diyoruz ve serinin bir sonraki bölümü, Vibe Coder #5.1: Teknik Borç ve Spagetti Kod – AI'ın Faizli Kredisi, tam olarak o faizin nasıl biriktiğine bakacak. Serinin tamamı ve yayınlanan bölümlerin listesi Vibe Coder El Kitabı sayfasında.
Fili tek lokmada yemeye çalışan ajan "bitti" der. Dilim dilim yiyen ajan her lokmada "bu kadarı bitti, kanıtı da bu" der. Siz ikincisini isteyin. Teknolojiyle kalın.
Yorumlar
0 yorum
Yorum yazın