<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/feed.xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Ali GÖREN</title>
    <link>https://notes.aligoren.com</link>
    <description>Yazılım ve Kişisel Notlar...</description>
    <language>tr</language>
    <lastBuildDate>Mon, 01 Jun 2026 04:04:31 GMT</lastBuildDate>
    <atom:link href="https://notes.aligoren.com/feed.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Performans Düşmanı: False Sharing</title>
      <link>https://notes.aligoren.com/performans-dusmani-false-sharing</link>
      <guid>https://notes.aligoren.com/performans-dusmani-false-sharing</guid>
      <pubDate>Thu, 13 Feb 2025 19:55:27 GMT</pubDate>
      <author>goren.ali@yandex.com (Ali Goren)</author>
      <description>Performans Düşmanı: False Sharing Görsel kaynağı: https://medium.com/java-performance/performance-is-the-enemy-of-clean-code-fdd65c4c7d99 Selamlar herkese. Değerli üstadım Türkay Ürkmez’in Generic Constraintlerle alakalı bir LinkedIn paylaşımını gördüm. Burada farklı bir açıdan…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h3 id="performans-duesman-false-sharing">Performans Düşmanı: False Sharing</h3>
<p><img src="/media/019e6b0111b17be5.png" alt="" />Görsel kaynağı: <a href="https://medium.com/java-performance/performance-is-the-enemy-of-clean-code-fdd65c4c7d99">https://medium.com/java-performance/performance-is-the-enemy-of-clean-code-fdd65c4c7d99</a><br />
Selamlar herkese. Değerli üstadım Türkay Ürkmez’in Generic Constraintlerle alakalı bir LinkedIn paylaşımını <a href="https://www.linkedin.com/feed/update/urn:li:activity:7295834161896939521/">gördüm</a>. Burada farklı bir açıdan performansa katkı olacak bir konu hakkında yorumda bulundum O sebeple böyle bir yazı yazmak istedim. Kısacası, konu başlıktan da anlaşılacağı üzere False Sharing.</p>
<h4 id="false-sharing-nedir">False Sharing Nedir?</h4>
<p>False sharing, aynı CPU cache line’ında yer alan birbirinden bağımsız değişkenlere, birden fazla thread’in erişmeye çalışması durumudur. Bu işlem de performans düşüşüne yol açar. Cache line derken bunun ne olduğuna da değinmemiz gerekiyor.</p>
<p><strong>Cache Line</strong>: CPU cache’lerinin bellekten veri çekerken kullandığı en küçük veri bloklarına verilen isimdir. 64 ya da 128 byte boyuta sahiptirler. CPU, veriyi bellekten tek tek okumak yerine, tüm cache line’ı çeker.</p>
<p>Biraz daha açıklamak gerekirse, eğer farklı thread’ler aynı cache line içinde yer alan farklı değişkenlere sıkça yazma işlemi yaparsa, CPU’lar sürekli olarak cache’in güncelliğini sağlamak için cache coherence protocol kullanarak senkronizasyonu sağlamaya çalışırlar. Bu yüzden de gereksiz bellek erişimi ve CPU yükü anlamına gelir.</p>
<p>Şimdi problemin olduğu noktaya gelelim. Örneğin long türünde bir değişkenimiz var bu da 8 byte demektir. Yukarıdaki bilgiye göre deCPU verileri byte byte değil de cache line’ı alarak çeker. Bu da 64–8 byte’lık bir alanın daha cache line’da gelebileceğini söyler. Bu nedenle 8'den sonra gelen diğer byte’lar da o cache line içerisinde yer alır. Ne zamana kadar? 64 ya da bazı mimarilerde 128 olana kadar.</p>
<p>Bunu şöyle anlatmaya çalışalım. Şöyle 2 alanımız olsun.</p>
<ul>
<li>sharedData[0] → 0x00000000</li>
<li>sharedData[1] → 0x00000008</li>
</ul>
<p>Bu iki değer sırasıyla thread 1 ve thread 2 tarafından güncellensin. Örneğin, sadece <strong>sharedData[0]</strong> güncellenirse, tüm CPU çekirdeklerine cache line’da değişiklik var sinyali gönderiliyor. Bu da cache invalidation dediğimiz olayı gerçekleştiriliyor. Yani cache geçersiz oluyor. Bu yüzden de tekrar cache line’ın dolması gerekiyor. Günün sonunda bu da yazının başında belirttiğimiz bellek erişimlerinin tekrar tekrar olmasını sağlar. Yani gereksiz yere bellek erişimi ortaya çıkar.</p>
<p><strong>Cache Invalidation:</strong> CPU veya bellek sisteminde bir cachelenmiş bir verinin güncelliğini yitirdiğini belirten bir mekanizmadır.</p>
<h4 id="false-sharing-problemine-kars-c-ile-coezuem-ueretmek">False Sharing Problemine Karşı C# ile Çözüm Üretmek</h4>
<p>Eğer C# ile yazılım geliştiriyorsanız örneklerle nasıl False Sharing oluşturacağımızı ve bunu nasıl çözeceğimizi görelim.</p>
<p><strong>False Sharing Örneği</strong></p>
<pre><code class="language-csharp">using System.Diagnostics;

const int iterations = 10_000_000;
var threadCount = Environment.ProcessorCount;
var sharedData = new long[threadCount];
var stopwatch = Stopwatch.StartNew();
var threads = new Thread[threadCount];

for (var i = 0; i &lt; threadCount; i++)
{
    var threadIndex = i;
    threads[i] = new Thread(() =&gt;
    {
        for (var j = 0; j &lt; iterations; j++)
        {
            sharedData[threadIndex]++;
        }
    });
}

foreach (var thread in threads) thread.Start();
foreach (var thread in threads) thread.Join();

stopwatch.Stop();
Console.WriteLine($&quot;False Sharing ile çalışan kod için geçen zaman: {stopwatch.ElapsedMilliseconds} ms&quot;);</code></pre>
<p><strong>Çıktısı:</strong> <em>False Sharing ile çalışan kod için geçen zaman: 986ms</em></p>
<p>Yukarıdaki koda baksetığımızda masum görünen bir <strong>sharedData[threadIndex]++</strong> ifadesi görmekteyiz. Bu ifade, aslında bütün cache line’ı güncelleten performans düşmanı bir ifadedir.</p>
<p><strong>False Sharing’in Önlendiği Örnek</strong></p>
<pre><code class="language-csharp">using System.Diagnostics;
using System.Runtime.InteropServices;

const int iterations = 10_000_000;
var threadCount = Environment.ProcessorCount;
var sharedData = new PaddedLong[threadCount];
var stopwatch = Stopwatch.StartNew();

var threads = new Thread[threadCount];

for (var i = 0; i &lt; threadCount; i++)
{
    var threadIndex = i;
    threads[i] = new Thread(() =&gt;
    {
        for (var j = 0; j &lt; iterations; j++)
        {
            sharedData[threadIndex].Value++;
        }
    });
}

foreach (var thread in threads) thread.Start();
foreach (var thread in threads) thread.Join();

stopwatch.Stop();
Console.WriteLine($&quot;False sharing önlerken çalışan kod için geçen zaman: {stopwatch.ElapsedMilliseconds} ms&quot;);

[StructLayout(LayoutKind.Explicit, Size = 64)]
struct PaddedLong
{
    [FieldOffset(0)]
    public long Value;
}</code></pre>
<p><strong>Çıktısı:</strong> <em>False sharing önlerken çalisan kod için geçen zaman: 244 ms</em></p>
<p>Yukarıdaki kodda, PaddedLong veri türü, 64 byte’lık bir cache line’a hizalanmış durumda (alignment). Bunu Size = 64 ile belirttik. Yani yazının başındaki 64 byte’ı hatırlayacak olursak, her PaddedLong nesnesi, kendi cache line’ına sahip demek bu. <strong>FieldOffset</strong> ise, değişkenin struct içerisindeki konumunu belirtir. Eğer StructLayout tanımında LayoutKind.Explicit bir yapı kullanmamış olsaydık, derleyici değişkenler için otomatik hizalama (auto alignment) yapacaktı. Bunu önleyerek de her nesneye kendi cache line’ına sahip olma şansı verdik yani boşluk bırakmadık diyelim :)</p>
<p>Yazı bu kadardı. Okuduğunuz için teşekkür ederim. Umarım sizlere faydalı olabilmiştir.</p>
<h4 id="kaynaklar">Kaynaklar</h4>
<ul>
<li><a href="https://theboreddev.com/understanding-false-sharing">https://theboreddev.com/understanding-false-sharing</a></li>
<li><a href="https://en.wikipedia.org/wiki/False_sharing">https://en.wikipedia.org/wiki/False_sharing</a></li>
<li><a href="https://stackoverflow.com/questions/22766191/what-is-false-sharing-how-to-reproduce-avoid-it">https://stackoverflow.com/questions/22766191/what-is-false-sharing-how-to-reproduce-avoid-it</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Windows’ta Batch Script Rehberi: Temel Dosya ve Klasör Komutları</title>
      <link>https://notes.aligoren.com/windowsta-batch-script-rehberi-temel-dosya-ve-klasor-komutlari</link>
      <guid>https://notes.aligoren.com/windowsta-batch-script-rehberi-temel-dosya-ve-klasor-komutlari</guid>
      <pubDate>Mon, 03 Feb 2025 20:34:42 GMT</pubDate>
      <author>goren.ali@yandex.com (Ali Goren)</author>
      <description>Görsel kaynağı: https://madushaprasad21.medium.com/what-is-batch-language-bbdd4ee9b627 Selamlar herkese. Bu yazıda Windows kullanırken bir şekilde karşılaştığımız komut satırı ekranında scripting nasıl yapılır onu anlatmaya çalışacağım. Batch Script Nedir? Bilmeyenleriniz varsa,…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><img src="/media/019e6b010f5176bd.jpg" alt="" />Görsel kaynağı: <a href="https://madushaprasad21.medium.com/what-is-batch-language-bbdd4ee9b627">https://madushaprasad21.medium.com/what-is-batch-language-bbdd4ee9b627</a><br />
Selamlar herkese. Bu yazıda Windows kullanırken bir şekilde karşılaştığımız komut satırı ekranında scripting nasıl yapılır onu anlatmaya çalışacağım.</p>
<h3 id="batch-script-nedir">Batch Script Nedir?</h3>
<p>Bilmeyenleriniz varsa, batch script Windows işletim sisteminde çalışan, belirtilen komutları otomatik olarak çalıştırmaya yaran script dosyalarıdır. Uzantı olarak genelde .bat yada .cmd şeklinde denk gelmişsinizdir.</p>
<p>Amacınız komutları tekrar tekrar çalıştırmaktan kaçınmaksa, bu tarz işleri Windows için batch, Linux için shell script ile daha kolay hale getirebilirsiniz. Bir bakıma otomasyon diyebiliriz.</p>
<h4 id="powershell-ile-fark-nedir"><strong>PowerShell ile Farkı Nedir?</strong></h4>
<p>Tabii Windows’ta batch script tek seçenek değil. Bunun yanı sıra, PowerShell de kullanabilirsiniz. Sadece PowerShell, daha gelişmiş bir dildir ve istendiği taktirde .NET kütüphanelerini de kullanabilirsiniz. Yani buradan şunu anlayabiliriz batch script’ten bahsediyorsak görece daha basit işlemleri yapabiliriz. PowerShell ise daha gelişmiş işlemler için idealdir.</p>
<h4 id="temel-komutlar">Temel Komutlar</h4>
<p>İlk temel komutumuz, şaşırtıcı bir komut olan, hiçbir yerde karşılaşmadığınız echo komutudur. İlginçtir bu komutla “Merhaba dünya” yazdıracağız.</p>
<pre><code class="language-bash">@echo off
echo Merhaba dunya
pause</code></pre>
<p><strong>@echo off</strong> ile komutların ekrana yazdırılmasını engelleriz. Eğer bunu yazdırmasaydık direkt echo Merhaba dunya komutunu ekrana yazdırılacaktı.</p>
<p><strong>echo</strong> ile ekrana bir mesaj basarız. Eğer herhangi bir parametre kullanmazsak, mevcut echo ayarını gösteriririz. Yani on mu off mu gibi.</p>
<p><strong>pause</strong> ise kullanıcıdan bir tuşa basmasını bekler.</p>
<p>Bu örnekle birlikte, bir batch dosyasının nasıl çağırılabileceğini de görmüş oluyoruz. Sadece dosyanın adını yazarak çağırabiliriz. Tabiiki çift tıklayarak da açabiliriz.<br />
<img src="/media/019e6b010f817edd.png" alt="" /></p>
<h4 id="cls"><strong>cls</strong></h4>
<p>Bu komutla ekrandaki çıktıları temizleriz.</p>
<pre><code class="language-bash">@echo off
echo Merhaba dunya
pause
echo

cls
echo Her seyi temizledim
pause</code></pre>
<p>Çıktı aşağıdaki gibidir. Görselleri paylaşarak anlatıyorum ama bunu başka türlü daha anlaşılır gösterebileceğimi sanmıyorum.<br />
<img src="/media/019e6b010fb07876.png" alt="" /></p>
<h4 id="klasoer-islemleri"><strong>Klasör İşlemleri</strong></h4>
<p>Bir klasör olşturmak için diğer işletim sistemlerinde de olduğu gibi burada da mkdir komutunu kullanırız. Kısa olarak md komutunu da kullanabilirsiniz. Burada her iki komut örneğini de göstereceğim. Ve pause’ları da kaldırayım diyorum :)</p>
<pre><code class="language-bash">@echo off

mkdir TestDizi
md TestDiziniMdIle

echo Klasorler olusturuldu</code></pre>
<p><img src="/media/019e6b010fe07f7d.png" alt="" /><br />
Gördüğünüz gibi her iki türlü de oluşturabildik. Dilersek tek seferde recursive olarak oluşturabiliriz. Bunun için de md ya da mkdir’i şöyle kullanmalıyız.</p>
<pre><code class="language-bash">@echo off

md a\b\c\d

echo Klasorler olusturuldu</code></pre>
<p><img src="/media/019e6b01101074f0.png" alt="" /></p>
<h4 id="dizin-degistirme"><strong>Dizin Değiştirme</strong></h4>
<p>Dizin değiştirme için diğer işletim sistemlerinde yer alan <strong>cd</strong> komutu burada da aynı şekilde kullanılıyor. Kodumuza bakalım önce</p>
<pre><code class="language-bash">@echo off

