Vagrant 3 : Up ve Provisioning

Bu yazımızda Vagrant’ı nasıl ayağa kaldıracağımızı ve basit bir shell script ile ayağa kaldırdığımız makinemizi nasıl yapılandırdığımızı (provisioning) işleyeceğiz.

İlk olarak komut satırını açıp vagrant init diyoruz. Bu komut ile bulunduğumuz dizinde default bir Vagrantfile oluşturulacaktır. Default oluşturulan bu dosyanın içeriği sizi korkutmasın 🙂 Vagrant ile ilgili kullanılabilecek comment edilmiş ayar komutları bulunuyor.

Baştan bir sanal makina kurulumu yapmak yerine box’ları kullanabiliriz. Box’lar bir hızlı bir şekilde sanal makina klonlamak için kullanılan bir nevi base image şeklinde düşünebiliriz. Bu örnekte Ubuntu 12.04 LTS 32-bit box işletim sistemini kullanacağız. Eğer farklı bir işletim sistemi yüklemek istiyorsanız Atlas.Hashicorp adresinden kullanıma sunulan box’ları inceleyebilirsiniz.

Screen Shot 2015-09-27 at 20.37.11Komut satırından  vagrant box add hashicorp/precise32 komutunu çalıştırıyoruz. Bu komut eğer daha önceden bu box sisteminiz de yoksa bir kereliğine base box’ı download edecektir. Daha sonraki kullanımlarda var olanı kullanacaktır. Her kullanımda orjinal box’ı kullanmak yerine bu orjinal box’ın klonları kullanılacağı için orjinal box’ınız hiçbir şekilde değişikliğe uğramayacaktır.  Base box’ımızı yükledikten sonra Vagrantfile dosyamızı açıp config.vm.box = “hashicorp/precise32”  satırını ekliyoruz. Bu satır ile kullanacağımız box’ı belirtiyoruz.

Şimdi vagrant up komutunu çalıştırıp makinemizi ayağa kaldıralım. Ayağa kaldırdığımız bu makineye vagrant ssh komutu ile tam yetkili bir ssh bağlantısı kuralım. Download işlemini saymazsak full ssh bağlantı yapabildiğimiz bir sanal makineyi saniyeler içerisinde ayağa kaldırmış bulunduk. Dark magic 🙂

Her şey tamam ve güzel. Sanal makine içerisinde herhangi bir işlem yapmam gerektiğinde downloadterminal tabanlı text editoru mu kullanmak zorundayım? Gelişmiş text editorleri dururken terminal ile bu iş biraz daha zahmetli ve sıkıcı. Tam bu noktada imdadımıza sycned folders yetişiyor. synced folders ile herhangi bir dosyayı guest ve host makinelerimiz arasında senkronize edebiliriz. Bunun için guest makinamızda touch /vagrant/senkFile yazıp çalıştıyoruz. Bu komut ile Vagrant, host ve guest makinamızda senkFile adında bir dosya oluşturacaktır. Bu dosya guest ve host arasında senkronize edilecektir.

Son olarak basit bir shell script kullanarak sanal makinemizde Apache web sunucusunu ayağafb0b45015a kaldıralım. Bunun için apache.sh adında bir dosya oluşturup aşağıdaki scripti yazıyoruz içerisine.


#!/usr/bin/env bash

apt-get update
apt-get install -y apache2
if ! [ -L /var/www ]; then
rm -rf /var/www
ln -fs /vagrant /var/www
fi

Daha sonra Vagrantfile dosyamıza config.vm.provision :shell, path: “apache.sh”  satırını Screen Shot 2015-09-27 at 21.18.54ekliyoruz. Bu kod ile sanal makinemizi shell script ile provision edeceğimiz söylüyoruz ve script dosyamızın bulunduğu dizini belirtiyoruz.  vagrant reload –provision
komutu ile sanal makinemizi tekrar ayağa kaldıralım. Vagrant ssh yapıp wget 127.0.0.1 komutunu çalıştırıp web sunucumuza istek yapabiliriz. Ve yaptığımız bu istek sonucunda HTTP 200 responsunun geldiğini görürüz.

 

 

EOF

Kaynakça :

https://www.vagrantup.com/

 

Vagrant 2 – Kurulum ve Terminoloji

Vagrant’ın ne olduğu ve ne işe yaradığını bir önceki yazıda bahsetmiştik. Bu yazıda Vagrant’a kısa bir giriş yapacağız.

Vagrant Kurulumu

Vagrant kurulumu oldukça basit. Vagrant için herhangi bir sanal makina provider’ının sisteminizde yüklü olması gerekiyor.  Ücretsiz olduğundan dolayı VirtualBox kullanacağım 🙂 Aşağıdaki adreslerden uygulamarı indirebilirsiniz. Uygulamaları indirip next next ile basitçe yükleyebilirsiniz.virtualbox-logo
Download Vagrant
Download Oracle VM VirtualBox

Yükleme işlemi bittikten sonra Vagrant otomatik olarak kendisini bilgisayarınızın çevre değişkenlerine ekleyecektir. Bunun sayesinden herhangi bir değişiklik yapmadan komut satırınızda vagrat komutlarını çalıştırabilirsiniz.

Terminoloji 

Vagrant ekosisteminde  bazı terminoloji ve konseptlere değinmek gerekiyor.

Öncelikle host machine kendi fiziksel makinamız, guest machine ise makinamıza kurduğumuz sanal makinayi ifade eder.

Boxes  (Kutu)

vagrant_chillingBoxes, Vagrant’ın temel yapı taşıdır. Boxes, Vagrant ortamları için öntanımlı paket formatıdır. Bu paket formatı içerisinde basit işletim sistemi yüklemesi olabileceği gibi birden fazla uygulama yüklemesi de olabilir. Vagrant ortamlarımız bu box dediğimiz kutularda durur. Vagrant ile ayağa kaldırdığımız her bir ortam bir box’a denk gelir.

Base Boxes

