20 Ocak 2018 Cumartesi

@Transactional Servise Mockito ile Mock Servis Enjekte Etme


Merhabalar. Bu yazımızda Java projelerimizde kullandığımız Mockito kütüphanesi ile, @Transactional anotasyonuna sahip bir servise mock servis enjekte edememe probleminden ve çözümünden bahsedeceğiz.
Öncelikle, neden mock (yapay, sahte) servis kullanıldığından bahsedelim. Unit test yazarken testin gerçekten unit olması için test ettiğiniz kod parçasının başka kodlara bağımlılığının olmaması gerekmektedir. Örneğin, sipariş toplam ücretini hesaplayan bir servis düşünelim. Ham ücrete eklenen vergi miktarını başka bir servisten hesaplatıp kullandığını düşünelim. Sipariş ücretini hesaplayan metodu sağlıklı test edebilmek için, vergiyi hesaplayan metoddan hatalı sonuç dönmeyeceğinden emin olmalıyız. Bu nedenle vergi hesaplayan metodun orjinal kodunu çalıştırmadan, doğrudan istediğimiz sonucu dönmesi için vergi servisini "mocklarız".

Mockito çatısını kullanırken bu işlemi @Mock anotasyonu ile yaparız. Test ettiğimiz servisin içindeki bir servise mock sevisimizi enjekte etmek için @InjectMocks anotasyonunu kullanırız. Yalnız, inject edilen servis @Transactional anotasyonuna sahip ise, enjekte işlemi gerçekleşmiyor. Çünkü, transactional servis, java proxy nesneye dönüştürüldüğü için, Mockito enjekte edecek sınıf elemanı bulamıyor. Bu problemi aşmak için, mock servisleri hazırladığımız sırada, ReflectionTestUtils kullanarak manuel olarak servisi enjekte ederek aşabiliriz.

Aşağıdaki kodlarla daha anlaşılır olacaktır.
"admin" kullanıcı adını dönen UserService.
UserService'den dönen kullanıcı adını customerName olarak dönen CustomerService.
UserService sınıfının getUserName metodunu mock user name dönmesini istememize rağmen, CustomerService @Transactional olduğundan içindeki UserService mocklanamadığı için test başarısız olmaktadır.
CustomerService içindeki UserService ReflectionTestUtils ile mocklandığı için, test başarılı sonuçlanmaktadır.

3 Ocak 2018 Çarşamba

Kötü Kod Alametleri - 2

Kodumdan Kötü Kokular Geldiğini Nasıl Anlarım? adlı yazımızda giriş yaptığımız kötü kod alametlerine devam edelim.


İsimden Bekleneni Yapmayan Metod

Örneğin,  isim ve soyisim parametresi alan bir Person sınıfı düşünelim. 

Person person = new Person("Ali", "Velioğlu");

Ben person nesnesinden ismi almak istediğimde kullanacağım metod 

String name = person.getName();

metodudur ve "Ali" dönmesini beklerim. Fakat metod bana "Ali Velioğlu" dönüyorsa, burada geliştiriciye çok can sıkıcı bir sürpriz hazırlanmış demektir. Sürprizlerden kaçınma ve bekleneni yapma prensibini benimsersek muhtemel onca hatayı daha oluşmadan engellemiş olacağız. (Based on a true story)

Mükerrer Kod (Dublikasyon)


Belki de en yaygın yapılan kod hatası budur. Zaman baskısı ve kolayımıza geldiği için hepimiz bu muhteşem COPY - PASTE kombinasyonunu kullanırız. Ancak bunun da bir maliyeti vardır. Hemen kopyalamak yerine, biraz daha efor sarfedip soyutlamaya ve ortaklamaya çalışmalıyız. Aynı kod satırlarının geçtiği yerler ortak bir metoda, hatta gerekiyorsa yeni bir sınıfa taşınabilir.

 Aşırı Yüklenmiş Sınıflar

 Örneğin, Long id değeri taşıması beklenen bir IdDto sınıfımız olsun.

public class IdDto {
private Long id;
 //getters & setters
}