md a
echo a dizini olusturuldu, ilgili dizine gidiliyor
cd a
echo a dizinine giris yapildi.
echo mevcut dizin %CD% olarak tanimli. Alt satirda tekrari yazdirilacak.
cd
echo ust dizine geri cikiliyor
cd ..</code></pre>
<p><strong>cd</strong> a bu komutla a dizinine gideriz.</p>
<p>echo içerisinde yazdığımız <strong>%CD%</strong> değeri bulunduğumuz dizin bilgisini tutan değişkendir. Bu tarz farklı hazır değişkenler mevcuttur.</p>
<p>Eğer cd komutuna parametre vermezseniz, <strong>%CD%</strong> değişkeni ile aynı şeyi yapar ve mevcut dizini yazdırır.</p>
<p>Bir üst dizin için ise yan yana iki nokta kullanırız. Diyelimki farklı bir sürücüdesiniz. Bu durumda aşağıdaki komut ile ilgili sürücüdeki dizine gidebilirsiniz. Diyelimki C sürücüsünde terminal ekranı açık. Bu durumda şu komut iş görür.</p>
<pre><code class="language-bash">cd /D D:\Projects/MyApi</code></pre>
<p>bunun bir diğer yöntemi ise <strong>pushd</strong> komutudur.</p>
<pre><code class="language-bash">pushd D:\Tests\batchs</code></pre>
<p>Sadece pushd kullandığınızda, değişmeden önceki dizin saklanır. Bu durumda, popd ile değişimden sonraki dizine geri dönersiniz. Örnek;</p>
<pre><code class="language-bash">@echo off

pushd C:\Python312
echo mevcut dizin %CD% olarak gorunuyor.
echo eski dizine geri donuluyor
popd
echo mevcut dizin artik %CD% olarak gorunuyor.</code></pre>
<p><img src="/media/019e6b0110407450.png" alt="" /></p>
<h4 id="dizin-silme"><strong>Dizin Silme</strong></h4>
<p>Diyelimki bir dizini silmek istiyorsunuz. Bu, örneklerimizde oluşan a dizini olsun, bunun için rmdir ya da kısa olarak rd komutunu kullanabilirsiniz.</p>
<pre><code class="language-bash">@echo off

echo D:\Tests\batchs\a dizini siliniyor...
rd D:\Tests\batchs\a /s /q
echo dizin silindi...</code></pre>
<p>2 farklı parametre gördük.</p>
<p><strong>/s parametresi</strong>, içerisindeki bütün dosyalarla birlikte silme işlemi yapar.</p>
<p>Eğer s parametresini vermeseydik dizinin boş olmadığına dair bir hata görecektik.<br />
<img src="/media/019e6b0110727888.png" alt="" /><br />
<strong>/q parametresi</strong>, silme işlemi için onay istemez.</p>
<p>Eğer q parametresini vermeseydik, böyle bir onay istenecekti.<br />
<img src="/media/019e6b0110a372e7.png" alt="" /></p>
<h4 id="dosya-islemleri"><strong>Dosya İşlemleri</strong></h4>
<p><strong>Dosyaya Yazdırma</strong></p>
<p>Örneğin bir mesajı, bir dosyaya yazdırmak isteseydik aşağıdaki şekilde echo kullanımı (pipe), dosyaya yazmamıza yardımcı olacaktı.</p>
<pre><code class="language-bash">@echo off
echo Lorem ipsum dolor sit falan filan. &gt; lorem.txt
echo Dosya olusturuldu</code></pre>
<p><strong>Dosya Taşıma</strong></p>
<p>Dosya taşıma için move komutunu kullanabilirsiniz.</p>
<pre><code class="language-bash">@echo off
echo Lorem ipsum dolor sit falan filan. &gt; lorem.txt
echo Dosya olusturuldu
echo Dosya tasiniyor
md dosyalar
move lorem.txt dosyalar\
echo Dosya tasindi</code></pre>
<p><img src="/media/019e6b0110dc7f37.png" alt="" /><br />
Burada move komutu /Y ve /-Y parametrelerini almaktadır.</p>
<p><strong>/Y parametresi</strong>, herhangi bir onay almadan dosyaları taşır</p>
<pre><code class="language-bash">move /Y lorem.txt dosyalar\</code></pre>
<p><img src="/media/019e6b01110c7056.png" alt="" /><br />
<strong>/-Y parametresi</strong>, kullanıcı onayını bekler.</p>
<pre><code class="language-bash">move /-Y lorem.txt dosyalar\</code></pre>
<p><img src="/media/019e6b0111397023.png" alt="" /><br />
<strong>Dosya Silme</strong></p>
<p>Batch scripting yaparken, windows’ta dosya silmek için <strong>del</strong> komutu kullanırız. Yine bu komut yerine <strong>erase</strong> komutunu da kullanabiliriz.</p>
<pre><code class="language-bash">@echo off

echo dosya siliniyor
del dosyalar\lorem.txt
echo Dosya silindi</code></pre>
<p><img src="/media/019e6b0111677554.png" alt="" /><br />
Parametrelerine gelecek olursak biraz daha bol parametreye sahiptir.</p>
<ul>
<li><strong>/F parametresi</strong>, read-only dosyaları zorla siler.</li>
<li><strong>/Q parametresi</strong>, kullanıcıdan onay beklemez.</li>
<li><strong>/S parametresi</strong>, alt dizinlerde yer alan dosyaları da siler.</li>
<li><strong>/P parametresi</strong>, kullanıcıdan onay istemek içindir.</li>
<li><strong>/A parametresi</strong>, bazı attribute’lara sahip dosyaları silmenize yardımcı olur.</li>
</ul>
<p>del /A parametresiyle kullanılabilecek tüm attribute’lar şunlardır:</p>
<ul>
<li><strong>R attribute’u</strong>, salt okunur (Read-only) dosyaları siler</li>
<li><strong>S attribute’u</strong>, sistem (System) dosyalarını siler</li>
<li><strong>H attribute’u</strong>, gizli (Hidden) dosyaları siler</li>
<li><strong>A attribute’u</strong>, arşiv (Archive) dosyalarını siler</li>
<li><strong>I attribute’u</strong>, içerik dizine eklenmeyen (Not Content Indexed) dosyaları siler</li>
<li><strong>L attribute’u</strong>, symlink ya da junction points gibi sembolik bağlantıları siler.</li>
<li><strong>O attribute’u</strong>, çevrimdışı (Offline) dosyaları siler</li>
<li>
<ul>
<li>ise herhangi bir özniteliğin olmadığını belirtir.</li>
</ul>
</li>
</ul>
<p>Örnek bir kullanım şöyledir;</p>
<pre><code class="language-css">del /A:HR dosyalar\*.txt</code></pre>
<p>Yukarıdaki örnekte hem gizli hem de read-only olan bütün txt dosyalarını siler. Yani bir wildcard kullanımı da yapabilirsiniz. Fakat wildcard kullanımı attribute olmadan da kullanılabilir. Sadece örnek vermek için wildcard kullandım.</p>
<p>İlk yazı bu kadardı. Okuduğunuz için teşekkür ederim. Hatalarım varsa affola.</p>
]]></content:encoded>
    </item>
    <item>
      <title>.NET Ekosistemi İçin Dağıtık Yük Testi Framework’ü: NBomber</title>
      <link>https://notes.aligoren.com/net-ekosistemi-i-cin-dagitik-yuk-testi-frameworku-nbomber</link>
      <guid>https://notes.aligoren.com/net-ekosistemi-i-cin-dagitik-yuk-testi-frameworku-nbomber</guid>
      <pubDate>Sun, 02 Feb 2025 19:42:26 GMT</pubDate>
      <author>goren.ali@yandex.com (Ali Goren)</author>
      <description>Görsel LinkedIn ile oluşturulmuştur. Bir yazılımın belirli yükler altında nasıl davrandığını anlamak için performans testleri kritik öneme sahiptir. Sistemde artan kullanıcı sayısı ile birlikte sistemlerin ölçeklenebilir olup olmadığı da önemli hale gelmiştir. Özellikle…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><img src="/media/019e6b010de17a98.png" alt="" />Görsel LinkedIn ile oluşturulmuştur.<br />
