Refactoring — Mevcut Kodun Tasarımını İyileştirme Sanatı — Bölüm 20: Veritabanı Refactoring — Şema…
Kısım IV — Büyük Resim: Sistem Ölçeğinde Refactoring

Refactoring — Mevcut Kodun Tasarımını İyileştirme Sanatı — Bölüm 20: Veritabanı Refactoring — Şema Evrimi ve Geçiş Stratejileri
Kısım IV — Büyük Resim: Sistem Ölçeğinde Refactoring
İçindekiler
Mimari göçün en zorlu kısmına, veriye odaklanıyoruz. ↗ Bölüm 19'da defalarca işaret ettiğimiz gibi, kod yönlendirilebilir ama veri durumludur, paylaşılır ve tutarlı kalmak zorundadır — bu yüzden mimari göçün asıl duvarı veritabanıdır. Bu bölüm, Scott Ambler ve Pramod Sadalage’in “Refactoring Databases” çalışmasından ilham alarak, bir veritabanı şemasını canlı sistemi bozmadan nasıl evrimleştireceğimizi gösterir: Expand-Contract desenini şemaya uygulamak, göç betikleri yazmak, ve sıfır kesintili şema değişiklikleri yapmak.
» Veri Neden En Sert Problem — Şemanın Üç Laneti » Database Refactoring — Şemayı Davranış Koruyarak Değiştirmek » Expand-Contract — Sıfır Kesintili Şema Değişikliği » Rename Column — Bir Sütunu Güvenle Yeniden Adlandırmak » Göç Betikleri — Şema Evrimini Versiyonlamak » Geriye Uyumluluk — Eski ve Yeni Kod Aynı Anda » Veri Dolumu — Mevcut Veriyi Güvenle Dönüştürmek » Aileyi Bir Arada Görmek — Veriyi Evrimleştirmek » Üç Gözlem Sorusu » Felsefi Kapanış » Sonraki Bölüm » https://gitlab.com/sahin.yelkenci2/refactoring-canli-bahis
Veri Neden En Sert Problem — Şemanın Üç Laneti
Bir veritabanı şeması, refactor edilmesi en zor şeydir, ve bunun üç nedeni — üç laneti — vardır. Bu üç laneti anlamak, neden mimari göçlerin tam veri katmanında tıkandığını (↗ Bölüm 19) açıklar.
Birinci lanet, paylaşımdır. Bir şema tipik olarak birçok uygulama ve servis tarafından paylaşılır — entegrasyon veritabanının asıl günahı budur. Bir şema değişikliği, her tüketiciye dalgalanır. Koddan farklı olarak (tek bir kod tabanı), bir şemanın çok sayıda, çoğu zaman bilinmeyen bağımlısı vardır. Bu, ↗ Bölüm 7'deki bağlılığın veri katmanındaki en şiddetli hâlidir: Bir sütunu değiştirdiğinizde, onu okuyan kaç sistemin kırılacağını bile bilmeyebilirsiniz.

İkinci lanet, durumdur (state). Bir şema yalnızca yapı değildir — canlı verisi vardır. Yapıyı değiştirmek, mevcut veriyi (potansiyel olarak devasa hacimleri) dönüştürmek demektir; bu yavaştır, risklidir, ve “yeniden derlenemez”. Kodda bir değişikliği derleyip biten alırsınız; veride, milyonlarca satırı dönüştürürken sistem çalışmaya devam etmek zorundadır.
Üçüncü lanet, geri alınamazlıktır. Bir veri dönüşümünü kolayca geri alamazsınız. Bir sütunu silerseniz verisi gider; veriyi dönüştürürseniz orijinali kaybolabilir. Geri alma, kodda olduğundan çok daha zordur — kodda yalnızca commit’i geri alırsınız, veride ise kaybolan veriyi geri getiremezsiniz. Bu üç lanet — paylaşılan, durumlu, geri alınması zor — şemayı en zor refactoring hedefi yapar. Ama umut vardır: Aynı refactoring disiplini burada da geçerlidir, ve üçünün de ilacı aynıdır — kademeli, expand-contract, davranış koruyan adımlar; asla büyük atomik bir şema değişikliği değil.