Baştan başa bir sanal makina ayağa kaldırmak zahmetli ve sıkıcı bir iştir. Vagrant hızlı bir şekilde sanal makina oluşturmak için base box dediğimiz base image kullanır. Maven’daki  archetype mantığına denk gelir. Aslında box’ların özel bir biçimidir. Sanal bir makina oluşturmak için minimum gereksinimlerin tanımlandığı box’lardır. Örneğin, hızlı bir şekilde Ubuntu Server 14.04 LTS işletim sistemine sahip olan bir sanal bir makina ayağa kaldırmak için ubuntu/trusty64 base box’ını kullanırız. Box list adresinden mevcut box’ları inceleyebilirisiniz.

Providers

Sanallaştırma adına asıl işi yapan kısım burası. Vagrant herhangi bir sanallaştırma işlevi sağlamıyor. Bunun yerine sanallaştırma hizmeti sunan teknolojilerden yararlanır. Vagrant ekosisteminde sanallaştırma işlevi sunan teknolojiler Provider olarak isimlendirilir. VirtualBoxVMWareHyper-V bunlardan birkaçı. Vagrant için default provider VirtualBox’tır.

Provisioners

 

Provisioners ( yapılandırma araçları ) yüklenmiş olan sanal makinada  tanımladığımız taskları chef.puppet.ansibe.saltstack.fabricçalıştıran araçlardır. Sanal sunucuyu yapılandırma, gerekli yazılımların yüklenmesi, sanalmakinada bazı taskların koşturulması gibi işlemleri yapmak için kullanırlar. Vagrant ile Chef, Puppet veAnsible vs.. gibi provisoner araçlarını kullanılabilir. Ayrıca herhangi bir provisioner aracı kullanmadan daha zahmetli olan shell script‘i yapılandırma için kullanabilirsiniz.

Synced Folders

Sycned Folder sayesinde host makinamız ile guet makinamız arasında istediğimiz dosyaları senkronize edebiliriz. Bu sayede kodumuzu host makinamızda geliştirip build/test ve compile işlemlerini guest makinasında yapabiliyoruz.
VagrantChef1Son olarak Vagrantfile dosyasına değinelim. Vagrant ortamımız ile ilgili her türlü bilgi bu dosyada tutulur. Sanal makinenin nasıl konfigure edileceği, yapılandırma işlemleri gibi tanımlamalar bu dosya içerisinde yapılır. Ruby syntax’ına sahiptir. Tanımlamalar o kadar basit ve anlaşılır ki Ruby programlama dilini bilmeden de bu dosyayı istediğimiz şekilde yönetebiliriz. Her
bir box yani proje için bir adet Vagrantfile tanımlanır.

Vagrantfile platform bağımsızdır. Projenin Vagrantfile dosyasına sahip iseniz istediğiniz platformda sanal makinanınız ayağa kaldırabilirsiniz.

 

EOF

Kaynakça :

https://www.vagrantup.com/

 

 

 

Vagrant 1 – Nedir/Neden

Bu yazıda Vagrant teknolojisinin ne işe yaradığını ve ne için kullanmamız gerektiğini işleyeceğiz.

Yazılım projelerinin bağımlılıkları ve karmaşıklıkları her geçen gün artıyor. Bu durum çeşitli problemleri de beraberinde getiriyor. Problemlerin en önemlisi de geliştirme ortamı (work environment).

download


Problem 1:  Yeni başlayan geliştirici

Ekibe yeni dahil olan geliştirici arkadaş için  geliştirme ortamlarının kurulması tam bir işkence. Örneğin, daha önce çalıştığım kurumsal bir firmada geliştirme ortamının kurulumu yaklaşık 2 gün sürmüştü (!). Zaman/kaynak ve motivasyon israfı.

Uygulama kurulumu için bir setup script ya da bir dokümantasyon oluşturabilirsiniz. Fakat bu dosyaların sürekli güncel tutulması gerekir ki bu da bir yazılımcı için gerçekten çok can sıkıcı bir durumdur.

Problem 2: Yeni teknoloji

Her gün onlarca teknoloji araçları ortaya çıkıyor. Yazılımcı bazı durumlarda bu yeni teknolojiyi bilgisayarında test etmek ya da çalıştırmak ister. Fakat yeni deneyeceğimiz bu teknoloji bizim düzgün çalışan geliştirme ortamımızı olumsuz etkileyebilir. Nahoş bir durum.

Problem 3: Çoklu proje

Geliştirdiğimiz birden fazla uygulamayı birbirinden tamamen izole edilmiş bir şekilde ayağa kaldırıp birbiriyle haberleştirmek isteyebiliriz. İzole edilmiş diyorum çünkü uygulamaların local makinada kullandıkları kaynaklar çakışabilir.

Problem 4: … ama lokalimde çalışıyor

Çoğu yazılımcının meslek hayatında çok kere sarfettiği cümle. Yazılımcı olarak bir problemi çözmüş ve proda kodu göndermiş olalım. Bir süre sonra geliştirdiğimiz çözüm prod ortamında  çalışmayabilir. Bunun sebebi ortamların farklılıkları. Prod ile geliştirme ortamları çoğu durumda farklıdır. Ortamlar arasındaki farklılık, problemi doğru bir şekilde gözlemleyip uygun çözüm üretmemize engel olur çoğunlukla.

Yukarıdaki ortamlar üzerine bir kaç problemden bahsettik. Tüm bu problemleri Vagrant ile kolaylıkla çözebiliriz.

vagrant-are-you-still-develop-in-a-nonvirtual-environment-6-638Vagrant Nedir?

Vagrant ; taşınabilir, tek kullanımlık, yeniden üretilebilir ortamlar oluşturmamızı sağlayan,bunun için sanallaştırma (Virtualbox,VMWare vs..) teknolojisinden faydalanan bir sanal makina yöneticisidir.Kolaylıkla yapılandırma teknolojileriyle (Chef,Ansible) konfigure edilebilir.

Uygulamayı bir kere Vagrant’a geçirdikten sonra istediğimiz an, istediğimiz makinada geliştirme ortamımızı çok hızlı bir şekilde oluşturabiliriz. Ortam bağımlılıklarını izole eder. Her yazılımcı klonlanmış prod ortamında kod yazıyor gibi olacak 🙂