Bir yazılımın belirli yükler altında nasıl davrandığını anlamak için performans testleri kritik öneme sahiptir. Sistemde artan kullanıcı sayısı ile birlikte sistemlerin ölçeklenebilir olup olmadığı da önemli hale gelmiştir. Özellikle mikroservis mimarilerinin yaygınlaşması ve dağıtık sistemlerin artışıyla yük testi yapılabilecek araçlara da ihtiyaç artmaya başlamıştır. Bu ihtiyaçlar için de aşağıdaki araçlar ortaya çıkmıştır</p>
<ul>
<li><a href="https://jmeter.apache.org/">Apache JMeter</a></li>
<li><a href="https://httpd.apache.org/docs/2.4/programs/ab.html">ApacheBench (ab)</a></li>
<li><a href="https://locust.io/">Locust</a></li>
<li><a href="https://k6.io/">k6</a></li>
<li><a href="https://gatling.io/">Gatling</a></li>
<li><a href="https://www.artillery.io/">Artillery</a></li>
</ul>
<p>Bu sistemler dışında, bu yazının da konusunu oluşturan NBomber da yine yük testi yapabilmenize olanak sağlayan F# ile geliştirilen, .NET ekosisteminde kullanılabilecek faydalı bir framework olarak öne çıkıyor.</p>
<p><a href="https://nbomber.com/">NBomber - Distributed load testing framework for .NET/C#/F#</a></p>
<h3 id="nbomber-nedir">NBomber Nedir?</h3>
<p>NBomber yük testleri ve stres testleri yapmak için geliştirilen, açık kaynak kodlu ve .NET tabanlı bir performans test aracıdır. Her ne kadar açık kaynak kodlu olsa da lisans politikası onu kişisel kullanım için ücretsiz kılarken, ticari lisanslar için ücret talep etmekte.</p>
<p>NBomber henüz cloud ortamda bir desteğe sahip olmasa da yakın zamanda geleceğini web sitelerinde de görebilirsiniz. Ayrıca bu kısımda mevcut lisans ücreti politikasını da görebilirsiniz.<br />
<img src="/media/019e6b010e21705b.png" alt="" /></p>
<h3 id="nbombern-oene-ckan-oezellikleri-nelerdir">NBomber’ın Öne Çıkan Özellikleri Nelerdir</h3>
<p>✅ Platform Bağımsız Çalışabilme</p>
<p>.NET Core tabanlı olduğı için herhangi bir sisteme bağımlı olmak zorunda değilsiniz. Ayrıca dockerize etmek de çok basit. Özellikle Visual Studio ya da Rider gibi IDE’ler kullanıyorsanız bu daha da basit halde.</p>
<p>✅ Zengin Protokol Desteği</p>
<p>NBomber, sadece HTTP testleri yapmak için tasarlanmış gibi durabilir ancak bunun dışında WebSockets, gRPC, Kafka, AMQP, SQL gibi protokollerde de testler yapmanıza olanak sağlar.</p>
<p>✅ Esnek API Desteği</p>
<p>NBomber dokümanlarında da göreceksinizdir ama buradan da belirtmek isterim, dilediğinizde kendi Sinklerinizi yaratabilmeniz için geliştirici dostu bir API mevcut.</p>
<p>✅ Gelişmiş / Görsel Raporlama</p>
<p>NBomber’da dilerseniz test sonuçlarını JSON, CSV ya da HTML olarak alabilirsiniz. Örnek bir rapor aşağıda yer almaktadır.</p>
<p><a href="https://nbomber.com/assets/reports/html_report.html">https://nbomber.com/assets/reports/html_report.htm</a>l</p>
<p>Bunun dışında gerçek zamanlı olarak da raporlama yapabilmek için aşağıdaki sinkler desteklenmektedir;</p>
<ul>
<li>InfluxDB</li>
<li>TimescaleDB</li>
<li>Grafana</li>
</ul>
<p>Bu bahsettiğim sinkler’i kendiniz de geliştirebilirsiniz. Bunun dışında bir veri tabanında tutmak istiyorsanız da yine kendi implementasyonunuzu yapabilirsiniz.</p>
<p>✅ Dağıtık Cluster Desteği</p>
<p>NBomber, dağıtık cluster desteği sağlar. Distributed mode’da milyonlarda kullanıcı varmış gibi simultane testler yapabilirsiniz. Bunu yine bahsettiğim gibi cluster ile yapabilirsiniz.</p>
<p><a href="https://nbomber.com/docs/cluster/overview/">Overview | NBomber</a></p>
<p>✅ CI/CD Entegrasyonu</p>
<p>Testlerinizi otomatik olarak çalıştırmak için CI/CD pipelinelarınıza NBomber’ı ekleyebilirsiniz. Olası performans düşüşlerini yakalayabilmek için assertion ve thresholdlar tanımlayabilirsiniz. Kendi örnekleri şu şekilde;</p>
<p><a href="https://github.com/PragmaticFlow/NBomber/blob/dev/examples/xUnitExample/LoadTestExample.cs">NBomber/examples/xUnitExample/LoadTestExample.cs at dev · PragmaticFlow/NBomber</a></p>
<p>Aslında burada xUnit ya da NUnit gibi testler içerisinde de NBomber’ı kullanabilirsiniz. Detaylı bilgi şurada yer almaktadır;</p>
<p><a href="https://nbomber.com/docs/nbomber/asserts_and_thresholds/">Asserts and Thresholds | NBomber</a></p>
<h4 id="nbomber-ile-oernek-yuek-testi-uygulamas">NBomber ile Örnek Yük Testi Uygulaması</h4>
<p>Bu kadar çok detay verdik ancak NBomber nasıl istediğimiz işleri yapar onu henüz konuşmadık.</p>
<p>NBomber temelde, senaryolardan oluşur ve bu senaryolar da kendi içerisinde adımlara sahiptir. Adımları da kullanıcı davranışı olarak düşünebilirsiniz. Örnek senaryolarımızda bu hareketleri tek bir kullanıcının yaptığını da düşünebilirsiniz. Kodlamayı yaparken de bunu göreceğiz. Ama önce NBomber’ı projemize dahil edelim.</p>
<pre><code class="language-bash">dotnet add package NBomber</code></pre>
<p>Projemizi oluşturduğumuzu varsaydığım için direkt yukarıdaki komutla dahil ettim. Şimdi ilk senaryomuzu oluşturalım.</p>
<pre><code class="language-csharp">using var httpClient = new HttpClient();
var ilkSenaryo = Scenario.Create(&quot;httpbin_ilk_test&quot;, async context =&gt;
{
    var response = await httpClient.GetAsync(&quot;https://httpbin.org/get&quot;);

    return response.IsSuccessStatusCode ? Response.Ok() : Response.Fail();
}).WithLoadSimulations(Simulation.KeepConstant(10, TimeSpan.FromSeconds(30)));

NBomberRunner
.RegisterScenarios(ilkSenaryo)
.Run();</code></pre>
<p>Bu örnekte httpbin adresine, 10 sanalkullanıcıyla sabit olarak 30 saniye boyunca istek atıyoruz. Burada örnek çıktı şöyle oluyor</p>
<pre><code>scenario: httpbin_ilk_test
  - ok count: 1624
  - fail count: 0
  - all data: 0 MB
  - duration: 00:00:30

load simulations:
  - keep_constant, copies: 10, during: 00:00:30

┌─────────────────────────┬─────────────────────────────────────────────────────────────┐
│                    step │ ok stats                                                    │
├─────────────────────────┼─────────────────────────────────────────────────────────────┤
│                    name │ global information                                          │
│           request count │ all = 1624, ok = 1624, RPS = 54.1                           │
│            latency (ms) │ min = 135.86, mean = 182.28, max = 1118.07, StdDev = 121.53 │
│ latency percentile (ms) │ p50 = 140.29, p75 = 141.57, p95 = 449.28, p99 = 748.03      │
└─────────────────────────┴─────────────────────────────────────────────────────────────┘</code></pre>
<p>Burada basit bir senaryo tanımını gördük. LoadSimulation tanımı ise yine en basitlerinden birisiydi. Diğer simülasyon türleri aşağıda yer almaktadır;</p>
<p><a href="https://nbomber.com/docs/nbomber/load-simulation/">Load Simulation | NBomber</a></p>
<p>Biz yine de açıklayalım.</p>
<p><strong>KeepConstant</strong></p>
<p>Sabit sayıda sanal kullanıcıyı belirli bir süre boyunca çalıştırır. Örneğin, 10 kullanıcı 30 saniye boyunca sürekli test isteği gönderir.</p>
<p><strong>Inject</strong></p>
<p>Her saniyede belirli bir sayıda yeni kullanıcı başlatır. Örneğin, her saniye 5 yeni kullanıcı başlatılır ve 30 saniye boyunca çalıştırılır.</p>
<p><strong>RampConstant</strong></p>
<p>Kullanıcı sayısını belirli bir süre boyunca kademeli olarak artırır. Örneğin, ilk başta 1 kullanıcıyla başlar, sonra yavaşça 50 kullanıcıya çıkar.</p>
<p><strong>RampInject</strong></p>
<p>İstek oranını (TPS — Transactions Per Second) kademeli olarak artırır. Örneğin, ilk başta her saniye 1 istek atılır, sonra giderek artar.</p>
<p><strong>InjectRandom</strong></p>
<p>İstek oranını belirli bir aralıkta rastgele değiştirerek gönderir. Örneğin, bir saniyede 1 ile 10 arasında değişen sayıda istek gönderir.</p>
<p><strong>IterationsForConstant</strong></p>
<p>Belirli bir kullanıcı sayısını sabit tutarak, her bir kullanıcının belirlenen toplam iterasyon sayısına ulaşana kadar testin devam etmesini sağlar.</p>
<p><strong>IterationsForInject</strong></p>
<p>Belirli bir hızda (rate) yeni kullanıcılar (sanal kullanıcılar) başlatarak, toplam belirlenen iterasyon sayısına ulaşana kadar testi devam ettirir.</p>
<p><strong>Pause</strong></p>
<p>Bir senaryonun belirli bir süre boyunca duraklatılmasını sağlar.<br />
Bu, senaryonun başlamasını geciktirmek veya çalışma sırasında bir ara vermek için kullanılabilir.</p>
<p>Burada bahsedilen simülasyon ayarları istenirse appsettings dosyasında da yer alabilir.</p>
<p><a href="https://nbomber.com/docs/nbomber/load-simulation/#loadsimulation-in-json-config">Load Simulation | NBomber</a></p>
<p>Konudan uzaklaşmadan son olarak da step tanımlarını görelim.</p>
<pre><code class="language-csharp">using var httpClient = new HttpClient();
var ilkSenaryo = Scenario.Create(&quot;httpbin_ilk_test&quot;, async context =&gt;
{
    await Step.Run(&quot;sadece_get_requesti&quot;, context, async () =&gt;
    {
        var response = await httpClient.GetAsync(&quot;https://httpbin.org/get&quot;);

        return response.IsSuccessStatusCode ? Response.Ok() : Response.Fail();
    });

    await Step.Run(&quot;query_string_ile_get_requesti&quot;, context, async () =&gt;
    {
        var response = await httpClient.GetAsync(&quot;https://httpbin.org/get?kullaniciadi=ali&quot;);

        return response.IsSuccessStatusCode ? Response.Ok() : Response.Fail();
    });

    return Response.Ok();

})
.WithLoadSimulations(Simulation.KeepConstant(10, TimeSpan.FromSeconds(30)));

NBomberRunner
.RegisterScenarios(ilkSenaryo)
.Run();</code></pre>
<p>Stepler için kullanıcı davranışlarını tanımlarız demiştim. Bu örnek uygun olmasa da nasıl tanımlandığını görmek açısından iyi olabilir.</p>
<p>Birden fazla step arasında veri paylaşımı yapılabilir. Bu işlemler şöyle yapılabilir;</p>
<ul>
<li>ResponseType ile</li>
<li>ScenarioContext.Data ile</li>
<li>Closure Variable ile</li>
</ul>
<p>Üç şekilde de veri paylaşabilirsiniz. Şu an için bu yazıda böyle bir örnek göstermeyeceğim. Yukarıdaki senaryoyu çalıştırınca aşağıdaki çıktıyı alıyoruz. Bu sefer örneğin ekran görüntüsünü atacağım.<br />
<img src="/media/019e6b010e677937.png" alt="" /><br />
Size ek olarak bazı linkler de paylaşacağım. Bunlardan birisi NBomber Studio. Kısacası çalışan testler grafik arayüzü ile görebileceğiniz bir web tabanlı arayüz.</p>
<h4 id="nbomber-studio">NBomber Studio</h4>
<p><a href="https://nbomber.com/docs/nbomber-studio/overview">Overview | NBomber</a><br />
<img src="/media/019e6b010eb17f59.png" alt="" /><br />
Aslında burada yer alan link bu arayüzü gösteriyor.</p>
<p><a href="https://nbomber.com/assets/reports/html_report.html">NBomber</a></p>
<h4 id="raporlar">Raporlar</h4>
<p>Eğer varsayılan olarak bir klasör tanımı yapmadıysanız raporlarınız, uygulama dizini altındaki reports klasörüne kayıt ediliyor. Bu bilgiyi de şöyle veriyor</p>
<pre><code class="language-bash">22:33:23 [INF] Reports saved in folder: &quot;D:\Tests\ConsoleApp4\ConsoleApp4\reports\2025-02-02_19.32.04_session_85af8b5e&quot;</code></pre>
<p>Bu klasörün içeriği de şöyle oluyor<br />
<img src="/media/019e6b010ee57bdd.png" alt="" /><br />
Örneğin steplerle beraber son oluşan testimiz için HTML rapor çıktısı şu şekilde yer alıyor<br />
<img src="/media/019e6b010f1b7369.png" alt="" /><br />
Hepsi bu kadardı. Okuduğunuz için teşekkür ederim. Umarım sizlere faydalı olabilecek bir paylaşım olmuştur.</p>
<h4 id="kaynaklar">Kaynaklar</h4>
<ul>
<li><a href="https://nbomber.com/docs/getting-started/overview/">https://nbomber.com/docs/getting-started/overview/</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>2024 Recap</title>
      <link>https://notes.aligoren.com/2024-recap</link>
      <guid>https://notes.aligoren.com/2024-recap</guid>
      <pubDate>Fri, 06 Dec 2024 20:51:10 GMT</pubDate>
      <author>goren.ali@yandex.com (Ali Goren)</author>
      <description>This image was generated using artificial intelligence. This year started rough for me. The reason is that I got sick at the beginning of 2024 — swine influenza on one side and COVID on the other. On January 2nd, I found out I had swine influenza. Even though I mentioned this in…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><img src="/media/019e6b010cf27d12.jpg" alt="" />This image was generated using artificial intelligence.<br />
This year started rough for me. The reason is that I got sick at the beginning of 2024 — swine influenza on one side and COVID on the other. On January 2nd, I found out I had swine influenza.</p>
<p>Even though I mentioned this in the first sentence, I made the career change I discussed in my 2023 Recap. This was one of the good things about 2024 for me.</p>
<p><a href="https://aligoren.com/2023-y%C4%B1l%C4%B1n%C4%B1n-%C3%B6zeti-5b6c35b5bd28">2023 Yılının Özeti</a></p>
<h4 id="my-father-had-surgery">My Father Had Surgery</h4>
<p>After February, we started frequent hospital visits because of my father’s thyroid issues. This process felt uncomfortably long for me.</p>
<p>Eventually, my father had thyroid surgery, and his thyroid was removed. The pre-surgery process, the surgery itself, and the post-surgery recovery period exhausted me. For months, we went back and forth to the hospital — endless tests, getting results, and doctor check-ups. At some point, I realized how utterly drained I was.</p>
<p>If I remember correctly, it was around June when we were told during a post-surgery check-up that everything was fine. That made me happy. But just think about it — a process that started in February lasted until June. It wore me out.</p>
<p>In this case, General Surgery Specialist Aygün Aliyeva performed my father’s surgery. I can’t thank her enough. Looking back now, I realize it was a very well-done operation.</p>
<p><a href="https://www.merkezsaglikgrubu.com.tr/doktorlarimiz/op-dr-aygun-aliyeva-209.html">Op. Dr. Aygün Aliyeva</a></p>
<h4 id="my-mother-had-surgery">My Mother Had Surgery</h4>
<p>After that, although I can’t remember the exact date, it was either July or August when my mom had eye surgery. She had a condition that could have left her almost blind — her cataract was very advanced.</p>
<p>I’m writing this based on what her doctor said, though I knew this condition had been there for 10–15 years. Thankfully, this surgery also went well. Still, it took about a month of back-and-forth hospital visits.</p>
<p>This was my second surgery adventure in 2024. :)</p>
<h4 id="my-father-had-surgery-again">My Father Had Surgery Again</h4>
<p>Just when I started to think I was feeling relieved, my father’s hemorrhoid problem came up. Unfortunately, this was another long-standing issue that had worsened over the years because my father neither paid attention to it himself nor listened to us or the doctors.</p>
<p>This process drained me so much. My father’s first surgery and my mother’s surgery hadn’t been this exhausting. Because of the blood loss my father experienced before the surgery, we were going to the hospital almost every other night. I spent the hours I should’ve been sleeping at the hospital, and then I worked during the day. I know I didn’t get proper sleep for about two weeks.</p>
<p>While trying to manage my work successfully, I also went through a psychologically challenging time. But I managed to get through it, thanks to the people around me. Just having them there was enough for me.</p>
<p>It’s been about 1.5 months since his surgery, and he suffered for the first month. Seeing him comfortable now makes me happy. I hope I don’t face another surgery during the rest of 2024.</p>
<p>By the way, during these surgeries and the preparation processes, my migraines became so intense that the doctor had to inject me in my forehead and the back of my head. I couldn’t even lower my head because the moment I did, I’d experience an extreme headache.</p>
<p>As a result, I was asked to get an MRI. Thankfully, everything came out fine with me. :)</p>
<h4 id="not-everything-was-bad">Not Everything Was Bad!</h4>
<p>Even though I couldn’t take a vacation this year due to these reasons, some good things happened too. For example, I moved to a nicer house. Of course, that was thanks to my manager(<a href="https://medium.com/u/43199ea07e9e">H. Yusuf Yavuz</a>) 😛</p>
<p>I also met a very skilled, knowledgeable, and great conversationalist CTO in 2024. Having the chance to learn from him has been a real privilege for me.(<a href="https://medium.com/u/9a8eb4158b72">Gürkan Sel</a>)</p>
<p>We launched many new projects, and these projects taught me a lot. Although the increase in my responsibilities sometimes tired me out, I learned how to handle it.</p>
<p>What is a source of stress for many became a game of time management for me.</p>
<p>Even though I can’t fully explain the details of these processes that contributed so much to my career, I’m happy with the work we accomplished in such a short time.</p>
<p>Also, one of the good things about 2024 was working at the same place as a friend like <a href="https://medium.com/u/18571947c562">Mustafa Dikyar</a> — someone whose advice I didn’t always follow but who still treated me with understanding.</p>
<p>I almost forgot! After swearing I’d never wear shirts or ties and making such bold statements, I’ve actually started enjoying it now. Really!<br />
<img src="/media/019e6b010d297b95.jpg" alt="" /><br />
Even if I tie my tie crooked, I don’t care. Feels like it’ll fix itself at some point :)</p>
<p>For this, I owe endless thanks to <a href="https://medium.com/u/b42da9eff386">Oğuz kumcular</a> and his amazing wife, my buddy. Otherwise, I wouldn’t have much of a clue about dressing up :)</p>
<p>Also, my birthday was celebrated for the first time in years. Normally, I’m not the kind of person for such things, but the fact that my friends did this made me incredibly happy ❤ (Getting emotional here).<br />
<img src="/media/019e6b010d5e7fc6.jpg" alt="" /><br />
This year, my cat pulled off some funny mischief that made us all laugh. That’s another reason I’m happy :)<br />
<img src="/media/019e6b010d917ac2.jpg" alt="" />At a moment when we were really worried because we thought it had gone outside and gotten lost, it suddenly appeared in a box on top of the kitchen cabinet :)<br />
After many years, I went to Balıkesir. I went with my manager(<a href="https://medium.com/u/43199ea07e9e">H. Yusuf Yavuz</a>), and it was truly a great experience for me. It’s such a beautiful place to live.</p>
<p>Other than that, I’d love to mention the amazing people at work here, but I can’t because I’m not sure if they have accounts or not.</p>
<p>By the way, I’m trying to improve my English level. I’ve made some progress through TV shows and writing like this, but since I don’t have any speaking practice, my speaking skills are non-existent.</p>
<p>Maybe I can work on this weakness in 2025.</p>
<h4 id="what-are-my-expectations-for-2025">What Are My Expectations for 2025?</h4>
<p>First of all, I don’t want any more surgeries or health problems. Please!</p>
<p>After that, I want health, happiness, and peace once again — for the whole world. I wish for a year where everyone talks about good things, has fun, and is free from wars and deaths.</p>
<p>These are just wishes, though. You know, Santa Claus isn’t real either. So, it’s not going to happen…</p>
<p>Best Regards!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Creational Design Patterns</title>
      <link>https://notes.aligoren.com/creational-design-patterns</link>
      <guid>https://notes.aligoren.com/creational-design-patterns</guid>
      <pubDate>Mon, 15 Jul 2024 19:09:37 GMT</pubDate>
      <author>goren.ali@yandex.com (Ali Goren)</author>
      <description>Creational Design Patterns https://unsplash.com/photos/man-in-black-jacket-holding-camera-CTflmHHVrBM Selamlar. Bu yazıda Design Patterns konularından olan Creational Patterns konusu hakkında bilgi vermeye çalışacağım. Türkçede çeviri olarak “Yaratımsal Tasarım Desenleri” olarak…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h3 id="creational-design-patterns">Creational Design Patterns</h3>