Bu kadar basit. Bu sınıfın tek görevi id taşımak olmalı. Bu sınıfın kullanıldığı yerde name değerinin de taşınması ihtiyacı doğduğunu varsayalım. Üşengeç bir geliştirici gelip, IdDto sınıfı içerisine String name alanını eklerse bu sınıf aşırı yüklenmiş bir sınıf halini alacaktır. İsminin çağrıştırdığından fazla iş yapıyor olacaktır. Kırık camlar teorisine göre, diğer geliştiriciler doğacak yeni ihtiyaçlarda yine bu sınıfı şişirmeye devam edecektir. Aşırı yüklenen bu sınıf kodu daha kırılgan hale getirecek ve sonuçta tahmin edilemeyecek yeni hataların oluşmasına neden olacaktır. Çözüm ise, sınıf ismine saygı duyulmalı, kendisinden beklenmeyen yeni işler yüklenmemelidir. Yüklenecekse sınıf ismi terfi ettirilerek daha anlamlı hale getirilmelidir. (Based on a true story).

Ölü Kod

Program akışı içinde çalışması imkansız olan kodlara ölü kod diyoruz. Örneğin, her zaman false değer alan bir if içindeki kod ölü koddur. Ölü kodlar ihmal edilirlerse zombi yaşamlarına uzun süre devam edebilirler. Ve bu zombi kodlar bir süre sonra tasarım değişikliklerine ayak uyduramaz ve ayak bağı olurlar. Yapılması gereken en kısa sürede vedalaşıp koddan temizlemektir.  
 

Dikey Boşluk

Yerel değişkenler kullanıldıkları yere en yakın yerde tanımlanmalıdırlar. Bir değişken tanımını bulmak için sayfalarca yukarı scroll etmemeliyiz. Aynı şekilde, private metodlar da kullanılan metodun hemen altına tanımlanmalı ve içeriğine bakmak istediğimizde az bir aşağı scroll ile görebilmeliyiz.

Proje Gelenek Göreneklerine Saygısızlık


Her projenin takım içinde belirlenmiş  kod gelenekleri vardır. Örneğin, Enum değerleri büyük harlerle yazılmalı, Entity sınıflarının ismi Entity ile bitmeli, Servis sınıflarının interfaceleri Service ile implementasyonları ServiceImpl ile bitmeli gibi. Bu geleneklere uymadan yazılmış her kod, takım arkadaşınıza yaptığınız kötü bir sürpriz anlamına gelmektedir. Sürprizlerden kaçınmamız gerektiğinden bahsetmiştik. Api projesinde tanımlanması öngörülen bir interface'i başka yerde tanımlarsanız, onu olması gereken yerde göremeyen takım arkadaşınıza özür borçlu olduğunuzu unutmayın.

 

Yeterince Test Edilmemiş Kod

Yazdığımız testlerin kodumuzun yüzde kaçını kapsadığını bilmeliyiz. Bunun için test coverage araçlarını kullanabiliriz. Örneğin, Eclipse için EclEmma kullanılabilir. Bu araçlar, yazdığımız testlerin, kodun nerelerini çalıştırdığını, hangi değişik şartları test ettiğini, hangi şartların test edilmesi gerektiğini bize raporluyorlar. Test coverage takibini günlük kod geliştirme faaliyetimizin bir parçası haline getirmemiz, projenin sağlığına oldukça fayda sağlayacaktır.







9 Aralık 2017 Cumartesi

Statik Kod Analizi ve SonarQube

Merhabalar. Önceki yazılarımızda "clean code" mevzusundan çokça bahsettik. Peki clean code pratiklerini nasıl öğreneceğiz? Kodumuzun ne kadar clean olduğunu nereden bileceğiz? Her zaman yanımızda kodumuzu inceleyip yol gösterecek, tenkit edecek bir üstad bulabilecek miyiz? Bu yazımızda bu sorulara cevap arayacağız.

Statik Kod Analizi

Yazılan kodların, önceden belirlenmiş kalite kriterlerine uyup uymadığını kodları çalıştırmadan analiz etmek şeklinde tanımlayabiliriz.
  • Hatalı kodların bulunması, 
  • Test edilmemiş kodların belirlenmesi, 
  • Tekrar eden kod bloklarının tespit edilmesi, 
  • Güvenlik açığına sebep olabilecek kodların yakalanması
  • Kötü kokan kodların raporlanması
bu analiz sonucu gerçekleşebilmektedir. Statik kod analizi, yazılım araçlarıyla otomatize edilebilmektedir. İnsanlar tarafından gözle yapılan analize kod gözden geçirme (code review,  code inspection) denilmektedir. Statik kod analizi, kod gözden geçirmenin yerini tutmasa da, birçok hatanın daha kod gözden geçirmeye gitmeden bulunmasını ve düzeltilmesini sağlamaktadır.

