18 Aralık 2012 Salı

Jirada import workflow XML sonrası NullPointerException almak


Jira'da iş akışını değiştirmek istedik. Bunun içinde arkadaşımın daha önceden hazırladığı iş akışını istedim. Onu alıp import edince herşey çok güzel olacak sandım... Ancak aldığım bu hata ile ciddi sorunlar yaşadım.

Error rendering WebPanel (workflows/workflows.vm): org.apache.velocity.exception.MethodInvocationException: Invocation of method 'getHtml' in class com.atlassian.jira.web.component.IssueConstantWebComponent threw exception java.lang.NullPointerException at workflows/workflows.vm[line 136, column 65]

Hatayı araştırdığınızda size önerilen şey şu;
https://confluence.atlassian.com/display/JIRAKB/NullPointerException+after+importing+workflow+XML

Aynı zamanda sorunu yaşayıp çözüm arayan garibanlar ; https://answers.atlassian.com/questions/60144/workflow-scheme-and-project-where-do-they-link-in-database

İşin kötü yanı bu workflow'u değiştirmek için girmeniz gereken sayfada bu hatayı alıyorsunuz. Başka bir projenin sayfasından bu yönetim kısmına gidip ID yi elle değişitrmek istediğinizde de yemiyor...

Projelerin ID lerini bulmak için rest API den faydalanıyoruz.
http://ip:8080/rest/api/2/project [1]

http://ip:8080/secure/project/SelectProjectWorkflowScheme!default.jspa?projectId=10000

Ama aynı hata devam ediyor...

Sonra aklıma yardım sayfasında elemanın mysql üzerinden insert yapmaya çalışması geldi. Yeni eklediğim workflow daki "attribute" ları eklemem gerektiğini düşündüm.  (En başta olması gereken buydu zaten)

http://ip:8080/secure/admin/ViewStatuses.jspa

Burda acaba ID tutar mı nasıl olacak derken aynı workflow da tanımlandığı ismi ile ekledim.
Ve her eklediğim o an aktif oldu.

Sonuç: Artık çalışıyor :)

[1] http://docs.atlassian.com/jira/REST/latest/


13 Aralık 2012 Perşembe

Code Retreat Istanbul

Merhaba,

Geçtiğimiz Cumartesi (8.12.2012) Parkyeri & Telenity iş birliği ile hazırlanan Coderetreat Istanbul etkinliğine katıldım. İnanılmaz keyifli ve güzeldi. Çeşitli etkinliklere kartılmıştım ama Coderetreat budur diyeceğimiz bir etkinlikti.

Neler kazandırdı ?

a. Hiç tanımadığınız insanlarla çalışma fırsatı.
b. Silbaştan yapmak gerek bazen.
c. Farklı şekilde düşünmeye çalışma.
d. Çok iyi şarkı söyleyemesenizde ortama ayak uydurma.
e. Dünya TDD yapana güzel.

a) Her 45 dakikada yeni bir oturum, yeni görev ve yeni bir arkadaşınız oluyor.
Herkes bir önceki otorumda yaptığı iş ile ilgili bilgi paylaşımında bulunuyor.
Tabi yeni gelişmelerle ilgili eski "pair" larınız ile konuşup geçmişi yad ediyorsunuz.

b) Her 45 dakika sonunda mevcut kodu shift+delete ile silip ortadan kaldırıyorsunuz.
Her oturumda yeni biri olarak işe başlıyorsunuz.

c) Aslında bunun için zorluyorlar ki bu çok iyi. Eve hergün aynı yoldan gidince durup düşünmüyorsunuz bile o yolu öylece gidiyorsunuz. Ama bilmediğiniz yola girince kafanız hiç aşağı eğilmiyor...

d) Bazı terimleri, yazılan kodu anlamasanızda sizde yazıyorsunuz bişeyler. Sonra zaten nakaratı öğrenince sizde bağırmaya başlıyorsunuz...