<p><img src="/media/019e6b010c7d7230.jpg" alt="" />https://unsplash.com/photos/man-in-black-jacket-holding-camera-CTflmHHVrBM<br />
Selamlar. Bu yazıda Design Patterns konularından olan Creational Patterns konusu hakkında bilgi vermeye çalışacağım. Türkçede çeviri olarak “Yaratımsal Tasarım Desenleri” olarak biliniyor. Birazcık anlamsal zorluğa sahip gibi geliyor.</p>
<h4 id="creational-patterns-nedir-ne-is-yapar">Creational Patterns Nedir? Ne İş Yapar?</h4>
<p>Aslında bu türden creational design patterns konusundan bahsederken, nesnelerin nasıl oluşturulacağından ve yönetileceğinden de bahsetmiş oluyoruz.</p>
<p>Nesne oluşturma işlemlerinde yaşanan karmaşayı azaltmayı hedefler. Bunun yanında koda esneklik kadar. Yeniden kullanılabilirlik katar.</p>
<h4 id="bana-creational-patterns-listesini-ver">Bana Creational Patterns Listesini Ver!</h4>
<p>Hay hay! Aşağıdaki design pattern konularını mutlaka duymuşsunuzdur. Bunlar creational patterns olarak da bilinir.</p>
<p><strong>Singleton Design Pattern</strong><br />
<img src="/media/019e6b010caf7448.jpg" alt="" /><br />
Singleton design pattern, bir sınıfın sadece bir örneğinin olmasını garanti eden bir patterndir. Tabiiki burada hatalı kodlanmış bir singleton örneğinden bahsetmiyorum. Design pattern buradaki konumuzdur. Bu design pattern’den bahsederken, aklınıza logging, configuration ya da database konuları gelebilir.</p>
<p>Veri tabanı ya da logger örnekleri gerçek hayat senaryoları içerisinde en çok karşılaşacağınız örnekler olabilir.</p>
<p><strong>Factory Method Pattern</strong></p>
<p>Bu design pattern’da nesnelerin oluşturulması alt sınıflarda gerçekleştirilir. Bunu yaparken de bir interface kullanılır. Bu sayede nesnelerin oluşturulması soyut bir hale gelirken, alt sınıflarda da hangi nesnelerin oluşturulacağı belirlenir.</p>
<p>Örneğin “ZubiZaretta” isimli bir e-ticaret sitemiz olsun. Bu sitede ödeme işlemleri yapılıyor. Kredi kartı, havale ya da örneğin yurt dışında da PayPal olsun. Elimizde aşağıdaki ödeme yöntemleri mevcut</p>
<ul>
<li>Kredi kartı</li>
<li>PayPal</li>
<li>Havale</li>
</ul>
<p>Factory Method Pattern kullanarak farklı olan bu ödeme yöntemleri yönetilebilir. Kod örneğini burada paylaşmak yazıyı uzatak ama faydasını şöyle gösterebilirim</p>
<pre><code class="language-csharp">ProcessPayment(new CreditCardPaymentProcessorFactory(), 200m);

void ProcessPayment(PaymentProcessorFactory factory, decimal amount)
{
    IPaymentProcessor processor = factory.CreatePaymentProcessor();
    processor.ProcessPayment(amount);
}</code></pre>
<p>Yukarıdaki koda bakarak bu kodun logic değiştirmeden, genişletilebilir bir kod olduğunu görmüş oluyoruz. 1 ay sonra Abuzittin isimli ödeme yöntemi gelseydi şöyle bir kod işimizi çözecekti.</p>
<pre><code class="language-csharp">ProcessPayment(new CreditCardPaymentProcessorFactory(), 200m);
ProcessPayment(new AbuzittinPaymentProcessorFactory(), 200m);

void ProcessPayment(PaymentProcessorFactory factory, decimal amount)
{
    IPaymentProcessor processor = factory.CreatePaymentProcessor();
    processor.ProcessPayment(amount);
}</code></pre>
<p>Factory sınıflarının kendi içlerindeki davranışları, o sınıfları bağlar. Örneği kredi kartı kuruluşunun API’ları ile Abuzittin’in aynı olmayabilir. Söylemek istediğim bu. Ama siz asla ve asla asıl payment adımında bir değişiklik yapmazsınız.</p>
<p><strong>Abstract Factory Pattern</strong></p>
<p>Bu design pattern Factory Method Design Pattern ile çok karıştırılıyor. Factory Method DP’de ortak bir interface ile işleri halledebilirken, Abstract Factory DP’de ise birden fazla nesnenin arayüzüne göre işleri hallederiz.</p>
<p>Sıkça verilen bir örnek üzerinden gitmek istiyorum. Örneğin mobilya üreten bir fabrikamız var. Bu fabrikada eski tür ve modern mobilyalar üretiliyor. Sandalye ve masalar olsun. Bunları üretirken yazılımsal olarak ortaya çıkan karmaşayı Abstract Factory Pattern ile çözebiliriz. Aslında buna karmaşa demem ama anlaşılması için öyle diyorum. Yaklaşımımız şöyle olur;</p>
<ul>
<li>Abstract Factory</li>
<li>Concrete Factory</li>
<li>Abstract Product</li>
<li>Concrete Product</li>
<li>Client</li>
</ul>
<p>Abstract factory ve abstract product’lar interface’leri içerirken, concrete factory ve product’lar ise implementasyonları içerir. Client ise burada kullanıcıdır.</p>
<p>Mesela sandalyeleri abstract factory olarak ISandalye olarak düşünelim. Yine IMasa da burada. Bunların implementasyonu Concrete Factory’de gerçekleştirilir.</p>
<p>Abstract Product dediğimiz factory interface ise bahsedilen 2 interface’i kullanır. Örneğin IUretimFactory adında bir interface olsun. Bu interface’in memberları ISandalye ve IMasa türünden 2 method olsun.</p>
<p>Concrete Product dediğimiz sınıflar ise bu bahsettiğimiz Abstract Product’ı implement eder.</p>
<p>Örneğin “FuturistikMobilya” adında 3. türden bir mobilya işimiz olsaydı, sadece FuturistikMobilya sınıfını ve bu sınıfı yönetmek için bir de factory sınıfını eklememiz yetecekti. Haliyle kod genişleyebilir durumda olurdu. Mevcut kodumuz değişmeden de yeni özellikler eklenebilir olurdu.</p>
<p><strong>Builder Pattern</strong></p>
<p>Bu design pattern kullanılarak karmaşıklığı yüksek nesnelerin adım adım oluşturulması sağlanır. Bu bize bir işin adımlara bölünerek yapılabileceğini söyler. Yine bu adımların yönetilmesi için de bir Builder sınıf kullanılır. Yapısal olarak şöyledir;</p>
<ul>
<li>Product</li>
<li>Builder</li>
<li>ConcreteBuilder</li>
<li>Director</li>
</ul>
<p>Gerçek dünya örneği birazcık acıkmamla alakalı olarak peynir üretim sürecini içerecek. Peynirin nasıl üretileceğini bilmesem de içerisindeki temel ürünleri koyduğumuzu söyleyelim. Normalde bu yazıda kod örneği vermeyecektim. Ancak kod örneği bu pattern’i çok iyi açıklar.</p>
<ul>
<li>Süt</li>
<li>Yoğurt</li>
<li>Tuz</li>
</ul>
<p>Şimdi sınıfınızın bu 3 property’e sahip olduğunu düşünün. Yani peyniri yaparken 3 farklı ürünü set etmeniz karışıma eklemeniz gerekiyor. Bunun class’ı nasıl olurdu?</p>
<pre><code class="language-csharp">internal class Peynir
{
    public double Sut { get; set; }

    public double Yogurt { get; set; }

    public double Tuz { get; set; }
}</code></pre>
<p>Ne demiştik yapılan işi süreçlere bölerek peyniri üreteceğiz. O zaman bu cümlesini kurduğumuz işin bir de arayüzünü kurgulayalım.</p>
<pre><code class="language-csharp">internal interface IPeynirBuilder
{
    void SetSut(double oran);

    void SetYogurt(double oran);

    void SetTuz(double oran);

    Peynir GetPeynir();
}</code></pre>
<p>Şimdi elimizde peynir sınıfı ve bir de Builder arayüzü var. Bu bilgilerle beyaz peynir üretelim.</p>
<pre><code class="language-csharp">internal class BeyazPeynirBuilder : IPeynirBuilder
{
    private Peynir _peynir = new Peynir();

    public void SetSut(double oran)
    {
        _peynir.Sut = oran;
    }

    public void SetTuz(double oran)
    {
        _peynir.Tuz = oran;
    }

    public void SetYogurt(double oran)
    {
        _peynir.Yogurt = oran;
    }

    public Peynir GetPeynir()
    {
        return _peynir;
    }
}</code></pre>
<p>E beyaz peyniri ürettik, bir de gelin kaşar peynir üretelim. Tabiiki kaşar peynir 2–3 malzeme ile üretilmiyor. Amaç burada süreci anlamak.</p>
<pre><code class="language-csharp">internal class KasarPeynirBuilder : IPeynirBuilder
{
    private Peynir _peynir = new Peynir();

    public void SetSut(double oran)
    {
        _peynir.Sut = oran;
    }

    public void SetTuz(double oran)
    {
        _peynir.Tuz = oran;
    }

    public void SetYogurt(double oran)
    {
        _peynir.Yogurt = oran;
    }

    public Peynir GetPeynir()
    {
        return _peynir;
    }
}</code></pre>
<p>Yapısal olarak bahsettiğimiz kısımda Director’den bahsetmiştik. Şimdi bu işi PeynirUretici isimli sınıfta yapalım.</p>
<pre><code class="language-csharp">internal class PeynirUretici
{
    private IPeynirBuilder _builder;

    public PeynirUretici(IPeynirBuilder builder)
    {
        _builder = builder;
    }

    public void BeyazPeynirUret()
    {
        _builder.SetSut(5);
        _builder.SetYogurt(2);
        _builder.SetTuz(0.4);
    }

    public void KasarPeynirUret()
    {
        _builder.SetSut(7);
        _builder.SetYogurt(10);
        _builder.SetTuz(2);
    }

    public Peynir GetPeynir()
    {
        return _builder.GetPeynir();
    }
}</code></pre>
<p>Artık kullanımı da şöyle olur :)</p>
<pre><code class="language-csharp">IPeynirBuilder beyazPeynirBuilder = new BeyazPeynirBuilder();
PeynirUretici peynirUretici = new PeynirUretici(beyazPeynirBuilder);
peynirUretici.BeyazPeynirUret();
var beyazPeynir = peynirUretici.GetPeynir();</code></pre>
<p>Aynısını kaşar peynir için de yapabilirsiniz.</p>
<p><strong>Prototype Pattern</strong></p>
<p>Son design pattern olan prototype pattern’a geldik. Bu design pattern’da mevcut bir nesnenin klonlarını oluşturarak yeni nesneler oluşturulur. Aslında bu cümle hatalı. Sıfırdan bir nesne oluşturmuyor. Var olan bir nesnenin kopyasını oluşturuyor. Yeni bir nesne oluşturmanın bir hayli maliyetli olduğu süreçlerde prototype pattern kullanılır. Nesnelerin oluşturulma süreçleri hızlanır. Yapısal olarak aşağıdaki gibidir;</p>
<ul>
<li>Prototype</li>
<li>ConcretePrototype</li>
</ul>
<p>Örneğin bir doküman yönetim sisteminde raporların, sözleşmelerin yönetilmesi için bir örneğimiz olsun. Örneğin şöyle bir sınıfımız olsun</p>
<pre><code class="language-csharp">internal abstract class Document
{
    public string Id { get; set; }
    public string Title { get; set; }

    public abstract Document Clone();
}</code></pre>
<p>Clone işlemi yapan abstract bir metoda sahibiz. Dokümanın kendisini klonlar.</p>
<p>Sonrasında rapor ve sözleşme için aşağıdaki sınıflarımızın olduğunu hayal edin.</p>
<pre><code class="language-csharp">internal class Report : Document
{
    public int PageCount { get; set; }

    public override Document Clone()
    {
        return (Document)MemberwiseClone();
    }

    public override string ToString()
    {
        return $&quot;Report: Id={Id}, Title={Title}, PageCount={PageCount}&quot;;
    }
}

internal class Contract : Document
{
    public string PartiesInvolved { get; set; }

    public override Document Clone()
    {
        return (Document)MemberwiseClone();
    }

    public override string ToString()
    {
        return $&quot;Contract: Id={Id}, Title={Title}, PartiesInvolved={PartiesInvolved}&quot;;
    }
}</code></pre>
<p>Hem rapor hem de sözleşmelerin cache’lendiği ve klonlandığı işi yapan DocumentCache sınıfı ise şöyle olsun</p>
<pre><code class="language-csharp">internal class DocumentCache
{
    private static Dictionary documentMap = new Dictionary();

    public static Document GetDocument(string documentId)
    {
        Document cachedDocument = documentMap[documentId];
        return cachedDocument.Clone();
    }

    public static void LoadCache()
    {
        Report report = new Report { Id = &quot;1&quot;, Title = &quot;Annual Report&quot;, PageCount = 50 };
        documentMap[report.Id] = report;

        Contract contract = new Contract { Id = &quot;2&quot;, Title = &quot;Sales Contract&quot;, PartiesInvolved = &quot;Company A &amp; Company B&quot; };
        documentMap[contract.Id] = contract;
    }
}</code></pre>
<p>Bu yapıyı kullanan örnek bir kodumuz şöyle olsun;</p>
<pre><code class="language-csharp">DocumentCache.LoadCache();

while (true)
{
    Console.WriteLine(&quot;Choose document to clone:&quot;);
    Console.WriteLine(&quot;1. Report&quot;);
    Console.WriteLine(&quot;2. Contract&quot;);
    Console.WriteLine(&quot;0. Exit&quot;);
    string choice = Console.ReadLine();

    if (choice == &quot;0&quot;)
    break;

    Document clonedDocument = null;
    switch (choice)
    {
        case &quot;1&quot;:
        clonedDocument = DocumentCache.GetDocument(&quot;1&quot;);
        break;
        case &quot;2&quot;:
        clonedDocument = DocumentCache.GetDocument(&quot;2&quot;);
        break;
        default:
        Console.WriteLine(&quot;Invalid choice.&quot;);
        continue;
    }

    if (clonedDocument != null)
    {
        clonedDocument.Id = Guid.NewGuid().ToString();
        Console.WriteLine(&quot;Cloned Document:&quot;);
        Console.WriteLine(clonedDocument);
    }
}</code></pre>
<p>Hepsi bu kadar. Umarım sizin için faydalı olmuştur. Okuduğunuz için teşekkür ederim.</p>
<h3 id="kaynaklar">Kaynaklar</h3>
<ul>
<li><a href="https://refactoring.guru/design-patterns/creational-patterns">https://refactoring.guru/design-patterns/creational-patterns</a></li>
<li><a href="https://en.wikipedia.org/wiki/Factory_method_pattern">https://en.wikipedia.org/wiki/Factory_method_pattern</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>SQL Server’da Change Data Capture Özelliğini Aktif Etmek</title>
      <link>https://notes.aligoren.com/sql-serverda-change-data-capture-ozelligini-aktif-etmek</link>
      <guid>https://notes.aligoren.com/sql-serverda-change-data-capture-ozelligini-aktif-etmek</guid>
      <pubDate>Sun, 17 Mar 2024 15:23:14 GMT</pubDate>
      <author>goren.ali@yandex.com (Ali Goren)</author>
      <description>SQL Server’da Change Data Capture Özelliğini Aktif Etmek Selam herkese. Bir önceki yazıda CDC ve Change Tracking hakkında ufak bir girizgahta bulunmuştum; SQL Server’da Veri Değişikliklerini İzlemek: CDC ve Change Tracking Nedir? Şimdi bu yazıyı teoriden pratiğe dökelim ve örnek…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h3 id="sql-serverda-change-data-capture-oezelligini-aktif-etmek">SQL Server’da Change Data Capture Özelliğini Aktif Etmek</h3>
