Refactoring — Mevcut Kodun Tasarımını İyileştirme Sanatı — Bölüm 21: Yüksek TPS ve Eşzamanlı…
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 21: Yüksek TPS ve Eşzamanlı Sistemlerde Refactoring
Kısım IV — Büyük Resim: Sistem Ölçeğinde Refactoring
İçindekiler
Kısım IV’ü, en ince meydan okumayla 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 görünmez 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.
» Görünmez Davranış — İşlevin Ötesinde Üç Davranış » Thread Güvenliği — Yerel Olmayan, Beliren Bir Özellik » Atomikliği Korumak — En Sinsi Eşzamanlılık Tuzağı » Yayınlama Kaçağı — Mutable Referansı Sızdırmak » Değişmezlik — Eşzamanlılığın En Güçlü Aracı » Performans Gerilemesi — Sıcak Yolda Ölçerek Yakalamak » Görünmez Davranış İçin Test — Yük, Stres ve Profil » Aileyi Bir Arada Görmek — Üç Ağ Birden » Üç Gözlem Sorusu » Felsefi Kapanış » Sonraki Bölüm » *https://gitlab.com/sahin.yelkenci2/refactoring-canli-bahis*
Görünmez Davranış — İşlevin Ötesinde Üç Davranış
↗ Bölüm 1'de refactoring’i tanımlarken, “davranışı koru” dedik — ve o davranışı çoğunlukla işlevsel olarak anladık: kodun ne döndürdüğü, gözlemlenebilir olarak ne yaptığı. Bu, çoğu kod için yeterlidir. Ama yüksek TPS ve eşzamanlı sistemlerde — canlı bahis tam da budur — bu tanım eksiktir. Çünkü orada, işlevsel testlere görünmez olan iki davranış daha vardır ve korunmaları gerekir: performans ve thread güvenliği.
Yani bu alanda “davranışı koru”, üç davranışa genişler. Birincisi işlevsel: kod ne döndürür, ne yapar. İkincisi performans: ne kadar hızlı, ne kadar verim (throughput). Üçüncüsü thread güvenliği: eşzamanlılık altında doğruluk. Bir refactoring, üçünü birden korumalıdır. İşlevsel olarak mükemmel ama performansı geri götüren ya da thread güvenliğini bozan bir refactoring, bu alanda başarısız bir refactoring’dir.

Tehlike şudur: Bir refactoring işlevsel olarak kusursuz olabilir — tüm birim testleri geçer — ama gizlice bir kilit darboğazı (performans gerilemesi), bir yarış koşulu (thread güvenliği ihlali) ya da pahalı bir yeniden hesap (performans gerilemesi) getirebilir. Bunlar en sinsi hatalardır, çünkü olağan güvenlik ağınız — işlevsel test takımı (↗ Bölüm 4) — onları yakalamaz. Yalnızca üretimde, yük ve eşzamanlılık altında yüzeye çıkarlar; ve o zaman çok geçtir.
Bu yüzden yüksek TPS kodu ekstra özen ve ekstra ağlar ister. Bahis domain’i — yarış oranları, gerçek zamanlı bahis, ödeme işleme — tam olarak budur: binlerce eşzamanlı kullanıcı, milisaniyelerle ölçülen gecikme, ve para. Bu bölümün tezi şudur: Bu kodu, üç davranışı birden akılda tutarak refactor edin, ve üçünü birden doğrulayın. İşlevsel doğruluk yeterli değildir; hız ve eşzamanlılık güvenliği de korunmalıdır.

Görünmez davranışı bilmenin dersi şudur: Yüksek TPS ve eşzamanlı sistemlerde “davranışı koru” üç davranışa genişler — işlevsel (ne döndürür), performans (hız + verim) ve thread güvenliği (eşzamanlılıkta doğruluk); bir refactoring işlevsel olarak kusursuz olsa bile gizlice bir kilit darboğazı, yarış koşulu ya da yeniden hesap getirebilir, ve bunlar en sinsi hatalardır çünkü işlevsel test takımı onları yakalamaz — yalnızca üretimde yük altında çıkarlar.
Thread Güvenliği — Yerel Olmayan, Beliren Bir Özellik
Thread güvenliğini refactor ederken anlaşılması gereken en kritik gerçek şudur: O, yerel olmayan, beliren (emergent) bir özelliktir. Bir metodu okuyarak thread güvenli olup olmadığını göremezsiniz. Kodun thread güvenli olup olmaması, birden çok thread’in birden çok metot ve nesne boyunca etkileşimine, kilitleme disiplinine ve görünürlük (visibility) garantilerine bağlıdır. Bütünden belirir, herhangi bir parçadan değil.