e) Eee bu kadar şey ne için, maymun gözünü açsın diye. Ama işe başladığınızda bal kabağı ile takılmaya devam ediyorsunuz. TDD yapılan bir firmada çalışmanın tadıda ne güzel olurdu...

Son olarak böylesi organizasyonların artmasını diliyorum, Allah diğer "büyük" firmalarada böylesi faydalı etkinlikler yapmayı nasip etsin. Büyükler bu işlere yatırım yapıp ev sahipliği yapmayacaksa "yurt dışından adam getirelim" kafası yaşamaya devam edecek. Ama bunun bir kısır döngü olduğu "bilen"ler tarafından "biliniyor"...

Not: Etkinlik ile ilgili detaylı bilgi için Facebook Sayfası

Teşekkürler Parkyeri & Telenity



25 Eylül 2012 Salı

Zend Framework 2'yi tanıyalım...

Bildiğiniz üzere Zend Framework 2'nin kararlı sürümü geçtiğimiz günlerde yayınlandı.
Zend ciddi değişiklikler ile karşımıza neredeyse tamamen yeni bir ürün çıkarttı. Bende bunu en sade haliyle anlatmaya çalıştım.

http://www.gelistiricigunlugu.com/zend-framework-2yi-taniyalim/

18 Ağustos 2012 Cumartesi

Rocket Internet'in ardından

Aslında söylenecek çok şey var ama çoğunu arkadaşlarımız söyledi şuralardan okuyabilirsiniz.

http://irfandurmus.com/blog/rocket-turkiye-ofisinin-kapanmasi/

http://ibrahimgunduz.net/rockete-veda/

http://negaripseylervarya.blogspot.com/2012/08/efendi-gibi-nasl-batlr.html

Birde işin medyatik yönü var o da şurda ;
www.webrazzi.com/2012/08/17/rocket-internet-turkiye-kapaniyor/


Eee bu kadar mı ? Yok arkadaşlar ben size başka şeyler anlatacağım. Bütün kaliteli imkanların yanı sıra,

Adam akıllı kütüphanesi vardı,
İnançlara saygı ve hoşgörü vardı.
Örnek:
Mescidi vardı (henüz bu imkanı veren yer göremedim, ayrıca mescit için toplantı odasının bir kısmını bölüp ayırmışlardı.)
Ramazan nedeniyle CTO (Önder Bey) Volkan sabah biraz erken gel akşamda kafan durunca çık diyebiliyordu.
Bir sorununuz olduğunda Takım liderinizden developer arkadaşlarınıza herkes alakadar oluyordu.
Kısaca insalık hoşgörü hat safhadaydı. Kimsede size dik dik bakıp laf sokuşturma peşinde değildi!

Bu kadar şeyden sonra Cumartesi sorun çıktı bakar mısın dediklerinde seve seve bakıyorsunuz...
(Gerçi öyle bişey nasip olmadı :) )

Sonuç Rocket Internet gerçekten iyiydi...

Tüm çalışma arkadaşlarıma teşekkürü bir borç biliyorum. Hepsine başarılar diliyorum.

31 Mayıs 2012 Perşembe

Subquery pişmanlık değildir!!!

Subquery pişmanlık değildir!!!

Neden mi ?

JOIN ile yaptığınız sql'i Explain ile kontrol edin. Sonrasında eğer bir tablonun binlerce satır gezdiğini görüyorsanız ve subquery yapılabiliyorsa direk select'e bunu alın...

Birde şimdi bakın hızına...

Büyük joinlerle yazdığınız SQL'ler sonrasında ORDER BY ile sıraya koyuluyorsa veya GROUP BY ile müdahale ediliyorsa bu müdahele öncesi bir joini tablodan çıkarmak akıllıca olacaktır...

Not: Asla unutmamak gerek ki bir durumda doğru olan bir şey her durumda doğru olmayabilir.
O yüzden diyoruz ki EXPLAIN kullanın.

