Önyüzünde Backbone kullandığımız projeye eklenmesi gereken basit bir özellik var.
– Formda 12 tane alan vardır bunların *,*,* alanları zorunludur.
– Kullanıcı formu doldurur.
– Form geçerli ise listeleme sayfasına yönlendirilir.
– Geçersiz ise ilk hatalı input viewport’a gelir (scroll yapılır).
– Hem desktop hem mobilde aynı akış sağlanmalıdır.
Ne mobilde ne de masaüstü sürümde (responsive, esnek tasarım) form elemanının yerini tespit edip scroll yapamayacağımıza göre en güzel çözüm o elemanı aktif hale getirmek, yani “focus” event’i tetiklemek. Backbone size form yapısı sağlamıyor, fakat @powmedia’nın formu hemen hemen bütün ihtiyaçları karşılıyor.
Sistemde kullandığımız hiç bir kütüphaneyi abstract bir katman eklemeden kullanmıyoruz. Dolayısı ile kendi oluşturduğumuz Form, Backbone.Form u extend eden abstract katman. Yapımız AMD (Asynchronous Module Definition) ve dependency manager olarak RequireJS kullanıyoruz. Bunlarla birlikte Backbone bağımlılıkları olan jQuery, underscore gibi kütüphaneleri de sayfaya yüklememiz gerekiyor.
Çalıştığımız dizine RequireJS, Backbone ve BackboneForms u koyduktan sonra BackboneForms’dan kalıtım alan modulümüzü şöyle yazıyoruz:
Not: Ön bilgi vermekte fayda var, sayfamızda Backbone.Form github’daki powmedia’nın geliştirdiği formdur. Radiobox, selectbox gibi form elementleri editors namespace’i altında toplanmış. Siz de kendi form element türlerinizi geliştirebilirsiniz. Mesela yukarıdan gelen bir başka istekde bir sistemdeki tüm fiyat belirten inputların başına para cinsi, sonuna da “.00” şeklinde küsüratı sabitlememiz istenmişti, biz bunu Backbone.Form.editors.PriceField şeklinde tanımladık, formların şema tanımlamalarında da “type: ‘Text'” yerine “type: ‘PriceField'” yazarak basitçe çözdük.
Tüm form elementleri Backbone.Form.Field‘i extend ediyor. Backbone.Form.editors namespace’i altında da üst paragrafda bahsettiğim form eleman türleri var. Yani checkbox’ı override etmek için Backbone.Form.editors.Checkboxes, veya hidden input’u yeniden tanımlamak için Backbone.Form.editors.Hidden methodunu ezmeniz gerekiyor.
Bu blog yazısında bahsettiğimiz yer Backbone.Form.Field methodunu yeniden tanımlamak. Fakat ileriye dönük farklı ihtiyaçları da karşılayabilmek için biz burada Backbone.Forms’u da boş şekilde extend ettik.
/**
* Author: Irfan Durmus
* Date: Thu Apr 3 12:03:32 2014 +0400
*
* Customized Backbone Form Asynchronous Module in order
* to provide atuo-focus to first error field in Backbone Forms.
*/
define([
'backbone',
'backbone-forms'
], function(
Backbone,
BackboneForms
){
// we'll need this variable to count how many element we have in our form.
var counter,
// extend Backbone.Form element to implement new features in the future
Form = Backbone.Form.extend({});
Form.Field = Backbone.Form.Field.extend({
/**
* Overwrite the setError method of Backbone.Form.Field
* to focus first element when error occur
*/
setError: function(msg) {
Backbone.Form.Field.prototype.setError.call(this, msg);
this.hasError = true;
counter++;
this.findError();
},
/**
* Overwrite the clearError method of Backbone.Form.Field
*/
clearError: function() {
Backbone.Form.Field.prototype.clearError.call(this);
this.hasError = false;
counter++;
this.findError();
},
findError: function() {
var totalSize = _.size(this.form.schema),
focusField = null;
if (counter == totalSize) {
// set counter 0 to able to manage next form action;
counter = 0;
_.each(this.form.fields, function(field, key, fields) {
if (!focusField && field.hasError) {
focusField = field;
}
});
if (focusField) {
focusField.focus();
}
}
}
});
// return and use this extended form class instead of Backbone.Forms;
return Form;
});
Form’u post ettiğimizde, form her bir elemanı için, clearError veya setError methodlarını çağırıyor. Biz yine formun sağladığı methodları static olarak Backbone.Form.Field.prototype.clearError.call ile çağırarak normal davranışını bozmadık. Sonra hata olup olmadığını anlamak için hasError’u set ettik (sanırım formda zaten var bu, satırı silip denemedim). Her bir form elemanı için her iki method’dan birisi çağrıldığına göre counter++ ile iki methodda da artırım yapmamızın bir saknıcası yok. Son olarak da kendi tanımladığımız findError methodunu çağırıyoruz.
Not: Diğerleri nasıl çözüm üretmiş diye araştırdığımda ingilizce kaynaklarda bile object orient bir çözüm olmaması çok garip gelmişti.
Ba’ğ’zı şeyler vardır ki ayda yılda bir lazım olur, her seferinde manuelde gezip zaman kaybetmek can sıkıcı. Son 5 yıl içinde 3-4 kez git sunucu kurdum, her seferinde de manuel e ihtiyaç duydum. Unutmamak için aldığım ‘not’ yazılarından biri de bu olacak.
Güvenli Git Sunucu Kurulumu
apt-get install git git-sh ile paketleri kurduktan sonra ‘git’ kullanıcısını debian üzerinde şu şekilde ekliyoruz: $ adduser --system --home /var/services/git --shell /usr/bin/git-shell --disabled-password git
Burada parametreler önemli.
--system ile kullanıcının “system user” olacağını belirledik ve /etc/skell altındaki .profile gibi dosyaların kopyalanmamasını sağladık. --home ‘a /var/services/git parametresini geçerek ‘git’ kullanıcısının dizinini /var/services altında olmasını istedik, normal kullanıcılar ile karışmasın. --shell parametresi güvenlik için önemli “kahrolsun diğer shell’ler”. git kullanıcısı hack’lense bile sadece git işlemleri yapılabilecek, sisteme ulaşılamayacak. --disabled-password ile “şifre ile giriş yapılamaz” olarak ayarladık. SSH key ile hala giriş yapılabilir, bize de bu lazım. Tabii ki ssh ile normal shell işlemleri de yapılamaz, –shell /usr/bin/git-shell ile bunu da engellemiştik, ssh user@server şeklinde bir giriş mümkün değil.
Özetle, sadece git işlemlerine, sadece ssh key kullanarak yapılmasına izin verdik. Ev dizinini değiştirmemizin bir güzelliği de git@irfandurmus.com:/var/services/git/myblog gibi çirkin/kullanışsız bir yapıyı da engelledik. Geliştiricilerin sadece git@irfandurmus.com:project şeklinde kullanmaları yeterli olacak.
/var/services/git dizin git’in home dizini ve boş. Şimdi repository oluşturalım, $ cd /var/services/git
$ mkdir myblog.git
$ cd myblog.git
$ git init --bare
$ ls
branches config description HEAD hooks info objects refs
/var/services/git/.ssh/authorized_keys dosyasını oluşturup, içerisine kullandığınız bilgisayardaki ~/.ssh/id_rsa.pub dosyamızı yazıyoruz, bildiğiniz standart ssh key login. (Dosya bilgisayarınızda yoksa ssh-keygen -t rsa ile oluşturabilirsiniz.) Takımdaki diğer arkadaşların id_rsa.pub dosyalarını da ekliyoruz buraya.
Tüm işlemleri root ile yaptığımız için /var/services/git/ dizini altında chown -R git:nogroup . komutunu çalıştırarak yetkileri düzenleyelim.
Hepsi bu kadar, bakalım çalışıyor mu; $ git clone git@irfandurmus.com:myblog
Cloning into 'myblog'...
The authenticity of host 'irfandurmus.com (***.**.***.***)' can't be established.
RSA key fingerprint is **:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'irfandurmus.com' (RSA) to the list of known hosts.
warning: You appear to have cloned an empty repository.
$ cd myblog/
$ touch foo
$ git add .
$ git commit -am "foo"
[master (root-commit) 9b630ea] foo
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 foo
$ git push -u origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 201 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@irfandurmus.com:myblog
* [new branch] master -> master
Branch master set up to track remote branch master from origin.
$ git remote -v
origin git@irfandurmus.com:myblog (fetch)
origin git@irfandurmus.com:myblog (push)
Homebrew hakkında çok güzel olduğunu iddia eden yazılar gördüm fakat adamakıllı bir kanıt göremedim ben. Homebrew’i aylar önce denedim ve kurduğum ilk gün 3 tane bağımlı paketin olmadığını görünce kırk takla atarak ports a göre döndüm. Kullanacağınız paket yöneticisinde paket zenginliği çok önemli. Kuracağınız paketlerin bağımlılığının olması doğaldır. Paket yöneticisi seçiminde paket zenginliği en önemli konulardan birisidir.
MacPorts çok yetenekli, neden macports un homebrew den daha üstün olduğunu gösterecek bir kaç örnek vereyim.
Zenginlik
Php 5.3 kullanıyorum, 5.4 ü de sistemime kurmak arada denemek istiyorum. Kullandığım bilgisayarda sudo port activate php54 ile version değiştirip, çalışmayan yer olup olmadığını test edip, herşey düzgün ise sunucuyu da 5.4 e yükseltebiliyorum. Eğer sorun varsa sudo port activate php53 ile önceki versionu aktif edebiliyorum. Aynı şey python veya diğer paketler için de geçerli.
Stabilite
Diyelim ki php5 paketini kurdum. php5 son stabil versiyona linklidir. Yani 5.3 stabil iken 5.3 e linklidir. 5.4 stabil olmuş ise 5.4 e otomatik yükseltilir ve 5.3 sisteminizden kaldırılmaz! Önemli nokta burası. Sistemi güncellediniz, sorun çıktı sudo port activate php53 ile geri dönebilirsiniz.
Ports /opt/local altına kurulur, MacOSX ile birlikte gelen hiç bir uygulamanıza karışmaz, dokunmaz. Kaldırmak istediğinizde de yardım bulması çok kolay.
Sistem Bakımı
Kolay sistem bakımı sağlar. port installed |grep -v “active” ile aktif olmayan paketlerin listesini alıyorsunuz. Baktınız hiç birisi işinize yaramıyor ve bir daha da kullanmayacaksınız. sudo port uninstall inactive ile hepsini kaldırıyorsunuz.
Upgrade / Downgrade
sudo port selfupdate ile sistem veritabanını günceller ve yeni versionları kurarsınız. Debian’daki apt-get update e eşittir. Sorun ile karşılaşırsanız zaten kurulmuş olan eski versionu güncellemek için sadece activate etmeniz yeterli.
Örneğin sunucunuzda php 4.4.9 gibi çok eski bir version var. Karşılaştığınız hatayı kullandığınız bilgisayarda görmek istiyorsunuz. “sudo port install php4 @4.4.9” yazıyorsunuz ve php4 ün 4.4.9 versionu u Macintosh’unuza MacPorts aracılığıyla kuruluyor. Hatayı kendi bilgisayarınızda tekrarlayıp, çözüp commit ediyorsunuz.
Dökümantasyon
En önemli noktalardan biridir dökümantasyon. port help yazıyorsunuz ve şöyle bir çıktı alıyorsunuz (sadece bir kısmı bu).
Bunlar sadece action lar. Yani alt komutlar ile bir çok işlem yapabilirsiniz. Daha fazla detay isterseniz kocaman man sayfaları var. homebrew de yardım ı çalıştırınca websitesine yönlendiriyor, ne saçmalık! İnternetim yoksa dökümanım da mı olmayacak?
İnternette Macports’a çok haksızlık ediliyor. Bir sisteme kötü demek için yaşanan problemlerin diğer insanların da yaşayıp yaşamadığına bakmak lazım. Bazı sorunlar “kullanıcı” kaynaklıdır.
MacPorts kullanıyorum, mutluyum. Stabil, başağrısız, bol paketli, güzel dökümantasyonlu bir paket yöneticisi arıyorsanız homebrew, fink gibi atraksyonlara girmenizi hiç tavsiye etmem.
Hala FTP ile live server’a dosya gönderenlerin oranı web üzerindeki domainlerin çoğunluğunu oluşturuyor. Revision Control kullananların bir kısmı da doğru sürümleme yapmıyor. Oyunu kurallarına göre oynamak, ürünün sürdürülebilirliği açısından önemlidir.
İşlerinizi otomatikleştirmek, en zayıf halka olan insan hata oranını olabildiğince aza düşürür, size zaman kazandırır. Yazılımınızın deployment stratejisi olması bu noktada önemli. Büyük bir ekip de olsanız, reklam ajansında küçük web siteleri yapıyor da olsanız düzeninizi kurduktan sonra sorunların çok daha hızlı çözüldüğünü göreceksiniz.
Boss Parametreleri
help Yardım dosyasını gösterir test Local, stage veya live sunucu üzerinde verilen projenin testini tetikler. deploy Verilen server üzerine verilen projenin verilen sürümünü deploy eder. rollback Local, stage veya live sunucu üzerinde son yapılan deployment’i geri alır. project Yeni proje eklemek, listelemek ve silmek için kullanılır.
Deployment
Web dünyasında deployment dediğimiz zaman akla gelen işlemler;
Code base update
Get pass frontend unit/integration tests
Pass backend tests
File permission updates
Database update (sql/no-sql)
Cache invalidation
Bu işlemleri önce kullandığınız bilgisayarda, sonra stage sunucuda son olarak da live sunucuda yaparsınız. Boss‘u ben bu işlemler için kullanıyorum. Farklı deployment yaklaşımları olabilir, size kalmış. Örneğin birden fazla application server’iniz var ise boss size yetersiz gelecektir, henüz çoklu live sunucu desteklenmiyor.
Bir kurulum ile birden fazla proje deploy edebilirsiniz. Sürüm için branch değil tag kullanır, kurulum çok basit;
$ git clone git@github.com/irfan/boss.git boss
$ cd boss
$ sh install.sh
Proje ismi, git repo, projenin bilgisayarınızda ki yolu, stage ve live sunucu bilgilerini girdikten sonra deployment için ilk proje config dosyanız ~/.boss/etc/<projeadi>.conf altında oluşturulacak.
NOT: Bu bilgileri eksiksiz girmelisiniz. sunucudaki proje dizininiz örneğin /var/www altında ise normal user ile burada değişiklik yapamayacağınız için root ssh login’in sunucuda açık olması ve root’u kullanmanız kolaylık sağlar. Eğer normal kullanıcı girerseniz, proje dizininiz /home/irfan altında olsa bile web sunucunuz www-data gibi bir kullanıcı ile çalıştığı için yine sıkıntı olacaktır. Fakat web sunucunuzu ssh ile aynı kullanıcıyla çalıştırıyorsanız sorun yaşamazsınız.
Versioning
Verisyon numaralarının anlamlı olması önemli. Bu konuda düşünceleriniz net değilse Wikipedia daki Software versioning başlığı sürümleme nedir ve nasıl olmalıdır konusunda size ön bilgili verebilir.
Boss sadece tag ile deployment yapabilir. Zaten branch ile yapılan sürümleme işlemi yanlıştır. Bu konu da ayrı bir yazının konusu.
Birinci sürüm deployment
Local, live ve stage sunucunuz da git repository’nizin olduğunu ve git pull yaptığınız zaman git sunucunuzdan güncellemeleri aldığınız bir sisteminizin olduğunu varsayarak devam ediyoruz. HEAD’inizi 1.0.0 sürümü oluşturarark sırasıyla local, stage ve live a deploy edelim.
NOT: Deployment a başlamadan önce .gitignore dosyanıza .boss/* satırını eklemelisiniz. .boss dizini altında deployment ve sürüm logları tutulmaktadır.
$ git status
# On branch master
nothing to commit (working directory clean)
$ git tag
$ git fetch --tags
$ git tag -a 1.0.0 -m "Version 1.0.0 releasing"
$ git push --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 172 bytes, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@happycoding.net:blog
* [new tag] 1.0.0 -> 1.0.0
$
Bulunduğumuz commit’i yani HEAD’ı 1.0.0 version olarak oluşturduk ve git server’a gönderdik. Şimdi bunu satge a deploy edip testlerimizi çalıştıralım.
$ boss deploy stage blog 1.0.0
==========================================
Deploying to: stage
Project: blog
Version: 1.0.0
==========================================
Pseudo-terminal will not be allocated because stdin is not a terminal.
--> Directory changing
--> creating log directory
fatal: No names found, cannot describe anything.
fatal: No names found, cannot describe anything.
--> Current version is
--> Checking uncommitted changes
--> Fetching tags
--> Pulling with flag
--> Getting new version
--> Setting permissions
Deployment succeed.
Current version is 1.0.0
$
İki tane fatal görünüyor, ilk kez deploy ettiğiniz için bunlar görünüyor. Bir sonraki sürümde görünmeyecek, bunları görmezden gelip devam edebiliriz. Şimdi sıra testlerimizi çalıştırmada.
NOT: Projenizi yapılandırırken testleri trigger edecek scriptin bulunduğu path i ve parametreleri girmiştiniz. Proje dizininizin altında bu scriptin bulunduğunu ve gerekli testleri tetikleyip sonucu verecek yeteneğe sahip olduğunu varsayıyoruz.
$ boss test stage blog
==========================================
Testing on: stage
Project: blog
Version: 1.0.0
==========================================
--> Running 74 frontend tests, please wait
--> 73 of 74 passed
--> 1 test failed:
- Test ID : 12
- Error : User ID could not found in user object
--> Running 138 backend tests, please wait
--> 138 of 138 test passed
Connection to irfandurmus.com closed.
$
Bir testimiz başarısız oldu. Gerekli değişikliği yapıp master branch’a commit edip, sunucuya push’luyoruz. Şimdi bir bugfix yapmış olduk ve bu ayrı bir sürüm olmalı. Sürümümüzün adı 1.0.0-1 olsun. $ git tag -a 1.0.0-1 -m "12th failed test fixed"
$ git push --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 173 bytes, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@happycoding.net:blog
* [new tag] 1.0.0-1 -> 1.0.0-1
$
Şimdi tekrar stage e deploy edip testleri çalıştıralım. $ boss deploy stage blog 1.0.0-1
==========================================
Deploying to: stage
Project: blog
Version: 1.0.0-1
==========================================
Pseudo-terminal will not be allocated because stdin is not a terminal.
--> Directory changing
--> Current version is 1.0.0
--> Checking uncommitted changes
--> Fetching tags
--> Pulling with flag
--> Getting new version
--> Setting permissions
Deployment succeed.
Current version is 1.0.0-1
$
Gördüğünüz gibi stage sunucu üzerindeki sürüm 1.0.0 dan 1.0.0-1 e yükselmiş oldu. Şimdi testleri çalıştıralım. $ boss test stage blog
==========================================
Testing on: stage
Project: blog
Version: 1.0.0-1
==========================================
--> Running 74 frontend tests, please wait
--> 74 of 74 passed
--> Running 138 backend tests, please wait
--> 138 of 138 test passed
Connection to irfandurmus.com closed.
$
Tüm testlerimiz başarılı olduğuna göre artık live sunucuya bu sürümümüzü deploy edebiliriz. $ boss deploy live blog 1.0.0-1
==========================================
Deploying to: live
Project: blog
Version: 1.0.0-1
==========================================
Pseudo-terminal will not be allocated because stdin is not a terminal.
--> Directory changing
--> Current version is 1.0.0-1
--> Checking uncommitted changes
--> Fetching tags
--> Pulling with flag
--> Getting new version
--> Setting permissions
Deployment succeed.
Current version is 1.0.0-1
İstersek testlerimizi live sunucu üzerinde de çalıştırıp bir hata varsa aynı şekilde fix edebiliriz fakat stage ile live aynı sonucu vermiyorsa sorun sistemler arasındaki farktadır.
Son olarak belirtmeliyim ki boss kesinlikle bir Jenkins veya Hudson alternatifi değildir, olamazda. Sadece işlerin nasıl olması gerektiğini gösteren basit bir script’dir.
lselect Finder için mükemmel bir tool. Basitçe yaptığı işlem aktif Finder penceresinde vereceğiniz bir regexp satırına uyan bütün dosya ve dizinleri seçmek. *.png veya *[0-9].??? gibi desenlerle bir dizinde select yapabilmek işleri kolaylaştırıyor -D
Link bir gün kırılırsa diye local mirror koydum. Snow leopardda denedim sorun yok, leopard ve tiger da deneyip yorum olarak eklerseniz sevinirim.
Daha önce bahsettiğim Finder için terminal butonunda eğer terminal penceresi açıksa, yeni bir pencere açıyordu. Buradan ve buradan yararlanarak bu zip dosyasını hazırladım. Diğer script de olan 2. pencere açma hatası ve terminal açıldıktan sonra görünen cd komutu yok. Eğer Terminal penceresi açıksa yeni bir terminal penceresi açıyor.
Burada anlattığım yöntem ve bash script ile eAccelerator kurmuşsanız scripti çalıştırdığınız dizinde eaccelerator-0.9.5.3 isminde bir klasör oluşacaktır.
Bu klasörün içerisinde bulacağınız control.php dosyası bize temel anlamda eAccelerator’ı yönetme imkanı veriyor. (daha&helliip;)
Var olan sisteminizin yükünü düşürmek istiyorsanız eAccelerator en iyi yöntem diyebilirim. eAccelerator derlenen PHP dosyalarını cache dizinde tutup, tekrar aynı dosyalara istek geldiğinde kodları yeniden derlemek yerine, bu dizindeki derlenmiş kodları httpd ye gönderir.
Yeni bir sisteme başlayacaksanız ve yeterli miktarda ram e ve server a para harcayabiliyorsanız memcached kullanılabilir. Memcached için özetle dağıtık önbellek sistemi diyebiliriz (Distributed Memory Caching System). Memcached’in diğer bir dezavantajı da işin yükünü programcıya bırakmasıdır. Memcached detaylı bir konu olduğu için (WordPress stats eklentisi bile var) daha sonraya bırakıp işimize dönelim.
Symfony 1.2.8 kullanıyordum, güncellemek için pear uninstall symfony/symfony-1.2 ile kaldırdıktan sonra 1.4.1 i kurayım dedim.
$ pear channel-discover pear.symfony-project.com
Channel "pear.symfony-project.com" is already initialized
$ pear install symfony/symfony-1.4.1
Failed to download symfony/symfony, version "1.4.1", latest release is version 1.3.0BETA1, stability "beta", use "channel://pear.symfony-project.com/symfony-1.3.0BETA1" to install
Gün geçtikçe Türkiye’nin kullanabileceği internet servisleri azalıyor. Daha önce Youtube DNS ve IP Adresleri başlıklı ve The Pirate Bay’dan Sıkıntısız Torrent Kullanabilmek başlıklı yazılar yazmıştım. Fakat her yasaklı site için bu gibi bir yöntem kullanmak oldukça zahmetli ve can sıkıcı bir iş. İleride servislerde yapılacak değişiklikler sonrasında bu yöntemler etkisiz kalacaktır.
MacOS X üzerinde default gelen bind ile bu sorunu tamamen ortadan kaldırıyoruz. Terminalden aşağıdaki komutları uyguluyoruz.
$ sudo rndc-confgen > /etc/rndc.conf
$ sudo service org.isc.named start
Alternatif yöntem;
$ sudo rndc-confgen -a
$ sudo service org.isc.named start
System Preferences -> Network -> Advanced -> DNS kısmına dns adresi olarak 127.0.0.1 giriyoruz.
Bilgisayarımızı yeniden başlatıyoruz.
Detaylı bilgi için ISC sayfalarını kontrol edebilirsiniz.
Sisteminiz MacOS X değil ise, BIND kurup gerekli değişiklikleri yapıp aynı şekilde DNS bazlı yasakları aşabilirsiniz.