Bu, eşzamanlı kodu refactor etmeyi tehlikeli kılar: Yerel bir değişiklik — bir metot çıkarmak, bir değişken tanıtmak, bir alanın erişimini değiştirmek — yerel olmayan bir değişmezi (invariant) bozabilir. Refactoring, izole olarak bakıldığında güvenli görünür ama küresel thread güvenliği özelliğini kırar. Örneğin senkronize bir bloğun bir parçasını kilidin dışına çıkarmak, o parçayı artık senkronizasyonsuz çalıştırır; kilit içinde okunan bir değeri tutan bir geçici değişken tanıtıp onu kilit dışında kullanmak, bayat (stale) bir okuma yaratır; bir final ya da volatile alanı değiştirmek, görünürlüğü bozar.
Disiplin şudur: Eşzamanlı kodu refactor etmeden ÖNCE, thread güvenliği değişmezlerini anlamalısınız — neyin hangi kilitle korunduğu, neyin atomik olması gerektiği, neyin görünürlüğe ihtiyaç duyduğu — ve onları korumalısınız. Ve burada, bu serinin baştan beri verdiği bir öğüde kritik bir istisna gelir: ↗ Bölüm 1'deki “araca güven” öğüdü, eşzamanlı kod için tam geçerli değildir. IDE’nin otomatik refactoring’leri İŞLEVSEL davranışı korur, ama thread güvenliğini DEĞİL. Otomatik bir Extract Method, kodu bir kilidin dışına taşıyabilir — ve işlevsel olarak doğru kalırken thread güvenliğini sessizce kırabilir. Eşzamanlı kodda, aracın değil, sizin yargınızın son sözü vardır.

Thread güvenliğini bilmenin dersi şudur: Thread güvenliği yerel olmayan, beliren bir özelliktir — bir metodu okuyarak görülemez, birden çok thread’in etkileşiminden belirir; bu yüzden yerel bir refactoring (metot çıkarma, değişken tanıtma, alan erişimi değiştirme) yerel olmayan bir değişmezi bozabilir, ve kritik bir istisna gelir: IDE’nin otomatik refactoring’leri işlevsel davranışı korur ama thread güvenliğini değil — eşzamanlı kodda son söz araçta değil, sizin yargınızdadır.
Atomikliği Korumak — En Sinsi Eşzamanlılık Tuzağı
Refactoring’in eşzamanlı koda getirdiği en yaygın ve en sinsi hata, bir bileşik işlemin atomikliğini bozmaktır. Bir bileşik işlem (kontrol-et-sonra-uygula, oku-değiştir-yaz), eşzamanlılık altında doğru olmak için atomik olmalıdır — tek bir bölünmez adım olarak, bir kilidin altında yapılmalıdır. Refactoring, onu atomik olmayan parçalara bölebilir: “kontrol”ü bir metoda, “uygula”yı başka bir metoda çıkarmak ya da bir parçayı kilidin dışına taşımak, kontrol ile uygula arasına başka bir thread’in girdiği bir yarış koşulu yaratır.

Bahis limit kontrolünü düşünün: “eğer mevcut bahis + yeni bahis ≤ LIMIT ise bahis ekle” işlemi atomik olmalıdır.
// ÖNCE — tek kilit altında atomik (DOĞRU)
public synchronized void bahisEkle(Bahis b) {
if (toplamBahis().add(b.miktar()).compareTo(LIMIT) <= 0) { // kontrol
bahisler.add(b); // uygula — kontrolle atomik
}
}
// SONRA — dikkatsiz bir refactoring: kontrol ve uygula bölündü, ATOMİK DEĞİL (yarış!)
public boolean limitUygun(Bahis b) { // kontrol
return toplamBahis().add(b.miktar()).compareTo(LIMIT) <= 0;
}
public void bahisEkle(Bahis b) { bahisler.add(b); } // uygula
// çağıran: if (limitUygun(b)) bahisEkle(b);
// İKİ thread aynı anda limitUygun'dan geçip ikisi de ekler → LİMİT AŞILIR
İkinci versiyon işlevsel olarak özdeş görünür — tek thread’de aynı sonucu verir, tüm birim testleri geçer. Ama atomikliği kırdı: İki thread aynı anda limitUygun'dan geçebilir (çünkü ikisi de henüz eklemeden kontrol eder), sonra ikisi de ekler, ve limit aşılır. Bu, ↗ Bölüm 14'teki Separate Query from Modifier ile bir gerilim yaratır: Komut-Sorgu Ayrımı işlevsel olarak mükemmeldir, ama eşzamanlı kodda kontrolü (sorgu) uygula'dan (komut) ayırmak atomikliği bozabilir — çünkü ikisinin tek bir bölünmez adım olması gerekir. Ders şudur: Bir senkronize bölgenin etrafında çıkarma/bölme yaparken, bileşik işlemi atomik tutmalısınız — ya tek bir kilit altında bırakarak, ya atomik ilkeller (compareAndSet gibi) kullanarak.