SonarQube

 

Statik kod analiz araçlarından günümüzde en popülerlerinde SonarQube'den bahsedelim. Standart statik kod analizi raporlarının yanında;
  • 20'den fazla programlama dilini analiz edebilmesi
  • Kendi kurallarınızı tanımlamaya izin vermesi
  • Sürekli entegrasyon araçlarıyla entegre çalışabilmesi
  • Tahmini teknik borç (technical debt) süresini raporlayabilmesi
gibi özellikleri sayesinde kaliteli yazılım geliştirme süreçlerinin vazgeçilmezi olmaya doğru gidiyor.

Bir Eğitimci Olarak SonarQube

SonarQube analiz raporları, raporlanan her hatada, çiğnenen kuralla ilgili detay bilgileri örnekleriyle birlikte sunmasından dolayı tecrübesiz yazılım geliştiriciler için birer eğitim materyali niteliği taşıyor.

Usta Bir Çift Göz

Ayrıca geliştiricinin kolayca gözünden kaçan kodsal hataları bulup gözünüze soktuğunda, kendisine duyduğunuz minnettarlığı dile dökmekte zorlanabiliyorsunuz. 7 / 24 gözü kodunuzda olan üstad bir yazılımcıyı her zaman yanınızda bulamayabilirsiniz. SonarQube sizde bu hissi uyandırabiliyor.


Sürekli Entegrasyonda Statik Kod Analizinin Yeri

Statik kod analizini sürekli entegrasyon sürecinin bir parçası haline getirerek projenizin kalitesine büyük katkı sağlayabilirsiniz. Her gün akşam üretilecek kod analiz raporlarıyla geliştiriciler yazdıkları koddaki hataları en kısa sürede farkedip düzeltme imkanı bulabilecekler. Yeterince çılgın geliştiriciler her committe statik kod analizi yaptırıp anlık olarak kodlarının kalitesini takip etmek isteyebilirler. Kod kalitesini sayısal metriklerle ölçülebilir hale getirdiğinden, süreç içerisinde kodun iyiye mi yoksa kötüye mi gittiğini tespit edebilirsiniz.

Sonuç olarak, evde geliştirdiğiniz hobi projelerden, dev kurumsal projelere kadar heryerde kullanabileceğiniz SonarQube ile projelerinizin daha az bug'lı, temiz geliştirilmesini sağlayabilir, her yeni hatada yeni birşeyler öğrenme imkanı bulabilirsiniz.




21 Ekim 2017 Cumartesi

Raspberry'de Python ile Tesseract OCR Kullanarak Plaka Okuma

OCR (Optical Character Recognition - Optik Karakter Tanıma),  bize grafiksel dosyalardaki yazıları yakalama imkanı veren teknolojidir. Örneğin, kameraya yakalanan kırmızı ışıkta geçen araçların plakaları bu teknoloji ile tespit edilebilmektedir. Bu yazımızda Raspberry Pi 3 cihazımıza tesseract-ocr programını kurarak, Python ile etkileşime geçip, örnek bir resim dosyasındaki plakayı okuyacağız.

Tesseract komut satırından kullanılabilen OCR aracıdır. Paket yöneticimizi güncelleyerek tesseract-ocr paketini yükleyelim.

sudo apt-get update



sudo apt-get install tesseract-ocr



Doğru kurulduğundan emin olmak için şu komutu çalıştırabiliriz.

tesseract -v


Şimdi örnek bir plaka resmi indirip tesseract programını komut satırından deneyelim. Aşağıdaki dosyayı plaka.jpg olarak kaydedelim.


Komut satırından tesseract programını örnek dosyamızı parametre vererek çağıralım. Sonucu komut satırına basması için stdout parametresini ekleyelim.

tesseract plaka.jpg stdout


Aslında baştaki TR kısmını okumaması işimize gelse de işimizi şansa bırakmamalıyız. tesseract'a resimleri vermeden önce image processing tekniklerini kullanarak işlemden geçirip, okunması gereken yazıyı daha belirgin hale getirmemiz gerektiğini not olarak düşelim.

Şimdi de Python ile tesseract'a resim okutalım. Resim işlemleri için Pillow, tesseract ile etkileşime geçmek için pytesseract kütüphanesini kurmamız gerekmektedir.

