<?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-17T08:20:40+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">C++ ile Fraktal Üretimi: Kaosun Piksel Piksel Haritası</title><link href="https://sonsuzus.github.io/posts/c-ile-fraktal-uretimi-kaosun-piksel-piksel-haritasi/" rel="alternate" type="text/html" title="C++ ile Fraktal Üretimi: Kaosun Piksel Piksel Haritası" /><published>2026-07-17T00:00:00+00:00</published><updated>2026-07-17T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/c-ile-fraktal-uretimi-kaosun-piksel-piksel-haritasi</id><content type="html" xml:base="https://sonsuzus.github.io/posts/c-ile-fraktal-uretimi-kaosun-piksel-piksel-haritasi/"><![CDATA[<p>Fraktallar, matematiğin “az kural, çok karmaşa” diyen asi çocuklarıdır. C++ ile fraktal üretmek ise bu çocuklara bir tuval vermek gibidir: basit bir formül yazarsınız, bilgisayar milyonlarca kez tekrarlar ve ekranda sonsuz kıvrımlara benzeyen görsel bir evren belirir. Özellikle Mandelbrot kümesi, kaos teorisinin en popüler posteridir; çünkü minicik bir başlangıç farkı, bambaşka görsel sonuçlar doğurabilir.
``
Fraktal mantığının kalbinde yineleme, yani aynı işlemi tekrar tekrar uygulama fikri vardır. Mandelbrot için temel formül oldukça kısa görünür: $z_{n+1}=z_n^2+c$. Burada $z$ karmaşık bir sayıdır, $c$ ise ekrandaki her pikselin temsil ettiği noktadır. Başlangıçta $z_0=0$ alınır. Sonra bu formül belirli sayıda çalıştırılır. Eğer $|z_n| &gt; 2$ olursa noktanın “kaçtığını” söyleriz; kaçmazsa Mandelbrot kümesinin içinde veya sınırında olabilir.</p>

<p>Bu basitlik aldatıcıdır. Çünkü her piksel için aynı işlem yapılmasına rağmen sonuçlar dramatik biçimde değişir. Bir piksel 10 yinelemede kaçarken komşusu 500 yineleme boyunca dayanabilir. İşte renkleri de genellikle bu kaçış hızına göre veririz.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Programdaki Karşılığı</th>
      <th>Görsel Etki</th>
      <th> </th>
      <th> </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Karmaşık sayı $c$</td>
      <td>Pikselin matematiksel koordinatı</td>
      <td>Fraktalda konum belirler</td>
      <td> </td>
      <td> </td>
    </tr>
    <tr>
      <td>Yineleme sayısı</td>
      <td>Döngü limiti</td>
      <td>Detay seviyesi artar</td>
      <td> </td>
      <td> </td>
    </tr>
    <tr>
      <td>Kaçış koşulu $</td>
      <td>z</td>
      <td>&gt;2$</td>
      <td>Döngüden çıkma şartı</td>
      <td>Renk yoğunluğunu belirler</td>
    </tr>
    <tr>
      <td>Yakınlaştırma</td>
      <td>Koordinat aralığını daraltma</td>
      <td>Sonsuz detay hissi verir</td>
      <td> </td>
      <td> </td>
    </tr>
  </tbody>
</table>

<p>Aşağıdaki C++ kodu, Mandelbrot kümesini PPM formatında bir görsele yazar. PPM seçmemizin nedeni eğlenceli derecede basit olmasıdır: dosyanın başına birkaç bilgi, ardından RGB değerleri. Yani kütüphane canavarı çağırmadan piksel piksel resim üretebiliriz.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;fstream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;complex&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">const</span> <span class="kt">int</span> <span class="n">width</span> <span class="o">=</span> <span class="mi">900</span><span class="p">;</span>
    <span class="k">const</span> <span class="kt">int</span> <span class="n">height</span> <span class="o">=</span> <span class="mi">600</span><span class="p">;</span>
    <span class="k">const</span> <span class="kt">int</span> <span class="n">maxIter</span> <span class="o">=</span> <span class="mi">300</span><span class="p">;</span>

    <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span> <span class="n">out</span><span class="p">(</span><span class="s">"mandelbrot.ppm"</span><span class="p">);</span>
    <span class="n">out</span> <span class="o">&lt;&lt;</span> <span class="s">"P3</span><span class="se">\n</span><span class="s">"</span> <span class="o">&lt;&lt;</span> <span class="n">width</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span> <span class="o">&lt;&lt;</span> <span class="n">height</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">255</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="n">height</span><span class="p">;</span> <span class="o">++</span><span class="n">y</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">width</span><span class="p">;</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span>
            <span class="kt">double</span> <span class="n">real</span> <span class="o">=</span> <span class="o">-</span><span class="mf">2.5</span> <span class="o">+</span> <span class="n">x</span> <span class="o">*</span> <span class="p">(</span><span class="mf">3.5</span> <span class="o">/</span> <span class="n">width</span><span class="p">);</span>
            <span class="kt">double</span> <span class="n">imag</span> <span class="o">=</span> <span class="o">-</span><span class="mf">1.2</span> <span class="o">+</span> <span class="n">y</span> <span class="o">*</span> <span class="p">(</span><span class="mf">2.4</span> <span class="o">/</span> <span class="n">height</span><span class="p">);</span>

            <span class="n">std</span><span class="o">::</span><span class="n">complex</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span> <span class="n">c</span><span class="p">(</span><span class="n">real</span><span class="p">,</span> <span class="n">imag</span><span class="p">);</span>
            <span class="n">std</span><span class="o">::</span><span class="n">complex</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span> <span class="n">z</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

            <span class="kt">int</span> <span class="n">iter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
            <span class="k">while</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">abs</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mf">2.0</span> <span class="o">&amp;&amp;</span> <span class="n">iter</span> <span class="o">&lt;</span> <span class="n">maxIter</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">z</span> <span class="o">=</span> <span class="n">z</span> <span class="o">*</span> <span class="n">z</span> <span class="o">+</span> <span class="n">c</span><span class="p">;</span>
                <span class="o">++</span><span class="n">iter</span><span class="p">;</span>
            <span class="p">}</span>

            <span class="kt">int</span> <span class="n">r</span> <span class="o">=</span> <span class="p">(</span><span class="n">iter</span> <span class="o">*</span> <span class="mi">9</span><span class="p">)</span> <span class="o">%</span> <span class="mi">256</span><span class="p">;</span>
            <span class="kt">int</span> <span class="n">g</span> <span class="o">=</span> <span class="p">(</span><span class="n">iter</span> <span class="o">*</span> <span class="mi">5</span><span class="p">)</span> <span class="o">%</span> <span class="mi">256</span><span class="p">;</span>
            <span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="n">iter</span> <span class="o">*</span> <span class="mi">13</span><span class="p">)</span> <span class="o">%</span> <span class="mi">256</span><span class="p">;</span>

            <span class="k">if</span> <span class="p">(</span><span class="n">iter</span> <span class="o">==</span> <span class="n">maxIter</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">r</span> <span class="o">=</span> <span class="n">g</span> <span class="o">=</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
            <span class="p">}</span>

            <span class="n">out</span> <span class="o">&lt;&lt;</span> <span class="n">r</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span> <span class="o">&lt;&lt;</span> <span class="n">g</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span> <span class="o">&lt;&lt;</span> <span class="n">b</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">out</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Kodda <code class="language-plaintext highlighter-rouge">real</code> ve <code class="language-plaintext highlighter-rouge">imag</code> değişkenleri, ekran koordinatını matematiksel düzleme çevirir. Yani <code class="language-plaintext highlighter-rouge">(x, y)</code> pikselini doğrudan çizmek yerine, onu karmaşık sayı düzlemindeki bir noktaya dönüştürürüz. Sonrasında <code class="language-plaintext highlighter-rouge">z = z * z + c</code> satırı fraktalın motorudur. Bu satır her piksel için yüzlerce kez çalışır; C++ burada hız avantajını gösterir.</p>

<p>Renk seçimi tamamen deney alanıdır. Yukarıdaki örnekte mod alma ile basit ama canlı bir palet oluşturduk. Daha yumuşak geçişler için logaritmik renklendirme kullanılabilir. Teorik olarak kaçış süresi $n$ ise, renk fonksiyonu $color=f(n)$ gibi düşünülebilir. Fonksiyon ne kadar yaratıcıysa fraktal o kadar “galaksi posteri” havasına bürünür.</p>

<table>
  <thead>
    <tr>
      <th>Ayar</th>
      <th>Düşük Değer</th>
      <th>Yüksek Değer</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">maxIter</code></td>
      <td>Hızlı ama az detay</td>
      <td>Yavaş ama keskin sınırlar</td>
    </tr>
    <tr>
      <td>Çözünürlük</td>
      <td>Küçük dosya</td>
      <td>Daha temiz görüntü</td>
    </tr>
    <tr>
      <td>Koordinat aralığı</td>
      <td>Geniş bakış</td>
      <td>Yakınlaştırılmış detay</td>
    </tr>
    <tr>
      <td>Renk formülü</td>
      <td>Düz görünüm</td>
      <td>Sanatsal sonuç</td>
    </tr>
  </tbody>
</table>

<p>Fraktalların büyüsü, deterministik olmalarına rağmen organik görünmeleridir. Aynı formül, aynı başlangıç, aynı sonuç; fakat sonuç, doğadaki kıyı çizgilerini, bulutları ve damar yapılarını hatırlatır. Kaos teorisi burada “rastgelelik” değil, başlangıç koşullarına aşırı duyarlılık demektir.</p>

<p>Bu programı geliştirmek için yakınlaştırma parametreleri ekleyebilir, PNG çıktısı almak için <code class="language-plaintext highlighter-rouge">stb_image_write</code> kullanabilir veya çok çekirdekli işlem için pikselleri paralel hesaplatabilirsiniz. Sonuçta C++ ile fraktal üretimi sadece görsel bir oyuncak değildir; matematik, performans ve yaratıcılığın aynı döngüde buluştuğu küçük bir evrendir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="C++" /><category term="Fraktal" /><category term="Mandelbrot" /><category term="Kaos Teorisi" /><summary type="html"><![CDATA[Fraktallar, matematiğin “az kural, çok karmaşa” diyen asi çocuklarıdır. C++ ile fraktal üretmek ise bu çocuklara bir tuval vermek gibidir: basit bir formül yazarsınız, bilgisayar milyonlarca kez tekrarlar ve ekranda sonsuz kıvrımlara benzeyen görsel bir evren belirir. Özellikle Mandelbrot kümesi, kaos teorisinin en popüler posteridir; çünkü minicik bir başlangıç farkı, bambaşka görsel sonuçlar doğurabilir.]]></summary></entry><entry><title type="html">C ile Kendi Mini Yorumlayıcını Yazmak: Sözdiziminden Bytecode’a</title><link href="https://sonsuzus.github.io/posts/c-ile-kendi-mini-yorumlayicini-yazmak-sozdiziminden-bytecodea/" rel="alternate" type="text/html" title="C ile Kendi Mini Yorumlayıcını Yazmak: Sözdiziminden Bytecode’a" /><published>2026-07-17T00:00:00+00:00</published><updated>2026-07-17T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/c-ile-kendi-mini-yorumlayicini-yazmak-sozdiziminden-bytecodea</id><content type="html" xml:base="https://sonsuzus.github.io/posts/c-ile-kendi-mini-yorumlayicini-yazmak-sozdiziminden-bytecodea/"><![CDATA[<p>Derleyiciler bazen kara kutu gibi görünür: kodu yazarsın, bir şeyler olur ve işlemci “tamamdır” der. Oysa içeride oldukça sistemli bir mutfak çalışır. Bu yazıda C ile minicik bir dil motoru tasarlayarak <code class="language-plaintext highlighter-rouge">SET x 5</code>, <code class="language-plaintext highlighter-rouge">ADD x 3</code>, <code class="language-plaintext highlighter-rouge">PRINT x</code> gibi komutları okuyacak, sözdizimini analiz edecek ve bunları basit bir “makine dili” yani bytecode’a çevireceğiz.
``
Bir yorumlayıcının temel fikri şudur: metin hâlindeki program önce anlamlı parçalara ayrılır, sonra kurallara göre dizilir, en sonunda da çalıştırılabilir talimatlara dönüştürülür. Gerçek derleyicilerde bu süreç daha karmaşıktır; optimizasyon, tip denetimi ve hedef mimari gibi konular devreye girer. Bizim oyuncak dilimizde ise değişkenler, sayılar ve birkaç komut yeterli olacak.</p>

<p>Teorik olarak kaynak koddan çalışmaya giden yol şöyle modellenebilir:</p>

\[Kaynak\ Kod \rightarrow Tokenlar \rightarrow AST/Komutlar \rightarrow Bytecode \rightarrow VM\]

<p>Burada “VM”, sanal makine demektir. Gerçek CPU yerine kendi küçük işlemcimizi C içinde simüle ederiz. Mesela <code class="language-plaintext highlighter-rouge">ADD x 3</code> komutu, bellekteki <code class="language-plaintext highlighter-rouge">x</code> değerini alıp üzerine 3 ekleyen bir bytecode talimatına dönüşür.</p>

<table>
  <thead>
    <tr>
      <th>Aşama</th>
      <th>Görevi</th>
      <th>Örnek</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Lexer</td>
      <td>Metni parçalara ayırır</td>
      <td><code class="language-plaintext highlighter-rouge">ADD</code>, <code class="language-plaintext highlighter-rouge">x</code>, <code class="language-plaintext highlighter-rouge">3</code></td>
    </tr>
    <tr>
      <td>Parser</td>
      <td>Sıralamanın doğru olup olmadığını kontrol eder</td>
      <td><code class="language-plaintext highlighter-rouge">ADD IDENT NUMBER</code></td>
    </tr>
    <tr>
      <td>Codegen</td>
      <td>Komutu bytecode’a çevirir</td>
      <td><code class="language-plaintext highlighter-rouge">OP_ADD, var_id, 3</code></td>
    </tr>
    <tr>
      <td>VM</td>
      <td>Bytecode’u çalıştırır</td>
      <td><code class="language-plaintext highlighter-rouge">x = x + 3</code></td>
    </tr>
  </tbody>
</table>

<p>Önce komut kümemizi tanımlayalım. Bu dilde üç işlem olsun: değişkene değer atama, toplama ve ekrana yazdırma. Matematiksel olarak belleği bir fonksiyon gibi düşünebiliriz: $M(v)$, <code class="language-plaintext highlighter-rouge">v</code> değişkeninin değeridir. <code class="language-plaintext highlighter-rouge">ADD x 3</code> çalışınca yeni durum $M’(x)=M(x)+3$ olur.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">enum</span> <span class="p">{</span>
    <span class="n">OP_SET</span><span class="p">,</span>
    <span class="n">OP_ADD</span><span class="p">,</span>
    <span class="n">OP_PRINT</span><span class="p">,</span>
    <span class="n">OP_HALT</span>
<span class="p">}</span> <span class="n">OpCode</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">OpCode</span> <span class="n">op</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">var</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">value</span><span class="p">;</span>
<span class="p">}</span> <span class="n">Instruction</span><span class="p">;</span>
</code></pre></div></div>

