<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://sonsuzus.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://sonsuzus.github.io/" rel="alternate" type="text/html" /><updated>2026-07-25T07:13:28+00:00</updated><id>https://sonsuzus.github.io/feed.xml</id><title type="html">SonsuzUs</title><subtitle>Programlama ve Yazılım</subtitle><author><name>Sonsuz Us</name></author><entry><title type="html">Birim Testleri ve Profil Analizi: Koduna Dedektif Gibi Yaklaş</title><link href="https://sonsuzus.github.io/posts/birim-testleri-ve-profil-analizi-koduna-dedektif-gibi-yaklas/" rel="alternate" type="text/html" title="Birim Testleri ve Profil Analizi: Koduna Dedektif Gibi Yaklaş" /><published>2026-07-25T00:00:00+00:00</published><updated>2026-07-25T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/birim-testleri-ve-profil-analizi-koduna-dedektif-gibi-yaklas</id><content type="html" xml:base="https://sonsuzus.github.io/posts/birim-testleri-ve-profil-analizi-koduna-dedektif-gibi-yaklas/"><![CDATA[<p>Kod yazmak bazen Lego yapmak gibidir: Parçalar tek tek güzel görünür ama kuleyi kaldırınca ortadan ikiye ayrılıyorsa bir yerde hata vardır. Birim testleri, bu Lego parçalarının tek başına sağlam olup olmadığını kontrol eder. Profil analizi ise aynı parçaların ne kadar hızlı, ne kadar bellekle ve hangi maliyetle çalıştığını gösterir. Yani biri doğruluk dedektifi, diğeri performans dedektifidir.
``
Birim testinin temel fikri basittir: Büyük bir sistemi küçük davranışlara ayırır, her davranışı izole biçimde sınarız. Bir fonksiyonun beklenen çıktıyı üretip üretmediğini test etmek, yazılımın matematiksel olarak daha güvenilir hale gelmesine yardım eder. Elbette testler mutlak ispat değildir; fakat doğru seçilmiş örnekler, sınır durumları ve hata senaryolarıyla güven düzeyini ciddi biçimde artırır.</p>

<p>Bir fonksiyonu $f(x)$ gibi düşünelim. Test yazarken aslında belirli girdiler için şu önermeyi kontrol ederiz: $f(girdi) = beklenen_çıktı$. Örneğin indirim hesaplayan bir fonksiyonda $f(100, 0.2) = 80$ olmalıdır. Eğer bu önerme bozulursa test kırmızıya döner ve bize şunu söyler: Kodun davranışı ile beklentin aynı evrende yaşamıyor.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Ne Kontrol Eder?</th>
      <th>Tipik Soru</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Birim testi</td>
      <td>Doğruluk</td>
      <td>Fonksiyon doğru sonucu veriyor mu?</td>
    </tr>
    <tr>
      <td>Entegrasyon testi</td>
      <td>Parçalar arası uyum</td>
      <td>Modüller birlikte çalışıyor mu?</td>
    </tr>
    <tr>
      <td>Profil analizi</td>
      <td>Performans</td>
      <td>Zaman ve bellek nerede harcanıyor?</td>
    </tr>
    <tr>
      <td>Benchmark</td>
      <td>Karşılaştırmalı hız</td>
      <td>A yöntemi mi B yöntemi mi hızlı?</td>
    </tr>
  </tbody>
</table>