say-one-more-time-works-on-my-machine

 

Bir sonraki yazıda Vagrant kurulumu ve Vagrant ile basit bir geliştirme ortamının nasıl kurulacağını göreceğiz.

EOF

Kaynakça :

https://www.vagrantup.com/

Apache Spark Streaming : Örnek Uygulama

Bu yazımızda Spark Streaming ile TCP socketten datayı okuyup, okuduğumuz bu datayı map reduce fonksiyonları ile işleyeceğiz.

Programlama dili olarak Scala ve IDE olarak intellij kullanacağız.

Öncelikle Intellij üzerinden SBT-based Scala örneği oluşturmamız gerekiyor. Bunu için New Project diyip Scala kategorisinde bulunan SBT‘yi seçiyoruz.
scala-sbt-version

 

 

 

 

Next diyip projenin ismini ve sbt, scala versiyonlarını seçiyoruz. SBT versiyonunu 0.13.8, Scala versiyonunu 2.11.6 olarak seçiyoruz.

sbt-scala-version

SBT, Scala uygulamaları için bir build aracıdır. Java dünyasında Maven’a denk gelir.

 

 

Spark Streaming için gerekli olan jar bağımlılıkarını build.sbt dosyamıza ekliyoruz. Spark Streaming 1.3.1 versiyonu kullanacağız.

libraryDependencies ++= Seq(
"org.apache.spark" % "spark-core_2.10" % "1.3.1",
"org.apache.spark" % "spark-streaming_2.10" % "1.3.1"
)

Bütün bunları yaptıktan sonra artık scala ile spark streaming işlemleri yapabiliriz.

Öncelikle StreamingContex‘i tanımlamamız gerekiyor. Aşağıdaki kod ile batch aralığı 1 saniye olan ve 2 thread ile çalışan bir StreamingContext oluşturuyoruz. 2 thread ile oluşturmamızın sebebi Receiver. 1 thread Receiver için 1 thread ise datayı işlemek için.

Not  : Eğer Kafka, TCP socket, Flume gibi receiver tabanlı data kaynakları ile streaming işlemleri yapıyorsanız her zaman için thread sayisi > receiver sayisi olmalıdır. Aksi takdirde Spark datayı okuyacak fakat işlemeyecektir.

val conf = new SparkConf().setMaster("local[2]").setAppName("NetworkWordCount")
val ssc = new StreamingContext(conf, Seconds(1))

StreamingContext hazır. Artık DStream objesi oluşturup datayı data kaynağından okuyabiliriz.
localhost:9999 adresinden datayı okuyan DStream objemizi oluşturuyoruz.

val lines = ssc.socketTextStream("localhost", 9999, StorageLevel.MEMORY_AND_DISK_SER)

lines DStream’inde bulunan her bir kayıt data kaynağından gelen bir text’i içerir.

Şimdi her bir text’i boşluk karakteri üzerinden kelimelere bölmek istiyoruz. Bunun için flatMap operasyonunu lines DStream‘i üzerinde gerçekliyoruz. flatMap operasyonun sonucunda yeni bir DStream objesi oluşur. flatMap işlemi one-to-many DStream operasyonudur.

streaming-dstream-ops

val words = lines.flatMap(_.split(" "))

 

words DStream’i içerisinde bulunan kelimeleri saymak istiyoruz. Her kelimenin tekrar sayısını elde etmek istiyoruz. Bunun için öncelikle word DStream’i içerisindeki her bir kayıt için K, V şeklinde bir pair çifti oluşturmak için one-to-one bir operasyon olan map fonksiyonunu kullanıyoruz. Daha sonra reduceByKey fonksiyonu ile her bir kelimenin tekrar sayısını buluyoruz.


val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _)

Aşağıdaki print işlemi ile wordCount DStream‘i içerisinde bulunan her bir RDD‘nin 10 elemanını consol’a basıyoruz.

Şimdiye kadar data üzerinde ne tür operasyonlar yapılacağını tanımladık. Spark Streaming’i aşağıdaki kod ile çalışmaya hazır hale getiririz.

ssc.start() // İşlemlere başla

Spark Streaming ile nerden datayı okuyacağımızı ve data üzerinde ne tür operasyonları yapacağımızı belirledik. Uygulamayı run etmek için sağ tıklayıp run diyoruz. Spark Streaming artık datayı alıp işlemeye hazır. Data göndermek için localimizde NetCat server ayağa kaldırıyoruz. Bunun için terminalde aşağıdaki komutu çalıştırıyoruz.

nc -lk 9999

Komutu çalıştırdıktan sonra “merhaba sevgili dünya” yazıp entera basıyoruz. Bunun sonucunda Spark Streaming önce bu text’i okuyup, boşluk karakterine göre split edip, her bir kelimenin tekrar sayısını consola basacaktır. Intellij consolunda aşağıdaki gibi bir çıktı generate edilecektir.

——————————————-
Time: 1432489453000 ms
——————————————-
(dünya,1)
(merhaba,1)
(sevgili,1)

——————————————-
Time: 1432489454000 ms

Not : Unutmayalım ki tüm map reduce fonksiyonları DStream’de bulunan RDD’ler üzerine gerçeklenir.

Diyelim ki biz her seferinde her kelimenin toplam tekrar sayısını tutmak istiyoruz. Bu durumda Spark Streaming içerisinde kelimeye dair bir state tutmamız gerekiyor. Ve her gelen data üzerinden bu state‘in güncellenmesini istiyoruz. Bunu UpdateStateByKey operasyonu ile gerçekleyebiliriz. UpdateStateByKey için öncelikle state’yi tanımlayıp daha sonra bu state içine update fonksiyonu tanımlamamız gerekiyor.

Update fonksiyonumuz :

def updateFunction(newValues: Seq[Int], runningCount: Option[Int]): Option[Int] = {
val newCount = newValues.sum + runningCount.getOrElse(0)
Some(newCount)
}

Update fonksiyonumuz DStream üzerinde gerçekliyoruz.

wordCounts.updateStateByKey[Int](updateFunction _)

update fonksiyonu her bir kelime için çağrılacak ve kelimenin önceki sayısı yeni sayı ile toplanıp, kelimenin sayısı güncellenecektir.

