İçeriğe geç
Muhammet Şafak
en

Uzmanlık

Yazılım mimarı: teslim garantisinin karar garantisi olmadığı sistemler

Bir fatura akışında outbox mesajın kaybolmamasını sağladı ama aynı mesajın aynı sonucu üreteceğini garanti etmedi; mimariyi o ikinci boşluğu da hesaba katan kararların toplamı olarak yapıyorum.

Başlangıç
2022 Başlangıç
yıl
4 yıl
yazı
5 yazı
proje
10 proje

Mimariyi bir desen koleksiyonu olarak değil, belirli bir sistemde, belirli bir sınırla ve belirli bir bedelle verilmiş karar olarak yapıyorum. Bu sayfa üç konuyu kendi kapsamında tutuyor: Software Architecture, System Design ve Event-Driven Architecture.

Üçünün kanıtı sitede duruyor. Teslim ve idempotency tarafı outbox günlüğünde, yasal bir kısıtın tasarımı nasıl daralttığı numara çakışması günlüğünde, teslimden sonraki determinizm sorusu ise determinizm yazısında. Rollerin kendisi özgeçmişte, konunun kitap ölçeğindeki karşılığı güvenilir event-driven sistemler kitabında. Derinliğe inmek isterseniz sade.dev tarafındaki mimari kararların neden çürüdüğü yazısı ve outbox ile idempotent tüketim anlatısı doğru yer.

Bu sayfanın kapsadığı üç konu

Üçü de sitedeki bir yazıya, kayda ya da deneyime dayanıyor; derinlik değil kimlik ve kanıt düzeyinde duruyor.

  • Software Architecture

    Mikroservis sınırlarını, kritik tasarım kararlarını ve bunların ekibe aktarılmasını kapsıyor. Senior Software Developer, ardından Staff Engineer rollerinde mimariyi domain-driven design ve test-odaklı geliştirmeyle birlikte yürüttüm; sınırları wiki'de bırakmayıp koda yazıp CI'da denetleyen yaklaşım da bu başlığın parçası.

  • System Design

    Bir sistemin ölçeklenme, erişilebilirlik ve yük dağılımı kararlarını kapsıyor. Senkron bir fatura akışını ortak bir kuyruğa ve ayrı bir consumer servisine taşıdım. Bunun temeli, mimari sorumluluk üstlenmemden önce bir arama altyapısında atıldı; MySQL ile Redis'i birlikte kullanan bir önbellek katmanı ve böldüğüm veritabanı ile cache kümeleri.

  • Event-Driven Architecture

    Teslim, tekrar ve determinizm sorularını kapsıyor. Transactional outbox, idempotent tüketici ve at-least-once teslim bu başlığın pratiği; teslim edilen bir mesajın aynı sonucu üreteceğinin ayrı bir garanti gerektirdiği de.

Bir kararın bedeli

E-fatura numarası üretiminde yasal bir kısıt tasarımın asıl kuvveti oldu. Zincir sırayla okunur.

01 Numarayı geç üretmek race doğurdu
Gönderim anında MAX değerine bir ekleyen yöntem tek worker'la çalışıyordu; paralel worker'lar aynı numarayı üretip dış API'ye aynı numarayla gitti.
02 Numarayı erken üretmek boşluk doğurdu
Numara kuyruğa atılırken üretilirse, düşen ya da iptal edilen fatura seride açıklanamayan bir boşluk bırakıyor. Yasal seride atlanan numara olamaz.
03 Yasal kısıt çözüm kümesini daralttı
Çakışmayı tek başına çözen çok yöntem var; boşluksuzluk eklenince çözüm kümesi bir anda daraldı. Gereksinimi iş kuralı diye kenara almadan önce mimariyi nasıl kısıtladığına bakmak gerekiyor.
04 Numara, dış çağrıdan hemen önce rezerve edildi
Rezerve edilen numara çağrı başarısız olsa da faturanın üstünde kalıyor ve aynı numarayla yeniden deneniyor. Dış çağrı transaction'ın dışında tutuldu; aksi hâlde sistem bir bottleneck'e dönüşürdü.

Teslim garantisi karar garantisi değildir

Her garanti bir maliyetle geliyor; bir deseni çözmek bir sonrakini açıyor.