Atomikliği korumayı bilmenin dersi şudur: Bir bileşik işlem (kontrol-et-uygula), eşzamanlılıkta doğru olmak için tek bir bölünmez adım olarak bir kilidin altında atomik olmalıdır; refactoring onu kontrol ve uygula olarak ayırırsa, aralarına başka bir thread girer ve bir yarış koşulu doğar — işlevsel olarak özdeş görünse de; bu, Separate Query from Modifier ile bir gerilim yaratır, ve çözüm bileşik işlemi tek bir kilit altında ya da atomik bir ilkelle bölünmez tutmaktır.
Çalışan örnek kodlara erişmek için: » https://gitlab.com/sahin.yelkenci2/refactoring-canli-bahis
Yayınlama Kaçağı — Mutable Referansı Sızdırmak
Eşzamanlı kodu refactor ederken ikinci sinsi tuzak, daha önce güvenle sınırlanmış (confined) bir mutable referansı yanlışlıkla yayınlamaktır (sızdırmak). Bu, ↗ Bölüm 12'deki Encapsulate Collection’ın “private yetmez” dersinin eşzamanlılık ışığındaki hâlidir — orada bir kapsülleme sızıntısıydı, burada bir thread güvenliği ihlalidir.

Tehlike şudur: Dikkatsiz bir Extract Variable, bir alanı döndürmek ya da bir Encapsulate Collection, içsel mutable duruma bir referans dağıtabilir. Tek thread’li kodda bu hafif bir kapsülleme sızıntısıdır (↗ Bölüm 12); ama eşzamanlı kodda bir thread güvenliği ihlalidir — başka bir thread artık içsel durumu, kilidi tutmadan değiştirebilir, ve senkronizasyon değişmezini bozar. Thread güvenliği çoğu zaman bir mutable nesnenin sınırlı kalmasına (yalnızca kilit altında erişilmesine) dayanır; referansı sızdıran bir refactoring, bu sınırlamayı kırar.
// SIZINTI — canlı mutable listeyi döndürür; eşzamanlı çağıran kilitsiz değiştirir → yarış
public List<Bahis> getBahisler() { return bahisler; }
// iki thread aynı anda iterasyon + değiştirme → ConcurrentModificationException / bozulma
// GÜVENLİ — savunmacı kopya / değiştirilemez görünüm; içsel durum sınırlı kalır
public List<Bahis> getBahisler() { return List.copyOf(bahisler); }
Çözüm, ↗ Bölüm 12'dekiyle aynıdır ama bu kez eşzamanlılık güdümlüdür: canlı mutable referansı asla sızdırmayın; değiştirilemez bir kopya ya da görünüm döndürün. Yani Encapsulate Collection, yalnızca bir tasarım refactoring’i değil, aynı zamanda bir thread güvenliği refactoring’idir. Ve ↗ Bölüm 12'deki “private yetmez” dersi burada iki kat kritiktir: Alanı private yapmak, getter canlı referansı döndürdüğü sürece eşzamanlılıkta hiçbir koruma sağlamaz — kapı yalnızca arkadan açık değil, aynı zamanda kilitsizdir.