<p><img src="/media/019e6b010ae572b3.jpg" alt="" /><br />
Selam herkese. Bir önceki yazıda CDC ve Change Tracking hakkında ufak bir girizgahta bulunmuştum;</p>
<p><a href="https://aligoren.com/sql-serverda-veri-de%C4%9Fi%C5%9Fikliklerini-i%CC%87zlemek-cdc-ve-change-tracking-nedir-2478ff24a0eb">SQL Server’da Veri Değişikliklerini İzlemek: CDC ve Change Tracking Nedir?</a></p>
<p>Şimdi bu yazıyı teoriden pratiğe dökelim ve örnek bir uygulama yapalım.</p>
<h3 id="gereksinimler">Gereksinimler</h3>
<ul>
<li>Docker</li>
<li>SQL Server</li>
<li>AdventureWorks veri tabanı</li>
</ul>
<p>Bu gereksinimler, bu yazı için olan gereksinimlerdir. Docker ve AdventureWorks veri tabanı tamamen benim çalışma ortamım için gerekli. Siz kendi veri tabanınızda bu çalışmaları gerçekleştirebilirsiniz.</p>
<h3 id="kurulum">Kurulum</h3>
<p>Eğer daha önce Docker üzerinde bir MSSQL kurulumu yapmadıysanız aşağıdaki şekilde kurulumu gerçekleştirebilirsiniz.</p>
<pre><code class="language-bash">docker run -e &quot;ACCEPT_EULA=Y&quot; -e &quot;MSSQL_SA_PASSWORD=BenimP@r0lam1923&quot; --env MSSQL_AGENT_ENABLED=True -p 1433:1433 --name localSqlServer --hostname localSqlServer -d mcr.microsoft.com/mssql/server:2022-latest</code></pre>
<p>Bu kurulumda bir envorinment variable tanımladık dikkatini çekmediyse belirteyim. <strong>MSSQL_AGENT_ENABLED=True</strong> bu tanım ile birlikte SQL Server Agent’ını da aktif ediyoruz. Eğer aktif etmezseniz, CDC çalışmaz, değişiklikler algılanmaz.</p>
<p>Eğer daha önceden MSSQL kurduysanız ancak agent aktifleştirme işlemi yapmadıysanız docker’da MSSQL uygulamasının shell’ine girmelisiniz. Daha sonra aşağıdaki komutu çalıştırmanız gerekiyor;</p>
<pre><code class="language-bash">/opt/mssql/bin/mssql-conf set sqlagent.enabled true</code></pre>
<p>Daha sonranda container’ı durdurup baştan başlatmanız yeterlidir. Eğer systemctl bu sistemde mevcut ise aşağıdaki komutu vermeniz yeterlidir;</p>
<pre><code class="language-bash">systemctl restart mssql-server.service</code></pre>
<p>Evet hepsi bu kadar. Ben bu yazı için yukarıda da bahsettiğim gibi AdventureWorks veri tabanını kullanıyorum. Aşağıdaki linkten indirebilirsiniz;</p>
<p><a href="https://github.com/Microsoft/sql-server-samples/releases/download/adventureworks/AdventureWorks2022.bak">https://github.com/Microsoft/sql-server-samples/releases/download/adventureworks/AdventureWorks2022.bak</a></p>
<p>Daha sonrasında bu restore etmeniz gerekiyor. Bu aşamayı SQL Server Management Studio ya da kullanıyorsanız DataGrip ile yapabilirsiniz.</p>
<p>Evet kurulum aşaması bu kadardı.</p>
<h3 id="change-data-capture-oezelligini-aktif-etmek">Change Data Capture Özelliğini Aktif Etmek</h3>
<p>Bu özelliği aktif etmek için öncelikle CDC’yi veri tabanı seviyesinde aktifleştirmemiz gerekiyor. Bunu aşağıdaki SQL kodu ile yapıyoruz;</p>
<pre><code class="language-sql">USE AdventureWorks2022
GO
EXEC sys.sp_cdc_enable_db
GO</code></pre>
<p>Bu değişiklik ile cdc adında bir şema oluşuyor. Ancak henüz bir tablo seviyesinde ayar yapmadık bunu belirteyim. Oluşan cdc şeması aşağıdaki gibi görünüyor;<br />
<img src="/media/019e6b010b197566.png" alt="" /><br />
Burada değişiklik algılanacak kolonlar, tablolar, DDL geçmişi gibi bilgiler yer alıyor. Ancak dediğim gibi henüz tablo seviyesi bir ayar yapmadığımız için şu anda bu tabloların tamamı boş durumda.</p>
<p>Eğer veri tabanı seviyesinde CDC işlemini kapatmak isteseydik aşağıdaki komutu kullanacaktık;</p>
<pre><code class="language-sql">USE AdventureWorks2022
GO
EXEC sys.sp_cdc_disable_db
GO</code></pre>
<p>Her şey okey, önceki yazıda bahsettiğim rollere sahip olduğumuzu varsayarak o kısımlara değinmedim. Artık tablo seviyesinde aktif etme işlemine geçebiliriz. Aşağıdaki SQL kodu ile tablo ve schema seviyesinde aktifleştirme işlemini gerçekleştirebiliriz;</p>
<pre><code class="language-sql">USE AdventureWorks2022
GO
EXEC sys.sp_cdc_enable_table
    @source_schema = N'HumanResources',
    @source_name   = N'Department',
    @role_name     = NULL,
    @supports_net_changes = 1
GO</code></pre>
<p>Yukarıdaki SQL kodu <strong>HumanResources</strong> şemasında yer alan Department tablosundaki değişiklikleri dinleyecek asenkron işlemi aktif ediyor.</p>
<ul>
<li><strong>source_schema</strong> — Şema bilgisi</li>
<li><strong>source_name</strong> — Tablo bilgisi</li>
<li><strong>role_name</strong> — Hangi rolde çalışılacağı bilgisini içerir. Eğer bu parametre NULL olarak ayarlanırsa veya belirtilmezse, varsayılan olarak CDC verilerine sadece sysadmin rolü ve db_owner veritabanı rolünün üyeleri erişebilir. Bu durum, CDC verilerinin güvenliğini sağlamak ve yalnızca yetkili kullanıcıların veya rollerin bu verilere erişimini kontrol etmek için önemlidir.</li>
<li><strong>supports_net_changes</strong> — Sadece nihai değişiklik bilgisini içerir. Yani bir satırdaki bir bilgi birden fazla defa değişikliğe uğradıysa en son veriyi tutar.</li>
</ul>
<p>Bir de yukarıda yer almayan bir değer daha var.</p>
<ul>
<li><strong>filegroup_name</strong> — cdc’nin hangi filegroup içerisinde yer alacağını belirtir. Varsayılan olarak cdc default file group altında yer alır.</li>
</ul>
<p>Açıklamalar bu kadar. Şimdi bu SQL kodunu çalıştıralım. Ben aşağıdaki gibi bir çıktıyı DataGrip üzerinden aldım.</p>
<pre><code class="language-bash">[2024-03-17 17:56:00] [S0001][22969] Update mask evaluation will be disabled in net_changes_function because the CLR configuration option is disabled.
[2024-03-17 17:56:00] [S0001][14243] Job 'cdc.AdventureWorks2022_capture' started successfully.
[2024-03-17 17:56:00] [S0001][14243] Job 'cdc.AdventureWorks2022_cleanup' started successfully.
[2024-03-17 17:56:00] completed in 6 s 274 ms</code></pre>
<p>Yukarıda 2 adet job’ın tanımlı olduğunu görüyoruz. Bunlardan ilki veri değişikliklerini yakalarken, diğeri de otomatik olarak cdc tablosunda cleanup işlemi gerçekleştirir. Varsayılan cleanup ise 3 günlük bir süreye sahip. Yani retention süresi 3 gün. Şimdi cdc tablolarındaki değişikliklere bir bakalım.</p>
<p><strong>captured_columns</strong> tablosunun değiştiğini, yani içerisine yeni veriler eklendiğini görmekteyiz.<br />
<img src="/media/019e6b010b5570e8.png" alt="" /><br />
<strong>change_tables</strong> da yine değişlik içermekte. Yani yeni bir satır eklendiğini görmekteyiz;<br />
<img src="/media/019e6b010b8d7c20.png" alt="" /><br />
Tabii bunlar olmadan CDC’nin enabled olup olmadığını veri tabanı seviyesinde ayrıca şöyle bir sorgu ile görebiliriz;</p>
<pre><code class="language-sql">SELECT name, is_cdc_enabled FROM sys.databases</code></pre>
<p><img src="/media/019e6b010bc27503.png" alt="" /><br />
Gördüğünüz gibi veri tabanı seviyesinde aktif olduğunu görebiliriz. Ayrıca CDC şemamıza içi boş olan yeni bir tablo daha katıldı. <strong>HumanResources_Department_CT</strong> adında bu tablo değişiklik kayıtlarının tutulacağı bilgiyi içerir. Dolu veri ile örneğini inceleyeceğiz.<br />
<img src="/media/019e6b010bf877cf.png" alt="" /><br />
Bu aşamadan sonra <strong>Department</strong> tablosunda ilk satırda bir değişiklik gerçekleştireceğim. Engineering olan Name kolonu değerini Engineering Department yapacağım. Ve CT yani Change Tracking tablosuna aşağıdaki 2 satır yansıdı.<br />
<img src="/media/019e6b010c2c7947.png" alt="" /><br />
Tabloya bakınca 2 farklı veri görüyorsunuz. Aslında neyin önce neyin sonra olduğunu anlayabilirsiniz. Fakat bunları daha kolay anlayabilmenin bir yolu daha var. 2 Satırlık verilerle bunları görmek daha kolay iken, binlerce satırda bu iş daha zor olabiliyor.</p>
<h4 id="operation-kolonu-degerleri-ve-acklamalar">__$operation Kolonu Değerleri ve Açıklamaları</h4>
<ul>
<li>1 — <strong>Delete</strong> sorgularında bu değer kullanılır. Yani bir satırın silindiğini görebiliriz.</li>
<li>2 — <strong>Insert</strong> işleminde bu değer kullanılır.</li>
<li>3 — <strong>Before Update</strong> işlemi olarak geçer. Güncelleme işlemi yapılmadan önceki kaydın durumunu temsil eder. Bu, bir güncelleme işleminin “önceki” durumunu belirtir ve genellikle net değişikliklerin hesaplanmasında kullanılır.</li>
<li>4 — <strong>After Update</strong> işlemi olarak geçer. Güncelleme işleminden sonra kaydın durumunu temsil eder. Bu, bir güncelleme işleminin “sonraki” durumunu temsil eder ve güncellenmiş değerleri gösterir.</li>
</ul>
<p>Tablo seviyesinde yapılan bu işlemi disable etmek istersek de aşağıdaki SQL kodunu kullanmamız gerekiyor;</p>
<pre><code class="language-sql">USE AdventureWorks2022
GO
EXEC sys.sp_cdc_disable_table
    @source_schema = N'HumanResources',
    @source_name   = N'Department',
    @capture_instance   = N'HumanResources_Department',
GO</code></pre>
<p>Genel olarak CDC işlemi temel olarak böyle. Tablo seviyesinde yapılan işlemler için ayrıca sadece kolon seviyesinde change tracking işlemi yapılabilir. Bu konuya şimdilik girmedim. Kaynaklar tarafında vereceğim linkten ulaşabilirsiniz.</p>
<p>Sonuç olarak CDC mükemmel bir özellik, ancak CDC tablolarında yer alan bu satırları böyle veri tabanından okumak çok zahmetli olabilir. Mesela şöyle bir süreç için zahmetli olabilir.</p>
<p>Satış yapıldığını varsayalım. Bu satışın verisi hem data warehouse’a aktarılacak hem de başka bir API’a bildirilecek. Bu gibi durumlarda bu tabloyu da ayrıca sürekli dinleyen bir çözüm üretmek gerekebilir.</p>
<p>Veri tabanındaki değişiklikleri CDC’yi kullanarak bir mesaj kuyruğuna stream etmek buradaki en iyi çözüm olabilir. Bunun için de Debezium kullanılabilir.</p>
<p><a href="https://debezium.io/">Debezium</a></p>
<p>Debezium aslında tam olarak bu iş için var. Örnek senaryomuz yukarıdaki senaryo olsun. Debezium, CDC tarafındaki verileri alsın ve belirttiğiniz bir Kafka kuyruğuna bassın. Siz de bu kuyruğu kullanarak data warehouse’a ve API endpointlerine yeni verileri aktarın. Bu gerçekten, custom solution implement etmekten daha da basit hale geliyor.</p>
<p>Hepsi bu kadar. Okuduğunuz için teşekkür ederim.</p>
<h3 id="kaynaklar">Kaynaklar</h3>
<ul>
<li><a href="https://learn.microsoft.com/en-us/sql/relational-databases/track-changes/enable-and-disable-change-data-capture-sql-server?view=sql-server-ver16">https://learn.microsoft.com/en-us/sql/relational-databases/track-changes/enable-and-disable-change-data-capture-sql-server?view=sql-server-ver16</a></li>
<li><a href="https://debezium.io/">https://debezium.io/</a></li>
<li><a href="https://stackoverflow.com/questions/69038304/how-enable-sql-server-agent-in-docker-container-existing">https://stackoverflow.com/questions/69038304/how-enable-sql-server-agent-in-docker-container-existing</a></li>
<li><a href="https://docs.rivery.io/docs/sql-server-cdc-troubleshooting">https://docs.rivery.io/docs/sql-server-cdc-troubleshooting</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>SQL Server’da Veri Değişikliklerini İzlemek: CDC ve Change Tracking Nedir?</title>
      <link>https://notes.aligoren.com/sql-serverda-veri-degisikliklerini-i-zlemek-cdc-ve-change-tracking-nedir</link>
      <guid>https://notes.aligoren.com/sql-serverda-veri-degisikliklerini-i-zlemek-cdc-ve-change-tracking-nedir</guid>
      <pubDate>Sat, 16 Mar 2024 18:37:46 GMT</pubDate>
      <author>goren.ali@yandex.com (Ali Goren)</author>
      <description>SQL Server’da Veri Değişikliklerini İzlemek: CDC ve Change Tracking Nedir? Herkese selamlar. Son yazının üzerinden 240 yıl falan geçti. Bu yazıyı da arayı fazla uzatmamak adına yazmak istedim. Şimdi bu yazının konusu CDC yani Change Data Capture olayı. Bir de yan sanayi olarak…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h3 id="sql-serverda-veri-degisikliklerini-izlemek-cdc-ve-change-tracking-nedir">SQL Server’da Veri Değişikliklerini İzlemek: CDC ve Change Tracking Nedir?</h3>