Verinin neden en sert problem olduğunu bilmenin dersi şudur: Bir veritabanı şeması üç lanet yüzünden en zor refactoring hedefidir — paylaşım (çok sistemin bilinmeyen bağımlılığı), durum (dönüştürülmesi gereken canlı veri) ve geri alınamazlık (silinen verinin geri getirilememesi); ama aynı refactoring disiplini geçerlidir ve üçünün de ilacı aynıdır: kademeli, expand-contract, davranış koruyan adımlar — asla büyük atomik bir şema değişikliği değil.
Database Refactoring — Şemayı Davranış Koruyarak Değiştirmek
Ambler ve Sadalage’in tanımıyla, bir database refactoring, bir şemada yapılan, tasarımını iyileştirirken hem davranışsal hem de bilgisel anlamı KORUYAN küçük bir değişikliktir. Yani verinin ne anlama geldiğini ya da sistemin ne yaptığını değiştirmez, yalnızca yapıyı düzeltir.

Bu tanımın ↗ Bölüm 1'deki kod refactoring tanımıyla aynı olduğuna dikkat edin: davranış koruyan yapısal değişiklik — yalnızca şemaya uygulanmış. Korunan davranış ikidir: verinin anlamı (bilgisel anlam) ve sistemin davranışı (davranışsal anlam). Database refactoring’lerin de tıpkı Kısım III gibi bir kataloğu vardır: Rename Column, Split Table, Merge Columns, Introduce Calculated Column, Move Column, Add Lookup Table ve daha fazlası. Her biri, küçük ve davranış koruyan bir şema dönüşümüdür.
Kod refactoring’inden kritik farkı şudur: Bir database refactoring, yapıyı + veriyi + erişim kodunu birden kapsar, ve üç lanet yüzünden atomik değil, aşamalı ve geriye uyumlu bir şekilde (expand-contract) yapılmalıdır. Bir kod Rename’i atomiktir (IDE anında yapar); bir DB Rename Column ise çok aşamalı bir göçtür. Bu yüzden her database refactoring’in bir “geçiş dönemi” (transition period) vardır — eski ve yeni şema öğelerinin bir arada var olduğu, tüm tüketicilerin göç etmesine izin veren bir pencere. Bu geçiş dönemi, ↗ Bölüm 19'da gördüğümüz “eski ve yeni bir arada yaşar” ilkesinin veri katmanındaki hâlidir.