<p>Bu yapı bizim mini makine dilimizdir. <code class="language-plaintext highlighter-rouge">op</code> hangi işlemin yapılacağını söyler, <code class="language-plaintext highlighter-rouge">var</code> değişkenin kimliğini, <code class="language-plaintext highlighter-rouge">value</code> ise sayısal argümanı taşır. Gerçek makinelerde bunlar baytlara sıkıştırılır; biz okunabilir kalsın diye <code class="language-plaintext highlighter-rouge">struct</code> kullandık.</p>

<p>Şimdi basit bir değişken tablosu yazalım. Oyuncak örnekte değişkenleri tek harf kabul etmek işi çok kolaylaştırır: <code class="language-plaintext highlighter-rouge">a</code>, <code class="language-plaintext highlighter-rouge">b</code>, <code class="language-plaintext highlighter-rouge">x</code> gibi. Böylece <code class="language-plaintext highlighter-rouge">x - 'a'</code> bize 0-25 arası bir indeks verir.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">var_id</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">name</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="sc">'a'</span> <span class="o">&amp;&amp;</span> <span class="n">name</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="sc">'z'</span> <span class="o">&amp;&amp;</span> <span class="n">name</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'\0'</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">name</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="sc">'a'</span><span class="p">;</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Parser tarafında satırı okuyup ilk kelimeye göre karar verebiliriz. Bu, tam teşekküllü bir parser değildir ama sözdizimi analizinin özünü gösterir: beklenen kalıba uyuyor mu?</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">compile_line</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">line</span><span class="p">,</span> <span class="n">Instruction</span> <span class="o">*</span><span class="n">out</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">char</span> <span class="n">cmd</span><span class="p">[</span><span class="mi">16</span><span class="p">],</span> <span class="n">name</span><span class="p">[</span><span class="mi">16</span><span class="p">];</span>
    <span class="kt">int</span> <span class="n">value</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">sscanf</span><span class="p">(</span><span class="n">line</span><span class="p">,</span> <span class="s">"SET %15s %d"</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">value</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">out</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">=</span> <span class="n">OP_SET</span><span class="p">;</span>
        <span class="n">out</span><span class="o">-&gt;</span><span class="n">var</span> <span class="o">=</span> <span class="n">var_id</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
        <span class="n">out</span><span class="o">-&gt;</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">out</span><span class="o">-&gt;</span><span class="n">var</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">sscanf</span><span class="p">(</span><span class="n">line</span><span class="p">,</span> <span class="s">"ADD %15s %d"</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">value</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">out</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">=</span> <span class="n">OP_ADD</span><span class="p">;</span>
        <span class="n">out</span><span class="o">-&gt;</span><span class="n">var</span> <span class="o">=</span> <span class="n">var_id</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
        <span class="n">out</span><span class="o">-&gt;</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">out</span><span class="o">-&gt;</span><span class="n">var</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">sscanf</span><span class="p">(</span><span class="n">line</span><span class="p">,</span> <span class="s">"PRINT %15s"</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">out</span><span class="o">-&gt;</span><span class="n">op</span> <span class="o">=</span> <span class="n">OP_PRINT</span><span class="p">;</span>
        <span class="n">out</span><span class="o">-&gt;</span><span class="n">var</span> <span class="o">=</span> <span class="n">var_id</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
        <span class="n">out</span><span class="o">-&gt;</span><span class="n">value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">out</span><span class="o">-&gt;</span><span class="n">var</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu kodun eğlenceli yanı, <code class="language-plaintext highlighter-rouge">sscanf</code> ile minik bir dilbilgisi kontrolü yapmasıdır. Daha ciddi bir projede token üretir, ardından recursive descent parser yazardık. Örneğin <code class="language-plaintext highlighter-rouge">expr -&gt; term ((+|-) term)*</code> gibi kurallarla matematiksel ifadeleri ayrıştırmak mümkün olurdu.</p>

<p>Son adımda bytecode’u çalıştıran sanal makineyi yazıyoruz:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">run</span><span class="p">(</span><span class="n">Instruction</span> <span class="o">*</span><span class="n">code</span><span class="p">,</span> <span class="kt">int</span> <span class="n">count</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">memory</span><span class="p">[</span><span class="mi">26</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">ip</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">ip</span> <span class="o">&lt;</span> <span class="n">count</span><span class="p">;</span> <span class="n">ip</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">Instruction</span> <span class="n">in</span> <span class="o">=</span> <span class="n">code</span><span class="p">[</span><span class="n">ip</span><span class="p">];</span>

        <span class="k">switch</span> <span class="p">(</span><span class="n">in</span><span class="p">.</span><span class="n">op</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">case</span> <span class="n">OP_SET</span><span class="p">:</span>
                <span class="n">memory</span><span class="p">[</span><span class="n">in</span><span class="p">.</span><span class="n">var</span><span class="p">]</span> <span class="o">=</span> <span class="n">in</span><span class="p">.</span><span class="n">value</span><span class="p">;</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="k">case</span> <span class="n">OP_ADD</span><span class="p">:</span>
                <span class="n">memory</span><span class="p">[</span><span class="n">in</span><span class="p">.</span><span class="n">var</span><span class="p">]</span> <span class="o">+=</span> <span class="n">in</span><span class="p">.</span><span class="n">value</span><span class="p">;</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="k">case</span> <span class="n">OP_PRINT</span><span class="p">:</span>
                <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">memory</span><span class="p">[</span><span class="n">in</span><span class="p">.</span><span class="n">var</span><span class="p">]);</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="k">case</span> <span class="n">OP_HALT</span><span class="p">:</span>
                <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Buradaki <code class="language-plaintext highlighter-rouge">ip</code>, instruction pointer’dır; yani sıradaki talimatın adresini gösterir. CPU’larda da benzer bir mantık vardır. Program sayacı ilerler, talimat çözülür, işlem yapılır. Bizim VM bunu C döngüsüyle taklit eder.</p>

<p>Örnek program şöyle olabilir:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SET x 10
ADD x 7
PRINT x
</code></pre></div></div>

<p>Derleme sonucunda yaklaşık olarak şu bytecode dizisi oluşur:</p>

<table>
  <thead>
    <tr>
      <th>Kaynak Satır</th>
      <th>Bytecode</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">SET x 10</code></td>
      <td><code class="language-plaintext highlighter-rouge">OP_SET, 23, 10</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ADD x 7</code></td>
      <td><code class="language-plaintext highlighter-rouge">OP_ADD, 23, 7</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">PRINT x</code></td>
      <td><code class="language-plaintext highlighter-rouge">OP_PRINT, 23, 0</code></td>
    </tr>
  </tbody>
</table>

<p>Çıktı doğal olarak <code class="language-plaintext highlighter-rouge">17</code> olur. Küçük ama güçlü bir fikir yakaladık: sözdizimi sadece metin kontrolü değildir; anlamlı eylemlere açılan kapıdır. Buradan sonra ifadeler, koşullar, döngüler ve hata mesajları ekleyerek mini dilinizi büyütebilirsiniz. Bir noktadan sonra fark edeceksiniz: derleyiciler büyü yapmıyor, sadece çok disiplinli bir çeviri işi gerçekleştiriyor.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="C" /><category term="yorumlayıcı" /><category term="derleyici" /><category term="parser" /><category term="bytecode" /><summary type="html"><![CDATA[Derleyiciler bazen kara kutu gibi görünür: kodu yazarsın, bir şeyler olur ve işlemci “tamamdır” der. Oysa içeride oldukça sistemli bir mutfak çalışır. Bu yazıda C ile minicik bir dil motoru tasarlayarak SET x 5, ADD x 3, PRINT x gibi komutları okuyacak, sözdizimini analiz edecek ve bunları basit bir “makine dili” yani bytecode’a çevireceğiz.]]></summary></entry><entry><title type="html">Go ile Blokzincir Temelleri: Hash’lerle Değiştirilemez Zincir Kurmak</title><link href="https://sonsuzus.github.io/posts/go-ile-blokzincir-temelleri-hashlerle-degistirilemez-zincir-kurmak/" rel="alternate" type="text/html" title="Go ile Blokzincir Temelleri: Hash’lerle Değiştirilemez Zincir Kurmak" /><published>2026-07-17T00:00:00+00:00</published><updated>2026-07-17T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/go-ile-blokzincir-temelleri-hashlerle-degistirilemez-zincir-kurmak</id><content type="html" xml:base="https://sonsuzus.github.io/posts/go-ile-blokzincir-temelleri-hashlerle-degistirilemez-zincir-kurmak/"><![CDATA[<p>Blokzincir kulağa bazen uzay teknolojisi gibi gelir; ama temel fikir oldukça nettir: Verileri bloklar halinde sakla, her bloğu bir öncekinin kriptografik iziyle bağla ve zincirin ortasından bir parçayı değiştirmeyi neredeyse imkânsız hale getir. Bu yazıda Go kullanarak küçük ama öğretici bir blokzincir modeli kuracağız; amaç coin üretmek değil, değiştirilemezlik fikrini programlayarak anlamak.
``</p>

<p>Blokzincirin kalbinde <strong>kriptografik özetleme fonksiyonu</strong> yani hash vardır. Bir hash fonksiyonu, herhangi uzunluktaki girdiyi sabit uzunlukta bir çıktıya dönüştürür. Örneğin SHA-256 çıktısı 256 bittir. Matematiksel olarak şöyle düşünebiliriz:</p>

\[H(x) = y\]

<p>Burada $x$ veri, $y$ ise özet değerdir. İyi bir hash fonksiyonunda küçük bir değişiklik bile sonucu tamamen farklılaştırır. Buna <strong>çığ etkisi</strong> denir. Yani <code class="language-plaintext highlighter-rouge">Merhaba</code> ile <code class="language-plaintext highlighter-rouge">MerhabA</code> aynı görünse de hash açısından bambaşka evrenlerdir.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Normal Kontrol Toplamı</th>
      <th>Kriptografik Hash</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Amaç</td>
      <td>Hata yakalama</td>
      <td>Bütünlük ve güvenlik</td>
    </tr>
    <tr>
      <td>Çıktı</td>
      <td>Genelde kısa</td>
      <td>Sabit ve güçlü</td>
    </tr>
    <tr>
      <td>Çakışmaya direnç</td>
      <td>Zayıf olabilir</td>
      <td>Çok güçlü olmalıdır</td>
    </tr>
    <tr>
      <td>Küçük değişime tepki</td>
      <td>Sınırlı</td>
      <td>Büyük, tahmin edilemez</td>
    </tr>
  </tbody>
</table>

<p>Bir blok genellikle şu alanlardan oluşur: veri, zaman damgası, kendi hash değeri ve önceki bloğun hash değeri. İşin sihri son alandadır. Çünkü her blok, kendinden öncekinin özetini taşır. Böylece üçüncü bloğu değiştirmek isterseniz sadece üçüncü bloğun hash’i değil, dördüncü, beşinci ve devamındaki tüm bloklar bozulur.</p>

<p>Basit formülümüz şu olabilir:</p>

\[BlockHash = SHA256(Index + Timestamp + Data + PreviousHash)\]

<p>Şimdi Go tarafına geçelim. Aşağıdaki kod, minimal bir blok yapısı tanımlar ve SHA-256 ile hash üretir:</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">"crypto/sha256"</span>
    <span class="s">"encoding/hex"</span>
    <span class="s">"fmt"</span>
    <span class="s">"time"</span>
<span class="p">)</span>

<span class="k">type</span> <span class="n">Block</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">Index</span>        <span class="kt">int</span>
    <span class="n">Timestamp</span>    <span class="kt">string</span>
    <span class="n">Data</span>         <span class="kt">string</span>
    <span class="n">PreviousHash</span> <span class="kt">string</span>
    <span class="n">Hash</span>         <span class="kt">string</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">calculateHash</span><span class="p">(</span><span class="n">b</span> <span class="n">Block</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
    <span class="n">record</span> <span class="o">:=</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"%d%s%s%s"</span><span class="p">,</span> <span class="n">b</span><span class="o">.</span><span class="n">Index</span><span class="p">,</span> <span class="n">b</span><span class="o">.</span><span class="n">Timestamp</span><span class="p">,</span> <span class="n">b</span><span class="o">.</span><span class="n">Data</span><span class="p">,</span> <span class="n">b</span><span class="o">.</span><span class="n">PreviousHash</span><span class="p">)</span>
    <span class="n">sum</span> <span class="o">:=</span> <span class="n">sha256</span><span class="o">.</span><span class="n">Sum256</span><span class="p">([]</span><span class="kt">byte</span><span class="p">(</span><span class="n">record</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">hex</span><span class="o">.</span><span class="n">EncodeToString</span><span class="p">(</span><span class="n">sum</span><span class="p">[</span><span class="o">:</span><span class="p">])</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">calculateHash</code>, bloğun anlamlı alanlarını tek bir metne çevirir ve SHA-256’dan geçirir. <code class="language-plaintext highlighter-rouge">hex.EncodeToString</code> ise ham byte çıktısını okunabilir onaltılık formata dönüştürür.</p>

<p>Şimdi yeni blok üretelim:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">createBlock</span><span class="p">(</span><span class="n">index</span> <span class="kt">int</span><span class="p">,</span> <span class="n">data</span> <span class="kt">string</span><span class="p">,</span> <span class="n">previousHash</span> <span class="kt">string</span><span class="p">)</span> <span class="n">Block</span> <span class="p">{</span>
    <span class="n">block</span> <span class="o">:=</span> <span class="n">Block</span><span class="p">{</span>
        <span class="n">Index</span><span class="o">:</span>        <span class="n">index</span><span class="p">,</span>
        <span class="n">Timestamp</span><span class="o">:</span>    <span class="n">time</span><span class="o">.</span><span class="n">Now</span><span class="p">()</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span>
        <span class="n">Data</span><span class="o">:</span>         <span class="n">data</span><span class="p">,</span>
        <span class="n">PreviousHash</span><span class="o">:</span> <span class="n">previousHash</span><span class="p">,</span>
    <span class="p">}</span>
    <span class="n">block</span><span class="o">.</span><span class="n">Hash</span> <span class="o">=</span> <span class="n">calculateHash</span><span class="p">(</span><span class="n">block</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">block</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu fonksiyon bloğu oluşturur, ardından hash değerini hesaplayıp bloğun içine yazar. İlk bloğa genellikle <strong>genesis block</strong> denir. Çünkü zincirin başlangıç noktasıdır ve önceki bloğu yoktur.</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">genesis</span> <span class="o">:=</span> <span class="n">createBlock</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="s">"Genesis Block"</span><span class="p">,</span> <span class="s">""</span><span class="p">)</span>
    <span class="n">second</span> <span class="o">:=</span> <span class="n">createBlock</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="s">"Ali -&gt; Ayşe: 10 token"</span><span class="p">,</span> <span class="n">genesis</span><span class="o">.</span><span class="n">Hash</span><span class="p">)</span>
    <span class="n">third</span> <span class="o">:=</span> <span class="n">createBlock</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="s">"Ayşe -&gt; Mehmet: 4 token"</span><span class="p">,</span> <span class="n">second</span><span class="o">.</span><span class="n">Hash</span><span class="p">)</span>

    <span class="n">blockchain</span> <span class="o">:=</span> <span class="p">[]</span><span class="n">Block</span><span class="p">{</span><span class="n">genesis</span><span class="p">,</span> <span class="n">second</span><span class="p">,</span> <span class="n">third</span><span class="p">}</span>

    <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">block</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">blockchain</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">"Index:"</span><span class="p">,</span> <span class="n">block</span><span class="o">.</span><span class="n">Index</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">"Data:"</span><span class="p">,</span> <span class="n">block</span><span class="o">.</span><span class="n">Data</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">"Prev:"</span><span class="p">,</span> <span class="n">block</span><span class="o">.</span><span class="n">PreviousHash</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">"Hash:"</span><span class="p">,</span> <span class="n">block</span><span class="o">.</span><span class="n">Hash</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">"---"</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu programı çalıştırdığınızda her bloğun, bir önceki bloğun hash değerini taşıdığını görürsünüz. Zincir fikri tam olarak budur: Her halka, kendinden önceki halkanın dijital parmak izini saklar.</p>

<p>Peki biri ikinci bloğun verisini değiştirirse ne olur? Mesela <code class="language-plaintext highlighter-rouge">Ali -&gt; Ayşe: 10 token</code> yerine <code class="language-plaintext highlighter-rouge">Ali -&gt; Ayşe: 1000 token</code> yazarsa, ikinci bloğun hash’i değişir. Ancak üçüncü blok hâlâ eski ikinci hash’e bağlıdır. Böylece zincir tutarsız hale gelir.</p>

<p>Bunu kontrol etmek için basit bir doğrulama fonksiyonu yazabiliriz:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">isChainValid</span><span class="p">(</span><span class="n">chain</span> <span class="p">[]</span><span class="n">Block</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
    <span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">chain</span><span class="p">);</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
        <span class="n">current</span> <span class="o">:=</span> <span class="n">chain</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
        <span class="n">previous</span> <span class="o">:=</span> <span class="n">chain</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="m">1</span><span class="p">]</span>

        <span class="k">if</span> <span class="n">current</span><span class="o">.</span><span class="n">Hash</span> <span class="o">!=</span> <span class="n">calculateHash</span><span class="p">(</span><span class="n">current</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="no">false</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="n">current</span><span class="o">.</span><span class="n">PreviousHash</span> <span class="o">!=</span> <span class="n">previous</span><span class="o">.</span><span class="n">Hash</span> <span class="p">{</span>
            <span class="k">return</span> <span class="no">false</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="no">true</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu fonksiyon iki şeyi denetler: Bloğun kendi hash’i gerçekten içeriğinden mi üretilmiş, ayrıca önceki bloğa doğru şekilde mi bağlanmış? İkisinden biri bozulursa zincir geçersizdir.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Go’daki Karşılığı</th>
      <th>Ne İşe Yarar?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Blok</td>
      <td><code class="language-plaintext highlighter-rouge">struct</code></td>
      <td>Veriyi paketler</td>
    </tr>
    <tr>
      <td>Hash</td>
      <td><code class="language-plaintext highlighter-rouge">sha256.Sum256</code></td>
      <td>Dijital parmak izi üretir</td>
    </tr>
    <tr>
      <td>Zincir</td>
      <td><code class="language-plaintext highlighter-rouge">[]Block</code></td>
      <td>Blokları sıralı tutar</td>
    </tr>
    <tr>
      <td>Doğrulama</td>
      <td><code class="language-plaintext highlighter-rouge">isChainValid</code></td>
      <td>Müdahaleyi yakalar</td>
    </tr>
  </tbody>
</table>

<p>Gerçek blokzincirlerde buna ek olarak dağıtık ağ, mutabakat algoritmaları, proof of work, imzalar ve cüzdanlar bulunur. Ancak çekirdek düşünce değişmez: Geçmişi değiştirmek pahalı, görünür ve pratikte sürdürülemez olmalıdır.</p>

<p>Özetle Go ile yazdığımız bu mini zincir, blokzincirin büyüsünü sadeleştirir: veri + önceki hash + kriptografik özet = birbirine kilitlenmiş kayıtlar. Gerçek dünyadaki dev sistemlerin altında da bu basit ama güçlü fikir yatar.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="Go" /><category term="Blockchain" /><category term="Kriptografi" /><summary type="html"><![CDATA[Blokzincir kulağa bazen uzay teknolojisi gibi gelir; ama temel fikir oldukça nettir: Verileri bloklar halinde sakla, her bloğu bir öncekinin kriptografik iziyle bağla ve zincirin ortasından bir parçayı değiştirmeyi neredeyse imkânsız hale getir. Bu yazıda Go kullanarak küçük ama öğretici bir blokzincir modeli kuracağız; amaç coin üretmek değil, değiştirilemezlik fikrini programlayarak anlamak.]]></summary></entry><entry><title type="html">PHP ile Mikro Servis Mimarisi: Dev Sistemi Küçük Parçalara Bölmek</title><link href="https://sonsuzus.github.io/posts/php-ile-mikro-servis-mimarisi-dev-sistemi-kucuk-parcalara-bolmek/" rel="alternate" type="text/html" title="PHP ile Mikro Servis Mimarisi: Dev Sistemi Küçük Parçalara Bölmek" /><published>2026-07-17T00:00:00+00:00</published><updated>2026-07-17T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/php-ile-mikro-servis-mimarisi-dev-sistemi-kucuk-parcalara-bolmek</id><content type="html" xml:base="https://sonsuzus.github.io/posts/php-ile-mikro-servis-mimarisi-dev-sistemi-kucuk-parcalara-bolmek/"><![CDATA[<p>Büyük bir PHP uygulaması zamanla dev bir apartmana dönüşebilir: kullanıcı yönetimi bir katta, ödeme sistemi başka katta, raporlama bodrumda, bildirimler ise çatı arasında çalışır. Her şey aynı kod tabanındaysa küçük bir değişiklik bile tüm binayı sallayabilir. Mikro servis mimarisi, bu apartmanı bağımsız küçük evlere ayırma fikridir. Her servis belirli bir iş yapar, kendi yaşam döngüsüne sahip olur ve gerektiğinde tek başına geliştirilip ölçeklenebilir.
``
Mikro servisleri anlamak için önce monolitik mimariyi hatırlayalım. Monolitik uygulamada kullanıcı kaydı, ürün yönetimi, sepet, ödeme ve e-posta gönderimi aynı proje içinde yer alır. Başlangıçta bu harikadır: tek repository, tek deployment, tek veritabanı. Ancak sistem büyüdükçe bağımlılıklar artar. Bir ödeme hatasını düzeltmek için tüm uygulamayı yeniden yayına almak gerekebilir.</p>

<p>Mikro servis yaklaşımında ise sistem $n$ adet küçük servise bölünür. Kabaca karmaşıklığı şöyle düşünebiliriz: monolitikte değişiklik etkisi çoğu zaman $O(n)$ modüle yayılırken, iyi ayrılmış servislerde etki alanı $O(1)$ veya sınırlı birkaç servise iner. Elbette bu sihirli bir değnek değildir; dağıtık sistem karmaşıklığı, ağ hataları ve veri tutarlılığı gibi yeni problemler getirir.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Monolitik PHP Uygulaması</th>
      <th>Mikro Servis PHP Mimarisi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Deployment</td>
      <td>Tüm uygulama birlikte yayınlanır</td>
      <td>Her servis ayrı yayınlanabilir</td>
    </tr>
    <tr>
      <td>Ölçekleme</td>
      <td>Uygulamanın tamamı ölçeklenir</td>
      <td>Sadece yoğun servis ölçeklenir</td>
    </tr>
    <tr>
      <td>Kod bağımlılığı</td>
      <td>Modüller sıkı bağlı olabilir</td>
      <td>Servisler API ile konuşur</td>
    </tr>
    <tr>
      <td>Hata etkisi</td>
      <td>Tek hata geniş alanı etkileyebilir</td>
      <td>Hata izole edilebilir</td>
    </tr>
    <tr>
      <td>Başlangıç maliyeti</td>
      <td>Daha düşüktür</td>
      <td>Daha fazla planlama ister</td>
    </tr>
  </tbody>
</table>

<p>PHP ile mikro servis yazmak için illa devasa framework kullanmak zorunda değilsiniz. Laravel, Symfony veya Slim gibi frameworkler servis geliştirmeyi kolaylaştırır. Önemli olan servis sınırlarını doğru çizmektir. Örneğin bir e-ticaret sisteminde şu servisler olabilir:</p>

<ul>
  <li><strong>User Service:</strong> kullanıcı kaydı, giriş, yetkilendirme</li>
  <li><strong>Catalog Service:</strong> ürün ve kategori yönetimi</li>
  <li><strong>Order Service:</strong> sipariş oluşturma ve durum takibi</li>
  <li><strong>Payment Service:</strong> ödeme alma ve doğrulama</li>
  <li><strong>Notification Service:</strong> e-posta, SMS, push bildirimleri</li>
</ul>

<p>Servisler genellikle HTTP/REST, gRPC veya mesaj kuyrukları üzerinden haberleşir. PHP tarafında basit bir REST endpoint şöyle görünebilir:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span>

<span class="k">require</span> <span class="s1">'vendor/autoload.php'</span><span class="p">;</span>

<span class="kn">use</span> <span class="nc">Slim\Factory\AppFactory</span><span class="p">;</span>

<span class="nv">$app</span> <span class="o">=</span> <span class="nc">AppFactory</span><span class="o">::</span><span class="nf">create</span><span class="p">();</span>

<span class="nv">$app</span><span class="o">-&gt;</span><span class="nf">get</span><span class="p">(</span><span class="s1">'/users/{id}'</span><span class="p">,</span> <span class="k">function</span> <span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$response</span><span class="p">,</span> <span class="nv">$args</span><span class="p">)</span> <span class="p">{</span>
    <span class="nv">$userId</span> <span class="o">=</span> <span class="p">(</span><span class="n">int</span><span class="p">)</span> <span class="nv">$args</span><span class="p">[</span><span class="s1">'id'</span><span class="p">];</span>

    <span class="nv">$data</span> <span class="o">=</span> <span class="p">[</span>
        <span class="s1">'id'</span> <span class="o">=&gt;</span> <span class="nv">$userId</span><span class="p">,</span>
        <span class="s1">'name'</span> <span class="o">=&gt;</span> <span class="s1">'Ada Lovelace'</span><span class="p">,</span>
        <span class="s1">'role'</span> <span class="o">=&gt;</span> <span class="s1">'admin'</span>
    <span class="p">];</span>

    <span class="nv">$response</span><span class="o">-&gt;</span><span class="nf">getBody</span><span class="p">()</span><span class="o">-&gt;</span><span class="nf">write</span><span class="p">(</span><span class="nb">json_encode</span><span class="p">(</span><span class="nv">$data</span><span class="p">));</span>
    <span class="k">return</span> <span class="nv">$response</span><span class="o">-&gt;</span><span class="nf">withHeader</span><span class="p">(</span><span class="s1">'Content-Type'</span><span class="p">,</span> <span class="s1">'application/json'</span><span class="p">);</span>
<span class="p">});</span>

<span class="nv">$app</span><span class="o">-&gt;</span><span class="nf">run</span><span class="p">();</span>
</code></pre></div></div>

<p>Bu örnekte küçük bir kullanıcı servisi, <code class="language-plaintext highlighter-rouge">/users/{id}</code> adresinden JSON veri döndürür. Gerçek dünyada burada veritabanı bağlantısı, doğrulama, loglama ve hata yönetimi de bulunur. Ama temel fikir basittir: servis tek bir sorumluluğa odaklanır.</p>

<p>Mikro servislerde en kritik konulardan biri veri yönetimidir. Her servisin kendi veritabanına sahip olması önerilir. Çünkü ortak veritabanı kullanılırsa servisler görünmez şekilde birbirine bağlanır. Bu durum mikro servis görünümünde monolit üretir; yani tabelada mikro servis yazar ama içeride herkes aynı mutfağı kullanır.</p>

<table>
  <thead>
    <tr>
      <th>Veri Yaklaşımı</th>
      <th>Avantaj</th>
      <th>Risk</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Ortak veritabanı</td>
      <td>Başlangıçta kolaydır</td>
      <td>Servis bağımsızlığını bozar</td>
    </tr>
    <tr>
      <td>Servis başına veritabanı</td>
      <td>Gevşek bağlılık sağlar</td>
      <td>Veri senkronizasyonu gerekir</td>
    </tr>
    <tr>
      <td>Event-driven yapı</td>
      <td>Esnek ve ölçeklenebilir</td>
      <td>İzleme ve hata ayıklama zorlaşır</td>
    </tr>
  </tbody>
</table>

<p>Örneğin ödeme tamamlandığında Payment Service, <code class="language-plaintext highlighter-rouge">payment.completed</code> adlı bir olay yayınlayabilir. Order Service bu olayı dinleyip sipariş durumunu günceller. Böylece servisler birbirini doğrudan çağırmak zorunda kalmaz. Bu modelde sistemin toplam güvenilirliği için basitçe $R_{sistem} = R_1 \times R_2 \times … \times R_n$ gibi düşünebiliriz. Servis sayısı arttıkça gözlemleme, retry ve circuit breaker gibi mekanizmalar daha önemli hale gelir.</p>

<p>PHP ekosisteminde RabbitMQ, Redis Streams veya Kafka ile olay tabanlı iletişim kurulabilir. Docker ise her servisi ayrı konteyner olarak çalıştırmak için neredeyse standarttır. Böylece User Service PHP 8.3 ile, Notification Service farklı bağımlılıklarla çalışabilir.</p>

<p>Sonuç olarak PHP ile mikro servis mimarisi, büyük uygulamaları daha yönetilebilir hale getirmek için güçlü bir yaklaşımdır. Ancak her projeye otomatik olarak uygulanmamalıdır. Küçük bir uygulamada monolit daha hızlı ve ekonomiktir. Mikro servis, ekip büyüdüğünde, domain sınırları netleştiğinde ve bağımsız ölçekleme ihtiyacı doğduğunda parlamaya başlar. Kısacası önce problemi büyütün, sonra mimariyi bölün; yoksa mikro servis değil, mikro kaos üretirsiniz.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="PHP" /><category term="Mikro Servis" /><category term="Yazılım Mimarisi" /><summary type="html"><![CDATA[Büyük bir PHP uygulaması zamanla dev bir apartmana dönüşebilir: kullanıcı yönetimi bir katta, ödeme sistemi başka katta, raporlama bodrumda, bildirimler ise çatı arasında çalışır. Her şey aynı kod tabanındaysa küçük bir değişiklik bile tüm binayı sallayabilir. Mikro servis mimarisi, bu apartmanı bağımsız küçük evlere ayırma fikridir. Her servis belirli bir iş yapar, kendi yaşam döngüsüne sahip olur ve gerektiğinde tek başına geliştirilip ölçeklenebilir.]]></summary></entry><entry><title type="html">Python ile Matematiksel Ağırlıklı Otomatik Makale Özetleyici</title><link href="https://sonsuzus.github.io/posts/python-ile-matematiksel-agirlikli-otomatik-makale-ozetleyici/" rel="alternate" type="text/html" title="Python ile Matematiksel Ağırlıklı Otomatik Makale Özetleyici" /><published>2026-07-17T00:00:00+00:00</published><updated>2026-07-17T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/python-ile-matematiksel-agirlikli-otomatik-makale-ozetleyici</id><content type="html" xml:base="https://sonsuzus.github.io/posts/python-ile-matematiksel-agirlikli-otomatik-makale-ozetleyici/"><![CDATA[<p>Uzun bir makaleyi okumadan önce “bana özü ver” demek, modern yazılımcının kahve istemesi kadar doğal hale geldi. Python ile geliştireceğimiz otomatik özetleyici, metindeki cümleleri matematiksel olarak puanlayıp en önemli olanları seçer. Yani modelimiz metni yeniden yazmaz; metnin içinden en temsilî cümleleri avlar. Bu yönteme çıkarımsal özetleme denir ve haberlerden akademik yazılara kadar birçok alanda oldukça kullanışlıdır.</p>

<p>``</p>

<h2 id="fikir-her-cümle-bir-adaydır">Fikir: Her Cümle Bir Adaydır</h2>

<p>Bir makaleyi cümlelere böldüğümüzde aslında elimizde küçük aday özet parçaları oluşur. Amacımız, her cümleye bir önem puanı vermektir. Bu puan; kelime sıklığı, cümlenin konumu ve metnin genel temasına benzerliği gibi sinyallerden oluşabilir.</p>

<p>Basit bir ağırlık formülü şöyle düşünülebilir:</p>

<p>$score(s)=0.5 \times freq(s)+0.3 \times sim(s)+0.2 \times pos(s)$</p>

<p>Burada $freq(s)$ cümlede geçen önemli kelimelerin toplam ağırlığıdır. $sim(s)$ cümlenin tüm belge vektörüne benzerliğini, $pos(s)$ ise cümlenin metindeki stratejik konumunu temsil eder. Örneğin giriş ve sonuç bölümlerindeki cümleler çoğu zaman daha bilgilendiricidir.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Ne Ölçer?</th>
      <th>Neden Önemli?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kelime sıklığı</td>
      <td>Anahtar kelimelerin yoğunluğu</td>
      <td>Konunun merkezini yakalar</td>
    </tr>
    <tr>
      <td>Kosinüs benzerliği</td>
      <td>Cümle ile belge arasındaki yakınlık</td>
      <td>Temsil gücünü ölçer</td>
    </tr>
    <tr>
      <td>Konum puanı</td>
      <td>Cümlenin metindeki yeri</td>
      <td>Giriş/sonuç etkisini hesaba katar</td>
    </tr>
  </tbody>
</table>

<h2 id="teorik-altyapı-tf-idf-ve-kosinüs-benzerliği">Teorik Altyapı: TF-IDF ve Kosinüs Benzerliği</h2>

<p>Kelime saymak tek başına yeterli değildir. “ve”, “bir”, “ile” gibi kelimeler çok geçer ama anlam taşıma güçleri düşüktür. Bu yüzden TF-IDF kullanırız. TF, bir kelimenin cümlede ne kadar sık geçtiğini; IDF ise o kelimenin tüm cümleler arasında ne kadar ayırt edici olduğunu gösterir.</p>

<p>Matematiksel olarak:</p>

<p>$tfidf(t,d)=tf(t,d) \times idf(t)$</p>

<p>Bir cümleyi ve tüm belgeyi vektör olarak düşündüğümüzde, aralarındaki açı bize benzerliği verir:</p>

<p>$cos(\theta)=\frac{A \cdot B}{|A||B|}$</p>

<p>Açı küçüldükçe benzerlik artar. Yani cümle, makalenin genel fikrine yaklaşıyorsa özet için güçlü bir adaydır.</p>

<h2 id="python-ile-orta-seviye-bir-uygulama">Python ile Orta Seviye Bir Uygulama</h2>

<p>Aşağıdaki kod, metni cümlelere ayırır, TF-IDF matrisi üretir, her cümleyi belge ortalamasıyla karşılaştırır ve en yüksek puanlı cümleleri seçer.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">re</span>
<span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">from</span> <span class="n">sklearn.feature_extraction.text</span> <span class="kn">import</span> <span class="n">TfidfVectorizer</span>
<span class="kn">from</span> <span class="n">sklearn.metrics.pairwise</span> <span class="kn">import</span> <span class="n">cosine_similarity</span>

<span class="n">STOPWORDS</span> <span class="o">=</span> <span class="p">{</span><span class="sh">'</span><span class="s">ve</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">ile</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">bir</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">bu</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">da</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">de</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">için</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">gibi</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">çok</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">ama</span><span class="sh">'</span><span class="p">}</span>

<span class="k">def</span> <span class="nf">split_sentences</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
    <span class="n">sentences</span> <span class="o">=</span> <span class="n">re</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="sa">r</span><span class="sh">'</span><span class="s">(?&lt;=[.!?]) +</span><span class="sh">'</span><span class="p">,</span> <span class="n">text</span><span class="p">.</span><span class="nf">strip</span><span class="p">())</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">s</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">sentences</span> <span class="k">if</span> <span class="nf">len</span><span class="p">(</span><span class="n">s</span><span class="p">.</span><span class="nf">split</span><span class="p">())</span> <span class="o">&gt;</span> <span class="mi">4</span><span class="p">]</span>

<span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="n">sentence</span><span class="p">):</span>
    <span class="n">sentence</span> <span class="o">=</span> <span class="n">sentence</span><span class="p">.</span><span class="nf">lower</span><span class="p">()</span>
    <span class="n">sentence</span> <span class="o">=</span> <span class="n">re</span><span class="p">.</span><span class="nf">sub</span><span class="p">(</span><span class="sa">r</span><span class="sh">'</span><span class="s">[^a-zA-ZçğıöşüÇĞİÖŞÜ0-9 ]</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s"> </span><span class="sh">'</span><span class="p">,</span> <span class="n">sentence</span><span class="p">)</span>
    <span class="n">words</span> <span class="o">=</span> <span class="p">[</span><span class="n">w</span> <span class="k">for</span> <span class="n">w</span> <span class="ow">in</span> <span class="n">sentence</span><span class="p">.</span><span class="nf">split</span><span class="p">()</span> <span class="k">if</span> <span class="n">w</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">STOPWORDS</span><span class="p">]</span>
    <span class="k">return</span> <span class="sh">'</span><span class="s"> </span><span class="sh">'</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">words</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">summarize</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">ratio</span><span class="o">=</span><span class="mf">0.3</span><span class="p">):</span>
    <span class="n">sentences</span> <span class="o">=</span> <span class="nf">split_sentences</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
    <span class="n">cleaned</span> <span class="o">=</span> <span class="p">[</span><span class="nf">clean</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">sentences</span><span class="p">]</span>

    <span class="n">vectorizer</span> <span class="o">=</span> <span class="nc">TfidfVectorizer</span><span class="p">()</span>
    <span class="n">matrix</span> <span class="o">=</span> <span class="n">vectorizer</span><span class="p">.</span><span class="nf">fit_transform</span><span class="p">(</span><span class="n">cleaned</span><span class="p">)</span>

    <span class="n">document_vector</span> <span class="o">=</span> <span class="n">matrix</span><span class="p">.</span><span class="nf">mean</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
    <span class="n">similarities</span> <span class="o">=</span> <span class="nf">cosine_similarity</span><span class="p">(</span><span class="n">matrix</span><span class="p">,</span> <span class="n">document_vector</span><span class="p">)</span>

    <span class="n">scores</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="n">n</span> <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">sentences</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">sim</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">similarities</span><span class="p">.</span><span class="nf">flatten</span><span class="p">()):</span>
        <span class="n">position_score</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">-</span> <span class="p">(</span><span class="n">i</span> <span class="o">/</span> <span class="nf">max</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> <span class="o">*</span> <span class="mf">0.3</span>
        <span class="n">final_score</span> <span class="o">=</span> <span class="mf">0.8</span> <span class="o">*</span> <span class="n">sim</span> <span class="o">+</span> <span class="mf">0.2</span> <span class="o">*</span> <span class="n">position_score</span>
        <span class="n">scores</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">final_score</span><span class="p">))</span>

    <span class="n">count</span> <span class="o">=</span> <span class="nf">max</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nf">int</span><span class="p">(</span><span class="n">n</span> <span class="o">*</span> <span class="n">ratio</span><span class="p">))</span>
    <span class="n">selected</span> <span class="o">=</span> <span class="nf">sorted</span><span class="p">(</span><span class="n">scores</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">reverse</span><span class="o">=</span><span class="bp">True</span><span class="p">)[:</span><span class="n">count</span><span class="p">]</span>
    <span class="n">selected_indexes</span> <span class="o">=</span> <span class="nf">sorted</span><span class="p">(</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">score</span> <span class="ow">in</span> <span class="n">selected</span><span class="p">)</span>

    <span class="k">return</span> <span class="sh">'</span><span class="s"> </span><span class="sh">'</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">sentences</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">selected_indexes</span><span class="p">)</span>
</code></pre></div></div>

<p>Kodda <code class="language-plaintext highlighter-rouge">TfidfVectorizer</code>, her cümleyi sayısal bir vektöre dönüştürür. <code class="language-plaintext highlighter-rouge">document_vector</code>, bütün metnin ortalama anlam merkezidir. Her cümle bu merkeze ne kadar yakınsa, <code class="language-plaintext highlighter-rouge">cosine_similarity</code> sonucu o kadar yüksek çıkar. Son olarak, skorlar büyükten küçüğe sıralanır; seçilen cümleler orijinal sırasına göre birleştirilir. Böylece özet, hem anlamlı hem de okunabilir kalır.</p>

<h2 id="çıkarımsal-ve-soyutlayıcı-özetleme">Çıkarımsal ve Soyutlayıcı Özetleme</h2>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Nasıl Çalışır?</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Çıkarımsal</td>
      <td>Metinden cümle seçer</td>
      <td>Hızlı ve güvenilir</td>
      <td>Yeni cümle kuramaz</td>
    </tr>
    <tr>
      <td>Soyutlayıcı</td>
      <td>Metni yeniden yazar</td>
      <td>İnsan gibi özetler</td>
      <td>Daha maliyetli ve riskli</td>
    </tr>
  </tbody>
</table>

<p>Bu projede çıkarımsal yöntemi seçmemizin sebebi, daha anlaşılır ve kontrol edilebilir olmasıdır. Özellikle ilk NLP projeleri için harika bir başlangıçtır.</p>

<h2 id="geliştirme-fikirleri">Geliştirme Fikirleri</h2>

<p>Bu aracı daha akıllı hale getirmek için Türkçe kök bulma, özel isim tanıma veya başlık ağırlığı eklenebilir. Ayrıca <code class="language-plaintext highlighter-rouge">sentence-transformers</code> gibi modellerle cümleleri bağlamsal vektörlere çevirerek daha güçlü benzerlik hesapları yapılabilir.</p>

<p>Sonuç olarak, otomatik özetleme sadece “kısaltma” işi değildir; metnin matematiksel haritasını çıkarma sanatıdır. Python ise bu haritayı çizmek için oldukça eğlenceli bir pusula sunar.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="Python" /><category term="Doğal Dil İşleme" /><category term="Otomatik Özetleme" /><summary type="html"><![CDATA[Uzun bir makaleyi okumadan önce “bana özü ver” demek, modern yazılımcının kahve istemesi kadar doğal hale geldi. Python ile geliştireceğimiz otomatik özetleyici, metindeki cümleleri matematiksel olarak puanlayıp en önemli olanları seçer. Yani modelimiz metni yeniden yazmaz; metnin içinden en temsilî cümleleri avlar. Bu yönteme çıkarımsal özetleme denir ve haberlerden akademik yazılara kadar birçok alanda oldukça kullanışlıdır.]]></summary></entry><entry><title type="html">SQL ile Anomali Tespiti: Log Denizinde Garip Balıkları Yakalamak</title><link href="https://sonsuzus.github.io/posts/sql-ile-anomali-tespiti-log-denizinde-garip-baliklari-yakalamak/" rel="alternate" type="text/html" title="SQL ile Anomali Tespiti: Log Denizinde Garip Balıkları Yakalamak" /><published>2026-07-17T00:00:00+00:00</published><updated>2026-07-17T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/sql-ile-anomali-tespiti-log-denizinde-garip-baliklari-yakalamak</id><content type="html" xml:base="https://sonsuzus.github.io/posts/sql-ile-anomali-tespiti-log-denizinde-garip-baliklari-yakalamak/"><![CDATA[<p>Sistem logları bazen sakin bir göl, bazen de üretim ortamında patlayan bir mısır tenceresi gibidir. Milyonlarca satır arasında “bir şeyler ters gidiyor” hissini elle aramak yerine, SQL ile olağandışı örüntüleri yakalayabiliriz. Üstelik bunun için her zaman dev bir yapay zekâ modeli gerekmez; iyi kurulmuş istatistiksel mantık, pencere fonksiyonları ve birkaç akıllı sorgu çoğu alarm zilini çaldırmaya yeter.</p>

<p>``</p>

<p>Anomali tespiti, verinin beklenen davranıştan anlamlı biçimde sapmasını bulma işidir. Log dünyasında bu sapma; hata sayısında ani artış, belirli bir servisin alışılmadık gecikmesi, tek bir IP’den anormal istek yağması veya normalde hiç görülmeyen hata kodlarının ortaya çıkması olabilir. Temel fikir şudur: Önce “normal” davranışı tanımlarız, sonra güncel değerin bu normale ne kadar uzaklaştığını ölçeriz.</p>

<p>En yaygın yöntemlerden biri z-skorudur. Bir ölçümün ortalamadan kaç standart sapma uzakta olduğunu gösterir:</p>

\[z = \frac{x - \mu}{\sigma}\]

<p>Burada $x$ gözlenen değer, $\mu$ geçmiş ortalama, $\sigma$ ise standart sapmadır. Örneğin bir serviste dakikada ortalama 20 hata varken standart sapma 5 ise, 45 hata geldiğinde $z = 5$ olur. Bu, “dostum burada bir şey yanıyor olabilir” demenin matematiksel hâlidir.</p>

<table>
  <thead>
    <tr>
      <th>Anomali Türü</th>
      <th>Log Örneği</th>
      <th>SQL ile Yaklaşım</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Noktasal anomali</td>
      <td>Bir dakikada 500 hata</td>
      <td>Ortalama ve standart sapma karşılaştırması</td>
    </tr>
    <tr>
      <td>Bağlamsal anomali</td>
      <td>Gece 03:00’te normal, öğlen anormal trafik</td>
      <td>Saat/gün bazlı gruplama</td>
    </tr>
    <tr>
      <td>Kolektif anomali</td>
      <td>Art arda gelen küçük timeout zinciri</td>
      <td>Pencere fonksiyonları ve hareketli toplam</td>
    </tr>
  </tbody>
</table>

<p>Diyelim ki elimizde <code class="language-plaintext highlighter-rouge">app_logs</code> adlı bir tablo var: <code class="language-plaintext highlighter-rouge">ts</code>, <code class="language-plaintext highlighter-rouge">service_name</code>, <code class="language-plaintext highlighter-rouge">level</code>, <code class="language-plaintext highlighter-rouge">status_code</code>, <code class="language-plaintext highlighter-rouge">duration_ms</code>, <code class="language-plaintext highlighter-rouge">message</code>. İlk hedefimiz, her servis için dakikalık hata sayılarını çıkarmak olsun.</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">WITH</span> <span class="n">minute_errors</span> <span class="k">AS</span> <span class="p">(</span>
  <span class="k">SELECT</span>
    <span class="n">DATE_TRUNC</span><span class="p">(</span><span class="s1">'minute'</span><span class="p">,</span> <span class="n">ts</span><span class="p">)</span> <span class="k">AS</span> <span class="n">minute_bucket</span><span class="p">,</span>
    <span class="n">service_name</span><span class="p">,</span>
    <span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="k">AS</span> <span class="n">error_count</span>
  <span class="k">FROM</span> <span class="n">app_logs</span>
  <span class="k">WHERE</span> <span class="k">level</span> <span class="o">=</span> <span class="s1">'ERROR'</span>
  <span class="k">GROUP</span> <span class="k">BY</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span>
<span class="p">)</span>
<span class="k">SELECT</span> <span class="o">*</span>
<span class="k">FROM</span> <span class="n">minute_errors</span>
<span class="k">ORDER</span> <span class="k">BY</span> <span class="n">minute_bucket</span> <span class="k">DESC</span><span class="p">;</span>
</code></pre></div></div>

<p>Bu sorgu ham logları daha anlamlı bir zaman serisine dönüştürür. Anomali tespitinde ilk büyük adım genellikle budur: Gürültülü satırları ölçülebilir metriklere çevirmek.</p>

<p>Şimdi geçmiş davranışı kullanarak z-skoru hesaplayalım. Aşağıdaki örnek PostgreSQL sözdizimine yakındır ve her servis için genel ortalama ile standart sapmayı çıkarır.</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">WITH</span> <span class="n">minute_errors</span> <span class="k">AS</span> <span class="p">(</span>
  <span class="k">SELECT</span>
    <span class="n">DATE_TRUNC</span><span class="p">(</span><span class="s1">'minute'</span><span class="p">,</span> <span class="n">ts</span><span class="p">)</span> <span class="k">AS</span> <span class="n">minute_bucket</span><span class="p">,</span>
    <span class="n">service_name</span><span class="p">,</span>
    <span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="k">AS</span> <span class="n">error_count</span>
  <span class="k">FROM</span> <span class="n">app_logs</span>
  <span class="k">WHERE</span> <span class="k">level</span> <span class="o">=</span> <span class="s1">'ERROR'</span>
  <span class="k">GROUP</span> <span class="k">BY</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span>
<span class="p">),</span> <span class="n">baseline</span> <span class="k">AS</span> <span class="p">(</span>
  <span class="k">SELECT</span>
    <span class="n">service_name</span><span class="p">,</span>
    <span class="k">AVG</span><span class="p">(</span><span class="n">error_count</span><span class="p">)</span> <span class="k">AS</span> <span class="n">avg_errors</span><span class="p">,</span>
    <span class="n">STDDEV</span><span class="p">(</span><span class="n">error_count</span><span class="p">)</span> <span class="k">AS</span> <span class="n">std_errors</span>
  <span class="k">FROM</span> <span class="n">minute_errors</span>
  <span class="k">WHERE</span> <span class="n">minute_bucket</span> <span class="o">&lt;</span> <span class="n">NOW</span><span class="p">()</span> <span class="o">-</span> <span class="n">INTERVAL</span> <span class="s1">'15 minutes'</span>
  <span class="k">GROUP</span> <span class="k">BY</span> <span class="n">service_name</span>
<span class="p">)</span>
<span class="k">SELECT</span>
  <span class="n">m</span><span class="p">.</span><span class="n">minute_bucket</span><span class="p">,</span>
  <span class="n">m</span><span class="p">.</span><span class="n">service_name</span><span class="p">,</span>
  <span class="n">m</span><span class="p">.</span><span class="n">error_count</span><span class="p">,</span>
  <span class="n">ROUND</span><span class="p">((</span><span class="n">m</span><span class="p">.</span><span class="n">error_count</span> <span class="o">-</span> <span class="n">b</span><span class="p">.</span><span class="n">avg_errors</span><span class="p">)</span> <span class="o">/</span> <span class="k">NULLIF</span><span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="n">std_errors</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mi">2</span><span class="p">)</span> <span class="k">AS</span> <span class="n">z_score</span>
<span class="k">FROM</span> <span class="n">minute_errors</span> <span class="n">m</span>
<span class="k">JOIN</span> <span class="n">baseline</span> <span class="n">b</span> <span class="k">USING</span> <span class="p">(</span><span class="n">service_name</span><span class="p">)</span>
<span class="k">WHERE</span> <span class="n">m</span><span class="p">.</span><span class="n">minute_bucket</span> <span class="o">&gt;=</span> <span class="n">NOW</span><span class="p">()</span> <span class="o">-</span> <span class="n">INTERVAL</span> <span class="s1">'15 minutes'</span>
  <span class="k">AND</span> <span class="p">(</span><span class="n">m</span><span class="p">.</span><span class="n">error_count</span> <span class="o">-</span> <span class="n">b</span><span class="p">.</span><span class="n">avg_errors</span><span class="p">)</span> <span class="o">/</span> <span class="k">NULLIF</span><span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="n">std_errors</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">3</span>
<span class="k">ORDER</span> <span class="k">BY</span> <span class="n">z_score</span> <span class="k">DESC</span><span class="p">;</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">NULLIF</code> küçük ama hayat kurtaran bir detaydır; standart sapma sıfırsa bölme hatasını engeller. <code class="language-plaintext highlighter-rouge">z_score &gt; 3</code> eşiği klasik bir başlangıç noktasıdır, fakat her sistem için kutsal değildir. Ödeme sisteminde eşik daha hassas, test ortamında daha gevşek olabilir.</p>

<p>Bazı durumlarda genel ortalama yanıltıcıdır. Pazartesi sabahı trafiği ile pazar gecesi trafiği aynı kefeye konmaz. Bu yüzden bağlamsal baz çizgiler kullanmak daha sağlıklıdır.</p>

<table>
  <thead>
    <tr>
      <th>Baseline Yöntemi</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Genel ortalama</td>
      <td>Basit ve hızlı</td>
      <td>Saatlik/dönemsel farkları kaçırır</td>
    </tr>
    <tr>
      <td>Saat bazlı ortalama</td>
      <td>Gün içi ritmi yakalar</td>
      <td>Daha fazla veri ister</td>
    </tr>
    <tr>
      <td>Hareketli pencere</td>
      <td>Güncel davranışa uyum sağlar</td>
      <td>Ani anomalileri baseline’a katabilir</td>
    </tr>
  </tbody>
</table>

<p>Gecikme anomalileri için yüzdelikler de çok değerlidir. Ortalama bazen aldatır; birkaç aşırı yavaş istek ortalamayı şişirebilir. Bu yüzden p95 veya p99 gibi değerler kullanılır.</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span>
  <span class="n">DATE_TRUNC</span><span class="p">(</span><span class="s1">'minute'</span><span class="p">,</span> <span class="n">ts</span><span class="p">)</span> <span class="k">AS</span> <span class="n">minute_bucket</span><span class="p">,</span>
  <span class="n">service_name</span><span class="p">,</span>
  <span class="n">PERCENTILE_CONT</span><span class="p">(</span><span class="mi">0</span><span class="p">.</span><span class="mi">95</span><span class="p">)</span> <span class="n">WITHIN</span> <span class="k">GROUP</span> <span class="p">(</span><span class="k">ORDER</span> <span class="k">BY</span> <span class="n">duration_ms</span><span class="p">)</span> <span class="k">AS</span> <span class="n">p95_latency</span>
<span class="k">FROM</span> <span class="n">app_logs</span>
<span class="k">GROUP</span> <span class="k">BY</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span>
<span class="k">HAVING</span> <span class="n">PERCENTILE_CONT</span><span class="p">(</span><span class="mi">0</span><span class="p">.</span><span class="mi">95</span><span class="p">)</span> <span class="n">WITHIN</span> <span class="k">GROUP</span> <span class="p">(</span><span class="k">ORDER</span> <span class="k">BY</span> <span class="n">duration_ms</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1000</span>
<span class="k">ORDER</span> <span class="k">BY</span> <span class="n">minute_bucket</span> <span class="k">DESC</span><span class="p">;</span>
</code></pre></div></div>

<p>Bu sorgu, isteklerin yüzde 95’inin altında kaldığı gecikme değerini bulur. Eğer p95 1000 ms üstüne çıkıyorsa kullanıcıların ciddi bir kısmı yavaşlık hissediyor olabilir.</p>

<p>Son olarak, SQL ile anomali tespiti sadece alarm üretmek değildir; açıklanabilirlik de sağlar. “Bir model söyledi” yerine “son 15 dakikada <code class="language-plaintext highlighter-rouge">payment-api</code> hata sayısı normalin 4.7 standart sapma üstüne çıktı” diyebilirsiniz. Bu da hem geliştiricinin hem SRE ekibinin hızlı aksiyon almasını kolaylaştırır.</p>

<p>Özetle SQL, log okyanusunda el feneri gibidir. Doğru gruplama, istatistiksel eşikler, pencere fonksiyonları ve bağlamsal düşünme ile beklenmeyen sistem hatalarını üretim ortamı yangına dönmeden yakalayabilirsiniz.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="SQL" /><category term="anomali tespiti" /><category term="log analizi" /><category term="veri analizi" /><summary type="html"><![CDATA[Sistem logları bazen sakin bir göl, bazen de üretim ortamında patlayan bir mısır tenceresi gibidir. Milyonlarca satır arasında “bir şeyler ters gidiyor” hissini elle aramak yerine, SQL ile olağandışı örüntüleri yakalayabiliriz. Üstelik bunun için her zaman dev bir yapay zekâ modeli gerekmez; iyi kurulmuş istatistiksel mantık, pencere fonksiyonları ve birkaç akıllı sorgu çoğu alarm zilini çaldırmaya yeter.]]></summary></entry><entry><title type="html">C++ ile Genetik Algoritmalar: Evrimi Kodla, Çözümü Seç</title><link href="https://sonsuzus.github.io/posts/c-ile-genetik-algoritmalar-evrimi-kodla-cozumu-sec/" rel="alternate" type="text/html" title="C++ ile Genetik Algoritmalar: Evrimi Kodla, Çözümü Seç" /><published>2026-07-16T00:00:00+00:00</published><updated>2026-07-16T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/c-ile-genetik-algoritmalar-evrimi-kodla-cozumu-sec</id><content type="html" xml:base="https://sonsuzus.github.io/posts/c-ile-genetik-algoritmalar-evrimi-kodla-cozumu-sec/"><![CDATA[<p>Bir problemi çözmeye çalışırken bazen “en iyi” cevabı doğrudan hesaplamak zordur; özellikle seçenek sayısı devasa ise klasik yöntemler yorulabilir. İşte genetik algoritmalar burada sahneye çıkar: Doğadaki seçilim, çaprazlama ve mutasyon fikrini taklit ederek veri havuzundaki aday çözümleri nesilden nesle iyileştirir. C++ ise performansı ve bellek kontrolü sayesinde bu evrimsel deneyi hızlıca çalıştırmak için harika bir araçtır.</p>

<p>``</p>

<p>Genetik algoritmanın temel fikri şudur: Elimizde bir <strong>popülasyon</strong> vardır. Popülasyondaki her birey, olası bir çözümü temsil eder. Bu bireylere çoğu zaman <strong>kromozom</strong> denir. Kromozom; bit dizisi, sayı vektörü, rota listesi veya başka bir veri yapısı olabilir. Her kromozomun başarısı bir <strong>uygunluk fonksiyonu</strong> ile ölçülür. Amaç, uygunluğu yüksek bireyleri seçip melezlemek ve zamanla daha iyi çözümler üretmektir.</p>

<p>Matematiksel olarak bir optimizasyon probleminde amaç genellikle şu biçimdedir:</p>

\[\max_{x \in S} f(x)\]

<p>Burada $S$ çözüm uzayı, $x$ aday çözüm, $f(x)$ ise uygunluk değeridir. Genetik algoritma, $S$ içinde tek tek tüm noktaları gezmek yerine “umut vadeden bölgeleri” keşfetmeye çalışır. Biraz dedektif, biraz çiftçi, biraz da çılgın bilim insanı gibi davranır.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Doğadaki Karşılığı</th>
      <th>Algoritmadaki Anlamı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Popülasyon</td>
      <td>Canlı topluluğu</td>
      <td>Aday çözümler kümesi</td>
    </tr>
    <tr>
      <td>Kromozom</td>
      <td>Genetik yapı</td>
      <td>Çözüm temsili</td>
    </tr>
    <tr>
      <td>Uygunluk</td>
      <td>Hayatta kalma başarısı</td>
      <td>Amaç fonksiyonu skoru</td>
    </tr>
    <tr>
      <td>Çaprazlama</td>
      <td>Üreme</td>
      <td>İki çözümden yeni çözüm üretme</td>
    </tr>
    <tr>
      <td>Mutasyon</td>
      <td>Gen değişimi</td>
      <td>Rastgele küçük değişiklik</td>
    </tr>
  </tbody>
</table>

<p>Basit bir örnek düşünelim: 0 ve 1’lerden oluşan 20 bitlik bir dizide mümkün olduğunca çok 1 elde etmek istiyoruz. Bu, eğitim amaçlı “OneMax” problemidir. Uygunluk fonksiyonu, kromozomdaki 1 sayısıdır. Yani $f(x)=\sum x_i$. Kulağa kolay geliyor ama aynı yapı, daha zor problemlerde rota optimizasyonu, çizelgeleme veya parametre ayarlama için de kullanılabilir.</p>

<p>Aşağıdaki C++ kodu orta düzey bir iskelet sunar. Popülasyon oluşturur, uygunluk hesaplar, turnuva seçimi yapar, çaprazlama ve mutasyon uygular:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;bits/stdc++.h&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">const</span> <span class="kt">int</span> <span class="n">GENE_LENGTH</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">POP_SIZE</span> <span class="o">=</span> <span class="mi">50</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">GENERATIONS</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">double</span> <span class="n">MUTATION_RATE</span> <span class="o">=</span> <span class="mf">0.02</span><span class="p">;</span>

<span class="n">mt19937</span> <span class="nf">rng</span><span class="p">(</span><span class="n">random_device</span><span class="p">{}());</span>

<span class="k">using</span> <span class="n">Chromosome</span> <span class="o">=</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">fitness</span><span class="p">(</span><span class="k">const</span> <span class="n">Chromosome</span><span class="o">&amp;</span> <span class="n">c</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">accumulate</span><span class="p">(</span><span class="n">c</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">c</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">Chromosome</span> <span class="nf">randomChromosome</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">uniform_int_distribution</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">bit</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">Chromosome</span> <span class="n">c</span><span class="p">(</span><span class="n">GENE_LENGTH</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span><span class="o">&amp;</span> <span class="n">gene</span> <span class="o">:</span> <span class="n">c</span><span class="p">)</span> <span class="n">gene</span> <span class="o">=</span> <span class="n">bit</span><span class="p">(</span><span class="n">rng</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">c</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">Chromosome</span> <span class="nf">tournamentSelect</span><span class="p">(</span><span class="k">const</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">Chromosome</span><span class="o">&gt;&amp;</span> <span class="n">pop</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">uniform_int_distribution</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">dist</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">POP_SIZE</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">Chromosome</span> <span class="n">a</span> <span class="o">=</span> <span class="n">pop</span><span class="p">[</span><span class="n">dist</span><span class="p">(</span><span class="n">rng</span><span class="p">)];</span>
    <span class="n">Chromosome</span> <span class="n">b</span> <span class="o">=</span> <span class="n">pop</span><span class="p">[</span><span class="n">dist</span><span class="p">(</span><span class="n">rng</span><span class="p">)];</span>
    <span class="k">return</span> <span class="n">fitness</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">fitness</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">?</span> <span class="n">a</span> <span class="o">:</span> <span class="n">b</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">Chromosome</span> <span class="nf">crossover</span><span class="p">(</span><span class="k">const</span> <span class="n">Chromosome</span><span class="o">&amp;</span> <span class="n">p1</span><span class="p">,</span> <span class="k">const</span> <span class="n">Chromosome</span><span class="o">&amp;</span> <span class="n">p2</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">uniform_int_distribution</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">pointDist</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">GENE_LENGTH</span> <span class="o">-</span> <span class="mi">2</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">point</span> <span class="o">=</span> <span class="n">pointDist</span><span class="p">(</span><span class="n">rng</span><span class="p">);</span>
    <span class="n">Chromosome</span> <span class="n">child</span><span class="p">(</span><span class="n">GENE_LENGTH</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">GENE_LENGTH</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
        <span class="n">child</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">point</span><span class="p">)</span> <span class="o">?</span> <span class="n">p1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">:</span> <span class="n">p2</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
    <span class="k">return</span> <span class="n">child</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">mutate</span><span class="p">(</span><span class="n">Chromosome</span><span class="o">&amp;</span> <span class="n">c</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">uniform_real_distribution</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span> <span class="n">prob</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span><span class="o">&amp;</span> <span class="n">gene</span> <span class="o">:</span> <span class="n">c</span><span class="p">)</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">prob</span><span class="p">(</span><span class="n">rng</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">MUTATION_RATE</span><span class="p">)</span> <span class="n">gene</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">-</span> <span class="n">gene</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu parçalar ana döngüde birleştirilir: Eski popülasyondan ebeveyn seçilir, çocuk üretilir, mutasyon uygulanır ve yeni nesil oluşturulur. Her nesilde en iyi bireyi izlemek, algoritmanın gerçekten evrimleşip evrimleşmediğini görmemizi sağlar.</p>

<table>
  <thead>
    <tr>
      <th>Parametre</th>
      <th>Düşük Değer Etkisi</th>
      <th>Yüksek Değer Etkisi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Popülasyon boyutu</td>
      <td>Hızlı ama dar arama</td>
      <td>Yavaş ama çeşitli arama</td>
    </tr>
    <tr>
      <td>Mutasyon oranı</td>
      <td>Yerel takılma riski</td>
      <td>Rastgeleliğe fazla kayma</td>
    </tr>
    <tr>
      <td>Nesil sayısı</td>
      <td>Erken durma</td>
      <td>Daha iyi yakınsama şansı</td>
    </tr>
    <tr>
      <td>Çaprazlama oranı</td>
      <td>Az kombinasyon</td>
      <td>Daha fazla keşif</td>
    </tr>
  </tbody>
</table>

<p>Genetik algoritmalarda sihirli tek bir ayar yoktur. Mutasyon oranı çok düşükse popülasyon birbirine benzer hale gelir; çok yüksekse öğrenilmiş iyi özellikler sürekli bozulur. Bu denge, <strong>keşif</strong> ve <strong>sömürü</strong> arasındaki klasik optimizasyon dansıdır. Keşif yeni bölgeleri aramak, sömürü ise bulunan iyi bölgeleri iyileştirmektir.</p>

<p>C++ tarafında dikkat edilmesi gereken önemli noktalardan biri kopyalama maliyetidir. Büyük kromozomlarda <code class="language-plaintext highlighter-rouge">vector</code> kopyalamak pahalı olabilir; gerekirse referans, taşıma semantiği veya özel veri yapıları kullanılabilir. Ayrıca rastgele sayı üretiminde <code class="language-plaintext highlighter-rouge">rand()</code> yerine <code class="language-plaintext highlighter-rouge">std::mt19937</code> tercih etmek daha sağlıklı sonuçlar verir.</p>

<p>Sonuç olarak genetik algoritmalar, kesin cevabı garanti eden sihirli değnekler değildir; ama karmaşık ve geniş arama uzaylarında oldukça pratik sezgisel yöntemlerdir. C++ ile birleştiğinde hızlı deneyler yapabilir, farklı uygunluk fonksiyonları deneyebilir ve algoritmanın küçük dijital canlılar gibi gelişmesini izleyebilirsiniz. Kısacası: Eğer probleminiz “çok fazla seçenek, çok az sabır” diyorsa, evrimi biraz koda dökmenin zamanı gelmiş olabilir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="C++" /><category term="Genetik Algoritma" /><category term="Optimizasyon" /><summary type="html"><![CDATA[Bir problemi çözmeye çalışırken bazen “en iyi” cevabı doğrudan hesaplamak zordur; özellikle seçenek sayısı devasa ise klasik yöntemler yorulabilir. İşte genetik algoritmalar burada sahneye çıkar: Doğadaki seçilim, çaprazlama ve mutasyon fikrini taklit ederek veri havuzundaki aday çözümleri nesilden nesle iyileştirir. C++ ise performansı ve bellek kontrolü sayesinde bu evrimsel deneyi hızlıca çalıştırmak için harika bir araçtır.]]></summary></entry><entry><title type="html">Go ile Gerçek Zamanlı Sohbet Sunucusu: Binlerce Bağlantıya Hazır Minimal Mimari</title><link href="https://sonsuzus.github.io/posts/go-ile-gercek-zamanli-sohbet-sunucusu-binlerce-baglantiya-hazir-minimal-mimari/" rel="alternate" type="text/html" title="Go ile Gerçek Zamanlı Sohbet Sunucusu: Binlerce Bağlantıya Hazır Minimal Mimari" /><published>2026-07-16T00:00:00+00:00</published><updated>2026-07-16T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/go-ile-gercek-zamanli-sohbet-sunucusu-binlerce-baglantiya-hazir-minimal-mimari</id><content type="html" xml:base="https://sonsuzus.github.io/posts/go-ile-gercek-zamanli-sohbet-sunucusu-binlerce-baglantiya-hazir-minimal-mimari/"><![CDATA[<p>Bir sohbet uygulaması yazmak ilk bakışta “mesajı al, herkese gönder” kadar basit görünür; fakat işin içine binlerce aktif kullanıcı, kopan bağlantılar, eşzamanlı mesajlar ve düşük gecikme girince konu bir anda backend spor salonuna dönüşür. Go burada hafif goroutine’leri, kanal tabanlı iletişim modeli ve sade sözdizimiyle harika bir adaydır.
``</p>

<p>Gerçek zamanlı sohbetin temelinde HTTP’nin klasik “istek-cevap” modelinden farklı bir yaklaşım vardır. Normal HTTP’de istemci sunucuya sorar, sunucu cevaplar ve bağlantı kapanır. Sohbette ise bağlantının açık kalması, sunucunun da istediği an istemciye mesaj gönderebilmesi gerekir. Bu yüzden WebSocket kullanırız. WebSocket, tek bir TCP bağlantısı üzerinde çift yönlü iletişim sağlar.</p>

<p>Teorik olarak her bağlantı için bir iş parçacığı açmak pahalıdır. Go’nun goroutine modeli bu maliyeti azaltır. Kabaca düşünürsek klasik thread maliyeti $M_t$, goroutine maliyeti $M_g$ olsun. Genellikle $M_g \ll M_t$ olduğu için aynı RAM ile çok daha fazla eşzamanlı bağlantı yönetilebilir. Toplam bellek tüketimini basitçe şöyle düşünebiliriz:</p>

\[M_{toplam} = n \times M_g + M_{uygulama}\]

<p>Burada $n$ aktif bağlantı sayısıdır. Ama sadece hafif olmak yetmez; bağlantılar arasında güvenli mesaj aktarımı da gerekir. İşte burada Go kanalları ve merkezi bir “hub” yapısı devreye girer.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
      <th>Sohbet İçin Uygunluk</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Klasik HTTP polling</td>
      <td>Basit kurulum</td>
      <td>Gereksiz istek yükü</td>
      <td>Düşük</td>
    </tr>
    <tr>
      <td>Long polling</td>
      <td>Daha az gecikme</td>
      <td>Bağlantı yönetimi karmaşık</td>
      <td>Orta</td>
    </tr>
    <tr>
      <td>WebSocket</td>
      <td>Çift yönlü ve hızlı</td>
      <td>Durum yönetimi gerekir</td>
      <td>Yüksek</td>
    </tr>
    <tr>
      <td>gRPC stream</td>
      <td>Güçlü tip sistemi</td>
      <td>Tarayıcı tarafı ek araç ister</td>
      <td>Orta-Yüksek</td>
    </tr>
  </tbody>
</table>

<p>Minimal mimarimiz üç parçadan oluşacak: <code class="language-plaintext highlighter-rouge">Client</code>, <code class="language-plaintext highlighter-rouge">Hub</code> ve WebSocket handler. <code class="language-plaintext highlighter-rouge">Client</code> tek bir kullanıcı bağlantısını temsil eder. <code class="language-plaintext highlighter-rouge">Hub</code>, gelen mesajları tüm istemcilere dağıtan küçük trafik polisi gibidir.</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">"log"</span>
    <span class="s">"net/http"</span>

    <span class="s">"github.com/gorilla/websocket"</span>
<span class="p">)</span>

<span class="k">type</span> <span class="n">Client</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">conn</span> <span class="o">*</span><span class="n">websocket</span><span class="o">.</span><span class="n">Conn</span>
    <span class="n">send</span> <span class="k">chan</span> <span class="p">[]</span><span class="kt">byte</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">Hub</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">clients</span>    <span class="k">map</span><span class="p">[</span><span class="o">*</span><span class="n">Client</span><span class="p">]</span><span class="kt">bool</span>
    <span class="n">broadcast</span>  <span class="k">chan</span> <span class="p">[]</span><span class="kt">byte</span>
    <span class="n">register</span>   <span class="k">chan</span> <span class="o">*</span><span class="n">Client</span>
    <span class="n">unregister</span> <span class="k">chan</span> <span class="o">*</span><span class="n">Client</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu yapıların amacı nettir: <code class="language-plaintext highlighter-rouge">clients</code> aktif bağlantıları tutar, <code class="language-plaintext highlighter-rouge">broadcast</code> herkese gönderilecek mesajları taşır, <code class="language-plaintext highlighter-rouge">register</code> yeni gelenleri ekler, <code class="language-plaintext highlighter-rouge">unregister</code> ayrılanları siler. Kanallar sayesinde farklı goroutine’ler aynı veriye doğrudan saldırmaz; mesajlaşarak anlaşır.</p>

<p>Şimdi hub döngüsünü yazalım. Bu döngü sunucunun kalbidir; gelen olaya göre kullanıcı ekler, siler veya mesaj dağıtır.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="p">(</span><span class="n">h</span> <span class="o">*</span><span class="n">Hub</span><span class="p">)</span> <span class="n">run</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">{</span>
        <span class="k">select</span> <span class="p">{</span>
        <span class="k">case</span> <span class="n">client</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">h</span><span class="o">.</span><span class="n">register</span><span class="o">:</span>
            <span class="n">h</span><span class="o">.</span><span class="n">clients</span><span class="p">[</span><span class="n">client</span><span class="p">]</span> <span class="o">=</span> <span class="no">true</span>

        <span class="k">case</span> <span class="n">client</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">h</span><span class="o">.</span><span class="n">unregister</span><span class="o">:</span>
            <span class="k">if</span> <span class="n">_</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="n">h</span><span class="o">.</span><span class="n">clients</span><span class="p">[</span><span class="n">client</span><span class="p">];</span> <span class="n">ok</span> <span class="p">{</span>
                <span class="nb">delete</span><span class="p">(</span><span class="n">h</span><span class="o">.</span><span class="n">clients</span><span class="p">,</span> <span class="n">client</span><span class="p">)</span>
                <span class="nb">close</span><span class="p">(</span><span class="n">client</span><span class="o">.</span><span class="n">send</span><span class="p">)</span>
            <span class="p">}</span>

        <span class="k">case</span> <span class="n">message</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="n">h</span><span class="o">.</span><span class="n">broadcast</span><span class="o">:</span>
            <span class="k">for</span> <span class="n">client</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">h</span><span class="o">.</span><span class="n">clients</span> <span class="p">{</span>
                <span class="k">select</span> <span class="p">{</span>
                <span class="k">case</span> <span class="n">client</span><span class="o">.</span><span class="n">send</span> <span class="o">&lt;-</span> <span class="n">message</span><span class="o">:</span>
                <span class="k">default</span><span class="o">:</span>
                    <span class="nb">close</span><span class="p">(</span><span class="n">client</span><span class="o">.</span><span class="n">send</span><span class="p">)</span>
                    <span class="nb">delete</span><span class="p">(</span><span class="n">h</span><span class="o">.</span><span class="n">clients</span><span class="p">,</span> <span class="n">client</span><span class="p">)</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Buradaki <code class="language-plaintext highlighter-rouge">default</code> kısmı önemlidir. Eğer bir istemci mesajları okuyamayacak kadar yavaşsa, tüm sistemi kilitlemesine izin vermeyiz. Gerçek zamanlı sistemlerde “en yavaş kullanıcı herkesi bekletmemeli” kuralı altın değerindedir.</p>

<p>WebSocket yükseltmesini yapan handler ise HTTP bağlantısını kalıcı, çift yönlü bir kanala dönüştürür.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">var</span> <span class="n">upgrader</span> <span class="o">=</span> <span class="n">websocket</span><span class="o">.</span><span class="n">Upgrader</span><span class="p">{</span>
    <span class="n">CheckOrigin</span><span class="o">:</span> <span class="k">func</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="kt">bool</span> <span class="p">{</span>
        <span class="k">return</span> <span class="no">true</span>
    <span class="p">},</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">serveWs</span><span class="p">(</span><span class="n">hub</span> <span class="o">*</span><span class="n">Hub</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">conn</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">upgrader</span><span class="o">.</span><span class="n">Upgrade</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">r</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">Println</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">client</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="n">Client</span><span class="p">{</span><span class="n">conn</span><span class="o">:</span> <span class="n">conn</span><span class="p">,</span> <span class="n">send</span><span class="o">:</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">,</span> <span class="m">256</span><span class="p">)}</span>
    <span class="n">hub</span><span class="o">.</span><span class="n">register</span> <span class="o">&lt;-</span> <span class="n">client</span>

    <span class="k">go</span> <span class="n">client</span><span class="o">.</span><span class="n">writePump</span><span class="p">()</span>
    <span class="k">go</span> <span class="n">client</span><span class="o">.</span><span class="n">readPump</span><span class="p">(</span><span class="n">hub</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">readPump</code> istemciden gelen mesajları okur ve hub’a yollar. <code class="language-plaintext highlighter-rouge">writePump</code> ise hub’dan gelen mesajları istemciye yazar. Okuma ve yazmayı ayrı goroutine’lere bölmek, bağlantının aynı anda hem dinleyip hem konuşabilmesini sağlar.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">Client</span><span class="p">)</span> <span class="n">readPump</span><span class="p">(</span><span class="n">hub</span> <span class="o">*</span><span class="n">Hub</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">defer</span> <span class="k">func</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">hub</span><span class="o">.</span><span class="n">unregister</span> <span class="o">&lt;-</span> <span class="n">c</span>
        <span class="n">c</span><span class="o">.</span><span class="n">conn</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>
    <span class="p">}()</span>

    <span class="k">for</span> <span class="p">{</span>
        <span class="n">_</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">conn</span><span class="o">.</span><span class="n">ReadMessage</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="k">break</span>
        <span class="p">}</span>
        <span class="n">hub</span><span class="o">.</span><span class="n">broadcast</span> <span class="o">&lt;-</span> <span class="n">message</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">Client</span><span class="p">)</span> <span class="n">writePump</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">defer</span> <span class="n">c</span><span class="o">.</span><span class="n">conn</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>

    <span class="k">for</span> <span class="n">message</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">c</span><span class="o">.</span><span class="n">send</span> <span class="p">{</span>
        <span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">conn</span><span class="o">.</span><span class="n">WriteMessage</span><span class="p">(</span><span class="n">websocket</span><span class="o">.</span><span class="n">TextMessage</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
            <span class="k">break</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Son olarak <code class="language-plaintext highlighter-rouge">main</code> fonksiyonu ile sistemi ayağa kaldırırız.</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">hub</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="n">Hub</span><span class="p">{</span>
        <span class="n">clients</span><span class="o">:</span>    <span class="nb">make</span><span class="p">(</span><span class="k">map</span><span class="p">[</span><span class="o">*</span><span class="n">Client</span><span class="p">]</span><span class="kt">bool</span><span class="p">),</span>
        <span class="n">broadcast</span><span class="o">:</span>  <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">),</span>
        <span class="n">register</span><span class="o">:</span>   <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="o">*</span><span class="n">Client</span><span class="p">),</span>
        <span class="n">unregister</span><span class="o">:</span> <span class="nb">make</span><span class="p">(</span><span class="k">chan</span> <span class="o">*</span><span class="n">Client</span><span class="p">),</span>
    <span class="p">}</span>

    <span class="k">go</span> <span class="n">hub</span><span class="o">.</span><span class="n">run</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">"/ws"</span><span class="p">,</span> <span class="k">func</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">serveWs</span><span class="p">(</span><span class="n">hub</span><span class="p">,</span> <span class="n">w</span><span class="p">,</span> <span class="n">r</span><span class="p">)</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">"Sohbet sunucusu :8080 üzerinde çalışıyor"</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">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="p">}</span>
</code></pre></div></div>

<p>Bu haliyle sunucu minimalisttir ama güçlü bir temel sunar. Üretim ortamında <code class="language-plaintext highlighter-rouge">CheckOrigin</code> kontrolünü sıkılaştırmalı, kullanıcı kimlik doğrulaması eklemeli, mesajlara oda bilgisi koymalı ve yatay ölçekleme için Redis Pub/Sub gibi bir ara katman kullanmalısınız. Yine de ana fikir değişmez: WebSocket bağlantıyı açık tutar, goroutine’ler hafif paralellik sağlar, hub ise mesaj trafiğini düzenler. Kısacası Go ile sohbet sunucusu yazmak, az kodla çok bağlantı yönetmenin en keyifli yollarından biridir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="Go" /><category term="WebSocket" /><category term="Gerçek Zamanlı Uygulamalar" /><category term="Backend" /><summary type="html"><![CDATA[Bir sohbet uygulaması yazmak ilk bakışta “mesajı al, herkese gönder” kadar basit görünür; fakat işin içine binlerce aktif kullanıcı, kopan bağlantılar, eşzamanlı mesajlar ve düşük gecikme girince konu bir anda backend spor salonuna dönüşür. Go burada hafif goroutine’leri, kanal tabanlı iletişim modeli ve sade sözdizimiyle harika bir adaydır.]]></summary></entry><entry><title type="html">JavaScript ile Tarayıcı Tabanlı Retro Oyunlar: Atari Ruhunu Canvas’a Taşımak</title><link href="https://sonsuzus.github.io/posts/javascript-ile-tarayici-tabanli-retro-oyunlar-atari-ruhunu-canvasa-tasimak/" rel="alternate" type="text/html" title="JavaScript ile Tarayıcı Tabanlı Retro Oyunlar: Atari Ruhunu Canvas’a Taşımak" /><published>2026-07-16T00:00:00+00:00</published><updated>2026-07-16T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/javascript-ile-tarayici-tabanli-retro-oyunlar-atari-ruhunu-canvasa-tasimak</id><content type="html" xml:base="https://sonsuzus.github.io/posts/javascript-ile-tarayici-tabanli-retro-oyunlar-atari-ruhunu-canvasa-tasimak/"><![CDATA[<p>Eski atari oyunlarının büyüsü, devasa grafik motorlarından değil; basit kuralların, hızlı geri bildirimin ve akıcı kontrollerin birleşiminden gelir. JavaScript, HTML ve biraz CSS ile tarayıcıda çalışan mini retro oyunlar yapmak, hem temel programlama mantığını pekiştirir hem de “oyun döngüsü” gibi yazılım dünyasının çok önemli kavramlarını eğlenceli biçimde öğretir.
``
Retro oyun dediğimizde akla Pong, Space Invaders, Snake veya Breakout gelir. Bu oyunların ortak noktası şudur: Ekranda birkaç şekil vardır, kullanıcı giriş yapar, nesneler hareket eder, çarpışmalar kontrol edilir ve skor güncellenir. Yani aslında elimizde küçük ama düzenli çalışan bir simülasyon vardır.</p>

<p>Tarayıcı tabanlı oyunlarda en popüler araçlardan biri <strong>HTML5 Canvas</strong>’tır. Canvas, piksel piksel çizim yapmamızı sağlayan bir sahne gibidir. JavaScript ise bu sahnedeki oyuncuları, topları, düşmanları ve puanları yöneten yönetmendir.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Web Karşılığı</th>
      <th>Oyundaki Rolü</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Sahne</td>
      <td><code class="language-plaintext highlighter-rouge">&lt;canvas&gt;</code></td>
      <td>Oyunun çizildiği alan</td>
    </tr>
    <tr>
      <td>Yönetmen</td>
      <td>JavaScript</td>
      <td>Kuralları ve akışı kontrol eder</td>
    </tr>
    <tr>
      <td>Kare</td>
      <td><code class="language-plaintext highlighter-rouge">requestAnimationFrame</code></td>
      <td>Her ekran yenilemesi</td>
    </tr>
    <tr>
      <td>Oyuncu girdisi</td>
      <td>Klavye / mouse eventleri</td>
      <td>Karakteri hareket ettirir</td>
    </tr>
    <tr>
      <td>Fizik</td>
      <td>Basit matematik</td>
      <td>Hız, yön, çarpışma</td>
    </tr>
  </tbody>
</table>

<p>Bir oyunun kalbi <strong>game loop</strong>, yani oyun döngüsüdür. Bu döngü genelde üç şey yapar: girdileri okur, oyun durumunu günceller, sonra ekrana çizer. Matematiksel olarak konum güncellemesini şöyle düşünebiliriz: $x_{yeni}=x+vx*dt$. Burada <code class="language-plaintext highlighter-rouge">x</code> konum, <code class="language-plaintext highlighter-rouge">vx</code> yatay hız, <code class="language-plaintext highlighter-rouge">dt</code> ise iki kare arasında geçen zamandır. Retro oyunlarda çoğu zaman bu formül yeterince güçlüdür.</p>

<p>Aşağıdaki örnek, Canvas üzerinde basit bir Pong topu hareketi oluşturur. Kodun amacı topu ekranda sektirmek ve temel oyun döngüsünü göstermektir:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;canvas</span> <span class="na">id=</span><span class="s">'game'</span> <span class="na">width=</span><span class="s">'640'</span> <span class="na">height=</span><span class="s">'360'</span><span class="nt">&gt;&lt;/canvas&gt;</span>
<span class="nt">&lt;script&gt;</span>
<span class="kd">const</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">game</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">ctx</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nf">getContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">2d</span><span class="dl">'</span><span class="p">);</span>

<span class="kd">const</span> <span class="nx">ball</span> <span class="o">=</span> <span class="p">{</span>
  <span class="na">x</span><span class="p">:</span> <span class="mi">320</span><span class="p">,</span>
  <span class="na">y</span><span class="p">:</span> <span class="mi">180</span><span class="p">,</span>
  <span class="na">r</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span>
  <span class="na">vx</span><span class="p">:</span> <span class="mi">180</span><span class="p">,</span>
  <span class="na">vy</span><span class="p">:</span> <span class="mi">140</span>
<span class="p">};</span>

<span class="kd">let</span> <span class="nx">lastTime</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

<span class="kd">function</span> <span class="nf">update</span><span class="p">(</span><span class="nx">dt</span><span class="p">)</span> <span class="p">{</span>
  <span class="nx">ball</span><span class="p">.</span><span class="nx">x</span> <span class="o">+=</span> <span class="nx">ball</span><span class="p">.</span><span class="nx">vx</span> <span class="o">*</span> <span class="nx">dt</span><span class="p">;</span>
  <span class="nx">ball</span><span class="p">.</span><span class="nx">y</span> <span class="o">+=</span> <span class="nx">ball</span><span class="p">.</span><span class="nx">vy</span> <span class="o">*</span> <span class="nx">dt</span><span class="p">;</span>

  <span class="k">if</span> <span class="p">(</span><span class="nx">ball</span><span class="p">.</span><span class="nx">x</span> <span class="o">&lt;</span> <span class="nx">ball</span><span class="p">.</span><span class="nx">r</span> <span class="o">||</span> <span class="nx">ball</span><span class="p">.</span><span class="nx">x</span> <span class="o">&gt;</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">width</span> <span class="o">-</span> <span class="nx">ball</span><span class="p">.</span><span class="nx">r</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">ball</span><span class="p">.</span><span class="nx">vx</span> <span class="o">*=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="k">if</span> <span class="p">(</span><span class="nx">ball</span><span class="p">.</span><span class="nx">y</span> <span class="o">&lt;</span> <span class="nx">ball</span><span class="p">.</span><span class="nx">r</span> <span class="o">||</span> <span class="nx">ball</span><span class="p">.</span><span class="nx">y</span> <span class="o">&gt;</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">height</span> <span class="o">-</span> <span class="nx">ball</span><span class="p">.</span><span class="nx">r</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">ball</span><span class="p">.</span><span class="nx">vy</span> <span class="o">*=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nf">draw</span><span class="p">()</span> <span class="p">{</span>
  <span class="nx">ctx</span><span class="p">.</span><span class="nx">fillStyle</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">#111</span><span class="dl">'</span><span class="p">;</span>
  <span class="nx">ctx</span><span class="p">.</span><span class="nf">fillRect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">width</span><span class="p">,</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">height</span><span class="p">);</span>

  <span class="nx">ctx</span><span class="p">.</span><span class="nx">fillStyle</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">#00ff99</span><span class="dl">'</span><span class="p">;</span>
  <span class="nx">ctx</span><span class="p">.</span><span class="nf">beginPath</span><span class="p">();</span>
  <span class="nx">ctx</span><span class="p">.</span><span class="nf">arc</span><span class="p">(</span><span class="nx">ball</span><span class="p">.</span><span class="nx">x</span><span class="p">,</span> <span class="nx">ball</span><span class="p">.</span><span class="nx">y</span><span class="p">,</span> <span class="nx">ball</span><span class="p">.</span><span class="nx">r</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">PI</span> <span class="o">*</span> <span class="mi">2</span><span class="p">);</span>
  <span class="nx">ctx</span><span class="p">.</span><span class="nf">fill</span><span class="p">();</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nf">loop</span><span class="p">(</span><span class="nx">time</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">dt</span> <span class="o">=</span> <span class="p">(</span><span class="nx">time</span> <span class="o">-</span> <span class="nx">lastTime</span><span class="p">)</span> <span class="o">/</span> <span class="mi">1000</span><span class="p">;</span>
  <span class="nx">lastTime</span> <span class="o">=</span> <span class="nx">time</span><span class="p">;</span>

  <span class="nf">update</span><span class="p">(</span><span class="nx">dt</span><span class="p">);</span>
  <span class="nf">draw</span><span class="p">();</span>
  <span class="nf">requestAnimationFrame</span><span class="p">(</span><span class="nx">loop</span><span class="p">);</span>
<span class="p">}</span>

<span class="nf">requestAnimationFrame</span><span class="p">(</span><span class="nx">loop</span><span class="p">);</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>Buradaki önemli detay <code class="language-plaintext highlighter-rouge">dt</code> kullanımıdır. Eğer sadece <code class="language-plaintext highlighter-rouge">ball.x += 3</code> yazsaydık, oyun farklı cihazlarda farklı hızlarda çalışabilirdi. <code class="language-plaintext highlighter-rouge">dt</code> sayesinde hareket zamana bağlanır. Yani saniyedeki kare sayısı değişse bile oyun daha tutarlı kalır. Basitçe hız formülü $v = mesafe / zaman$ mantığına dayanır.</p>

<p>Çarpışma kontrolü de retro oyunların vazgeçilmezidir. En basit yöntemlerden biri dikdörtgen çarpışmasıdır. İki kutu üst üste biniyorsa çarpışma vardır.</p>

<table>
  <thead>
    <tr>
      <th>Yöntem</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Daire çarpışması</td>
      <td>Top, mermi gibi nesnelerde kolaydır</td>
      <td>Köşeli nesnelerde hassas değildir</td>
    </tr>
    <tr>
      <td>Dikdörtgen çarpışması</td>
      <td>Platform ve blok oyunları için idealdir</td>
      <td>Dönen nesnelerde yetersiz kalır</td>
    </tr>
    <tr>
      <td>Piksel kontrolü</td>
      <td>Çok hassastır</td>
      <td>Performans maliyeti yüksektir</td>
    </tr>
  </tbody>
</table>

<p>Klavye kontrolü için tuş durumlarını saklamak iyi bir pratiktir. Böylece tek tek “tuşa basıldı” olayına bağlı kalmak yerine, her karede mevcut durumu okuyabiliriz:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">keys</span> <span class="o">=</span> <span class="p">{};</span>
<span class="kd">const</span> <span class="nx">player</span> <span class="o">=</span> <span class="p">{</span> <span class="na">x</span><span class="p">:</span> <span class="mi">40</span><span class="p">,</span> <span class="na">y</span><span class="p">:</span> <span class="mi">150</span><span class="p">,</span> <span class="na">w</span><span class="p">:</span> <span class="mi">12</span><span class="p">,</span> <span class="na">h</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span> <span class="na">speed</span><span class="p">:</span> <span class="mi">240</span> <span class="p">};</span>

<span class="nb">document</span><span class="p">.</span><span class="nf">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">keydown</span><span class="dl">'</span><span class="p">,</span> <span class="nx">e</span> <span class="o">=&gt;</span> <span class="nx">keys</span><span class="p">[</span><span class="nx">e</span><span class="p">.</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="kc">true</span><span class="p">);</span>
<span class="nb">document</span><span class="p">.</span><span class="nf">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">keyup</span><span class="dl">'</span><span class="p">,</span> <span class="nx">e</span> <span class="o">=&gt;</span> <span class="nx">keys</span><span class="p">[</span><span class="nx">e</span><span class="p">.</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="kc">false</span><span class="p">);</span>

<span class="kd">function</span> <span class="nf">updatePlayer</span><span class="p">(</span><span class="nx">dt</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if </span><span class="p">(</span><span class="nx">keys</span><span class="p">[</span><span class="dl">'</span><span class="s1">ArrowUp</span><span class="dl">'</span><span class="p">])</span> <span class="nx">player</span><span class="p">.</span><span class="nx">y</span> <span class="o">-=</span> <span class="nx">player</span><span class="p">.</span><span class="nx">speed</span> <span class="o">*</span> <span class="nx">dt</span><span class="p">;</span>
  <span class="k">if </span><span class="p">(</span><span class="nx">keys</span><span class="p">[</span><span class="dl">'</span><span class="s1">ArrowDown</span><span class="dl">'</span><span class="p">])</span> <span class="nx">player</span><span class="p">.</span><span class="nx">y</span> <span class="o">+=</span> <span class="nx">player</span><span class="p">.</span><span class="nx">speed</span> <span class="o">*</span> <span class="nx">dt</span><span class="p">;</span>

  <span class="nx">player</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">min</span><span class="p">(</span><span class="mi">360</span> <span class="o">-</span> <span class="nx">player</span><span class="p">.</span><span class="nx">h</span><span class="p">,</span> <span class="nx">player</span><span class="p">.</span><span class="nx">y</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu yapı, oyuncunun paddle’ını yukarı-aşağı hareket ettirir ve ekran dışına çıkmasını engeller. Aslında burada küçük bir durum makinesi kurmuş oluruz: tuş basılıysa hareket et, değilse bekle.</p>

<p>Retro hissi artırmak için piksel fontlar, sınırlı renk paleti, basit ses efektleri ve düşük çözünürlüklü görseller kullanabilirsiniz. Önemli olan, oyunu karmaşıklaştırmadan “oynanabilir döngüyü” hızlıca kurmaktır: başlat, oyna, kaybet, tekrar dene.</p>

<p>Sonuç olarak JavaScript ile retro oyun yapmak; değişkenler, fonksiyonlar, döngüler, olaylar, matematik ve durum yönetimi gibi temel konuları tek bir eğlenceli projede birleştirir. Bir topu sektirmekle başlayan yolculuk, kısa sürede kendi Pong’unuza, Snake’inize veya uzay nişancı oyununuza dönüşebilir. Üstelik tek ihtiyacınız olan şey bir tarayıcı, biraz merak ve bolca “bir tur daha” isteği!</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="javascript" /><category term="canvas" /><category term="retro-oyun" /><summary type="html"><![CDATA[Eski atari oyunlarının büyüsü, devasa grafik motorlarından değil; basit kuralların, hızlı geri bildirimin ve akıcı kontrollerin birleşiminden gelir. JavaScript, HTML ve biraz CSS ile tarayıcıda çalışan mini retro oyunlar yapmak, hem temel programlama mantığını pekiştirir hem de “oyun döngüsü” gibi yazılım dünyasının çok önemli kavramlarını eğlenceli biçimde öğretir.]]></summary></entry><entry><title type="html">PHP ile MVC Mimarisi: Temiz, Modüler ve Sürdürülebilir Web Projeleri</title><link href="https://sonsuzus.github.io/posts/php-ile-mvc-mimarisi-temiz-moduler-ve-surdurulebilir-web-projeleri/" rel="alternate" type="text/html" title="PHP ile MVC Mimarisi: Temiz, Modüler ve Sürdürülebilir Web Projeleri" /><published>2026-07-16T00:00:00+00:00</published><updated>2026-07-16T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/php-ile-mvc-mimarisi-temiz-moduler-ve-surdurulebilir-web-projeleri</id><content type="html" xml:base="https://sonsuzus.github.io/posts/php-ile-mvc-mimarisi-temiz-moduler-ve-surdurulebilir-web-projeleri/"><![CDATA[<p>PHP projeleri büyüdükçe en büyük düşman genellikle veritabanı sorgularının, HTML çıktısının ve iş kurallarının aynı dosyada çorba olmasıdır. MVC mimarisi tam da bu noktada sahneye çıkar: Model veriyi, View kullanıcı arayüzünü, Controller ise akışı yönetir. Böylece projeniz “çalışıyor ama dokunmayalım” seviyesinden “geliştirebiliriz, test edebiliriz, bakım yapabiliriz” seviyesine yükselir.
``</p>

<h2 id="mvc-mantığı-nedir">MVC Mantığı Nedir?</h2>

<p>MVC, <strong>Model-View-Controller</strong> kelimelerinin kısaltmasıdır. Basit bir denklemle düşünebiliriz: $Uygulama = Veri + Mantık + Arayüz$. MVC bu parçaları birbirinden ayırarak karmaşıklığı azaltır. Yani aynı anda hem SQL yazıp hem HTML basıp hem de kullanıcı yetkisi kontrol etmek yerine, her katmana net bir sorumluluk veririz.</p>

<table>
  <thead>
    <tr>
      <th>Katman</th>
      <th>Görevi</th>
      <th>PHP Projesindeki Örnek</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Model</td>
      <td>Veri erişimi ve veri kuralları</td>
      <td>Kullanıcıları veritabanından çekmek</td>
    </tr>
    <tr>
      <td>View</td>
      <td>Kullanıcıya gösterilecek çıktı</td>
      <td>HTML tablo, form, liste</td>
    </tr>
    <tr>
      <td>Controller</td>
      <td>İstekleri karşılamak ve yönlendirmek</td>
      <td><code class="language-plaintext highlighter-rouge">/users</code> isteğini işleyip listeyi göstermek</td>
    </tr>
  </tbody>
</table>

<p>Buradaki kritik fikir <strong>sorumluluk ayrımıdır</strong>. Bir sınıfın değişmesi için tek bir nedeni olmalıdır. Matematiksel düşünürsek, karmaşıklığı $K$ ile gösterirsek monolitik bir dosyada $K = V * M * C$ gibi büyürken, MVC’de parçalar ayrıldığı için yönetilebilirlik $K = V + M + C$ seviyesine yaklaşır. Elbette bu tam bir bilimsel formül değil; ama zihinde güzel bir alarm yakar: çarpım büyür, toplam daha kolay yönetilir.</p>

<h2 id="akış-nasıl-çalışır">Akış Nasıl Çalışır?</h2>

<p>Bir kullanıcı <code class="language-plaintext highlighter-rouge">/users</code> adresine girdiğinde süreç genellikle şöyledir:</p>

<ol>
  <li>Router isteği ilgili Controller metoduna yollar.</li>
  <li>Controller, Model’den gerekli veriyi ister.</li>
  <li>Model veritabanı sorgusunu çalıştırır ve sonucu döndürür.</li>
  <li>Controller sonucu View’e gönderir.</li>
  <li>View HTML üretir.</li>
</ol>

<p>Bu akışta Controller patron gibi görünse de aslında “orkestra şefi”dir; kemanı kendi çalmaz, davula kendi vurmaz, sadece doğru parçayı doğru anda çağırır.</p>

<h2 id="basit-bir-php-mvc-örneği">Basit Bir PHP MVC Örneği</h2>

<p>Aşağıdaki örnekte kullanıcı listesini çeken bir Model, bunu çağıran bir Controller ve View dosyasını yükleyen küçük bir View yardımcı sınıfı görüyoruz. Kodun amacı tam bir framework yazmak değil; MVC fikrini sade biçimde göstermektir.</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">final</span> <span class="kd">class</span> <span class="nc">UserModel</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">function</span> <span class="n">__construct</span><span class="p">(</span><span class="k">private</span> <span class="kt">PDO</span> <span class="nv">$db</span><span class="p">)</span> <span class="p">{}</span>

    <span class="k">public</span> <span class="k">function</span> <span class="n">activeUsers</span><span class="p">():</span> <span class="kt">array</span>
    <span class="p">{</span>
        <span class="nv">$stmt</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="n">db</span><span class="o">-&gt;</span><span class="nf">prepare</span><span class="p">(</span><span class="s1">'SELECT id, name, email FROM users WHERE active = :active'</span><span class="p">);</span>
        <span class="nv">$stmt</span><span class="o">-&gt;</span><span class="nf">execute</span><span class="p">([</span><span class="s1">'active'</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">]);</span>

        <span class="k">return</span> <span class="nv">$stmt</span><span class="o">-&gt;</span><span class="nf">fetchAll</span><span class="p">(</span><span class="no">PDO</span><span class="o">::</span><span class="no">FETCH_ASSOC</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">final</span> <span class="kd">class</span> <span class="nc">UserController</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">function</span> <span class="n">__construct</span><span class="p">(</span><span class="k">private</span> <span class="kt">UserModel</span> <span class="nv">$model</span><span class="p">)</span> <span class="p">{}</span>

    <span class="k">public</span> <span class="k">function</span> <span class="n">index</span><span class="p">():</span> <span class="kt">void</span>
    <span class="p">{</span>
        <span class="nv">$users</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="n">model</span><span class="o">-&gt;</span><span class="nf">activeUsers</span><span class="p">();</span>
        <span class="nc">View</span><span class="o">::</span><span class="nf">render</span><span class="p">(</span><span class="s1">'users/index'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'users'</span> <span class="o">=&gt;</span> <span class="nv">$users</span><span class="p">]);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">final</span> <span class="kd">class</span> <span class="nc">View</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="n">render</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$file</span><span class="p">,</span> <span class="kt">array</span> <span class="nv">$data</span> <span class="o">=</span> <span class="p">[]):</span> <span class="kt">void</span>
    <span class="p">{</span>
        <span class="nb">extract</span><span class="p">(</span><span class="nv">$data</span><span class="p">);</span>
        <span class="k">require</span> <span class="k">__DIR__</span> <span class="mf">.</span> <span class="s1">'/views/'</span> <span class="mf">.</span> <span class="nv">$file</span> <span class="mf">.</span> <span class="s1">'.php'</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">UserModel</code> sadece veriye odaklanır. SQL sorgusu Controller içinde değildir; bu harika bir şeydir çünkü yarın MySQL yerine başka bir kaynak kullansanız Controller’ın bozulma ihtimali azalır. <code class="language-plaintext highlighter-rouge">UserController</code> iş akışını yönetir: kullanıcıları alır ve View’e gönderir. <code class="language-plaintext highlighter-rouge">View::render()</code> ise ilgili PHP şablonunu yükler.</p>

<h2 id="klasik-php-ile-mvc-karşılaştırması">Klasik PHP ile MVC Karşılaştırması</h2>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Her şey tek dosyada</td>
      <td>Başlangıçta hızlıdır</td>
      <td>Büyüdükçe bakım kabusa döner</td>
    </tr>
    <tr>
      <td>MVC</td>
      <td>Test edilebilir, okunabilir, modülerdir</td>
      <td>İlk kurulum biraz disiplin ister</td>
    </tr>
    <tr>
      <td>Framework MVC</td>
      <td>Router, ORM, güvenlik hazır gelir</td>
      <td>Öğrenme eğrisi ve yapı bağımlılığı oluşur</td>
    </tr>
  </tbody>
</table>

<h2 id="dikkat-edilmesi-gerekenler">Dikkat Edilmesi Gerekenler</h2>

<p>MVC kullanırken en yaygın hata, Controller’ı şişirmektir. Controller içine uzun validasyonlar, karmaşık hesaplamalar ve SQL sorguları yazarsanız mimari yine çorbaya döner; sadece adı “MVC çorbası” olur. İş mantığı büyüdüğünde Service katmanı eklemek iyi fikirdir. Örneğin ödeme hesaplama, stok kontrolü veya kampanya kuralları Model ile Controller arasına yerleşen servislerde durabilir.</p>

<p>Ayrıca View dosyalarında mümkün olduğunca az PHP mantığı bulundurun. View’in görevi karar vermek değil, gösterim yapmaktır. <code class="language-plaintext highlighter-rouge">if</code> ve <code class="language-plaintext highlighter-rouge">foreach</code> makuldür; ancak indirim hesaplama algoritması View içinde yaşıyorsa küçük bir mimari yangın başlamış demektir.</p>

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

<p>PHP ile MVC mimarisi, projeyi daha profesyonel hale getiren güçlü bir düşünme biçimidir. Veritabanı sorgularını Model’e, kullanıcı arayüzünü View’e, istek akışını Controller’a taşıyarak hem bug bulmayı kolaylaştırır hem de yeni özellik eklemeyi daha güvenli hale getirirsiniz. Küçük projelerde bile bu alışkanlığı kazanmak, büyük projelerde sizi ciddi teknik borçtan kurtarır. Kısacası MVC, PHP dünyasında düzenli masa, etiketli çekmece ve kaybolmayan tornavida etkisi yaratır.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="PHP" /><category term="MVC" /><category term="Web Geliştirme" /><category term="Mimari" /><summary type="html"><![CDATA[PHP projeleri büyüdükçe en büyük düşman genellikle veritabanı sorgularının, HTML çıktısının ve iş kurallarının aynı dosyada çorba olmasıdır. MVC mimarisi tam da bu noktada sahneye çıkar: Model veriyi, View kullanıcı arayüzünü, Controller ise akışı yönetir. Böylece projeniz “çalışıyor ama dokunmayalım” seviyesinden “geliştirebiliriz, test edebiliriz, bakım yapabiliriz” seviyesine yükselir.]]></summary></entry></feed>