<p><img src="/media/019e6b010a3e7136.jpg" alt="" /><br />
Herkese selamlar. Son yazının üzerinden 240 yıl falan geçti. Bu yazıyı da arayı fazla uzatmamak adına yazmak istedim.</p>
<p>Şimdi bu yazının konusu CDC yani Change Data Capture olayı. Bir de yan sanayi olarak Change Tracking olayı var. Aslında ikisi de aynı işi yapıyorlar. Sadece maliyet noktasında farklılıkları var.</p>
<p>Change Data Capture, SQL Server’a has bir özellik değil bu arada. Bunu destekleyen farklı veri tabanları da var. Örneğin PostgreSQL, MySQL, MongoDB gibi. Ama bu yazıda ben SQL server üzerine yoğunlaşmak istedim.</p>
<p><em>Not: Bu yazı sadece CDC ve Change Tracking nedir onu anlatıyor. Diğer yazılarda ise uygulama aşamasına geçerek örnekler sunmak istiyorum.</em></p>
<h3 id="cdc-tam-olarak-neyi-anlatyor">CDC Tam Olarak Neyi Anlatıyor?</h3>
<p>CDC ya da diğer bir özellik olan Change Tracking kavramları, bize veri tabanındaki değişikliklerin anında yakalanmasını ve başka bir yere loglanmasını anlatıyor gibi basit bir şey söyleyebilirim.</p>
<p>Normalde bu işlemler için, client tarafında AOP yaklaşımlı çözümler mevcut iken(Entity Framework tarafında da yine bu işlemler uygulama içerisinde yapılabilmekte), bu yaklaşımda böyle bir gereksinim bulunmamaktadır.</p>
<p>Çünkü burada işlemler en azından SQL Server tarafında veri tabanı tarafından gerçekleştirilmektedir.</p>
<p>Uygulama dışında CDC olmadan başka neler yapılabilirdi? Belki çoktan aklınıza gelmiş olabilir. Trigger kullanımı da bu konuda size destek sağlayabilird. Ancak şu ana kadar baktığınız her şey, ekstra geliştirmeler gerektiriyor.</p>
<h4 id="faydalar-neler">Faydaları Neler?</h4>
<p>Öncelikle ilk faydası, development zamanını düşürmesidir. Yani kendiniz bu iş için ayrıca bir application logic yazmak zorunda değilsiniz.</p>
<p>Database şema değişikliğinin bilinmesi zorunluluğu da yok. Yani yeni kolonlar eklemek zorunda değilsiniz ya da triggerlar ya da ikinci bir tablo. Bu tablo genelde silinen ya da değişen kayıtları basit bir timestamp datası ile tutabiliyor sonuçta. Ama buna da gerek duymuyorsunuz.</p>
<p>Gelelim TTL, retention gibi konulara. Normalde, CDC olmasaydı, siz belirli dataları manuel bir çözüm ile silmek durumunda kalabilirdiniz. Bu tablo sadece değişenleri tutan bir tablo olduğu için, ilgili işlem bitince, silinmeleri gerekiyor sonuçta. CDC ise otomatik olarak bunu bir background task gibi süresi dolanları silerek çözmekte.</p>
<p>DML işlemlerinde öyle aman aman bi yük yok. Birazdan değineceğimiz Change Tracking işleminde ufak da olsa bir yük var. Ancak öyle çok da büyük bir yük değil. Yani bir manuel çözüm bu trigger vs. olabilir, bu gibi çözümlerden kesinlikle daha az yüke sahip.</p>
<h4 id="change-data-capture-vs.change-tracking-arasndaki-farklar-nelerdir">Change Data Capture vs. Change Tracking Arasındaki Farklar Nelerdir?</h4>
<p>Öncelikle her ikisi de DML değişikliklerini desteklemekte. Ayrıca DML veri türü ya da kolon değişiklikleri de bu iki işlemde desteklenmekte.</p>
<p>Gelelim fark noktasına. Öncelikle, CDC tarihsel veri tutarken, change tracking tutmuyor. Haliyle bu alan olarak change tracking işlemini tercih edilebilir hale getiriyor.</p>
<p>Fakat bir başka noktada da CDC kullanılabilir oluyor. Çünkü CDC, asenkron bir şekilde çalışırken, Change Tracking senkron bir şekilde çalışıyor.</p>
<p>CDC tarafında bir veri değişikliğinde kullanıcı tablosunda hem gerçekleşeni hem de gerçek datayı saklama işlemi gerçekleştirilir. Bu işlem transaction logları asenkron şekilde okunarak gerçekleştirilir. Aşağıda bir CDC işlem örneği yer almaktadır;<br />
<img src="/media/019e6b010a727a4a.png" alt="" />CDC simulasyonu<br />
Change Tracking ise değişiklik bilgisini saklarken, (örneğin yeni bir satır eklediniz, güncellediniz ya da sildiniz) değişikliğe dair ayrıntıları belirtmez. Yani hangi veriler değişmiş bilemezsiniz. Kısacası bu işlemde hangi satırlarda değişiklik olduysa onu bilirsiniz fakat ne değişmiş bilemezsiniz. Bir de change tracking işleminde işlemler senkron olarak gerçekleştirilir, tarihsel veri tutmaz. Bu nedenle depolama noktasında daha az maliyetlidir.<br />
<img src="/media/019e6b010aa57475.png" alt="" />Change Tracking simulasyonu<br />
CDC işlemini database seviyesinde aktif etmek ya da pasif etmek için, <strong>sp_cdc_enable_db | sp_cdc_disable_db</strong> prosedürlerini çalıştıran kullanıcılar, <strong>sysadmin</strong> rolünde olmalıdır.</p>
<p>CDC işlemini tablo seviyesinde aktif ya da pasif etmek için <strong>sp_cdc_enable_table | sp_cdc_disable_table</strong> prosedürlerini çalıştıran kullanıcılar <strong>sysadmin</strong> rolünde ya da <strong>database db_owner</strong> rolünde olmalıdır. Bu ikisi farklı şeyler. Buna dikkat etmek gerekebilir.</p>
<p>Bu roller dışında bir kullanıcı rolü ile bu işlemler yapılamaz.</p>
<p>Şu anlık bu yazı bu kadar arkadaşlar. Okuduğunuz için teşekkür ederim. Haydi görüşürük ❤</p>
<h3 id="kaynaklar">Kaynaklar</h3>
<ul>
<li><a href="https://learn.microsoft.com/en-us/sql/relational-databases/track-changes/track-data-changes-sql-server?view=sql-server-ver16">https://learn.microsoft.com/en-us/sql/relational-databases/track-changes/track-data-changes-sql-server?view=sql-server-ver16</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>2023 Yılının Özeti</title>
      <link>https://notes.aligoren.com/2023-yilinin-ozeti</link>
      <guid>https://notes.aligoren.com/2023-yilinin-ozeti</guid>
      <pubDate>Wed, 20 Dec 2023 20:01:32 GMT</pubDate>
      <author>goren.ali@yandex.com (Ali Goren)</author>
      <description>2023 Yılının Özeti Bu yıl çok fazla şey oldu. Yani bir tanesi dünyanın gündemine oturdu. Keşke dünya gündemine iyi bir konuyla otursaydık. Ama bir depremle yok olduk adeta. Ben bu depremle bir arkadaşımı kaybettim. 50 bin’den fazla insan ise hayatını kaybetti. Milyonlar ise…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h3 id="ylnn-oezeti">2023 Yılının Özeti</h3>
<p><img src="/media/019e6b0100a57a52.jpg" alt="" /><br />
Bu yıl çok fazla şey oldu. Yani bir tanesi dünyanın gündemine oturdu. Keşke dünya gündemine iyi bir konuyla otursaydık. Ama bir depremle yok olduk adeta.</p>
<p>Ben bu depremle bir arkadaşımı kaybettim. 50 bin’den fazla insan ise hayatını kaybetti. Milyonlar ise yakınlarını, Türkiye ise mutluluğunu kaybetti.<br />
<img src="/media/019e6b0100e47e31.jpg" alt="" /><br />
Yukarıdaki fotoğrafı gördüğümde gözlerimdeki yaşı tutamamıştım. Birçok duyguyu aynı anda yaşadım. Ama bu fotoğraftaki babanın duygularını asla anlayamam. Ölen kızının başında bekledi ve o anda yaşadıkları. Yok yine çok üzülüyorum.<br />
<img src="/media/019e6b01012379bc.jpg" alt="" /><br />
Siz bakmayın epik değeri olan bu fotoğrafa. Çok uzun bir süre yardım gidemedi oraya. Sebebiyle ilgili değilim asla. Oraya gidemeyen yardımlardan dolayı birinde hakkım var ise haram olsun.<br />
<img src="/media/019e6b0101647f03.jpg" alt="" /><br />
Yukarıdaki adam toplumun kahramanı olurken, teröristler onu karalamak için kampanya başlattı. Tabiiki üçün birini aldılar. Allah kimseyi bazı egolar nedeniyle enkaz altında yardım beklemeye muhtaç etmesin.<br />
<img src="/media/019e6b01019a72e6.jpg" alt="" /><br />
Yukarıdaki fotoğraf gibi birçok kare birçok ilde vardı. Hatta bu sene Ağustos ayında arkadaşım Elazığ’da evlendi. Oraya giderken Malatya’dan geçtik. O aylarda bile enkazlar duruyordu. Yamulmuş ama düşmemiş bir bina da bir dağın başında kurulan köyde vardı.</p>
<h3 id="baz-geziler-falan">Bazı Geziler Falan</h3>
<p>Arkadaşımın nişanı yapıldıktan sonraki gün Munzur’a gittik. Hayatımda ilk defa gittim oraya. Gerçekten harika bir yer. Bir zamanlar buralarda terörün çok fazla olması beni çok fazla üzdü. Çünkü böyle harika bir yerin, terör nedeniyle yıllarca ulaşılmaz oluşu çok kötüydü.</p>
<p>Giderken aşağıdaki kaleyi gördüm. Elazığ’dan feribot ile geçerken bu manzaraya sahip olabiliyorsunuz.<br />
<img src="/media/019e6b0101d77e83.jpg" alt="" /><br />
Daha sonra Tunceli içerisinde bir dağda çay içtik. Bu esnada manzaram şöyleydi.<br />
<img src="/media/019e6b0102157ccc.jpg" alt="" /><br />
Munzur Baba Dergah’ına gittik. Girişte şunu görüyorsunuz<br />
<img src="/media/019e6b01025677f4.jpg" alt="" /><br />
Burada cerağ yaktım. Bilmediğim bir şeydi. Öğrenmiş oldum.<br />
<img src="/media/019e6b0102a87ee5.jpg" alt="" /><br />
Daha sonra burada bu suya girdik. Gerçekten aşırı soğuk 😄 öyle böyle değil. Eve getirdik ve su hemen bitti. Aşağıda peş peşe birkaç fotoğraf gelecek.</p>
<p><img src="/media/019e6b0102f97745.jpg" alt="" /></p>
<p><img src="/media/019e6b010348738c.jpg" alt="" /><img src="/media/019e6b01038d72fc.jpg" alt="" /></p>
<p><img src="/media/019e6b0103cf7be6.jpg" alt="" /></p>
<p>Daha bir sürü fotoğraf var ama fotoğraflarda pozveremeyen bir salağım ben 😄</p>
<p>Düğünden sonraki sabah Harput kalesine çıktık. Kaleye girdik, kalenin içine girdik bildiğiniz. Rütubetli o odalara kadar. Merdivenlerden indik.<br />
<img src="/media/019e6b0104077744.jpg" alt="" /><br />
Bence herkesin gelip görmesi gereken bir yer. Ama uçakla gelin ya da arabayla geliyorsanız atmosferik motor olmasın. Böyle bir yerde yemek yedik.<br />
<img src="/media/019e6b0104447324.jpg" alt="" /><br />
Ben harput kebap ne bir şey yedim. Tadı iyiydi. Et biraz sertti. Ama tadı enfesti. Daha sonra dabakhane’ye gittik.<br />
<img src="/media/019e6b01047d758b.jpg" alt="" /><br />
Tekrardan kaleye döndük harput’a. Ve birkaç fotoğraf çektim.<br />
<img src="/media/019e6b0104b577de.jpg" alt="" /><img src="/media/019e6b0104ea7078.jpg" alt="" /><img src="/media/019e6b0105297700.jpg" alt="" /><img src="/media/019e6b0105717bda.jpg" alt="" /><br />
Ahan da fotojenik sayılabilecek düzeyde bir fotoğrafım varmış. Not: En fotojeniği bu 😛</p>
<p><img src="/media/019e6b0105b07843.jpg" alt="" /></p>
<p>Sonra yer altına indim yani kalenin alt kısımlarına girdik. Biraz rütubetliydi.<br />
<img src="/media/019e6b0105ea7506.jpg" alt="" /><br />
Baya bir aşağıya inmeniz gerekiyor 😛<br />
<img src="/media/019e6b01061c7665.jpg" alt="" /><br />
Kaleden ayrıldıktan sonra dönüşte Keban Barajı’nı gördük.Lan buranın manzarası bana daha iyi geliyor ya.<br />
<img src="/media/019e6b01065171c6.jpg" alt="" /><br />
Neden bilmiyorum şu manzarayı da sevdim</p>
<p><img src="/media/019e6b0106827efd.jpg" alt="" /><br />
Daha sonra Kapadokya’ya gittim. Biraz gezdik. Yani iyiydi diyeceğim ama yok be diyemiyorum. Çok pahalı şehir. Fakat bazı fotoğraflar çekmedim değil;<br />
<img src="/media/019e6b0106b575d8.jpg" alt="" /></p>
<p>Lan bu fotoda kaya sanki bir yüz ifadesine sahip gibi 😛<br />
<img src="/media/019e6b0106ec7a6e.jpg" alt="" /><br />
Asmalı Konak’a gittik 😛<br />
<img src="/media/019e6b0107267811.jpg" alt="" /><br />
Lan be şuraya bak ya :)<br />
<img src="/media/019e6b010765753d.jpg" alt="" /><br />
Yine malak gibi poz vermişim 😛</p>
<p><img src="/media/019e6b01079e760f.jpg" alt="" /></p>
<p><img src="/media/019e6b0107d77dde.jpg" alt="" /><img src="/media/019e6b01080b7436.jpg" alt="" /></p>
<p><img src="/media/019e6b01083e7b76.jpg" alt="" /></p>
<p>Canımızdan çok sevdiğimiz bayrağımızla fotoğraf çekinmezsek olmaz dedik ve bir fotoğraf karesinde yer aldık 😛<br />
<img src="/media/019e6b0108797355.jpg" alt="" /></p>
<p><img src="/media/019e6b0108b3751a.jpg" alt="" /></p>
<p>Not: Güzel kızlar eqlesin<br />
<img src="/media/019e6b0108f47529.jpg" alt="" /><br />
Fotoğraftan gram anlamadığım için bu fotoğrafı beğendim ben. Güneş, araba, yol falan filan.</p>
<p><img src="/media/019e6b01092872b7.jpg" alt="" /></p>
<p>Daha sonra Nevşehir’e hacıbektaş’a gittik. Çingeneler ve suriyeliler oraya doluşmuş. Devletin uğramadığı bir yer haline gelmiş. Sanırım devletin şevkatli eli oralarda yoktu.<br />
<img src="/media/019e6b01095f7649.jpg" alt="" /><br />
Ne zaman poz vermeyi öğreneceksem artık…<br />
<img src="/media/019e6b0109907c3a.jpg" alt="" /><img src="/media/019e6b0109c1712a.jpg" alt="" /><br />
Burada kalacaktık ancak kalmak istemedik. Böyle güzel bir mekanı adeta yok etmişler. Gerçekten o maneviyat burada kalmamış. Gezilen her yere kakasını yapmışlar. Çilehane’ye gittik. Salak salak düşün IQ ne idüğü belirsiz tipler gelmişler, adeta oyun oynuyorlar, işiyorlardı. Gezi falan burada sona erdi. 12–13 saat sonra Gebze’de olduk.</p>
<h3 id="kariyer-degisikligi">Kariyer Değişikliği</h3>
<p>2023'ün Kasım ayında Enuygun’dan istifa ettim. 22 Aralık 2023 itibariyle de Enuygun ile tüm ilişiğim kesilmiş olacak. 2023 yılında çok güzel şeyler tattım diyebilirim. Bir finans kuruluşuna geçtim diyebilirim. Türkiye’nin en büyük holdinglerinden birisinin bir kuruluşuna.</p>
<h3 id="artk-kaldrabiliyorum">Artık Kaldırabiliyorum</h3>
<p>Araba kullanmayı biraz daha öğrendim. En azından yokuşta kaldırabiliyorum artık 😛 ama İstanbul trafiğine hala girmek istemiyorum. Bana manuel hala zor geliyor. Amelelik gibi geliyor.</p>
<h3 id="borsa">Borsa</h3>
<p>Borsaya girdim lan. YTD. Yapıyoruz bir şeyler. Sağolsun <a href="https://medium.com/u/b42da9eff386">Oğuz kumcular</a> ile ilerletiyoruz bu işi. Bu süreçte şu varlıklarımın tamamında karlıyım. 2023'ü karlı kapatıyorum;</p>
<ul>
<li>BES</li>
<li>Yerli fon</li>
<li>Yerli hisse senedi</li>
<li>Kripto</li>
<li>Döviz</li>
<li>Emtia (Altın, Gümüş, Paladyum, Platin)</li>
</ul>
<p>Umarım böyle de gider he.</p>
<h3 id="yeni-dostlar">Yeni Dostlar</h3>
<p>Bu yıl içerisinde <a href="https://medium.com/u/18571947c562">Mustafa Dikyar</a> gibi harika bir insanı kazandım. Umarım bu güzel insanla dostluğumuz sonsuza dek gider. Gerçekten vakit geçirmekten keyif aldığım süper bir insan.</p>
<p>Birbirimizi anlıyoruz. Tradeofflarımızı biliyoruz. Ve aynı sıkıntıları paylaşıp, yükleniyoruz. Bence öyle. Öyle değil mi lan Mıstaa?</p>
<p>Size Mıstaa’yı anlatacak olursam, çok çalışkan, işini sahiplenen, öğrenmeyi seven, öğretmeyi seven, ekibinin yaşadığı zorluklarda kendisin öne atan über bir insan.</p>
<p>Ahan bu da Mıstaa’lı bir fotoğraf olsun<br />
<img src="/media/019e6b0109f8723e.jpg" alt="" /></p>
<h3 id="oezet-gec-pc-diyenler-icin">Özet Geç P*ç Diyenler İçin</h3>
<p>Kısacası 2023 benim için diğer yıllara göre çok daha fazla dolu bir yıl oldu. Mutlu muyum değil miyim bilemiyorum. Çünkü çok üzüldüğüm zamanlar oldu. Çünkü arkadaşımı kaybettim depremde. Ama yeni arkadaşlar kazandım. İş değişikliğim oldu. Borsa ile haşır neşir oldum. Öyle ya başka daha ne olsun? Ha bir de tekrardan spor yapma kararı aldım. Daha önce 2.5–3 sene aralıksız yapmıştım. Pandemi olmasaydı yapmaya devam da ederdim.</p>
<p>Bu kadar uzun bir yazıyı, fotoğraflı falan okuyup sabrettiyseniz, teşekkürler gerçekten. Sabrınıza hayranım ve zamanınızı ayırdığınız için müteşekkirim.</p>
<p>2024 umarım hepimiz için mutlu bir yıl olur. Bir daha asla üzülmeyiz ve gökkuşağından daha fazla renkleri olan, güneşten daha sıcak gülücükler dağıtırız çevremize.</p>
<p>Öptüm, kib…</p>
]]></content:encoded>
    </item>
    <item>
      <title>.NET Core ve System.CommandLine ile Komut Satırı Uygulamaları Geliştirmek</title>
      <link>https://notes.aligoren.com/net-core-ve-system-commandline-ile-komut-satiri-uygulamalari-gelistirmek</link>
      <guid>https://notes.aligoren.com/net-core-ve-system-commandline-ile-komut-satiri-uygulamalari-gelistirmek</guid>
      <pubDate>Sun, 12 Nov 2023 20:54:19 GMT</pubDate>
      <author>goren.ali@yandex.com (Ali Goren)</author>
      <description>Herkese selamlar. Bu yazı’da .NET Core ile birlikte üçüncü parti kütüphanelere ya da manuel yöntemlere gerek duymaksızın nasıl CLI uygulamalar geliştirebileceğimize değinmek istiyorum. Daha önce commandlineparser kullandınız mı bilmiyorum. Ancak enuygun’dan önceki firmamda, bir…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><img src="/media/019e6b00ffa0706a.png" alt="" /><br />