Data üzerinde bir tane window operasyonu gerçekleyip örneğimizi sonlandıracağız. Spark Streaming windowed operasyonları desteler. Windowed operasyon bir zaman aralığı belirleyip RDD’leri birleştirip, bu birleşik RDD’ler üzerinde işlem yapmamızı sağlar. Bunu Türkçe dile getirmek biraz zor 🙂  Aşağıdaki şekil bir window operasyonunu gösteririr.
streaming-dstream-window

Window operasyonu için 2 parametreyi tanımlamamız gerekiyor.

1-) window lenght :  Her bir window’un süresi (Yukarıdaki şekilde bu 3tür)
2-) sliding interval :  Gerçeklenen window operasyonun aralığı (Yukarıdaki şekilde bu 2dir)

Diyelim ki bizim örneğimizde  her 2 saniyede bir gelen datanın son 10 saniyesini işlemek istiyoruz.

val windowedCount = wordCounts.reduceByKeyAndWindow((a:Int,b:Int) => (a + b), Seconds(10), Seconds(2))

Yukarıdaki kod ile her 2 saniyede bir DStream üzerindeki data’nın son 10 saniyesini okuyup işleriz.

Aşağıdaki adresten kaynak kodu indirebilirsiniz.

https://github.com/mstzn36/SparkStreamingTCPExample

EOF

 

 

 

Kaynakça :
https://spark.apache.org/docs/latest/streaming-programming-guide.html

Apache Spark Streaming Giriş

Bu yazımızda Apache Spark Streaming ne olduğunu ve işleyişini incelemeye çalışacağız.

Apache Spark Streaming Nedir ?

Spark Streaming, Apache Spark projesinin bir alt-projesidir. Apache Spark engine üzerinde çalışır ve gerçek zamanlı işlem (real-time processing) yapmamıza olanak sağlayan bir araçtır.

Not: Apache Spark, batch processing platformudur. Apache Hadoop’un alternatifidir diyebiliriz.

Spark Streaming ile olay bazlı, asenkron, ölçeklenebilir, tip güvenli ve hata tolerans’lı uygulamalar geliştirebiliriz. Farklı event stream’lerden(Kafka, Twitter, TCP socket) gelen gerçek zamanlı datayı kolaylıkla Spark Streaming‘e entegre edebiliriz. Gerçek zamanlı datayı yüksek seviye(high-level) fonksiyonlarla(map, reduce, join, window) işleyebilir ve işlenen datayı veritabanı, live dashboard ve file stream’lere yazabiliriz.

spark-in-out

Spark Streaming ile çeşitli alanlarda yüksek hacimli, ölçeklenebilir, güvenilir, güçlü uygulamalar geliştirebiliriz. Aşağıdaki gösterimde Spark Streaming’in bazı uygulama alanlarını görebiliriz.

streaming-use-cases

Apache Spark Streaming’in Çalışma Mantığı

Spark Streaming, event stream’lerdan aldığı live datayı mikro batchlere ayırır, bu mikro data batchler Spark Engine tarafından işlenir. Ve son olarak işlenen data yine mikro batchler olarak çıktıya yönlendirilir.

streaming-flow

Her bir data stream için bir tane DStream oluşturulur. Ham data DStream üzerinde tutulur. DStream‘i (Discretized Stream), mikro batch’lerin bir serisi gibi düşünebiliriz. Her bir mikro batch, RDD(Resilient Distributed Dataset) olarak ifade edilir. Her bir RDD, hata toleranslı bir element dizisi tutar. RDD, immutable, read-only ve paralel olarak işlenebilen objedir. Aşağıdaki şekilde de  görüleceği gibi bir RDDDStream üzerinde belli bir zaman aralığındaki datayı tutar.

streaming-dstream

DStream üzerinden yapılan her bir işlem(map, reduce, window) bu DStream altında bulunan RDD‘ler üzerinde yapılır. Aşağıdaki şekilde basit bir flatMap operasyonun gösterimi mevcuttur.

streaming-dstream-ops

Bir data kaynağından (Kafka, Twitter) ham datayı DStream ile okuruz. Bu tip DStream’ler input DStream olarak isimlendirilir. Her bir input DStream, bir Receiver ile ilişkilendirilir. Receiver, data kaynağından datayı alır ve daha sonra işlenebilmesi için Spark’ın hafızasında tutar.

Not : Data kaynağı file stream olan DStream’ler için Receiver kullanılmıyor.

Spark Streaming kavramları üzerinde biraz bilgi sahibi olduk. Sonraki yazımızda Spark Stream kullanarak TCP socket üzerinden datayı okuyup, bazı map reduce işlemleri yapacağız.

EOF

Kaynakça :
https://spark.apache.org/docs/latest/streaming-programming-guide.html#
http://planetcassandra.org/apache-spark-streaming/

Bölüm 3 : Arrays & ArrayBuffer

Bu bölümde Scala Arrays yapılarına kısa bir giriş yapacağız.

1-) Fixed-Length Arrays

Scala’da sabit uzunlukta array tanımlamak için Array tipini kullanırız.
val nums  = new Array[ Int ](10)
//10 adet integer tipinde eleman içeren bir array.Tüm elemanların değeri 0
val a = new Array[String](10)
//10 adet String tipinde eleman içeren bir array.Tüm elemanların değeri null
val s = Array("Eleman1","Eleman2")
//2 elemanlı array
s(0) = "ElemanYeni"

s array’nin elemanları Array(“ElemanYeni”,”Eleman2″) olur

Array’in elemanlarına erişmek için Java’daki [] yerine () karakterlerini kullanırız.

Önemli ! : Array tanımlarken elemanları ilk değerle tanımladığımız new operatörünü kullanmamıza gerek yok.

JVM,bir Scala Array tipini Java Array olarak işler.Örneğin, Scala’da bir Array[Int] aslında Java int[] olarak temsil edilir.Aynı zamanda Scala Array, Java’daki Array’den daha fazlasıdır.Mesela, Scala Array generic tanımlanabilir.T tip parametresi veya abstract tip olmak üzere Array[T] şeklinde bir array tanımlayabiliriz Scala’da.

