<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Emre Yılmaz]]></title><description><![CDATA[Emre Yılmaz]]></description><link>http://blog.emre.sh/</link><generator>Ghost 0.6</generator><lastBuildDate>Mon, 20 Nov 2023 08:37:54 GMT</lastBuildDate><atom:link href="http://blog.emre.sh/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Makarna yiyen filozoflar problemi]]></title><description><![CDATA[<p>Reyizlerin reyizi <a href="https://en.wikipedia.org/wiki/Edsger_W._Dijkstra">Edsger Dijkstra</a> 1965 yılında, ögrencilere ne sorsam, ne sorsam diye düşünürken "dining philosophers problem" diye bir problem icad etmiş.</p>

<p><img src="http://emre.sh/assets/dining-philosophers-problem-small.jpg"></p>

<p>Problemin tanımı basit.</p>

<p>Resimdeki masada 5 tane filozof oturduğunu düşünün. Filozoflarımızın yaşam şifreleri çok basit. Düşünüyorlar, acıkınca da yemek yiyorlar. Sonra tekrar düşünmeye devam ediyorlar; sonra tekrar yemek yiyorlar.</p>]]></description><link>http://blog.emre.sh/makarna-yiyen-dusunurler-problemi/</link><guid isPermaLink="false">a8353065-9293-45b5-a6c5-db9ed48fa920</guid><category><![CDATA[concurrent programming]]></category><category><![CDATA[dijkstra]]></category><dc:creator><![CDATA[Emre Yilmaz]]></dc:creator><pubDate>Thu, 22 Oct 2015 17:43:10 GMT</pubDate><content:encoded><![CDATA[<p>Reyizlerin reyizi <a href="https://en.wikipedia.org/wiki/Edsger_W._Dijkstra">Edsger Dijkstra</a> 1965 yılında, ögrencilere ne sorsam, ne sorsam diye düşünürken "dining philosophers problem" diye bir problem icad etmiş.</p>

<p><img src="http://emre.sh/assets/dining-philosophers-problem-small.jpg"></p>

<p>Problemin tanımı basit.</p>

<p>Resimdeki masada 5 tane filozof oturduğunu düşünün. Filozoflarımızın yaşam şifreleri çok basit. Düşünüyorlar, acıkınca da yemek yiyorlar. Sonra tekrar düşünmeye devam ediyorlar; sonra tekrar yemek yiyorlar. Sonsuza kadar gidiyor bu durum.</p>

<p>Masada ise sadece 5 tane çatal var. İşin tricky kısmı ise şu; bir filozof ortadaki makarnayı yemek için 2 tane çatala ihtiyaç duyuyor.</p>

<p>Dolayısıyla bir filozofun yaşam döngüsü şu şekilde:</p>

<pre><code>while True:
    dusun();
    catallari_al();
    makarnayi_vur();
    catallari_birak();
</code></pre>

<hr>

<p>Çözmemiz gereken problem ise şu: </p>

<p>Tüm filozoflar aynı anda yemek yemeye kalkarsa sofrada yeterince çatal (resource) yok. Dolayısıyla, bu filozofların yönetimi, kaynak paylaşımı nasıl olmalı ki, yemeye niyetlenen bir filozof mutlaka -eninde sonunda- iki çatal elde edip yemeğini yiyebilmeli.</p>

<p>Dikkat etmemiz gereken şeyler:</p>

<ol>
<li>Filozoflar(Threadler) arasında Deadlock oluşmamalı. Örneğin, sonsuza kadar birbirini bekleyen filozoflar (Bırak şu çatalı da yiyelim!)  </li>
<li>Herhangi bir filozof aç kalmamalı. (4 tanesi götürdü, vurdu makarnaları, biri aç kaldı. Olur mu? Olmaz.)  </li>
<li>Aynı anda birden fazla filozof makarna yiyebilmeli.</li>
</ol>

<h5 id="filozofsnf">Filozof Sınıfı</h5>

<p>Filozofların hangi çatalları alıp kullanmaları gerektiği konusunda 2 yardımcı metod yazalım. isimleri left ve right olsun.</p>

<pre><code>class Philosopher:

    def __init__(self, *args, **kwargs):
        self.index = kwargs.pop("index")

    @property
    def left(self):
        return self.index

    @property
    def right(self):
        # when it gets to 5, (4 + 1) % 5 = 0
        return (self.index + 1) % 5
</code></pre>

<p>Her filozofun 0..4 arası index'i olduğunu varsayarsak; çatalları da bu indexle aynı şekilde ilişkilendirebiliriz.</p>

<p>left metodu; filozofun numarası ile aynı sonucu versin. 4.filozof sol eline 4.çatalı alsın. <br>
right metodu ise mod5'e gore index+1'i versin. 4.filozof, sağ eline 0. çatalı alacak bu şekilde. (masa yuvarlak, filozof ve çatal sayısı 5.)</p>

<pre><code>class Philosopher:

    def __init__(self, *args, **kwargs):
        self.index = kwargs.pop("index")

    @property
    def left(self):
        return self.index % 5

    @property
    def right(self):
        # when it gets to 5, (4 + 1) % 5 = 0
        return (self.index + 1) % 5
</code></pre>