Not2: Testler öncesinde şu komutları çalıştırmayı unutmayın, aynı zamanda test edilen iki query aynı anda çalıştırılmalı. Birini çalıştırıp daha sonra diğerini çalıştırmak büyük hata olacaktır.


SET GLOBAL query_cache_size = 0;
SET GLOBAL query_cache_type=0;

Not3: DISTINCT ile GROUP BY arasındaki fark GROUP BY'ın aynı zamanda ORDER BY özelliğinin bulunmasıdır. Ona göre bu komutları kullanın.

28 Mayıs 2012 Pazartesi

Git notlarım

Bunlar sadece çok kullandığımız komutların notları. Zaman zaman güncellenecektir.

git reset --hard origin/branch-name
local branch’i origin deki ile aynı duruma getirmek için kullanılıyor.
git reset --hard hash ile geri çektik
git push origin +master:master çekilen yere ana depo eşitlendi.

git push origin branch-name yeni dal uzakta oluşturma
git push origin :branch-name  remote depo silme

git branch -a bütün depoları göster
git branch -r uzak depoları göster
git branch -l local depoları göster

git branch -m old-branch-name new-branch-name  branch adı değiştirme

git push origin branch-name  kendi kullanıcıma bağlı olan yerde dal açma

git remote add uzakdepo /home/username/myrepo uzak depo bağlama
Böylece uzakdepo benim için anahtar kelime oluyor

Belirli bir loga dönmek için
git reset --hard (hash)d6422a1266c4199cf772d960a172b7aceca66e3b

git reset --hard origin/master locali origine eşitlemek için


Bir dosyayı herhangi bir dala geri alma;
git checkout hash  filePath
Stage de iken git checkout -- filePath


uzaktaki dalı localde oluşturmak için
git checkout -b BRANCH-NAME origin/BRANCH-NAME
git checkout -b BRANCH-NAME BRANCH-NAME
İki türlüde oluyor. Uzaktaki dalı sizin için çekiyor.

git fetch ile locale merge edilebilecek veya erişilebilecek dallar veya dosyalar çekilir
git pull ile hem fetch işlemi hemde merge işlemi yapılır

git diff branch-name bulunduğunuz branch ile yazdığınız branch arasındaki farkı gösterir
git diff branch-name > diff.patch göstereceği şeyi dosyaya yazar

Sadece git değil svn üzerinden aldığınız patchleride uygulayabilirsiniz.

Diff alma ve patch'e yazma
git diff > ../diff.patch
git diff BRANCH-NAME > ../diff.patch


Branch birleştirme
git merge BRANCH-NAME
Çakışma varsa
git mergetool

branchi hangi daldan oluşturduğunu bulma
git reflog show --all | grep -i "branch:" | grep -i created | grep -i BRANCH-ADI


comit edilmemiş dosyayı silme:
Önce fiziksel silme “rm file” sonra “git rm file”   git add -u incele

for x in `git status | grep deleted | awk '{print $3}'`; do echo $x; done;
Statusu deleted olanları ekrana basma.

İki commit arasındaki farkları alma;
git log ile yapılan commitlerin hashi bulunur.
git diff hash1 hash2 şeklinde fark görüntülenir.

Alınan diff'i kontrol etme
git apply --check diff.patch


Alınan diff ile nelerin değiştiğini görme
git apply --stat diff.patch


Uygulama
git apply diff.patch

Diff olayı derin mevzu şurası iyi bir kaynak : http://learn.github.com/p/diff.html