Yayınlama kaçağını bilmenin dersi şudur: Dikkatsiz bir Extract Variable, alan döndürme ya da Encapsulate Collection, daha önce kilit altında sınırlanmış bir mutable referansı sızdırabilir — tek thread’de bu hafif bir kapsülleme sızıntısıyken, eşzamanlı kodda bir thread güvenliği ihlalidir çünkü başka bir thread içsel durumu kilitsiz değiştirir; çözüm canlı referansı asla sızdırmamak, değiştirilemez kopya/görünüm döndürmektir, ve “private yetmez” dersi eşzamanlılıkta iki kat kritiktir.
Çalışan örnek kodlara erişmek için: » https://gitlab.com/sahin.yelkenci2/refactoring-canli-bahis
Değişmezlik — Eşzamanlılığın En Güçlü Aracı
Şimdi karanlık tuzaklardan, en güçlü araca geçelim: değişmezlik (immutability). Bir değişmez nesne — ↗ Bölüm 12'deki değer nesneleri: Para, Oran — doğası gereği thread güvenlidir. Paylaşılan mutable durum yoksa, yarış yoktur, kilide gerek yoktur, görünürlük sorunu yoktur; güvenle yayınlandıktan sonra bir değişmez nesne her zaman tutarlıdır.
Neden bu kadar güçlü? Çünkü tüm eşzamanlılık problemleri — atomiklik, görünürlük, yayınlama — paylaşılan MUTABLE durumdan kaynaklanır. Değişebilirliği kaldırın, problemler buharlaşır. Bir değişmez nesne, thread’ler arasında sıfır senkronizasyonla serbestçe paylaşılabilir. Bu yüzden değişmezliğe doğru refactoring, en güçlü eşzamanlılık refactoring’lerinden biridir: ↗ Bölüm 12'deki Change Reference to Value, alanları final yapmak, mutasyonu yeni nesne döndürmekle değiştirmek. Bu, o nesneler için kilide olan ihtiyacı tümüyle ortadan kaldırır — ve kilit çekişmesini (lock contention) yok ederek bir performans kazancı da sağlar.

Bu, ↗ Bölüm 12'deki değer nesnesi çalışmasını doğrudan thread güvenliğine bağlar: İnşa ettiğimiz değişmez Para ve Oran, yalnızca temiz değil, yapıları gereği thread güvenlidir. ↗ Bölüm 12'deki "geçersiz durumları temsil edilemez kıl" ilkesi, burada "yarışları temsil edilemez kıl"a genişler. Yüksek TPS sistemlerinde değişmezlik çifte bir kazançtır: thread güvenli (doğruluk) VE kilitsiz (performans — çekişme yok). İşte bu yüzden fonksiyonel ve değişmez stiller iyi ölçeklenir. Desen şudur: değişebilirliği küçük, iyi kontrol edilen yerlere sınırlayın; gerisini değişmez yapın. Domain'iniz ne kadar değişmezse, o kadar az eşzamanlılık muhakemesine ihtiyaç duyarsınız. Bir nüans: Değişmezliğin bir maliyeti vardır (mutasyon yerine yeni nesne üretmek — GC baskısı), bu yüzden uç sıcak yollarda bir takastır; ama çoğu kod için güvenlik kazancı baskındır.

Değişmezliği bilmenin dersi şudur: Değişmez bir nesne doğası gereği thread güvenlidir çünkü tüm eşzamanlılık problemleri paylaşılan mutable durumdan kaynaklanır ve değişmezlik onları buharlaştırır — sıfır senkronizasyonla serbestçe paylaşılır; değişmezliğe doğru refactoring (Change Reference to Value, final, mutasyon yerine yeni nesne) en güçlü eşzamanlılık refactoring’lerinden biridir ve çifte kazançtır (thread güvenli doğruluk + kilitsiz performans), bir nüans olarak yalnızca uç sıcak yollarda GC baskısıyla bir takas yaratır.
Performans Gerilemesi — Sıcak Yolda Ölçerek Yakalamak
Bir refactoring, özellikle sıcak yollarda (milyonlarca kez çalışan kod), performansı geri götürebilir. Örnekler: Replace Temp with Query (↗ Bölüm 9, 12), pahalı bir değeri önbelleğe almak yerine her çağrıda yeniden hesaplar — işlevsel olarak özdeş, ama sıcak yolda bir gerileme. Encapsulate Collection (↗ Bölüm 12), savunmacı bir KOPYA döndürür — büyük bir koleksiyonu her erişimde kopyalamak sıcak yolda pahalıdır. Bir soyutlama/dolaylılık tanıtmak (bir arayüz, bir Strategy, bir katman), sıcak yolda bir sanal çağrı ya da tahsis ekler. Değişmezlik bile, uç bir sıcak yolda işlem başına bir nesne tahsis eder (GC baskısı).