01 Outbox mesajın kaybolmamasını sağlar
Mesaj, kayıtla aynı transaction içinde bir outbox satırı olarak yazılıyor ve bir relay onu yayımlıyor. Dual-write problemi böylece kapanıyor.
02 At-least-once tekrar getirir
Mesaj kaybolmuyor ama tekrar edebiliyor. Tüketicinin idempotent olması, tekrarı yan etkisiz hâle getiriyor.
03 Teslim edilen mesaj aynı kararı vermeyebilir
Aynı önek listesi iki ayrı serviste tutulduğunda, birinin güncellenmesi, birkaç saat arayla gelen aynı biçimdeki iki mesajdan birini geçirip ötekini reddettirdi. Mesaj, kararın girdisinin tamamı değil.
04 Bağlamı üretim anında dondurmak gerekiyor
Karar için gereken bilgiyi tüketici kendi çözmemeli; olay kendi bağlamını taşımalı. Retry, karar anını değiştirmemeli.

Mimariyi nasıl yürütüyorum

Üç alışkanlık, hepsi ekibin aynı kararı aynı biçimde okuyabilmesine dönük.

  • Kararın bedelini yazmak

    Bir kararın neyi kapattığını ve yerine ne koyduğunu yazmadan onu mimari saymıyorum. Yukarıdaki iki zincir bu alışkanlığın çıktısı.

  • Sınırı koda yazmak

    Katmanları ve izinli bağımlılıkları tek bir dosyada beyan edip her commit'te CI'da denetlemek, bir mimari kararın iki yıl sonra çürümesini önlüyor.

  • Bilgiyi ekibe aktarmak

    Ekibe TDD ve DDD mentörlüğü verdim ve bir code-review rehberi hazırladım; mimarinin yaşadığı yer belge değil, ekibin her gün verdiği küçük kararlar.

Derinlik burada değil

Bu sayfa kimlik ve kanıt düzeyinde kalıyor. Desen anlatısını, mimari kararların neden çürüdüğünü ve outbox ile numara rezervasyonunun ayrıntılarını sade.dev'de yazıyorum.

Bir çekirdek Go'da 14.330, PHP-FPM'de 5.152 OAuth2 isteği taşıyor

Her istekte RS256 bearer token doğrulayıp PostgreSQL'e bir satır yazan ya da okuyan aynı API, bir, iki ve dört çekirdekte Go, PHP-FPM ve FrankenPHP worker ile saniyede kaç karma istek taşıyor?

Bulgu

Dört çekirdekte Go 57.321, FrankenPHP 25.659, PHP-FPM 20.606 karma istek taşıdı; çekirdek başına 14.330, 6.415 ve 5.152. Kapasite planına giren sayı bu değil, istek başına uygulama CPU'su: Go 66,8, FrankenPHP 110,7, PHP-FPM 187,7 mikrosaniye. FrankenPHP doyduğunda dört çekirdeğin ancak 2,84'ünü kullanabiliyor — Go 3,83, PHP-FPM 3,87. Darboğaz veritabanı değil: aynı dört çekirdekte PostgreSQL tek başına saniyede 68.212 satır yazıyor, yani en hızlı adayın karma tavanının üstünde.

21 gün önce ölçüldü

Orta güven

Partial index on beş dakikada üç yüz beş kat şişti — ve autovacuum bir kez bile gelmedi

Sürekli churn altındaki bir kuyruk tablosunda partial index'in küçüklüğü kalıcı mı, ve varsayılan autovacuum ayarları ona yetişiyor mu?

Bulgu

Canlı küme yaklaşık 845. saniyeye kadar beş bin satırda sabit dururken partial index 0,125 MB'dan 38,2 MB'a çıktı — üç yüz beş kat. Küçüklüğü canlı satır sayısından geliyor, şişme hızı iş hacminden, ve ikisi arasında hiçbir bağ yok. Composite index oransal olarak daha az şişti (%42) ama mutlak olarak daha çok (+126 MB) ve şişerken çöktü — büyük olasılıkla belleğe sığmadığı için, ki bu ölçümde nedeni ölçülmedi: gecikmesi 0,52 ms'den 61 saniyeye çıktı, kuyruğu 126 bine tırmandı. On beş dakikada 1,75 milyon ölü satır birikti ve autovacuum **bir kez bile koşmadı** — varsayılan eşik tablonun tamamına göre ölçekleniyor (50 + 0,2 × 10 milyon ≈ 2 milyon), churn ise küçük canlı kümede oluyor.