Git commit lerini birleştirme; git commit -m 'mesaj' . ile çok sayıda commit yapıp sonra bunları teke çekmek isteyebilirsiniz. komut: git rebase -i HEAD~3 Burda 3 commit sayısı siz commit sayınızı yazacaksınız. vim açılacak; pick 73a45d3 mesaj1 pick b5f70f9 mesaj2 pick a2c63a4 mesaj3 sondan iki "pick" i "f" yapıyoruz; pick 73a45d3 mesaj1 f b5f70f9 mesaj2 f a2c63a4 mesaj3 :wq! işlem tamam. git log ile kontrol edebilirsiniz . daha fazla durum için açılan pencereden detaylar var oraya bakabilirsiniz. Çalıştığınız branch'e origin(master) den güncelleme almak. Sorun şöyle çıkıyor, bir branch de çalışıp push ettiniz front-end aldı bişeyler yaptı push etti. Locali son duruma getirmek için komut ; git pull --rebase origin BRANCH-NAME

Sürekli kullanıcı adı veya Şifre sorulması
Projenizde çalışırken bu sorunu yaşıyorsanız https şeklinde url set edilmiş demektir.
Şöyle değiştirebilirsiniz.
git remote set-url origin git@github.com:kullanici/proje.git
Tüm değerleri görmek içi: git config --list

Yapılan commiti geri alma
git reset --soft HEAD^

Uzak depo ekleme
git remote add zf2 https://github.com/zendframework/zf2.git
Depoyu çekme
git fetch zf2
Depoyu master ile birleştirme (çek birleştir)
git pull zf2 master
Kimi zaman birleştirme yerine araya girme yapılmalı, sizin branch geride kalmış olabilir.
git rebase zf2
Yaptıklarımızı gönderme
git push origin

Bulunduğunuz branch için güncelleme geldiğinde onu kolayca almak
git checkout zf2
git pull --rebase

Önce zf2 branchine geçtik, bu başka bir branchde olabilirdi.
Sonra yeni neler var diye baktık.
Son olarak zf2 için gelen yeni kodları ilgili branche aldık.

Değişiklikleri kaydet ve dalın içini değişim öncesi hale getir.
git stash save
Kaydettiğin değişiklikleri geri getir.
git stash pop

Hayat kurtarır (projeyi git te olmayan herşeyden temizler...)
git clean -d -f -x


Local branch silme
git branch -D ISSUE-NO
Uzak branch silme
git push origin :ISSUE-NO

26 Mayıs 2012 Cumartesi

MySQL'de sayfalama yaparken dikkat edilecekler...



Herşeyin normal olduğu bir dünyada sayfalama yaparken datanın istenilen kısmını göstermek için MySQL'de "LIMIT" kullanılır.


LIMIT 0,2 veya LIMIT 2 dediğim zaman bana ilk iki datayı getirir. LIMIT 2,2 dediğimde ise ilk iki datadan sonra gelen 2 datayı getirir. Bu şekilde biz sayfalama yapıp tablolardan ihtiyacımız olan kadar datayı çekip gösteriyoruz.  Tabi bunu hesaplayabilmek için başlangıçta "toplam" datayıda bilmek gerek.
Bunun için MySQL'de kullanılan yöntem ;

"SELECT SQL_CALC_FOUND_ROWS * FROM test LIMIT 1"
"SELECT FOUND_ROWS()"



SQL_CALC_FOUND_ROWS anahtar kelimesi ile aslında toplam satır sayını hesapladık. Böylece aynı oturumda
"SELECT FOUND_ROWS()" kullanıldığında bize anında toplam data sayısını veriyor.

Ama burda şöyle bir durum var ana sorgumuzda kullandığımız "LIMIT 1" ile toplamda 1 satır dönsede aslında toplam satır sayısını hesaplıyor. Çünkü biz ona bunu yapmasını SQL_CALC_FOUND_ROWS anahtar kelimesi ile söyledik.

Normal olmayan durumlar ise joinler ile yaptığınız içinde WHERE/ORDER olan ve büyük datası olan tablonun böyle bir hesaplama durumunda oldukça uzun sürmesi. Bu durumda SQL_CALC_FOUND_ROWS'u kaldırıp hesaplamayı
"SELECT count(*) FROM test " ile daha hızlı bir şekilde yapabiliriz.

