Maslak’ta değil ama benzer ölçekte bir galeri: araç stoğu, hazırlık süreçleri, satış, servis, ikinci el ilanları. Hepsi Excel ve WhatsApp üzerinden yürüyordu.
“Bir CRM kuralım” değildi istenen. Galerinin çalışma biçiminin yazılıma dönmesiydi.
İlk gün sonunda 29 commit vardı ve hiçbiri yarım değildi.
Neden ekrandan başlamadım
Ekrandan başlamak hızlı hissettirir. Üç gün sonra elinde çalışan bir ekran ve altında hiçbir şey olur. Dördüncü gün ilk gerçek kural geldiğinde — “bu araç serviste ama satışa da açık olabilir mi?” — hem ekranı hem veritabanını yeniden yazarsın.
Tabandan başlamak yavaş hissettirir ve değildir. Her katmanı bir öncekinin üstüne koyup o noktada çalıştığını kanıtlayarak ilerlersen hiçbir adımda geri dönmezsin.
Gün boyu bir kez geri almadım.
Dokuz katman
| # | katman | ne kanıtlar |
|---|---|---|
| 01 | Şema — 16 migration | veri modeli tutarlı, kiracıya bölünmüş |
| 02 | Değer nesneleri | şasi no, plaka, para, tarih kendi kuralını taşıyor |
| 03 | Varlıklar + olaylar | araç bir satır değil, bir kimlik |
| 04 | Durum geçiş grafı | “buradan şuraya geçilebilir mi?” tek yerde |
| 05 | Repository portları | alan katmanı veritabanını tanımıyor |
| 06 | Repository uygulamaları | tanımayı biri yapıyor, o da burada |
| 07 | Uygulama servisi | kullanım senaryoları + olay dağıtımı |
| 08 | Yönetim arayüzü | ilk kez gözle görülür |
| 09 | Olay işleyicileri | zaman çizelgesi projeksiyonu |
Bu listenin en önemli özelliği sırası değil, her satırın tek başına test edilebilir olması. Katman 4 bittiğinde durum geçiş grafını çağırıp doğru cevabı aldım; ortada ne ekran vardı ne HTTP.
Çekirdeğin altındaki çekirdek
Katman 1’den önce, gün başında açılabilen bir uygulama iskeleti gerekti. O da aynı güne sığdı:
Konteyner ve yönlendirme. Çok kiracılılık — repository’ler sorguları otomatik olarak kiracıya daraltıyor. Yerelleştirme. Olay omurgası. Görünüm motoru. Doğrulama. Dosya depolama (dizin geçişine kapalı). Ayarlar ve özellik bayrakları. Denetim günlüğü (yalnız ekleme). Kimlik doğrulama, yetki kapısı, CSRF. Kuyruk sağlayıcı.
Çok kiracılı bir sistemde filtreyi sorgu yazana bırakma. Veri katmanı her sorguya kiracı koşulunu kendisi ekliyor. Böylece bir geliştiricinin WHERE tenant_id unutması fiziksel olarak mümkün değil.
Bir SaaS’ta en pahalı hata sınıfı budur: bir kiracının verisinin başka bir kiracıya görünmesi. Ve bu hata her zaman “unutuldu” diye olur, “bilinmiyordu” diye değil.
Günün en sıkıcı commit’i
Dokuz katmanın ortasında şu var: veritabanı hedefi MariaDB 10.4 ile MySQL 8’in ortak alt kümesi.
Sıkıcı. Ama sunucu MariaDB, geliştirme makinesi MySQL. İkisinin varsayılan karakter kümesi ve karşılaştırma kuralı aynı değil.
Bunu 16 migration yazıldıktan sonra fark etseydim hepsini yeniden yazacaktım — ve hata üretimde, iki farklı yazımdaki bir plakanın aynı sayılmasıyla ortaya çıkacaktı.
İzinler koda değil, veriye ait
Galeride bir araç “yıkama” sürecinden geçiyor. Yıkamacı bunu işaretlemeli — ama satış ekranlarını görmemeli.
Bunu rollerle çözersen her yeni süreç için yeni bir rol yazarsın. Bunun yerine izin kodu süreç tipinden türetiliyor:
// yeni süreç tipi tanımlandı: "seramik kaplama"
process.code = 'ceramic'
// izin kodu kendiliğinden var oluyor, kimse kod yazmıyor
→ vehicle.process.ceramic
Ve kalite çıtası
Araç ekleme ekranı açılır liste yığını değil, adım adım bir sihirbaz. Her adımda büyük dokunmatik kutular, seçtikçe sağda canlı bir araç profili oluşuyor.
Sebep: galeride kimse klavyenin başında durmuyor. Herkes elinde tabletle arabanın yanında.
Bu kararı ilk gün vermek önemliydi, çünkü veri modelini de etkiliyor: “dokunmatik öncelikli” demek, her seçeneğin bir görseli ve kısa bir etiketi olması demek. Sonradan eklemek tüm katalog tablolarını değiştirmek olurdu.
Ne öğrendim
29 commit’in sebebi hızlı yazmam değil. Hiç geri dönmemem. Ve geri dönmememin sebebi her katmanı bir sonrakine geçmeden gerçekten çalıştırmam.
“Önce mantık, sonra kod” bir slogan değil, bir zamanlama kararı. Mantığı kodun içinde keşfetmeye çalışırsan, keşfettiğin her şey seni bir öncekini silmeye zorlar.