47 gün önce ölçüldü

Yüksek güven

Postgres partial index'i generic plana çevirmedi: kırk çalıştırma, kırk custom plan

Hazırlanmış bir deyimde Postgres partial index'li sorguyu kendiliğinden generic plana çeviriyor mu — yoksa bin altı yüz otuz beş katlık uçuruma ancak elle mi düşülüyor?

Bulgu

Postgres geçişi reddediyor. Partial index'te kırk çalıştırmanın kırkı da custom plan — sayaç 40/0. Reddetmesinin sebebi tam olarak felaketin kendisi: generic plan partial index'i kullanamaz, bu yüzden tahmini maliyeti yüksek çıkar ve planner onu seçmez. Composite index ise ders kitabındaki gibi altıncı çalıştırmada geçiyor (5/35) ve hiçbir şey kaybetmiyor. Yani bin altı yüz otuz beş katlık uçurum gerçek ama çitli: ona düşmek için `plan_cache_mode = force_generic_plan` yazmak gerekiyor.

47 gün önce ölçüldü

Yüksek güven

Üretim veritabanına giden ad-hoc SQL'i onaya, maskelemeye ve değiştirilemez bir ize bağlayan self-hosted portal; QueryProxy ürününe dönüştü.

Şu an ne yapıyor

Geliştiricinin yazdığı SQL'i üretim veritabanında doğrudan değil, bir onaydan geçirerek çalıştırıyor; sonuçlar diske yazılırken maskeleniyor ve her istek değiştirilemez bir kayda düşüyor. Prod erişimi tek kişide toplanmış ekipler kurabilir.

Open-Source Web PHP Laravel Livewire +5 daha
Eylül 2026 — Eylül 2026

Çok hesaplı gelir-gider takibini tek modelde toplayan finans çekirdeği; web + iOS + Android'de çalışan Parantaj'a dönüştü.

Şu an ne yapıyor

Tek hesap/işlem modeli çoklu hesap yönetimini, bütçeyi, hedefleri ve raporlamayı aynı çekirdekte taşıyor; web, iOS ve Android istemcileri yayında. Kişisel ve kurumsal finansını tek yerden takip etmek isteyen kullanabilir.

Open-Source Web Mobil PHP Laravel Go +4 daha
Mart 2024 — Ekim 2024

Her projeye kendi MCP ucunu açan, dokümanı kendi sunucunda tutan çok kiracılı doküman sunucusu; embedding'ler CPU'da üretiliyor.

Şu an ne yapıyor

Bir projenin klasörünü, git deposunu, Obsidian kasasını ya da Notion çalışma alanını tek bir MCP ucunun arkasında aranabilir kılıyor; ajan dokümana ulaşırken veri üçüncü tarafa gitmiyor. Docker ile kurup panelden yöneten herkes kendi sunucusunda çalıştırabilir.

Open-Source Web TypeScript Node.js Fastify +6 daha
Ağustos 2026 — Eylül 2026

Bu alanda üretime çıkan işler

Tüm projeler : Bu alanda üretime çıkan işler
QueryProxy onay kuyruğu — bekleyen bir sorgu isteği, çözümleme uyarıları ve maskelenmiş sonuç sütunları

QueryProxy

Devam ediyor

Founder & Developer

Seviye: Ana Odak

QueryProxy, geliştiricilerin üretim veritabanına kimlik bilgisi almadan erişebilmesi için geliştirdiğim self-hosted bir sorgu onay portalıdır. Yazılan SQL çözümlenerek denetlenir, bir DBA onayından geçtikten sonra kuyrukta çalışır, sonuçlar diske yazılırken maskelenir ve her adım değiştirilemez bir denetim kaydına düşer.

PHP Laravel Livewire +13 daha
Eylül 2026 — Devam ediyor
Parantaj kapak görseli — toplam bakiye, hesaplar, harcama kategorileri ve nakit akışı grafiğiyle bir finans kontrol paneli