<p>çatalları ise, bir liste halinde hepsi birer semafor olacak şekilde tanımlayalım. (Semafor kullanıyoruz, zira 2 filozof aynı anda, aynı çatala meyledebilir, critical section'da kavga etmesinler.)</p>

<pre><code>forks = [Semaphore(1) for i in xrange(5)]
</code></pre>

<p>Filozofa ekleyeceğimiz sadece 2 metod kaldı. get<em>forks(), ve put</em>forks()</p>

<p>get<em>forks() -> çatalları al, yemeye başla. <br>
put</em>forks() -> yemeni bitir, çatalları geri bırak.</p>

<pre><code>def get_forks(self):
    self.forks[self.left].acquire()
    self.forks[self.right].acquire()

def put_forks(self):
    self.forks[self.left].release()
    self.forks[self.right].release()
</code></pre>

<p>Bir filozof, çatal alacağı zaman önce solundaki çatalı bekliyor. Eğer çatal boştaysa (Semaforlar sağolsun) alıyor, sonra sağdaki çatalı bekliyor. Eğer o da boştaysa amenna, direkt makarnayı göturmeye başlıyor. (random çalışma süresi olan bir self.eat metodu ile)</p>

<p>Çatallara erişim semaforlar tarafından kontrol edildiği için her şey güzel gibi. Kodların çalışan, derli toplu hali <a href="https://github.com/emre/semaphores/blob/master/puzzles/dining-philosophers-deadlock.py">dining-philosophers-deadlock.py</a> üzerinde var.</p>

<p>Bu kodu 3-5 defa çalıştırın sisteminizde python varsa. Birkaç denemeden sonra şöyle bir deadlock ile karşılaşacaksınız.</p>

<pre><code>$ python dining-philosophers-deadlock.py

1 got the left fork 1
2 got the left fork 2
4 got the left fork 4
0 got the left fork 0
3 got the left fork 3
</code></pre>

<p>Tüm filozoflar, aynı anda sol çatallarını aldı. Sağdaki çatalın boşalmasını bekliyor. Ama boşa düşmeyecek hiçbiri; zira, hepsi beklemede.</p>

<p>Bu duruma terminolojide <em>deadlock</em> diyoruz. Grup halinde threadlerimiz, sürekli askıda birbirlerinden işlem bekliyorlar.</p>

<p><strong>Çözüm</strong></p>

<p>65'ten bu yana bu problem çokca tartışılmış ve çeşitli çözümler getirilmiş. Ben en beğendiğim çözümü uygulayacağım.</p>

<p>Aynı anda maksimum 4 filozofa işlem yapma izni verirsek, bu durumdan kurtulabiliriz. En kötü ihtimalle 4 filozof birden de sol çatalı kaldırsa, 1 tane sağ çatal boşta olacak; ve filozoflardan biri yemeye devam edebilecek.</p>

<p>Az önce yazdığımız koda ufak bir değişiklik yaparak bu durumu elde edebiliyoruz. </p>

<pre><code>multiplex = Semaphore(4)
</code></pre>

<p>diye bir semafor daha tanımlayıp; </p>

<pre><code>def get_forks(self):
    self.multiplex.acquire()
    self.forks[self.left].acquire()
    self.forks[self.right].acquire()


def put_forks(self):
    self.forks[self.left].release()
    self.forks[self.right].release()
    self.multiplex.release()
</code></pre>

<p>Filozofların çatalları aldığı yerde, multiplex'in değerini bir düşürüp, çatalları bıraktığı yerde ise multiplex değerini bir arttırıp aynı anda maksimum 4 filozofun yeme işlemiyle meşgul olabileceğini karara bağlamış oluyoruz.</p>

<p>Terminojide bu pattern'e ise multiplex deniyor.</p>

<p>Örneğin bir cafe sahibisiniz. Ağırlayabileceğiniz kişi sayısı belli. Aynı anda cafenizde N kişi bulunabilir. Cafenizin içerisini de <strong>critical section</strong> olarak düşünün. Bu durumda Semaphore(N) gibi bir semafor yardımıyla, içerdeki kişilerin hesabını tutar, gereğinden fazla yük altında kalmazsınız.</p>

<hr>

<p>Çözümün derlenmiş toplanmış, çalışır hali ise <a href="https://github.com/emre/semaphores/blob/master/puzzles/dining-philosophers-multiplex.py">dining-philosophers-multiplex.py</a> adresinde. Başka semafor puzzle'ları ile ilgilenirseniz de <a href="https://github.com/emre/semaphores">repoya</a> bekleriz.</p>

<p>Problemle ilgili diğer detaylara ve diğer çözümlere ise <a href="https://en.wikipedia.org/wiki/Dining_philosophers_problem">wikipedia/Dining<em>philosophers</em>problem</a> üzerinden ulaşabilirsiniz.</p>]]></content:encoded></item><item><title><![CDATA[observer yazılım deseni ve starcraft]]></title><description><![CDATA[<p><img src="http://s4.postimg.org/gi1bf7rpp/darktemplar.jpg"></p>

<blockquote>
  <p>"I strike from the shadows!"</p>
</blockquote>

<p>Bu arkadaşın adı dark templar. Kendisi, starcraft evreninde acımasız bir adamdır. Normal zamanlarda kendisini göremezsiniz. "invisible" bir ünitedir.</p>

<p>Bu arkadaş bir çok ünitenizi tek vuruşta keser. Bu yüzden savunma olarak detection yapabilen bir üniteye sahip olmanız gerekir. <a href="http://www.osirissc2guide.com/starcraft-2-dark-templar-rush-build-order.html">Dark templar rush</a> olarak bilinen stratejiye nice yiğitler</p>]]></description><link>http://blog.emre.sh/observer-design-pattern-ve-starcraft/</link><guid isPermaLink="false">1f70d351-6d98-4595-b413-a5db10c55426</guid><category><![CDATA[design patterns]]></category><category><![CDATA[starcraft]]></category><dc:creator><![CDATA[Emre Yilmaz]]></dc:creator><pubDate>Sun, 20 Sep 2015 08:30:16 GMT</pubDate><content:encoded><![CDATA[<p><img src="http://s4.postimg.org/gi1bf7rpp/darktemplar.jpg"></p>