Disiplin şudur: Sıcak yollarda, öncesini ve sonrasını ÖLÇÜN (↗ Bölüm 8 — tahmin etme, profille). ↗ Bölüm 8'deki “erken optimizasyon” uyarısı iki yönde de keser: spekülatif olarak optimize etmeyin, ama körlemesine kötüleştirmeyin (pessimize) de — bir sıcak yolu geriye götüren temiz bir refactoring, ölçülüp belki ayarlanmalıdır. Denge şudur: Kodun çoğu sıcak yol DEĞİLDİR; orada netliği önceliklendirin (temiz refactoring). Yalnızca ölçülmüş sıcak yollarda — çalışma süresine hâkim olan o küçük yüzdede (80–20) — performansı netliğe karşı tartarsınız, ve o zaman bile önce ölçersiniz.
Anahtar araç, profillemedir (↗ Bölüm 8): gerçek sıcak yolları o belirler; performans koruyan refactoring’i yalnızca orada dert edinirsiniz. Başka her yerde, netlik için serbestçe refactor edersiniz. Performans hakkında sezginize güvenmeyin — ölçün. Geriye götürdüğünü DÜŞÜNDÜĞÜNÜZ bir refactoring götürmüyor olabilir; sorunsuz sandığınız biri geriye götürebilir. Hakem, profilerdir. Örneğin sıcak bir oran-hesaplama yolunda, Replace Temp with Query yeniden hesaplayacaksa, ölçün; geriye götürüyorsa, önbelleğe alınmış geçici değişkeni (ya da memoize edilmiş bir sorguyu) koruyun.

Performans gerilemesini bilmenin dersi şudur: Bir refactoring sıcak yollarda performansı geri götürebilir (yeniden hesap, kopya, dolaylılık, GC baskısı); disiplin, sıcak yolda öncesini ve sonrasını ölçmektir çünkü erken optimizasyon uyarısı iki yönde keser — spekülatif optimize etmeyin ama körlemesine kötüleştirmeyin de; kodun çoğu sıcak yol olmadığı için orada netliği önceliklendirin, yalnızca profilerin gösterdiği gerçek sıcak yollarda performansı netliğe karşı tartın, ve hakem sezgi değil profilerdir.
Görünmez Davranış İçin Test — Yük, Stres ve Profil
↗ Bölüm 4'teki güvenlik ağı, yüksek TPS kodu için genişletilmelidir: İşlevsel testler performans ve eşzamanlılık gerilemelerini yakalamadığı için, ek ağlara ihtiyacınız vardır. Üç ek ağ gerekir. Birincisi, yük/performans testleri ve benchmark’lar: bir refactoring’in öncesinde ve sonrasında gecikmeyi ve verimi ölçer (mikro-benchmark için JMH, sistem düzeyi için yük testleri) — performans gerilemelerini yakalar. İkincisi, eşzamanlılık/stres testleri: kodu birçok thread altında çalıştırıp yarışları, kilitlenmeleri (deadlock) ve bozulmayı arar (sistematik eşzamanlılık testi için jcstress gibi araçlar) — thread güvenliği ihlallerini yakalar. Üçüncüsü, profilleme: sıcak yolları ve çekişmeyi belirler (kilit profilleme, alev grafikleri), nerede dikkatli olunacağını gösterir.

İlke şudur: Yüksek TPS kodu için güvenlik ağı, üç ağdır — işlevsel (birim/entegrasyon), performans (benchmark/yük) ve eşzamanlılık (stres/jcstress). Üçünün altında refactor edersiniz. Ama sert bir gerçek vardır: Eşzamanlılık hataları belirlenimci değildir — var olsalar bile testlerde yeniden üretilmeyebilirler. Bu yüzden stres testi riski azaltır ama yok etmez; onu dikkatli muhakemeyle (önceki thread güvenliği analizi) ve code review ile (↗ Bölüm 24) birleştirmelisiniz. Eşzamanlılıkta yalnızca testler yetmez; muhakeme + test + gözden geçirme gerekir. Disiplin şudur: Yüksek TPS kodunda, bir refactoring’i birleştirmeden önce işlevsel testleri (doğruluk), benchmark’ları (performans) ve stres testlerini (eşzamanlılık) çalıştırın — üç davranışı birden doğrulayın.

