96 puan yazan GN⁺ 2025-08-18 | 1 yorum | WhatsApp'ta paylaş
  • İyi sistem tasarımı, karmaşık görünmeyen ve uzun süre boyunca kayda değer sorunlar çıkarmayan bir yapı demektir
  • Sistem tasarımında en zor kısım durum (state) ile başa çıkmaktır; bu yüzden durum tutan bileşenlerin sayısını mümkün olduğunca azaltmak önemlidir
  • Veritabanı, durumun çoğunlukla saklandığı yerdir; bu nedenle şema tasarımı ve indeksleme ile darboğazları gidermeye odaklanan bir yaklaşım gerekir
  • Caching, event işleme ve arka plan işleri performans ve bakım kolaylığı için dikkatle devreye alınmalı, aşırı kullanımından kaçınılmalıdır
  • Karmaşık tasarımlar yerine yeterince doğrulanmış basit bileşen ve yöntemleri uygun şekilde kullanmak, sürdürülebilir ve istikrarlı sistem kurmanın anahtarıdır

Sistem tasarımının tanımı ve genel yaklaşım

  • Yazılım tasarımı kodun bir araya getirilmesiyse, sistem tasarımı da çeşitli servislerin bir araya getirilmesi sürecidir
  • Sistem tasarımının başlıca bileşenleri uygulama sunucusu, veritabanı, cache, kuyruk, event bus, proxy gibi parçalardır
  • İyi bir tasarım, "özel bir sorun yok", "beklediğimden daha kolay bitti", "bu kısmı dert etmeye gerek yok" gibi tepkiler doğurur
  • Buna karşılık karmaşık ve göze çarpan tasarımlar, temel sorunları gizliyor ya da aşırı tasarımı işaret ediyor olabilir
  • Karmaşık sistemleri en baştan doğrudan devreye almak yerine, çalışan en basit yapıdan başlayıp zamanla geliştirmek daha avantajlıdır

Durum (state) ve stateless ayrımı

  • Yazılım tasarımındaki en çetin konu durum yönetimidir
  • Bilgi saklamadan anında sonuç döndüren servisler (GitHub’ın PDF render etmesi gibi) stateless yapıdadır
  • Buna karşılık veritabanına yazma yapan servisler durum yönetir
  • Sistem içinde durum tutan bileşenleri mümkün olduğunca azaltmak gerekir. Bu, sistemin karmaşıklığını ve arıza olasılığını düşürür
  • Durum yönetimini tek bir servisin üstlenmesi, diğer servislerin ise API çağrısı yapmak veya event üretmek gibi stateless rollere odaklanması önerilir

Veritabanı tasarımı ve darboğaz noktaları

Şema ve indeks tasarımı

  • Veriyi saklamak için insanın kolay okuyabileceği bir şema tasarımı gerekir
  • Fazla esnek şemalar (ör. her şeyi bir JSON kolonunda saklamak) uygulama kodu ve performans üzerinde yük oluşturabilir
  • Sık sorgulanacak kolonları temel alarak uygun indeksler tanımlanmalıdır. Her şeye indeks koymak ise gereksiz ek yük doğurur
Reklam

Darboğazları çözme yöntemleri

  • Veritabanı erişimi çoğu zaman ağır bir darboğaz haline gelir
  • Mümkün olduğunda karmaşık verileri uygulama katmanında değil, veritabanı içinde JOIN gibi işlemlerle ele almak performans açısından daha avantajlıdır
  • ORM kullanırken döngü içinde sorgu çalıştırma hatasına dikkat edilmelidir
  • Gerektiğinde sorguları bölerek veritabanının yükünü ya da sorgu karmaşıklığını dengelemek de bir yöntemdir
  • Okuma sorgularını read-replica'lara dağıtmak, ana (write) düğüm üzerindeki yükü azaltmada etkilidir
  • Çok sayıda sorgu aynı anda geldiğinde transaction ve yazma işlemleri veritabanını kolayca aşırı yükleyebilir; bu nedenle query throttling (sınırlama) düşünülmelidir