<blockquote>
  <p>"I strike from the shadows!"</p>
</blockquote>

<p>Bu arkadaşın adı dark templar. Kendisi, starcraft evreninde acımasız bir adamdır. Normal zamanlarda kendisini göremezsiniz. "invisible" bir ünitedir.</p>

<p>Bu arkadaş bir çok ünitenizi tek vuruşta keser. Bu yüzden savunma olarak detection yapabilen bir üniteye sahip olmanız gerekir. <a href="http://www.osirissc2guide.com/starcraft-2-dark-templar-rush-build-order.html">Dark templar rush</a> olarak bilinen stratejiye nice yiğitler heba olmuştur.</p>

<hr>

<p><img src="http://s16.postimg.org/unxzm7vjp/latest_cb_20141121074339.jpg"></p>

<p>Bu arkadaşın adı da observer. Kendisi, protoss mühendislerinin ürettiği etkili bir drone'dur. Savaş alanında olan bitenleri gözlemleyip, protoss arşivlerine iletir. </p>

<p>Hem görünmez olup, hem de "dark templar" gibi üniteleri detect (tespit) edebilir. </p>

<hr>

<p><img src="http://s30.postimg.org/up1d3rpht/latest_cb_20090129013727.jpg"></p>

<p>Bu çirkin şey ise raven. Bu da terranların drone'u. Uzaktan bir terran pilotu tarafından kontrol edilir. Ama içerisinde mükemmel bir AI (yapay zeka) bulundurur. Drone içerisindeki bir çok konuya kendisi karar verir ve ayarlar. (Sıcaklık, Genel savaş durumu, enerji seviyeleri ve dış tehditler gibi.) </p>

<p>1 saniye içerisinde milyarlara varan komutu işleyebilir bir cpu'ya sahiptir. Birçok terran mühendisi, AI'sinin bu derece güçlü olmasından dolayı (bağımsız karar verebilme) tamamen bağımsız duruma geçebileceğinden ve felaketlere yol açabileceği şeklinde rapor vermiş.</p>

<p>Ama çok şükür iş daha terminator'e dönmemiş durumda. Şimdilik, raven gayet sadık bir ünite.</p>

<p>Bu arkadaş da, dark templar gibi görünmez ve saldırgan üniteleri tespit ettiği için terran taburları genelde 1 tane yanında bulundurur.</p>

<hr>

<p><img src="http://s13.postimg.org/bwlvcoo87/serdar_ortac.jpg"></p>

<p>Bu arkadaş da Serdar Ortaç. </p>

<p>İçinde "Serdar Ortaç" bulunan evrene dönüyoruz... Yıl 95-96. Blizzard'ın ofisindeyiz. Yazılımcılar, gün içinde sigara-kahve molaları ve goygoylardan kalan zamanlarda ufak ufak kod da yazıyorlar.</p>

<p>İşin tespit edilme, detection'a sıra geldiğinde şöyle bir yapı kuruyorlar.</p>

<p>Demişler ki, Dark Templar bir nesne olsun. InvisibleUnit sınıfını extend etsin. InvisibleUnit, haritadaki observerları kendisine register etsin. Onların görüş alanına girdiğinde desin ki "ben geldim!".</p>

<p><strong>InvisibleUnit sınıfı</strong></p>

<pre><code>class InvisibleUnit(object):

    def __init__(self):
        self.observers = []

    def register(self, observer):
        if not observer in self.observers:
            self.observers.append(observer)

    def unregister(self, observer):
        if observer in self.observers:
            self.observers.remove(observer)

    def unregister_all(self):
        if self.observers:
            del self.observers[:]

    def on_observer_range(self, *args, **kwargs):
        for observer in self.observers:
            observer.saw_something(*args, **kwargs)
</code></pre>

<p><strong>Dark templar sınıfı</strong></p>

<pre><code>from invisibleunit import InvisibleUnit

class DarkTemplar(InvisibleUnit):
    hp = 100
    damage = 50
</code></pre>

<p>InvisibleUnit'e ek olarak hp, damage gibi property'ler ekledik. İleride dark templar gibi başka görünmez üniteler de olabilir diye düşünmüşler çünkü.</p>

<p>InvisibleUnit sınıfı register metoduyla haritadaki observerları kendi içine dahil ediyor. Observerların görüş alanına geldiğinde de o listeyi dönüp kendini observerlara <strong>saw_something</strong> metodu üzerinden bildiriyor. (Basitlik açısından observerların haritada aynı yer üzerinde olduklarını varsayıyoruz.) </p>

<p><strong>observer.py</strong></p>

<pre><code>from abc import ABCMeta, abstractmethod

class Observer(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def saw_something(self, *args, **kwargs):
        pass
</code></pre>

<p>ABCMeta, abstract method gibi şeyler <a href="https://docs.python.org/2/library/abc.html">python dahilindeki</a> şeyler. </p>

<p>Basitçe observer sınıƒından türeyen observerların, saw_something metodunu implemente ettiğinden emin olmak istiyoruz.</p>

<p><strong>protoss_observer.py</strong></p>

<pre><code>from observer import Observer

class ProtossObserver(Observer):
    def saw_something(self, unit_name, hp, damage):
        print "I saw a {}. (HP: {}, Damage: {}) - {} reported.".format(
            unit_name,
            hp,
            damage,
            self.__class__.__name__
        )
</code></pre>

<p><strong>raven.py</strong></p>

<pre><code>from observer import Observer

class Raven(Observer):
    def saw_something(self, unit_name, hp, damage):
        print "I saw a {}. (HP: {}, Damage: {}) - {} reported.".format(
            unit_name,
            hp,
            damage,
            self.__class__.__name__
        )
</code></pre>

<p>Son olarak, test yapabileceğiniz bir <strong>main.py</strong></p>

<pre><code>from darktemplar import DarkTemplar

from protoss_observer import ProtossObserver
from raven import Raven

# dark templar
dt = DarkTemplar()

# protoss observer
protoss_observer = ProtossObserver()

# terran observer (Raven)
raven = Raven()


dt.register(protoss_observer)
dt.register(raven)

dt.on_observer_range(
    "Dark Templar",
    dt.hp,
    dt.damage,
)
</code></pre>

<p>Bu şekilde, observer yazılım desenini starcraft içinde basitçe <br>
implemente etmiş olduk. </p>

<pre><code>$ python main.py
I saw a Dark Templar. (HP: 100, Damage: 50) - ProtossObserver reported.
I saw a Dark Templar. (HP: 100, Damage: 50) - Raven reported.
</code></pre>

<p>Starcraft evreninden çıkıp, bizim evrene dönersek; herhangi bir gazeteye abonelik durumu observer desenini en iyi açıklayan senaryo, pub-sub dediğimiz modeldir. Gazete aboneliği düşünün.</p>

<p>Aboneler=Observer, Gazete=Subject(Observable) gibi. Subject'in, Observerlara karşı one-to-many bir ilişkisi bulunur.</p>

<p>1 Dark templar'ın, birden fazla gözlemcisi olabilir. (Raven, OverSeer, Protoss Observer gibi.)</p>

<p>Duruma göre, bu observerlar dinlemeyi bırakabilir. Bunu da ana subject sınıfında (unregister) yapabilirler. Observer deseninin isminden haber olmasanız da birçok problemi bu veya buna benzer bir şekilde çözmüşsünüzdür.</p>

<p>Dark Templarsız günler dilerim.</p>

<blockquote>
  <p>"Though we strike at you from the shadows, do not think that we lack the courage to stand in the light. - Dark Templar"</p>
</blockquote>

<p>Yazıda bulunan kodların derli toplu hali: <a href="https://github.com/emre/starcraft-observer-pattern">@emre/starcraft-observer-pattern</a></p>]]></content:encoded></item><item><title><![CDATA["kodlara bolca yorum yazalım" miti]]></title><description><![CDATA[<p>7-8 sene önce, profesyonelliğe taze taze adım attığım zamanlarda birkaç (PHP) freelance işi aldıktan sonra her türk genci gibi kendi uygulama geliştirme çatımı yazmaya başlamıştım. </p>

<p>Neredeyse yazdığım kod kadar "yorum" yazmak gibi değişik bir takıntım vardı. Çünkü o şekilde daha güzel, daha profesyonel, daha bir <em>roket bilimi</em> gibi görünüyordu.</p>

<p><img src="http://s17.postimg.org/u7wmg802n/P5joi5_D.jpg"></p>

<p>Yıllardır</p>]]></description><link>http://blog.emre.sh/yorum-yazalim-miti/</link><guid isPermaLink="false">a1a4b875-c369-42be-996d-c40faa594c8a</guid><category><![CDATA[code commenting]]></category><category><![CDATA[programming]]></category><dc:creator><![CDATA[Emre Yilmaz]]></dc:creator><pubDate>Wed, 16 Sep 2015 18:31:00 GMT</pubDate><content:encoded><![CDATA[<p>7-8 sene önce, profesyonelliğe taze taze adım attığım zamanlarda birkaç (PHP) freelance işi aldıktan sonra her türk genci gibi kendi uygulama geliştirme çatımı yazmaya başlamıştım. </p>

<p>Neredeyse yazdığım kod kadar "yorum" yazmak gibi değişik bir takıntım vardı. Çünkü o şekilde daha güzel, daha profesyonel, daha bir <em>roket bilimi</em> gibi görünüyordu.</p>

<p><img src="http://s17.postimg.org/u7wmg802n/P5joi5_D.jpg"></p>

<p>Yıllardır da "yazdığınız kodu anlatın" goygoyu sektörün içinde var. Hatta, stajyerlerin, işe yeni başlayanların aldığı yegane tavsiye; <em>"kodlarına yorum yazmayı unutma, yoksa 6 ay sonra o kodu sen de anlamazsın!"</em> goygoyudur.</p>

<p>Halbuki, pratikte ideal bir yazılım geliştirme sürecinde, kod tabanında mümkün olduğunca <strong>az</strong> yorum olmalıdır. </p>

<p>Sürdürülebilir ve bakımı yapılabilir kod, kendi kendini anlatmalıdır. Kötü programlama teknikleriyle bir implementasyon yapıp, daha sonra o implementasyonu kodtaki satır sayısı kadar anlatmanın bir mantığı yoktur.</p>

<p>Bir kod parçasının ne yaptığını ayrı bir şekilde anlatmak için yorum satırlarına ihtiyaç duymamalıyız. Yazılan kod, gerek isimlendirme, gerekse modern yazılım kuralları dahilinde, zaten kendi kendini anlatacak seviyede basit ve açık olmalıdır.</p>

<p>Ama gerçek dünyada, bu işi %100 yapabilmeniz zor. Bazen elimizde olmayan sebeplerden, bazen tembelliğimizden bu basitliği kaybediyoruz ve neyi niye yaptığımızı anlatmamız gerekebiliyor. hatta, yalan söylemeyelim, işyerlerimizde genelde "workaround" ve "quick hack" modelleriyle günü idare ediyoruz. :)</p>

<hr>

<p><strong>gereksizin gereksizi yorumlar</strong></p>

<pre><code>meyveler = ["Elma", "Armut", ]
# listeye Ayva ekle.
meyveler.append("Ayva")
</code></pre>

<p>Aferin. Laf söyledi balkabağı. Python'ın listeleri dünyanın en temiz API'sine sahip olduğu halde, bizim küçük wozniak python standart kütüphanesi içerisindeki veri tipini dökümente etmek istemiş.</p>

<p>Buradaki tek sorun bu da değil; yarın birgün meyveler listesine Ayvayla birlikte "Cilek" eklemek istek, kodu düzenlemenin yanında bir de üstündeki gereksiz yorumu güncel tutmaya çalışacağız.</p>

<hr>

<p><strong>phpdoc ve benzeri araçlar</strong></p>

<p>"Kaynak kod üzerinden dökümantasyon çıkaralım" fikri ilk kimden çıktı bilmiyorum ama bu <a href="http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_tags.param.pkg.html">arkadaşlar</a> kaynak kod kalabalığı yapmaktan başka bir tek <em>şekilli</em> HTML çıktıları almaya işe yarıyor olabilirler.</p>

<p>Dahası, koda yeni geliştirmeler yaptığınızda bakımını yapmanız gereken bir de docstring'ler olacak. ve tembellikten orayı güncellemeyeceğiz. (güncellemiyoruz da) bu sefer, zaten açıkta olan bir bilgiyi, yorumlar bize yanlış iletecek. dahası, sevgili IDE'lerimiz o docstringleri okuyup, bize yanlış type bildirimleri yapacaklar.</p>

<p>Bir fonksiyonun aldığı her parametre için dökümantasyona ihtiyacımız yok. fonksiyonun, parametrelerin isimlendirmesine dikkat etmek, parametre sayısını abartmamak gibi işler yaptığımızda zaten yine bu stringlere ihtiyacımız olmayacak.</p>

<hr>

<p><strong>bir versiyon kontrol sistemi olarak kod dosyaları</strong></p>

<p>Bu tip bir kullanım umarım 2015 senesi itibariyle kalmamıştır, ama güzel bir anı olarak kalsın;</p>

<p>Çok uzun yıllar önce (belki 9-10 yıl?)  <a href="http://ceviz.net">ceviz.net</a>'in ceviz.net olduğu zamanlarda site yazılımında her bir değişiklik yapıldığında değişikliği yapan kodun başına, tarih, değişen kısım, değiştiren kişi şeklinde not düşüyordu.</p>

<pre><code>"""
* "zaa" hatasi duzeltildi. "zort" durumunu da dusunmekte fayda var. - emre, 21.12.2007

* emre'nin bozdugu yerleri duzelttim. - ansugo, 20.12.2006

* hicbirinizin anlamadigi bir seyler yaptim. -acemi, 19.12.2005
"""
</code></pre>