<p>Birim testlerinde yaygın desen Arrange-Act-Assert üçlüsüdür. Önce ortamı hazırlarız, sonra fonksiyonu çalıştırırız, en sonunda sonucu doğrularız. Python ve pytest ile küçük ama anlamlı bir örnek görelim:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">calculate_discount</span><span class="p">(</span><span class="n">price</span><span class="p">,</span> <span class="n">rate</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">price</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">(</span><span class="sh">'</span><span class="s">price cannot be negative</span><span class="sh">'</span><span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="mi">0</span> <span class="o">&lt;=</span> <span class="n">rate</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">(</span><span class="sh">'</span><span class="s">rate must be between 0 and 1</span><span class="sh">'</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">price</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">rate</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">test_calculate_discount_normal_case</span><span class="p">():</span>
    <span class="c1"># Arrange
</span>    <span class="n">price</span> <span class="o">=</span> <span class="mi">100</span>
    <span class="n">rate</span> <span class="o">=</span> <span class="mf">0.25</span>

    <span class="c1"># Act
</span>    <span class="n">result</span> <span class="o">=</span> <span class="nf">calculate_discount</span><span class="p">(</span><span class="n">price</span><span class="p">,</span> <span class="n">rate</span><span class="p">)</span>

    <span class="c1"># Assert
</span>    <span class="k">assert</span> <span class="n">result</span> <span class="o">==</span> <span class="mi">75</span>


<span class="k">def</span> <span class="nf">test_calculate_discount_rejects_negative_price</span><span class="p">():</span>
    <span class="kn">import</span> <span class="n">pytest</span>
    <span class="k">with</span> <span class="n">pytest</span><span class="p">.</span><span class="nf">raises</span><span class="p">(</span><span class="nb">ValueError</span><span class="p">):</span>
        <span class="nf">calculate_discount</span><span class="p">(</span><span class="o">-</span><span class="mi">10</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">)</span>
</code></pre></div></div>

<p>Bu testler sadece normal senaryoyu değil, hata senaryosunu da kontrol eder. İyi test yazmanın püf noktası, mutlu yol kadar mutsuz yolları da düşünmektir. Çünkü kullanıcılar her zaman bizim hayal ettiğimiz gibi davranmaz; bazen eksi fiyat girerler, bazen yüzde 400 indirim isterler, bazen de sistemin sabrını sınarlar.</p>

<p>Test kapsamı konuşulurken sıkça coverage oranı gündeme gelir. Diyelim ki projenizde 100 satır çalıştırılabilir kod var ve testler 85 satırı çalıştırıyor. Kapsam yaklaşık $Coverage = \frac{85}{100} \times 100 = 85\%$ olur. Ancak dikkat: Yüksek coverage, kaliteli test anlamına her zaman gelmez. Bir satırı çalıştırmak başka, onun doğru davrandığını doğrulamak başkadır.</p>

<table>
  <thead>
    <tr>
      <th>İyi Test</th>
      <th>Kötü Test</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tek davranışı sınar</td>
      <td>Her şeyi aynı anda test eder</td>
    </tr>
    <tr>
      <td>Okunabilir isim taşır</td>
      <td>test1, test2 gibi belirsizdir</td>
    </tr>
    <tr>
      <td>Sınır durumlarını içerir</td>
      <td>Sadece kolay örnekleri dener</td>
    </tr>
    <tr>
      <td>Deterministiktir</td>
      <td>Bazen geçer bazen kalır</td>
    </tr>
  </tbody>
</table>

<p>Gelelim profil analizine. Kod doğru olabilir ama yavaşsa kullanıcı yine mutsuz olur. Python’da cProfile, hangi fonksiyonun kaç kez çağrıldığını ve toplamda ne kadar süre harcadığını gösterir:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">cProfile</span>

<span class="k">def</span> <span class="nf">slow_sum</span><span class="p">(</span><span class="n">numbers</span><span class="p">):</span>
    <span class="n">total</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">number</span> <span class="ow">in</span> <span class="n">numbers</span><span class="p">:</span>
        <span class="n">total</span> <span class="o">+=</span> <span class="n">number</span>
    <span class="k">return</span> <span class="n">total</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="sh">'</span><span class="s">__main__</span><span class="sh">'</span><span class="p">:</span>
    <span class="n">data</span> <span class="o">=</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)</span>
    <span class="n">cProfile</span><span class="p">.</span><span class="nf">run</span><span class="p">(</span><span class="sh">'</span><span class="s">slow_sum(data)</span><span class="sh">'</span><span class="p">)</span>
</code></pre></div></div>

<p>Bu çıktı bize darboğazları gösterir. Performans analizinde önemli olan tahminle değil ölçümle hareket etmektir. Çünkü geliştiricinin iç sesi çoğu zaman dramatiktir: “Kesin şu döngü yavaş!” Profil aracı ise sakin bir şekilde “Hayır dostum, asıl sorun veritabanı çağrısında” diyebilir.</p>

<p>Birim testleri ve profil araçları birlikte kullanıldığında güvenli refactoring mümkün olur. Önce testlerle davranışı sabitlersin, sonra profille yavaş noktaları bulursun, ardından kodu iyileştirirsin. Son adımda testleri tekrar çalıştırırsın. Eğer testler yeşilse ve profil daha iyiyse, kodun hem doğru hem de daha fit hale gelmiştir.</p>

<p>Özetle, test yazmak zaman kaybı değil, gelecekteki panik anlarına yapılan yatırımdır. Profil analizi de optimizasyonu falcılıktan çıkarıp mühendisliğe dönüştürür. Koduna küçük bir laboratuvar kur: testlerle doğrula, profille ölç, sonra gönül rahatlığıyla geliştir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="unit-testing" /><category term="pytest" /><category term="profiling" /><category term="performans" /><category term="yazılım-kalitesi" /><summary type="html"><![CDATA[Kod yazmak bazen Lego yapmak gibidir: Parçalar tek tek güzel görünür ama kuleyi kaldırınca ortadan ikiye ayrılıyorsa bir yerde hata vardır. Birim testleri, bu Lego parçalarının tek başına sağlam olup olmadığını kontrol eder. Profil analizi ise aynı parçaların ne kadar hızlı, ne kadar bellekle ve hangi maliyetle çalıştığını gösterir. Yani biri doğruluk dedektifi, diğeri performans dedektifidir.]]></summary></entry><entry><title type="html">Dosya İşlemleri ve I/O Akışları: Veriyi Diskle Dans Ettirmek</title><link href="https://sonsuzus.github.io/posts/dosya-islemleri-ve-io-akislari-veriyi-diskle-dans-ettirmek/" rel="alternate" type="text/html" title="Dosya İşlemleri ve I/O Akışları: Veriyi Diskle Dans Ettirmek" /><published>2026-07-25T00:00:00+00:00</published><updated>2026-07-25T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/dosya-islemleri-ve-io-akislari-veriyi-diskle-dans-ettirmek</id><content type="html" xml:base="https://sonsuzus.github.io/posts/dosya-islemleri-ve-io-akislari-veriyi-diskle-dans-ettirmek/"><![CDATA[<p>Bir programın dış dünyayla konuşmasının en eski ama en vazgeçilmez yolu dosyalardır. Günlük tutan bir uygulama, JSON ayarı okuyan bir oyun, CSV raporu üreten bir analiz aracı ya da büyük veri parçasını satır satır işleyen bir servis… Hepsi aslında aynı soruyu sorar: Veriyi güvenli, hızlı ve anlaşılır biçimde nasıl okur/yazarım?
``
Dosya işlemlerini sadece open-read-write-close ezberi gibi görmek büyük haksızlık olur. Arka planda işletim sistemi, disk, bellek, tamponlar ve akışlar arasında minik bir lojistik şirketi çalışır. Programımız dosyanın tamamını çoğu zaman doğrudan diske gidip almaz; işletim sistemi veriyi parça parça getirir, tamponlar, gerektiğinde diske yazar. Bu yüzden I/O yani Input/Output işlemlerinde performansın anahtarı, veriyi doğru boyutta ve doğru biçimde taşımaktır.</p>

<p>Temel kavram akıştır. Akış, verinin bir kaynaktan hedefe sıralı şekilde aktığı soyut kanaldır. Dosya, terminal, ağ soketi veya bellek tamponu birer akış gibi düşünülebilir. Matematiksel olarak okuma maliyetini basitçe şöyle düşünebiliriz: $T = \frac{B}{R} + L$. Burada $B$ taşınan bayt sayısı, $R$ aktarım hızı, $L$ ise gecikmedir. Küçük küçük binlerce okuma yapmak $L$ değerini tekrar tekrar ödetir; parçalı ama dengeli okumak genelde daha verimlidir.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Ne zaman kullanılır?</th>
      <th>Avantaj</th>
      <th>Risk</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tüm dosyayı okumak</td>
      <td>Küçük metinler, ayar dosyaları</td>
      <td>Basit kod</td>
      <td>Büyük dosyada bellek şişer</td>
    </tr>
    <tr>
      <td>Satır satır okumak</td>
      <td>Log, CSV, rapor</td>
      <td>Bellek dostu</td>
      <td>Rastgele erişim zayıf</td>
    </tr>
    <tr>
      <td>Parça parça okumak</td>
      <td>Büyük ikili dosya</td>
      <td>Performans kontrolü</td>
      <td>Kod biraz uzar</td>
    </tr>
    <tr>
      <td>Yapılandırılmış okuma</td>
      <td>JSON, YAML, CSV</td>
      <td>Anlamlı veri modeli</td>
      <td>Hatalı format patlatabilir</td>
    </tr>
  </tbody>
</table>

<p>Metin dosyalarında kodlama konusu da kritik. UTF-8 bugün varsayılan kahramanımızdır; Türkçe karakterlerin bozulmaması için dosya açarken kodlamayı açıkça belirtmek iyi alışkanlıktır. İkili dosyalarda ise karakter değil bayt okuruz; resim, ses veya sıkıştırılmış dosyalar bu kategoriye girer.</p>

<p>Aşağıdaki örnek, bir JSON ayar dosyasını okumayı; dosya yoksa varsayılan içerikle oluşturmayı gösterir:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
<span class="kn">import</span> <span class="n">json</span>

<span class="n">path</span> <span class="o">=</span> <span class="nc">Path</span><span class="p">(</span><span class="sh">'</span><span class="s">ayarlar.json</span><span class="sh">'</span><span class="p">)</span>

<span class="k">try</span><span class="p">:</span>
    <span class="k">with</span> <span class="n">path</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="sh">'</span><span class="s">r</span><span class="sh">'</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">config</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
<span class="k">except</span> <span class="nb">FileNotFoundError</span><span class="p">:</span>
    <span class="n">config</span> <span class="o">=</span> <span class="p">{</span><span class="sh">'</span><span class="s">tema</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">dark</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">sayfa_boyutu</span><span class="sh">'</span><span class="p">:</span> <span class="mi">20</span><span class="p">}</span>
    <span class="k">with</span> <span class="n">path</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="sh">'</span><span class="s">w</span><span class="sh">'</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">json</span><span class="p">.</span><span class="nf">dump</span><span class="p">(</span><span class="n">config</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="n">ensure_ascii</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="n">config</span><span class="p">[</span><span class="sh">'</span><span class="s">tema</span><span class="sh">'</span><span class="p">])</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">with</code> bloğu çok önemlidir. Dosyayı açar, iş bitince otomatik kapatır. Eğer istisna oluşursa bile kaynak sızıntısı yaşanmaz. Bu fikir genelde RAII veya context management mantığıyla açıklanır: Kaynağı kim aldıysa, düzenli biçimde geri bırakmalıdır.</p>

<p>Yazma işlemlerinde bir başka hassas konu atomikliktir. Program dosyayı yazarken çökerse yarım kalmış, bozuk bir dosya bırakabilir. Daha güvenli yaklaşım önce geçici dosyaya yazmak, sonra hedef dosyayla atomik olarak değiştirmektir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
<span class="kn">import</span> <span class="n">os</span><span class="p">,</span> <span class="n">tempfile</span>

<span class="k">def</span> <span class="nf">guvenli_yaz</span><span class="p">(</span><span class="n">hedef</span><span class="p">:</span> <span class="n">Path</span><span class="p">,</span> <span class="n">veri</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
    <span class="n">klasor</span> <span class="o">=</span> <span class="n">hedef</span><span class="p">.</span><span class="n">parent</span>
    <span class="k">with</span> <span class="n">tempfile</span><span class="p">.</span><span class="nc">NamedTemporaryFile</span><span class="p">(</span><span class="sh">'</span><span class="s">w</span><span class="sh">'</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">,</span> <span class="nb">dir</span><span class="o">=</span><span class="n">klasor</span><span class="p">,</span> <span class="n">delete</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span> <span class="k">as</span> <span class="n">tmp</span><span class="p">:</span>
        <span class="n">tmp</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="n">veri</span><span class="p">)</span>
        <span class="n">tmp</span><span class="p">.</span><span class="nf">flush</span><span class="p">()</span>
        <span class="n">os</span><span class="p">.</span><span class="nf">fsync</span><span class="p">(</span><span class="n">tmp</span><span class="p">.</span><span class="nf">fileno</span><span class="p">())</span>
        <span class="n">gecici_ad</span> <span class="o">=</span> <span class="n">tmp</span><span class="p">.</span><span class="n">name</span>
    <span class="n">os</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="n">gecici_ad</span><span class="p">,</span> <span class="n">hedef</span><span class="p">)</span>

<span class="nf">guvenli_yaz</span><span class="p">(</span><span class="nc">Path</span><span class="p">(</span><span class="sh">'</span><span class="s">rapor.txt</span><span class="sh">'</span><span class="p">),</span> <span class="sh">'</span><span class="s">Merhaba dosya sistemi!</span><span class="sh">'</span><span class="p">)</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">flush()</code> veriyi kullanıcı alanı tamponundan işletim sistemine iter; <code class="language-plaintext highlighter-rouge">fsync()</code> ise diske yazılmasını daha güçlü biçimde talep eder. Her zaman gerekli değildir, çünkü pahalıdır; ama para transferi, kritik ayar veya işlem günlüğü gibi durumlarda değerlidir.</p>

<table>
  <thead>
    <tr>
      <th>İşlem</th>
      <th>Kullanım</th>
      <th>Performans notu</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">read()</code></td>
      <td>Tam içerik</td>
      <td>Küçük dosyada ideal</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">readline()</code></td>
      <td>Tek satır</td>
      <td>Etkileşimli akışlarda kullanışlı</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">for line in f</code></td>
      <td>Satır satır</td>
      <td>Log işlemede favori</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">write()</code></td>
      <td>Metin/bayt yazma</td>
      <td>Tamponlanır</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">fsync()</code></td>
      <td>Diske zorlama</td>
      <td>Güvenli ama yavaş</td>
    </tr>
  </tbody>
</table>

<p>Son olarak, dosya yolu güvenliğini unutmayın. Kullanıcıdan gelen dosya adını doğrudan birleştirmek path traversal gibi sorunlara yol açabilir. Ayrıca eşzamanlı çalışan programlarda kilitleme, izinler ve yarış koşulları düşünülmelidir. Kısacası dosya I/O, basit bir kapı kolu gibi görünür; ama arkasında bellek yönetimi, işletim sistemi çağrıları ve veri bütünlüğüyle dolu koca bir makine odası vardır. Doğru akış modelini seçerseniz, veriniz de programınız da huzurla yaşar.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="dosya-islemleri" /><category term="io-akislari" /><category term="programlama" /><summary type="html"><![CDATA[Bir programın dış dünyayla konuşmasının en eski ama en vazgeçilmez yolu dosyalardır. Günlük tutan bir uygulama, JSON ayarı okuyan bir oyun, CSV raporu üreten bir analiz aracı ya da büyük veri parçasını satır satır işleyen bir servis… Hepsi aslında aynı soruyu sorar: Veriyi güvenli, hızlı ve anlaşılır biçimde nasıl okur/yazarım?]]></summary></entry><entry><title type="html">Go ile JSON İşlemleri ve Veri Serileştirme</title><link href="https://sonsuzus.github.io/posts/go-ile-json-islemleri-ve-veri-serilestirme/" rel="alternate" type="text/html" title="Go ile JSON İşlemleri ve Veri Serileştirme" /><published>2026-07-25T00:00:00+00:00</published><updated>2026-07-25T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/go-ile-json-islemleri-ve-veri-serilestirme</id><content type="html" xml:base="https://sonsuzus.github.io/posts/go-ile-json-islemleri-ve-veri-serilestirme/"><![CDATA[<p>Modern yazılımlar artık tek başına yaşayan küçük adacıklar değil; API’ler, mikroservisler, mobil uygulamalar ve üçüncü parti sistemlerle sürekli konuşan sosyal kelebekler. Go tarafında bu sohbetin en popüler dili JSON’dır. Bir Go yapısını JSON’a çevirmek, valize kıyafet yerleştirmeye benzer: veriyi dış dünyaya taşınabilir, okunabilir ve standart bir forma sokarız. Gelen JSON’u tekrar Go struct’ına çözmek ise valizi açıp eşyaları doğru çekmecelere yerleştirmektir.
``</p>

<h2 id="json-ve-serileştirmenin-teorisi">JSON ve serileştirmenin teorisi</h2>

<p>Serileştirme, bellekte duran bir veri yapısını aktarılabilir bir biçime dönüştürme işlemidir. Go’da buna çoğunlukla <strong>marshal</strong>, tersine ise <strong>unmarshal</strong> denir. Matematiksel düşünürsek, serileştirmeyi bir dönüşüm fonksiyonu gibi görebiliriz: $f: GoStruct \rightarrow JSON$. Ters işlem ise $f^{-1}: JSON \rightarrow GoStruct$ şeklindedir. Elbette pratikte $f^{-1}$ her zaman mükemmel değildir; eksik alanlar, tip uyuşmazlıkları veya beklenmeyen değerler yüzünden hata alabiliriz.</p>

<p>JSON’un avantajı basit olmasıdır: string, number, boolean, array, object ve null. Go ise daha zengin tiplere sahiptir. Bu yüzden iki dünya arasında çeviri yaparken tip eşleşmelerini iyi bilmek gerekir.</p>

<table>
  <thead>
    <tr>
      <th>JSON Tipi</th>
      <th>Go Karşılığı</th>
      <th>Not</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>string</td>
      <td>string</td>
      <td>Tarihler genellikle string taşınır</td>
    </tr>
    <tr>
      <td>number</td>
      <td>int, float64</td>
      <td>Varsayılan interface{} çözümünde float64 olur</td>
    </tr>
    <tr>
      <td>boolean</td>
      <td>bool</td>
      <td>Doğrudan eşleşir</td>
    </tr>
    <tr>
      <td>array</td>
      <td>slice</td>
      <td>Örn: []string</td>
    </tr>
    <tr>
      <td>object</td>
      <td>struct veya map</td>
      <td>API modellerinde struct tercih edilir</td>
    </tr>
    <tr>
      <td>null</td>
      <td>pointer, sql.Null*</td>
      <td>Yokluğu temsil etmek için kullanılır</td>
    </tr>
  </tbody>
</table>

<h2 id="struct-tag-json-pasaport-kontrolü">Struct tag: JSON pasaport kontrolü</h2>

<p>Go’da alan adları dışa açılmak için büyük harfle başlamalıdır. Ancak JSON alan isimleri genellikle küçük harfli veya snake_case olur. İşte struct tag burada devreye girer.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"encoding/json"</span>
    <span class="s">"fmt"</span>
<span class="p">)</span>

<span class="k">type</span> <span class="n">User</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">ID</span>       <span class="kt">int</span>    <span class="s">`json:"id"`</span>
    <span class="n">FullName</span> <span class="kt">string</span> <span class="s">`json:"full_name"`</span>
    <span class="n">Email</span>    <span class="kt">string</span> <span class="s">`json:"email,omitempty"`</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">user</span> <span class="o">:=</span> <span class="n">User</span><span class="p">{</span><span class="n">ID</span><span class="o">:</span> <span class="m">7</span><span class="p">,</span> <span class="n">FullName</span><span class="o">:</span> <span class="s">"Ada Lovelace"</span><span class="p">}</span>

    <span class="n">data</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">json</span><span class="o">.</span><span class="n">MarshalIndent</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="s">""</span><span class="p">,</span> <span class="s">"  "</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
        <span class="nb">panic</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="kt">string</span><span class="p">(</span><span class="n">data</span><span class="p">))</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu örnekte <code class="language-plaintext highlighter-rouge">MarshalIndent</code>, JSON’u okunabilir biçimde üretir. <code class="language-plaintext highlighter-rouge">omitempty</code> ise alan boşsa JSON’a yazma anlamına gelir. Yani e-posta yoksa gereksiz bir <code class="language-plaintext highlighter-rouge">email</code> alanı gönderilmez. API tüketen sistemlerin “Bu niye boş geldi?” diye trip atmasını engeller.</p>

<h2 id="gelen-jsonu-go-yapısına-çözmek">Gelen JSON’u Go yapısına çözmek</h2>

<p>Dış sistemden veri geldiğinde <code class="language-plaintext highlighter-rouge">json.Unmarshal</code> kullanırız. Burada önemli detay, hedef değişkenin adresini vermektir; çünkü Go’nun o değişkenin içini doldurması gerekir.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"encoding/json"</span>
    <span class="s">"fmt"</span>
<span class="p">)</span>

<span class="k">type</span> <span class="n">Product</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">Code</span>  <span class="kt">string</span>  <span class="s">`json:"code"`</span>
    <span class="n">Price</span> <span class="kt">float64</span> <span class="s">`json:"price"`</span>
    <span class="n">Stock</span> <span class="kt">int</span>     <span class="s">`json:"stock"`</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">raw</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">(</span><span class="s">`{"code":"KB-42","price":129.90,"stock":15}`</span><span class="p">)</span>

    <span class="k">var</span> <span class="n">product</span> <span class="n">Product</span>
    <span class="n">err</span> <span class="o">:=</span> <span class="n">json</span><span class="o">.</span><span class="n">Unmarshal</span><span class="p">(</span><span class="n">raw</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">product</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"JSON hatası:"</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
        <span class="k">return</span>
    <span class="p">}</span>

    <span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%s ürünü %.2f TL</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">product</span><span class="o">.</span><span class="n">Code</span><span class="p">,</span> <span class="n">product</span><span class="o">.</span><span class="n">Price</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Buradaki fiyat alanı için <code class="language-plaintext highlighter-rouge">float64</code> kullandık. Para işlemlerinde kayan nokta hassasiyetine dikkat etmek gerekir. Örneğin $0.1 + 0.2 \neq 0.3$ gibi görünen sonuçlar bilgisayar temsilinden kaynaklanabilir. Finansal uygulamalarda kuruşu <code class="language-plaintext highlighter-rouge">int</code> olarak saklamak daha güvenlidir.</p>

<h2 id="struct-mı-map-mi">Struct mı map mi?</h2>

<p>Her JSON için struct yazmak zorunda değilsiniz. Dinamik veya şeması belirsiz verilerde <code class="language-plaintext highlighter-rouge">map[string]interface{}</code> kullanılabilir. Ancak bu esneklik, tip güvenliğinden ödün verir.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>struct</td>
      <td>Tip güvenli, okunabilir, IDE dostu</td>
      <td>Şema değişirse güncelleme ister</td>
    </tr>
    <tr>
      <td>map[string]interface{}</td>
      <td>Esnek, hızlı prototiplenir</td>
      <td>Tip kontrolü zahmetlidir</td>
    </tr>
    <tr>
      <td>json.RawMessage</td>
      <td>Parçalı çözümleme sağlar</td>
      <td>Daha ileri seviye yönetim ister</td>
    </tr>
  </tbody>
</table>

<h2 id="hata-yönetimi-ve-sözleşme-bilinci">Hata yönetimi ve sözleşme bilinci</h2>

<p>JSON işlemlerinde en büyük hata, “Karşı taraf doğru gönderir ya” rahatlığıdır. Göndermez. Alan eksik gelir, sayı string gelir, null gelir, hatta bazen HTML hata sayfası JSON sanılıp parse edilmeye çalışılır. Bu yüzden her <code class="language-plaintext highlighter-rouge">Marshal</code> ve <code class="language-plaintext highlighter-rouge">Unmarshal</code> çağrısında hata kontrolü yapılmalıdır.</p>

<p>Ayrıca JSON, sistemler arası bir sözleşmedir. Bu sözleşmenin maliyetini basitçe şöyle düşünebiliriz: $Toplam\ Risk = Veri\ Belirsizliği \times Entegrasyon\ Sayısı$. Entegrasyon arttıkça küçük tip hataları bile büyük problemlere dönüşür.</p>

<h2 id="sonuç">Sonuç</h2>

<p>Go’nun <code class="language-plaintext highlighter-rouge">encoding/json</code> paketi, dış sistemlerle konuşmak için sade ama güçlü bir araçtır. Struct tag’leriyle alan adlarını kontrol eder, <code class="language-plaintext highlighter-rouge">Marshal</code> ile veriyi dışarı yollar, <code class="language-plaintext highlighter-rouge">Unmarshal</code> ile gelen veriyi güvenli şekilde içeri alırız. İyi modellenmiş struct’lar, dikkatli hata yönetimi ve tip farkındalığı sayesinde JSON iletişimi kaotik bir mesajlaşma grubu olmaktan çıkar, düzenli bir protokole dönüşür.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="Go" /><category term="JSON" /><category term="Serileştirme" /><summary type="html"><![CDATA[Modern yazılımlar artık tek başına yaşayan küçük adacıklar değil; API’ler, mikroservisler, mobil uygulamalar ve üçüncü parti sistemlerle sürekli konuşan sosyal kelebekler. Go tarafında bu sohbetin en popüler dili JSON’dır. Bir Go yapısını JSON’a çevirmek, valize kıyafet yerleştirmeye benzer: veriyi dış dünyaya taşınabilir, okunabilir ve standart bir forma sokarız. Gelen JSON’u tekrar Go struct’ına çözmek ise valizi açıp eşyaları doğru çekmecelere yerleştirmektir.]]></summary></entry><entry><title type="html">Go ile Temel HTTP Web Sunucusu Geliştirme</title><link href="https://sonsuzus.github.io/posts/go-ile-temel-http-web-sunucusu-gelistirme/" rel="alternate" type="text/html" title="Go ile Temel HTTP Web Sunucusu Geliştirme" /><published>2026-07-25T00:00:00+00:00</published><updated>2026-07-25T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/go-ile-temel-http-web-sunucusu-gelistirme</id><content type="html" xml:base="https://sonsuzus.github.io/posts/go-ile-temel-http-web-sunucusu-gelistirme/"><![CDATA[<p>Go ile web sunucusu yazmak, mutfağa girip “Ben bugün internet pişireceğim” demek gibidir: az malzemeyle şaşırtıcı derecede doyurucu sonuç alırsın. Go’nun standart kütüphanesindeki <code class="language-plaintext highlighter-rouge">net/http</code> paketi, harici framework kurmadan HTTP isteklerini dinleyen, yönlendiren ve yanıtlayan sade ama güçlü bir sunucu ayağa kaldırmamızı sağlar.
``</p>

<h2 id="http-mantığını-kısaca-isıtalım">HTTP Mantığını Kısaca Isıtalım</h2>

<p>HTTP, istemci ile sunucu arasında yapılan istek-yanıt tabanlı bir protokoldür. Tarayıcı istemcidir; Go ile yazdığımız uygulama ise sunucudur. İstemci “Bana <code class="language-plaintext highlighter-rouge">/</code> adresini ver” der, sunucu da “Buyur, içerik burada” diye yanıt döner.</p>

<p>Bu model basitçe şöyle düşünülebilir:</p>

\[İstek + İşleyici = Yanıt\]

<p>Daha teknik bir bakışla yanıt süresi şu şekilde modellenebilir:</p>

\[T_{yanıt} = T_{ağ} + T_{işleme} + T_{veri}\]

<p>Yani iyi bir web sunucusu yalnızca çalışmakla kalmaz; istekleri doğru yakalar, hızlı işler ve anlaşılır yanıt üretir.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Ne İşe Yarar?</th>
      <th>Go’daki Karşılığı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Client</td>
      <td>İstek gönderen taraf</td>
      <td>Tarayıcı, Postman, curl</td>
    </tr>
    <tr>
      <td>Server</td>
      <td>İstekleri dinleyen uygulama</td>
      <td><code class="language-plaintext highlighter-rouge">http.ListenAndServe</code></td>
    </tr>
    <tr>
      <td>Route</td>
      <td>URL yoluna göre yönlendirme</td>
      <td><code class="language-plaintext highlighter-rouge">/</code>, <code class="language-plaintext highlighter-rouge">/api</code>, <code class="language-plaintext highlighter-rouge">/hello</code></td>
    </tr>
    <tr>
      <td>Handler</td>
      <td>İsteğe cevap veren fonksiyon</td>
      <td><code class="language-plaintext highlighter-rouge">http.HandleFunc</code></td>
    </tr>
    <tr>
      <td>Response</td>
      <td>İstemciye dönen çıktı</td>
      <td><code class="language-plaintext highlighter-rouge">http.ResponseWriter</code></td>
    </tr>
  </tbody>
</table>

<h2 id="i̇lk-go-http-sunucusu">İlk Go HTTP Sunucusu</h2>

<p>Aşağıdaki örnek, kök adrese gelen HTTP isteklerini karşılayan sade bir Go web sunucusudur:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"fmt"</span>
    <span class="s">"log"</span>
    <span class="s">"net/http"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">homeHandler</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Fprintln</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="s">"Merhaba! Go HTTP sunucusu çalışıyor."</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">http</span><span class="o">.</span><span class="n">HandleFunc</span><span class="p">(</span><span class="s">"/"</span><span class="p">,</span> <span class="n">homeHandler</span><span class="p">)</span>

    <span class="n">log</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Sunucu http://localhost:8080 üzerinde çalışıyor..."</span><span class="p">)</span>
    <span class="n">err</span> <span class="o">:=</span> <span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":8080"</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
        <span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu kodda <code class="language-plaintext highlighter-rouge">http.HandleFunc</code>, belirli bir URL yolunu fonksiyona bağlar. <code class="language-plaintext highlighter-rouge">/</code> yoluna istek geldiğinde <code class="language-plaintext highlighter-rouge">homeHandler</code> çalışır. <code class="language-plaintext highlighter-rouge">http.ResponseWriter</code>, istemciye yanıt yazmamızı sağlar. <code class="language-plaintext highlighter-rouge">*http.Request</code> ise gelen isteğin metodunu, başlıklarını, yolunu ve gövdesini taşır.</p>

<p>Programı çalıştırmak için:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go run main.go
</code></pre></div></div>

<p>Ardından tarayıcıda <code class="language-plaintext highlighter-rouge">http://localhost:8080</code> adresine gittiğinde mesajı görürsün. Tebrikler, artık kendi mini web sunucun var!</p>

<h2 id="i̇stek-metodunu-kontrol-etmek">İstek Metodunu Kontrol Etmek</h2>

<p>HTTP’de her istek aynı değildir. <code class="language-plaintext highlighter-rouge">GET</code> veri okumak, <code class="language-plaintext highlighter-rouge">POST</code> veri göndermek için kullanılır. Handler içinde metodu kontrol ederek daha bilinçli davranabiliriz:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">helloHandler</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="n">r</span><span class="o">.</span><span class="n">Method</span> <span class="o">!=</span> <span class="n">http</span><span class="o">.</span><span class="n">MethodGet</span> <span class="p">{</span>
        <span class="n">http</span><span class="o">.</span><span class="n">Error</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="s">"Sadece GET desteklenir"</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusMethodNotAllowed</span><span class="p">)</span>
        <span class="k">return</span>
    <span class="p">}</span>

    <span class="n">name</span> <span class="o">:=</span> <span class="n">r</span><span class="o">.</span><span class="n">URL</span><span class="o">.</span><span class="n">Query</span><span class="p">()</span><span class="o">.</span><span class="n">Get</span><span class="p">(</span><span class="s">"name"</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">name</span> <span class="o">==</span> <span class="s">""</span> <span class="p">{</span>
        <span class="n">name</span> <span class="o">=</span> <span class="s">"Gopher"</span>
    <span class="p">}</span>

    <span class="n">fmt</span><span class="o">.</span><span class="n">Fprintf</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="s">"Merhaba, %s!"</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu fonksiyon <code class="language-plaintext highlighter-rouge">/hello?name=Ayse</code> gibi bir istek aldığında kişiselleştirilmiş yanıt üretir. Boş gelirse varsayılan olarak <code class="language-plaintext highlighter-rouge">Gopher</code> der. Küçük ama üretim mantığına yakın bir davranış!</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Avantaj</th>
      <th>Ne Zaman Kullanılır?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Sadece <code class="language-plaintext highlighter-rouge">/</code> handler</td>
      <td>Çok basit ve hızlı</td>
      <td>Deneme, prototip</td>
    </tr>
    <tr>
      <td>Çoklu route</td>
      <td>Daha düzenli yapı</td>
      <td>Küçük API’ler</td>
    </tr>
    <tr>
      <td>Method kontrolü</td>
      <td>Güvenli davranış</td>
      <td>REST mantığı</td>
    </tr>
    <tr>
      <td>JSON yanıt</td>
      <td>Modern istemcilerle uyum</td>
      <td>API geliştirme</td>
    </tr>
  </tbody>
</table>

<h2 id="json-yanıt-döndürmek">JSON Yanıt Döndürmek</h2>

<p>Web sunucuları çoğu zaman HTML değil JSON döndürür. Go’da bu da standart kütüphane ile mümkündür:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">statusHandler</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">w</span><span class="o">.</span><span class="n">Header</span><span class="p">()</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"Content-Type"</span><span class="p">,</span> <span class="s">"application/json"</span><span class="p">)</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Fprintln</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="s">`{"status":"ok","message":"Sunucu ayakta"}`</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Header ayarı önemlidir; istemciye “Benim yanıtım JSON formatında” demiş oluruz. Bu küçük detay, API tüketen uygulamaların doğru davranmasını sağlar.</p>

<h2 id="sonuç">Sonuç</h2>

<p>Go ile temel HTTP sunucusu geliştirmek, web’in çalışma mantığını öğrenmek için harika bir başlangıçtır. Framework kullanmadan route, handler, request, response ve method gibi temel kavramları çıplak gözle görürsün. Bu sayede ileride Gin, Echo veya Fiber gibi framework’lere geçtiğinde arka planda neler döndüğünü çok daha iyi anlarsın. Kısacası Go’nun <code class="language-plaintext highlighter-rouge">net/http</code> paketi, küçük projeler için yeterince sade; büyük fikirler içinse yeterince güçlüdür.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="go" /><category term="http" /><category term="web-sunucusu" /><category term="standart-kutuphane" /><summary type="html"><![CDATA[Go ile web sunucusu yazmak, mutfağa girip “Ben bugün internet pişireceğim” demek gibidir: az malzemeyle şaşırtıcı derecede doyurucu sonuç alırsın. Go’nun standart kütüphanesindeki net/http paketi, harici framework kurmadan HTTP isteklerini dinleyen, yönlendiren ve yanıtlayan sade ama güçlü bir sunucu ayağa kaldırmamızı sağlar.]]></summary></entry><entry><title type="html">Kod Arkeolojisi: Terk Edilmiş Repolardan Algoritma Hazinesi Çıkarmak</title><link href="https://sonsuzus.github.io/posts/kod-arkeolojisi-terk-edilmis-repolardan-algoritma-hazinesi-cikarmak/" rel="alternate" type="text/html" title="Kod Arkeolojisi: Terk Edilmiş Repolardan Algoritma Hazinesi Çıkarmak" /><published>2026-07-25T00:00:00+00:00</published><updated>2026-07-25T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/kod-arkeolojisi-terk-edilmis-repolardan-algoritma-hazinesi-cikarmak</id><content type="html" xml:base="https://sonsuzus.github.io/posts/kod-arkeolojisi-terk-edilmis-repolardan-algoritma-hazinesi-cikarmak/"><![CDATA[<p>Terk edilmiş açık kaynak repoları, yazılım dünyasının tozlu tavan araları gibidir: kırık README’ler, çalışmayan CI rozetleri ve arada bir “Bunu kim, nasıl düşünmüş?” dedirten parlak fikirler. Kod arkeolojisi tam da burada başlar; amaç eski kodu kutsamak değil, içindeki zekice çözümü bugünün diliyle yeniden anlamaktır.
``
Bir repoya yıllardır commit gelmemiş olması, içindeki fikrin bayatladığı anlamına gelmez. Hatta bazen eski projeler, güncel framework kalabalığından uzakta, problemi çıplak haliyle çözer. Yeni kütüphaneler katman eklerken, eski kodlar çoğu zaman doğrudan algoritmanın kalbine gider. Bu yüzden kod arkeoloğunun ilk sorusu “Bu proje hâlâ çalışıyor mu?” değil, “Burada hangi problem, hangi kısıt altında çözülmüş?” olmalıdır.</p>

<p>Teorik altyapı için üç şeyi ayırmak çok işe yarar: veri yapısı, karmaşıklık ve bağlam. Bir algoritma hilesi genellikle bu üçlünün kesişiminde saklanır. Örneğin eski bir arama aracında tam metin arama yerine bit maskeleri kullanılmış olabilir. Eğer belge sayısı $n$, kelime sayısı $m$ ise klasik yaklaşımda sorgu maliyeti kabaca $O(n \cdot m)$ gibi büyürken, bit kümeleriyle kesişim almak $O(n / w)$ seviyesine iner; burada $w$ makine kelimesi genişliğidir. Yani 64 bitlik işlemcide tek hamlede 64 olasılık süzülür. Bu, küçük bir sihir değil; donanımı algoritmaya dahil etmektir.</p>

<table>
  <thead>
    <tr>
      <th>Bulgu</th>
      <th>Eski Kodda Görünümü</th>
      <th>Güncel Dille Yorumu</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Bit maskesi</td>
      <td><code class="language-plaintext highlighter-rouge">flags &amp; 8</code> gibi gizemli kontroller</td>
      <td>Bellek dostu durum modeli</td>
    </tr>
    <tr>
      <td>LRU listesi</td>
      <td>Çift bağlı liste + hash tablo</td>
      <td>$O(1)$ cache stratejisi</td>
    </tr>
    <tr>
      <td>Sentinel değer</td>
      <td><code class="language-plaintext highlighter-rouge">-1</code>, <code class="language-plaintext highlighter-rouge">NULL_NODE</code></td>
      <td>Sınır kontrolünü sadeleştirme</td>
    </tr>
    <tr>
      <td>Ön hesaplama</td>
      <td>Büyük sabit tablolar</td>
      <td>Zaman-bellek takası</td>
    </tr>
  </tbody>
</table>

<p>Arkeolojik kazıda en sevdiğim örneklerden biri, eski oyun motorlarında görülen “kirli dikdörtgen” tekniğidir. Ekranın tamamını yeniden çizmek yerine sadece değişen bölgeler işaretlenir. Bugün bunu “incremental rendering” diye daha havalı anlatıyoruz. Mantık basittir: Eğer ekran alanı $A$, değişen alan $d$ ise ve $d \ll A$ ise, çizim maliyeti dramatik biçimde düşer. Formül gibi söyleyelim: toplam iş $T \approx c \cdot d$ olur, $c \cdot A$ değil.</p>

<p>Aşağıdaki örnek, terk edilmiş bir GUI kütüphanesinde görebileceğiniz fikri modern Python ile sadeleştirir. Amaç, çakışan kirli bölgeleri birleştirip gereksiz çizimi azaltmaktır:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>

<span class="nd">@dataclass</span>
<span class="k">class</span> <span class="nc">Rect</span><span class="p">:</span>
    <span class="n">x</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">y</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">w</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">h</span><span class="p">:</span> <span class="nb">int</span>

    <span class="k">def</span> <span class="nf">overlaps</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
        <span class="k">return</span> <span class="ow">not</span> <span class="p">(</span>
            <span class="n">self</span><span class="p">.</span><span class="n">x</span> <span class="o">+</span> <span class="n">self</span><span class="p">.</span><span class="n">w</span> <span class="o">&lt;</span> <span class="n">other</span><span class="p">.</span><span class="n">x</span> <span class="ow">or</span> <span class="n">other</span><span class="p">.</span><span class="n">x</span> <span class="o">+</span> <span class="n">other</span><span class="p">.</span><span class="n">w</span> <span class="o">&lt;</span> <span class="n">self</span><span class="p">.</span><span class="n">x</span> <span class="ow">or</span>
            <span class="n">self</span><span class="p">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">self</span><span class="p">.</span><span class="n">h</span> <span class="o">&lt;</span> <span class="n">other</span><span class="p">.</span><span class="n">y</span> <span class="ow">or</span> <span class="n">other</span><span class="p">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">other</span><span class="p">.</span><span class="n">h</span> <span class="o">&lt;</span> <span class="n">self</span><span class="p">.</span><span class="n">y</span>
        <span class="p">)</span>

    <span class="k">def</span> <span class="nf">merge</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
        <span class="n">x1</span> <span class="o">=</span> <span class="nf">min</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">other</span><span class="p">.</span><span class="n">x</span><span class="p">)</span>
        <span class="n">y1</span> <span class="o">=</span> <span class="nf">min</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">y</span><span class="p">,</span> <span class="n">other</span><span class="p">.</span><span class="n">y</span><span class="p">)</span>
        <span class="n">x2</span> <span class="o">=</span> <span class="nf">max</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">x</span> <span class="o">+</span> <span class="n">self</span><span class="p">.</span><span class="n">w</span><span class="p">,</span> <span class="n">other</span><span class="p">.</span><span class="n">x</span> <span class="o">+</span> <span class="n">other</span><span class="p">.</span><span class="n">w</span><span class="p">)</span>
        <span class="n">y2</span> <span class="o">=</span> <span class="nf">max</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">self</span><span class="p">.</span><span class="n">h</span><span class="p">,</span> <span class="n">other</span><span class="p">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">other</span><span class="p">.</span><span class="n">h</span><span class="p">)</span>
        <span class="k">return</span> <span class="nc">Rect</span><span class="p">(</span><span class="n">x1</span><span class="p">,</span> <span class="n">y1</span><span class="p">,</span> <span class="n">x2</span> <span class="o">-</span> <span class="n">x1</span><span class="p">,</span> <span class="n">y2</span> <span class="o">-</span> <span class="n">y1</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">compact_dirty_regions</span><span class="p">(</span><span class="n">regions</span><span class="p">):</span>
    <span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">rect</span> <span class="ow">in</span> <span class="n">regions</span><span class="p">:</span>
        <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">old</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">result</span><span class="p">):</span>
            <span class="k">if</span> <span class="n">rect</span><span class="p">.</span><span class="nf">overlaps</span><span class="p">(</span><span class="n">old</span><span class="p">):</span>
                <span class="n">result</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">old</span><span class="p">.</span><span class="nf">merge</span><span class="p">(</span><span class="n">rect</span><span class="p">)</span>
                <span class="k">break</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">result</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">rect</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">result</span>
</code></pre></div></div>

<p>Bu kod kusursuz bir geometri motoru değildir; fakat fikri net gösterir. Eski projelerde sıkça karşılaşılan değer de budur: üretim seviyesinde paketlenmiş bir çözüm değil, doğru problemi doğru yerinden yakalayan küçük bir mekanizma.</p>

<p>Kod arkeolojisi yaparken commit geçmişi, issue tartışmaları ve test dosyaları altın değerindedir. Kod “ne” yaptığını söyler, testler “neden” yaptığını fısıldar, issue’lar ise “hangi acı yüzünden” yazıldığını bağırır. Özellikle performansla ilgili yamalarda şu izi arayın: Önce basit çözüm vardır, sonra kullanıcı şikâyeti gelir, ardından küçük ama keskin bir optimizasyon eklenir.</p>

<table>
  <thead>
    <tr>
      <th>Kazı Aracı</th>
      <th>Ne Aranır?</th>
      <th>Tehlike</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">git blame</code></td>
      <td>Kararın tarihi</td>
      <td>Kişiyi suçlama tuzağı</td>
    </tr>
    <tr>
      <td>Testler</td>
      <td>Kenar durumlar</td>
      <td>Eksik senaryo sanmak</td>
    </tr>
    <tr>
      <td>Benchmark</td>
      <td>Gerçek darboğaz</td>
      <td>Mikro optimizasyona kapılmak</td>
    </tr>
    <tr>
      <td>README</td>
      <td>Tasarım niyeti</td>
      <td>Güncel sanmak</td>
    </tr>
  </tbody>
</table>

<p>Sonuçta terk edilmiş repolar birer mezarlık değil, fikir fosili yatağıdır. Her eski hileyi bugüne taşımak gerekmez; bazıları sadece döneminin kısıtlarına uygundur. Ama iyi bir kod arkeoloğu, paslı satırların arasından şu soruyu çıkarır: “Bu çözüm hangi basit ilkeye dayanıyor?” Cevap çoğu zaman hâlâ değerlidir: daha az iş yap, veriyi doğru biçimde tut, sınır durumunu baştan tasarla ve algoritmanın matematiğini unutma.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="açık kaynak" /><category term="algoritmalar" /><category term="kod arkeolojisi" /><category term="refactoring" /><summary type="html"><![CDATA[Terk edilmiş açık kaynak repoları, yazılım dünyasının tozlu tavan araları gibidir: kırık README’ler, çalışmayan CI rozetleri ve arada bir “Bunu kim, nasıl düşünmüş?” dedirten parlak fikirler. Kod arkeolojisi tam da burada başlar; amaç eski kodu kutsamak değil, içindeki zekice çözümü bugünün diliyle yeniden anlamaktır.]]></summary></entry><entry><title type="html">Paket Yönetimi ve Go Modules: Go Projelerini Düzenli, Güvenli ve Tekrarlanabilir Tutmak</title><link href="https://sonsuzus.github.io/posts/paket-yonetimi-ve-go-modules-go-projelerini-duzenli-guvenli-ve-tekrarlanabilir-tutmak/" rel="alternate" type="text/html" title="Paket Yönetimi ve Go Modules: Go Projelerini Düzenli, Güvenli ve Tekrarlanabilir Tutmak" /><published>2026-07-25T00:00:00+00:00</published><updated>2026-07-25T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/paket-yonetimi-ve-go-modules-go-projelerini-duzenli-guvenli-ve-tekrarlanabilir-tutmak</id><content type="html" xml:base="https://sonsuzus.github.io/posts/paket-yonetimi-ve-go-modules-go-projelerini-duzenli-guvenli-ve-tekrarlanabilir-tutmak/"><![CDATA[<p>Bir Go projesi büyüdükçe kodu tek dosyada tutmak, mutfakta tüm malzemeleri aynı çekmeceye atmaya benzer: başta pratik görünür, sonra tarçınla tornavidayı karıştırırsın. Paket yönetimi ve Go Modules, kodu yeniden kullanılabilir parçalara ayırmayı, dış kütüphaneleri doğru sürümle projeye dahil etmeyi ve aynı projenin farklı makinelerde aynı şekilde çalışmasını sağlar.
``</p>

<p>Go’da temel organizasyon birimi <strong>package</strong> kavramıdır. Aynı amaca hizmet eden fonksiyonlar, tipler ve değişkenler bir paket altında toplanır. Örneğin <code class="language-plaintext highlighter-rouge">payment</code>, <code class="language-plaintext highlighter-rouge">user</code>, <code class="language-plaintext highlighter-rouge">logger</code> gibi paketler hem okunabilirliği artırır hem de kodun tekrar kullanılmasını kolaylaştırır. Daha büyük ölçekte ise <strong>module</strong>, bir veya daha fazla paketi içeren ve kökünde <code class="language-plaintext highlighter-rouge">go.mod</code> dosyası bulunan sürümlenebilir proje birimidir.</p>

<p>Teorik olarak şöyle düşünebiliriz: Paket, kodun mantıksal bölmesidir; modül ise bu bölmelerin sürüm ve bağımlılık kimliğidir. Eğer projenin bağımlılık kümesini $D$ ve her bağımlılığın seçilen sürümünü $v_i$ olarak düşünürsek, modülün derlenebilir durumu kabaca şöyle ifade edilebilir: $M = {(d_i, v_i) \mid d_i \in D}$. Yani sadece hangi kütüphaneyi kullandığın değil, <strong>hangi sürümünü</strong> kullandığın da önemlidir.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Ne işe yarar?</th>
      <th>Örnek</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Package</td>
      <td>Kodları mantıksal gruplara ayırır</td>
      <td><code class="language-plaintext highlighter-rouge">package auth</code></td>
    </tr>
    <tr>
      <td>Module</td>
      <td>Projenin bağımlılık ve sürüm sınırını belirler</td>
      <td><code class="language-plaintext highlighter-rouge">module github.com/ali/app</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">go.mod</code></td>
      <td>Gerekli modülleri ve Go sürümünü tutar</td>
      <td><code class="language-plaintext highlighter-rouge">require</code> satırları</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">go.sum</code></td>
      <td>İndirilen bağımlılıkların doğrulama izlerini saklar</td>
      <td>checksum kayıtları</td>
    </tr>
  </tbody>
</table>

<p>Yeni bir Go modülü başlatmak için genellikle şu komut kullanılır:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go mod init github.com/kullanici/proje
</code></pre></div></div>

<p>Bu komut projenin kökünde <code class="language-plaintext highlighter-rouge">go.mod</code> dosyası üretir. Basit bir <code class="language-plaintext highlighter-rouge">go.mod</code> şöyle görünebilir:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">module</span> <span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">kullanici</span><span class="o">/</span><span class="n">proje</span>

<span class="k">go</span> <span class="m">1.22</span>

<span class="n">require</span> <span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">google</span><span class="o">/</span><span class="n">uuid</span> <span class="n">v1</span><span class="m">.6.0</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">module</code> satırı projenin kimliğini, <code class="language-plaintext highlighter-rouge">go</code> satırı hedef Go sürümünü, <code class="language-plaintext highlighter-rouge">require</code> satırı ise dış bağımlılığı belirtir. <code class="language-plaintext highlighter-rouge">github.com/google/uuid v1.6.0</code> ifadesi, projede UUID üretmek için kullanılan paketin belirli bir sürümünü kilitler. Böylece bugün çalışan kodun yarın gizemli biçimde bozulma ihtimali azalır.</p>

<p>Go’da paketleri kullanmak oldukça doğaldır. Diyelim ki <code class="language-plaintext highlighter-rouge">internal/logger</code> adlı bir paket yazdık:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">logger</span>

<span class="k">import</span> <span class="s">"fmt"</span>

<span class="k">func</span> <span class="n">Info</span><span class="p">(</span><span class="n">message</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"[INFO] "</span> <span class="o">+</span> <span class="n">message</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Ana uygulamada bu paketi şöyle çağırabiliriz:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="s">"github.com/kullanici/proje/internal/logger"</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">logger</span><span class="o">.</span><span class="n">Info</span><span class="p">(</span><span class="s">"Uygulama başladı"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Buradaki <code class="language-plaintext highlighter-rouge">internal</code> klasörü özel bir anlama sahiptir: Go, bu klasör altındaki paketlerin yalnızca ilgili modül içinde kullanılmasına izin verir. Bu da mimari sınırları korumak için harika bir yöntemdir. Kısacası <code class="language-plaintext highlighter-rouge">internal</code>, paketin kapısına asılmış nazik ama kararlı bir “personel harici giremez” tabelasıdır.</p>

<p>Sürümleme tarafında Go Modules, semantik sürümleme yaklaşımını destekler. Genel biçim $MAJOR.MINOR.PATCH$ şeklindedir. Örneğin <code class="language-plaintext highlighter-rouge">v1.6.0</code> için $MAJOR=1$, $MINOR=6$, $PATCH=0$ olur.</p>

<table>
  <thead>
    <tr>
      <th>Değişim türü</th>
      <th>Anlamı</th>
      <th>Örnek</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>PATCH</td>
      <td>Hata düzeltmesi, API bozulmaz</td>
      <td><code class="language-plaintext highlighter-rouge">v1.6.0</code> → <code class="language-plaintext highlighter-rouge">v1.6.1</code></td>
    </tr>
    <tr>
      <td>MINOR</td>
      <td>Yeni özellik, geriye uyumlu</td>
      <td><code class="language-plaintext highlighter-rouge">v1.6.0</code> → <code class="language-plaintext highlighter-rouge">v1.7.0</code></td>
    </tr>
    <tr>
      <td>MAJOR</td>
      <td>Kırıcı değişiklik olabilir</td>
      <td><code class="language-plaintext highlighter-rouge">v1.6.0</code> → <code class="language-plaintext highlighter-rouge">v2.0.0</code></td>
    </tr>
  </tbody>
</table>

<p>Bağımlılık eklemek için çoğu zaman ayrıca dosya düzenlemeye gerek yoktur. Şu komut yeterlidir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go get github.com/google/uuid@v1.6.0
</code></pre></div></div>

<p>Ardından kullanılmayan bağımlılıkları temizlemek ve eksikleri tamamlamak için şu komut çalıştırılır:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go mod tidy
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">go mod tidy</code>, projenin oda toparlayan robot süpürgesi gibidir: gereksizleri kaldırır, eksikleri yerine koyar. CI/CD süreçlerinde de bu dosyaların tutarlı olması önemlidir. <code class="language-plaintext highlighter-rouge">go.mod</code> ve <code class="language-plaintext highlighter-rouge">go.sum</code> dosyaları mutlaka sürüm kontrolüne eklenmelidir; çünkü ekip arkadaşlarının ve sunucuların aynı bağımlılık ağacını kurmasını sağlar.</p>

<p>Sonuç olarak Go Modules, sadece “kütüphane indirme aracı” değildir. Kodun sınırlarını çizen, bağımlılıkları matematiksel bir kesinlikle sürümlere bağlayan ve projeyi taşınabilir hale getiren bir sistemdir. Paketler kodu okunabilir kılar, modüller ise projeyi güvenilir yapar. İyi organize edilmiş bir Go projesinde her paket kendi işini bilir, her bağımlılığın sürümü bellidir ve geliştirici de hata ayıklamak yerine keyifle üretmeye odaklanır.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="Go" /><category term="Go Modules" /><category term="Paket Yönetimi" /><category term="Bağımlılık Yönetimi" /><summary type="html"><![CDATA[Bir Go projesi büyüdükçe kodu tek dosyada tutmak, mutfakta tüm malzemeleri aynı çekmeceye atmaya benzer: başta pratik görünür, sonra tarçınla tornavidayı karıştırırsın. Paket yönetimi ve Go Modules, kodu yeniden kullanılabilir parçalara ayırmayı, dış kütüphaneleri doğru sürümle projeye dahil etmeyi ve aynı projenin farklı makinelerde aynı şekilde çalışmasını sağlar.]]></summary></entry><entry><title type="html">Rastgele Sayı Üretmenin Felsefesi: Determinist Bir Evrende Gerçekten Rastgele Var mı?</title><link href="https://sonsuzus.github.io/posts/rastgele-sayi-uretmenin-felsefesi-determinist-bir-evrende-gercekten-rastgele-var-mi/" rel="alternate" type="text/html" title="Rastgele Sayı Üretmenin Felsefesi: Determinist Bir Evrende Gerçekten Rastgele Var mı?" /><published>2026-07-25T00:00:00+00:00</published><updated>2026-07-25T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/rastgele-sayi-uretmenin-felsefesi-determinist-bir-evrende-gercekten-rastgele-var-mi</id><content type="html" xml:base="https://sonsuzus.github.io/posts/rastgele-sayi-uretmenin-felsefesi-determinist-bir-evrende-gercekten-rastgele-var-mi/"><![CDATA[<p>Bilgisayarların zar atabildiğini düşünmek tatlı bir yanılsamadır; çünkü işlemcinin içinde minik bir kumarbaz yoktur. Bir programın ürettiği sayı çoğu zaman, sadece iyi gizlenmiş bir düzenin sonucudur. İşte bu yüzden rastgele sayı üretimi, hem yazılım mühendisliğinin pratik bir konusu hem de ‘evren gerçekten öngörülebilir mi?’ sorusuna açılan küçük ama derin bir kapıdır.
``</p>

<h2 id="rastgelelik-ne-demek">Rastgelelik Ne Demek?</h2>

<p>Gündelik hayatta rastgelelik, sonucu önceden bilememek demektir. Ancak bilgisayar biliminde bu tanım yetmez. Bir sayı dizisinin rastgele görünmesi, onun gerçekten nedensiz olduğu anlamına gelmez. Determinist bir sistemde aynı başlangıç koşulları aynı sonucu üretir. Yani bir algoritmaya aynı tohumu, yani seed değerini verirseniz, aynı sayı dizisini tekrar alırsınız.</p>

<p>Matematiksel olarak birçok sözde rastgele sayı üreteci şu fikre dayanır:</p>

<p>$X_{n+1} = (aX_n + c) \bmod m$</p>

<p>Bu formül, Linear Congruential Generator yani LCG adı verilen klasik yöntemin kalbidir. Burada $X_n$ mevcut durum, $a$ çarpan, $c$ artış ve $m$ mod değeridir. Sonuçta kaotik görünen ama tamamen hesaplanabilir bir dizi oluşur.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Gerçek Rastgelelik</th>
      <th>Sözde Rastgelelik</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kaynak</td>
      <td>Fiziksel olaylar</td>
      <td>Algoritma</td>
    </tr>
    <tr>
      <td>Tekrar üretilebilir mi?</td>
      <td>Genelde hayır</td>
      <td>Evet, aynı seed ile</td>
    </tr>
    <tr>
      <td>Hız</td>
      <td>Daha yavaş olabilir</td>
      <td>Çok hızlıdır</td>
    </tr>
    <tr>
      <td>Kullanım</td>
      <td>Kriptografi, güvenlik</td>
      <td>Simülasyon, oyun, test</td>
    </tr>
    <tr>
      <td>Felsefi tat</td>
      <td>Evrenin cilvesi</td>
      <td>Determinizmin makyajı</td>
    </tr>
  </tbody>
</table>

<h2 id="seed-kaderin-küçük-başlangıç-noktası">Seed: Kaderin Küçük Başlangıç Noktası</h2>

<p>Seed, algoritmanın başlangıç koşuludur. Determinist felsefede evrenin tüm anları, ilk koşullardan zorunlu olarak çıkıyorsa; PRNG de bunun cep boy versiyonudur. Seed değerini bilirseniz geleceği bilirsiniz. Bu, Laplace’ın şeytanı fikrine benzer: Evrenin tüm parçacıklarının konumunu ve hızını bilen bir zihin, geçmişi ve geleceği hesaplayabilir miydi?</p>

<p>Basit bir PRNG örneği görelim:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">LCG</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">seed</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">state</span> <span class="o">=</span> <span class="n">seed</span>
        <span class="n">self</span><span class="p">.</span><span class="n">a</span> <span class="o">=</span> <span class="mi">1664525</span>
        <span class="n">self</span><span class="p">.</span><span class="n">c</span> <span class="o">=</span> <span class="mi">1013904223</span>
        <span class="n">self</span><span class="p">.</span><span class="n">m</span> <span class="o">=</span> <span class="mi">2</span><span class="o">**</span><span class="mi">32</span>

    <span class="k">def</span> <span class="nf">next_int</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">state</span> <span class="o">=</span> <span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">a</span> <span class="o">*</span> <span class="n">self</span><span class="p">.</span><span class="n">state</span> <span class="o">+</span> <span class="n">self</span><span class="p">.</span><span class="n">c</span><span class="p">)</span> <span class="o">%</span> <span class="n">self</span><span class="p">.</span><span class="n">m</span>
        <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">state</span>

    <span class="k">def</span> <span class="nf">random</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="nf">next_int</span><span class="p">()</span> <span class="o">/</span> <span class="n">self</span><span class="p">.</span><span class="n">m</span>

<span class="n">rng</span> <span class="o">=</span> <span class="nc">LCG</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
<span class="n">numbers</span> <span class="o">=</span> <span class="p">[</span><span class="n">rng</span><span class="p">.</span><span class="nf">random</span><span class="p">()</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">5</span><span class="p">)]</span>
</code></pre></div></div>

<p>Bu kodda <code class="language-plaintext highlighter-rouge">random()</code> metodu 0 ile 1 arasında sayı üretir. Fakat sihir yoktur; her şey <code class="language-plaintext highlighter-rouge">state</code> değişkeninin dönüşümünden ibarettir. <code class="language-plaintext highlighter-rouge">42</code> seed değeriyle çalıştırırsanız, diziniz her seferinde aynı olur. Yani bilgisayar ‘şaşırmaz’, sadece bizi şaşırtır.</p>

<h2 id="entropi-bilgisayarın-kaos-arayışı">Entropi: Bilgisayarın Kaos Arayışı</h2>

<p>Gerçek rastgeleliğe yaklaşmak için işletim sistemleri fare hareketleri, klavye zamanlamaları, disk erişim gecikmeleri veya donanımsal gürültüler gibi kaynaklardan entropi toplar. Entropi, kabaca belirsizlik miktarıdır. Bilgi kuramında şu şekilde ifade edilir:</p>

<p>$H(X)=-\sum p(x)\log_2 p(x)$</p>

<p>Bir olay ne kadar öngörülemezse entropisi o kadar yüksektir. Adil bir yazı-tura atışında iki sonuç da eşit olasılıklıdır ve belirsizlik maksimumdur. Ama hileli bir paranın sonucu daha tahmin edilebilirdir; entropisi düşer.</p>

<table>
  <thead>
    <tr>
      <th>Kullanım Senaryosu</th>
      <th>Hangi Rastgelelik Yeterli?</th>
      <th>Neden?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Oyunlarda loot düşürme</td>
      <td>PRNG</td>
      <td>Hızlı ve kontrol edilebilir</td>
    </tr>
    <tr>
      <td>Bilimsel simülasyon</td>
      <td>Kaliteli PRNG</td>
      <td>Tekrar edilebilir deney gerekir</td>
    </tr>
    <tr>
      <td>Şifreleme anahtarı</td>
      <td>Kriptografik RNG</td>
      <td>Tahmin edilemezlik şarttır</td>
    </tr>
    <tr>
      <td>Sanatsal üretim</td>
      <td>PRNG veya fiziksel RNG</td>
      <td>Estetik amaç baskındır</td>
    </tr>
  </tbody>
</table>

<h2 id="metafizik-soru-rastgelelik-cehalet-mi-gerçek-mi">Metafizik Soru: Rastgelelik Cehalet mi, Gerçek mi?</h2>

<p>Eğer evren tamamen deterministse, rastgelelik sadece bizim bilgisizliğimiz olabilir. Zarın sonucu, hava direnci, atış açısı, yüzey sürtünmesi ve kuvvet bilinse hesaplanabilir. Bu bakışa göre rastgelelik epistemiktir: Bilginin eksikliğinden doğar.</p>

<p>Ama kuantum mekaniği sahneye çıkınca işler karışır. Bazı yorumlara göre parçacıkların davranışı temelde olasılıksaldır. Bu durumda rastgelelik ontolojik olabilir: Yani sadece bilmiyoruz değil, gerçekten belirlenmemiştir. Bilgisayarlar bu tartışmayı çözmez; sadece onu kod yazarken masamıza getirir.</p>

<h2 id="sonuç-rastgelelik-bir-araç-bir-ayna-ve-bir-şaka">Sonuç: Rastgelelik Bir Araç, Bir Ayna ve Bir Şaka</h2>

<p>Programcı için rastgele sayı üretimi, test verisi hazırlamak, oyun tasarlamak, simülasyon yapmak ve güvenlik sağlamak için vazgeçilmezdir. Filozof içinse aynı konu, özgür irade ve determinizm tartışmasının dijital bir modelidir. Bilgisayarların ürettiği çoğu rastgelelik aslında sözde rastgeleliktir; ama yeterince iyi tasarlandığında pratikte harika çalışır.</p>

<p>Belki de en güzel cevap şudur: Bilgisayar rastgeleliği üretmez, rastgelelik hissini mühendislik eder. Ve bazen, yazılım dünyasında ihtiyacımız olan şey tam olarak budur.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="rastgelelik" /><category term="algoritmalar" /><category term="felsefe" /><category term="kriptografi" /><summary type="html"><![CDATA[Bilgisayarların zar atabildiğini düşünmek tatlı bir yanılsamadır; çünkü işlemcinin içinde minik bir kumarbaz yoktur. Bir programın ürettiği sayı çoğu zaman, sadece iyi gizlenmiş bir düzenin sonucudur. İşte bu yüzden rastgele sayı üretimi, hem yazılım mühendisliğinin pratik bir konusu hem de ‘evren gerçekten öngörülebilir mi?’ sorusuna açılan küçük ama derin bir kapıdır.]]></summary></entry><entry><title type="html">Select İfadesi ile Çoklu Kanal Yönetimi</title><link href="https://sonsuzus.github.io/posts/select-ifadesi-ile-coklu-kanal-yonetimi/" rel="alternate" type="text/html" title="Select İfadesi ile Çoklu Kanal Yönetimi" /><published>2026-07-25T00:00:00+00:00</published><updated>2026-07-25T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/select-ifadesi-ile-coklu-kanal-yonetimi</id><content type="html" xml:base="https://sonsuzus.github.io/posts/select-ifadesi-ile-coklu-kanal-yonetimi/"><![CDATA[<p>Modern yazılımlarda işler sırayla değil, çoğu zaman aynı anda olur: kullanıcıdan mesaj gelir, ağdan cevap döner, zamanlayıcı tetiklenir, iptal sinyali ulaşır. Go dilindeki <code class="language-plaintext highlighter-rouge">select</code> ifadesi tam bu karmaşada trafik polisi gibi davranır; birden fazla kanalı aynı anda dinler ve hangi kanal hazırsa onu bloklanmadan işleme alır.
``
<code class="language-plaintext highlighter-rouge">select</code>, Go’nun eşzamanlılık modelindeki en güçlü kontrol yapılarından biridir. Normal bir kanal okuması, veri gelene kadar goroutine’i bekletir. Örneğin <code class="language-plaintext highlighter-rouge">&lt;-ch</code> dediğinizde kanal boşsa kod orada durur. Fakat gerçek hayatta çoğu zaman tek bir kanalı değil, birçok olasılığı bekleriz. İşte <code class="language-plaintext highlighter-rouge">select</code>, bu olasılıkları <code class="language-plaintext highlighter-rouge">case</code> blokları halinde tanımlar ve hazır olan ilk iletişim yolunu çalıştırır.</p>

<p>Teorik olarak <code class="language-plaintext highlighter-rouge">select</code> ifadesini olay tabanlı bir karar mekanizması gibi düşünebiliriz. Elimizde $n$ adet kanal olsun: $C_1, C_2, …, C_n$. Her kanalın veri üretme zamanı farklıdır. Programın tepki süresi kabaca şu şekilde modellenebilir:</p>

\[T_{tepki} = \min(T_{C_1}, T_{C_2}, ..., T_{C_n})\]

<p>Yani en erken hazır olan kanal, akışı belirler. Bu sayede yavaş bir işlem, hızlı gelen başka bir sinyali engellemez. Özellikle ağ programlama, worker pool, timeout yönetimi ve iptal edilebilir işlemlerde bu yaklaşım hayat kurtarır.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Davranış</th>
      <th>Risk</th>
      <th>Kullanım Alanı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tek kanal okuma</td>
      <td>Sadece bir kanalı bekler</td>
      <td>Bloklanma</td>
      <td>Basit veri akışı</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">select</code></td>
      <td>Birden çok kanalı dinler</td>
      <td>Yanlış tasarımda karmaşa</td>
      <td>Eşzamanlı sistemler</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">select + default</code></td>
      <td>Hazır kanal yoksa beklemez</td>
      <td>CPU’yu yorabilir</td>
      <td>Non-blocking kontrol</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">select + timeout</code></td>
      <td>Belirli süre sonra vazgeçer</td>
      <td>Süre yanlış seçilebilir</td>
      <td>API, ağ istekleri</td>
    </tr>
  </tbody>
</table>

<p>Basit bir örnekle başlayalım. Aşağıdaki kodda iki farklı kanal farklı sürelerde veri üretir. <code class="language-plaintext highlighter-rouge">select</code>, hangisi önce hazır olursa onu işler:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"fmt"</span>
    <span class="s">"time"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">fast</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">string</span><span class="p">)</span>
    <span class="n">slow</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="kt">string</span><span class="p">)</span>

    <span class="k">go</span> <span class="k">func</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">time</span><span class="o">.</span><span class="n">Sleep</span><span class="p">(</span><span class="m">1</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">)</span>
        <span class="n">fast</span> <span class="o">&lt;-</span> <span class="s">"hızlı kanaldan veri geldi"</span>
    <span class="p">}()</span>

    <span class="k">go</span> <span class="k">func</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">time</span><span class="o">.</span><span class="n">Sleep</span><span class="p">(</span><span class="m">3</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">)</span>
        <span class="n">slow</span> <span class="o">&lt;-</span> <span class="s">"yavaş kanaldan veri geldi"</span>
    <span class="p">}()</span>

    <span class="k">select</span> <span class="p">{</span>
    <span class="k">case</span> <span class="n">msg</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">fast</span><span class="o">:</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
    <span class="k">case</span> <span class="n">msg</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">slow</span><span class="o">:</span>
        <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu örnekte program büyük olasılıkla <code class="language-plaintext highlighter-rouge">fast</code> kanalındaki mesajı basar. Çünkü <code class="language-plaintext highlighter-rouge">fast</code> kanalı 1 saniyede hazır olurken <code class="language-plaintext highlighter-rouge">slow</code> 3 saniye bekler. Buradaki kritik nokta şudur: <code class="language-plaintext highlighter-rouge">select</code>, kodu sırayla yukarıdan aşağıya denemez; hazır olan <code class="language-plaintext highlighter-rouge">case</code> çalışır. Birden fazla kanal aynı anda hazırsa Go çalışma zamanı bunlardan birini sözde rastgele seçer. Bu özellik, bazı kanalların sürekli öncelik kazanmasını engellemeye yardımcı olur.</p>

<p><code class="language-plaintext highlighter-rouge">select</code> ifadesi timeout ile birleştiğinde daha da kullanışlı hale gelir. Diyelim ki bir servisten cevap bekliyorsunuz ama sonsuza kadar beklemek istemiyorsunuz:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">select</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">result</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">responseCh</span><span class="o">:</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Cevap alındı:"</span><span class="p">,</span> <span class="n">result</span><span class="p">)</span>
<span class="k">case</span> <span class="o">&lt;-</span><span class="n">time</span><span class="o">.</span><span class="n">After</span><span class="p">(</span><span class="m">2</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Second</span><span class="p">)</span><span class="o">:</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"İstek zaman aşımına uğradı"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">time.After</code>, belirtilen süre sonunda veri gönderen özel bir kanal döndürür. Eğer <code class="language-plaintext highlighter-rouge">responseCh</code> iki saniye içinde cevap vermezse timeout bloğu çalışır. Böylece uygulama takılı kalmaz, kullanıcıya veya üst sisteme kontrollü bir sonuç döner.</p>

<p>Bazen de hiç beklemek istemeyiz. Bunun için <code class="language-plaintext highlighter-rouge">default</code> kullanılır:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">select</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">job</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">jobs</span><span class="o">:</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"İş alındı:"</span><span class="p">,</span> <span class="n">job</span><span class="p">)</span>
<span class="k">default</span><span class="o">:</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Şu an hazır iş yok, başka göreve geçiliyor"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">default</code>, hazır kanal yoksa hemen çalışır. Ancak dikkat: Bu yapı döngü içinde kontrolsüz kullanılırsa sürekli dönerek CPU tüketebilir. Genellikle kısa beklemeler, <code class="language-plaintext highlighter-rouge">time.Sleep</code> veya daha iyi bir olay tasarımıyla desteklenmelidir.</p>

<table>
  <thead>
    <tr>
      <th>Senaryo</th>
      <th>Önerilen Kalıp</th>
      <th>Neden?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kullanıcı iptali</td>
      <td><code class="language-plaintext highlighter-rouge">select</code> + <code class="language-plaintext highlighter-rouge">context.Done()</code></td>
      <td>Temiz durdurma sağlar</td>
    </tr>
    <tr>
      <td>Ağ cevabı bekleme</td>
      <td><code class="language-plaintext highlighter-rouge">select</code> + <code class="language-plaintext highlighter-rouge">time.After</code></td>
      <td>Sonsuz beklemeyi önler</td>
    </tr>
    <tr>
      <td>Worker yönetimi</td>
      <td><code class="language-plaintext highlighter-rouge">select</code> + iş kanalları</td>
      <td>Dinamik görev dağıtır</td>
    </tr>
    <tr>
      <td>Anlık kontrol</td>
      <td><code class="language-plaintext highlighter-rouge">select</code> + <code class="language-plaintext highlighter-rouge">default</code></td>
      <td>Bloklanmadan ilerler</td>
    </tr>
  </tbody>
</table>

<p>Özetle <code class="language-plaintext highlighter-rouge">select</code>, Go’da çoklu kanal yönetiminin kalbidir. Onu sadece bir <code class="language-plaintext highlighter-rouge">switch</code> benzeri yapı olarak görmek eksik olur; aslında zaman, veri ve iptal sinyalleri arasında akıllı bir koordinasyon sağlar. Doğru kullanıldığında sisteminiz daha tepkisel, daha güvenli ve daha ölçeklenebilir hale gelir. Kısacası goroutine’ler orkestraysa, <code class="language-plaintext highlighter-rouge">select</code> elindeki bagetle tüm ritmi yöneten şeftir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="Go" /><category term="Concurrency" /><category term="Channel" /><category term="Select" /><summary type="html"><![CDATA[Modern yazılımlarda işler sırayla değil, çoğu zaman aynı anda olur: kullanıcıdan mesaj gelir, ağdan cevap döner, zamanlayıcı tetiklenir, iptal sinyali ulaşır. Go dilindeki select ifadesi tam bu karmaşada trafik polisi gibi davranır; birden fazla kanalı aynı anda dinler ve hangi kanal hazırsa onu bloklanmadan işleme alır.]]></summary></entry><entry><title type="html">Arayüzler ve Çok Biçimlilik: Kim Olduğun Değil, Ne Yapabildiğin Önemli</title><link href="https://sonsuzus.github.io/posts/arayuzler-ve-cok-bicimlilik-kim-oldugun-degil-ne-yapabildigin-onemli/" rel="alternate" type="text/html" title="Arayüzler ve Çok Biçimlilik: Kim Olduğun Değil, Ne Yapabildiğin Önemli" /><published>2026-07-24T00:00:00+00:00</published><updated>2026-07-24T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/arayuzler-ve-cok-bicimlilik-kim-oldugun-degil-ne-yapabildigin-onemli</id><content type="html" xml:base="https://sonsuzus.github.io/posts/arayuzler-ve-cok-bicimlilik-kim-oldugun-degil-ne-yapabildigin-onemli/"><![CDATA[<p>Yazılım dünyasında bazen nesnelere fazla kimlik sorarız: “Sen gerçekten User mısın, Admin misin, Robot musun?” Oysa esnek tasarımın daha havalı sorusu şudur: “Ne yapabiliyorsun?” Arayüzler, tam da bu bakış açısını kodun merkezine koyar. Bir nesnenin sınıf soy ağacına değil, sunduğu davranış sözleşmesine odaklanır. Böylece kodumuz daha az dedikoducu, daha çok iş bitirici olur.
``</p>

<p>Arayüzü teorik olarak bir <strong>sözleşme</strong> gibi düşünebiliriz. Bir arayüz, “Beni uygulayan her yapı şu metotları, özellikleri veya davranışları sağlayacak” der. Ancak bunu nasıl yapacağını söylemez. Matematiksel olarak bir arayüzü, nesneler kümesinden davranışlar kümesine kurulan bir beklenti ilişkisi gibi görebiliriz: $I = {b_1, b_2, b_3}$ ise, bu arayüzü uygulayan her nesne bu davranışları sağlamalıdır. Burada önemli olan nesnenin iç yapısı değil, dışarıdan gözlemlenebilen davranışıdır.</p>

<p>Çok biçimlilik yani polymorphism ise aynı mesajın farklı nesnelerde farklı şekillerde çalışabilmesidir. Örneğin <code class="language-plaintext highlighter-rouge">draw()</code> çağrısı bir daireyi yuvarlak, bir kareyi köşeli çizer. Çağıran kod için önemli olan şeklin gerçek sınıfı değil, çizilebilir olmasıdır. Bu yaklaşım $Kod -&gt; Arayüz$ bağımlılığını güçlendirir, $Kod -&gt; SomutSınıf$ bağımlılığını azaltır.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Soru</th>
      <th>Sonuç</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Sınıfa odaklanmak</td>
      <td>“Bu nesne hangi tür?”</td>
      <td>Daha sıkı bağımlılık</td>
    </tr>
    <tr>
      <td>Arayüze odaklanmak</td>
      <td>“Bu nesne ne yapabilir?”</td>
      <td>Daha esnek tasarım</td>
    </tr>
    <tr>
      <td>Kalıtım merkezli tasarım</td>
      <td>“Kimden türedi?”</td>
      <td>Hiyerarşi baskısı</td>
    </tr>
    <tr>
      <td>Davranış merkezli tasarım</td>
      <td>“Hangi sözleşmeyi sağlar?”</td>
      <td>Değişime açıklık</td>
    </tr>
  </tbody>
</table>

<p>Basit bir TypeScript örneği düşünelim:</p>

<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">interface</span> <span class="nx">Payable</span> <span class="p">{</span>
  <span class="nf">calculatePayment</span><span class="p">():</span> <span class="kr">number</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">class</span> <span class="nc">Employee</span> <span class="k">implements</span> <span class="nx">Payable</span> <span class="p">{</span>
  <span class="nf">constructor</span><span class="p">(</span><span class="k">private</span> <span class="nx">salary</span><span class="p">:</span> <span class="kr">number</span><span class="p">)</span> <span class="p">{}</span>

  <span class="nf">calculatePayment</span><span class="p">():</span> <span class="kr">number</span> <span class="p">{</span>
    <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">salary</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="kd">class</span> <span class="nc">Freelancer</span> <span class="k">implements</span> <span class="nx">Payable</span> <span class="p">{</span>
  <span class="nf">constructor</span><span class="p">(</span><span class="k">private</span> <span class="nx">hourlyRate</span><span class="p">:</span> <span class="kr">number</span><span class="p">,</span> <span class="k">private</span> <span class="nx">hours</span><span class="p">:</span> <span class="kr">number</span><span class="p">)</span> <span class="p">{}</span>

  <span class="nf">calculatePayment</span><span class="p">():</span> <span class="kr">number</span> <span class="p">{</span>
    <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">hourlyRate</span> <span class="o">*</span> <span class="k">this</span><span class="p">.</span><span class="nx">hours</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nf">printPayment</span><span class="p">(</span><span class="nx">entity</span><span class="p">:</span> <span class="nx">Payable</span><span class="p">):</span> <span class="k">void</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Ödeme: </span><span class="dl">'</span> <span class="o">+</span> <span class="nx">entity</span><span class="p">.</span><span class="nf">calculatePayment</span><span class="p">());</span>
<span class="p">}</span>

<span class="nf">printPayment</span><span class="p">(</span><span class="k">new</span> <span class="nc">Employee</span><span class="p">(</span><span class="mi">40000</span><span class="p">));</span>
<span class="nf">printPayment</span><span class="p">(</span><span class="k">new</span> <span class="nc">Freelancer</span><span class="p">(</span><span class="mi">750</span><span class="p">,</span> <span class="mi">32</span><span class="p">));</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">printPayment</code> fonksiyonu, parametrenin <code class="language-plaintext highlighter-rouge">Employee</code> ya da <code class="language-plaintext highlighter-rouge">Freelancer</code> olmasını umursamaz. Tek şartı vardır: <code class="language-plaintext highlighter-rouge">Payable</code> davranışını sağlaması. Bu fonksiyonun zihni oldukça rahattır; CV sormaz, sadece ödeme hesaplayabiliyor musun diye bakar.</p>

<p>Bu tasarımın gücü, <strong>Açık/Kapalı Prensibi</strong> ile birleştiğinde ortaya çıkar. Yazılım birimleri genişletmeye açık, değiştirmeye kapalı olmalıdır. Yeni bir <code class="language-plaintext highlighter-rouge">Consultant</code> sınıfı eklediğimizde <code class="language-plaintext highlighter-rouge">printPayment</code> fonksiyonunu değiştirmiyorsak doğru yoldayız demektir. Teorik olarak bu, sistemin yeni türler karşısında kararlı kalmasıdır: $YeniTip + EskiArayüz = DahaAzKırılma$.</p>

<table>
  <thead>
    <tr>
      <th>Tasarım ilkesi</th>
      <th>Arayüzle ilişkisi</th>
      <th>Pratik fayda</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Dependency Inversion</td>
      <td>Üst seviye modüller somuta değil soyuta bağlıdır</td>
      <td>Test edilebilirlik artar</td>
    </tr>
    <tr>
      <td>Open/Closed</td>
      <td>Yeni davranışlar mevcut kodu bozmadan eklenir</td>
      <td>Bakım kolaylaşır</td>
    </tr>
    <tr>
      <td>Liskov Substitution</td>
      <td>Arayüzü uygulayan nesne beklenen davranışı bozmaz</td>
      <td>Güvenilir polymorphism</td>
    </tr>
    <tr>
      <td>Interface Segregation</td>
      <td>Büyük arayüzler küçük parçalara ayrılır</td>
      <td>Gereksiz bağımlılık azalır</td>
    </tr>
  </tbody>
</table>

<p>Ancak arayüz kullanmak her derde deva büyülü bir iksir değildir. Gereksiz arayüzler, projede “soyutlama sisi” oluşturabilir. Eğer sadece tek bir sınıfınız varsa ve değişim ihtimali düşükse, hemen arayüz üretmek erken mühendislik olabilir. İyi arayüz, gerçek bir değişim eksenini temsil eder. Yani “ileride farklı ödeme stratejileri olabilir” diyorsanız <code class="language-plaintext highlighter-rouge">Payable</code> anlamlıdır; ama “belki bir gün kahve makinesi de ödeme hesaplar” diyorsanız biraz sakinleşmek gerekebilir.</p>

<p>Arayüzlerin bir diğer güzelliği testlerde görülür. Somut veritabanı bağlantısı yerine <code class="language-plaintext highlighter-rouge">Repository</code> arayüzüne bağımlı kod, test sırasında sahte bir bellek içi nesneyle çalışabilir. Böylece kodun davranışını izole ederiz. Bu da yazılımı daha ölçülebilir yapar; çünkü test maliyeti kabaca $Maliyet = Kurulum + Bağımlılık + Bekleme$ ise, arayüzler özellikle bağımlılık ve bekleme kısmını azaltır.</p>

<p>Sonuç olarak arayüzler, yazılım tasarımında kimlik kontrolünden davranış kontrolüne geçiştir. Çok biçimlilikle birleştiğinde, aynı kodun farklı nesnelerle uyumlu çalışmasını sağlar. Bu yaklaşım, gelecekte gelecek yeni sınıflara kapıyı açık bırakırken mevcut kodu sakin ve kararlı tutar. Kısacası iyi tasarlanmış bir arayüz şunu söyler: “Bana nereden geldiğini anlatma, ne yapabildiğini göster.”</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="arayüzler" /><category term="çok biçimlilik" /><category term="yazılım tasarımı" /><summary type="html"><![CDATA[Yazılım dünyasında bazen nesnelere fazla kimlik sorarız: “Sen gerçekten User mısın, Admin misin, Robot musun?” Oysa esnek tasarımın daha havalı sorusu şudur: “Ne yapabiliyorsun?” Arayüzler, tam da bu bakış açısını kodun merkezine koyar. Bir nesnenin sınıf soy ağacına değil, sunduğu davranış sözleşmesine odaklanır. Böylece kodumuz daha az dedikoducu, daha çok iş bitirici olur.]]></summary></entry><entry><title type="html">Diziler ve Dilimler: Bellekte Sabit Kutular, Esnek Pencereler</title><link href="https://sonsuzus.github.io/posts/diziler-ve-dilimler-bellekte-sabit-kutular-esnek-pencereler/" rel="alternate" type="text/html" title="Diziler ve Dilimler: Bellekte Sabit Kutular, Esnek Pencereler" /><published>2026-07-24T00:00:00+00:00</published><updated>2026-07-24T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/diziler-ve-dilimler-bellekte-sabit-kutular-esnek-pencereler</id><content type="html" xml:base="https://sonsuzus.github.io/posts/diziler-ve-dilimler-bellekte-sabit-kutular-esnek-pencereler/"><![CDATA[<p>Bir veri koleksiyonunu saklamak istediğimizde aklımıza ilk gelen yapı genellikle dizidir; ama Go gibi dillerde sahneye bir de dilimler, yani slices çıkar. Dizi, bellekte yan yana duran sabit sayıda kutu gibidir; dilim ise bu kutuların tamamını ya da bir bölümünü gösteren akıllı bir pencere. Aralarındaki farkı anlamak, sadece sözdizimini değil, performans ve bellek davranışını da doğru okumayı sağlar.
``</p>

<h2 id="teorik-temel-boyut-mu-esneklik-mi">Teorik Temel: Boyut mu, Esneklik mi?</h2>

<p>Dizi, uzunluğu türünün parçası olan sabit boyutlu bir veri yapısıdır. Go’da <code class="language-plaintext highlighter-rouge">[3]int</code> ile <code class="language-plaintext highlighter-rouge">[4]int</code> farklı türlerdir. Yani derleyici için “3 elemanlı int dizisi” ile “4 elemanlı int dizisi” aynı ailenin kuzenleri bile değildir; tamamen ayrı kimliklere sahiptir.</p>

<p>Dilim ise kendi başına veriyi doğrudan taşımaz. Arkasında genellikle bir dizi bulunur ve dilim bu dizinin belirli bir aralığına referans verir. Bir slice üç parçalı küçük bir başlık gibi düşünülebilir:</p>

<ul>
  <li>işaretçi: alttaki dizide başlangıç konumu,</li>
  <li>uzunluk: şu an görünen eleman sayısı,</li>
  <li>kapasite: başlangıçtan itibaren kullanılabilecek maksimum alan.</li>
</ul>

<p>Matematiksel olarak temel kural şudur: $0 \le len(slice) \le cap(slice)$. Yani uzunluk kapasiteyi aşamaz; ama <code class="language-plaintext highlighter-rouge">append</code> ile kapasite yetmezse Go yeni ve daha büyük bir alttaki dizi ayırabilir.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Array</th>
      <th>Slice</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Boyut</td>
      <td>Sabit</td>
      <td>Dinamik görünümlü</td>
    </tr>
    <tr>
      <td>Tür bilgisi</td>
      <td>Boyut türün parçasıdır</td>
      <td>Boyut türün parçası değildir</td>
    </tr>
    <tr>
      <td>Kopyalama</td>
      <td>Tüm elemanlar kopyalanır</td>
      <td>Başlık kopyalanır, veri paylaşılabilir</td>
    </tr>
    <tr>
      <td>Bellek modeli</td>
      <td>Doğrudan veri</td>
      <td>Alttaki diziye referans</td>
    </tr>
    <tr>
      <td>Esneklik</td>
      <td>Düşük</td>
      <td>Yüksek</td>
    </tr>
  </tbody>
</table>

<h2 id="diziler-sabit-boyutlu-disiplin">Diziler: Sabit Boyutlu Disiplin</h2>

<p>Diziler, özellikle boyutun kesin bilindiği durumlarda harikadır. Örneğin RGB renk değeri için <code class="language-plaintext highlighter-rouge">[3]uint8</code> gayet anlamlıdır. Çünkü kırmızı, yeşil ve mavi olmak üzere tam üç kanal vardır; dördüncü eleman beklenmez.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">updateArray</span><span class="p">(</span><span class="n">a</span> <span class="p">[</span><span class="m">3</span><span class="p">]</span><span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">a</span><span class="p">[</span><span class="m">0</span><span class="p">]</span> <span class="o">=</span> <span class="m">99</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">nums</span> <span class="o">:=</span> <span class="p">[</span><span class="m">3</span><span class="p">]</span><span class="kt">int</span><span class="p">{</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">}</span>
    <span class="n">updateArray</span><span class="p">(</span><span class="n">nums</span><span class="p">)</span>
    <span class="nb">println</span><span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="m">0</span><span class="p">])</span> <span class="c">// 1</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu örnekte <code class="language-plaintext highlighter-rouge">updateArray</code> fonksiyonuna dizi gönderildiğinde tüm dizi kopyalanır. Fonksiyon içindeki değişiklik dışarıdaki <code class="language-plaintext highlighter-rouge">nums</code> dizisini etkilemez. Bu davranış güvenlidir ama büyük dizilerde maliyetli olabilir. Eğer $n$ elemanlı bir dizi kopyalanıyorsa işlem maliyeti yaklaşık $O(n)$ olur.</p>

<h2 id="dilimler-esnek-ve-paylaşımcı-pencereler">Dilimler: Esnek ve Paylaşımcı Pencereler</h2>

<p>Dilimlerde durum daha hareketlidir. Slice değeri kopyalansa bile alttaki dizi çoğu zaman aynı kalır. Bu yüzden bir fonksiyona slice gönderdiğinizde eleman değişiklikleri dışarıdan görülebilir.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">updateSlice</span><span class="p">(</span><span class="n">s</span> <span class="p">[]</span><span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">s</span><span class="p">[</span><span class="m">0</span><span class="p">]</span> <span class="o">=</span> <span class="m">99</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">nums</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">int</span><span class="p">{</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">}</span>
    <span class="n">updateSlice</span><span class="p">(</span><span class="n">nums</span><span class="p">)</span>
    <span class="nb">println</span><span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="m">0</span><span class="p">])</span> <span class="c">// 99</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">s</code> aslında slice başlığının kopyasıdır; fakat başlığın gösterdiği alttaki dizi aynıdır. Bu nedenle <code class="language-plaintext highlighter-rouge">s[0] = 99</code>, orijinal veriyi değiştirir. İşte slice’ların “referans gibi davranıyor” denmesinin sebebi budur. Tam anlamıyla referans türü demek yerine, “referans taşıyan küçük bir descriptor” demek daha doğrudur.</p>

<h2 id="append-ve-kapasite-sürprizi">Append ve Kapasite Sürprizi</h2>

<p>Slice’ların en eğlenceli tarafı <code class="language-plaintext highlighter-rouge">append</code> ile büyüyebilmesidir; ama burada küçük bir numara vardır. Kapasite yetiyorsa aynı alttaki dizi kullanılır. Yetmiyorsa yeni bir dizi oluşturulur ve elemanlar oraya taşınır.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">a</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">int</span><span class="p">{</span><span class="m">10</span><span class="p">,</span> <span class="m">20</span><span class="p">,</span> <span class="m">30</span><span class="p">}</span>
    <span class="n">b</span> <span class="o">:=</span> <span class="n">a</span><span class="p">[</span><span class="o">:</span><span class="m">2</span><span class="p">]</span>

    <span class="n">b</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="m">99</span><span class="p">)</span>

    <span class="nb">println</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="m">2</span><span class="p">])</span> <span class="c">// kapasite yeterse 99 olabilir</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu örnekte <code class="language-plaintext highlighter-rouge">b</code>, <code class="language-plaintext highlighter-rouge">a</code> dizisinin ilk iki elemanını gösterir. Eğer <code class="language-plaintext highlighter-rouge">b</code> için kapasite yeterliyse <code class="language-plaintext highlighter-rouge">append</code>, üçüncü konuma <code class="language-plaintext highlighter-rouge">99</code> yazar ve <code class="language-plaintext highlighter-rouge">a[2]</code> de değişmiş gibi görünür. Bu, slice paylaşımının hem süper gücü hem de potansiyel tuzağıdır.</p>

<table>
  <thead>
    <tr>
      <th>Senaryo</th>
      <th>Sonuç</th>
      <th>Dikkat Edilecek Nokta</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Slice elemanı değiştirme</td>
      <td>Alttaki dizi değişir</td>
      <td>Diğer slice’lar etkilenebilir</td>
    </tr>
    <tr>
      <td>Append, kapasite yeterli</td>
      <td>Aynı dizi kullanılır</td>
      <td>Yan etki oluşabilir</td>
    </tr>
    <tr>
      <td>Append, kapasite yetersiz</td>
      <td>Yeni dizi ayrılır</td>
      <td>Eski slice etkilenmeyebilir</td>
    </tr>
    <tr>
      <td>Array fonksiyona geçme</td>
      <td>Tam kopya</td>
      <td>Büyük veri için pahalıdır</td>
    </tr>
  </tbody>
</table>

<h2 id="ne-zaman-hangisi">Ne Zaman Hangisi?</h2>

<p>Boyut gerçekten sabitse ve bu bilgi programın anlamının parçasıysa array iyi seçimdir. Örneğin matris boyutu, kriptografik bloklar veya sabit protokol alanları buna uygundur. Ancak çoğu uygulama kodunda veri miktarı çalışma zamanında değişir: kullanıcı listeleri, dosyadan okunan satırlar, API sonuçları… Bu durumda slice çok daha pratiktir.</p>

<p>Kısa özetle: array, bellekte düzenli ve sabit bir apartman; slice ise bu apartmanın odalarına bakan esnek bir emlak danışmanıdır. Danışman hafiftir, kolay kopyalanır; ama hangi odayı gösterdiğini unutursanız yanlış duvarı boyayabilirsiniz. Go’da güçlü ve hatasız kod yazmanın yolu, bu küçük pencerenin arkasındaki büyük diziyi her zaman akılda tutmaktan geçer.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="Go" /><category term="Arrays" /><category term="Slices" /><category term="Bellek Yönetimi" /><summary type="html"><![CDATA[Bir veri koleksiyonunu saklamak istediğimizde aklımıza ilk gelen yapı genellikle dizidir; ama Go gibi dillerde sahneye bir de dilimler, yani slices çıkar. Dizi, bellekte yan yana duran sabit sayıda kutu gibidir; dilim ise bu kutuların tamamını ya da bir bölümünü gösteren akıllı bir pencere. Aralarındaki farkı anlamak, sadece sözdizimini değil, performans ve bellek davranışını da doğru okumayı sağlar.]]></summary></entry></feed>