Görünmez davranış için testi bilmenin dersi şudur: Yüksek TPS kodu için güvenlik ağı üç ağa genişler — işlevsel (doğruluk), performans (benchmark/yük), eşzamanlılık (stres/jcstress) — ve bir refactoring’i birleştirmeden önce üçü birden çalıştırılır; ama eşzamanlılık hataları belirlenimci olmadığı için testlerde çıkmayabilir, bu yüzden stres testi riski azaltır ama yok etmez ve dikkatli muhakeme ile code review’le birleştirilmelidir — eşzamanlılıkta yalnızca testler yetmez.
Aileyi Bir Arada Görmek — Üç Ağ Birden
Bu bölümün parçalarını tanıdık; şimdi onları birleştiren tek fikri görelim: Yüksek TPS ve eşzamanlı kodda, “davranışı koru” üç davranış demektir — işlevsel, performans, thread güvenliği — ve bunlar üç ağ ile doğrulanır. Refactoring felsefesi değişmez; yalnızca “davranış”ın tanımı genişler, ve güvenlik ağı onunla birlikte genişlemelidir.
Aşağıdaki tablo, üç davranışı, nasıl bozulabileceklerini ve nasıl korunup doğrulanacaklarını bir arada gösterir:

Bu tabloda bir araç öne çıkar: değişmezlik (immutability), eşzamanlılığın ana anahtarıdır. Eşzamanlılık problemlerinin çoğu — atomiklik, görünürlük, yayınlama — değişmezliğe doğru refactor ederseniz buharlaşır; bu, en yüksek kaldıraçlı tek hamledir. Bir bahis sistemini güvenli ve hızlı kılmanın en güçlü yolu, domain’i değişmez değer nesneleriyle (↗ Bölüm 12) örmek, ve değişebilirliği küçük, kilitli adacıklara hapsetmektir. Domain’iniz ne kadar değişmezse, hem o kadar az kilit (performans) hem de o kadar az yarış (doğruluk) olur.
Birleştiren kavrayış şudur: Refactoring disiplini değişmez — küçük adım, davranışı koru, doğrula — ama “davranış”ın daha zengin bir tanımına uygulanır, ve güvenlik ağı da onunla birlikte üçe çıkar. Ve böylece Kısım IV’ü — “Büyük Resim”i — tamamlıyoruz. Bu kısım boyunca, refactoring’i en zorlu koşullara taşıdık: büyük ölçek (↗ Bölüm 16), testsiz legacy (↗ Bölüm 17), desenler (↗ Bölüm 18), mimari (↗ Bölüm 19), veri (↗ Bölüm 20) ve eşzamanlılık (bu bölüm). Hepsinin ortak dersi tekti: Aynı felsefe — küçük, güvenli, davranış koruyan, geri alınabilir adımlar — en büyük ve en zor zeminlerde bile işler. Şimdi sıra, bu felsefeyi günlük pratiğe ve takım kültürüne dönüştürmekte.

Üç ağ birden görmeyi bilmenin dersi şudur: Yüksek TPS kodda “davranışı koru” üç davranış demektir (işlevsel, performans, thread güvenliği) ve üç ağ ile doğrulanır — refactoring felsefesi değişmez, yalnızca “davranış”ın tanımı genişler ve güvenlik ağı onunla; en yüksek kaldıraçlı araç değişmezliktir, çünkü çoğu eşzamanlılık problemini buharlaştırır, ve Kısım IV’ün ortak dersi aynı felsefenin en zor zeminlerde bile işlemesidir.
Üç Gözlem Sorusu
Bu eşzamanlılık bölümünü — ve Kısım IV’ü — kendi yüksek TPS kodunuzu sınayan üç soruyla kapatalım.
Birinci Gözlem Sorusu. Sisteminizde, bir kontrol ile bir uygulamanın (örneğin bir limit kontrolü ile bir ekleme) atomik olması gereken bir yer düşünün. O işlem, tek bir kilit ya da atomik bir ilkel altında mı, yoksa birden çok thread’in arasına girebileceği ayrı adımlara mı bölünmüş? Bir refactoring, farkında olmadan o atomikliği kırmış olabilir mi?

İkinci Gözlem Sorusu. Bir nesnenin bir getter’ı, içsel bir mutable koleksiyona ya da diziye canlı referans döndürüyor mu? Eğer öyleyse, eşzamanlı bir çağıran o referansı kilitsiz değiştirebilir mi — ve bu nesneyi değişmez kılsaydınız ya da savunmacı bir kopya döndürseydiniz, hem kapsülleme hem de thread güvenliği aynı anda düzelir miydi?