2-) Variable-Length Arrays / Array Buffers

Java’da boyutu değişebilir array tanımlamak için ArrayList kullanırız.Scala’da ise aynı işlevi ArrayBuffer ile sağlarız.

import scala.collection.mutable.ArrayBuffer
val aBuffer = ArrayBuffer[Int]()
//Ya da new ArrayBuffer[Int].Int tipinde eleman almaya hazır boş array buffer
aBuffer += 1
// += ile eleman ekleyebiliyoruz
aBuffer += (1,2,3,5)
// () ile aynı anda birden fazla eleman ekleyebiliyoruz array'e
aBuffer ++= Array(8,13,21)
// ++= operatörü ile herhangi bir collection dizisini array buffer'a ekleyebiliyoruz
aBuffer.trimEnd(5)
//trimEnd fonksiyonu ile son 5 elemanı array buffer'dan çıkarabiliriz

Diyelim ki bir Array tanımlamak istiyoruz ama boyutunu ne olacağını kestiremiyoruz.Bu durumda önce ArrayBuffer oluşturup,elemanları ekleyip daha sonra bu buffer üzerinde toArray fonksiyonun çağırarak Array oluşturabiliriz.

3-) Traversing Arrays and Array Buffers

Scala’da array elemanları içerisinde gezinmek Java’ya nispeten çok daha kolaydır.

for( i<-0  until a.lenght)

until methodu RichInt class’ının bir methodur.

0 until 10 aslında 0.until(10) çağrımıdır.Ve bu çağrım 0’dan 9’a kadar değer döner gider.Fakat 10 değerini dönmez.

Eğer index’e ihtiyaç duymuyorsak aşağıdaki gibi array’i gezinebiliriz.

for( elem <-  a )

4-) Transforming Arrays

Bu bölüme kadar hemen hemen Java’da yapabildiğimiz array işlemlerini gördük.Bu alt başlıkta Scala’nın Java oranla array işlemlerini nasıl basitleştirdiğini göreceğiz.

val aBuffer = ArrayBuffer[Int](1,2,3)
val result = for(elem<-aBuffer) yield 2 * elem // result = ArrayBuffer(2,4,6) değerlerini içerir

yield fonksiyonu orjinal tip ve değerlerden oluşan yeni bir collection oluşturur.Daha sonra bu yeni array’in her bir değerini 2 ile çarpıp result değişkenine atanır.

Scala’da collection yapıları üzerinde map ve filter methodlarını kullanabilriz.Örneğinde yukarıdaki işlemi aşağıdaki gibi de gerçekleyebiliriz.

val test = aBuffer.map( _ * 2)

map ile _ karakteri ile aBuffer array’nin her elemanını 2 ile çarpar ve geriye yeni bir array dönderir.Ayrıca collection üzerinde filter methodu ile array’in elemanların filtreyebiliriz.

val test 2 =aBuffer.filter( _ % 2 ==0 )

aBuffer array’nin 2 ile bölünebilen elemanlarını bulur ve yeni bir array’e atar.

5-) Common Algorithms

Scala’da toplama ve sıralama işlemleri için built-in fonksiyonlar vardır.

Array(1,7,2,9).sum //19

Array’daki tüm değerleri toplar. sum methodunu kullanabilmek için eleman tipleri numeric olmalıdır. Benzer bir şekilde min ve max methodları ile collection içerisindeki en küçük ve en büyük elemanları elde edebiliriz.

ArrayBuffer("scala","çok","kullanışlıdır").max //"kullanışlıdır" değeri döner
sorted methodu ile bir array veya arraybuffer içerisindeki elemanları sıralayabiliriz.
val b = ArrayBuffer(1,7,2,9) val bSorted = b.sorted //b değişmedi.bSorted ise (1,2,7,9) olur
Eğer collection üzerinde özel bir sorting yapmak istiyorsak,sortWith methodunu kullanabiliriz. val bDescending= b.sortWith(_ > _) // ArrayBuffer(9,7,2,1)

Son olarak eğer bir array/arrayBuffer dizilerinin elemanları print etmek istiyorsak bunun için mkString methodunu kullanabiliriz.

b.mkString(" and ")
//"1 and 2 and 7 and 9"

Scala’da array ve array buffer üzerinden kullanabileceğiz bir sürü method bulunmakta.Bunların hepsini burada anlatmaya yerimiz yetmez.Aşağıdaki linkten bu methodları inceleyebilrsiniz.

http://www.scala-lang.org/api/2.11.5/index.html#scala.collection.mutable.ArrayOps

6-) Multidimensional Arrays

Scala’da çok boyutlu array tanımlamak için ofDim methodunu kullanabiliriz.

val matrix = Array.ofDim[Double](3,4)
//Double tipinde 3 satır ve 4 kolonlu bir array.

Array’in elemanlarına erişmek için veya değer atamak için parantez çiftlerini kullanabiliriz.

matrix(satır)(kolon) = 42

 

Yazdığımız kod örneklerini github üzerinden inceleyebilirsiniz.

https://github.com/mstzn36/scala-examples

 

EOF

Kaynakça
http://horstmann.com/scala/
http://www.scala-lang.org/api/2.11.5/index.html

Bölüm 2 : Kontrol Yapıları ve Fonksiyonlar

Bu bölümde condition,loop yapılarını ve fonksiyonları inceleyeceğiz.Ve incelemeyi mümkün olduğunca C++ ve Java dilleriyle karşılaştırarak yapacağız.

1- Conditional Expressions

Scala’daki if/else yapısı Java’daki ile aynıdır.Fakat Scala’daki if/else yapısının bir değeri vardır.Yani if/else geriye bir değer dönderiyor.

Önemli ! : Scala’da hemen hemen tüm yapıların bir değeri vardır.

val s = if (x  > 0 ) 10 else 20

Yukarıdaki if’in değeri x’in değerine göre 10 veya 20’dir.Yani s değişkeni 10 veya 20 olabilir.