Yavaş işler ile hızlı işlerin ayrılması

  • Kullanıcının etkileşimde bulunduğu işlemlerin yüzlerce milisaniye içinde yanıt vermesi gerekir
  • Uzun süren işler (ör. büyük PDF dönüştürmeleri), önde kullanıcıya sadece en az gerekli kısmı hemen sunup geri kalanını arka planda çalıştırma yaklaşımıyla daha verimli yönetilir
  • Arka plan işleri genelde bir kuyruk (ör. Redis) ve job runner ile birlikte çalışır
  • Uzak zamana planlanmış işler için Redis yerine ayrı bir DB tablosu kullanıp scheduler ile çalıştırmak daha pratiktir

Caching

  • Caching, aynı ya da maliyetli işlemler tekrarlandığında maliyeti düşürür ve performansı artırır
  • Genelde cache’i yeni öğrenen junior mühendisler her şeyi cache’lemek ister; deneyimli mühendisler ise cache kullanımında daha temkinlidir
  • Cache yeni bir durum katmanı eklediği için senkronizasyon sorunları, hatalar ve stale data riski taşır
  • Önce sorguya indeks eklemek gibi performans iyileştirmeleri denenmeli, cache daha sonra uygulanmalıdır
  • Büyük ölçekli cache için Redis/Memcached yerine S3/Azure Blob Storage gibi doküman depolarına periyodik olarak yazma yöntemi de kullanılabilir

Event işleme

  • Çoğu şirketin bir event hub'ı (ör. Kafka) vardır ve farklı servisler event tabanlı olarak dağıtık biçimde çalışır
  • Event’leri gereğinden fazla kullanmak yerine, basit istek–yanıt API tasarımı logging ve sorun çözme açısından daha faydalıdır
  • Event tabanlı işleme, gönderenin alıcının davranışını önemsemesine gerek olmayan ya da yüksek hacimli, gecikmeye toleranslı senaryolar için uygundur

Verinin iletilme biçimi: push ve pull

  • Veri iletiminde iki yaklaşım vardır: Pull (istekten sonra yanıt) ve Push (değişiklik olduğunda otomatik iletim)
  • Pull yaklaşımı basittir ama tekrar eden istekler ve aşırı yük sorunları doğurabilir
  • Push yaklaşımında sunucu, veri değiştiğinde istemciye anında iletim yapar; bu da daha verimli olmasını ve güncel veriyi korumasını sağlar
  • Çok sayıda istemciyi desteklemek için her iki yaklaşımda da uygun altyapı genişletmesi (event queue, birden çok cache sunucusu vb.) gerekir
Reklam

Hot path'lere odaklanmak

  • Hot path, sistem içinde en kritik ve en yoğun veri akışının geçtiği yolu ifade eder
  • Hot path’lerde seçenek azdır ve tasarım hatası durumunda tüm servis genelinde ciddi sorunlara yol açabilir; bu yüzden dikkatli tasarım şarttır
  • Seçeneği bol küçük özellikler yerine, hot path’lere odaklanıp tasarım ve teste kaynak ayırmak daha etkilidir

Logging, metrikler ve izleme

  • Arıza anında nedeni teşhis edebilmek için, olumsuz akışlar (unhappy path) hakkında ayrıntılı loglar tutmak gerekir
  • Sistem kaynakları (CPU/bellek), kuyruk boyutu, istek/iş süresi gibi temel gözlemlenebilirlik metrikleri toplanmalıdır
  • Sadece ortalama değerlere bakmak yerine p95, p99 gecikme süreleri gibi dağılım metrikleri de mutlaka izlenmelidir. En yavaş küçük bir istek grubu, en kritik kullanıcıların sorununu temsil ediyor olabilir

