İlk Kez Veritabanına Yazdım — ve Kendi Kendini Onaylatmak İsteyen Birini Durdurdum
6. Günün sonunda şöyle demiştim: “Şimdiye kadar hep tek yönlüydü — veritabanından al, sayfaya koy. Sıradaki adım ters yöne gitmek.” Bugün o adımı attım: siteye gelen birinin yazdığı bir şeyi (bir yorumu) veritabanına kaydeden ilk kapıyı açtım.
Ve bu, sandığımdan daha farklı bir işmiş.
Okumak kolay, yazmak sorumluluk
Şu ana kadar yaptığım her şeyde veriyi ben üretiyordum. Yazılarımı ben yazıyordum, veritabanına ben koyuyordum, site de onları alıp gösteriyordu. İçeriğin tamamı benim kontrolümdeydi.
Yazma tarafı bunu tamamen değiştiriyor. Artık tanımadığım biri bana veri gönderiyor ve ben onu kendi veritabanıma koyuyorum.
Aradaki farkı şöyle düşündüm: okumak, kütüphaneden kitap almak gibi. En kötü ihtimalle yanlış kitabı alırsın. Yazmak ise kapıyı açıp “ne getirirsen koyabilirsin” demek. Kim ne getiriyor, gerçekten kitap mı, içinde ne var — hiçbirini bilmiyorsun. Kapıyı açmak kolay; asıl iş, içeri ne girdiğini kontrol etmek.
Her yorum bir yazıya ait: iki tabloyu bağlamak
İlk iş yeni bir tablo açmaktı: comments. Ama burada yeni bir kavramla karşılaştım.
Yazılar tablosu tek başına anlamlı: her satır bir yazı. Yorumlar öyle değil — havada duran bir yorum hiçbir şey ifade etmiyor. Her yorumun bir yazıya ait olması gerekiyor.
Bunun için her yorum kaydında “hangi yazıya ait olduğu” bilgisi duruyor. Ama asıl öğrendiğim şey, bu bağı veritabanına söylediğinde ne olduğu: veritabanı bunu kendi başına denetlemeye başlıyor. Olmayan bir yazıya yorum eklemeye çalışırsan, kodumda bir hata olsa bile veritabanı bunu reddediyor.
Yani veri tutarlılığını sadece kendi koduma emanet etmiş olmuyorum. Altta bir kat daha koruma var. Bunu sevdim: bir şeyin iki ayrı yerde kontrol edilmesi, birinin gözden kaçırdığını diğerinin yakalaması demek.
Bir de şunu söyledik: bir yazı silinirse, o yazının yorumları da silinsin. Yoksa sahipsiz yorumlar birikirdi.
Günün asıl dersi: gönderilen her şeye inanmamak
Yorumlar hemen görünmeyecek, ben onayladıktan sonra görünecek. Yani her yorum kaydında “onaylandı mı” diye bir bilgi duruyor ve yeni gelen yorumlarda bu bilgi “hayır” olarak başlıyor.
İşte buradaki tuzak: Eğer kod, gelen isteği olduğu gibi alıp veritabanına yazsaydı, biri isteğinin içine “onaylandı: evet” diye bir satır ekleyip kendi yorumunu kendisi onaylatabilirdi. Siteme girer, ne isterse yazar, ve benim onayım olmadan yayına girerdi.
Çözüm basit ama disiplin istiyor: kullanıcıdan sadece beklediğin alanları al, geri kalan her şeyi görmezden gel. Gelen istekte ne varsa alıp veritabanına aktarmak kolay yol; ama o kolay yol kapıyı ardına kadar açıyor. Onay bilgisi gibi şeyleri her zaman sunucunun kendisi belirlemeli, kullanıcının gönderdiğine bakmamalı.
Bunu test ettik. Bilerek kötü niyetli bir istek gönderdik: içinde “onaylandı: evet” yazıyordu, ayrıca yorumun hangi yazıya ait olacağını, kayıt numarasını ve tarihini de sahte değerlerle doldurmuştuk. Sonuç: hiçbiri kullanılmadı. Yorum onaysız kaydedildi, doğru yazıya bağlandı, tarihi bugündü.
Bu testin geçmesi, bugünün en somut kazancıydı. Bir açığı “kapattık” demekle, “kapandığını gördük” demek arasında büyük fark var.
Ayrıca: boş isim, 50.000 karakterlik yorum, bozuk istek
Onay tuzağının yanında daha sıradan kontroller de gerekiyordu. İsim boş olabilir mi? Yorum ne kadar uzun olabilir? Gelen şey hiç anlamlı bir metin değilse ne olacak?
Bunların hepsi için ayrı ayrı kurallar koyduk: isim en fazla 80 karakter, yorum en fazla 2000 karakter, ikisi de boş olamaz, gelen istek anlamsızsa düzgün bir hata mesajıyla reddedilsin — program çökmesin.
Burada küçük ama hoşuma giden bir detay çıktı. Bilgisayar, emoji gibi bazı karakterleri sayarken 1 yerine 2 sayabiliyor; veritabanı ise aynı karakteri 1 sayıyor. Bu fark gözden kaçsa, “80 karakteri geçmiyor” diye kabul ettiğimiz bir ismi veritabanı reddedebilirdi. İki tarafın aynı şekilde sayması sağlandı. Bu tür şeyler, ancak birisi durup “acaba iki taraf aynı mı sayıyor?” diye sorduğunda ortaya çıkıyor.
Kontrol sırası: ucuz olanı önce yap
Burada güzel bir şey oldu: planı yaparken ben bir sıra önerdim, karşı taraf daha iyisini önerdi ve gerekçesini açıkladı.
Ben “önce yorumun ait olduğu yazıyı bul, sonra gelen veriyi kontrol et” demiştim. Önerilen sıra ise tersiydi: önce gelen veriyi kontrol et, sonra yazıyı ara.
Gerekçesi şuydu: bu kapı internete açık. Biri saçma isteklerle üzerine yüklenirse, benim sıramda her saçma istek veritabanına bir sorgu attırır. Diğer sırada hiçbiri attırmaz, çünkü istek daha veritabanına gitmeden elenir.
Kural olarak aklımda kalan şu: ucuz kontrolü pahalı olandan önce yap. Bir isteği reddedeceksen, bunu mümkün olan en erken noktada yap.
Onikinci hata: bende olmayan bir komutu çalıştırmak
Testleri kendi terminalimde denemek istedim. Bana verilen komutlardan birini yapıştırdım, hiçbir şey olmadı.
Sebebi şuydu: o komut aslında bir “komut” değil, o oturumda tanımlanmış bir kısayoldu. Claude Code kendi penceresinde onu önce tanımlamış, sonra kullanmıştı. Ben sadece kullanım kısmını kopyalamıştım — tanım kısmını değil.
Buradan öğrendiğim şey, terminalin nasıl çalıştığıyla ilgili: her pencere sıfırdan başlar ve başka bir pencerede olan bitenden haberi yoktur. Bir yerde tanımladığın şey, diğerinde yoktur. Önce tanımı yapıştırdım, sonra komut çalıştı.
Tek bir veritabanım varmış
Bugün fark ettiğim bir şey daha var. Kendi bilgisayarımda test ederken kullandığım veritabanı ile canlı sitenin kullandığı veritabanı aynı veritabanı. Yani “deneme amaçlı” gönderdiğim yorumlar, gerçek veritabanına gerçek kayıt olarak giriyor.
Onaylanmadıkları için sitede görünmüyorlar, yani şu an bir zararı yok. Ama kavram olarak doğru değil: deneme yaparken gerçek veriye dokunmamak gerekir. Bir gün yanlış bir komut çalıştırırsam, denemem gerçek içeriğimi bozabilir.
Neon’un bunun için bir özelliği varmış: veritabanının bir kopyasını çıkarıp deneme için onu kullanabiliyorsun. Bugünün konusu değildi ama listeme ekledim.
Test yorumlarını iş bitince temizledik. “Denemeydi” diye bıraktığın şeyler, bir süre sonra “bu neydi?” diye baktığın şeylere dönüşüyor.
Yapay zekâ da hata yaptı ve söyledi
Testler sırasında Claude Code kendi hatasını yakalayıp bana bildirdi: test komutlarının bir kısmını çalıştırmak isterken yanlışlıkla tamamını çalıştırmış, bu yüzden 2 yerine 4 deneme kaydı oluşmuş. Hepsini temizledi ve ne olduğunu açıkça yazdı.
2. Günde “AI emin bir tonla yanlış şeyler söyleyebilir, kontrol et” demiştim. Bugün madalyonun diğer yüzünü gördüm: kendi hatasını fark edip söylemesi, benim o hatayı hiç aramama gerek bırakmadı. Mesele AI’a güvenmek ya da güvenmemek değil; ne olduğunun görünür olması. Görünen hata, saklanan hatadan her zaman iyidir.
Sonunda: yorum göründü
Her şeyi yayına aldıktan sonra uçtan uca denedim.
Canlı adrese bir yorum gönderdim — kabul edildi, “onaydan sonra görünecek” cevabı geldi. Sonra yorumları listeledim: boş. Çünkü henüz onaylamamıştım. Buraya kadar doğru.
Sonra veritabanında o yorumu onayladım ve listeyi tekrar istedim: yorum oradaydı.
Bir de güzel bir ayrıntı: yorumu Türkçe karakterlerle yazmıştım. Terminalden çıkıp API’ye, oradan veritabanına, geri API’ye ve tekrar bana dönene kadar hiçbir harf bozulmadı. Türkçe bir blog için bu küçük bir detay değil.
Ve son bir kafa karışıklığı
Yorumu onayladıktan sonra veritabanı ekranına baktım ve hiçbir şey göremedim. “Onayladım ama yorum görünmüyor” diye takıldım.
Oysa yorum oradaydı, sadece ekran bana göstermiyordu. Sebebi şu: veritabanına verdiğim komut bir değiştirme komutuydu — “şu kaydı onaylı yap”. Bu tür komutlar geriye bir şey döndürmez, sadece işi yapar. Veriyi görmek istiyorsan ayrıca bir okuma komutu vermen gerekiyor.
Bunun ne kadar yerinde bir kafa karışıklığı olduğunu sonradan fark ettim: bütün gün okuma ile yazmanın farklı şeyler olduğunu anlatan bir sistem kurdum, sonra gidip aynı farkı en küçük haliyle kendi ekranımda yaşadım. Yazdım ama okumadım, sonra “görünmüyor” dedim.
Sırada ne var?
Yorum sistemi arka tarafta çalışıyor ama sitede henüz hiçbir izi yok. Ne bir yorum kutusu var, ne de yazıların altında görünen yorumlar.
Sıradaki adım bu. Ve orada beni bekleyen bir şey olduğunu biliyorum: siteme bir yorum formu koyduğumda, tarayıcı bu isteği büyük ihtimalle engelleyecek. Çünkü sitem bir adreste, API’m başka bir adreste duruyor — ve tarayıcılar, bir sitenin başka bir adrese veri göndermesine varsayılan olarak izin vermiyor. Bu kasıtlı bir güvenlik kuralı.
Yani yarın muhtemelen bir hata ekranıyla başlayacağım. Ama bu sefer ne olacağını önceden biliyorum; nadiren olan bir lüks.
Yorumlar