Yukarıdaki kodu Java’da gerçeklemek için üçlü operatörü (?:) kullanırız.Scala üçlü operatöre ihtiyaç duymadan bu operatörün işlevini if/else ile gerçekleyebiliyor.

if/else yapısının bir dönüş değeri var dedik.Peki Scala bu dönüş değerinin tipini nasıl belirliyor ? Scala geri dönüş değerinin tipini her bir branchin dönderdiği değerin tipine bakarak anlıyor.İlk örneğimizde her iki branchte dönen değer Int olduğundan if/else‘nin dönerdiği değerin tipi Int olur.Fakat diyelim ki bir branch String bir branch ise Int dönderiyor.Bu durumda dönen değerin tipi her tipinde ortak super class’ı olan Any tipinde bir değer döner.

if(x > 0) “test” else 10         // Bu durumda bu if/else ‘nin geri dönüş değeri Any olur.

Şimdiye kadar ki if/else yapılarında her iki branchinde bir değeri vardı.Peki bir branch es geçilirse geri dönüş değeri ne olacak ? Yani else yapısı yazılmamış ise.Bu durumda geri dönüş değeri Unit olabilecektir.Örneğin

if(x > 0) 10     //  x, 0’dan büyükse if yapısının dönüş tipi Int olacaktır.Fakat eğer x, 0’dan
küçükse bu if yapısının dönüş tipi Unit olacaktır.

Unit, Java’daki void tipine denk geliyor.İkisi tam olarak aynı şey değil.Scala,Unit tipi ile bir değerin işe yarar bir bilgi taşımadığını belirtir.

Daha akılda kalması açısından şöyle düşünebiliriz.Void boş bir cüzdanı ifade ediyorsa,Unit cüzdanın içerisinde “para yok” diyen bir notu işaret eder 🙂

Scala’da switch yapısı yoktur.Buna ihtiyaç duyulmuyor.Sonraki yazılarda bunu işleyeceğiz.

2-Statement Termination

Java ve C++ dillerinde her kod satırı noktalı virgül ile bitmek zorundadır.Scala’da bu opsiyoneldir.İsteğe bağlı olarak kullanabilir veya kullanmayabilirsiniz.

Ben özellikle noktalı virgül kullanmamaya çalışıyorum.Eski dillerden kalma alışkanlıklarımızı devam ettirmenin bir manası yok 🙂

3- Input ve Output

Bir değeri konsola basmak için print veya println fonksiyonlarını kullanabilirsiniz.println fonksiyonu değeri bastıktan sonra bir sonraki satıra geçer.Java ile benzer.

readLine fonksiyonu ile consoldan bir değeri okuyabilirsiniz.Numeric,Boolean,character okumak için readInt,readDouble,readByte,readBoolean,readChar fonksiyonları kullanabilirsiniz.

4- Loops

Scala’da while yapısı Java’daki ile benzerdir.

while(x>0){
r =r * x
n-=1
}

Scala’daki for yapısı Java’dakinin gelişmişi olarak düşünebiliriz. for(ilk_deger,test,güncelle) yapısı bulunmuyor Scalada.Bu gerçeklemek içib ya while yapısı ya da aşağıdaki gibi bir for yapısı kullanabiliriz.

for( i  <-  1 to n)  // Scala
r = r + i

for(i = 1;i <= n; i++) // Java
r = r + i

1 to n, bir number aralığı döner. Örneğin , 1 to 5 demek kısaca (1,2,3,4,5) demektir.

for yapısı içerisinde birden fazla değişkeni noktalı virgül ile ayırarak kullanabilirsiniz.Örneğin;

for( i  <- 1 to 3; j <- 1 to 3 )  // Consola 11 12 13 21 22 23 31 32 33 değerlerini basar
print(10 * i + j + ” “)

Hatta for içerisinde condition bile kullanabiliyorsunuz.

for(i  <- 1 to 3; j <- 1 to 3 if i != j ) // Consola 12 13 21 23 31 32 değerlerini basar
print(10 * i + j + ” “)

if‘den önce noktalı virgül kullanmadığımıza dikkat edelim.

Scala for yapısı o kadar güçlüdür ki,bu yapı içerisinde döngü içerisinde kullanılmak üzere değişken tanımlayabilirsiniz.

for(i  <- 1 to 3; from = 4 -i ; j <- from to 3 )  // Consola 13 21 23 31 32 33 değerlerini basar
print(10 * i + j + ” “)

5- Functions

Scala’da methodlara ek olarak fonksiyon da tanımlayabiliriz.Bir method, object üzerinde işlem yapar.Java’da bir methodu static tanımlayarak fonksiyon gibi davranmasını sağlıyoruz.Scala’da ise def keyword‘u ile fonksiyonumuz basitçe tanımlayabiliyoruz.

Bir fonksiyon tanımlamak için,fonksiyonun ismini,parametrelerini ve içeriğini (body) belirtmemiz gerekiyor.

def abs (x : Double ) = if( x > 0) x else -x

Fonksiyonun tüm parametrelerinin tipini belirtmemiz gerekiyor.Fonksiyon recursive olmadığı sürece geri dönüş tipini belirtmemiz gerekmiyor.Scala geri dönüş tipini fonksiyonun içeriğinden anlıyor.Fonksiyonun değeri, fonksiyon içerisindeki son kod satırının değeridir.

Aşağıdaki fonksiyonun değeri,for bittikten sonraki r‘nin değeridir.

def fac(n: Int ) = {
var r = 1
for(i <- 1 to n)  r = r * i
}

Eğer recursive bir fonksiyon tanımlıyorsak mutlaka geri dönüş tipini Scala’ya söylememiz gerekiyor.Aksi takdirde compiler hata verecektir.

def fac(n: Int): Int = if( n <= 0) 1 else n *  fac(n-1)

Fonsiyon tanımlarken parametreler için default değerler tanımlayabiliyoruz.

def decorate(str : String, left : String = “[” ,right : String =”]”)=
left + str + right

left ve right parametleri default değerlere sahip.

Java’da bir foknsiyonu çağırırken parametrelerin fonksiyon tanımındaki gibi aynı sırada olması gerekiyor.Scala’da böyle bir zorunluluk yok.Örneğin yukarıdaki fonksiyonu aşağıdaki gibi çağırabiliriz.