Kill switch, retry ve arıza kurtarma

  • Kill switch (sistemi geçici olarak durdurma) ve retry stratejilerinin doğru kullanımı önemlidir
  • Rastgele retry yapmak sadece diğer servislere yük bindirir; etkili olması için istekler önceden circuit breaker gibi mekanizmalarla kontrol edilmelidir
  • Idempotency Key kullanımı, aynı isteğin yeniden işlenmesi sırasında yinelenen işlemleri önleyebilir
  • Bazı arıza durumlarında fail open veya fail closed arasında seçim yapmak gerekir. Örneğin rate limiting için fail open (izin vermek) kullanıcı etkisini azaltır. Buna karşılık kimlik doğrulamada fail closed zorunludur

Sonuç

  • Servis ayrımı, container, VM kullanımı, tracing gibi bazı konular atlanmış olsa da, iyi doğrulanmış bileşenleri doğru yerde kullanmak uzun vadede en istikrarlı sistemi kurmanın yoludur
  • Teknik olarak sıra dışı tasarımlar gerçekte çok enderdir; sıkıcı denecek kadar basit tasarımlar ise pratikte en sık kullanılanlardır
  • Özünde iyi sistem tasarımı, göze çarpmayan ve yeterince kanıtlanmış yöntemleri güvenli biçimde bir araya getirme sürecidir