Parantaj

Devam ediyor

Owner

Seviye: Aktif Geliştirme

Kişisel ve kurumsal finansal yönetim platformu. Gelir-gider takibi, bütçe planlama, detaylı raporlama ve çoklu hesap yönetimi sunar.

PHP Laravel Go +8 daha
Ekim 2024 — Devam ediyor
academia.sh ders ekranı — müfredat/kurs/konu/ders hiyerarşisi, teori ve sahadan problemin aynı ders metninde aktığı panel, tam metin arama ve sertifika kayıt dondurma özetleri

academia.sh

Devam ediyor

Founder & Author

Seviye: Aktif Geliştirme

academia.sh, bir dersin teorisini sahadan gelen gerçek bir problemden ayırmayan, dersleri kayıt olmadan ücretsiz okunan bir öğrenme platformudur. Müfredat-kurs-konu-ders hiyerarşisiyle sunulur, ilerleme ve quiz teoriyle problemi ayırmadan ders bazında ölçülür, tam metin arama Postgres üzerinde çalışır; kurs sonu sınavı, sertifika ve çalışma asistanı Pro katmanda. İçerik ayrı bir GitHub reposunda tutulur; ilk alan bilgisayar bilimleri, model baştan çok disiplinli tasarlandı.

Laravel PHP Livewire +6 daha
Eylül 2026 — Devam ediyor

Bu alanda sorulanlar

Bu eksende 13 soru yanıtlandı.

Tüm sorular : Bu alanda sorulanlar

Birlikte kullandığım teknolojiler

  • RabbitMQ

    Servisler arası asenkron teslim; outbox relay'inin çıkış kapısı.

  • Redis

    Önbellek katmanında ilişkisel depoyla birlikte çalışan hızlı katman.

  • MySQL

    Önbellekli okuma ve outbox tablosunun üzerinde durduğu depo.

  • PostgreSQL

    Kuyruk tablosu ve index davranışını üzerinde ölçtüğüm veritabanı.

  • Docker

    Geliştirme ortamı ve dağıtım paketi.

  • GitHub Actions

    Mimari sınırların her commit'te denetlendiği CI hattı.

Sık sorulanlar

5 soru

  • Mimari alanında kaç yıldır çalışıyorsun?

    2022'den bu yana, 4 yıldır. Senior Software Developer olarak başladım, Mart 2025'ten beri Staff Engineer olarak mikroservis ve event-driven mimariyi tasarlıyorum. Daha önceki arama altyapısı yıllarındaki sistem tasarımı temeli bu sürenin dayanağı; sürenin kendisine dahil değil. Bu sitede bu işlerle kesişen 5 yazı kayıtlı.

  • Software Architecture, System Design ve Event-Driven Architecture arasında nasıl ayırıyorsun?

    Software Architecture sınırları ve kararları, System Design bir sistemin ölçeklenme ve erişilebilirlik davranışını, Event-Driven Architecture ise servisler arasındaki teslim, tekrar ve determinizm sorularını kapsıyor. Üçü aynı işin farklı ölçekleri; bu sayfa üçünü birlikte tutuyor.

  • Kuyruğa taşımak teslim garantisi verir mi?

    Hayır. Outbox mesajın kaybolmamasını sağlar ama size at-least-once verir; tekrarı idempotent tüketici bastırır. Teslim edilen mesajın aynı kararı vereceği ise üçüncü bir garanti ve bir fatura akışında onu ayrıca kurmam gerekti.

  • Mimari kararı nasıl değerlendiriyorsun?

    Neyi kapattığına ve yerine ne koyduğuna bakarak. E-fatura numarası örneğinde numarayı geç üretmek race, erken üretmek boşluk doğuruyordu; çözüm ikisini birden tutmaktı.

  • Derin mimari yazılarını nerede okuyabilirim?

    sade.dev'de. Bu sayfa kimlik ve kanıt düzeyinde kalıyor; desen anlatısı ve uzun mimari yazılar orada.

Birlikte çalışalım

Bu ekosistemde bir işiniz varsa, ne yaptığınızı anlatın; nasıl kurulacağını konuşalım.

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi