Make love, not var_dump())

Captain's Log

Vaktiyle, http://kodaman.org adresinde güzel bir oluşum vardı. Kimi zaman güzel teknik dökümanlar ekleniyordu. Daha sonra kodaman ansızın yayın hayatına son verdi. Gözümden kaçmış olabilir belki ama, "Siteyi kapatıyoruz panpalar, dökümanlarınızı yedekleyin" dediklerini de hatırlamıyorum. Neyse ki ben yedeklemiştim ;)

Velhasıl, kodaman.org üzerinde yayınladığım, ve garip bir şekilde üçü de en çok tutulan ilk 10 yazı arasına girmiş yazıları bizim blogdan da paylaşmaya karar verdim. Aşağıdaki belge de Haziran 2010 gibi kodaman'da yayınladığım, ve "en çok tutulan ilk 10" içinde uzunca süre en üstte duran bir belgeydi. Hiç değiştirmeden, ~2.5 sene önceki haliyle tekrar yayına almanın uygun olacağını düşündüm. Diğer yazıları da zamanla buraya aktaracağım.

Web Önyüzü Nasıl Olmalı?

Web Onyuzu Nasil Olmali - instacode Web önyüzü (Front-End) temel olarak üç öğeden oluşur, İşaretleme Dili, Stil Dosyaları ve Dinamik Öğeler.
İşaretleme Dili : HTML, XHTML, HTML5, WML (Wireless Markup Language - Mobil Cihazlarda kullanılır.) gibi işaretleme dilleri. Bunlar sayfanın ana iskeletini oluşturur.
Stil Dosyaları : CSS. Bunlar ise iskeletin üzerine giydirilen görsel öğeleri belirler.
Dinamik Öğeler : JavaScript. JavaScript ise sayfalarda, istemci (client) tarafında dinamik istekler yapmamıza yardımcı olur.


Web önyüz kodlamada yapılan en büyük yanlışlardan birisi de bu üç öğenin birbiri içerisinde gereğinden fazla yer almasıdır. Bu üç öğenin etkileşimi kaçınılmaz olsa da, bu etkileşimi en aza indirmek, hem daha güzel/anlaşılır kodlar üretmek, hem de daha hızlı ve kararlı web önyüzleri üretmemizde faydalı olur. Bu yazıda, nasıl daha standart, anlaşılabilir, güzel, sade web önyüz kodları üretebileceğiniz anlatılmaya çalışılacaktır. Bir web önyüzü;


Standartlara uygun olmalı

Web sayfanızda muhakkak, hangi işaretleme dili kullandığınızı belirtin ve kodlarınızı belirtilen bu işaretleme dillerine uygun standartlarda yazmaya özen gösterin.

XHTML Strict için :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

HTML5 için :

<!DOCTYPE html>

Bu örnekte, üretilen işaretleme dilinin, http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd adresinde belirlenen DTD(Document Type Definition/Belge Tipi Tanımlaması)'ye uygun olarak XHTML 1.0 Strict olması beklenir. Tarayıcılar bu bu tanımlamaya uymayan hataların bir çoğunu tolere etse de, bu tolere etme işlemi tarayıcıların ekstra işlem yapmasına, pek hissedilmeyen küçük performans kayıplarına sebep verir.


Dinamik içerikli (verilerin kullanıcıdan alındığı) sayfalarda, bu standartları korumak zor gibi görünebilir. Bu tip sorunlar için, kullanıcıdan gelen verinin HTML Tidy gibi araçlar veya düzenli ifadeler yardımıyla filtrelenmesi, standartları korumanıza yardımcı olur.


Sayfanızın, belirtilen tanımlamaya uygun olup olmadığını http://validator.w3.org adresinden denetleyebilirsiniz.


Yine aynı şekilde CSS kodlarını yazarken de W3'ün belirlediği standartlara uygun kodlar yazmalıyız.

Internet Explorer'ın CSS yorumlama farkları çok canımızı yakar. Ancak Internet Explorer 6 için bile, standartların dışına çıkmadan (veya çok az çıkarak) kodlar geliştirilebileceğinden yanayım.


Yine de explorer için özel bir CSS yazacaksanız, bunları diğer CSS'lerden ayırın.

<link href="site.css" rel="stylesheet" type="text/css" />

<!--[if lte IE 6]>
<link href="ie6.css" rel="stylesheet" type="text/css" />
<![endif]-->

CSS'lerimizin standartlara uygunluğunu da http://jigsaw.w3.org/css-validator/ adresinden yapabiliriz.


Güncel tarayıcıların tümünde sorunsuz çalışmalı

Evet, yazdığımız kod İnternet Explorer 6 için bile sorunsuz olmalı. Tarayıcılar, çoğu DOM elementini farkli yorumlayabiliyor. Kimi tarayıcıda <body>'nin öntanımlı davranışı {margin:2px; padding:2px;} iken kimi tarayıcılarda {margin:0; padding:0} olabiliyor.


Bunun gibi farkları en aza indirmek için ise reset.css kullanmak. Hazırlanan bu CSS dosyası ile yukarıda belirttiğim sorunların büyük bir kısmı hallolsa da, tarayıcıların yorumlama farkları, siz standartlara uysanız da hâla devam etmekte. Bunun için yazdığınız kodu güncel ve eski tarayıcılarda test etmelisiniz.


Geliştirme aşamasında anlaşılabilir olmalı

Yukarıda bahsettiğim gibi, üç ana öğeyi olabildiğince birbirinden ayırmanız gerekir. Aşağıdaki XHTML tanımlamasını uygun olarak yazıldığını varsaydığımız kod kötü bir web önyüz koduna örnek olarak incelenebilir

<div style="display:block; font-size:17px; color:red; _height:100px;">
<input type="button" value="Gönder" onclick="if (formDenetimiBasarili()) { birkacIsYap(); formuGonder(); }" style="color:black;">
<!-- bu satırlar arasında 100 tane satır olduğunu düşünün -->
</div>

İlk satırdaki div içinde, div'in görünümünü belirten, yani CSS içinde tanımlı olması gereken kodlar, sadece sayfanın istkeleti olması gereken işaret dilinin içersinde yer alıyor. Üstelik div'in display özelliği zaten block iken tekrar tanımlanmış, üstelik standart olmayan bir _height özelliği kullanılmış.


İkinci satırda ise sayfada dinamik birkaç kontrol yapacak JavaScript kodları, yine işaretleme dilinin içerisine konulmuş. Ayrıca yine görünüm tanımlaması vereceğimiz CSS kodları, işaretleme dilinin içerisinde yer alıyor. Üstelik XHTML tanımlamalarına göre <input> etiketini kapatmak zorunludur.


Üçüncü satırda ise bu satırların arasında 100 satırlık başka bir kod olduğunu hayal edin. Dördüncü satırdaki </div>'in hangi div'e ait olduğunu bulmanız büyük zaman alacaktır.


Kodu üç ana parçaya bölecek olursak;

CSS dosyası

/* iletisim formunu kaplayan div */
.contactDiv {
    height: 100px;
    font-size: 17px;
    color: red;
}

/* iletisim formunun icindeki dugme */
.contactDiv input {
    color: #000; /* renklerin RGB kodlarının yazılması tavsiye edilir */
}

JavaScript dosyası

/* iletisim formundaki dugmeye basilma durumunu takip et*/
$(".contactDiv input").click( function() {
    if (formDenetimiBasarili()) { 
        birkacIsYap();
        formuGonder();
    }
});

XHTML dosyası

<!-- bundan once CSS ve JavaScript dosyalarinin cagirildigini farzedin -->
<div class="contactDiv">
    <input type="button" value="Gönder"/>
    <!-- arada yuz satir oldugunu dusunun -->
</div>
<!-- .contactDiv -->

Gördüğünüz gibi, işaretleme dilini, stil dosyalarını ve JavaScript'leri ayrı dosyalar haline getirdik.


Kodu daha anlaşılabilir yapan en büyük etkenlerden birisi de yazdığımız yorum satırları oldu. Hem CSS, hem JavaScript hem de XHTML dosyamıza ilgili yorumları yazarak kodu daha anlaşılabilir yapma yolunda büyük bir adım attık.


Örneğin, XHTML dosyasında son satırdaki <!-- .contactDiv --> ise o div'in contactDiv class'lı bir divin sonu oldugunu belirtiyor.


Aynı şekilde CSS ve JavaScript dosyalarınızı da olabildiğince anlaşılabilir tutmaya çalışın; genel ve özel olarak ikiye ayırın.

Genel dosyalar, sitenin neredeyse tümünde kullanılan sayfalar için yazılan kodları, özel kodlar ise belli sayfalara özel kodları barındırsın. Örneğin, tüm sayfada <a> elementinin rengini kırmızı yapmak istiyorsanız bunu "genel" bir dosyaya koyun, yine aynı şekilde sadece iletişim sayfasında çalışmasını istediğiniz bir JavaScript'iniz varsa bunu da "iletisimSayfasi.js" gibi bir isimle kaydedin.

CSS ve JavaScript dosyalarınızın boyutunun büyümesinden endişe ediyorsanız, aşağıdaki paragraflarda anlatıldığı gibi bunları sıkıştırıp optimize edebilirsiniz.


"Peki bu bize ne kazandırdı?"

  • Kodumuz daha okunabilir hale geldi, yapılan işler ayrıldı. XHTML bilmeyen(veya uğraşmak istemeyen) bir JavaScript programcısı, sadece JavaScript dosyalarını düzenleyebilir hale geldi. Ayrıca yine tasarımcı arkadaşlarımız sadece CSS dosyasına müdahele ederek, sayfamıza istedikleri görünümü verebilmiş oldular.
  • Kod kısaldı. Dinamik bir sayfa oldugunu varsayarsak, XHTML kodu her seferinde değişebilir. Ancak CSS ve JavaScript kodları sabit kalabilir. CSS ve JavaScript kodları tarayıcı tarafında cache'lenebilirken XHTML için bu pek mümkün olmayabilir. XHTML'in kısalması ise bant genişliği masraflarını azaltmaya yardımcı olacaktır.

Gerçek ortamda az trafik harcamalı, hızlı olmalı

Geliştirme ortamında her şey günlük güneşliktir. Hazırladığınız sayfa 100 tane css içeriyor olabilir. 100 kişilik geliştirme ekibiniz olsa bile bu pek sorun teşkil etmeyecektir. Ancak, kodunuz gerçek ortamda çok farklı isteklerle karşılaşacak, anlık gelen 5000 istek sonrasında sistem yöneticilerinizin canı yanabilir.


Hazırladığınız sayfadaki, harici öğelerin (CSS, JavaScript, resimler vs) her biri için bir HTTP isteği yapılır. HTTP istekleri, sunucu tarafında maliyetli isteklerdir. Yukarıdaki gibi bir örnekte, sayfada hazırladığınız 100 CSS dosyası, sayfanın her ziyaretinde sunucuya 100 istek yapacaktır. Bu istekleri en aza düşürmek için ise uygulamanız gereken birkaç yöntem var.


1) JavaScript ve CSS dosyalarını birleştirin

Elinizdeki CSS ve JavaScript dosyalarını uygun sıra ile birleştirip tek dosya haline getirin. Bunu basit olarak aşağıdaki komut ile yapabilirsiniz.

cat reset.css genel.css anaSayfa.css iletisim.css > tumu.css
cat jquery.js genel.js sayfalar.js > tumu.js

2) Dosyaları sıkıştırın ve optimize edin

Sunucudaki istekleri tek dosyaya indirdik. Artık istek sayımız azaldı. Ama bu tek dosya toplamda 100 kilobyte tutuyor olabilir. Ve bu 100 kilobyte'ın 50 kilobyte'ı yorum satırları veya boş satırlar olabilir. Aşağıdaki iki JavaScript kodu aslında aynı işlemi yapmaktadır.


Geliştirme ortamı kodu: Aşağıdaki kodda kurulan hiyerarşi, yorumlar vesaire pek anlaşılır bir şekilde, olması gerektiği gibi yazılmış.

/**
* Bu kod sunu sunu yapiyor
* Su event'leri dinleyip, su class'lari cagiriyor
* Ayrica bu kod su lisansa sahip
* WEB_GELISTIRICI_LISANSI_1.0
* Bu lisans sunları sunları gerektirir
* 
* params {String} metin : Ekrana basilacak metni bildirir
*/
sayfalar.iletisim.hata.ekranaBas = function(metin) {
    // gelen metni ekrana basar
    alert(metin);
};


/**
* baglantinin tiklama isleminde bir hata olusura ekrana bas
*/
$("a").click ( function() {
//herhangi bir hata olustuysa ekrana hata bas
    if (hataVarMi()){ 
        sayfalar.iletisim.hata.ekranaBas("Bir hata olustu");
    }
});

Ancak, aslında yukarıdaki kodun yaptığı işi, şu kod aynen yapıyor.

x=function(a){alert(a)};$("a").click(function(){hataVarMi()&&x("Bir hata olustu")});

Yazdığımız CSS ve JavaScript kodları, yorumlardan, gereksiz satırlardan arındırmak ve hatta aynı işi yapan daha kısa kodlar üretmek için çeşitli araçlar mevcut.

Bunlardan birisi Yahoo'nun geliştirdiği YUI Compressor. YUI compressor ile JavaScript ve CSS dosyalarınızı sıkıştırabilirsiniz. Ayrıca Google'ın Google Closure Compiler uygulaması da JavaScript sıkıştırma işleminde gayet başarılı. Ayrıca web üzerinden de kullanılabiliyor.


CSS dosyalarınızı optimize etmek için de CSS Optimizer kullanabilirsiniz.

Bu uygulamalar ile, birleştirerek HTTP isteklerinden tasarruf sağladığınız kodlarınızı küçültüp, bant genişliğinden de kazanç sağlayabilirsiniz.


3) Mümkün olan resimleri birleştirin

Sayfada bulunan "harici" öğelerden birisi de resimlerdir. Sayfanızın tasarımı için kullandığınız her resim, sunucuya yine bir HTTP isteği yapacak, anlık 5000 ziyaret sonrası sistem yöneticilerinizin yine canı yanabilir. Bu resimleri mümkün olduğunca birleştirerek istek sayısını azaltabilirsiniz. Bunun için CSS Sprite tekniğini kullanabilirsiniz. Bu teknikle, örnek olarak sayfanızdaki resim olan menü öğelerini, tek bir resme koyup (istek sayısını bire indirip), CSS background-position özelliği ile resmin ilgili yerinin gösterilmesini sağlayabilirsiniz.


4) Resimleri optimize edin

Oluşturduğunuz resimleri optimize ederek daha düşük boyutda, neredeyse aynı kalitede resimler sunabilirsiniz. Bunun için pngcrush veya jpegtan gibi uygulamaları kullanabilirsiniz. Ayrıca Yahoo'nun SmushIt servisi ile, bu optimizasyonları Web üzerinden de yapabilirsiniz.


5) Mümkün olan her şeyi önbelleğe alın (cache)

5.1 ) Expires, Cache-Control veya ETags HTTP başlıkları kullanın

Sunucu tarafında, önbelleğe alınmasını istediğiniz dosyaları (.js, .css) Expires veya cache-control başlıkları ile gönderirseniz, tarayıcı bu dosyalara yapılan istekleri kendi önbelleğine alacak ve ikinci istekte sunucuya gitmeyecektir.

5.2) Cevapları sıkıştırın

İsteklere gönderilen cevapları(response), sunucu tarafında gzip ile sıkıştırarak gönderererek bant genişliğinden tasarruf edebilirsiniz.

5.3) AJAX isteklerini önbelleğe alın

Eğer sayfanızda, sıkça AJAX isteği yapıyorsanız, bunlar için bir "cache" mekanizması geliştirin. Aşağıdaki gibi bir kodunuz olduğunu düşün.

/** kullanici verilerini getir */
function kullaniciVerileriniGetir() {
    var veri = Ajax.senkronIstekYap("http://sayfa.com/veriGetir.php");
    return veri;
}

/** kullanici resimlerini getir **/
function resimleriGetir() { 
     var kullaniciVerileri = kullaniciVerileriniGetir(); // ajax requesti yapacak
     //ancak bu veriyi onbellege alsaydaik bu requeste gerek kalmayacakti

     var kullaniciId = kullaniciVerileri['id'];
     var resimler = Ajax.senkronIstekYap("http://sayfa.com/resimleriGetir?id="+kullaniciId"); //ajax requesti yapacak
     return resimler;
}

Ama kullaniciVerileriniGetir() fonksiyonu icin bir cache mekanizması oluşturulsaydı, resimleriGetir() içinde çağırılan kullaniciVerileriniGetir() için istek yapılmayacaktı.


Örnek olarak basitce şöyle bir mekanizma geliştirilebilir.

/** önbellek objesi **/
var cache={};

function kullaniciVerileriniGetir() {
    /** önbellekte yoksa istegi yap, önbelleğe al */
    if (!cache['kullaniciVerisi']) {
        cache['kullaniciVerisi'] = Ajax.senkronIstekYap("http://sayfa.com/getir.php");
    }
    
    return cache['kullaniciVerisi'];
}

5.4) DOM öğelerine yapılan istekleri önbelleğe alın

Sayfadaki DOM öğelerine yapılan istekler de istemci tarafını yorar. Aşağıdaki gibi bir JavaScript kodunuz olduğunu düşünün.

$("div.hede span.hodo a[name='hebele']");

Bu jQuery kodu, DOM'daki tüm hede sınıflı div'leri, onun içindeki hodo sınıflı tüm span'ları onun içinde de name özniteliği hebele olan tüm a'ları alacak (Yazması bile ne kadar sürdü?). Ve bunu sayfada birden fazla yerde kullandığınızı düşünürseniz DOM'da gereksiz yere birden çok kez gezineceksiniz.

Yukarıdaki sorgu sonunda bulunan öğeleri bir değişkene atayarak, işlemleri de bu değişken üzerinden yaparak, her seferinde DOM'da gezinmekten kurtulmuş olursunuz.

var $hebele = $("div.hede span.hodo a[name='hebele']");
//sonraki her yerde $hebele'yi kullanabilirsiniz

Kod "Anlamlı" olmalı

Üretilen kod "anlamlı" olmalı. Anlamlı olmalı ki arama motorları ne demek istediğimizi daha iyi anlasın. Örneğin, sayfadaki bir baglantıyı, <a> etiketi yerine istedigimiz herhangi bir elementin click event'ine bir kural belirleyerek de yapabiliriz. Ancak bir <div>'e tıklanınca başka bir sayfaya gitmesi pek anlamlı değildir. Aynı şekilde bir liste kullanacaksak bunları <ul>, <li> etiketleri içerisine, bir veri listeleyeceksek de bunu <table> etiketi içerisine koymalıyız. (table etiketini tasarım için kullanmaktan uzun süre önce vazgeçtiğinizi ümid ediyorum :] ).

Yine aynı şekilde bir haber başlığını <span> içinde vermektense <h1> içinde vermek daha anlamlı olacaktır. Bu sayede arama motorları ile daha kolay "anlaşa"bileceğiz.


Mümkün olduğunca JavaScript bağımsız olmalı/olabilmeli

AJAX'ın giderek popülerleştiği günümüzde neredeyse her işimizi JavaScript ile yapar olduk. Ancak arama motorları JavaScript'i pek sevmiyor. Aşağıdaki gibi bir kodumuz olduğunu düşünün.

<a href="#" class="iletisimSayfasinaGit">iletisim</a>

<script type="text/javascript">
$("a.iletisimSayfasinaGit").click( function() {
    $("#icerikDivi").load("http://www.sayfa.com/getir.php?iletisim&sadeceIcerik=true");
}
</script>

Ama bu kod JavaScript desteklemeyen bir tarayıcı (tamam pek yok günümüzde ama) ve arama motorları için pek bir şey ifade etmiyor. Bu kod şu şekilde olsa daha bir anlamlı olur.

<a href="http://www.sayfa.com/getir.php?iletisim" class="iletisimSayfasinaGit">iletisim</a>
<script type="text/javascript">
$("a.iletisimSayfasinaGit").click( function(event) {
    event.preventDefault(); //burada normal sayfaya gitmesini engelledik
    $("#icerikDivi").load("http://www.sayfa.com/getir.php?iletisim&sadeceIcerik=true");
}
</script>

Bu şekilde, JavaScript destekli istemci kullanan kullanıcılar sayfayı AJAX ile çağırabilirken, JavaScript desteklemeyen bir istemciye sahip kullanıcılar ise www.sayfa.com/getir.php?iletisim adresini ziyaret etmiş olacaklar.

Sonuç olarak...

Bu tip birkaç kural ile daha "iyi" web önyüzleri hazırlayabilirsiniz. Yahoo'nun hazırladığı YSlow Firefox eklentisi ile hazırladığınız sayfaların yukarıda anlatılan bazı kuralllara ne kadar uyduğunu da kontrol edebilirsiniz.