1 yorum

 
GN⁺ 2025-08-18
Hacker News görüşleri
  • Bu noktada sık sık yalnız olduğumu hissediyorum. Mühendisler karmaşık sistemlere bakınca ilginç unsur çok olduğu için “işte burada gerçek sistem tasarımı yapılıyor!” diye düşünüyor, ama aslında karmaşık sistemler çoğu zaman iyi tasarımın yokluğunun sonucu oluyor. İş arayan biriyseniz, mülakat sırasında bu gerçeği tamamen unutmanız gerekir. Ben de sistem tasarımı mülakatında bu düşünceyi dürüstçe aktarıp hata yapmıştım. Varsayımsal bir startup uygulaması mülakatında “bu kadar QPS’te backpressure’ı görmezden gelebiliriz”, “cron job yerine kuyruk kullanmaya gerek yok, tabii trade-off’lar var”, “SQL vs NoSQL? Ekibin en iyi bildiğini kullanmak yeterli” gibi cevaplar verdim, ama mülakat yapanlar böyle cevaplar istemiyor. Beyaz tahtayı baştan sona doldurup Kubernetes’in Kubernetes’i yönettiği seviyede karmaşık bir tasarım göstermelisiniz ki onların aradığı sinyali verebilesiniz

    • Yüzlerce kez sistem tasarımı mülakatı yapmış ve birçok kişiyi eğitmiş biri olarak söylüyorum. Bahsettiğin cevaplar zayıf sinyal veriyor (kuyrukla ilgili cevap hariç); mülakatçıların gerçekten bilmek istediği şey, bu kararları neden aldığın, hangi etkenleri değerlendirdiğin ve düşünce sürecin. Cevabı ayrıntılı açıklamazsan, mülakatçı açısından “buradan çok az bilgi çıkar” diye düşünmek kolay olur. Bu yüzden aday, mülakatçının istediği bilgiyi proaktif biçimde vermeli. Ayrıca iyi bir mülakatçı bile cevapları zorla çekmek zorunda kalırsa “açıklaması makul ama iletişimi verimsiz” diye not düşer. İletişim becerisi de değerlendirme kapsamındadır. Son olarak SQL/NoSQL cevabına katılmıyorum. Ekip deneyimi önemli ama teknolojiler arasındaki farklar nettir ve duruma göre performans farkı da büyüktür. Bu cevap, farklı durumlarla ilgili deneyimin az olduğu izlenimi bırakıyor

    • “Mülakat iki yönlüdür” denir ya, bence cevapların gayet makul. Ben mülakatçı olsaydım muhtemelen yüksek puan verirdim. Buna karşılık seni bu cevaplar yüzünden eleyen bir şirketse, muhtemelen sorun şirkettedir. Ama pratikte çoğu zaman hızlıca bir yere yerleşmek gerekir; bu yüzden dengeyi iyi kurup cevabı karşı tarafın beklediği yöne ayarlamak da gerekebilir

    • Bu tavsiye iyi değil. Basit ama zarif tasarım, potansiyel sorunları görmezden gelerek başlamaz. Derinleştirme soruları, teknik trivia yağdırma zamanı değil, birlikte tartışalım sinyalidir. Verdiğin cevaplar bilgelik göstermiyor; daha çok hâlâ olgunlaşmamış bir izlenim veriyor. Suç mülakatçıda değil

    • Yan yorumda söylenen “mülakat iki yönlüdür” noktasına katılıyorum ama iyi bir mülakatçı dürüstçe “bu cevap da iyi ama ben şu anda bu temadaki bilginizi ölçüyorum” derdi. Kişinin sürekli alakasız şeylerden söz etmesi ise tersine bir endişe işaretidir

    • Bunun, LinkedIn-driven development’ın neden var olduğunun birebir örneği olduğunu düşünüyorum. CV’ye sayısız teknoloji yazmak, tek bir Postgres ve modüler monolit ile işi çok iyi yaptığını anlatmaktan çok daha havalı görünüyor; gerçek bu

  • Bunun gerçekten çok iyi bir yazı olduğunu düşünüyorum. Ama bu tür best practice’lerin sınırlarından da söz etmek isterim. Örneğin “beş farklı servis aynı tabloya yazmasın; dördü API çağırsın ya da event göndersin, tabloya sadece bir servis yazsın” tavsiyesi var; ama gerçek hayat bu kadar temiz ayrılmıyor. Beşinin de DB’ye erişmesi zaten dağıtık sistem kurduğunuz anlamına geliyor ama DB varsayılan olarak yetki, transaction ve custom query desteği verdiği için ayrıca arayüz tasarlamak gerekmeyebiliyor. Öte yandan tek bir servisle üst seviye bir arayüz kurarsanız, bu kez ayrı authentication, transaction ve exception handling’i kendiniz yazmanız gerekiyor. Pratikte bu, daha fazla failure mode ve mikroservis yönetim vergisi eklemekten başka bir şey değil mi diye düşünüyorum. Öte yandan birden fazla servisin aynı DB’ye erişmesi başlı başına bir code smell de olabilir. Belki bu DB aslında birkaç DB’nin birleşmiş kalıntısıdır ve servisler de gerçekte iki ya da üçe indirilebilir

    • “Ne kazanıyoruz?” sorusuna cevaben, API’ler paylaşılan DB şemasına göre değişime çok daha uyumludur. Birçok farklı sistemde çalışmış biri olarak, birden fazla servisin aynı DB’yi paylaştığı bir yapıyı yeniden tasarlamazdım. 2000’lerin başında küçük şirketlerde idare etmiş olabilir ama sonrasında gördüğüm hep başarısız örnekler oldu (aynı servis içinde sadece read/write yolunun ayrıldığı durumlar hariç)

    • DB’nin arayüz olduğu ve ayrıca tasarım gerekmediği iddiasına katılmıyorum. Aynı DB’yi birden fazla client kullanınca erişim kalıpları farklılaşıyor ve migration sorunları büyüyor. Sonunda view’lar, yetki yönetimi gibi ek tasarımlar gerekiyor ve bakım yükü artıyor. İdeal durumda API çok daha temiz. Gerçekte ise hızlı özellik çıkarma baskısı yüzünden doğrudan DB erişimine göz yumuluyor ama kök neden, birçok kişinin yeni gereksinimlere veya tasarıma göre sistemi baştan şekillendirmekten kaçınması

    • Değişiklik gerektiğinde amaç, ilgili uyarlama alanını en aza indirmektir. Datastore yapısını değiştirmek gerektiğinde, ona erişen her yeri kontrol etmeniz gerekir; dolayısıyla erişim yolu ne kadar azsa değişiklik o kadar kolay olur. Örneğin iş ortamında DB’yi ayırdığımızda 40’tan fazla ekip kod değiştirmek zorunda kaldı. Böyle bir değişim “özellik gereksinimi” yüzünden olduysa durum bu. Eğer konu “ölçeklenebilirlik” olsaydı, ürünün kendisi bile çökebilirdi

    • Birden fazla servisin tek bir DB’ye bağlanmasını “code smell” diye tanımladınız ama tersinden bakarsak, her servise fiziksel olarak ayrı bir DB vermek zorunda kalırsanız kullanılabilirlik N’den N’in M’inci kuvvetine çıkıp pratikte sistem daha da kırılgan hâle gelebilir (DB cluster düzeyinde konuşuyorsak)

  • Veritabanını sorgularken, gerçekten de DB’ye sorgu atmak en verimli yöntemdir. Birden fazla tablodan veri gerekiyorsa, uygulamada tek tek sorgulayıp birleştirmek yerine join kullanmalısınız. Hatta view ve hatta stored procedure kullanımını da özellikle tavsiye ederim. View’lar veri soyutlama katmanıdır, bu yüzden tasarıma ciddi fayda sağlar; SQL kodu da iyi yazılırsa anlaşılması kolay ve bakımı rahattır

    • ORMs’ların bu kadar çok soruna yol açmasının sebeplerinden biri de bu. SSR ortamındaki her MVC view için SQL view/custom query’leri doğrudan kullanmak, büyük web servislerini verimli ve zarif kılan yoldur. Ağır işi RDBMS’e bırakıp web sunucusunun SQL sonuçlarını doğrudan tabloya vermesi yeterlidir. MSSQL ve Oracle gibi legacy RDBMS’lerde çok sayıda yerleşik optimizasyon vardır. Buna karşılık ORMs tek bir object model’i dayattığı için neredeyse hiç esneklik bırakmaz

    • Stored procedure’lar faydalı görünebilir ama pratikte dilin (T-SQL vb.) sınırları yüzünden ekipte herkesin bildiği modern bir dilde birleşerek geliştirme yapmak zorlaşıyor. Büyük bir T-SQL codebase’ini koruyup geliştiriyorum; version control ve teşhis araçları da pek iyi değil. Yeni başlayanların yazdığı uygulama kodları yine okunabiliyor ama T-SQL tam bir kâbus

    • Katılmıyorum. Modern, ölçeklenebilirlik odaklı mimarilerde join’leri DB’nin önündeki backend katmanında yapmak daha iyidir. DB’ye basit index lookup işini verip join’i backend’de yapacak şekilde kurgularsanız, hem DB daha iyi ölçeklenir hem de daha hızlı olur. Çünkü server instance artırmak, DB büyütmekten daha kolaydır. Eğer join yalnızca DB’nin kaldırabileceği kadar devasa veriler için şartsa, ancak o noktada yapıyı değiştirmek gerekir. Join’i frontend’e kadar taşıyabiliyorsanız, sonuç cache’i açısından da avantajlı olabilir

    • Gerçekten öyle mi? Örneğin 10 bin müşteri ve 1 milyon siparişte, müşteri için 20 alan ve sipariş için 5 alan içeren tabloları join edip gönderirseniz 25 milyon alan taşımış olursunuz. İki bağımsız sorguyla getirip sonra join ederseniz, 5 milyon sipariş alanı + 200 bin müşteri alanı olur. Bant genişliği ve performans açısından bu çok daha iyi değil mi?

    • Bu kural başlangıç noktası olarak fena değil ama ne zaman istisna gerektiğini iyi bilmek gerekir. Çalıştığım bir uygulamada join yüzünden kayıtlar geometrik olarak şişiyordu. Sorguları ayırınca ağ overhead’inden çok sonuç işleme/filtreleme kazancı elde ettik ve çok daha hızlı oldu. Daha sonra tüm veriyi JSONB içinde saklayan bir yapıya geçtik ve durum daha da iyileşti

  • İyi sistem tasarımından söz ederken asıl problem alanına hiç değinilmemesi bana eksik geliyor. Sistem tasarımında en temel ve en zor şey, sistemin kullanıcıya sunduğu arayüzdür. Sonuçta yazılım sistemi bir takastır: “sana bu işlevi vereceğim ama karşılığında bu yapı/modeli anlaman gerekecek.” Arayüz tasarımındaki hatalar en büyük maliyettir; eğer zamanın çoğunu arayüzleri konuşmadan geçiriyorsanız, asıl önemli şeyi kaçırıyorsunuz. Bunun dışındaki sistem unsurlarının çoğu daha sonra kullanıcıyı etkilemeden değiştirilebilir

  • “İyi tasarım göze batmaz, kötü tasarım ise daha etkileyici görünür” sözünün sahada ne kadar doğru hissettirdiğine katılıyorum. Mühendis değerlendirmesi “karmaşıklık” üzerinden yapılınca overengineering’i teşvik eden bir yapı oluşmuş gibi. KISS ilkesi uzun süredir yeterince ciddiye alınmıyor

    • Bazen codebase’te üstünde pek düşünmeden geçtiğim yerleri dönüp inceliyorum; bunlar çoğu zaman iyi tasarım yapıldığının işareti oluyor

    • Bu ne yazık ki doğru. Çoğu insan karmaşık çözümleri daha çekici buluyor ve basit bir cevap verdiğinizde yetersiz görünme ihtimali de var. Oysa gerçekte yönetimi kolay, basit yapı tüm projenin başarısına daha çok katkı sağlar. Tabii kaçınılmaz biçimde karmaşık problemler de var ama çoğu şey sonuçta sıradan bir web uygulaması

  • Şema tasarımında en önemli şey esnekliktir. Çünkü veri biriktikçe şemayı değiştirmek çok zorlaşır. Ama tasarımı fazla esnek kurarsanız (tüm veriyi JSON’a koymak ya da EAV yapısı kurmak gibi!) uygulama kodu sonsuz derecede karmaşıklaşır ve garip performans sorunları çıkar. Bu yüzden genelde, sadece tablo yapısına bakınca bile ne işe yaradığını sezebileceğiniz, insan tarafından okunabilir şemaları tercih ederim. EAV ve JSON column/table’ları sık görünce insan gerçekten geliştirmeyi bırakmak istiyor. EAV’nin işe yaradığı bazı durumlar elbette var ama çoğu durumda sahaya sadece kaos getiriyor. N+1 problemi, sorguların dinamik üretilmesi, audit verisinin aynı DB’de tutulup sonra iş mantığının parçasına dönüşmesi, karmaşık Oracle ortamları ve neyin DB’de neyin uygulamada olması gerektiğinin kötü ayrılması gibi değişkenlerin her biri geliştirici yaşam kalitesini ciddi biçimde düşürüyor

    • Bununla ilgili olarak Bill Karwin’in “SQL Antipatterns” kitabı EAV deseninin risklerini ve sınırlarını çok iyi anlatıyor. Yine de bazen, şemayı net çizemediğiniz dönemlerde (Postgres’te JSONB column gibi) geçici çözüm olarak kullanılabilir ama örnek alınacak bir kural olamaz. Normalization mümkünse her zaman normalization’ı seçmek daha iyidir

    • “Audit verisini aynı DB’de tutarsanız sonunda iş mantığının parçası hâline gelir ve sorun çıkar” noktasında, peki bunun “doğru” yaklaşımı nedir merak ediyorum. Ayrı bir DB mi? Tamamen bağımsız bir storage mı?

  • “Beş servis aynı tabloya yazmasın; dördü API çağırsın ya da event atsın, yalnızca biri doğrudan DB’ye yazsın” tavsiyesi için, en iyisi zaten baştan beş servisin aynı tabloya yazmasını gerektirmeyecek bir yapı kurmaktır. Eğer yazıyorlarsa, servisler arası iş mantığı gerçekte ciddi biçimde iç içe geçmiş olabilir. O zaman bu beş servisin gerçekten ayrı olması gerekip gerekmediğini, tek bir serviste birleşip birleşemeyeceğini düşünmek gerekir. Pratikte ayrı veri tabloları vermek ya da refactor yapmak sorunu daha iyi çözebilir

  • Stateful/stateless ayrımı, altyapı ile geliştirme sorumluluğunu bölmenin anahtarıdır. Bir şeyi container içinde stateless çalıştırıyorsanız, yanlış gidecek fazla bir şey yoktur; bozulursa yeniden deploy edersiniz. Dataset’i bozacak seviyede bir DB hatası yapmadığınız sürece çoğu şey hızlıca toparlanabilir. Kariyer deneyimi, zamanı ve titizliği farklı seviyelerde olan insanlar bu noktaya kadar işi götürebilir. Ama database, file storage gibi state taşıyan alanlar tamamen farklıdır. Tek bir hata tüm işi riske atabilir; bu yüzden bunları sahada deneyimli, adanmış kişiler yönetmelidir. DB sorunsuz çalışıyor olsa bile backup yoksa zaten büyük risk altındasınız. Gerçek hayatta bu alanlar, birkaç dakikada deploy edip çözülebilecek türden değildir

    • “Stateless container uygulamasında büyük kaza olmaz → deploy edip toparlarız” derken bir noktada stateful konuya geçmişsin; mantık akışını tam takip edemedim
  • “bool yerine timestamp kullanın” tavsiyesi bana biraz fazla genel geliyor. Örneğin is_on → true, on_at → 1023030 anlaşılır; ama is_a_bear → true, a_bear_at → 12312231231 oldukça tuhaf. Çoğu ayı belli bir anda ayı olmaz sonuçta… Bu sadece belirli durumlara uyan bir öneri gibi

    • Ben neredeyse her durumda boolean yerine timestamp ya da integer kullanmanın daha iyi olduğunu düşünüyorum. Özellikle yalnızca iki durumlu alanlar zamanla “tür sınıflandırmasına” evrilmeye meyilli oluyor. Örneğin sadece ayı olsa bile ileride enum türüne genişleyebilme ihtimali için hazırlıklı olmak iyi olabilir; durum alanları da basit aktif/pasif’in ötesinde durduruldu, silindi, askıya alındı gibi çeşitli hâllere genişler. Bu yüzden boolean’lar çoğaldıkça iş daha da karmaşıklaşır. Integer daha iyidir

    • Bu önermeyi olduğu gibi alırsak, DB’de boolean kullanmanın başlı başına bir koku olduğu sonucu çıkıyor; buna katılıyorum. Ama bu yaklaşımın (bool → timestamp dönüşümünün) join işlemlerinde pratik kolaylık sağladığı durumlar olsa da sözde “tam çözüm” olmadığını düşünüyorum. Gerçek zamanlı değişim önemliyse, en doğrusu baştan audit table kullanmaktır. Soft delete de benzer şekilde bana yarım bir çözüm gibi geliyor. Asıl amaç silmeyi önlemekse, backup/restore ile daha etkili koruma sağlanabilir

    • Boolean tipi daha küçük veri boyutuna sahip olduğu için bazı iş yüklerinde (örneğin analiz amaçlı büyük veri setleri) daha verimlidir. Bazen mantıksal olarak boolean saklamak gerçekten doğrudur. Örneğin bir sürecin sonucu (başarılı/başarısız) için boolean pratiktir

    • Sadece boolean’ı timestamp’a çevirmek için özel bir neden var mı emin değilim. isDarkTheme, paginationItems gibi şeylerde de değişim zamanı ilginç olabilir. Biraz fakir işi changelog gibi duruyor

    • O durumda Bear gibi bir enum değeri kullanmak daha iyi olur

  • İyi sistem tasarımı hakkında daha soyut bir perspektiften öğrenebileceğiniz bir kitap arıyorsanız, John Gall’ın Systemantics kitabını güçlü biçimde tavsiye ederim. Bir mühendis olarak kesinlikle okumaya değer

    • Kitap kısa ama okuması çok keyifliydi. Üslubunun epey sıra dışı olması da ayrıca etkileyiciydi