Herkese selamlar. Bu yazı’da .NET Core ile birlikte üçüncü parti kütüphanelere ya da manuel yöntemlere gerek duymaksızın nasıl CLI uygulamalar geliştirebileceğimize değinmek istiyorum.</p>
<p>Daha önce <a href="https://github.com/commandlineparser/commandline">commandlineparser</a> kullandınız mı bilmiyorum. Ancak enuygun’dan önceki firmamda, bir süreliğine kullanma durumum olmuştu mono kullanarak.</p>
<p>Hep içten içe bu işi daha çok kolaylaştıran bir kütüphane olması gerektiğini düşünüyordum. Haliyle kendi kütüphanemi yapmaya karar verdim ve bok gibi bir şey ortaya çıktı. Zaten hiçbir yerde de göremezsiniz onu.</p>
<p>Daha sonraları ise Microsoft mühendisleri ve topluluk gerçekten çok tatlış bir kütüphane ortaya çıkartmış. Kullanımı kolay, dokümantasyonu güzel olan bir kütüphane yani <a href="https://learn.microsoft.com/en-us/dotnet/standard/commandline/">System.CommandLine</a> kütüphanesi.</p>
<h3 id="ksaca-system.commandline">Kısaca System.CommandLine</h3>
<p>Öncelikle şu anda System.CommandLine preview olarak yayında. Yani kurarken “<strong>Include prerelease</strong>” demeniz gerekiyor.</p>
<p>Bu kütüphane temel olarak bir CLI uygulaması yapma esnasında ne gerekiyor ise onu size sağlıyor. Mesela CLI input parse etmek ya da bir description göstermek gibi.</p>
<p>Prerelease dedim ancak şu anda .NET CLI, .NET için uninstall, diagnostic tool, svcutil vs. gibi birçok araç yine bu kütüphaneyi kullanıyor.</p>
<p>Ayrıca bu kütüphane şu anda AOT desteği ile birlikte geliyor. Kısacası modern özelliklerle size CLI app geliştirmek konusunda yardımcı olabilir.</p>
<p>Yine bu kütüphane POSIX ya da Windows kurallarına göre inputların kontrolünden de emin oluyor.</p>
<p>Tab completion ve response file desteği de yine bu kütüphane ile gelmekte.</p>
<h3 id="kurulum">Kurulum</h3>
<p>Eğer Visual Studio kullanıyorsanız Nuget paketlerine prerelease olanları da dahil ederek System.CommandLine olarak arama yapın. Yok kullanmıyor iseniz şöyle de kurabilirsiniz</p>
<pre><code class="language-bash">dotnet add package System.CommandLine --prerelease</code></pre>
<h3 id="oernek-bir-proje-docker-image-search">Örnek Bir Proje — Docker Image Search</h3>
<p>Örneğin bir projede oluşturduk ve bu projenin amacı da Docker üzerinden image araması gerçekleştirmek. Yani aslında birden çok özelliği var fakat bu projede image search yapalım. Hem yukarıdaki kütüphaneyi hem de Docker kütüphanesini kuralım</p>
<pre><code class="language-bash">dotnet add package Docker.DotNet</code></pre>
<p>Şimdi gelelim kütüphanenin kullanımına. Öncelikle System.CommandLine kütüphanesi option dediğimiz, command’lara passlanabilen named parameter dediğimiz özelliklere sahiptir. Ya da yapı diyeyim.</p>
<p>Dinamik olarak type bind edilebilen generic türlerdir. Örneğin bir image’in adını alacağımız option’ı yazmamız gerekirse şöyle olur;</p>
<h4 id="option-tanmlamak">Option Tanımlamak</h4>
<pre><code class="language-csharp">var dockerImageNameOption = new Option(
        name: &quot;--image-name&quot;,
        description: &quot;Image name to search&quot;
    );</code></pre>
<p>Gördüğünüz gibi eğer bir “<strong>— image-name</strong>” komutu gönderirsek bunun türü string olmalıdır diyebiliyoruz. Eğer bir option’ın T değeri nullable değil ise required olarak tanımlanmış demektir. Mesela search aşamasında bir de limit belirtelim. Yani bize tek seferde 2 sonuç dönsün diyebilelim ya da limit belirtmeden kütüphanenin default değerleri dönsün diyebilelim.</p>
<pre><code class="language-csharp">var dockerImageLimitOption = new Option(
        name: &quot;--count&quot;,
        description: &quot;Search response limit. The default value is null&quot;
    );</code></pre>
<p>Örneğin yukarıdaki senaryoda image name girilmeseydi şu şekilde bir çıktı alacaktık<br />
<img src="/media/019e6b00ffe37749.png" alt="" /><br />
Tabii option tanımladık hemen anında olsun gibi bir şey yok :) option’lar için ne demiştik? Command’lara passlanmalılar. Şimdi gelin bir root command tanımlayalım.</p>
<h4 id="rootcommand-tanmlama">RootCommand Tanımlama</h4>
<p>Öncelikle RootCommand nedir onu bilmeliyiz. Bir root command, çalıştırılabilir uygulamanın dosyasının adını belirten komuttur. Bu yazı dotnet üzerine olduğu için dotnet komutu, dotnet.exe’yi belirtir diyebiliriz.</p>
<p>Örneğimiz için RootCommand şöyle olsun;</p>
<pre><code class="language-csharp">var rootCommand = new RootCommand(&quot;Sample Docker CLI&quot;);
rootCommand.AddOption(dockerImageNameOption);
rootCommand.AddOption(dockerImageLimitOption);</code></pre>
<p>Tabiiki bu tarz bir yapı kurulmamalı ama örnek olması açısından veriyorum. Option’larımızı rootCommand olarak ekledik ancak bu option’lara veri geldiğinde bunları yakalayıp işlem yaptırmamız da gerekiyor. Diğer türlü sadece option eklemiş olur ancak handle etmemiş oluruz</p>
<pre><code class="language-csharp">rootCommand.SetHandler(async (imageName, imageCount) =&gt;
{
    var images = await client.Images.SearchImagesAsync(new Docker.DotNet.Models.ImagesSearchParameters()
    {
        Term = imageName,
        Limit = imageCount
    });

    foreach (var image in images)
    {
        Console.WriteLine(&quot;----------------&quot;);
        Console.WriteLine($&quot;Image: {image.Name}&quot;);
        Console.WriteLine($&quot;Description: {image.Description}&quot;);
        Console.WriteLine($&quot;Start: {image.StarCount}&quot;);
        Console.WriteLine($&quot;Official: {(image.IsOfficial ? &quot;Yes&quot; : &quot;No&quot;)}&quot;);
        Console.WriteLine(&quot;----------------&quot;);
        Console.WriteLine(Environment.NewLine);
    }

}, dockerImageNameOption, dockerImageLimitOption);</code></pre>
<p>Yukarıdaki kod örneğinde, rootCommand bir variadic yapıya sahiptir. Yani istediğiniz kadar parametre alabiliyor. Tabiiki abartmayın 😛</p>
<p>Aldığı parametrelerin türü ise, option’ların aldığı T türünden.</p>
<p>Daha sonrasında ise şu kodu ekleyerek, CLI tarafında gelen argümanları rootCommand’e paslamamız gerekiyor;</p>
<pre><code class="language-csharp">await rootCommand.InvokeAsync(args);</code></pre>
<p>Projemize, launchSettings ile CLI args paslayarak test işlemimizi şöyle yapalım;<br />
<img src="/media/019e6b01001a7f3a.png" alt="" /><br />
Default hiçbir parametrenin girilmediği yani root command’in bir şey parse etmediği durumda eğer uygulamayı çağırır isek şöyle bir çıktımız olacak.<br />
<img src="/media/019e6b0100537979.png" alt="" /><br />
Bu yazı bu kadar. Okuduğunuz için teşekkür ederim. Umarım faydalı olmuştur :)</p>
<h4 id="oernek-github-reposu">Örnek GitHub Reposu</h4>
<p><a href="https://github.com/aligoren/docker-cli-example-with-system-commandline">GitHub - aligoren/docker-cli-example-with-system-commandline: Docker CLI Example with…</a></p>
<h3 id="kaynaklar">Kaynaklar</h3>
<ul>
<li><a href="https://learn.microsoft.com/en-us/dotnet/standard/commandline/">https://learn.microsoft.com/en-us/dotnet/standard/commandline/</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Reliability Üzerine</title>
      <link>https://notes.aligoren.com/reliability-uzerine</link>
      <guid>https://notes.aligoren.com/reliability-uzerine</guid>
      <pubDate>Wed, 05 Jul 2023 20:05:47 GMT</pubDate>
      <author>goren.ali@yandex.com (Ali Goren)</author>
      <description>Selamlar. Bir önceki yazımda Veri Sistemleri Üzerine bir ufak girizgahta bulunmuştum. Sonuçta data-intensive bir uygulama geliştiriyor isek, bunlar hakkında da konuşabilmeliyiz. Bu yazıda ise reliability kavramı üzerine konuşacağız. Reliability ya da bir şeyin reliable olması…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><img src="/media/019e6b00fe387d5c.jpg" alt="" /><br />