decorate( left = “<>”, str = “hello”)     // Dikkat ederseniz fonksiyon tanımındaki parametre
sırasına göre fonksiyonu çağırmadık.

decorate( “Hello”,right = “<<<” )                // calls decorate(“Hello” , “[“, “<<<” )

Bazı durumlarda parametre olarak number of arguments alan bir fonksiyon tanımlamak isteriz.

def sum(args : Int*) = {
var result = 0
for( arg <- args ) result += arg
result
}

Yukarıdaki fonksiyonu aşağıdaki şekillerde çağırabiliriz.

val s = sum(1,2,3,4,5)

val s = sum(1 to 5:_*)

6- Procedures

Scala’da değeri olmayan fonksiyonlar için özel bir notasyon vardır.Eğer bir fonksiyon tanımında { parantezinden önce = karakteri kullanılmıyorsa bu fonksiyonun geri dönüş tipi Unit olur.Bu tip fonksiyonlar procedure olarak adlandırılır.Bir procedure fonksiyonun geri dönüş değeri yoktur.Örneğin aşağıdaki gibi string print etmek istiyoruz.

——-
|Hello|
——-

def box( s :  String  ) {                                                     // = karaktrerinin olmadığına dikkat edin.
val border = “-” * s.lenght + “–\n”
println(border + “|” + s + “|\n” + border)
}

def box(s : String) : Unit = {                            //Bu fonksiyon ve yukarıdaki fonksiyon eşdeğerdir.
val border = “-” * s.lenght + “–\n”
println(border + “|” + s + “|\n” + border)
}

7- Lazy Values

Bir val değişkeni lazy olarak işaretlenmiş ise bu değere erişilmediği sürece initialization yapılmaz.

lazy val words = scala.io.Source.fromFile(“/usr/share/words”).mkString

Uygulama, words değişkenine erişmediği sürece words initialize edilmez.

Diyelim ki bir ton değişken tanımının olduğu bir class’ınız var.Ve bazı değişkenler belki hiç kullanılmayacak uygulama içerisinde.Bu durumda ilk baştaki initialize maliyetini azaltmak için lazy değişkenler kullanabilirsiniz.

Lazy değişkenleri val ve def arasında bir yerde düşünebiliriz.

val words = scala.io.Source.fromFile(“/usr/share/words”).mkString
// Compiler words değişken tanımını gördüğü an işler

lazy val words = scala.io.Source.fromFile(“/usr/share/words”).mkString
// Compiler,words değişkeni ilk defa kullanıldığında işler

def words = scala.io.Source.fromFile(“/usr/share/words”).mkString
// Compiler,words değişkeni her kullanıldığında işler

8- Exceptions

Scala’daki exception işleme mantığı Java’daki gibidir.Aşağıdaki gibi bir exception fırlatıldığında,

throw new IllegalArgumentException(“x should not be negative”)

o anki işlemler durur,ve runtime system bir exception handler bekler.Eğer exception handler yoksa uygulama durur.

Scala’da checked exception yok.Bildiğimiz gibi checked exception‘lar compile time’da check edilir.Şöyle ki eğer bir method IOException fırlatıyorsa bu exception’u method tanımında tanımlamanız gerekiyor.

if( x >= 0 )  {  sqrt(x)
else throw new IllegalArgumentException(“x should not be negative”)

İlk branch’in tipi Double.İkinci brach’in tipi ise Nothing‘tir.

val in = new URL(“mesutozen.wordpress.com/test.gif”).openStream()
try {
process(in)
} catch {
case _ : MalformedURLException => println(“Exception occured”)
case ex: IOException => ex.printStackTrace()
} finally {
in.close
}

Java’da olduğu gibi daha spesifik hatalar genel hatalardan önce gelir,yakalanır.

Eğer hata değişkenine ihtiyacımız yok ise _ karakterini kullanabiliriz.

finally bloğu Java’daki gibidir.Hata alınsada alınmasa da finally bloğu çalışır.

 

EOF

Bölüm 1 : Scala Giriş

Nedir Bu Scala ?

Scala, hem nesne yönelimli hem de fonksiyonel programlama metodolojilerini içeren bir programlama dilidir.Scala’nın kendi derleyecisi olmasına rağmen Java Byte-Code üretebiliyor yani JVM üzerinde koşturabiliyorsunuz.Bu sayede java kütüphanelerini,framework’lerini,tool’larını rahatlıkla scala ile kullanabilirsiniz.

Scala ile kod yazarken java’nın boiler plate dediğimiz can sıkıcı işlerini yapmak zorunda kalmıyoruz.Bazı kısımlarda inanılmaz bir productivity sağlıyor.Geliştirme işini zevkli hale getirebiliyor.Tabi ilk başlarda eğer siz de benim gibi java gibi geleneksel dilleri kullanmışsanız zorlanıyor olacaksınız.Zamanla scala syntax’ına alıştıkça geliştirmenin java’ya göre daha hızlı ve zevkli olduğunu görürsünüz.Java da 10 satırda yapabildiğiniz işi scala ile bir satırda yapabiliyorsunuz.

Scalada kodunuzu hem compile hem de interpret edebiliyorsunuz.Scala’nın REPL (Read-Evaluate-Print Loop) dediğimiz bir yorumlayıcısı vardır.Teknik olarak REPL arka tarafta hızlı bir şekilde byte-code compile edip,byte-code’nin jvm tarafından execute edilmesidir.Bu geliştirciye, kodunu hızlıca çalıştırıp, hızlıca feedback almasına olanak sağlıyor.

Scala Yükleme

Scalayı bilgisayara yüklemek çok basit.

Windows için Install Scala For Windows kullanabilirsiniz.

Mac için

  • Mac için istediğiniz scala versiyonunu indirin.
  • İndirdiğiniz dosyayı bir dizine extract edin.
  • Aşağıdaki tanımlamları bash_profile dosyanıza ekleyin.
    export SCALA_HOME=/Users/mesutozen/Documents/scala-2.11.6
    export PATH=$PATH:$SCALA_HOME/bin
  • Komut satırından scala yazıp enter’a bastığınızda Welcome Scala yazısını gördüyseniz yükleme tamamdır
  • Scala Giriş

    Evet scala’yı install etmiş oldu.Şimdi biraz scala kodu çalıştıralım 🙂

    scala

    scala


    Solda kısaca 8 * 5 + 2 yazıp enter’a bastık.Ve scala, kodu interpret edip sonucu, tipi Int olan res0 değişkenine atayıp gösteriyor.Daha sonra bu değişkeni 0.2 ile çarptğımız da bunu Double değişkene atıyor,en son kısımda ise bir String ile birleştiriyoruz.Ve her seferinde scala işlemi yapıp uygun tipte bir değişkene atıyor.

    Dikkat ederseniz burada hiç bir tip tanımı yapmadık.Normal de java ile bunları yapabilmek için her seferinde type cast yapmamız gerekiyordu fakat scala bunu kendisi yapıyor.Bunu da değişkenlerin değerinden anlıyıp gerçekliyor.

    Screen Shot 2015-04-25 at 16.26.02
    Ayrca komut satırında res0. yapıp tab tuşuna bastığımızda scala bize bu değişken üzerinde çalıştırabileceğimiz methodların listesini veriyor.Değişken üzerinde methodu çağırdığımızda scala, ne yapıyor peki ? Scala interpreteri öncelikle expression’u read eder,daha sonra evaluate eder,sonra print eder ve sonraki expression’u read eder.İşte REPL dediğimiz yapı bu şekilde çalışıyor.

    Val ve Var Değişken Tanımlama

    Scalada kendi değişkenlerimizi aşağıdaki gibi val ve var kullanarak tanımlayabiliriz.

    Screen Shot 2015-04-25 at 17.05.36

    Değişken tanımlarken bu değişkenlerin tipini belirtmek zorunda değilsiniz.Scala,değişkene verdiğiniz ilk değerden değişkenin tipine karar veriyor.Bir değişkeni tanımlarken ilk değer ataması yapmadan tanımlayamazsınız.

    Scalada bir değişkeni val olarak tanımladığınızda bu değişkene daha sonra değer atayamazsınız.Yani bu sizin sabit’iniz(constant) oluyor.Javada bu final keyword’una denk geliyor.

    Bir değişkeni var olarak tanımladığınız da bu değişken üzerinden istediğiniz gibi değişiklik yapabilirsiniz.

    Yaygın Kullanılan Tipler

    Scala’da 8 adet numeric data tipi vardır.Byte,Char,Short,Int,Long,Float,Double ve Boolean.
    Dikkat ettiyseniz scalada javadaki gibi primitive type yok.Yani tüm tipler birer class.Böylelikle sayılar üzerinden method çağırımları yapabilirsiz.

    Aritmetik ve Operator Aşırı Yükleme (Overloading)

    Scaladaki aritmetik operatorlar aynen javadaki gibi çalışır.Fakat burada farklı olan şey bu operatorların aslında birer method olmaları.Örneğin, a+b aslında a.+(b)‘nin kısaltılmışıdır. + bir method adı.Benim için pek üzücü olmasa da scalada ++ operatoru mevcut değil.

    Fonksiyon ve Method Çağrımları

    Scala,methodlara ek olarak fonksiyonlara da sahiptir.Scalada matematiksel fonksiyonları kullanmak çok basittir.Javadaki gibi static call’lar yapmanıza gerek yok.

    pow(2,4) // 16.0
    min(3,Pi) // 3.0

    Bu fonksiyonlar scala.math paketinde tanımlıdır.import scala.math._ diyip kullabilirsiniz. “_” karakteri Javadaki “*” karakterine denk geliyor.

    Scalada parametre almayan methodları parantez kullanmadan kullanabilirsiz.Genel olarak,değişkenin değerini değiştirmeyen methodlar parametre almaz.

    “Scala”.distinct

    apply Methodu

    “Scala”(4) // ‘a’

    Yukarıdaki işlem için javada .charAt(4) şeklinde bir method çağrımı yapmamız gerekirdi.Ama scala sadece parantez kullanarak yapabiliyoruz.İlk gördüğümde vay arkadaş demiştim,nasıl yapıyor bunu 🙂 Peki scala bunu nasıl gerçekliyor ? () operatoru overloaded edildiğinden dolayı mı ?Hayır.Basitçe aslında String üzerinden apply methodunu call ediyoruz.Scalada StringOps class’ina baktığınızda aşağıdaki method tanımının olduğunu görürsünüz.

    def apply(n: Int):Char // Scalada geri dönüş değerinin tipini parantezlerin bitiminde “:” karakterinden sonra tanımlandığını görüyoruz.

    apply için başka bir örneği BigInt üzerinden verelim.

    BigInt(“555”) aslında BigInt.apply(“555”) işleminin kısaltılmışıdır.

    Şimdilik burada bitirelim.Artık Scala’nın ne olduğunu ve scala ilgili bazı temel bilgileri edinmiş olduk.Benim için faydalı oldu.Umarım sizler için de faydalı olur.

    EOF

    Kaynakça
    http://horstmann.com/scala/
    http://www.tutorialspoint.com/scala/scala_data_types.htm
    http://www.scala-lang.org/what-is-scala.html

    Başlarken

    Yakın zamanda Big Data ekosisteminde apache kafka,apache spark ve apache cassandra’yı da içeren uygulama geliştireceğiz.Bu uygulamayı da tavsiye edilen ve geliştirilmesi java’ya nispeten daha kolay olan scala ile yapıyor olacağız.Bu nedenle scala öğrenmeye başladım.Bunun için Cay S. Horstmann’in Scala for the Impatient kitabından faydalanacağım.Bu kitaptan öğreneceğim bilgileri chapter by chapter bu bloga aktarmaya çalışacağım.

    Bu yazı dizisini bitirdikten sonra efektif bir şekilde scala’yı kullanabiliyor olacağız.

    Aklınıza takılan her türlü soruyu sorabilirsiniz.Bildiğim kadarıyla cevaplamaya çalışırım.

    Let’s begin 🙂