sudo pip install pillow
sudo pip install pytesseract


"plaka.jpg" isimli dosyayı okuyup içerisindeki yazıyı ekrana basan aşağıdaki Python kodunu "simple_ocr_plaka.py" isimli bir dosyaya kaydedelim.


Kodu çalıştırıp çıktısına bakalım:

python simple_ocr_plaka.py


Böylece, OCR teknolojisine temel bir giriş yapmış olduk. Gerçek hayat senaryolarında okunacak görüntü dosyaları bu kadar açık net ve basit olmayacaktır. Başarılı sonuç alabilmek için OpenCV kütüphanesi kullanarak, araçların plakaları tespit edilip, netlik ayarlamaları yapılmalı, görüntüdeki pürüzler giderilmelidir.





7 Ekim 2017 Cumartesi

GeoJSON ile Daire ve Yay Çizme

GeoJSON, çeşitli coğrafik şekilleri tanımlamaya yarayan JSON tabanlı bir standarttır. Standardı detaylı incelediğimizde, tanımlı şekiller arasında dairenin bulunmadığını görüyoruz. Peki, dairesel çizim ihtiyacını nasıl karşılayabiliriz? 
Bu yazımızda, yeni geliştirdiğimiz ultimate-geojson java kütüphanesini kullanarak nasıl dairesel çizim elde edilebileceği konusu üzerinde duracağız. 

Biraz Matematik

Bir düzlemde bir noktaya eşit uzaklıktaki sonsuz noktalar kümesine çember diyoruz. Bu çemberin içinde kalan alana da daire diyoruz. Sonsuz noktayı hesaplamak ve tutmak şu anki teknolojide pek mümkün olmadığından, çember üzerinde kabul edilebilir çoklukta nokta bularak mükemmel olmasa da dairesel çizimler elde etmek mümkün olmaktadır.
İhtiyacımız olan, merkez noktası olarak aldığımız bir koordinatın, belirli bir yarıçap mesafe uzaklıktaki noktasının koordinatını bulmak. Bunu 360 farklı açı için tekrarlarsak, bulduğumuz 360 nokta ile bir daire temsil eder hale gelebiliriz.
Dünya yüzeyi düz olmadığından alışılageldik trigonometrik hesaplamalar, merkez noktaya yarıçap kadar uzaklıktaki koordinatları bulmakta yetersiz kalmaktadır. Bunun için kütüphanemizde şuradaki dünyanın küreselliğini dikkate alan formülü kullandık.

Pasta Dilimini Nasıl Yapacağız?

Taramak istediğimiz açı aralığını belirledikten sonra, sadece o aralıkta kalan noktaları bularak, yay çizimini elde edebiliriz. 

Show me the code!

ultimate-geojson kütüphanesi kullanarak, hesaplamalara elinizi bulaştırmadan dairesel çizim elde edebilirsiniz. 

CircularDrawingAlgorithmImpl circleDrawer = new CircularDrawingAlgorithmImpl();
List<PositionDto> circlePoints = circleDrawer.getCirclePositions(new PositionDto(35,38), 10000.0);
  
UltimateGeoJSONFactory factory = new UltimateGeoJSONFactory();
PolygonDto circleAsPolygon = factory.createPolygon(circlePoints);