<p>Bir dosya üzerinde 15-20 iş yapıldığını düşünün. :)</p>]]></content:encoded></item><item><title><![CDATA[python ve call by sharing]]></title><description><![CDATA[<p>python’ı diğer dillerden ayıran bir başka özelliği değişkenlerin fonksiyonlara nasıl yollandığı. Klasik “call by reference” veya “call by value” şeklinde de değil.</p>

<p>Aşağıdaki gibi örnek bir fonksiyonumuz var.</p>

<pre><code>def add_to_list(x):
    x.append(25)
</code></pre>

<p>fonksiyon basit. girdi olarak liste alıp, listeye 25 değerinde bir int ekliyor. Hemen</p>]]></description><link>http://blog.emre.sh/python/</link><guid isPermaLink="false">95ad670e-6e5e-4a1e-89fd-be16f50da158</guid><category><![CDATA[python]]></category><category><![CDATA[call by sharing]]></category><dc:creator><![CDATA[Emre Yilmaz]]></dc:creator><pubDate>Thu, 01 May 2014 06:28:00 GMT</pubDate><content:encoded><![CDATA[<p>python’ı diğer dillerden ayıran bir başka özelliği değişkenlerin fonksiyonlara nasıl yollandığı. Klasik “call by reference” veya “call by value” şeklinde de değil.</p>

<p>Aşağıdaki gibi örnek bir fonksiyonumuz var.</p>

<pre><code>def add_to_list(x):
    x.append(25)
</code></pre>

<p>fonksiyon basit. girdi olarak liste alıp, listeye 25 değerinde bir int ekliyor. Hemen fonksiyonu deneyelim:</p>

<pre><code>&gt;&gt;&gt; y = [15, ]
&gt;&gt;&gt; add_to_list(y)
</code></pre>

<p>y’nin global alanda değerinin ne olmasını beklersiniz?</p>

<pre><code>&gt;&gt;&gt; y
[15, 25]
</code></pre>

<p>Bu şekilde bakarsak <strong>call by reference</strong> şeklinde gözüküyor. fonksiyonun içinde değeri değiştirdiğimiz halde genel scope’da baktığımızda da değer değişmiş durumda.</p>

<p>--</p>

<p>Başka bir deneme yapalım.</p>

<pre><code>&gt;&gt;&gt; def add_to_list(x):
... x = x + [25,]
... print x
... 
&gt;&gt;&gt; y = [15]
&gt;&gt;&gt; add_to_list(y)
[15, 25]
&gt;&gt;&gt; y
[15]
</code></pre>

<p>Bu sefer baktığımızda fonksiyon scope’u içerisinde x, üzerinde oynanmış değere sahipken, fonksiyon scope’undan çıktığımızda x’in güncellenmediğini görüyoruz.</p>

<p>Bu fonksiyonu ele alırsak da model, <strong>call by value</strong> şeklinde gözüküyor?</p>

<p>Python iki modele de sahip değil. Bu durum, <strong>call by sharing</strong> veya <strong>call by object reference</strong> şeklinde geçiyor daha çok literatürde.</p>

<p>--</p>

<p>Python’da her şey — veri tipleri de dahil objedir.</p>

<pre><code>&gt;&gt;&gt; x = 42
&gt;&gt;&gt; id(x)
14822312
</code></pre>

<p>Herhangi bir instantiation(örnekleme?) yapmasak da arkaplanda x bir objeden türetilerek oluşturulur. Bu nesnelerin hepsinin bir referansı olur ve referanslar da basit olarak hafızada hangi objenin nerede tutulduğunu tutar.</p>

<p>İlk yazdığımız fonksiyonu bir daha hatırlayalım:</p>

<pre><code>&gt;&gt;&gt; y = [15, ]
&gt;&gt;&gt; def add_to_list(x):
... x.append(25)
...
&gt;&gt;&gt; y
[15, 25]
</code></pre>

<p>add_to_list() fonksiyonu çalışmaya başladığında arkaplanda y nesnesinin referansı kopyalanıyor. birden fazla referans <strong>aynı</strong> nesneyi paylaşıyor.</p>

<p><img src="http://i.imgur.com/27go1an.png" alt="resim1"></p>

<p>İki referans da aynı nesneyi paylaştığı için, hangi referanstan olursa olsun bir değişiklik yaptığımız da aynı nesne etkilenecektir.</p>

<p>Peki ikinci fonksiyondaki fark ne? Bakalım.</p>

<pre><code>&gt;&gt;&gt; y = [15, ]
&gt;&gt;&gt; def add_to_list(x):
... x = x + [25,]
... 
&gt;&gt;&gt; add_to_list(y)
&gt;&gt;&gt; y
[15]
</code></pre>

<p>Bu sefer fark fonksiyon içinde x’in yeni bir liste nesnesine atanıyor oluşu.</p>

<p><code>x = [15, ] + [25, ]</code> şeklinden farkı yok. Farklı bir nesne, farklı bir referans demek, memory’de farklı bir yer demek.</p>

<p><img src="http://i.imgur.com/h87EfGA.png" alt="resim2"></p>

<p>--</p>

<h3 id="immutabledeitirelemezobjeler">immutable (değiştirelemez) objeler</h3>

<p><a href="http://docs.python.org/2/reference/datamodel.html">immutable</a> objeler bir kere yaratıldıktan sonra değiştirelemez objelerdir.</p>

<p>yazının başındaki fonksiyonlarda mutable veri tipi olan listeleri kullandık. immutable bir veri tipi kullanırsak senaryo yine değişiyor.</p>

<pre><code>&gt;&gt;&gt; y = "kazu"
&gt;&gt;&gt; def add_to_string(x):
... x += "makino"
... 
&gt;&gt;&gt; y
kazu
</code></pre>

