
AI Junior Geliştiricileri Ortadan Kaldırmadı. Fake Senior Kod Üretti.
Bariz şekilde bozuk kodu reddetmek kolaydır. Daha zor olan, düzenli görünen ama üretim kurallarını atlayan koddur.
Bu çalışma küçük bir Laravel projesi kullanıyor. Bir kullanıcı başka bir kullanıcıya bakiye gönderiyor. Aynı özellik iki kez yazıldı: biri temiz görünen ama eksik sınırları olan servis, diğeri validation, authorization, transaction, row lock, failure records, logs ve testleri açıkça uygulayan servis.
Çalışma komutu iki servisi de 16 senaryodan geçiriyor. Fake servis 9 senaryoyu geçti, 7 senaryoda kaldı ve 100 üzerinden 51.7 aldı. Gerçek servis 16 senaryonun tamamını geçti ve 100 aldı.
İddia
Sorun AI'ın kötü kod üretebilmesi değil. Kötü kod AI'dan önce de vardı. Buradaki risk, kodun üretim kurallarını karşılamadan tamamlanmış gibi görünmesi.
Bu projedeki fake implementasyon saçma yazılmış bir örnek değil. Service class var. Ortak result object var. İsimler okunabilir. Amount numeric mi diye bakıyor. Negatif amount reddediliyor. Başarılı işlem için transaction kaydı yazılıyor. Happy path çalışıyor.
Ama cüzdan transferi için bu yeterli değil. Harcama yetkisi kontrol edilmeli. Sıfır amount reddedilmeli. Kullanıcının kendisine transfer engellenmeli. Failure kaydı bırakılmalı. Sender ve receiver wallet güncellemeleri tek database transaction içinde yapılmalı.
Dış Bağlam
AI coding araçlarıyla ilgili sonuçlar tek yönde değil. GitHub Copilot productivity study, sınırlı bir JavaScript HTTP-server görevinde daha hızlı tamamlama raporladı. Buna karşılık METR'nin deneyimli open-source geliştiricilerle yaptığı çalışma, geliştiricilerin bildikleri repositorylerde AI araçları açıkken daha yavaş tamamladığını buldu.
Stack Overflow 2025 AI Developer Survey, AI çıktısının doğruluğuna güvenmeyen geliştiricilerin güvenenlerden fazla olduğunu gösterdi. DORA 2025 State of AI-assisted Software Development report da benzer bir noktaya gelir: sonuç sadece araçla değil, aracın çalıştığı mühendislik sistemiyle ilgilidir.
Bu proje daha dar bir soruya bakıyor: Tek bir Laravel servisi 16 açık backend kontrolünden geçiyor mu?
Proje Yapısı
Projenin adı fake-senior-code-laravel-wallet. Çalıştırılabilir bir Laravel uygulaması. İçinde migrations, models, services, policy, tests, scoring helper ve Artisan command var.
Domain, Laravel'in varsayılan users tablosunu ve iki ek tabloyu kullanıyor:
wallets: her kullanıcı için bir cüzdan ve decimal balance.wallet_transactions: başarılı veya başarısız her transfer denemesi için kayıt.
İki servis de aynı public method'u kullanıyor:
public function transfer(
User $actor,
int $senderId,
int $receiverId,
mixed $amount
): TransferResult;Karşılaştırma bu yüzden net. Aynı input. Aynı beklenen davranış. Fark implementasyonda.
Cüzdan Transfer Kontratı
Bu benchmark tam bir ödeme sistemi modellemiyor. Basit bir cüzdan transferinde eksik olmaması gereken backend kurallarını kontrol ediyor.
| Öğe | Kural |
|---|---|
actor | Sender wallet üzerinden harcama yetkisi olmalı. |
sender_id | Var olan ve yeterli bakiyesi olan bir wallet'a işaret etmeli. |
receiver_id | Var olan bir wallet'a işaret etmeli ve sender ile aynı olmamalı. |
amount | Numeric, sıfırdan büyük ve iki decimal hassasiyetinde olmalı. |
| Balance update | Debit ve credit tek database transaction içinde yapılmalı. |
| Wallet rows | Yeni balance hesaplanmadan önce satırlar lock edilmeli. |
| Failure path | Başarısız denemeler reason ile kaydedilmeli. |
İki Servis
FakeSeniorTransferService ilk bakışta kabul edilebilir görünür. Amount numeric mi diye bakar, negatif amount'u reddeder, sender ve receiver wallet'ları bulur, balance kontrol eder, bakiyeleri günceller ve başarılı transaction kaydı yazar.
Eksikler burada başlıyor:
Authorization yok. Bir actor başka kullanıcının wallet'ından harcayabilir.
0.00başarılı transfer kabul edilir.Kullanıcının kendisine transferi serbesttir ve balance bozulabilir.
DB::transactionyok.lockForUpdateyok.Birçok failure case
wallet_transactionstablosuna yazılmaz.
RealSeniorTransferService aynı özelliği açık kurallarla uygular: amount normalization, self-transfer rejection, actor ownership, wallet policy, wallet existence checks, transaction wrapper, row locking, failed transaction rows ve warning logs.
Senaryo Protokolü
php artisan wallet:fake-senior-study komutu her case için yeni users ve wallets oluşturur. Sonra iki servisi aynı senaryodan geçirir ve sonucu skorlar.
Ölçülen senaryo sayısı:
S = 16Ana senaryolar:
successful transfer
insufficient balance
transfer to self
zero amount
negative amount
missing sender wallet
missing receiver wallet
unauthorized transfer attempt
repeated transfer attempt
transaction history consistency
failure reason logging
balance unchanged after failed transfer
Skorlama
Production Readiness Score ağırlıklı bir checklist kullanır:
PRS =
0.20 Validation
+ 0.20 Authorization
+ 0.20 Database Consistency
+ 0.15 Failure Handling
+ 0.15 Test Coverage
+ 0.10 MaintainabilityHer kategori şu şekilde hesaplanır:
Category Score = Passed Checks / Total Checks x 100Ölçülen Sonuçlar
Proje yerelde şu komutlarla çalıştırıldı:
php artisan test
php artisan wallet:fake-senior-study --jsonTest sonucu: 20 test ve 72 assertion geçti.
| Servis | Geçti | Kaldı | Skor |
|---|---|---|---|
| Fake Senior Code | 9 | 7 | 51.7 / 100 |
| Real Senior Code | 16 | 0 | 100 / 100 |
Ana senaryo sonucu:
| Senaryo | Fake | Real |
|---|---|---|
| Happy path result | PASS | PASS |
| Transfer to self | FAIL | PASS |
| Zero amount | FAIL | PASS |
| Negative amount | PASS | PASS |
| Insufficient balance | PASS | PASS |
| Missing sender wallet | FAIL | PASS |
| Missing receiver wallet | FAIL | PASS |
| Unauthorized transfer attempt | FAIL | PASS |
| Repeated transfer attempt | PASS | PASS |
| Transaction history consistency | FAIL | PASS |
| Failure reason logging | FAIL | PASS |
| Balance unchanged on failed transfer | PASS | PASS |
Bazı Skorlar Neden Aynı?
Fake servis ölçülen database consistency kategorisinde 100% aldı. Bu, production traffic altında güvenli olduğu anlamına gelmez.
Bu kategori sadece sequential case'leri kontrol etti: başarı sonrası balance, insufficient balance, repeated transfer ve failed transfer. Fake servis bunları geçti. Ama hâlâ DB::transaction ve lockForUpdate yok. Bu benchmark aynı sender wallet'a paralel worker çalıştırmıyor.
Sonraki benchmark bu kategoriyi ikiye ayırmalı:
sequential consistency
concurrency safety
Test coverage ve maintainability de eşit görünüyor çünkü iki servis de aynı method'u açıyor ve TransferResult döndürüyor. Bu önemli: fake senior code yapılı görünebilir, ama yine de kritik kuralları uygulamayabilir.
Sayıları Okumak
Fake servis 16 senaryonun 9'unu geçti. Bu geçişler gerçek. Happy path çalışıyor. Negative amount reddediliyor. Basit insufficient-balance case'i balance'ları değiştirmiyor.
Ship etmek için daha önemli olan failure'lar. Unauthorized transfer çalışıyor. Zero amount başarılı kabul ediliyor. Self-transfer balance'ı bozabiliyor. Missing-wallet failure kaydedilmiyor. Failure reason saklanmıyor. Update path'te transaction veya row lock yok.
Real servis 16 senaryonun tamamını geçti. Bu onu tam bir ödeme sistemi yapmaz. Sadece bu projede tanımlanan kontratı karşıladığını gösterir.
Pratik Notlar
Benchmark SQLite kullanıyor. Bu pattern production'a taşınacaksa locking davranışını ve performansı MySQL veya PostgreSQL üzerinde ayrıca kontrol etmek gerekir.
Concurrency senaryosu tam paralel load testi değil. Real serviste transaction ve row-lock boundary olduğunu doğruluyor, repeated transfer davranışını sequential olarak kontrol ediyor. Sonraki versiyon aynı wallet'a paralel request çalıştırmalı.
Gerçek bir wallet sistemi ayrıca idempotency keys, immutable ledger rows, currency handling, retry behavior, reconciliation ve daha güçlü audit kuralları ister.
Sonuç
Ölçülen sonuç basit: fake servis 16 senaryonun 9'unu geçti ve 51.7 aldı. Real servis 16 senaryonun tamamını geçti ve 100 aldı.
Fake servis iyi bir örnek çünkü her yerde kötü değil. Yapısı var. Basit kontrolleri geçiyor. Test ownership, invalid amounts, failure history ve database boundary sorduğunda düşüyor.
AI destekli backend kodunda service class ve success response yeterli değil. Production kurallarını tanımlamak ve test etmek gerekiyor. Bu Laravel projesinde farkı göstermek için 16 senaryo yeterli oldu.
Daha ayrıntılı incelemek isteyenler için çalışmanın tüm detaylarını içeren PDF dosyasını burada ekledim.
