<?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-16T15:33:04+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 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><entry><title type="html">Python ile Otomatik Değerlendirme Sistemleri: Güvenli Kod Çalıştırma ve Notlandırma</title><link href="https://sonsuzus.github.io/posts/python-ile-otomatik-degerlendirme-sistemleri-guvenli-kod-calistirma-ve-notlandirma/" rel="alternate" type="text/html" title="Python ile Otomatik Değerlendirme Sistemleri: Güvenli Kod Çalıştırma ve Notlandırma" /><published>2026-07-16T00:00:00+00:00</published><updated>2026-07-16T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/python-ile-otomatik-degerlendirme-sistemleri-guvenli-kod-calistirma-ve-notlandirma</id><content type="html" xml:base="https://sonsuzus.github.io/posts/python-ile-otomatik-degerlendirme-sistemleri-guvenli-kod-calistirma-ve-notlandirma/"><![CDATA[<p>Bir öğrencinin yazdığı kodu saniyeler içinde çalıştırıp çıktısını kontrol eden, puanını hesaplayan ve geri bildirim veren sistemler kulağa küçük bir sihirbazlık gibi gelir. Aslında bu sihrin adı auto-grader: test senaryoları, izole çalışma ortamı ve adil puanlama mantığının birleşimi. Python ile böyle bir sistem geliştirmek hem eğitim platformları hem de kodlama yarışmaları için çok güçlü bir projedir.
``
Auto-grader sisteminin temel problemi şudur: Kullanıcının gönderdiği kodu çalıştırmak istiyoruz, ama bu kod güvenilmez olabilir. Sonsuz döngüye girebilir, dosya sistemini kurcalayabilir, çok fazla bellek tüketebilir veya gizli testleri okumaya çalışabilir. Bu yüzden auto-grader yalnızca <code class="language-plaintext highlighter-rouge">subprocess.run()</code> çağırıp sonucu okumaktan ibaret değildir; güvenlik, zaman sınırı, kaynak sınırı ve test tasarımı birlikte düşünülmelidir.</p>

<p>Teorik olarak her soru için bir değerlendirme fonksiyonu vardır. Öğrencinin cevabını $S$, beklenen çıktıyı $E$, üretilen çıktıyı $O$ kabul edelim. Basit bir çıktı karşılaştırmasında puan fonksiyonu şöyle yazılabilir: $score(S)=100$ eğer $O=E$, aksi halde $0$. Daha gelişmiş sistemlerde çoklu test kullanılır: \(score=\frac{passed\_tests}{total\_tests}\times100\) Böylece öğrencinin çözümü bazı durumları doğru ele alıyorsa kısmi puan alabilir.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Avantaj</th>
      <th>Risk</th>
      <th>Kullanım Yeri</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Çıktı karşılaştırma</td>
      <td>Basit ve hızlı</td>
      <td>Format hatalarına hassas</td>
      <td>Başlangıç ödevleri</td>
    </tr>
    <tr>
      <td>Birim test</td>
      <td>Fonksiyon davranışını ölçer</td>
      <td>Kod yapısı beklentisi vardır</td>
      <td>Algoritma soruları</td>
    </tr>
    <tr>
      <td>Gizli testler</td>
      <td>Ezber çözümü engeller</td>
      <td>Test kalitesi kritik</td>
      <td>Yarışmalar</td>
    </tr>
    <tr>
      <td>Sandbox</td>
      <td>Güvenliği artırır</td>
      <td>Kurulum maliyetli</td>
      <td>Gerçek platformlar</td>
    </tr>
  </tbody>
</table>

<p>En küçük auto-grader çekirdeği, öğrencinin kodunu geçici bir dosyaya yazıp belirli girdilerle çalıştırabilir. Aşağıdaki örnek, zaman aşımı olan basit bir değerlendirme yapar. Bu sürüm öğretici amaçlıdır; üretimde Docker, kullanıcı yetkisi düşürme ve dosya sistemi izolasyonu eklenmelidir.</p>

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

<span class="n">TESTS</span> <span class="o">=</span> <span class="p">[</span>
    <span class="p">{</span><span class="sh">'</span><span class="s">input</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">2 3</span><span class="se">\n</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">expected</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">5</span><span class="sh">'</span><span class="p">},</span>
    <span class="p">{</span><span class="sh">'</span><span class="s">input</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">10 -4</span><span class="se">\n</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">expected</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">6</span><span class="sh">'</span><span class="p">},</span>
<span class="p">]</span>

<span class="k">def</span> <span class="nf">grade_python_code</span><span class="p">(</span><span class="n">source_code</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">2</span><span class="p">):</span>
    <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">with</span> <span class="n">tempfile</span><span class="p">.</span><span class="nc">TemporaryDirectory</span><span class="p">()</span> <span class="k">as</span> <span class="n">tmp</span><span class="p">:</span>
        <span class="n">path</span> <span class="o">=</span> <span class="nc">Path</span><span class="p">(</span><span class="n">tmp</span><span class="p">)</span> <span class="o">/</span> <span class="sh">'</span><span class="s">solution.py</span><span class="sh">'</span>
        <span class="n">path</span><span class="p">.</span><span class="nf">write_text</span><span class="p">(</span><span class="n">source_code</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">)</span>

        <span class="k">for</span> <span class="n">test</span> <span class="ow">in</span> <span class="n">TESTS</span><span class="p">:</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">run</span> <span class="o">=</span> <span class="n">subprocess</span><span class="p">.</span><span class="nf">run</span><span class="p">(</span>
                    <span class="p">[</span><span class="sh">'</span><span class="s">python</span><span class="sh">'</span><span class="p">,</span> <span class="nf">str</span><span class="p">(</span><span class="n">path</span><span class="p">)],</span>
                    <span class="nb">input</span><span class="o">=</span><span class="n">test</span><span class="p">[</span><span class="sh">'</span><span class="s">input</span><span class="sh">'</span><span class="p">],</span>
                    <span class="n">text</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
                    <span class="n">capture_output</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
                    <span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span>
                <span class="p">)</span>
                <span class="n">output</span> <span class="o">=</span> <span class="n">run</span><span class="p">.</span><span class="n">stdout</span><span class="p">.</span><span class="nf">strip</span><span class="p">()</span>
                <span class="n">passed</span> <span class="o">=</span> <span class="n">output</span> <span class="o">==</span> <span class="n">test</span><span class="p">[</span><span class="sh">'</span><span class="s">expected</span><span class="sh">'</span><span class="p">]</span>
                <span class="n">results</span><span class="p">.</span><span class="nf">append</span><span class="p">({</span>
                    <span class="sh">'</span><span class="s">passed</span><span class="sh">'</span><span class="p">:</span> <span class="n">passed</span><span class="p">,</span>
                    <span class="sh">'</span><span class="s">output</span><span class="sh">'</span><span class="p">:</span> <span class="n">output</span><span class="p">,</span>
                    <span class="sh">'</span><span class="s">expected</span><span class="sh">'</span><span class="p">:</span> <span class="n">test</span><span class="p">[</span><span class="sh">'</span><span class="s">expected</span><span class="sh">'</span><span class="p">],</span>
                    <span class="sh">'</span><span class="s">error</span><span class="sh">'</span><span class="p">:</span> <span class="n">run</span><span class="p">.</span><span class="n">stderr</span><span class="p">.</span><span class="nf">strip</span><span class="p">()</span>
                <span class="p">})</span>
            <span class="k">except</span> <span class="n">subprocess</span><span class="p">.</span><span class="n">TimeoutExpired</span><span class="p">:</span>
                <span class="n">results</span><span class="p">.</span><span class="nf">append</span><span class="p">({</span>
                    <span class="sh">'</span><span class="s">passed</span><span class="sh">'</span><span class="p">:</span> <span class="bp">False</span><span class="p">,</span>
                    <span class="sh">'</span><span class="s">output</span><span class="sh">'</span><span class="p">:</span> <span class="sh">''</span><span class="p">,</span>
                    <span class="sh">'</span><span class="s">expected</span><span class="sh">'</span><span class="p">:</span> <span class="n">test</span><span class="p">[</span><span class="sh">'</span><span class="s">expected</span><span class="sh">'</span><span class="p">],</span>
                    <span class="sh">'</span><span class="s">error</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">Zaman aşımı</span><span class="sh">'</span>
                <span class="p">})</span>

    <span class="n">score</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">r</span><span class="p">[</span><span class="sh">'</span><span class="s">passed</span><span class="sh">'</span><span class="p">]</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">results</span><span class="p">)</span> <span class="o">/</span> <span class="nf">len</span><span class="p">(</span><span class="n">results</span><span class="p">)</span> <span class="o">*</span> <span class="mi">100</span>
    <span class="k">return</span> <span class="n">score</span><span class="p">,</span> <span class="n">results</span>
</code></pre></div></div>

<p>Bu kodun yaptığı iş şudur: gönderilen Python kodu geçici klasöre kaydedilir, her test girdisi programa verilir, standart çıktı yakalanır ve beklenen sonuçla karşılaştırılır. <code class="language-plaintext highlighter-rouge">timeout</code> parametresi sonsuz döngüleri durdurmak için ilk savunma hattıdır. Fakat tek başına yeterli değildir; öğrenci kodu <code class="language-plaintext highlighter-rouge">open()</code> ile dosya okuyabilir veya çok bellek harcayabilir.</p>

<p>Daha güvenli mimaride her çözüm ayrı bir konteyner içinde çalışır. Docker tabanlı yaklaşımda işlemci, bellek ve dosya sistemi sınırlandırılır. Mantık kabaca şöyledir:</p>

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

<span class="k">def</span> <span class="nf">run_in_docker</span><span class="p">(</span><span class="n">file_path</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">subprocess</span><span class="p">.</span><span class="nf">run</span><span class="p">(</span>
        <span class="p">[</span>
            <span class="sh">'</span><span class="s">docker</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">run</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">--rm</span><span class="sh">'</span><span class="p">,</span>
            <span class="sh">'</span><span class="s">--network</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">none</span><span class="sh">'</span><span class="p">,</span>
            <span class="sh">'</span><span class="s">--memory</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">128m</span><span class="sh">'</span><span class="p">,</span>
            <span class="sh">'</span><span class="s">--cpus</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">0.5</span><span class="sh">'</span><span class="p">,</span>
            <span class="sh">'</span><span class="s">-v</span><span class="sh">'</span><span class="p">,</span> <span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">file_path</span><span class="si">}</span><span class="s">:/app/solution.py:ro</span><span class="sh">'</span><span class="p">,</span>
            <span class="sh">'</span><span class="s">python:3.12-slim</span><span class="sh">'</span><span class="p">,</span>
            <span class="sh">'</span><span class="s">python</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">/app/solution.py</span><span class="sh">'</span>
        <span class="p">],</span>
        <span class="n">text</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
        <span class="n">capture_output</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
        <span class="n">timeout</span><span class="o">=</span><span class="mi">3</span>
    <span class="p">)</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">--network none</code> ağ erişimini kapatır, <code class="language-plaintext highlighter-rouge">--memory</code> bellek sınırı koyar, <code class="language-plaintext highlighter-rouge">--cpus</code> işlemci kullanımını kısıtlar. Dosya <code class="language-plaintext highlighter-rouge">:ro</code> ile salt okunur bağlanır. Yani öğrenci kodu küçük bir akvaryumda yüzer; okyanusa açılamaz.</p>

<p>Test tasarımı da en az güvenlik kadar önemlidir. Sadece örnek testlerle notlandırma yapmak, öğrencileri çıktı ezberlemeye iter. İyi bir sistemde görünür testler öğrenmeyi destekler, gizli testler ise genelleme yeteneğini ölçer. Ayrıca geri bildirim metinleri pedagojik olmalıdır: yalnızca yanlış demek yerine, hangi durumda hata oluştuğunu söylemek öğrencinin öğrenmesini hızlandırır.</p>

<p>Sonuç olarak Python ile auto-grader geliştirmek; <code class="language-plaintext highlighter-rouge">subprocess</code>, test mühendisliği, güvenlik ve eğitim psikolojisini bir araya getiren harika bir projedir. Küçük başlayın: birkaç test, zaman sınırı ve JSON sonuçları üretin. Sonra Docker sandbox, gizli test havuzu, kısmi puanlama ve web arayüzü ekleyin. Bir süre sonra fark edeceksiniz: artık sadece kod çalıştıran bir araç değil, öğrenciye anında geri bildirim veren mini bir öğretmen inşa ettiniz.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="python" /><category term="auto-grader" /><category term="eğitim teknolojileri" /><category term="test otomasyonu" /><summary type="html"><![CDATA[Bir öğrencinin yazdığı kodu saniyeler içinde çalıştırıp çıktısını kontrol eden, puanını hesaplayan ve geri bildirim veren sistemler kulağa küçük bir sihirbazlık gibi gelir. Aslında bu sihrin adı auto-grader: test senaryoları, izole çalışma ortamı ve adil puanlama mantığının birleşimi. Python ile böyle bir sistem geliştirmek hem eğitim platformları hem de kodlama yarışmaları için çok güçlü bir projedir.]]></summary></entry><entry><title type="html">SQL ile Davranışsal Analiz: Kullanıcı Yolculuğunu Sorgularla Okumak</title><link href="https://sonsuzus.github.io/posts/sql-ile-davranissal-analiz-kullanici-yolculugunu-sorgularla-okumak/" rel="alternate" type="text/html" title="SQL ile Davranışsal Analiz: Kullanıcı Yolculuğunu Sorgularla Okumak" /><published>2026-07-16T00:00:00+00:00</published><updated>2026-07-16T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/sql-ile-davranissal-analiz-kullanici-yolculugunu-sorgularla-okumak</id><content type="html" xml:base="https://sonsuzus.github.io/posts/sql-ile-davranissal-analiz-kullanici-yolculugunu-sorgularla-okumak/"><![CDATA[<p>Bir kullanıcının uygulamada attığı her adım, aslında küçük bir dijital ayak izidir: ana sayfayı açar, kategori gezer, ürüne bakar, sepete ekler, bazen de sessizce kaybolur. SQL ile davranışsal analiz, bu izleri düzenleyip anlamlı bir hikâyeye dönüştürme sanatıdır. Amaç sadece rapor çıkarmak değil; kullanıcının niyetini tahmin edip ona doğru zamanda doğru içerik, kampanya veya öneriyi sunmaktır.
``
Davranışsal analizin temelinde olay tabanlı veri modeli vardır. Klasik kullanıcı tablosu bize kullanıcının kim olduğunu söylerken, olay tablosu ne yaptığını anlatır. Genellikle <code class="language-plaintext highlighter-rouge">user_id</code>, <code class="language-plaintext highlighter-rouge">event_name</code>, <code class="language-plaintext highlighter-rouge">platform</code>, <code class="language-plaintext highlighter-rouge">event_time</code>, <code class="language-plaintext highlighter-rouge">session_id</code> ve ek özelliklerin tutulduğu bir yapı kullanılır. Burada kritik nokta zamandır; çünkü davranış, sıralama olmadan sadece dağınık noktalar kümesidir.</p>

<p>Matematiksel olarak kullanıcı yolculuğunu bir dizi gibi düşünebiliriz: $J_u = [e_1, e_2, e_3, …, e_n]$. Burada $u$ kullanıcıyı, $e_i$ ise i. olayı temsil eder. Eğer kullanıcıların bir sonraki adımını tahmin etmek istiyorsak, basitçe şu olasılıkla ilgileniriz: $P(e_{i+1} \mid e_i)$. Yani kullanıcı ürün detayına baktıysa, bir sonraki adımının sepete ekleme olma ihtimali nedir?</p>

<table>
  <thead>
    <tr>
      <th>Analiz Türü</th>
      <th>Sorduğu Soru</th>
      <th>SQL Tekniği</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Funnel analizi</td>
      <td>Kullanıcılar hangi adımda düşüyor?</td>
      <td>CTE, COUNT DISTINCT</td>
    </tr>
    <tr>
      <td>Sıralı davranış</td>
      <td>Bir olaydan sonra ne geliyor?</td>
      <td>LAG, LEAD</td>
    </tr>
    <tr>
      <td>Segmentasyon</td>
      <td>Benzer kullanıcılar kimler?</td>
      <td>CASE WHEN, GROUP BY</td>
    </tr>
    <tr>
      <td>Kişiselleştirme</td>
      <td>Kime ne önerelim?</td>
      <td>Skorlama, JOIN</td>
    </tr>
  </tbody>
</table>

<p>Örneğin farklı platformlarda ürün görüntüleme sonrası sepete ekleme oranını ölçmek isteyelim. Aşağıdaki sorgu, kullanıcıların olay sırasını inceler ve <code class="language-plaintext highlighter-rouge">view_product</code> olayından sonra gelen adımı yakalar:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">WITH</span> <span class="n">ordered_events</span> <span class="k">AS</span> <span class="p">(</span>
  <span class="k">SELECT</span>
    <span class="n">user_id</span><span class="p">,</span>
    <span class="n">platform</span><span class="p">,</span>
    <span class="n">event_name</span><span class="p">,</span>
    <span class="n">event_time</span><span class="p">,</span>
    <span class="n">LEAD</span><span class="p">(</span><span class="n">event_name</span><span class="p">)</span> <span class="n">OVER</span> <span class="p">(</span>
      <span class="k">PARTITION</span> <span class="k">BY</span> <span class="n">user_id</span><span class="p">,</span> <span class="n">platform</span>
      <span class="k">ORDER</span> <span class="k">BY</span> <span class="n">event_time</span>
    <span class="p">)</span> <span class="k">AS</span> <span class="n">next_event</span>
  <span class="k">FROM</span> <span class="n">events</span>
  <span class="k">WHERE</span> <span class="n">event_time</span> <span class="o">&gt;=</span> <span class="k">CURRENT_DATE</span> <span class="o">-</span> <span class="n">INTERVAL</span> <span class="s1">'30 day'</span>
<span class="p">),</span> <span class="n">transitions</span> <span class="k">AS</span> <span class="p">(</span>
  <span class="k">SELECT</span>
    <span class="n">platform</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">product_views</span><span class="p">,</span>
    <span class="k">SUM</span><span class="p">(</span><span class="k">CASE</span> <span class="k">WHEN</span> <span class="n">next_event</span> <span class="o">=</span> <span class="s1">'add_to_cart'</span> <span class="k">THEN</span> <span class="mi">1</span> <span class="k">ELSE</span> <span class="mi">0</span> <span class="k">END</span><span class="p">)</span> <span class="k">AS</span> <span class="n">cart_adds</span>
  <span class="k">FROM</span> <span class="n">ordered_events</span>
  <span class="k">WHERE</span> <span class="n">event_name</span> <span class="o">=</span> <span class="s1">'view_product'</span>
  <span class="k">GROUP</span> <span class="k">BY</span> <span class="n">platform</span>
<span class="p">)</span>
<span class="k">SELECT</span>
  <span class="n">platform</span><span class="p">,</span>
  <span class="n">product_views</span><span class="p">,</span>
  <span class="n">cart_adds</span><span class="p">,</span>
  <span class="n">ROUND</span><span class="p">(</span><span class="n">cart_adds</span> <span class="o">*</span> <span class="mi">100</span><span class="p">.</span><span class="mi">0</span> <span class="o">/</span> <span class="k">NULLIF</span><span class="p">(</span><span class="n">product_views</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">conversion_rate</span>
<span class="k">FROM</span> <span class="n">transitions</span><span class="p">;</span>
</code></pre></div></div>

<p>Bu sorgu bize örneğin mobilde ürün görenlerin daha fazla sepete eklediğini, webde ise kullanıcıların kararsız kaldığını gösterebilir. Böylece web kullanıcılarına karşılaştırma kartları, mobil kullanıcılara hızlı ödeme butonu sunmak mantıklı hale gelir.</p>

<p>Kişiselleştirme tarafında ise davranışları puanlamak çok işe yarar. Basit bir skor formülü şöyle kurulabilir:</p>

\[score = 5 \times cart + 3 \times view + 2 \times favorite - 4 \times bounce\]

<p>Bu formül mükemmel olmak zorunda değildir; başlangıç için sezgisel olması yeterlidir. SQL ile bunu hesaplayabiliriz:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span>
  <span class="n">user_id</span><span class="p">,</span>
  <span class="n">category_id</span><span class="p">,</span>
  <span class="k">SUM</span><span class="p">(</span>
    <span class="k">CASE</span>
      <span class="k">WHEN</span> <span class="n">event_name</span> <span class="o">=</span> <span class="s1">'add_to_cart'</span> <span class="k">THEN</span> <span class="mi">5</span>
      <span class="k">WHEN</span> <span class="n">event_name</span> <span class="o">=</span> <span class="s1">'view_product'</span> <span class="k">THEN</span> <span class="mi">3</span>
      <span class="k">WHEN</span> <span class="n">event_name</span> <span class="o">=</span> <span class="s1">'favorite'</span> <span class="k">THEN</span> <span class="mi">2</span>
      <span class="k">WHEN</span> <span class="n">event_name</span> <span class="o">=</span> <span class="s1">'bounce'</span> <span class="k">THEN</span> <span class="o">-</span><span class="mi">4</span>
      <span class="k">ELSE</span> <span class="mi">0</span>
    <span class="k">END</span>
  <span class="p">)</span> <span class="k">AS</span> <span class="n">interest_score</span>
<span class="k">FROM</span> <span class="n">events</span>
<span class="k">WHERE</span> <span class="n">event_time</span> <span class="o">&gt;=</span> <span class="k">CURRENT_DATE</span> <span class="o">-</span> <span class="n">INTERVAL</span> <span class="s1">'14 day'</span>
<span class="k">GROUP</span> <span class="k">BY</span> <span class="n">user_id</span><span class="p">,</span> <span class="n">category_id</span>
<span class="k">HAVING</span> <span class="k">SUM</span><span class="p">(</span>
  <span class="k">CASE</span>
    <span class="k">WHEN</span> <span class="n">event_name</span> <span class="o">=</span> <span class="s1">'add_to_cart'</span> <span class="k">THEN</span> <span class="mi">5</span>
    <span class="k">WHEN</span> <span class="n">event_name</span> <span class="o">=</span> <span class="s1">'view_product'</span> <span class="k">THEN</span> <span class="mi">3</span>
    <span class="k">WHEN</span> <span class="n">event_name</span> <span class="o">=</span> <span class="s1">'favorite'</span> <span class="k">THEN</span> <span class="mi">2</span>
    <span class="k">WHEN</span> <span class="n">event_name</span> <span class="o">=</span> <span class="s1">'bounce'</span> <span class="k">THEN</span> <span class="o">-</span><span class="mi">4</span>
    <span class="k">ELSE</span> <span class="mi">0</span>
  <span class="k">END</span>
<span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">;</span>
</code></pre></div></div>

<p>Bu çıktıyı içerik tablosuyla birleştirerek kullanıcılara en yüksek skorlu kategorilerden öneriler gösterebilirsiniz. Mesela oyun laptoplarına bakan ama satın almayan kullanıcıya inceleme videosu, sepete ekleyip çıkan kullanıcıya sınırlı süreli indirim sunulabilir.</p>

<table>
  <thead>
    <tr>
      <th>Kullanıcı Davranışı</th>
      <th>Olası Niyet</th>
      <th>Önerilen İçerik</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Çok görüntüleme, sepet yok</td>
      <td>Araştırıyor</td>
      <td>Rehber yazı, karşılaştırma</td>
    </tr>
    <tr>
      <td>Sepete ekleme, satın alma yok</td>
      <td>Tereddüt ediyor</td>
      <td>Kupon, ücretsiz kargo</td>
    </tr>
    <tr>
      <td>Favori ekleme</td>
      <td>İlgileniyor</td>
      <td>Stok bildirimi</td>
    </tr>
    <tr>
      <td>Hızlı çıkış</td>
      <td>Uyuşmadı</td>
      <td>Alternatif kategori</td>
    </tr>
  </tbody>
</table>

<p>Elbette bu analizlerde dikkat edilmesi gereken iki büyük konu vardır: veri kalitesi ve gizlilik. Aynı kullanıcının farklı cihazlarda parçalanması, saat dilimi hataları veya yanlış event isimleri sonuçları bozabilir. Ayrıca kişiselleştirme yaparken kullanıcı rızası, anonimleştirme ve veri minimizasyonu unutulmamalıdır.</p>

<p>Sonuç olarak SQL, sadece veri çekme dili değil; kullanıcı davranışlarını anlamak için güçlü bir mercek gibidir. Doğru modellenmiş olay verisi, pencere fonksiyonları ve akıllı skorlama ile platformlarınız kullanıcıya ‘beni anlıyor’ hissi verebilir. Ve kabul edelim: İyi yazılmış bir SQL sorgusu, bazen en havalı yapay zekâ modelinden bile daha hızlı değer üretir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="SQL" /><category term="Davranışsal Analiz" /><category term="Kişiselleştirme" /><summary type="html"><![CDATA[Bir kullanıcının uygulamada attığı her adım, aslında küçük bir dijital ayak izidir: ana sayfayı açar, kategori gezer, ürüne bakar, sepete ekler, bazen de sessizce kaybolur. SQL ile davranışsal analiz, bu izleri düzenleyip anlamlı bir hikâyeye dönüştürme sanatıdır. Amaç sadece rapor çıkarmak değil; kullanıcının niyetini tahmin edip ona doğru zamanda doğru içerik, kampanya veya öneriyi sunmaktır.]]></summary></entry><entry><title type="html">C ile Gömülü Sistemlerde Bellek Yönetimi: Her Byte’ın Hesabını Tutmak</title><link href="https://sonsuzus.github.io/posts/c-ile-gomulu-sistemlerde-bellek-yonetimi-her-bytein-hesabini-tutmak/" rel="alternate" type="text/html" title="C ile Gömülü Sistemlerde Bellek Yönetimi: Her Byte’ın Hesabını Tutmak" /><published>2026-07-15T00:00:00+00:00</published><updated>2026-07-15T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/c-ile-gomulu-sistemlerde-bellek-yonetimi-her-bytein-hesabini-tutmak</id><content type="html" xml:base="https://sonsuzus.github.io/posts/c-ile-gomulu-sistemlerde-bellek-yonetimi-her-bytein-hesabini-tutmak/"><![CDATA[<p>Gömülü sistemlerde bellek yönetimi, masaüstü programlamadaki konforlu dünyadan biraz farklıdır: burada RAM bazen birkaç kilobayttır, heap kullanmak riskli olabilir ve yanlış boyutlandırılmış bir dizi tüm kontrol döngüsünü sabote edebilir. C dili bu dünyada hâlâ kraldır; çünkü donanıma yakın çalışır, maliyeti düşüktür ve geliştiriciye her byte üzerinde doğrudan kontrol verir.
``
Bir mikrodenetleyicide bellek genellikle üç ana bölge gibi düşünülür: Flash, RAM ve çevresel register alanları. Flash program kodunu ve sabit verileri tutar; RAM ise çalışma zamanındaki değişkenler, stack ve varsa heap için kullanılır. Kısıtlı sistemlerde temel denklem şudur: $RAM_{kalan} = RAM_{toplam} - (global + stack + heap + buffer)$. Bu denklem basit görünür ama gerçek hayatta her kesme rutini, her geçici değişken ve her iletişim tamponu bu hesabı değiştirir.</p>

<table>
  <thead>
    <tr>
      <th>Bellek Alanı</th>
      <th>Ne İçin Kullanılır?</th>
      <th>Avantaj</th>
      <th>Risk</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Flash</td>
      <td>Kod, sabit tablolar</td>
      <td>RAM tüketmez</td>
      <td>Yazma yavaştır, sınırlı ömür</td>
    </tr>
    <tr>
      <td>Global/Static RAM</td>
      <td>Kalıcı değişkenler</td>
      <td>Öngörülebilir</td>
      <td>Fazla kullanılırsa RAM biter</td>
    </tr>
    <tr>
      <td>Stack</td>
      <td>Fonksiyon çağrıları, yerel değişkenler</td>
      <td>Hızlı</td>
      <td>Taşma tespiti zordur</td>
    </tr>
    <tr>
      <td>Heap</td>
      <td>Dinamik ayırma</td>
      <td>Esnek</td>
      <td>Parçalanma ve belirsizlik</td>
    </tr>
  </tbody>
</table>

<p>Kontrol döngülerinde hedef yalnızca az bellek kullanmak değildir; aynı zamanda zamanlamayı da garanti etmektir. Örneğin bir motor kontrol döngüsünde örnekleme süresi $T_s = 1ms$ ise, bellek ayırma yüzünden oluşan rastgele gecikmeler kabul edilemez. Bu yüzden gömülü C projelerinde <code class="language-plaintext highlighter-rouge">malloc</code> ve <code class="language-plaintext highlighter-rouge">free</code> çoğu zaman yasaklı kelimeler gibidir. Heap parçalanması, başlangıçta çalışıp saatler sonra çöken cihazların klasik sebeplerindendir.</p>

<p>Dinamik ayırma gerekiyorsa, genel amaçlı heap yerine sabit bloklu bir bellek havuzu daha güvenlidir. Aşağıdaki örnek, 16 adet sabit boyutlu mesaj bloğunu yönetir. Böylece ayırma süresi yaklaşık sabittir ve parçalanma oluşmaz.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdint.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stddef.h&gt;</span><span class="cp">
</span>
<span class="cp">#define BLOCK_SIZE 32
#define BLOCK_COUNT 16
</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="n">data</span><span class="p">[</span><span class="n">BLOCK_SIZE</span><span class="p">];</span>
    <span class="kt">uint8_t</span> <span class="n">used</span><span class="p">;</span>
<span class="p">}</span> <span class="n">Block</span><span class="p">;</span>

<span class="k">static</span> <span class="n">Block</span> <span class="n">pool</span><span class="p">[</span><span class="n">BLOCK_COUNT</span><span class="p">];</span>

<span class="kt">void</span> <span class="o">*</span><span class="nf">pool_alloc</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">uint8_t</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">BLOCK_COUNT</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">pool</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">used</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">pool</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">used</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
            <span class="k">return</span> <span class="n">pool</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">data</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">pool_free</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">uint8_t</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">BLOCK_COUNT</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">pool</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="n">ptr</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">pool</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">used</span> <span class="o">=</span> <span class="mi">0</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>Bu kodda belleğin tamamı derleme zamanında ayrılır. <code class="language-plaintext highlighter-rouge">pool_alloc</code>, boş bir blok bulur ve işaretçi döndürür. <code class="language-plaintext highlighter-rouge">pool_free</code> ise bloğu tekrar kullanılabilir hâle getirir. Dezavantajı, her bloğun aynı boyutta olmasıdır; 5 byte veriye de 32 byte ayrılır. Ancak gömülü sistemlerde öngörülebilirlik çoğu zaman maksimum verimden daha değerlidir.</p>

<p>Stack kullanımı da ayrıca izlenmelidir. Büyük dizileri fonksiyon içinde tanımlamak cazip görünür ama tehlikelidir. Örneğin <code class="language-plaintext highlighter-rouge">uint8_t buffer[1024];</code> satırı, 2 KB RAM bulunan bir mikrodenetleyicide felaketin yarısı olabilir. Büyük tamponlar global veya static tanımlanmalı, mümkünse boyutları hesaplanmalıdır: \(Buffer_{toplam}=N_{paket}\times Boyut_{paket}\). Eğer UART üzerinden 8 paket tutulacak ve her paket 32 byte olacaksa toplam tampon 256 byte eder; kulağa az gelir ama 2 KB RAM içinde yüzde 12.5 demektir.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Ne Zaman Tercih Edilir?</th>
      <th>Bellek Davranışı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Yerel küçük değişken</td>
      <td>Kısa hesaplamalar</td>
      <td>Stack üzerinde hızlı</td>
    </tr>
    <tr>
      <td>Static tampon</td>
      <td>Sürekli kullanılan veri</td>
      <td>Sabit RAM tüketimi</td>
    </tr>
    <tr>
      <td>Ring buffer</td>
      <td>UART, ADC, sensör akışı</td>
      <td>Verimli ve tahmin edilebilir</td>
    </tr>
    <tr>
      <td>Heap</td>
      <td>Nadiren önerilir</td>
      <td>Esnek ama riskli</td>
    </tr>
  </tbody>
</table>

<p>Veri tipi seçimi de byte avcılığının eğlenceli kısmıdır. Sıcaklık 0-100 arasıysa <code class="language-plaintext highlighter-rouge">uint8_t</code> yeterli olabilir; sayaç 100000 değerine çıkacaksa <code class="language-plaintext highlighter-rouge">uint32_t</code> gerekir. Ancak işlemci 8 bit ise 32 bit aritmetik daha yavaş olabilir. Yani bellek optimizasyonu ile CPU maliyeti birlikte düşünülmelidir.</p>

<p>Pratikte iyi bir strateji şudur: önce bellek haritasını çıkar, global değişkenleri say, maksimum stack derinliğini tahmin et, kesme rutinlerinde büyük işlem yapma ve iletişim tamponlarını matematiksel olarak boyutlandır. Derleyicinin map dosyası bu noktada hazine haritasıdır; hangi sembolün kaç byte tuttuğunu gösterir.</p>

<p>Sonuç olarak C ile gömülü sistemlerde bellek yönetimi, biraz muhasebe biraz da mühendislik sezgisidir. Her byte’ın bir görevi olmalı, her tamponun nedeni bilinmeli ve her kontrol döngüsü zamanında bitmelidir. Kaynak kısıtlı olabilir; ama iyi tasarlanmış bir bellek düzeniyle küçük bir mikrodenetleyici bile şaşırtıcı derecede kararlı ve güçlü çalışabilir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="C" /><category term="Gömülü Sistemler" /><category term="Bellek Yönetimi" /><category term="Mikrodenetleyici" /><summary type="html"><![CDATA[Gömülü sistemlerde bellek yönetimi, masaüstü programlamadaki konforlu dünyadan biraz farklıdır: burada RAM bazen birkaç kilobayttır, heap kullanmak riskli olabilir ve yanlış boyutlandırılmış bir dizi tüm kontrol döngüsünü sabote edebilir. C dili bu dünyada hâlâ kraldır; çünkü donanıma yakın çalışır, maliyeti düşüktür ve geliştiriciye her byte üzerinde doğrudan kontrol verir.]]></summary></entry><entry><title type="html">JavaScript ile Mantık Bulmacaları Çözücüleri: Tarayıcıda Adım Adım Algoritma Şovu</title><link href="https://sonsuzus.github.io/posts/javascript-ile-mantik-bulmacalari-cozuculeri-tarayicida-adim-adim-algoritma-sovu/" rel="alternate" type="text/html" title="JavaScript ile Mantık Bulmacaları Çözücüleri: Tarayıcıda Adım Adım Algoritma Şovu" /><published>2026-07-15T00:00:00+00:00</published><updated>2026-07-15T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/javascript-ile-mantik-bulmacalari-cozuculeri-tarayicida-adim-adim-algoritma-sovu</id><content type="html" xml:base="https://sonsuzus.github.io/posts/javascript-ile-mantik-bulmacalari-cozuculeri-tarayicida-adim-adim-algoritma-sovu/"><![CDATA[<p>Bir Sudoku karesine bakıp beyninizin fanlarının hızlandığını hissettiyseniz, yalnız değilsiniz. Güzel haber şu: JavaScript ile tarayıcı üzerinde çalışan, hem bulmacayı çözen hem de çözüm adımlarını görselleştiren etkileşimli çözücüler yazabiliriz. Bu yazıda mantık bulmacalarını sadece kodla çözmeyi değil, algoritmanın nasıl düşündüğünü kullanıcıya sahne sahne göstermeyi konuşacağız.
``</p>

<h2 id="bulmaca-çözmek-aslında-arama-problemidir">Bulmaca çözmek aslında arama problemidir</h2>

<p>Birçok mantık bulmacası, bilgisayar bilimi açısından bir <strong>durum uzayı araması</strong> problemidir. Elimizde başlangıç durumu, geçerli hamle kuralları ve hedef durum vardır. Örneğin Sudoku için hedef, her satırda, sütunda ve 3x3 kutuda 1’den 9’a kadar sayıların çakışmadan yerleşmesidir.</p>

<p>Teorik olarak her boş hücre için olasılıkları deneriz. Eğer $b$ her adımda ortalama seçenek sayısı, $d$ ise boş hücre sayısıysa kaba karmaşıklık $O(b^d)$ olur. Kulağa korkutucu geliyor; çünkü gerçekten de öyle. Ama kısıtlar ve akıllı seçim stratejileriyle arama ağacını ciddi biçimde budayabiliriz.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Mantık</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Brute force</td>
      <td>Tüm olasılıkları dener</td>
      <td>Basit uygulanır</td>
      <td>Çok yavaş olabilir</td>
    </tr>
    <tr>
      <td>Backtracking</td>
      <td>Hatalı yolda geri döner</td>
      <td>Pratik ve anlaşılır</td>
      <td>Kötü seçimlerde dallanır</td>
    </tr>
    <tr>
      <td>Constraint propagation</td>
      <td>İmkansız seçenekleri erken eler</td>
      <td>Çok hızlandırır</td>
      <td>Kuralları modellemek gerekir</td>
    </tr>
    <tr>
      <td>Heuristic seçim</td>
      <td>En az seçenekli hücreyi seçer</td>
      <td>Aramayı küçültür</td>
      <td>Ek hesaplama ister</td>
    </tr>
  </tbody>
</table>

<h2 id="tarayıcı-neden-harika-bir-oyun-alanı">Tarayıcı neden harika bir oyun alanı?</h2>

<p>Tarayıcı bize üç güzel şey verir: DOM ile görsel arayüz, Canvas/SVG ile çizim ve <code class="language-plaintext highlighter-rouge">async/await</code> ile adım adım animasyon. Böylece algoritma sadece sonucu basmaz; hangi hücreyi denediğini, nerede çuvalladığını ve neden geri döndüğünü de gösterir. Kullanıcı için bu, kara kutu yerine cam kutu deneyimidir.</p>

<p>Aşağıdaki örnek, basitleştirilmiş bir Sudoku çözücünün kalbini gösterir. Amaç, boş hücre bulmak, geçerli sayıları denemek ve çıkmaz sokakta geri almaktır.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">findEmpty</span><span class="p">(</span><span class="nx">board</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">r</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">r</span> <span class="o">&lt;</span> <span class="mi">9</span><span class="p">;</span> <span class="nx">r</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">c</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">c</span> <span class="o">&lt;</span> <span class="mi">9</span><span class="p">;</span> <span class="nx">c</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">if </span><span class="p">(</span><span class="nx">board</span><span class="p">[</span><span class="nx">r</span><span class="p">][</span><span class="nx">c</span><span class="p">]</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="p">{</span> <span class="nx">r</span><span class="p">,</span> <span class="nx">c</span> <span class="p">};</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nf">isValid</span><span class="p">(</span><span class="nx">board</span><span class="p">,</span> <span class="nx">r</span><span class="p">,</span> <span class="nx">c</span><span class="p">,</span> <span class="nx">n</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">9</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">board</span><span class="p">[</span><span class="nx">r</span><span class="p">][</span><span class="nx">i</span><span class="p">]</span> <span class="o">===</span> <span class="nx">n</span> <span class="o">||</span> <span class="nx">board</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="nx">c</span><span class="p">]</span> <span class="o">===</span> <span class="nx">n</span><span class="p">)</span> <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="kd">const</span> <span class="nx">sr</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="nx">r</span> <span class="o">/</span> <span class="mi">3</span><span class="p">)</span> <span class="o">*</span> <span class="mi">3</span><span class="p">;</span>
  <span class="kd">const</span> <span class="nx">sc</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="nx">c</span> <span class="o">/</span> <span class="mi">3</span><span class="p">)</span> <span class="o">*</span> <span class="mi">3</span><span class="p">;</span>

  <span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="nx">sr</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">sr</span> <span class="o">+</span> <span class="mi">3</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">j</span> <span class="o">=</span> <span class="nx">sc</span><span class="p">;</span> <span class="nx">j</span> <span class="o">&lt;</span> <span class="nx">sc</span> <span class="o">+</span> <span class="mi">3</span><span class="p">;</span> <span class="nx">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">if </span><span class="p">(</span><span class="nx">board</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="nx">j</span><span class="p">]</span> <span class="o">===</span> <span class="nx">n</span><span class="p">)</span> <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu iki fonksiyon hakem gibi çalışır. <code class="language-plaintext highlighter-rouge">findEmpty</code>, sıradaki problemi bulur; <code class="language-plaintext highlighter-rouge">isValid</code> ise önerilen hamlenin kurallara uygun olup olmadığını söyler. Şimdi buna görsellik ekleyelim.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">sleep</span> <span class="o">=</span> <span class="nx">ms</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="nc">Promise</span><span class="p">(</span><span class="nx">resolve</span> <span class="o">=&gt;</span> <span class="nf">setTimeout</span><span class="p">(</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">ms</span><span class="p">));</span>

<span class="k">async</span> <span class="kd">function</span> <span class="nf">solve</span><span class="p">(</span><span class="nx">board</span><span class="p">,</span> <span class="nx">render</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">cell</span> <span class="o">=</span> <span class="nf">findEmpty</span><span class="p">(</span><span class="nx">board</span><span class="p">);</span>
  <span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">cell</span><span class="p">)</span> <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>

  <span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">n</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">n</span> <span class="o">&lt;=</span> <span class="mi">9</span><span class="p">;</span> <span class="nx">n</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if </span><span class="p">(</span><span class="nf">isValid</span><span class="p">(</span><span class="nx">board</span><span class="p">,</span> <span class="nx">cell</span><span class="p">.</span><span class="nx">r</span><span class="p">,</span> <span class="nx">cell</span><span class="p">.</span><span class="nx">c</span><span class="p">,</span> <span class="nx">n</span><span class="p">))</span> <span class="p">{</span>
      <span class="nx">board</span><span class="p">[</span><span class="nx">cell</span><span class="p">.</span><span class="nx">r</span><span class="p">][</span><span class="nx">cell</span><span class="p">.</span><span class="nx">c</span><span class="p">]</span> <span class="o">=</span> <span class="nx">n</span><span class="p">;</span>
      <span class="nf">render</span><span class="p">(</span><span class="nx">board</span><span class="p">,</span> <span class="nx">cell</span><span class="p">,</span> <span class="dl">'</span><span class="s1">try</span><span class="dl">'</span><span class="p">);</span>
      <span class="k">await</span> <span class="nf">sleep</span><span class="p">(</span><span class="mi">80</span><span class="p">);</span>

      <span class="k">if </span><span class="p">(</span><span class="k">await</span> <span class="nf">solve</span><span class="p">(</span><span class="nx">board</span><span class="p">,</span> <span class="nx">render</span><span class="p">))</span> <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>

      <span class="nx">board</span><span class="p">[</span><span class="nx">cell</span><span class="p">.</span><span class="nx">r</span><span class="p">][</span><span class="nx">cell</span><span class="p">.</span><span class="nx">c</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
      <span class="nf">render</span><span class="p">(</span><span class="nx">board</span><span class="p">,</span> <span class="nx">cell</span><span class="p">,</span> <span class="dl">'</span><span class="s1">backtrack</span><span class="dl">'</span><span class="p">);</span>
      <span class="k">await</span> <span class="nf">sleep</span><span class="p">(</span><span class="mi">80</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">render</code> fonksiyonu arayüzü günceller. <code class="language-plaintext highlighter-rouge">try</code> durumunda hücre yeşil, <code class="language-plaintext highlighter-rouge">backtrack</code> durumunda kırmızı gösterilebilir. Böylece kullanıcı algoritmanın düşündüğü yolları izler.</p>

<h2 id="daha-zeki-çözücü-en-az-adaylı-hücre">Daha zeki çözücü: en az adaylı hücre</h2>

<p>Sıradaki boş hücreyi soldan sağa seçmek kolaydır ama her zaman akıllıca değildir. Daha iyi strateji, aday sayısı en az olan hücreyi seçmektir. Buna genellikle <strong>MRV</strong>, yani minimum remaining values denir. Eğer bir hücrede sadece 2 ihtimal, diğerinde 7 ihtimal varsa önce 2 ihtimalli hücreye bakmak mantıklıdır.</p>

<p>Bu yaklaşım arama ağacını küçültür. Örneğin teorik olarak $5^{40}$ gibi devasa bir deneme alanı, iyi kısıtlarla çok daha yönetilebilir hale gelir. Elbette garanti sihir değildir; fakat gerçek bulmacalarda fark şaşırtıcıdır.</p>

<h2 id="görsel-bulmacalara-genişletmek">Görsel bulmacalara genişletmek</h2>

<p>Aynı model Sudoku dışında Nonogram, KenKen, labirent, taş kaydırma oyunları ve hatta satranç problemleri için kullanılabilir. Değişen şey <code class="language-plaintext highlighter-rouge">isValid</code> fonksiyonunun kurallarıdır. Nonogram’da satır ipuçlarını, labirentte duvarları, satrançta taş hareketlerini kontrol edersiniz. Genel iskelet aynı kalır: durum üret, geçerliliği kontrol et, uygunsa ilerle, değilse geri dön.</p>

<h2 id="son-dokunuşlar">Son dokunuşlar</h2>

<p>Kullanıcıya hız kontrolü, adım sayacı, duraklat-devam et düğmesi ve çözüm geçmişi eklerseniz proje bir algoritma demosundan mini eğitim aracına dönüşür. Hatta her hamleyi bir listeye yazıp neden seçildiğini açıklayabilirsiniz. İşin eğlenceli tarafı şu: JavaScript burada yalnızca çözüm üreten bir araç değil, algoritmanın zihnini görünür kılan bir sahne yönetmenidir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="javascript" /><category term="algoritma" /><category term="bulmaca" /><category term="backtracking" /><category term="web" /><summary type="html"><![CDATA[Bir Sudoku karesine bakıp beyninizin fanlarının hızlandığını hissettiyseniz, yalnız değilsiniz. Güzel haber şu: JavaScript ile tarayıcı üzerinde çalışan, hem bulmacayı çözen hem de çözüm adımlarını görselleştiren etkileşimli çözücüler yazabiliriz. Bu yazıda mantık bulmacalarını sadece kodla çözmeyi değil, algoritmanın nasıl düşündüğünü kullanıcıya sahne sahne göstermeyi konuşacağız.]]></summary></entry><entry><title type="html">Python ile Webhook Entegrasyonları: Sosyal Medyadan Otomatik Konu Açma</title><link href="https://sonsuzus.github.io/posts/python-ile-webhook-entegrasyonlari-sosyal-medyadan-otomatik-konu-acma/" rel="alternate" type="text/html" title="Python ile Webhook Entegrasyonları: Sosyal Medyadan Otomatik Konu Açma" /><published>2026-07-15T00:00:00+00:00</published><updated>2026-07-15T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/python-ile-webhook-entegrasyonlari-sosyal-medyadan-otomatik-konu-acma</id><content type="html" xml:base="https://sonsuzus.github.io/posts/python-ile-webhook-entegrasyonlari-sosyal-medyadan-otomatik-konu-acma/"><![CDATA[<p>Sosyal medyada biri markanızdan bahsettiğinde, yeni bir gönderi paylaştığında veya belirli bir etiketi kullandığında başka bir sitede otomatik konu açıldığını düşünün. İşte webhook entegrasyonları tam olarak bu küçük dijital domino taşlarını devirir: bir olay olur, Python dinler, doğrular, işler ve hedef sisteme aksiyon aldırır.
``
Webhook, klasik API sorgulamasının tersine çalışan bir bildirim mekanizmasıdır. Normalde siz API’ye sürekli “Yeni bir şey var mı?” diye sorarsınız; buna polling denir. Webhook’ta ise platform size “Bir şey oldu, al sana veri!” der. Bu yaklaşım hem daha hızlıdır hem de gereksiz istek trafiğini azaltır.</p>

<p>Basit akış şöyledir:</p>

<ol>
  <li>Sosyal medya platformunda olay gerçekleşir.</li>
  <li>Platform, sizin belirlediğiniz URL’ye HTTP POST isteği gönderir.</li>
  <li>Python uygulamanız imzayı ve veriyi doğrular.</li>
  <li>Olay türüne göre hedef sitede konu açılır.</li>
  <li>Sonuç loglanır, hata varsa tekrar deneme kuyruğuna alınır.</li>
</ol>

<p>Teorik olarak bir webhook sistemini şu fonksiyon gibi düşünebiliriz:</p>

\[f(event) = action\]

<p>Burada $event$ sosyal medya hareketini, $action$ ise başka sitede konu açma işlemini temsil eder. Ancak gerçek dünyada iş biraz daha baharatlıdır: güvenlik, tekrar eden istekler, zaman aşımı, API limitleri ve veri eşleme gibi konular devreye girer.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Nasıl Çalışır?</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Polling</td>
      <td>Belirli aralıklarla API sorgulanır</td>
      <td>Kurulumu basit</td>
      <td>Gereksiz trafik ve gecikme</td>
    </tr>
    <tr>
      <td>Webhook</td>
      <td>Olay olunca platform size istek atar</td>
      <td>Anlık ve verimli</td>
      <td>Güvenlik ve erişilebilirlik ister</td>
    </tr>
    <tr>
      <td>Kuyruklu Webhook</td>
      <td>Olay kuyruğa alınır, sonra işlenir</td>
      <td>Dayanıklı ve ölçeklenebilir</td>
      <td>Ek altyapı gerekir</td>
    </tr>
  </tbody>
</table>

<p>Güvenlik tarafında en önemli noktalardan biri imza doğrulamadır. Platform genellikle gövde verisini gizli anahtarla imzalar. Siz de aynı hesabı yapıp gelen imzayla karşılaştırırsınız:</p>

\[signature = HMAC_{SHA256}(secret, payload)\]

<p>Eğer imzalar eşleşmiyorsa istek reddedilmelidir. Çünkü internete açık bir endpoint, robotların ve meraklı kişilerin favori oyun alanıdır.</p>

<p>Aşağıdaki örnek Flask ile yazılmış orta düzey bir webhook alıcısıdır. Gelen olayı doğrular, aynı olayın iki kez işlenmesini engeller ve hedef foruma konu açmak için örnek bir POST isteği gönderir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">os</span>
<span class="kn">import</span> <span class="n">hmac</span>
<span class="kn">import</span> <span class="n">hashlib</span>
<span class="kn">import</span> <span class="n">requests</span>
<span class="kn">from</span> <span class="n">flask</span> <span class="kn">import</span> <span class="n">Flask</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">abort</span><span class="p">,</span> <span class="n">jsonify</span>

<span class="n">app</span> <span class="o">=</span> <span class="nc">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>

<span class="n">SECRET</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">WEBHOOK_SECRET</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">dev-secret</span><span class="sh">'</span><span class="p">)</span>
<span class="n">FORUM_API</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">FORUM_API</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">https://forum.example.com/api/topics</span><span class="sh">'</span><span class="p">)</span>
<span class="n">FORUM_TOKEN</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">FORUM_TOKEN</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">demo-token</span><span class="sh">'</span><span class="p">)</span>

<span class="n">processed_events</span> <span class="o">=</span> <span class="nf">set</span><span class="p">()</span>

<span class="k">def</span> <span class="nf">verify_signature</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="n">received_signature</span><span class="p">):</span>
    <span class="n">expected</span> <span class="o">=</span> <span class="n">hmac</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span>
        <span class="n">SECRET</span><span class="p">.</span><span class="nf">encode</span><span class="p">(),</span>
        <span class="n">payload</span><span class="p">,</span>
        <span class="n">hashlib</span><span class="p">.</span><span class="n">sha256</span>
    <span class="p">).</span><span class="nf">hexdigest</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">hmac</span><span class="p">.</span><span class="nf">compare_digest</span><span class="p">(</span><span class="n">expected</span><span class="p">,</span> <span class="n">received_signature</span> <span class="ow">or</span> <span class="sh">''</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">create_topic</span><span class="p">(</span><span class="n">event</span><span class="p">):</span>
    <span class="n">username</span> <span class="o">=</span> <span class="n">event</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">username</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">bilinmeyen</span><span class="sh">'</span><span class="p">)</span>
    <span class="n">text</span> <span class="o">=</span> <span class="n">event</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">text</span><span class="sh">'</span><span class="p">,</span> <span class="sh">''</span><span class="p">)</span>
    <span class="n">platform</span> <span class="o">=</span> <span class="n">event</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">platform</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">sosyal medya</span><span class="sh">'</span><span class="p">)</span>

    <span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
        <span class="sh">'</span><span class="s">title</span><span class="sh">'</span><span class="p">:</span> <span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">platform</span><span class="si">}</span><span class="s"> üzerinde yeni hareket: </span><span class="si">{</span><span class="n">username</span><span class="si">}</span><span class="sh">'</span><span class="p">,</span>
        <span class="sh">'</span><span class="s">body</span><span class="sh">'</span><span class="p">:</span> <span class="sa">f</span><span class="sh">'</span><span class="s">Kullanıcı: </span><span class="si">{</span><span class="n">username</span><span class="si">}</span><span class="se">\n\n</span><span class="s">İçerik:</span><span class="se">\n</span><span class="si">{</span><span class="n">text</span><span class="si">}</span><span class="sh">'</span><span class="p">,</span>
        <span class="sh">'</span><span class="s">category</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">Sosyal Medya</span><span class="sh">'</span>
    <span class="p">}</span>

    <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
        <span class="sh">'</span><span class="s">Authorization</span><span class="sh">'</span><span class="p">:</span> <span class="sa">f</span><span class="sh">'</span><span class="s">Bearer </span><span class="si">{</span><span class="n">FORUM_TOKEN</span><span class="si">}</span><span class="sh">'</span>
    <span class="p">}</span>

    <span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="nf">post</span><span class="p">(</span><span class="n">FORUM_API</span><span class="p">,</span> <span class="n">json</span><span class="o">=</span><span class="n">data</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
    <span class="n">response</span><span class="p">.</span><span class="nf">raise_for_status</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">response</span><span class="p">.</span><span class="nf">json</span><span class="p">()</span>

<span class="nd">@app.post</span><span class="p">(</span><span class="sh">'</span><span class="s">/webhooks/social</span><span class="sh">'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">social_webhook</span><span class="p">():</span>
    <span class="n">payload</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="nf">get_data</span><span class="p">()</span>
    <span class="n">signature</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="n">headers</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">X-Signature</span><span class="sh">'</span><span class="p">)</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="nf">verify_signature</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="n">signature</span><span class="p">):</span>
        <span class="nf">abort</span><span class="p">(</span><span class="mi">401</span><span class="p">)</span>

    <span class="n">event</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="nf">get_json</span><span class="p">()</span>
    <span class="n">event_id</span> <span class="o">=</span> <span class="n">event</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">id</span><span class="sh">'</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">event_id</span> <span class="ow">in</span> <span class="n">processed_events</span><span class="p">:</span>
        <span class="k">return</span> <span class="nf">jsonify</span><span class="p">({</span><span class="sh">'</span><span class="s">status</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">duplicate_ignored</span><span class="sh">'</span><span class="p">})</span>

    <span class="n">processed_events</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="n">event_id</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">event</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">type</span><span class="sh">'</span><span class="p">)</span> <span class="o">==</span> <span class="sh">'</span><span class="s">mention</span><span class="sh">'</span><span class="p">:</span>
        <span class="n">result</span> <span class="o">=</span> <span class="nf">create_topic</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
        <span class="k">return</span> <span class="nf">jsonify</span><span class="p">({</span><span class="sh">'</span><span class="s">status</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">topic_created</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">result</span><span class="sh">'</span><span class="p">:</span> <span class="n">result</span><span class="p">})</span>

    <span class="k">return</span> <span class="nf">jsonify</span><span class="p">({</span><span class="sh">'</span><span class="s">status</span><span class="sh">'</span><span class="p">:</span> <span class="sh">'</span><span class="s">ignored</span><span class="sh">'</span><span class="p">})</span>
</code></pre></div></div>

<p>Bu kodda <code class="language-plaintext highlighter-rouge">processed_events</code> örnek amaçlı bellekte tutuluyor. Gerçek projede Redis, PostgreSQL veya benzeri kalıcı bir sistem kullanmak daha doğrudur. Çünkü uygulama yeniden başlarsa bellek sıfırlanır ve aynı olay tekrar konu açabilir. Bu probleme idempotency denir: aynı isteğin birden fazla kez gelmesi durumunda sistemin aynı sonucu üretmesi gerekir.</p>

<p>Veri eşleme de önemlidir. Sosyal medya olayı doğrudan forum konusuna dönüşmez; arada anlamlı bir çeviri katmanı gerekir.</p>

<table>
  <thead>
    <tr>
      <th>Webhook Alanı</th>
      <th>Forum Alanı</th>
      <th>Dönüşüm Mantığı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">username</code></td>
      <td>Konu başlığı</td>
      <td>Hareketi yapan kişiyi belirtir</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">text</code></td>
      <td>Konu içeriği</td>
      <td>Paylaşım veya yorum metni eklenir</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">platform</code></td>
      <td>Etiket</td>
      <td>Kaynağın neresi olduğu anlaşılır</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">created_at</code></td>
      <td>Zaman bilgisi</td>
      <td>Konunun bağlamını güçlendirir</td>
    </tr>
  </tbody>
</table>

<p>Hata yönetimi tarafında üstel geri çekilme kullanabilirsiniz. Örneğin tekrar deneme süresi şu şekilde büyüyebilir:</p>

\[delay = min(2^n, 300)\]

<p>Burada $n$ deneme sayısıdır, üst sınır ise 300 saniyedir. Böylece hedef site kısa süreli çökerse sisteminiz panikle spam atmaz.</p>

<p>Sonuç olarak Python ile webhook entegrasyonu, sadece bir endpoint yazmaktan ibaret değildir. Güvenli doğrulama, idempotency, veri dönüştürme, loglama ve tekrar deneme stratejileriyle birleşince ortaya sosyal medya hareketlerini otomatik aksiyona dönüştüren sağlam bir tetikleyici mekanizma çıkar. Küçük başlar, sonra bir bakmışsınız forumunuz sosyal medyanın nabzını gerçek zamanlı tutan mini bir haber merkezine dönüşmüş!</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="python" /><category term="webhook" /><category term="otomasyon" /><category term="api" /><summary type="html"><![CDATA[Sosyal medyada biri markanızdan bahsettiğinde, yeni bir gönderi paylaştığında veya belirli bir etiketi kullandığında başka bir sitede otomatik konu açıldığını düşünün. İşte webhook entegrasyonları tam olarak bu küçük dijital domino taşlarını devirir: bir olay olur, Python dinler, doğrular, işler ve hedef sisteme aksiyon aldırır.]]></summary></entry><entry><title type="html">C ile Donanım İletişimi: Eski Disklerden Adaptörlere Sürücü Mantığı</title><link href="https://sonsuzus.github.io/posts/c-ile-donanim-iletisimi-eski-disklerden-adaptorlere-surucu-mantigi/" rel="alternate" type="text/html" title="C ile Donanım İletişimi: Eski Disklerden Adaptörlere Sürücü Mantığı" /><published>2026-07-14T00:00:00+00:00</published><updated>2026-07-14T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/c-ile-donanim-iletisimi-eski-disklerden-adaptorlere-surucu-mantigi</id><content type="html" xml:base="https://sonsuzus.github.io/posts/c-ile-donanim-iletisimi-eski-disklerden-adaptorlere-surucu-mantigi/"><![CDATA[<p>Eski bir IDE disk, USB-SATA dönüştürücü ya da seri port adaptörü elinize geçtiğinde ilk soru genelde şudur: “Bunu işletim sistemiyle nasıl konuştururum?” C dili burada hâlâ sahnenin başrol oyuncusudur; çünkü donanıma yakın, bellek düzenini tahmin edilebilir kılan ve kesme, DMA, I/O portu gibi düşük seviye kavramları açıkça modelleyebilen bir araçtır.
``
Donanım iletişimini sürücü seviyesinde düşünürken üç katmanı ayırmak gerekir: fiziksel aygıt, denetleyici protokolü ve işletim sistemi arayüzü. Örneğin eski bir ATA disk doğrudan “dosya” bilmez; sektör okur, sektör yazar. Dosya sistemi ise bu ham blokların üzerine kurulan daha üst seviye bir soyutlamadır. Sürücü algoritmanızın görevi, işletim sisteminden gelen “şu blokları oku” isteğini aygıtın anlayacağı komutlara çevirmektir.</p>

<p>Teorik olarak blok tabanlı aygıtlarda en küçük adreslenebilir birim genellikle sektördür. Klasik disklerde sektör boyutu çoğunlukla 512 bayt, yeni disklerde ise 4096 bayt olabilir. Bir okuma işleminin yaklaşık maliyeti şu şekilde düşünülebilir:</p>

\[T_{okuma} = T_{arama} + T_{gecikme} + \frac{B}{R}\]

<p>Burada $B$ okunan bayt miktarı, $R$ aktarım hızı, $T_{arama}$ mekanik kafanın konumlanma süresi, $T_{gecikme}$ ise dönüş gecikmesidir. SSD ve USB adaptörlerde mekanik süreler yoktur ama komut kuyruğu, veri yolu gecikmesi ve köprü yongasının davranışı hâlâ önemlidir.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Kullanım Alanı</th>
      <th>Avantaj</th>
      <th>Risk</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Port I/O</td>
      <td>Eski x86 ATA, seri port</td>
      <td>Basit ve doğrudan</td>
      <td>Mimariye bağımlı</td>
    </tr>
    <tr>
      <td>MMIO</td>
      <td>PCI/PCIe aygıtlar</td>
      <td>Bellek gibi erişim</td>
      <td>Yanlış adres sistemi kilitleyebilir</td>
    </tr>
    <tr>
      <td>DMA</td>
      <td>Yüksek hızlı disk, ağ kartı</td>
      <td>CPU yükü az</td>
      <td>Bellek eşleme hataları tehlikeli</td>
    </tr>
    <tr>
      <td>USB sınıf sürücüsü</td>
      <td>Harici adaptörler</td>
      <td>Standart protokoller</td>
      <td>Köprü yongası farklı davranabilir</td>
    </tr>
  </tbody>
</table>

<p>C tarafında en temel fikir, donanım kayıtlarını temsil eden kesin boyutlu veri tipleri kullanmaktır. <code class="language-plaintext highlighter-rouge">uint8_t</code>, <code class="language-plaintext highlighter-rouge">uint16_t</code> ve <code class="language-plaintext highlighter-rouge">uint32_t</code> bu yüzden önemlidir. Ayrıca derleyicinin optimizasyon sırasında donanım erişimini “gereksiz” sanıp silmemesi için <code class="language-plaintext highlighter-rouge">volatile</code> kullanılır.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdint.h&gt;</span><span class="cp">
</span>
<span class="cp">#define ATA_DATA       0x1F0
#define ATA_SECTOR_CNT 0x1F2
#define ATA_LBA_LOW    0x1F3
#define ATA_COMMAND    0x1F7
</span>
<span class="k">static</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">outb</span><span class="p">(</span><span class="kt">uint16_t</span> <span class="n">port</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">__asm__</span> <span class="k">volatile</span> <span class="p">(</span><span class="s">"outb %0, %1"</span> <span class="o">:</span> <span class="o">:</span> <span class="s">"a"</span><span class="p">(</span><span class="n">value</span><span class="p">),</span> <span class="s">"Nd"</span><span class="p">(</span><span class="n">port</span><span class="p">));</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kr">inline</span> <span class="kt">uint8_t</span> <span class="nf">inb</span><span class="p">(</span><span class="kt">uint16_t</span> <span class="n">port</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="n">value</span><span class="p">;</span>
    <span class="n">__asm__</span> <span class="k">volatile</span> <span class="p">(</span><span class="s">"inb %1, %0"</span> <span class="o">:</span> <span class="s">"=a"</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="o">:</span> <span class="s">"Nd"</span><span class="p">(</span><span class="n">port</span><span class="p">));</span>
    <span class="k">return</span> <span class="n">value</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu örnekte x86 üzerinde I/O portlarına erişen küçük yardımcı fonksiyonlar var. <code class="language-plaintext highlighter-rouge">outb</code> donanıma komut veya parametre gönderir, <code class="language-plaintext highlighter-rouge">inb</code> ise durum bayrağı okur. Gerçek bir çekirdek sürücüsünde bunlar doğrudan kullanıcı programından çağrılamaz; ayrıcalıklı kip gerekir. Linux’ta bu iş çekirdek modülü, Windows’ta ise WDM/KMDF sürücüsü üzerinden yapılır.</p>

<p>Bir sürücü algoritmasının kalbi genellikle durum makinesidir. Aygıta komut verilir, aygıt meşgul olur, sonra hazır bayrağı beklenir. Basitleştirilmiş akış şöyledir:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">enum</span> <span class="n">disk_state</span> <span class="p">{</span>
    <span class="n">DISK_IDLE</span><span class="p">,</span>
    <span class="n">DISK_SEND_CMD</span><span class="p">,</span>
    <span class="n">DISK_WAIT_READY</span><span class="p">,</span>
    <span class="n">DISK_TRANSFER</span><span class="p">,</span>
    <span class="n">DISK_ERROR</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="nf">wait_ready</span><span class="p">(</span><span class="kt">void</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">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="mi">100000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">uint8_t</span> <span class="n">status</span> <span class="o">=</span> <span class="n">inb</span><span class="p">(</span><span class="n">ATA_COMMAND</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">((</span><span class="n">status</span> <span class="o">&amp;</span> <span class="mh">0x80</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">status</span> <span class="o">&amp;</span> <span class="mh">0x08</span><span class="p">))</span>
            <span class="k">return</span> <span class="mi">0</span><span class="p">;</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>Burada <code class="language-plaintext highlighter-rouge">0x80</code> meşgul bayrağını, <code class="language-plaintext highlighter-rouge">0x08</code> veri hazır bayrağını temsil eder. Döngü sonsuza kadar beklemek yerine zaman aşımı uygular; çünkü donanım dünyasında “cevap gelmedi” de geçerli bir cevaptır. Sağlam sürücü yazmanın sırrı, mutlu yoldan çok hata yollarını ciddiye almaktır.</p>

<p>Harici adaptörlerde tablo biraz değişir. USB-SATA köprüleri çoğunlukla Mass Storage Class ya da UASP kullanır. Siz doğrudan ATA portuna yazmazsınız; SCSI benzeri komut paketleri gönderirsiniz. Yani algoritma yine blok okuma/yazma yapar ama alttaki taşıma protokolü farklıdır. Bu yüzden iyi tasarımda “blok aygıt arayüzü” ile “taşıma katmanı” ayrılır.</p>

<p>Son olarak güvenlik notu: Gerçek disklere deneme sürücüsüyle yazmak veri kaybına yol açabilir. Önce QEMU, Bochs, loop device veya sahte blok aygıtlarıyla test yapmak en sağlıklı yoldur. C ile donanım konuşmak, biraz arkeoloji biraz da elektrikli ejderha terbiyeciliğidir: protokolü okur, bayrakları izler, zaman aşımını koyar ve asla donanıma körü körüne güvenmezsiniz.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="C" /><category term="donanım" /><category term="sürücü-geliştirme" /><summary type="html"><![CDATA[Eski bir IDE disk, USB-SATA dönüştürücü ya da seri port adaptörü elinize geçtiğinde ilk soru genelde şudur: “Bunu işletim sistemiyle nasıl konuştururum?” C dili burada hâlâ sahnenin başrol oyuncusudur; çünkü donanıma yakın, bellek düzenini tahmin edilebilir kılan ve kesme, DMA, I/O portu gibi düşük seviye kavramları açıkça modelleyebilen bir araçtır.]]></summary></entry></feed>