Üçüncü Gözlem Sorusu. Yüksek TPS kodunuzu refactor ederken, işlevsel testlerin dışında performans ve eşzamanlılık için de ağlarınız var mı — benchmark’lar, stres testleri? Yoksa bir refactoring’in gizlice bir gerileme ya da yarış getirip getirmediğini ancak üretimde mi öğreniyorsunuz?

Felsefi Kapanış
Bu bölümle, refactoring’in en ince sınırına — gözle görülmeyen ama hayati olan davranışlara — dokunduk. Ve Kısım IV’ü, “Büyük Resim”i, bu bölümle kapatıyoruz. Bu kısmın en derin dersi şudur: Bir sistemin en kritik özellikleri çoğu zaman en görünmez olanlardır. İşlev göz önündedir; ama performans ve eşzamanlılık güvenliği, ancak sistem baskı altındayken — ve çoğu zaman çok geç olduğunda — kendini gösterir. Usta, görünmeyeni korumayı, görüneni korumak kadar ciddiye alır.

Bu yüzden bölümü, görünmez olanın doğasına dair bir düşünceyle kapatalım:
Bir cerrah ameliyat ederken yalnızca gördüğü dokuyu değil, görmediği ama hayati olanı — kan akışını, sinir yollarını, organın eşzamanlı çalışan ritmini — de korumak zorundadır. Görünen kesiği temiz yapmak ustalığın yarısıdır; görünmeyen hayati işleyişi bozmadan bırakmak diğer yarısıdır. Yazılımda da öyledir: Bir refactoring’in kodu daha temiz göstermesi yetmez; sistemin görünmeyen ritmini — hızını ve binlerce thread’in sessiz uyumunu — da bozmadan bırakmalıdır. Çünkü bir sistemin sağlığı, yalnızca okuduğunuz satırlarda değil, o satırların yük altında, binlerce kez, aynı anda nasıl davrandığında yaşar. En büyük ustalık, gördüğünü güzelleştirirken görmediğini incitmemektir.
Sonraki Bölüm
***↗ Bölüm 22: IDE Araçları ve Otomatik Refactoring — Aracın Gücü ve Sınırı ile Kısım V’e, “Pratik ve Kültür”e geçiyoruz. ***Kısım IV refactoring’i en büyük ölçeklere taşıdı; şimdi mercimizi günlük pratiğe ve takım kültürüne çeviriyoruz — refactoring’i bir teoriden bir alışkanlığa dönüştüren şeylere. İlk durağımız, bu serinin baştan beri andığı ama hiç tam ele almadığı araçtır: IDE’nin otomatik refactoring yetenekleri. ↗ Bölüm 1'de “araca güven” demiştik; şimdi o güvenin tam olarak nereye kadar gittiğini göreceğiz — IntelliJ IDEA gibi modern bir IDE’nin Extract Method, Rename, Change Signature gibi hamleleri AST düzeyinde nasıl güvenle yaptığını, hangi refactoring’lerin otomatikleştirilebileceğini, ve ↗ bu bölümde gördüğümüz gibi otomasyonun nerede durduğunu (thread güvenliği, yargı gerektiren kararlar). Büyük resmi gördük; şimdi günlük işin araçlarını ve kültürünü ustalaştırma zamanı.
**İçindekiler… « Önceki [Bölüm 20: Veritabanı Refactoring — Şema Evrimi ve Geçiş Stratejileri] » Sonraki *[Bölüm 22: IDE ve Otomatik Refactoring Araçları — Güvenilir Dönüşümler] *» https://gitlab.com/sahin.yelkenci2/refactoring-canli-bahis
메타데이터
- post_id
- 0d91c947b375
- slug
- refactoring-mevcut-kodun-tasarımını-i̇yileştirme-sanatı-bölüm-21-yüksek-tps-ve-eşzamanlı-0d91c947b375
- 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-21-y%C3%BCksek-tps-ve-e%C5%9Fzamanl%C4%B1-0d91c947b375
- 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-21-y%C3%BCksek-tps-ve-e%C5%9Fzamanl%C4%B1-0d91c947b375
- author_url
- https://medium.com/@sahinyelkenci
- status
- ok
- fetched_at
- 2026-08-11 02:01:24