String geoJSON = UltimateGeoJSONBuilder.getInstance().toGeoJSON(circleAsPolygon);
 Üretilen GeoJSON'ı herhangi bir GeoJSON viewer'da deneyebilirsiniz. (örneğin: http://geojson.io/
.

Yay çizimi de benzer bir şekilde, fakat yayın başlangıç ve bitiş açıları verilmek suretiyle çizilebilmektedir.
CircularDrawingAlgorithmImpl circleDrawer = new CircularDrawingAlgorithmImpl();
PositionDto center = new PositionDto(35,38);
List<PositionDto> arcPositions = circleDrawer.getArcPositions(center, 10000, 0, 45);
  
UltimateGeoJSONFactory factory = new UltimateGeoJSONFactory();
PolygonDto polygon = factory.createPolygon(arcPositions);
  
String geoJSON = UltimateGeoJSONBuilder.getInstance().toGeoJSON(polygon);


DEMO


23 Eylül 2017 Cumartesi

Kodumdan Kötü Kokular Geldiğini Nasıl Anlarım? - 1



Kötü kokuya burnumuz alışınca artık kokuyu farketmez oluruz. Kodlamada da durum farklı değil. Kötü kokan koda o kadar aşina olmuşuzdur ki, onun yanlış olduğunu bile fark edemeyebiliriz.
Clean Code notlarımıza devam ediyoruz. İşte kötü kokan kodu farketmemize yarayacak bazı ipuçları:

Yorumlar

  • Yersiz Bilgilendirme:
    • Kodun değişiklik geçmişi, en son kimin değiştirdiği gibi bilgiler versiyon takip sistemlerinde tutulmalıdır. Bu bilgileri kodda tutmak gereksiz yorum kirliliğine neden olmaktadır.
  • Eskimiş yorum:
    • Kod değiştirildikçe taşıdığı anlam değişir ve buna bağlı olarak yorumların da güncellenmesi gerekebilmektedir. Mevcut yorum artık yeni kod için anlamsızdır. Yanlış eskimiş yorumlar derleme hatasına yol açmadığı için çoğu yazılımcı yorumları güncellemeyi ihmal eder. 
  • Lüzumsuz Yorum:
    • Koddan apaçık şekilde anlaşılabilecek konuları yorum olarak eklememek gerekir. Yorumlar kodun söyleyemediği şeyleri söylemek için yazılmalıdır.
  • Yoruma alınmış kod bloğu:
    • Gereksiz kodları silmekten korkmayın. Tekrar yazabileceğinize güvenin. Aksi takdirde yoruma alınmış kod, birgün birinin işine yarayabileceği düşüncesiyle kimsenin silmeye cesaret edemeyeceği kirlilik olarak kaynak kodda bulunmaya devam eder.

Geliştirme Ortamı

  • Derlemenin birden fazla adımda gerçekleştirilebilmesi: 
    • Projeyi derlemeden önce yaptığınız adımları gözünüzün önüne getirin. properties dosyasında bir düzenleme, kullanılan üçüncü parti kütüphanelerde ekleme/çıkarma yapma, xml, java dosyalarında değişiklik yapma... Derleme işlemini basit bir kaç adımda gerçekleştiremiyorsanız geliştirme ortamınızı elden geçirme ihtiyacı var demektir. Kaynak kodu çektikten sonra basit bir derleme komutuyla proje derlenebilmelidir.
  • Testleri koşmanın birden fazla adımda gerçekleştirilebilmesi:
    • Testler de basit bir "run" komutuyla çalıştırılabilmelidir. Testleri çalıştırmanın basit, hızlı ve kolay olması gerekir. Aksi takdirde geliştiriciler test yazmaya ve koşmaya soğuyabilirler.

Fonksiyonlar

  • Çok fazla argüman alan fonksiyon:
    • Hiç argüman almayan fonksiyon en iyisidir. Sırasıyla bir, iki ve üç argüman alan fonksiyonlar gelir. Üçten fazla argüman alan fonksiyonlar tercih edilmemeli, gerekli refactoring yapılarak, argüman sınıfları oluşturularak bu kötü koku giderilebilir.
  • Output argümanı kullanmak:
    • Fonksiyon argümanları genelde input olarak anlaşılır. Output argüman kullanmak okuyucuyu yanlış yönlendirebilir. 
  • Flag argümanı kullanmak:
    • Boolean flag argüman alan fonksiyon kuvvetle muhtemel iki iş yapıyor demektir. Fonksiyonlar tek işten sorumlu olmalıdır.
  • Atıl fonksiyon barındırmak:
    • Hiç çağrılmamış, kullanılmayan fonksiyonlar silinmelidir. İhtiyaç duyulması halinde versiyon kontrol sistemindeki geçmişe bakarak tekrar yazılabilir.
Devam edecek...

24 Temmuz 2017 Pazartesi

Negatif Mutlak Değer Olur Mu?

Java'da mutlak değer metodunun negatif sayı dönebileceğini biliyor muydunuz?



Mesela random pozitif integer değer almaya çalışırken beklenmedik bir negatif sayı sistemi alt üst edebilir. Bu sorun sadece bir exception fırlatmakla kalmaz bazen milyon dolarlık zararlara da yol açabilir.

@Transactional Servise Mockito ile Mock Servis Enjekte Etme

Merhabalar. Bu yazımızda Java projelerimizde kullandığımız Mockito kütüphanesi ile, @Transactional anotasyonuna sahip bir servise mock ...