Database refactoring’i bilmenin dersi şudur: Bir database refactoring, bir şemada yapılan, verinin anlamını ve sistemin davranışını koruyan küçük bir tasarım iyileştirmesidir — kod refactoring tanımının şemaya uygulanmış hâli; bir kataloğu vardır (Rename Column, Split Table…), ama kod refactoring’inden farkı yapıyı, veriyi ve kodu birden kapsamasıdır, bu yüzden atomik değil, eski ve yeninin bir arada yaşadığı bir geçiş dönemiyle aşamalı ve geriye uyumlu yapılır.
Expand-Contract — Sıfır Kesintili Şema Değişikliği
Tüm database refactoring’lerin temel tekniği, Expand-Contract’tır (Genişlet-Daralt; ↗ Bölüm 16'daki Parallel Change’in şemaya uygulanmış hâli). Sıfır kesintili (zero-downtime) şema değişikliği yapmanın standart yoludur.
Üç aşaması vardır. GENİŞLET: Yeni şema öğesini (yeni sütun/tablo), eskiyi KALDIRMADAN ekle. Şemada artık ikisi de var. Yazmaları her ikisine de gönder (uygulama kodu ya da DB tetikleyicisiyle çift yazma), ve mevcut veriyi yeni öğeye doldur (backfill). Hem eski hem yeni geçerli. GÖÇ ET: Okuyucuları eskiden yeniye taşı (yeniyi okuyan kodu dağıt); yazıcıları tamamen yeniye geçir. DARALT: Hiçbir şey eskiyi okumayıp yazmadığında, onu kaldır (eski sütunu/tabloyu düşür).

Bu neden sıfır kesinti verir? Çünkü şema hiçbir noktada çalışan kodla uyumsuz bir durumda olmaz. Eski öğe, tüm kod onu kullanmayı bırakana kadar var olur; yeni öğe, herhangi bir kod onu kullanmadan önce var olur. Her dağıtım geriye uyumludur. Şema değişikliği ile kod dağıtımının ayrıştığını görün: Şema göçleri ve kod dağıtımları ayrı, sıralı adımlarda olur — şemayı genişlet (1. dağıtım), yeniyi kullanan kodu dağıt (2. dağıtım), şemayı daralt (3. dağıtım). Şu an çalışan kodu kıran bir şema değişikliğini asla dağıtmazsınız.
-- ÖRNEK: kupon tablosuna yeni para_birimi sütunu eklemek
-- GENİŞLET: yeni sütunu ekle (eskiyi kaldırma), mevcut veriyi doldur
ALTER TABLE kupon ADD COLUMN para_birimi VARCHAR(3);
UPDATE kupon SET para_birimi = 'TRY' WHERE para_birimi IS NULL; -- backfill
-- uygulama artık ÇİFT YAZAR: hem eski varsayım hem yeni para_birimi
-- GÖÇ ET: okuyucular yeni sütunu okuyan koda geçer (ayrı dağıtım)
-- DARALT: hiçbir şey eski varsayımı kullanmayınca temizlenir (ayrı dağıtım)
Bu, ↗ Bölüm 16'daki Parallel Change’in veri katmanındaki birebir uygulamasıdır — yalnızca durulu (stateful) olduğu için backfill ve çift yazma adımlarıyla zenginleştirilmiştir. Genişlet aşamasında her iki öğe de korunduğu için, tüm tüketiciler kendi takvimlerinde göç edebilir; ve sistem hiçbir an durmaz. Sıfır kesintinin sırrı, şemayı asla çalışan koddan ileride ya da geride bırakmamaktır.

Expand-Contract’ı bilmenin dersi şudur: Tüm database refactoring’lerin temel tekniği, Parallel Change’in şemaya uygulanmış hâli olan Expand-Contract’tır — yeni öğeyi ekle ve mevcut veriyi doldurup çift yaz (genişlet), okuyucuları taşı (göç et), kimse kullanmayınca eskiyi düşür (daralt); bu sıfır kesinti verir çünkü şema hiçbir an çalışan kodla uyumsuz değildir, ve şema değişikliğini kod dağıtımından ayırarak şu an çalışan kodu kıran bir değişikliği asla dağıtmazsınız.
Rename Column — Bir Sütunu Güvenle Yeniden Adlandırmak
Database refactoring’in kanonik worked example’ı, bir sütunu yeniden adlandırmaktır — ↗ Bölüm 14'teki kod Rename’inin veri katmanındaki kardeşi. Ama kodda atomik olan bu hamle, veride çok aşamalı bir göçtür, çünkü sütun paylaşılan ve durulu bir şeydir.
Bir kod Rename’i atomiktir (IDE anında yapar); bir DB Rename Column ise tam bir expand-contract göçüdür. kupon tablosundaki tutar sütununu miktar olarak yeniden adlandırmayı, üç aşamada görelim.

GENİŞLET:
ALTER TABLE kupon ADD COLUMN miktar NUMERIC(19,2); -- yeni sütun, eskiyi koru
UPDATE kupon SET miktar = tutar; -- mevcut veriyi doldur (backfill)
-- bir tetikleyici (trigger) ya da uygulama kodu, geçiş boyunca
-- tutar ve miktar'ı senkron tutar (çift yazma)
GÖÇ ET: miktar'ı okuyan/yazan kodu dağıt; doğrula; eski tutar hâlâ senkronla korunuyor.
DARALT:
ALTER TABLE kupon DROP COLUMN tutar; -- artık kimse kullanmıyor
-- senkron tetikleyicisi de kaldırılır
Buradaki asıl ders şudur: Kodda tek bir atomik işlem olan bir “rename”, veritabanında dikkatli, çok dağıtımlı bir göç olur — bu, üç lanetin bedelidir, ve expand-contract güvenli yoldur. Bir nüans: Geçiş dönemindeki çift yazma/senkronizasyon (tetikleyici ya da uygulama), bu hamleyi güvenli kılan şeydir — her iki sütun da geçiş boyunca geçerli kalır. Bu senkronizasyonu atlamayın; onsuz, eski kod tutar'a yazarken yeni kod miktar'ı okur ve veri ıraksar.

Rename Column’ı bilmenin dersi şudur: Kodda atomik olan bir sütun yeniden adlandırma, veride üç aşamalı bir expand-contract göçü olur — yeni sütunu ekle, eskiden doldur ve çift yaz (genişlet), yeni sütunu kullanan kodu dağıt (göç et), sonra eski sütunu düşür (daralt); sırrı, geçiş boyunca iki sütunu senkron tutan çift yazmadır, çünkü onsuz eski ve yeni veri ıraksar.
Göç Betikleri — Şema Evrimini Versiyonlamak
Şema değişikliklerini elle yapmazsınız; göç betikleriyle (migration) yaparsınız. Göç betikleri, şemayı evrimleştiren versiyonlanmış, sıralı ve tekrarlanabilir betiklerdir — Flyway ve Liquibase gibi araçlarla yönetilir. Her göç, küçük, numaralı, çoğu zaman yalnızca ileri yönlü bir değişikliktir ve uygulama koduyla birlikte versiyon kontrolündedir.
Göç betikleri neden önemlidir? Çünkü şemanın evrimi, tekrar üretilebilir ve versiyon kontrollü hâle gelir — tıpkı kodun refactoring geçmişi gibi. Her ortam (geliştirme, hazırlık, üretim) aynı sıralı göçleri uygular, böylece şemalar senkron kalır. Üretimde elle ALTER çalıştırmazsınız; bir göç yazar, commit eder, ve araç onu her yerde uygular. Göçler bir kez uygulandıktan sonra değişmezdir: Üretimde çalışmış bir göçü asla düzenlemezsiniz; düzeltmek/değiştirmek için yeni bir göç yazarsınız (yalnızca-ileri disiplini).

Bu, refactoring disiplininin veri katmanındaki yansımasıdır: küçük adımlar (her göç küçüktür), versiyon kontrolü (↗ Bölüm 23), tekrar üretilebilirlik, ve şemanın izlenen artışlarla evrimleşmesi — her refactoring adımını commit etmenin DB karşılığı. Her expand-contract aşaması tipik olarak kendi göçüdür: bir genişletme göçü, sonra (kod dağıtımının ardından) bir daraltma göçü. Göçler, aşamalı planı kodlar.
-- V5__kupon_miktar_ekle.sql (GENİŞLET aşaması)
ALTER TABLE kupon ADD COLUMN miktar NUMERIC(19,2);
UPDATE kupon SET miktar = tutar;
-- ... arada: miktar'ı kullanan kod dağıtılır ...
-- V7__kupon_tutar_dusur.sql (DARALT aşaması, ayrı göç)
ALTER TABLE kupon DROP COLUMN tutar;
Göçlerin numaralı ve açıklayıcı adlandırılması (V{n}__{açıklama}.sql), şema evriminin okunabilir bir tarihçesini oluşturur — bir yıl sonra biri "miktar sütunu nereden geldi?" diye sorduğunda, cevap göç tarihçesindedir. Göç betikleri, şemayı evcil bir "yapılandırılmış metin"e dönüştürür: izlenebilir, gözden geçirilebilir (code review), ve geri sarılabilir bir evrim.

Göç betiklerini bilmenin dersi şudur: Şema değişiklikleri, versiyonlanmış, sıralı ve tekrarlanabilir göç betikleriyle yapılır (Flyway/Liquibase) — bu, şema evrimini tekrar üretilebilir ve versiyon kontrollü kılar, tıpkı kodun refactoring geçmişi gibi; her ortam aynı göçleri uygular, göçler bir kez çalıştıktan sonra değişmezdir (yalnızca-ileri), ve her expand-contract aşaması kendi göçü olarak aşamalı planı kodlar.
Geriye Uyumluluk — Eski ve Yeni Kod Aynı Anda
Sıfır kesintili dağıtımların (rolling deploy) altında bir gerçek yatar: Eski ve yeni kod sürümleri AYNI ANDA çalışır — tüm örnekler bir anda yükseltilmez. Bu yüzden her şema durumu, birlikte çalışan HEM eski HEM yeni kodla uyumlu olmalıdır. İşte expand-contract’ı ve adımların sırasını zorunlu kılan kısıt budur.
Kuralı somutlaştıralım: Eski (hâlâ çalışan) kodun okuduğu bir sütunu düşüremezsiniz — eski kod onu ararken bulamaz. Yeni bir sütunu, eski kod (onu ayarlamayan) çalışmayı bırakmadan önce NOT NULL yapamazsınız — eski kodun eklemeleri kırılır. Kural şudur: Her ara durum (şema + birlikte çalışan kod sürümleri kümesi), karşılıklı uyumlu olmalıdır. Bu, aşamalı yaklaşımı zorlar — genişlet (eskiyle uyumlu, yeni için hazır), tüm kod yükselsin, sonra daralt (artık eski kod kalmadığı için güvenli).

Bu, ↗ Bölüm 16'daki “her zaman sevk edilebilir” ve “her ara durum geçerli” kısıtının, eklenen bir karmaşıklıkla — birden çok kod sürümünün aynı anda çalışması (rolling deploy) — birlikte hâlidir. Uyumluluk tuzaklarına dikkat: Varsayılansız bir NOT NULL sütun eklemek (eski eklemeleri kırar); bir sütunu çok erken düşürmek (eski okumaları kırar); yerinde yeniden adlandırmak (geçiş anında hem eskiyi hem yeniyi kırar). Disiplin şudur: Her şema değişikliğini, geçiş penceresi boyunca hem geriye hem ileriye uyumlu olacak şekilde tasarlayın — ve expand-contract bunu garanti eder.

Geriye uyumluluğu bilmenin dersi şudur: Rolling deploy’da eski ve yeni kod aynı anda çalıştığı için, her şema durumu birlikte çalışan hem eski hem yeni kodla uyumlu olmalıdır — bu, eski kodun okuduğu sütunu düşürmeyi ya da eski kodu kıracak bir NOT NULL eklemeyi yasaklar; her ara durumun geçerli olması kısıtı aşamalı yaklaşımı zorlar, ve expand-contract her şema değişikliğini geriye ve ileriye uyumlu tutarak bunu garanti eder.
Veri Dolumu — Mevcut Veriyi Güvenle Dönüştürmek
Expand aşamasının en sert pratik kısmı, veri dolumudur (backfill): Mevcut veriyi yeni yapıya dönüştürmek. Çünkü veri hacimleri devasa olabilir, ve tabloyu saatlerce kilitleyemezsiniz. Milyarlarca satırlık bir tabloda tek bir UPDATE, tabloyu kilitler, saatlerce çalışır, işlem günlüklerini (transaction log) şişirir, ve canlı sistemi riske atar.

Bu yüzden veri dolumu dikkatle yapılmalıdır, ve birkaç teknik vardır. Birincisi, parçalı dolum (batched backfill): veriyi küçük parçalar hâlinde (örneğin her seferinde bin satır) işleyip her parçayı commit ederek ilerlemek — böylece tablo kilitlenmez ve sistem hizmet vermeye devam eder. İkincisi, çevrimiçi/kısıtlı (throttled): düşük trafik saatlerinde çalıştırmak, DB’yi aşırı yüklememek için hızı kısmak. Üçüncüsü, idempotent (yeniden çalıştırılabilir): dolum yarıda kalırsa kaldığı yerden devam edebilmeli — yalnızca henüz göç etmemiş satırları işleyerek.
-- Parçalı, idempotent backfill (kavramsal): kilit tutmadan, parça parça
UPDATE kupon SET miktar = tutar
WHERE miktar IS NULL -- idempotent: yalnızca göç etmemiş satırlar
AND id BETWEEN :baslangic AND :bitis; -- batch penceresi
-- döngüde, her batch'i commit ederek ilerle; aralarda kısa bekle (throttle)
Çift yazma ile veri dolumunun nasıl birlikte çalıştığını görün: Expand sırasında YENİ yazmalar her ikisine de gider (çift yazma), bu sırada backfill ESKİ mevcut satırları halleder. İkisi birlikte, tüm verinin — eski ve yeni — yeni yapıda olmasını garanti eder. Ve son bir disiplin: Doldurmadan sonra, okuyucuları göç etmeden ÖNCE tutarlılığı doğrulayın (satır sayıları, sağlama toplamları). Veriye güvenmeyin, doğrulayın — çünkü sessizce eksik dolan bir backfill, en sinsi veri hatasıdır.

Veri dolumunu bilmenin dersi şudur: Mevcut veriyi yeni yapıya dönüştürmek (backfill) en sert pratik kısımdır çünkü devasa hacimde tek bir UPDATE tabloyu kilitleyip sistemi riske atar; çözüm parçalı (her batch commit, kilit yok), kısıtlı (düşük trafikte, hızı kıs) ve idempotent (yarıda kalırsa devam) dolumdur — çift yazma yeni satırları, backfill eski satırları halleder, ve okuyucuları göç etmeden önce tutarlılık mutlaka doğrulanmalıdır, çünkü sessizce eksik dolan bir backfill en sinsi veri hatasıdır.
Aileyi Bir Arada Görmek — Veriyi Evrimleştirmek
Bu bölümün parçalarını tanıdık; şimdi onların tek bir bütün oluşturduğunu görelim. Çünkü bu bölümün tamamı tek bir fikirdir: Şemayı, kodu evrimleştirdiğiniz gibi — kademeli, davranış koruyarak, expand-contract ile — evrimleştirin; üç lanete rağmen.
Parçaların nasıl birleştiğine bakın. Üç lanet (paylaşım, durum, geri alınamazlık) probleminin neden zor olduğunu söyler. Database refactoring tanımı (anlamı koruyan şema değişikliği) hedefi belirler. Expand-contract çekirdek tekniktir. Göç betikleri evrimi versiyonlar. Geriye uyumluluk, adımların sırasını zorlayan kısıttır. Veri dolumu, durulu veriyi taşıyan iştir. Bunların hepsi, tek bir güvenli şema değişikliğinin anatomisini oluşturur.

Birleştiren en derin kavrayış şudur: Bir şema, birlikte evrimleşen veri + yapı + tüketicilerdir; güvenli yol her zaman kademeli, davranış koruyan, expand-contract’tır — asla büyük atomik bir değişiklik değil. Veri en zor ortamdır çünkü durulu, paylaşılan ve geri alınması zordur; ama onu evcilleştiren disiplin, kodu evcilleştiren disiplinin AYNISIDIR — küçük adımlar, her zaman uyumlu, mümkün olduğunca tersine çevrilebilir. Üç lanetten kaçış yoktur; onları aşamalandırma (phasing) ile yönetirsiniz. Veri, refactoring felsefesinin en sert sınavıdır — ve onu geçen, felsefenin gerçekten evrensel olduğunu görmüştür.

Veriyi evrimleştirmeyi bilmenin dersi şudur: Bu bölümün parçaları tek bir güvenli şema değişikliğinin anatomisini oluşturur — genişletme göçü, çift yazma ve backfill, doğrulama, kod dağıtımı, daraltma göçü; en derin kavrayış, verinin en zor ortam olmasına rağmen (durulu, paylaşılan, geri alınması zor) onu evcilleştiren disiplinin kodu evcilleştirenin aynısı olmasıdır — küçük adımlar, her zaman uyumlu, kademeli; üç lanetten kaçış yoktur, onları aşamalandırmayla yönetirsiniz.
Üç Gözlem Sorusu
Bu veri bölümünü, kendi sisteminizin şemasını sınayan üç soruyla kapatalım.
Birinci Gözlem Sorusu. Veritabanı şemanızda, kötü adlandırılmış ya da kötü tasarlanmış olduğunu bildiğiniz ama “değiştirmeye korktuğunuz” bir sütun ya da tablo var mı? Onu expand-contract ile — yeni öğeyi ekleyip, çift yazıp, backfill edip, kodu göç ettirip, sonra eskiyi düşürerek — sistemi hiç durdurmadan değiştirebileceğinizi fark etmek, o korkuyu azaltır mı?

İkinci Gözlem Sorusu. Şema değişikliklerinizi nasıl yapıyorsunuz — üretimde elle ALTER çalıştırarak mı, yoksa versiyonlanmış göç betikleriyle mi? Eğer elle yapıyorsanız, geliştirme ve üretim şemalarınızın senkron kaldığından nasıl emin oluyorsunuz, ve bir değişikliğin "nereden geldiğini" bir yıl sonra nasıl izliyorsunuz?

Üçüncü Gözlem Sorusu. Son yaptığınız bir şema değişikliğini düşünün. O değişiklik, rolling deploy sırasında aynı anda çalışan eski ve yeni kod sürümleriyle uyumlu muydu — yoksa kısa bir kesinti mi gerektirdi? Eğer kesinti gerektirdiyse, expand-contract’ı uygulasaydınız o kesintiyi sıfıra indirebilir miydiniz?

Felsefi Kapanış
Bu bölümle, refactoring felsefesinin en sert sınavını — veriyi — geçtik. Ve gördük ki, en zor ortamda bile aynı ilkeler işler: küçük adımlar, davranışı koruma, eski ile yeniyi bir süre yan yana yaşatma. Veri, refactoring’in sınırı değil; onun en derin doğrulamasıdır. Çünkü bir felsefe, ancak en zor koşulda da geçerliyse gerçekten evrenseldir — ve refactoring, durulu, paylaşılan, geri alınması imkânsız verinin karşısında bile ayakta kalır.

Bu yüzden bölümü, verinin doğasına dair bir düşünceyle kapatalım:
Bir binanın temelini, içinde insanlar yaşarken değiştirmek — mühendisliğin en korkutucu işidir. Çünkü temel, görünmezdir ama her şeyi taşır; bir hata, yalnızca bir odayı değil, tüm yapıyı çökertir. Usta, bu işi asla tek bir hamlede yapmaz; yeni bir kirişi eskinin yanına yerleştirir, yükü yavaşça ona aktarır, eskinin hâlâ taşıdığından emin olur, ve ancak yeni tamamen güvenli olduğunda eskiyi söker — ve binada yaşayanlar, ayaklarının altındaki temelin tamamen yenilendiğini hiç hissetmez. Veri, bir yazılım sisteminin temelidir: en derinde, en görünmez, ve en kritik. Onu evrimleştirmek cesaret değil, sabır ister; çünkü temeli değiştirenin lüksü yoktur — yalnızca disiplini vardır. Ve o disiplin, bu serinin baştan beri söylediği tek şeydir: küçük adım, her adımda ayakta.
Sonraki Bölüm
***↗ Bölüm 21: Yüksek TPS ve Eşzamanlı Kodu Refactor Etmek — Performans, Thread Güvenliği ve En İnce Davranış ile Kısım IV’ü tamamlıyoruz.*** Şimdiye kadar “davranışı koru” derken, çoğunlukla işlevsel davranışı kastettik — kodun ne döndürdüğünü, ne yaptığını. Ama canlı bahis gibi yüksek TPS (saniyede işlem) sistemlerinde, korunması gereken iki ince davranış daha vardır: performans ve thread güvenliği. Bir refactoring işlevsel olarak doğru olabilir ama gizlice bir kilit darboğazı, bir yarış koşulu (race condition) ya da bir performans gerilemesi getirebilir — ve bunlar, en sinsi hatalardır, çünkü testlerin çoğu onları yakalamaz. Bu bölümde, eşzamanlı ve performans-kritik kodu refactor ederken bu görünmez davranışları nasıl koruyacağımızı göreceğiz: thread güvenliğini bozmadan refactor etmeyi, değişmezliğin (immutability) eşzamanlılıktaki gücünü, ve performans gerilemelerini ölçerek yakalamayı. Veriyi evrimleştirmeyi öğrendik; şimdi Kısım IV’ün son ve en ince meydan okumasına — hızı ve eşzamanlılığı korumaya — geçiyoruz.
**İçindekiler… « Önceki [Bölüm 19: Mimari Refactoring — Strangler Fig ve Modülerleşme] » Sonraki *[Bölüm 21: Yüksek TPS ve Eşzamanlı Sistemlerde Refactoring] *» https://gitlab.com/sahin.yelkenci2/refactoring-canli-bahis
메타데이터
- post_id
- f7d8f778e33d
- slug
- refactoring-mevcut-kodun-tasarımını-i̇yileştirme-sanatı-bölüm-20-veritabanı-refactoring-şema-f7d8f778e33d
- url
- https://medium.com/@sahinyelkenci/refactoring-mevcut-kodun-tasar%C4%B1m%C4%B1n%C4%B1-i%CC%87yile%C5%9Ftirme-sanat%C4%B1-b%C3%B6l%C3%BCm-20-veritaban%C4%B1-refactoring-%C5%9Fema-f7d8f778e33d
- canonical_url
- https://medium.com/@sahinyelkenci/refactoring-mevcut-kodun-tasar%C4%B1m%C4%B1n%C4%B1-i%CC%87yile%C5%9Ftirme-sanat%C4%B1-b%C3%B6l%C3%BCm-20-veritaban%C4%B1-refactoring-%C5%9Fema-f7d8f778e33d
- author_url
- https://medium.com/@sahinyelkenci
- status
- ok
- fetched_at
- 2026-08-07 04:19:21