<p>aynı işi listelerle yaptığımızda farklı olan senaryo string kullandığımızda değişti.</p>

<p><img src="http://i.imgur.com/A1SvQBk.png" alt="resim3"></p>

<p>Aynı şekilde; iki referans aynı nesneyi (‘kazu’) paylaşsa da nesne immutable olduğu için değiştirilemedi. string, tuple, integer gibi değerler argüman olarak yollandığında — bu objeler özünde iyi ve immutable oldukları için, scope içine başka bir string nesnesi/referans yeni haliyle yerleştiriliyor.</p>]]></content:encoded></item><item><title><![CDATA[yüksek concurrency'nin olduğu sistemlerde caching]]></title><description><![CDATA[<p><em>"There are only two hard things in Computer Science: cache invalidation and naming things."</em></p>

<p>-- Phil Karlton</p>

<p>"caching de nedir ki ya, bu kadar zor olan ne var?" diyorsaniz bu yazi tam size gore. proje buyudukce ve caching'e gercekten
ihtiyaciniz olan durumlarda isin icine beklemediginiz problemler giriyor. (cache invalidation, dog</p>]]></description><link>http://blog.emre.sh/welcome-to-ghost/</link><guid isPermaLink="false">aafce41a-f172-46a7-a043-45ab37e3da36</guid><category><![CDATA[python]]></category><category><![CDATA[caching]]></category><category><![CDATA[django]]></category><dc:creator><![CDATA[Emre Yilmaz]]></dc:creator><pubDate>Fri, 04 Jan 2013 07:29:00 GMT</pubDate><content:encoded><![CDATA[<p><em>"There are only two hard things in Computer Science: cache invalidation and naming things."</em></p>

<p>-- Phil Karlton</p>

<p>"caching de nedir ki ya, bu kadar zor olan ne var?" diyorsaniz bu yazi tam size gore. proje buyudukce ve caching'e gercekten
ihtiyaciniz olan durumlarda isin icine beklemediginiz problemler giriyor. (cache invalidation, dog piling) ya da aslinda farkinda olmadiginiz sorunlar icin <br>
optimizasyonlar yapmaniz gerekebiliyor.</p>

<p>asagida genel bir caching pattern'i var, muhtemelen bu sekilde calisan kodu bircogumuz yazdik ve kullaniyoruz.</p>

<pre><code>from django.core import cache

def get_post_data(post_id):
    cache_key = "post_{post_id}".format(post_id=post_id)

    post = cache.get(cache_key)

    if not post:
        post = Post.objects.get(pk=post_id)
        cache.set(cache_key, post, 1800)

    return post
</code></pre>

<p>anlik 40.000 trafigin oldugu bir web uygulamasi dusunun, anlik 40.000 kisi db'ye gitse eski ve guzel RDBMS'iniz sikinti yasayacak durumda. boyle bir problem yasanmansin diye ne var yok cache'e yukaridakine benzer bir pattern'le dayadiniz.</p>

<p>redis'le memcache ile concurrency'in dibine vuruyorsunuz, hatta sirketiniz yazilim etkinliklerine sponsor oluyor orada <em>"nasil sistemi scale ettik?"</em>, <em>"memcache'in ustunde nasil at kosturdum?"</em> diye sunumlar yapiyorsunuz. groupie'leriniz oluyor, skype'da feyizli yazilim sohbetlerinde <em>"abi scaling bizden sorulur, hatta mysql'i de ssd'ye aldik, parasini verdik ama degdi"</em> diyorsunuz, buraya kadar her sey cok guzel.</p>

<h3 id="problem1timeout">problem #1: timeout</h3>

<p>timeout, yuksek trafikli sistemlerde kullanilmamasi gereken bir ozellik. cache'leriniz mumkunse sonsuza kadar durmali ya da olabildigince uzun tutulmali sistemde. </p>

<p><strong>dog piling -- veya thundering hard</strong></p>

<p>tamamen yukaridaki kod uzerinden dusunun. post_42 key'li cache'iniz var, 1800 saniye gecti timeout oldu, bir kullanici geldi, cache sistemine baktiniz key yok, tekrar olusturdunuz, koydunuz sisteminize.</p>

<p>burada asil sikinti yuksek trafigin oldugu sistemlerde, post<em>42 key'i database'den hesaplanip tekrar cache'e konulacak zamanda,  bir degil, binlerce, onbinlerce kullanicinin o key'e istek yapmasi. bu da binlerce kullanici kadar database'e ayni anda gidis demek. bunu sadece bir post detayi icin dusunmeyin, anasayfadaki bir top</em>users widget'i icin de olabilirdi. </p>

<p>hesaplamasi 1 saniye suren, ciddi JOIN'lerin oldugu bir SQL sorgusu da olabilirdi.</p>

<p>halbuki, timeout vermeseydik, cache invalidation'i tembellik etmeyip kendimiz yapsaydik boyle bir problem olmayacakti.</p>

<p>cache'lediginiz objeler guncel olmayan bir duruma geldiginde (editorlerden biri yaziyi update etti) siz de otomatik olarak bir sinyalle objenin cache'inin uzerine yazacaksiniz. dolayisiyla, olabildiginca timeout kullanmaktan kacinip, DELETE kullanmadiginiz surece herhangi bir "cache miss" ile karsilasmayacaksiniz. yukaridaki kodu buna gore update edip biraz duzeltelim.</p>

<pre><code>from django.core import cache

def get_post_data(post_id):
    cache_key = "post_{post_id}".format(post_id=post_id)

    post = cache.get(cache_key)

    if not post:
        post = Post.objects.get(pk=post_id)
        cache.set(cache_key, post)

    return post
</code></pre>

<p>yeni yaklasimla -teoride- hicbir sekilde cache miss ile karsilasmamamiz gerekiyor, ama yine de if not post: kismini her ihtimale karsi tutuyoruz.</p>

<h3 id="problem2hataliurller">problem #2: hatali URL'ler</h3>

<p>asthon kutcher projenizi gordu, twitter'ina atti, atarken bir yanlislik oldu, URL degisti. aslinda olmayan bir yaziya milyonlar twitterdan geldi. yukaridaki kodta, aslinda olmayan bir yazi icin onlarca cache ve db sorgusu demek. buradaki yuku azaltmak da mumkun.</p>

<pre><code>from django.core import cache

NOT_FOUND = "404"

def get_post_data(post_id):
    cache_key = "post_{post_id}".format(post_id=post_id)

    post = cache.get(cache_key)

    if post == NOT_FOUND:
        raise Post.DoesNotExist

    if not post:
        try:
            post = Post.objects.get(pk=post_id)                
        except Post.DoesNotExist:
            post = NOT_FOUND

        cache.set(cache_key, post)        

    return post
</code></pre>

<p>1 sefer baktik database'e. eger boyle bir sey yoksa, belirledigimiz <em>"icerik bulunamadi"</em> kodunu cache key'ine atadik. ilk istekten sonra gelen tum istekler icin bundan sonra db'ye gidilmeyecek. aslinda bulunamayan yaziya post girilse dahi, key update edilecegi icin herhangi bir sikinti olmayacak.</p>

<h3 id="iyilestirme1globalbircache_keylistesi">iyilestirme #1: global bir cache_key listesi</h3>

<p>buyuk projelerde onlarca belki de yuzlerce cache key'i olabilir. dolayisiyla cache key'lerini bunun gibi bir fonksiyon icerisinde hazirlamak yerine, cache_keys.py gibi ayri bir dosya tutmak ve gerektiginde import edip kullanmak daha mantikli.</p>

<p>su sekilde ayri bir dosyaniz oldugunu dusunun:</p>

<p><strong>cache_keys.py</strong></p>

<pre><code>NOT_FOUND = "404"

keys = {
    "post": "post_{post_id}",
    "comment": "comment_{comment_id}",
}
</code></pre>

<p>daha sonra view dosyanizda bunu kullanmak kolay:</p>

<pre><code>&gt;&gt;&gt; import cache_keys
&gt;&gt;&gt; cache_keys.keys["post"].format(post_id=42)
post_42
</code></pre>

<p>bu sekilde kullanmak insani hatalardan dolayi farkli key'lerle ugrasmanizi engeller, projeye sonradan katilan dev. icin de harika bir sey olur.</p>

<pre><code>from django.core import cache
from cache_keys import keys
from cache_keys import NOT_FOUND

def get_post_data(post_id):
    cache_key = cache_keys.keys["post"].format(post_id=post_id)

    post = cache.get(cache_key)

    if post == NOT_FOUND:
        raise Post.DoesNotExist

    if not post:
        try:
            post = Post.objects.get(pk=post_id)
        except Post.DoesNotExist:
            post = NOT_FOUND

        cache.set(cache_key, post)        

    return post
</code></pre>

<p>kod ilk haline gore oldukca degisti. ama cok daha saglam.</p>

<p>--</p>

<p>genel oneriler</p>

<ul>
<li>modellerin save/update gibi metodlarinda cache set/update gibi isler yapmayin. django icin model signals ile halledin ornegin.</li>
<li>birden fazla makineyi caching olarak kullaniyorsaniz <a href="https://github.com/emre/redis-router">consistent hashing</a> kullanin. data invalidation oranini server ekleme/cikarma gibi durumlarda minimuma indirip guzel bir dagitim orani saglayacaktir.</li>
<li>memcache, redis gibi gibi sistemlerin portlari disariya acik olmamali. maalesef cok gozardi edilen bir durum.</li>
<li>in process caching/memoization kullanin. django orm'in bir cok durumda <a href="https://docs.djangoproject.com/en/dev/topics/db/queries/#querysets-are-lazy">lazy sorgular</a> atmasi buna guzel bir ornek.</li>
<li><a href="http://sonsuzdongu.com/blog/varnish-ile-hizli-web">varnish</a> gibi upstream caching sistemleri az maliyetli ve cok etkili. kullanilabilecek yerlerde kullanmak cok mantikli.</li>
<li>caching'e gercekten ihtiyaciniz var mi emin olun. kodunuzu gereksiz yere karmasik hale getirmeniz her zaman gerekli olmayabilir.</li>
</ul>]]></content:encoded></item></channel></rss>