Selamlar. Bir önceki yazımda <a href="https://medium.com/@aligoren/veri-sistemleri-%C3%BCzerine-f466dd821e3e">Veri Sistemleri Üzerine</a> bir ufak girizgahta bulunmuştum. Sonuçta data-intensive bir uygulama geliştiriyor isek, bunlar hakkında da konuşabilmeliyiz. Bu yazıda ise reliability kavramı üzerine konuşacağız.</p>
<p>Reliability ya da bir şeyin reliable olması demek güvenilir olması demektir. Negatif durumlarda ise unreliable olduğunu söyleriz.</p>
<p>Yazılım süreçlerinde ise reliable olma konusunu konuşurken şunları düşünebiliriz.</p>
<ul>
<li>Uygulama, kullanıcının beklediği şekilde fonksiyonu çalıştırır</li>
<li>Kullanıcı kaynaklı hataları ya da kullanıcının bir yazılımı beklentilerin üzerinde bir şekilde kullanmasını tolere eder</li>
<li>Performansı söz konusu ise hem yük hem de veri yoğunluğu noktasında yeterli düzeydedir</li>
<li>Sistem, herhangi bir yetkisiz erişimi ve kötüye kullanımı engeller.</li>
</ul>
<p>Eğer tüm bu bahsedilenler bir araya geldiğinde iyi bir şekilde ya da doğru şekilde çalışmak anlamına geliyorsa, reliability kavramını şöyle düşünebiliriz</p>
<blockquote>
<p>bazı şeyler yanlış gittiğinde bile doğru şekilde çalışmaya devam etmek</p>
</blockquote>
<p>Yanlış gitmesi mümkün olan şeylere <strong>faults</strong> deriz yani hatalardır. Bu hataları tahmin edebilen sistemlere ise <strong>fault-tolerent</strong> ya da <strong>resilient</strong> sistemler deriz.</p>
<h4 id="kavramlara-bir-goez-atalm">Kavramlara Bir Göz Atalım</h4>
<p><strong>faults:</strong> Hatalar</p>
<p><strong>fault tolerent:</strong> Hata tolere edebilirlik</p>
<p><strong>resilient:</strong> Esnek ya da dayanıklılık</p>
<p>Kısacası bir şeyler yanlış gidebilir bu mümkün, bu durumda faults olarak değerlendiririz. Bu hataların oluşmasını tolere edebilecek bir sistemden de bahsettiğimizde ya fault-toleren ya da resilient sistemlerden bahsetmiş oluyoruz.</p>
<p>Aslında fault-tolerent kavramını belki yanlış anlayabileceğimizi öğretiyor bu kitap.</p>
<p>Düşünün bir kara delik dünyamızın yanında belirdiği anda dünyayı da yok yutacaktır. Bu noktada var olan bütün sunucularımız da bununla birlikte yok olacaktır. Bu durumda 2 senaryo var.</p>
<p><strong>Senaryo 1</strong></p>
<p>Mister Spak ve Turist Ömer verilerimizi kompüter’e taşıyabilir.<br />
<img src="/media/019e6b00fe7273cf.jpg" alt="" /><br />
<strong>Senaryo 2</strong></p>
<p>Bir başka gezegende de host edilebilir ortamlar oluşturmak</p>
<p>İlk senaryo kurgu olsa da ikinci senaryo da şu an için pek mümkün değil gibi. Çünkü sisteminizin fault tolerent olabilmesi için milyarlarca doları gözden çıkarmanız gerekebilir.</p>
<p>Yani fault tolerent sistem olmak, her durumu temsil etmez. Ancak belirli durumlarda fault tolerent olmaktır.</p>
<h4 id="fault-vs-failure">Fault vs Failure</h4>
<p>Bir sistem hakkında konuşurken fault yani hata ya da failure gibi durumlardan bahsedebiliriz. İkisi aynı anda söylenebilir ancak aynı şeyler değildir.</p>
<p>Fault dediğimiz durumda sistem çalışıyordur ancak bir şeyler yanlış gidiyordur. Failure durumda ise gerçekten bir sorun vardır ve hizmet verilemezlik ortaya çıkmıştır. Faults dediğimiz durumların failure ortaya çıkarabileceğini de bilmemiz gerekiyor.</p>
<h4 id="sfr-hata-sfr-arza-m-demek-hocam">Sıfır Hata, Sıfır Arıza mı Demek Hocam?</h4>
<p><img src="/media/019e6b00fea973fd.jpg" alt="" /><br />
Gerçekçi olmak gerekirse hataların tamamen yok edilmesi en azından günümüzde pek mümkün görünmüyor sevgili okur 😛</p>
<p>Bu nedenle fault tolerent sistemler tasarlarken de, hataların arıza oluşturan yani failure oluşturan durumlara yol açmasının önüne geçecek fault tolerent sistemler tasarlamamız gereklidir</p>
<p>Kitapta bu noktadan sonra hata türleri önümüze geliyor. Bunlar ise şunlar</p>
<ul>
<li>Hardware Faults</li>
<li>Software Errors</li>
<li>Human Errors</li>
</ul>
<p>Bunlara da birazcık değinmek gerekebilir.</p>
<h4 id="hardware-faults-bize-neyi-anlatr">Hardware Faults Bize Neyi Anlatır?</h4>
<p>Genellikle bir sistemsel hata ile karşılaşınca, donanımsal hataları düşünmeye başlarız.</p>
<p>Örnek vermek gerekirse bir anda hard-disk’ler çökebilir, RAM kaynaklı hatalar ortaya çıkabilir, dünyanın en mükemmel en sorunsuz elektrikli ülkesi olan Türkiye’de elektrik bir anda kesintiye uğrayabilir, ya da kediniz ağ kablosunu kemirebilir ya da daha fena şeyler yapabilir. Takılmayın kedidir kedi<br />
<img src="/media/019e6b00fede79d4.jpg" alt="" /><br />
Bir firmada çalışan bir arkadaşım bu tarz şeyleri veri merkezlerinde sürekli olabildiğini söylüyordu. Bu gerçekten Enuygun’dan önceki firmamda iş ortaklığı yürüttüğümüz bir firmada sistem admin ve daha fazlası olarak çalışan bir arkadaşla olan sohbette duyduklarımdı.</p>
<p><strong>Peki ne yapılabilir?</strong></p>
<p>İlk olarak, bir HDD’nin bozulacağı senaryo için, bir başka yedek satın alarak onu bekletmek olabilir. Diskler belki RAID olarak yarlanabilirler. Sunucularda belki çiftli güç kaynakları olabilir. (Donanımdan anlamadığım belli mi lan?) Ya da jeneratorler yedek güç olarak bu noktada yer alabilir.</p>
<p>Günün sonunda bir HDD mi bozuldu? Diğeri devreye girebilir, sallıyorum bir güç kaynağı mı bozuldu? Diğeri devreye girer. Elektrik mi gitti? Bu noktada artık jeneratorler devreye girer.</p>
<p>Siz bu sayede bir donanımın bozulmasını engellemiş olmuyorsunuz, sistemin yıllarca sorunsuz şekilde çalışmış oluyorsunuz.</p>
<p><strong>Maliyetler?</strong></p>
<p>Normalde bu tarz bir yaklaşım sorun yaratmazken, yüksek işlem gücü gerektiren uygulamalar ve veri saklama alanları nedeniyle donanım gereksinimleri de arttı. E bu durumda her donanımı çiftlemek de birazcık güç olabilir. Bunun yerine AWS gibi Azure gibi ya ad Google Cloud gibi sistemler sanal makineler oluşturarak size esnek ve elastik yapıları tek bir reliable makine üzerinde çalışma fırsatı sunuyor.</p>
<h4 id="software-errors-bize-neyi-anlatr">Software Errors Bize Neyi Anlatır?</h4>
<p>Genellikle donanım kaynaklı hataların birbirinden bağımsız ya da bir anda ortaya çıktığını varsayarız. Bir makinenin diski ya da RAM’i arızalanıyor ise, bu başka bir makinede de böyle bir sorunun olacağını göstermez. Çünkü bu sıcaklıktan, voltajdan vs. birçok şeyden de ortaya çıkabilir.</p>
<p>Ayrıca bir başka hata türü de mesela, tasarlanan sistemde oluşan sistemsel hata türüdür. Bu tarz hataları tahmin etmek çok zordur. Bunun için testler yapıyor olmanız size tünelin sonundaki ışığı göstermeyecektir.<br />
<img src="/media/019e6b00ff1970e9.jpg" alt="" /><br />
<em><strong>Örnek 1:</strong></em></p>
<p>Belirli kötü bir girdi verildiğinde bir uygulama sunucusunun her bir örneğini çökerten bir yazılım hatası. Örneğin, 30 Haziran 2012'deki artık saniye (leap second) olayı, Linux çekirdeğindeki bir hatadan dolayı birçok uygulamanın aynı anda askıda kalmasına neden oldu.</p>
<p>Kaynak: <a href="https://www.wired.com/2012/07/leap-second-glitch-explained/">https://www.wired.com/2012/07/leap-second-glitch-explained/</a></p>
<p><em><strong>Örnek 2:</strong></em></p>
<p>Örneğin CPU’yu, belleği, disk alanı vs. gibi paylaşılan kaynakları tüketen kontrolsüz bir süreç.</p>
<p><strong>Örnek 3:</strong></p>
<p>Bir sistem düşünün ana thread’i bloklasın. Bu nedenle yanıt verilebilir olması da sıkıntıya giriyor.</p>
<p><strong>Örnek 4:</strong><br />
<img src="/media/019e6b00ff5a74a7.jpg" alt="" /><br />
Kelebek etkisi. Bir hatanın bir başka hatayı, o hatanın da başka bir hatayı tetiklemesi nedeniyle ortaya çıkan kaotik hatalar da ortaya çıkabilir.</p>
<p>Maalesef bu türden hatalar ortaya çıkana dek kendisini göstermeyen sinsi düşmanlardır. Maalesef bu tarz hataların hemen uygulanacak hızlı çözümleri de yoktur :( Ama şöyle örnekler sunulabilir</p>
<ul>
<li>Kapsamlı testler yapmak</li>
<li>Process’leri izole etmek</li>
<li>Process’lerin crash olmasına ve restart edilmesine izin vermek</li>
<li>Monitoring</li>
</ul>
<p>Vs. vs. vs. bildiğiniz türden şeyler</p>
<h4 id="human-errors-bize-neyi-anlatr">Human Errors Bize Neyi Anlatır?</h4>
<p>Günün sonunda bugün ortaya çıkan tüm ürünler, insan elinin değdiği sistemlerdir. Yapay zeka projelerinden tutun da yazdığımız CRUD uygulamalara kadar. Ayrıca bu sistemlerin çalışmasında görevli kişiler de yine insanlardır.</p>
<p>Kedi gibi bir insan da olsa sonuçta insanlar yani hata yapabilirler 😛 Localde çalışıyordu demeleriyle ünlüdürler.</p>
<p>Ünlü GitLab veri silme hikayesini biliyorsunuzdur belki. 300 GB data bir anda uçuruldu.</p>
<p>Kaynak: <a href="https://about.gitlab.com/blog/2017/02/10/postmortem-of-database-outage-of-january-31/">https://about.gitlab.com/blog/2017/02/10/postmortem-of-database-outage-of-january-31/</a></p>
<p>Hiç kuşku yok ki bu hatayı yapan kişi kötü bir niyetle yapmasa da insanlara ve yaptıkları işlere güvenme noktasında agnostik olmamız gerektiğini kabul etmeliyiz.</p>
<h4 id="nasl-guevenilir-sistemler-insa-ederiz">Nasıl Güvenilir Sistemler İnşa Ederiz?</h4>
<p>Peki insanlar güvenilir değil yani unreliable ise, sistemlerimizi nasıl güvenilir yapacağız?</p>
<ul>
<li>Hata oluşma ihtimallerinin en aza indirileceği sistemler tasarlayabiliriz. Mesela, iyi şekilde tasarlanan abstraction’lar, API’lar vs… Bunlar bir şeyleri doğru yapmaya sizi zorlarken, yanlış yapma noktasında da önünüze engeller çıkarır. Örneğin çok kritik bir şeyi silecekseniz, bunu bir UI ile yapacaksanız üzerinde düşünmeniz gereken bazı UI/UX durumları olabilir.</li>
<li>Sandbox ortamlar kullanarak, hataların yapılabileceği noktaları gerçek ortamlardan ayırabiliriz. Bu sayede gerçek kullanıcı datasına herhangi bir müdahalemiz de olmamış olur. GitLab örneği çok iyi açıklıyor bunu.</li>
<li>Çok yorucu olsa da manuel testler, integration testler ve unit testleri tüm noktalarıyla yapmaya çalışabiliriz. Burada belki automated testler de nadir de olsa ortaya çıkabilecek durumlar için önden size bu durumu bildirebilirler. (<em>Çalıştığım firmada, kendi projemde bir test ile hiç karşılaşmadığımız bir hatayı cover edebildik</em>)</li>
<li>Bu türden hatalar olabilir ancak bunların hızlı şekilde kontrol altına alınabileceği etkisi daha ufak geliştirmelere izin vermemiz gerekebilir. Örneğin bir noktada config sorunumuz var ise hemen roll-back yapabilmeliyiz.</li>
<li>Detaylı bir monitoring işimize yarayabilir. Mesela performans ölçümleri, hata oranları vs. gibi. Buna diğer mühendislik disiplinlerinde telemetry de denilebilir.</li>
</ul>
<h4 id="peki-reliability-ne-kadar-oenemlidir">Peki Reliability Ne Kadar Önemlidir?</h4>
<p>Reliable olma, bir nükleer tesis yazılımında ya da uzay araçları yaızlımlarında fark etmeksizin önemlidir. Bunun yanında bir e ticaret platformunun yazılımlarında da önemlidir. Yani reliable yani güvenilir olma durumu her koşulda önem arz eder.</p>
<p>X bir firmada sıklıkla ortaya çıkan buglar nedeniyle hem finansal kayıplar olabilir hem de prestij kaybı ortaya çıkabilir. Yani bu güvenilir olmama durumunun ortaya çıkaracağı etkilerdir.</p>
<p>Bazen ise reliable olma durumunun o kadar da olmadığı şartlara sahip olabiliriz. Mesela bir prototip ürün geliştirirken reliable olması çok önemli değildir. Prototipin işi bu değildir. Eğer bunun üzerine çok düşünülür ise geliştirme maliyetleri bir hayli artacaktır.</p>
<p>Bu konu bu kadardı. Umarım kafanızda data-system ya da veri sistemi üzerine birazcık da olsa bir şeyler oluşturabilmişimdir. Buradaki içerikler kitaptan geliyor.</p>
<p>Okuduğunuz için teşekkür ederim.</p>
<h3 id="kaynaklar">Kaynaklar</h3>
<ul>
<li><a href="https://dataintensive.net/">https://dataintensive.net/</a></li>
</ul>
]]></content:encoded>
    </item>
  </channel>
</rss>