Burdan çıkartılacak ders, bir anahtar kelime/çözüm bir yerde iyi çalışıyorsa her yerde iyi çalışacak diye bir şeyin olmadığı gerçeğidir. Her durum için ayrı çözümler üretmek gerkebileceği için tasarladığımız sistemleri bu durumları düşünerek tasarlamız gerekmektedir...

Bu bilgilere ek olarak tablolarınızda "ORDER BY x" kullanırken dikkatli olmalısınız. Eğer INDEX'i olmayan bir field'a göre sıralama yapmak istiyorsanız işiniz bir hayli zor olacaktır. Konuyla ilgili detaylı bilgi almak için içinde çok datası olan tabloları EXPLAIN komutu ile sorgunuzu index'i olmayan ve index'i olan field lar ile sıralayıp bir alıştırma yapınız :)

Aynı şey "WHERE" içinde geçerli INDEX'i olmayan ve koşula giren bir "field" çoğu zaman yavaşlama yapabilir ama bazen etkisizde olabilir. Test etmenizde fayda var.

Konuyla ilgili şu linkler ilginizi çekebilir;

http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/
http://stackoverflow.com/questions/186588/which-is-fastest-select-sql-calc-found-rows-from-table-or-select-count
http://stackoverflow.com/questions/818567/mysql-pagination-without-double-querying
http://www.xarg.org/2011/10/optimized-pagination-using-mysql/
http://forge.mysql.com/wiki/Top10SQLPerformanceTips

27 Nisan 2012 Cuma

Bug Böceği

Not: Başlık biraz garip farkındayım :)

Geçengün bir issue geldi bu issueda verilen bilgiler "new relic"'e düşen php hata mesajlarından ibaretti.
Hata "Solr Error 0, HTTP Code 400 url( http://localhost:8080/select****" şeklinde oldukça uzun bir query çıktısını vermiş. Ama bu çıktı yarım gibiydi. Sanki oluşturulan Url fazla uzun olduğu için kesilmiş ve o kesik haliyle tomcat/jetty'e gönderilmiş gibiydi.

Url: /***** gibi çok uzun bir url vardı.

İlk iş olarak url yi kendi tarayıcıma yazıp aynı hatayı tekrar etmek istedim.
Aldığım mesaj:

Forbidden

You don't have permission to access /****

oldu.

Konuyu araştırınca apache mod_rewrite ($1 gibi...) her bir parametrenin maksiumum 255 karakter alabileceğini öğrendim. Bu sebeple nginx kurup php yi de fast-cgi olarak kurdum  (

brew tap josegonzalez/homebrew-php
brew install php --without-apache --with-mysql --with-cgi
brew install nginx
)

Bu kez hatayı tam olarak gördüm özeti şu şekilde;

1. Solr için üretilen sorgu new relic'in gösterdiğinden çok daha büyükmüş.
2. Url aslında kesik değil tam olarak gönderilmiş.
3. Solr'ın gerçek isteği elimize geçtiği için doğrudan sunucuda

GET 'http://localhost:8080(select/***' şeklinde sorgulama yapıp şu sonucu görüp sorunu tesbit ettiğimiz için mutlu oluyoruz :)


400 Bad Request
Connection: close

Bu sorunun çözümü için tomcat de maksimum url uzunluğunu belirlemek gerekiyor. Bunun için aşağıdaki komutu:  

 

 kullanıyoruz. Detaylar.

jetty için ;

      
          
    65536
          
      

         
     

Buda böyle ilginç bir hikayedir...

Önemli Ek 1: (28/05/2012)
HTTP Code 400 hatası alıyorsanız muhtemel sebepler;
1. Solr'a giden sorgu kaldırabileceğinden çok uzun olabilir.
2. Sorguda giden field lardan biri Solr üzerinde bulunmuyor olabilir. (schema.xml de yapılan güncelleme test yapılan yerde olmayabilir, solr yeniden çalıştırılmamış olabilir)
3. Solr'a giden datada Türkçe karakter sorunu olabilir. Bunu genelde IE yapıyor.