Quantcast
Channel: Burak Selim Şenyurt
Viewing all 351 articles
Browse latest View live

Tek Fotoluk İpucu 141 - Dosyadan Rastgele Satır Çekmek

$
0
0

Merhaba Arkadaşlar,

Elinizde N sayıda şarkı adının kayıtlı olduğu fiziki bir dosya olduğunu düşünün. Amacımız ise bu dosya içerisinden rastgele şarkılar çekmek. Ancak bunu yaparken ilgili dosyanın tamamını belleğe açmak istemiyorsunuz. Nitekim dosyayı okuma modunda açıp readlines gibi bir metod ile tüm içeriğ okuduktan sonra içinden rastgele bir satırı seçme yolunu tercih edebilirsiniz. Ama bu büyük boyutlu bir dosyanın tamamen belleğe yüklenmesine de neden olacaktır. Performans ve hız açısından farklı bir şey yapılabilmelidir. Örneğin belleğe sadece o anki satırı okuyup ileri yönlü hareket edecek bir iterasyon kodu geliştirilebilir. Peki Ruby'de bunun için nasıl bir yol izlerdiniz? Aşağıdaki fotoğraftaki gibi olabilir mi?

Enumerable modülü içerisine getRandomLine isimli bir metod yerleştirdik. Metod aslında numaralandırıcı olarak gelen listeyi dolaşmakta. Bunun için each_with_index fonksiyonundan yararlanıyoruz. each_with_index fonksiyonu iki parametre alıyor. İlki numaralandırıcının o an üzerinde olduğu veri(ki örneğimizde bu dosya satırı olacak), ikincisi ise index numaras(ki bu da hangi satırda olduğumuzu gösterecek) Blok içerisinde rastgele sayı üretip bir kontrol gerçekleştiriyor ve o anki satırın bu koşula uyması halinde line değişkenine atanmasını ve son olarak nil değilse geri döndürülmesini sağlıyoruz. 

Örnek metin dosyasını açtıktan sonra getRandomLine metodunu üzerinde uygulayabiliriz çünkü satır bazında ileri yönlü itere edilebilir bir nesne örneği vermektedir. Dikkat edilmesi gereken nokta ise rewind çağrısıdır. Nitekim satır bulunurken mutlak olarak dosya sonuna gelinmektedir. Yani her satır okunur. Bu yüzden tekrar başa dönmezsek sadece ilk seferde şarkı seçimi gerçekleşir ve sonraki iterasyonlarda nil değerler alınır(Şarkıları rahatça görebilmek için program Thread'ini 2 saniye süreyle uyutuyoruz ki konumuzla çok alakalı değil)

Bu tekniği içeriğinde farklı veriler tutan pek çok dosya için uygulayabilirsiniz. Örneğin kullanıcılara rastgele promosyon uygulanacağı durumlarda verinin fiziki dosyada saklanması söz konusu ise bu tip bir metod oldukça işe yarayacaktır. Böylece geldik bir ipucunun daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.


Ruby Kod Parçacıkları 24 - Binary Tree ve Morse Kodları

$
0
0

Merhaba Arkadaşlar,

Geçtiğimiz günlerde çalışma arkadaşımla aramızda gelişen teknolojiler üzerine bir takım konuşmalar geçti. Amazon Alexa'dır, Facebook'un Face Recognation teknolojileridir, Arduino'dur, Drone'lardır vs derken OCR konusuna da değindik. Bükük duran bir kağıdın fotoğrafını çeken uygulamanın, kağıt üzerindeki şekli düz bir biçimde algılayabilidiğini, bunu yapmak içinse matematik'teki Laplace denklemleri ve Fourier serilerine başvurduğunu öğrendik. Bir Matematik Mühendisi olarak bu dersleri hep teorik olarak okumuştum. Tabii o zamanlarda bu tip denklemlerin gerçek hayat uygulamalarını pek görememiştim. Bu yüzden çoğu teori soyut olarak kalmıştı.

Benzer durumu Ruby ile ilgili çalışmalarıma devam ederken de yaşadım. Geçtiğimiz günlerde Enumerable modülünü incelemeye çalışırken kendimi bir anda Binary Tree veri yapısını tekrardan incelerken buldum. C# tarafında bu veri yapısını incelemiş ve kullanmıştım ancak Ruby tarafında incelerken farklı bir yaklaşımı benimsedim. Aynen OCR denklemlerinde olduğu gibi bunu gerçek hayat örnekleri ile eşleştirmeye gayret ettim. Yaptığım araştırmalar sonuncunda Morse kodlarının ikili ağaç yapısı ile ifade edilebildiğini öğrendim. Bilmediğim bir bilgiydi ve Binary Tree'yi daha iyi anlamama yardımcı oldu. 

Binary Tree'ler aslında bir veri yapısı(Data Structure) olarak ifade ediliyor. Bu veri yapısı birbirine bağlı boğumlardan(Node) oluşmakta. Her boğum iki alt boğum içermekte ve sağ sol olmak üzere en fazla iki alt dala ayrılmakta. Solda veya sağda kalan boğumlar kendi aralarında benzer ilişkilere sahip olacak şekilde bir dizilim söz konusu. Ne demek istediğimi daha iyi anlatabilmek için Morse kodlarının ağaç yapısında nasıl ifade edildiğine bir bakalım. Bu amaçla aşağıdaki grafiği göz önüne alabiliriz.

Root'tan başlayarak aşağıya doğru dallanan ve morse alfabesindeki her bir değerin boğumlar içerisinde ele alındığı bir ağaç yapısı söz konusu. Sol dalda yer alan boğumlar arasındaki ilişkiler nokta(.), sağ boğumlar arasındaki ilişkiler ise tire(-) sembolü ile ifade ediliyor. Yani kısa ve uzun sinyal olarak ifade edebiliriz. Buna göre bir harfin veya sayının Morse kodunu bulmak için ağaç üzerinde o değere doğru ilerlememiz yeterli. Söz gelimi 0'ın Morse kodu beş uzun sinyalden oluşuyor(-----) Yani T->M->O->Boşluk->0 sırasını izlersek kodu bulabiliriz. A harfini göz önüne aldığımızda bir kısa bir uzun sinyal söz konusu(.-) Buna göre root->E->A şeklinde ilerlememiz yeterli.

Binary Tree çok hızlı bir veri yapısı olmasa da çok yavaş da değil ve söz konusu Morse kodlarına uygun bir model sunmakta. Üzerinde arama kriterleri de uygulandığında tadından yenmeyecek bir veri içeriği oluşuyor.

Peki Ruby tarafında bu tip bir veri yapısını nasıl oluşturabiliriz? Bunun bir kaç yolu var ama birbirine bağlı boğumları tanımlama ve ağacı oluşturmak şu an daha ilgi çekici geliyor. Benim için iki ana unsur var. Birincisi boğumun içerisindeki harfi ve mors kodunu temsil edecek bir sınıfa ihtiyacım olacak. Diğer yandan Node yapısını işaret edecek bir sınıf daha gerekiyor. Bu sınıfa Enumerable modülünü dahil ederek kendi üzerinde taşıdığı öğeler üzerinde iteratif hareket edebilmeyi umuyoroum. İlk olarak Code sınıfını tanımlayalım.

class Code
	attr_accessor :letter, :signal
	def initialize(letter,signal)
		@letter=letter
		@signal=signal
	end
	def to_s
		"#{@letter}-#{@signal}"
	end
end

Code sınıfı bir harf veya sayıya karşılık gelecek sinyali barındırmakta. Node sınıfını ise temel olarak aşağıdaki gibi tasarlayabiliriz.

class Node
	include Enumerable
	attr_accessor :owner,:left,:right
	def initialize(letter,signal)
		@owner=Code.new(letter,signal)
	end
	def each(&block)
		left.each(&block) if left
		block.call(self)
		right.each(&block) if right
	end
	def translate(word)
		newWord=""
		word.split("").each{|c|newWord<<find{|n|n.owner.letter==c.upcase}.owner.signal}
		newWord.chomp
	end
	def to_s
		@owner.to_s
	end
end

Node sınıfı bir boğumun kendisi ve bu boğumun sağ ile sol boğumlarını temsil eden sınıfımızdır. Initialize metoduna gelen iki parametre ile harfi ve sinyali alıp bir Code nesne örneği oluşturmaktadır. Bünyesinde barındırdığı each metodunun dikkat çekici yanı parametre olarak bir block almasıdır. Bu bloğu kendisine, varsa sol ve sağ boğumlarına da uygular. left ve right değişkenleri üzerinden de each çağrısı yapıldığına dikkat edelim. each metoduan gelen kod bloğu bu sayede left ve right değişkenleri altındaki boğumlara da uygulanmaktadır. Kısacası Node örneğine ait fonksiyona bir kod bloğunu gönderebilir ve boğumun kendisi ile sonrasında gelen elemanlar için bu blok içeriğini çalıştırabiliriz. Örneğin root ve altındaki tüm boğumları yazdırabiliriz. Bunun için aşağıdaki kodu kullanmak yeterli.

root.each{|n|puts n.to_s}

Ekran görüntüsünde görüldüğü gibi tüm boğumları elde ettik. Bu arada bu boğumları nasıl oluşturduk diye düşünebilirsiniz. Tekniğinden tam olarak emin olamadığım biraz da amelece diyebileceğimiz bir kodlama yapmak durumunda kaldım. Morse kodlarına ait ikili ağaç yapısını Node sınıfına ait bir nesne örneği üzerinden tek tek ekleyerek oluşturmaya çalıştım. Kodun uzunluğu için şimdiden beni mazur görün. Eminim çok daha şık bir yol vardır. Pişmanım ama elden ne gelir.

root=Node.new("root",nil)
Empty1=Node.new(nil,nil)
Empty2=Node.new(nil,nil)
Empty3=Node.new(nil,nil)
E=Node.new("E",".")
I=Node.new("I","..")
S=Node.new("S","...")
H=Node.new("H","....")
V=Node.new("V","...-")
U=Node.new("U","..-")
F=Node.new("F","..-.")
A=Node.new("A",".-")
R=Node.new("R",".-.")
L=Node.new("L",".-..")
W=Node.new("W",".--")
P=Node.new("P",".--.")
J=Node.new("J",".---")
T=Node.new("T","-")
N=Node.new("N","-.")
M=Node.new("M","--")
G=Node.new("G","--.")
O=Node.new("O","---")
D=Node.new("D","-..")
K=Node.new("K","-.-")
B=Node.new("B","-...")
X=Node.new("X","-..-")
C=Node.new("C","-.-.")
Y=Node.new("Y","-.--")
Z=Node.new("Z","--..")
Q=Node.new("Q","--.-")

N0=Node.new("0","-----")
N1=Node.new("1",".----")
N2=Node.new("2","..---")
N3=Node.new("3","...--")
N4=Node.new("4","....-")
N5=Node.new("5",".....")
N6=Node.new("6","-....")
N7=Node.new("7","--...")
N8=Node.new("8","---..")
N9=Node.new("9","----.")

root.left=E
root.right=T
E.left=I
E.right=A
I.left=S
I.right=U
U.left=F
U.right=Empty1
Empty1.right=N2
S.left=H
H.left=N5
H.right=N4
S.right=V
V.left=N3
A.left=R
R.left=L
A.right=W
W.left=P
W.right=J
J.right=N1
T.left=N
T.right=M
N.left=D
N.right=K
D.left=B
D.right=X
B.left=N6
K.left=C
K.right=Y
M.left=G
M.right=O
G.left=Z
Z.left=N7
G.right=Q
O.left=Empty2
O.right=Empty3
Empty2.left=N8
Empty3.left=N9
Empty3.right=N0

Buna göre herhangibir boğum ve sonrasında gelenleri each metodu üzerinden çekebiliriz. Örneğin kök boğumun sağ tarafındaki diziden G ve altındaki bağlantıları bulalım.

G.each{|n|puts n.to_s}

Translate fonksiyonu ise bir kelimenin harflerini tek tek ele alıp find metodu üzerinden hareket ederek karşılık gelen sinyalleri bulmak için yazılmıştır. Aşağıdaki kod parçasında bir kaç örnek kullanımını bulabilirsiniz.

signs=["WeAreSinkingStop","soss","HelpUSStop"]
signs.each{|w| puts "#{w} = #{root.translate(w)}"}

Görüldüğü gibi yazılan metinlerin Morse kodlarına göre karşılıklarını elde ettik. Aslında bir harfin karşılığı olan morse kodunun key-value çiftleri şeklinde tutulması da mümkün. Bizim buradaki amacımız ikili ağaç veri yapısında bu serinin nasıl oluşturulabileceğini görmekti. Diğer yandan kodda dikkat çekici başka noktalar da bulunmakta. Enumerable modülünün dahil edilmesi, each metoduna block geçirilmesi ve find operasyonunun ezilmesi bunlar arasında sayılabilir. Bir antrenman kodu olarak değerlendirebilirsiniz. Tabii kodda bir çok sıkıntı var. Söz gelimi ikili ağaç resminde görünün sırada elde edemiyoruz. Buna bir bakmak lazım. Böylece geldik bir Ruby maceramızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

Ruby Kod Parçacıkları 25 - Unit Test Yazmak

$
0
0

Merhaba Arkadaşlar,

İyi yazılım geliştirmenin olmazsa olmaz parçalarından birisi de birim testleridir(Unit Tests) Tahmin edileceği üzere Test Driven Development denildiğinde(aklımızda hemen Red Green Blue - Fail, Fix, Refactoring oluşmalı) birim testleri ön plana çıkmaktadır. Pek çok programlama ortamında birim testler için hazır kütüphaneler yer alır. Ruby dilinde ise standart kütüpanede yer alan Test::Unit modülü kullanılmaktadır. Testlere dahil edilecek savlar(assert diyelim) oldukça geniştir. assert, assert_not_equal, assert_nil, assert_respond_to, assert_raise ve benzeri fonksiyonellikler söz konusudur (Kullanılabilecek savların listesine şuradan bakabilirsiniz) Aşağıdaki kod parçasında basit bir test düzeneğine yer verilmiştir.

require 'test/unit'

class Product

	attr_accessor :title, :listPrice, :category
	
	def initialize(title,listPrice,category)
	
	       raise ArgumentError,"#{listPrice} must be greater than 10" unless listPrice>10
	       @title=title
	       @listPrice=listPrice
	       @category=category
	end
end
class ProductTest < Test::Unit::TestCase             
	TITLE,LIST_PRICE,CATEGORY="Head First Design Patterns",39.99,"Book"            
	def setup
	       @product=Product.new(TITLE,LIST_PRICE,CATEGORY)
	end        
	def testForTitle
	       assert_not_nil @product.title
	       assert_equal TITLE,@product.title
	end
	def testForListPrice
	       assert_equal 39.99,@product.listPrice
	       assert_raise(ArgumentError){Product.new(TITLE,9.99,CATEGORY)}
	end
	def testForCategory
	       assert_send([["Book","Computer","Camera"], :include?, @product.category]) 
	       assert_send([["Book","Computer","Camera"], :include?, Product.new(TITLE,LIST_PRICE,"Unknown").category]) 
	end
end

Program kodu test/unit modülünün kullanılacağını belirten require bildirimi ile başlar. Örneğimizde Product isimli bir kobay sınıf yer almaktadır. Sınıfı belirleyen üç nitelik var. Ürün adı, liste fiyatı ve yer aldığı kategori. Amacımız Unit Test'lerin basitçe nasıl yazıldığını görmek. Bu yüzden çok karmaşık test vakalarına girmedik. Tüm savlar ProductTest sınıfı içerisinde yer alan testForFile,testForListPrice ve testForCategory fonksiyonları ile icra edilmekte. 

ProductTest sınıfının test metodları içerdiğini ve çalışma zamanında test sürecine dahil olacağını belirtmek içinse Test::Unit::TestCase sınıfından bir türetme söz konusudur. setup fonksiyonu var olan test senaryolarından önce çalışan bir metoddur. Tahmin edileceği gibi bu sınıf içerisinde test metodları boyunca kullanılacak ortak nesnelerin üretimi veya ön hazırlık işlemleri yapılabilir. Örnekte bir Product nesnesini üretip test vakalarının kullanımına sunuyoruz.

testForTitle metodunda Title niteliği için iki sav deneniyor. Bunlardan birisi nil kontrolü diğeri ise nitelik değerinin "Head First Design Pattern" metnine eşit olup olmadığı. testForListPrice metodunda da benzer bir eşitlik kontrolü var. Ayrıca liste fiyatının 10 birimin altında olması durumunda almayı beklediğimiz ArgumentError istisnasının kontrolü de bulunuyor. Yani 10 birimin altında bir değer verildiğinde ortama ArgumentError fırlatılmasını bekliyoruz. Nitekim Product sınıfının initalize metodu içerisinde bu tip bir exception kontrolü söz konusu. Eğer liste fiyatı beklenen değerin altında ise ortama fırlatılacak bir hata var. assert_raise bu hatanın fırlatılacağı vakayı test ediyor. Savımızın kabul kriteri 10un altında bir değer verilmesi halinde ortama hata yollanması. testForCategory metodunda ise assert_send isimli bir çağrım yer alıyor. Burada kategorinin ilk parametre ile gelen dizi içerisindeki bir eleman olması durumu test edilmekte. Metodun ilk parametresinde kullanılabilecek kategorilere ait dizi yer alıyor. İkinci parametre array sınıfı üzerinden kullanılabilecek ve include? metodu ve son parametrede include?'a verilebilecek olan değer. İkinci satırdaki kodda sav'ın geçersiz olmasına ait bir kriter kontrol ediliyor. Hepsi bu. Dilerseniz çalışma zamanı sonuçlarına da bir bakalım.

Product içerisinde yer alan tüm test metodları sırasıyla çalıştırılmıştır. 3 test metodu ve içerisinde yer alan 6 assert icra edilmiştir. Bu varsayımlardan beklediğimiz gibi hatalı kateogori vakasının kodun hangi satırında oluştuğu terminal penceresine dökülmüştür. Dilersek bir veya n sayıda test metodunu da çalıştırabiliriz. Nitekim bazı test sınıfları içerisinde fazla sayıda test metodu olabilir ve o an için sadece bellir birini(veya bir kaçını) test etmemiz gerekebilir. Sonuçta test operasyonları da zaman zaman süre ve kaynak kullanımı adına maliyetli olabilir. Böyle bir durumda verbose --name testMetodu dizilimini kullanabiliriz. Aşağıdaki ekran görüntüsünde örnek bir kullanım yer almaktadır.

Bu kez sadece testForTitle isimli test vakası çalıştırılmıştır. Görüldüğü gibi Unit Test'ler oluşturmak oldukça pratik ve kolay. İşin önemli olan kısmı test vakalarını oluşturabilmek ve Test Driven Development yaklaşımının benimsediği şekilde kodları geliştirebilmek. Böylece geldik bir kod parçamızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

Ruby Kod Parçacıkları 26 - Eğlenerek Binary Dosya Okumak

$
0
0

Merhaba Arkadaşlar,

Vakit buldukça Ruby programlama dili ile ilgili bir şeyler yapmaya çalışıyorum. Halen daha dilin kabiliyetlerini tanıma aşamasındayım. Geçtiğimiz günlerde de Ruby Cookbook kitabından binary dosyalar üzerinde yapılan işlemlere ait örnekleri inceliyordum. Hoşuma giden uygulamalardan birisi de MP3 dosyalarına ait Tag bilgilerinin elde edilmesiydi. Gerçek hayat örneği olduğundan benim için daha öğretici idi. Örnekleri inceledim ve kendime göre farklılaştırarak basit bir kod parçası oluşturmaya çalıştım.

Amaç bir MP3 dosyası üzerinde eğer varsa kayıtlı Tag bilgilerini elde etmek. Tag bilgilerine bakarak şarkının adını, söyleyen sanatçı veya grubu, yayınlandığı yılı ve içinde bulunduğu albüm bilgilerini elde etmek mümkün. Hatta albümdeki sıra numarası, türünü, başlangıç ve bitiş sürelerini dahi elde edebiliyoruz. Tabii MP3 dosya formatlarına ve ID3 standartlarına göre farklılıklar söz konusu olabiliyor. Uzatılmış tag yapısı gibi bir kavram ve ID3 ün farklı versiyonları var. Buna göre farklı bilgileri de elde etmek mümkün. Lakin ben 128 byte' lık segment yapısına sahip dosyaları ele almaya çalıştım(ID3 formatına ait detaylı bilgi almak için wikipedia adresine bakmanızı öneririm)

Önce kod içeriğine bir bakalım ve sonrasında neler öğrendiğimi sizlere aktarayım.

class TagInfo
	attr_accessor :track_name,:artist_name,:album_name,:year
	def initialize(track_name,artist_name,album_name,year)
		@track_name,@artist_name,@album_name,@year=track_name,artist_name,album_name,year
	end
	def to_s
		"#{@artist_name}-#{@album_name}-#{@track_name} (#{@year})"
	end
end

def get_tag_info(mp3)
	info=nil
	open(mp3) do |f|
		f.seek(-128,File::SEEK_END)
		if f.read(3)=="TAG"
			info=TagInfo.new(
				f.read(30),
				f.read(30),
				f.read(30),
				f.read(4)
			)
		end
	end
	return info
end

songs=Dir.glob("*.mp3")
songs.each{
	|s|
	puts get_tag_info(s).to_s
	}

Kodumuz TagInfo isimli bir sınıf tasarımı ile başlıyor. Bana göre MP3 şarkısının tag yapısı sistem içerisinde bir varlık olarak ifade edilmeli(Hatta daha geniş kapsamlı düşünüsek MP3 dosya içeriğini ve ilgili Tag bilgilerini barındıran bir sınıf tasarımı da mümkün olabilir. Bu sınıfa ait nesne örnekleri NoSQL tabanlı bir yapıda saklanabilir. Alın size db tabanlı bir müzik seti) Ben çok daha yüzeysel basit bir sınıf tanımladım. İçerisinde dört nitelik yer alıyor. track, artist, album ve year bilgilerini tutmayı planlıyorum. Örnek çıktılarını ekrana bastırmak gibi bir amacım da olduğundan to_s metodunu eziyorum(Bu arada initialize metodu içerisinde çoklu atama işlemi gerçekleştirdiğimize dikkat edelim) 

Kodun önemli operasyonu tabii ki get_tag_info isimli metod. MP3 dosyaları normalde binary olarak okunabiliyorlar. Standartlara göre 128nci byte'tan sonra gelen ilk 3 byte içerisinde TAG yazıyorsa bahsettiğimiz bilgilere ulaşma şansımız var. Öncelikle dosyayı okuma modunda açmamız gerekiyor. open fonksiyonunu bu amaçla kullanıyoruz. Fonksiyona geçecek blokta dosyanın kendisini f ile işaret etmekteyiz. seek metodu 128nci byte'tan itibaren dosya sonuna kadarlık kısmı almamızı sağlayacak. Yani dosya üzerindeki işaretçiyi 128nci byte'a aldığımızı düşünebiliriz. read metoduna verilen parametre ile ne kadarlık bilgi okuyacağımızı belirtiyoruz. Buna göre read(3) ile aradığımız TAG bilgisinin olduğu bölümü okumaktayız. Okuma işlemi sonrası dosya üzerindeki konumumuz 3 byte ilerlemiş olacak. Eğer buradaki içerik TAG ise sonrasında ID3 standartına göre dosya üzerindeki konumumuzu ileri doğru hareket ettirerek bir okuma gerçekleştiriyoruz. 

İlk 30 byte ile track_name, sonrasında gelen 30 byte ile artist_name, sonrasında gelen 30 byte ile album_name ve sonrasında gelen 4 byte ile de year bilgisini okumaktayız. Okuduğumuz bilgileri kullanarak bir TagInfo nesne örneği oluşturuyor ve metodumuzdan geriye döndürüyoruz.

Tabii kodu uygulamak için MP3 şarkılarının olduğu bir konumda çalıştırmak gerekiyor(Siz kendi örneğinizi yaparken klasör bilgisini programa parametre olarak almayı denemelisiniz)İşte o anda bir klasör ve içerisindeki MP3 uzantılı dosyaları nasıl çekebileceğimi öğrendim. Dir tipine ait glob metoduna geçirilecek desen ile bu işlemi gerçekleştirmemiz mümkün. sonrasında each metodunu çağırıyor ve blok içerisinde get_tag_info fonksiyonunu kullanarak MP3 dosyalarına ait bilgileri ekrana basıyoruz. Örnek şarkılarıma ait klasör içeriğini tarattığımda aşağıdaki gibi bir çıktı elde ettim.

Görüldüğü gibi Binary dosya içeriklerini iler yönlü okumak ve içlerinden bilgi almak son derece kolay. open fonksiyonu haricinde seek ve read metodlarının kullanımı da önemli. Örneğimizde sınıf oluşturulması ve Dir tipine ait globe metodunun kullanılmasını da öğrenmiş bulunuyoruz. Bilgilerimiz çoğaldıkça Ruby ile kodlama daha da eğlenceli hale gelmeye başlıyor. Bir başka kod parçasında görüşünceye dek hepinize mutlu günler dilerim.

CodeFiction P2P Söyleşim

$
0
0

Merhaba Arkadaşlar,

Geçtiğimiz günlerde değerli meslektaşlarım Mert Susur, Deniz İrgin, Uğur Atar ve Fırat Özbolat ile code('fiction')'ın konuğu olarak keyifli bir söyleşiye katıldım. Ağırlıklı olarak bankacılık uygulamalarından, bu dünyada Enterprise Mimari'nin nasıl yürüdüğünden ve yazılımcı olarak genel dertlerimizden konuştuk. Ayrıca genç meslektaşlarımız için yol gösterici bilgiler vermeye çalıştık.  

Umarım dinleyenler için de keyifli ve yararlı bir söyleşi olmuştur. Görüşmek dileğiyle hepinize mutlu günler dilerim.

Ruby Kod Parçacıkları 28 - Multithreading ve Mutex Kullanımı

$
0
0

Merhaba Arkadaşlar,

Ruby Kod Parçacıkları serimizin bir önceki bölümünde çoklu iş parçacıklarının(Multithreading) nasıl yazılabileceğini incelemeye başlamıştık. Başrol oyuncumuz olan Thread sınıfının kullanımını gördük. Lakin birden fazla iş parçacığının ele alındığı senaryolarda dikkat edilmesi gereken önemli konulardan birisi de ortak veriler üzerinde işlemler yapıldığında ortaya çıkmaktadır. Eş zamanlı olarak çalışan iş parçacıkları bazı durumlarda verinin tutarlılığının bozulmasına neden olabilir. Nitekim n sayıda iş parçacığının farklı anlarda aynı veri üzerinde işlem yapması söz konusudur. Birbirlerinin işlerini kesebilirler.

Eğer ortak verinin tutarlılığı/kararlılığı önemli ise ilgili iş parçacıklarının senkronize edilmesi gereklidir. Bu pek çok programlama dilinde benzer teknikler ile çözülen bir problemdir. Ruby tarafında Mutex sınıfını kullanarak bu sorunun kontrollü bir şekilde ele alınması sağlanabilir. Mutex ile atomik olmayan metodların atomikleştirilmesi, memory barier konulması vb işler yapılabilir. Kısacası thread-safe denilen güvenli paralelliği sağlayabiliriz.

Tabii öncelikle meseleyi anlamamız gerekiyor. Ortak veri nasıl olur da bozulabilir? İşe aşağıdaki basit kod parçası ile başlayabiliriz.

Concurrency'nin Temel İlkesi Atomicity'nin Bozulması

require 'thread'

for i in 1..5 do
  points = [0, 0, 0, 0, 0]
  
  threads = 100.times.map do
    Thread.new do
      5000.times do
        points.map! { |i| i + 1 }
      end
    end
  end
  threads.each{|t|t.join}  
  puts points.to_s
end

Kodu dikkatli bir şekilde incelemeliyiz. Anlamlı bir iş yapmıyor ancak bize Concurrency konusunda önemli dersler veriyor. 5 sefer çalışan bir test sürecimiz söz konusu. Her seferinde 100 farklı iş parçacığı açıyoruz(Thread nesnesi örnekleyerek) Her bir iş parçacığı içinde 5000 kez yapılan bir işlem söz konusu. Bu işlem sırasında points isimli dizinin eleman değerleri arttırılıyor. Uygulama tamamlandığında dizideki her bir elemanın 500000 olmasını bekleriz değil mi? Oysaki çalışma zamanı sonuçları oldukça farklıdır.

Ekran görüntüsü Eclipse IDE'sine aittir. Eclipse'e şu adresteki plug-in'i yükleyerek Ruby için geliştirme yapabilirsiniz.

Dikkat edileceği üzere sadece bir sefer 500000 değeri tutturulabilmiş(siz yapacağınız denemelerde daha fazla tutturabilir veya hiç tutturamayabilirsiniz de) ve kalan diğer denemelerde farklı sayılar elde edilmiştir. Buradaki sıkıntı points dizisi içerisindeki elemanlara erişen iş parçacıkları içerisinde atomiklik ilkesini bozan map! metodunun kullanılmasıdır. Bu durumu biraz daha açmaya çalışalım.

Çalışan iş parçacıklarından birisi points dizisindeki bir elemanı okumuş olsun. Okuma işlemi sonrası bunun değerini bir arttıracaktır. Lakin arttırma işlemi öncesi diğer bir iş parçacığının ilk iş parçacığının işleyişini kestiğini düşünelim. Hatta bu ikinci iş parçacığı dizideki ilgili elemanı okuyup arttırmış ve başarılı bir şekilde kayıt etmiş olsun (O değerle ilgilenen ilk iş parçacığı henüz işini bitirememişken)İşte problem.

Bu yüzden 500000 değerinden küçük ve birbirlerinde farklı sayısal değerler elde ettik. Problem iş parçacıklarının birbirini karşılıklı kesmesi dışında Conccurency'nin temel gerekliliklerinden olan Atomicity ilkesini bozan map! metodunun kullanılmasıdır. Öyleyse sorunu çözelim(Bu arada Conccurency denince üç temel ilke söz konusu. Atomicity, Visibility-bir thread tarafından oluşturulan etkinin diğer thread'ler tarafından da görülmesi ve Ordering. Visibility ve Ordering konularını ilerleyen zamanlarda ele almaya çalışacağım)

map! Kullanımını Atomikleştirmek

Mutex sınıfını kullanarak map operasyonunu atomik hale getirebiliriz. Aslında yapacağımız şey bir iş parçacıklarını ilgili veri ile uğraşırken kitlemek ve diğer iş parçacıklarını bu iş sırasında bekletmekten ibaret. Kodu aşağıdaki gibi değiştirerek ilerleyelim.

require 'thread'

mtx=Mutex.new()

for i in 1..5 do
  points = [0, 0, 0, 0, 0]
  
  threads = 100.times.map do
    Thread.new do
      5000.times do
        mtx.synchronize(){
          points.map! { |i| i + 1 }
        }
      end
    end
  end
  threads.each{|t|t.join}  
  puts points.to_s
end

Yaptığımız ilk şey mtx isimli bir Mutex nesnesi örneklemek. Sonrasında atomikleştirmek istediğimiz kod parçasını synchronize metoduna ait kod bloğu içerisine alıyoruz. Bu şekilde map operasyonunu senkronize etmiş oluyoruz. Senkronizasyonu sağlayarak çalışmakta olan iş parçacıklarının aynı veri üzerinde işlem yaparken birbirlerini kesmemesi ve veri bütünlüğünün bozulmaması mümkün hale geliyor. İşte çalışma zamanı sonuçları.

Görüldüğü gibi tüm denemelerde points dizisi elemanları beklediğimiz gibi aynı toplam değerini üretmiştir. İş parçacıklarını senkronize olarak çalıştırmak bazı durumlarda işlemlerin daha yavaş tamamlanmasına da neden olabilir ancak verinin tutarlılığı oldukça önemli bir konudur. Böylece geldik bir kod parçacığının daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

GDG DevFest Edirne'de Buluşalım

$
0
0

Merhaba Arkadaşlar,

Bu sene yeni yetme bir Rubyist olarak Bolu Abant İzzet Baysal Üniversitesi'nin düzenlediği GDG festivaline katılma fırsatı bulmuştum. Ardından Ruby dilini Karabük Üniversitesi'ndeki genç meslektaşlarımızla da paylaştım. Her ne kadar Google'ın bir ürünü olmasa da Ruby dilini anlatmak için bir fırsat daha buldum. Bir aksilik olmazsa 18 Aralık Pazar günü GDG Edirne'nin düzenlediği etklinlikte Ruby dilini tanıtmaya çalışacağım. Program inanılmaz derecede güzel. İtiraf etmek gerekirse diğer konulara bakıldığında arada biraz sırıtıyor gibiyim. Yine de değerli katılımcılarımıza Ruby konusundaki bilgilerimi elimden geldiğince iyi bir şekilde aktarmaya çalışacağım. 

Program detayları ise şu şekilde.

  • Barıs YESUGEY - Google Technologies ve PWA
  • Salim KAYABAŞI - PWA - An Unexpected Journey
  • Elif BONCUK - Android Layouts and A New One: ConstraintLayout
  • Ertaç PAPRAT - Dev Veri ile Başa Çıkmak
  • Ben - Ruby
  • Celil BOZKURT - Google Play'de Popüler Olmak
  • Erol KAFTANOĞLU - Firebase:Getting Started
  • Kadir Can KIRKOYUN - Getting Started : React-Native
  • Sercan YUSUF - Android 101
  • Barış CEVİZ - Getting Started: GoLang

Orada görüşmek üzere.

Tek Fotoluk İpucu 148 - Hassas Bilgiyi Hash'leyerek Saklayalım

$
0
0

Merhaba Arkadaşlar,

Yazdığımız bir uygulamada kullanıcının anne kızlık soyadı, kimlik numarası, şifre ve benzeri bilgilerini aldığımızı düşünelim. Bir arayüz üzerinden giriliyor olabilirler. Bu bilgileri herhangibir amaçla veritabanında sakladığımızı varsayalım. Şirket güvenlik politikları gereği ilgili bilgiler açık bir şekilde tutulmamalı. Yani anne kızlık soyadı, şifre veya kimlik numarası gözle okunabilir halde tutulmamalı. Buna göre ilgili bilgileri veritabanı üzerinde maskeleyerek saklamak doğru bir çözüm olabilir. Bunu yapabilmek için akla gelen yollardan birisi de tahmin edileceği üzere Hash algoritmalarına başvurmaktır. Peki güçlü bir Hash algoritması ile bu maskeleme işlemini yapmak ister misiniz? Aşağıdaki fotoğraf size yol gösterebilir.

RNGCryptoServiceProvider sınıfı bir salt içeriği oluşturulmasında görev alıyor. Bu içerik sonraki aşamada verinin maskelenmesi sırasında kullanılıyor. Salt hash çıktısının benzersiz ve tahmin edilemez olması noktasında önem arz etmekte. Örnekte 48 byte'lık bir salt verisi oluşturuldu ama bu şart değil. Farklı boyutlarda salt içerikleri üretilebilir. Oluşturulan salt Rfc2898DerivedBytes sınıfının yapıcı metoduna parametre olarak geçiliyor. İlk parametrede ise maskelenecek olan içeriğimiz var ki bu örnekte Anne Kızlık Soyadı bilgisini ele alıyoruz. İkinci parametre ise salt değeri. IterationCount özelliğine atanan değer karmaşıklığı arttırmak için veriliyor. İterasyon sayısı fazlalaştıkça algoritma biraz daha karmaşık çalışıyor ve tahmin edilebilirlik ihtimalini düşürüyor diyebiliriz. Maskelenen içeriği yine GetBytes metodu yardımıyla elde ediyoruz. Sonrasında bunu ToBase64String metodu ile string formatta ekrana yazdırmaktayız. Elbette gerçek dünya senaryosunda maskelenen bu string içeriği veritabanına kayıt etmeniz gerekiyor.

Peki ya sonrasında...Müşteri uygulamaya tekrardan giriş yapıp Anne Kızlık Soyadı bilgisini girdiğinde aynı süreç işleyip üretilen maskelenmiş verinin veritabanındaki versiyonu ile karşılaştırması yeterli. Bu iki içerik aynı olduğu takdirde doğru bilgi girmiş olduğunu düşünerek sürecin ilerletilmesini sağlayabiliriz. Ayrıca anne kızlık soyadı sistemin hiç bir noktasında gözle okunabilir formatta dolaşmamış da olur.

Tabii ekranda bu bilgilerin girildiği kutucukların ve ağ üzerinde bu bilgilerin aktığı hattın güvenliği bambaşka bir konu. Burada servis mesaj içeriklerinin şifrelenerek kullanılması ya da https gibi protokollerin tercih edilmesi doğru bir yaklaşım olabilir. Nitekim hattın güvenli olması ve dinleyen yabancı uygulamaların bu içerikleri görememesi çok önemlidir.

Tabii örnek sadece nasıl kullanılırı gösteriyor. İlgili fonksiyonelliğin kütüphaneleştirilmesi çok daha doğru olacaktır. Bu görevi siz değerli okurlarıma bırakıyorum. Bir başka tek fotoluk ipucunda görüşmek dileğiyle hepinize mutlu günler dilerim.


Ruby Kod Parçacıkları 29 - Kod Yazan Kodlar

$
0
0

Merhaba Arkadaşlar,

Ruby programlama dilinin öne çıkan özellikleri arasında dinamiklik ve meta programlama yetenekleri de yer almaktadır. Aslında işin özeti kod yazan kodlardır diyebiliriz. Ruby yorumlamalı bir dildir ve doğal olarak her şey çalışma zamanında icra edilmektedir. Ancak bazı senaryolarda metinsel olarak gelen bir içeriğin kod parçası şeklinde değerlendirilmesi ve çalışma zamanında yürütülmesi istenebilir. Hatta çalışan kod üzerinde değişiklikler yapılabilmesi de belli ölçülerde mümkündür. Konu pek tabii benim burada anlatacağım kadar basit değil. Örneğin Amazon'da bu konu üzerine yazılmış kitaplar bulabilirsiniz. Bu yazımızda kodu çalışma zamanında üretmek veya çalışan kodu manipule etmek için yapılabileceklerden bir kaçına değinmeye çalışacağız.

Bazı durumlarda Meta-programlama ile Reflection birbirleri ile karışıtırılır. Normal de Reflection Meta-programlama'nın bir alt dalı olarak karşımıza çıkar ve özellikle yorumlamalı betik dillerde program kodu hakkında çalışma zamanına bilgi sağlamak amacıyla kullanılır. Bir sınıfın özellik adlarını yakalamak gibi. Oysa ki meta-programlama ile çalışan kodun çalışma zamanında değiştirilmesi veya çalışabilecek metinsel kod parçalarının yine çalışma zamanında ayağa kaldırılıp yürütülmesi gibi işlemler kastedilir. Bu açıdan bakıldığında meta-programlama'nın yer bulduğu en önemli alan Domain Specific Language yazılmasıdır.

Eval ile Çalışma Zamanında Kod İşletmek

İlk örneğimizde eval fonksiyonelliğini ele alarak metinsel bir kod parçasını nasıl çalıştırabileceğimizi anlamaya çalışacağız.

puts 'insert a simple code'
code=gets
eval code

someCodes="puts 'whats your name?'
        name=gets
        puts name.upcase!()
"
eval someCodes

İlk olarak çalışma zamanı çıktısına bir bakalım dilerseniz.

Sizi bilemem ama ben bu kod parçasına baktığımda epeyce etkileniyorum. İlk olarak kullanıcıdan ekrana bir kod parçası girmesini istiyoruz. Tabii örnekte işletilebilir bir kod parçası eklediğimizi itiraf etmeliyim(Hatalı bir kod parçasının nasıl tepki vereceğini incelemek ise size bir ödev olsun) Sonrasında ise birden fazla satıra yayılan bir kod parçası söz konusu. Önemli olan nokta code ve someCodes değişkenlerinin eval ile birlikte kullanılması. Yani çalışan bir kodun içerisinde başka bir ruby kodunun çalıştırılmasını sağlamış olduk. eval, parametre olarak gelen ifadenin değerlendirilmesini yapıp yorumlanacak şekilde ruby ortamına aktarmakla görevli. Bu arada eval, RubyKernel API'si içerisinde yer alan instance metodlarından birisidir.

Binding

Bir diğer Kernel metodu ise binding'dir. eval fonksiyonu ile birlikte kullanılır. Temel olarak bir metod ve değişkenlerini program ortamı içerisinde başka bir noktaya bağlayabilmemize olanak sunar. Konuyu açıklamak için aşağıdaki kod parçasını ele alalım.

def doSomething
  puts "in doSomething"
  return binding
end
bind=doSomething{3.times{puts "arigatou"}}
eval "yield",bind

ve çalışma zamanı görüntüsü.

doSomething metodu içerisinde binding kullanılmıştır. Buna göre çalışma zamanında doSomething metodu ve parametrik yapısı yaklanarak eval ifadesi üzerinden kendisine kod parçası gönderilebilir. Şimdi konuyu dikkatlice inceleyelim. Çalışma zamanında ekrana ilk olarak "in doSomething" yazar. Sonrasında ise 3 kez "arigatou". Bunu 3.times{puts "arigatou"} ifadesinin gerçekleştirdiği aşikardır. Bu ifadenin doSomething metodu içerisine gönderilmesi içinse eval fonksiyonuna iki parametre geçilmiştir. İlki yield anahtar kelimesi, ikincisi ise metodun bağlandığı değişken olan bind(Açıkçası binding konusu bana biraz karışık geldi. Daha iyi bir şekilde öğrenmek için uğraşıyorum)

Bir Sabitin Çalışma Zamanında Yakalanması

Pek tabii dinamiklik ve meta-programlama söz konusu ise ortada reflection gibi konularda yer alacaktır. Örneğin çalışma zamanında bir değişmezi(Constant) yakalamak için const_get metodundan yararlanılabilir(eval'e göre daha performanslı olduğu ifade edilmektedir) Aşağıdaki kod parçasını ele alalım.

eValue="E"
piValue="PI"
result1=Math.const_get(eValue)*10
result2=Math.const_get(piValue)*10*10
puts result1,result2

pi=eval "Math::PI"
puts pir

Bu kod parçasında Math sınıfında yer alan PI ve E değişmezlerinin çalışma zamanında bir string üzerinden yorumlanması örneklenmektedir. eValue ve piValue değişkenleri dikkat edileceği üzere string veri türündedir. Math sınıfı üzerinden const_get metodu kullanılarak bu iki değişmezin değeri yakalanabilir. Dolayısıyla kendi tanımladığımız bir sabitin değerini de bu şekilde çalışma zamanında yakalamamız mümkün. İkinci kod parçasında sabit değerinin eval ile yorumlanması örneklenmiştir. Çalışma zamanına ait çıktımız aşağıdaki gibi olacaktır.

Bir Sınıfı Adından Örneklemek 

Dilersek bir sınıfı yine metin olarak gelen adından örnekleyebiliriz. .Net tarafında da reflection teknikleri ile yapabildiğimiz bir operasyon olduğunu biliyoruz. Aslında bir sınıfın çalışma zamanında örneklenmesi olarak ifade edebileceğimiz bir durum(Tabii Ruby'de her şey çalışma zamanında gerçekleşiyor bunu da unutmamak lazım) Konuyu aşağıdaki örnekle anlamaya çalışalım.

module Game
  class Player
    attr_accessor :name,:point
    def initialize(name,point)
      @name,@point=name,point
    end
    def to_s
      "#{@name}-(#{@point})"
    end
  end
end

# sinif module icinde oldugundan :: notasyonu kullaniliyor
obj=Object.const_get("Game::Player") #sinif adini alip
o=obj.new("burk",100) #ornekliyoruz
puts o.to_s #ve icindeki bir metodu kullaniyoruz

Game modülü içerisinde örnek olarak ele aldığımız Player isimli bir sınıf bulunuyor. Sınıfa sembolik olarak bir kaç nitelik ve ezilmiş to_s metodunu ekledik. Bizi ilgilendiren kısım ise Object sınıfı üzerinden çağırdığımız const_get fonksiyonu. Bu, parametre olarak "Game::Player" şeklinde bir metin almakta. Player sınıfı bir modül içerisine yer aldığından :: notasyonuna başvuruyoruz. Bu satır ile Player tipinden bir örnek üretiliyor ve obj isimli değişkene aktarılıyor. Player.new gibi bir oluşumdan farklı bir şey yaptığımızı fark ediyorsunuz değil mi? Nitekim obj.new ile Player nesnesi oluşturmaktayız evet ama nesne adı string olarak gelmekte. Hatta yapıcı metoda parametrelerini gönderip to_s metodunu da kullanıyoruz. İşte çalışma zamanı çıktıları.

define_method ile Çalışma Zamanında Metod Oluşturmak

Ruby dilini öğrenmeye çalışırken özellikle dinamik olması ve meta-programlama yetenekleri içermesi nedeniyle anlamakta zorlandığım pek çok kısım oluyor. define_method'da bunlardan birisi. Temel olarak çalışma zamanında metod üretebilmemize izin veren bir fonksiyonellik olarak düşünebiliriz. Konuyu öğrenirken ki tek sıkıntım işe yaramayacak olsa da nasıl uygulandığını gösteren bir örnek bulmak oldu. İlk olarak aşağıdaki gibi bir sınıfımız olduğunu düşünelim.

class GameZone
  def title=(zone_name)
    @title=zone_name
  end
  def title
    @title
  end
  def capacity=(player_count)
    @capacity=player_count
  end
  def capacity
    @capacity
  end
  def color=(color)
    @color=color
  end
  def color
    @color
  end
end
rogue_one=GameZone.new
rogue_one.title="Rogue One"
rogue_one.capacity=48
rogue_one.color="black"
puts rogue_one.title,rogue_one.capacity,rogue_one.color

Bu kod parçasında GameZone isimli bir sınıf ve bir kaç nitelik metodu tanımı görüyoruz. Aslında title,capacity ve color nitelikleri için attr_accessor da kullanılabilir ki genelde öyle yapılıyor ancak amacımız bu metod ihtiyaçlarının çalışma zamanında nasıl üretilebileceğini görmek. Aşağıdaki kod parçasını inceleyince ne demek istediğimi daha iyi anlayacaksınız.

class GameZoneV2
   PROPERTIES=["title","capacity","color"]
   PROPERTIES.each{|p|
     define_method("#{p}="){|i|
       instance_variable_set("@#{p}",i)
     }
     define_method("#{p}"){
       instance_variable_get("@#{p}")
     }
   }
end
zone_gold=GameZoneV2.new
zone_gold.title="Gold zone"
zone_gold.capacity=34
zone_gold.color="Gold"
puts zone_gold.title,zone_gold.capacity,zone_gold.color

GameZoneV2 içerisinde yine sihirli bir şeyler var. PROPERTIES isimli dizi içerisindeki her bir eleman için getter ve setter metodları define_method yardımıyla çalışma zamanında üretilmekte. each bloğu içerisinde her bir p değişkeni(PROPERTIES elemanı) için iki define_metod çağrısı söz konusu. İlkinde = ile biten setter metod oluşturuluyor ki burada instance_variable_set ile atama bildirimi de yapılmakta. İkinci define_method ile de getter fonksiyonu tanımlamakta. Kodun ilerleyen kısımlarında zone_gold isimli nesne örneği üzerinden title, capacity ve color niteliklerinin kullanılabildiğine şahit oluyoruz. İşte çalışma zamanı sonuçları.

Demek ki çalışma zamanında gelecek bir takım parametrelere göre sınıflara farklı operasyonları eklememiz mümkün. Dikkat edin çalışma zamanında diyorum.

self.class.send Kullanarak metod işletmek

Olayı biraz daha ilginç hale getirmeye ne dersiniz? Mesela sınıfa dahil etmek istediğimiz getter ve setter metodlarının sahibi olacak nitelikleri de dışarıdan verebiliyor olalım. Aşağıdaki kor parçasını bu anlamda ele alabiliriz.

class Person
  def createGetterSetter(*args)
    Array(args).each{|attr|
      self.class.send(:define_method,"#{attr}="){|v|
        instance_variable_set("@#{attr}", v)
      }
      self.class.send(:define_method,"#{attr}") {
        instance_variable_get("@#{attr}")
      }
    }
  end
end
logan=Person.new
logan.createGetterSetter("name","salary")
logan.name="burki"
logan.salary=1250
puts "#{logan.name}-(#{logan.salary})"

Person sınıfı içerisinde yer alan createGetterSetter metodu değişken sayıda parametre alabilmektedir. İçinde yer alan each bloğunda her bir argüman için birer getter ve setter metodu tanımlanması sağlanmaktadır. Burada dikkat edilmesi gereken nokta define_method'un kullanım şeklidir. define_method private tanımlanmış bir sınıf fonksiyonudur. Bunu Player örneği üzerinden çağırmak için self.class.send şeklinde bir yol izlenmelidir. Kodun ilerleyen kısımlarında createGetterSetter metoduna örnek iki eleman yollanmış ve kullanılmıştır.

Aynı örnekte işi biraz daha ileriye götürebiliriz. Zaten attr_accessor bir nitelik için gerekli getter ve setter operasyonlarını hazır olarak sunmaktadır. Peki aynı örnekteki nitelikleri attr_accessor ile tanımlayabilir miyiz? Tabii çalışma zamanında. Aşağıdaki kod parçası işimizi görecektir.

class Person
  def createAttr(*args)
    Array(args).each{|attr|
      self.class.send(:attr_accessor,"#{attr}")
    }
  end
end
logan=Person.new
logan.createAttr(:name,:salary)
logan.name="burki"
logan.salary=1250
puts "#{logan.name}-(#{logan.salary})"

Yine self.class.send metodunun kullanıldığına dikkat edelim. Bunun dışında createAttr metoduna :name ve :salary isimli iki symbol göndermekteyiz.

Görüldüğü gibi metinsel olarak gelen bir kod parçasını çalışma zamanında işletmemiz mümkün. Bir sınıfa çalışma zamanında gelecek bilgiler ve yönergeler doğrultusunda yeni fonksiyonellikler katmamız da söz konusu. Bir sınıfı adından yola çıkarak örneklememiz veya içerisindeki değişmez değeri yakalamamız da mümkün. Daha yapılabilecek pek çok şey olduğu da ortada. Bunları ilerleyen bölümlerimizde incelemeye gayret edeceğim. Böylece geldik bir kod parçasının daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

Ruby Kod Parçacıkları 30 - Programın Çalışma Zamanını İzlemek

$
0
0

Merhaba Arkadaşlar,

Diyelim ki geliştirdiğimiz kodların çalışma zamanındaki işleyişlerini izlemek istiyoruz. Sırasıyla hangi nesneler örnekleniyor, çağırılan metodlar ve varsa sonuçları hangi aşamada icra ediliyor, devreye giren C veya block çağrıları bulunuyor mu? Bu gibi sorular aslında bir uygulamayı Monitor etmek olarak da adlandırılmakta. Büyük kod parçalarında işleyiş sıralarını takip etmek ve olası istisna durumlarında kodun hangi aşamada kalmış olduğunu görmek açısından değerli bir konu. Peki Ruby kodlarının çalışma zamanı işleyişlerini nasıl izleyebiliriz. Konu ile ilgili bir çok gem veya API olsa da gömülü olarak gelen TracePoint sınıfı bize basit anlamda izleme kabiliyetleri sunmakta. Aşağıdaki örnek kod parçasını bu anlamda ele alabiliriz.

@call_depth=0
TracePoint.trace(:c_call,:call,:class,:end,:b_call){|t|
  @call_depth+=1
  puts "#{t.path} #{t.defined_class}.#{t.method_id} Line : #{t.lineno} Event : #{t.event}"
}

TracePoint.trace(:return,:b_return){|t|
  puts "#{t.path} Line :  #{t.lineno} Event : #{t.event} Value :  #{t.return_value}"
  @call_depth-=1
}

class Player
  attr_accessor :nick,:level
  
  def initialize(nick,level)
    @nick,@level=nick,level
  end
  
  def Move(location)
    "Move to #{location}"
  end
end

players=[]
players<<Player.new("master vindu",19000)
players<<Player.new("luk skay valkr",21000)
players<<Player.new("princes leya",13400)
players<<Player.new("obi van kinobi",90980)
players.each{|p|
  p.Move("istanbul")
  p.level+=10
}

Player tipinden bir sınıfla ilgili işlemler yapıldığını görüyoruz. nick ve level şeklinde iki nitelik içeren bu sınıfa ait 4 farklı nesne örneği bir dizi içerisinde toplanıyor. Sonrasında bu dizi üzerinden örnek kod bloğu çağırılıyor. Block içerisinde her bir oyuncu için Move operasyonu gerçekleştirilip level değerleri 10ar birim arttırılıyor. Acaba bu işleyişin arka plandaki izleri nasıl? Bunun için kodun en başında TracePoint sınıfının trace metoduna çağırılar yapıldığını görmektesiniz. trace metodu parametre olarak izlenmek istenen olay veya olaylar zincirini alıyor. Birer symbol olarak gelen bu parametrelerin farklı anlamları var. Aslında bunların her biri bir olaya karşılık geliyor. Örneğin :call ile ruby metod çağrılarının gerçekeştiği anları izleyeceğimizi belirtiyoruz. :c_call ise C fonksiyon çağrılarını işaret etmekte. :b_call sembolü tahmin edeceğiniz üzere block çağrılarını takip etmek istediğimizde kullanılıyor. :class ve :end symbol'leri ile sınıf tanımlamalarının yapıldığı ve bittiği kod anlarını izleme şansına sahibiz. 

Dikkat edilmesi gereken hususlardan birisi de iki trace çağrısı yapmamız. İkinci parçada metodların dönüş yaptığı yerleri izleyeceğimizi belirtmekteyiz. :return normak fonksiyon çağrılarını işaret ederken, :b_return yine tahmin edileceği üzere değer dönüşü olan block'ları belirtmekte. 

trace metodları içerisinde işleyişin o anki zamanına ait bir takım bilgileri ekrana bastırıyoruz. Örneğin hangi sınıfın hangi metodunun kullanıldığını, satır numarasını, varsa metod/block dönüş değerlerini ve gerçekleşen olayı bastırmaktayız. Pek tabii bu bilgiler ekran yerine loglama amacıyla farklı veri ortamlarına da kayıt ediliebilirler. Yukarıdaki kod parçasının çalışma zamanı çıktısı ise aşağıdaki gibi olacaktır.

D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb #<Class:TracePoint>.trace Line : 7 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Class.inherited Line : 12 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb . Line : 12 Event : class
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Module.attr_accessor Line : 13 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Module.method_added Line : 13 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Module.method_added Line : 13 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Module.method_added Line : 13 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Module.method_added Line : 13 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Module.method_added Line : 15 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Module.method_added Line : 19 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb . Line : 22 Event : end
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Class.new Line : 25 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Player.initialize Line : 15 Event : call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Line :  17 Event : return Value :  ["master vindu", 19000]
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Class.new Line : 26 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Player.initialize Line : 15 Event : call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Line :  17 Event : return Value :  ["luk skay valkr", 21000]
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Class.new Line : 27 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Player.initialize Line : 15 Event : call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Line :  17 Event : return Value :  ["princes leya", 13400]
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Class.new Line : 28 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Player.initialize Line : 15 Event : call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Line :  17 Event : return Value :  ["obi van kinobi", 90980]
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Array.each Line : 29 Event : c_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb . Line : 29 Event : b_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Player.Move Line : 19 Event : call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Line :  21 Event : return Value :  Move to istanbul
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Line :  32 Event : b_return Value :  19010
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb . Line : 29 Event : b_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Player.Move Line : 19 Event : call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Line :  21 Event : return Value :  Move to istanbul
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Line :  32 Event : b_return Value :  21010
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb . Line : 29 Event : b_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Player.Move Line : 19 Event : call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Line :  21 Event : return Value :  Move to istanbul
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Line :  32 Event : b_return Value :  13410
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb . Line : 29 Event : b_call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Player.Move Line : 19 Event : call
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Line :  21 Event : return Value :  Move to istanbul
D:/Users/bsenyurt/rubyWorkSpace/Ruby101/TraceMeSample.rb Line :  32 Event : b_return Value :  90990

Dikkat edileceği üzere takip etmek istediğimiz olayların çalışma zamanına ait bilgileri ekrana basılmıştır. Bunu daha düzgün bir formatta yazarsak okunabilir bir Trace çıktısı elde etmemiz içten bile değil. Bu taktiği daha karmaşık Ruby kodlarında uyguladığımızda çalışma zamanında ceyran eden olayları izleyerek işleyiş hakkında detaylı bilgilere sahip olmamız mümkün. Hatta süre bilgisini de ekleyerek metod geçişleri arasındaki farkları izleyebilir ve uygulamanın yavaş işleyen parçalarını tespit edebiliriz. TracePoint sınıfına ait detaylı bilgilere şu adresten ulaşabilirsiniz. Böylece geldik bir ruby kod parçacığının daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

Ruby Kod Parçacıkları 31 - Kendi gem Paketimizi Hazırlamak

$
0
0

Merhaba Arkadaşlar,

Bildiğiniz gibi günümüz popüler programlama dillerinin çoğunun internet üzerinden ulaşılabilen paket destekleri mevcut. Özellikle açık kaynak tabanlı ürünlerde önem verilen bir konu olduğu ortada. Yazılımcıların birbirlerinin kullanımına açtığı bu paketler Ruby tarafında da mevcut ve gem olarak adlandırılmaktaHatta şu adresten bir çok değerli mücehvere ulaşabilir kendi paketlerinizi de yükleyebilirsiniz. Peki kendi gem paketlerimizi en basit haliyle nasıl yazabiliriz? Hatta yazdığımız bir gem'i herkesin kullanımına nasıl açabiliriz? Gelin bu konuyu kısaca incelemeye çalışalım. 

Bazı firmalarda katı güvenlik kuralları olabilir. Örneğin bir bankanın geliştirme ortamlarından, NuGet, RubyGems gibi küresel paket sağlayıcılarına erişim izni verilmeyebilir. Bu gibi hallerde güvenlik denetimlerinden geçmiş olup geliştiricilerin kullanabileceği paketlerin sunulması için şirket ağı üzerinde paket depoları oluşturulabilir.

Paket için Klasör Yapısı

Bir gem üretmeden önce belli bir ağaç yapısını sistem üzerinde oluşturmamız gerekir. Aşağıdaki ekran görüntüsünde bu işin en yalın halini görmektesiniz. Ancak pakete ilişkin teknik dokümantasyon, paketle birilikte kullanılacak yürütülebilir dosyalar gibi diğer kaynaklara da ihtiyaç varsa farklı klasörleri konuşlandırmak gerekir. İcra edilebilir(Executable) dosyalar için bin, Unit Test'ler için test isimli klasörler vb.

Paket İçeriğini Hazırlayalım

Paketimizin adı Einstein. İçerisinde lib isimli bir klasör ve gemspec uzantılı bir dosya var. Kodlarımızı lib klasörü içerisinde tutmamız gerekiyor. Einstein.rb dosyasına ait kod içeriği aşağıdaki gibi oluşturulabilir.

#Einstein Gem
module Algebra
	class Common
		def self.factorial(number)
			if(number==0)
				return 1
			else
				return number*factorial(number-1)
			end
		end
		def self.sum(*numbers)
			total=0
			numbers.each{|n|total+=n}
			total
		end
	end
end

Sadece pratik olması açısından iki fonksiyonellik sunduğumuz basit bir sınıf söz konusu. Bir sayının faktöryelini ve n sayıda rakamın toplamını hesap eden operasyonlar Algebra modülündeki Common sınıfında yer alıyor(self kullanımı nedeniyle sınıfı örneklemeden ilgili fonksiyonellikleri çağırabileceğimizi hatırlatalım)Önemli olan kısım gemspec uzantılı dosya içeriği. Paket ile aynı isimde olan dosya da aslına bakarsanız ruby kodları içermekte. Dikkat edilecek olursa Specification tipinden yeni bir nesne oluşturuyor ve bazı niteliklerine değerler atılıyor.

Gem::Specification.new do |s|
  s.name        = 'BuraksEinstein'
  s.version     = '0.0.2'
  s.date        = '2016-12-20'
  s.summary     = "Simple and funny math operations for kids"
  s.description = "A Simple and Funny Math"
  s.authors     = ["Burak Selim Senyurt"]
  s.email       = 'selim@buraksenyurt.com'
  s.files       = ["lib/einstein.rb"]
  s.homepage    = 'http://rubygems.org/gems/einstein'
  s.license     = 'MIT'
end

Bu dosyayı paket ile ilgili temel bilgileri içeren bir manifesto olarak düşünebilirsiniz. Paket adı, versiyon numarası, ne yaptığının özeti, kimin yazdığı, irtibat için elektronik posta adresi, lisanslama modeli ve içerisinde kullanılan kod dosyası vb pek çok bilgi bu dosya içerisinde bildirilmekte.

Paketin Üretilmesi

Kod ve manifesto içerikleri hazırlandıktan sonra gem aracını kullanarak paketin oluşturulması ve test adımlarına geçilebilir. Komut satırından yapacaklarımız aşağıdaki ekran görüntüsünde olduğu gibidir.

Dilerseniz neler olduğuna sırasıyla bakalım. İlk olarak bir build işlemi gerçekleştirmekteyiz. Bu işlem sonrasında gem uzantılı bir dosya oluşur. manifesto içerisinde belirtilen versiyon numarasına göre farklı gem içerikleri üretilebilir. Bu sayede kütüphanenin kullanılacağı platform için farklı sürümlerin değerlendirilmesi de mümkün olabilir(Özellikle güncellenen ürünlerin eski sürümleri ile bir süre daha paralel çalışması gerektiği hallerde önem kazanan bir uygulamadır) gem için build komutu sonrası bunu kendi sistemimizde denemek adına install işlemi gerçekleştiriyoruz(3 numara) Dikkat edilecek olursa paket adını yazarken versiyon numarasını da belirttik(Bir başka deyişle sistemimize farklı versiyonları da yükleyebiliriz) Paketin oluşturulması yeterli değil. Bunu kolay bir şekilde deneyip çalıştığından emin olmakta yarar var. irb üzerinden factorial metodunu kullanarak 8 sayısının faktoryelini hesaplıyoruz (İşte test klasörünün oluşturulması ve test metodlarının icra edilmesi bu noktada anlam kazanan bir durum. Yazımızda yer vermedik ancak kaynak bağlantıdan bakarak konu hakkında detay bilgi alabilirsiniz.)

Paketi RubGems.org Sitesine Aktarmak

Buraya kadar her şey yolunda gitti. Kodlarımızı kendi sistemimizde gem paketi haline getirip başarılı bir şekilde denedik. Peki bunu herkesin ortaklaşa kullanabileceği paket sunucusuna nasıl atabiliriz? Öncelikle rubygems.org'a üye olmamız ve bizim için üretilecek uygulama anahtarına(rubygems_api_key olarak geçiyor) ihtiyacımız var. Üyelik işlemi sonrası ilgili anahtarı üretmek için komut satırından curl aracından yararlanabilir veya paketin ilgili sunuculara gitmesi için gerekli credentials dosyasının içeriğini manuel olarak çekebiliriz. Tek yapmamız gereken üyelik işlemi sonrası https://rubygems.org/api/v1/api_key.yaml adresine gidip kullanıcı adı ve şifre bilgisini girdikten sonra indirilen yaml içeriğini credentials dosyasına koymak. Eğer her şey yolunda giderse aşağıdaki ekran görüntüsünde olduğu gibi paketin sunucuya atıldığını görebiliriz. Bunun için gem aracını push komutu ile birlikte kullanmamız yeterlidir. 

Artık BuraksEinstein isimli paketimiz rubygems sitesinde kendisine bir yer buldu. Aslında örneği Einstein isimli bir paketi atacak şelilde geliştirmiştim ancak bu isimde zaten bir çok paket olduğundan hata aldım. Paket adının BuraksEinstein olmasının sebebi bu.

Pek tabii bu gem'in de kullanılıp kullanılmadığını denememiz lazım. Bu yüzden ilgili paketi sistemimize yüklemeyi deneyerek ilerleyelim. Sonrasında da irb'den bir test yapalım. 

Görüldüğü gibi yazdığımız bir gem paketini RubyGems.org sitesine yükleyebildik. Ruby ile geliştirdiğimiz paketleri bu şekilde ekleyebilir ve başka geliştiricilerin kullanımına açarak diğer Rubyist'leri sevindirebiliriz. Elbette işe yarar paketler yazmamı önemli. Buradaki tek eksi sanıyorum ki gem içeriklerinin kontrol edilemeyişi. Yani kötü amaçlı gem paketleri de bu sunuculara atılabilir mi bilemiyorum. Böylece geldik bir makalemizin daha sonuna. Bir başka kod parçacığında görüşünceye dek hepinize mutlu günler dilerim.

Kaynak : http://guides.rubygems.org/make-your-own-gem/

Tek Fotoluk İpucu 149 - SecureString ile Caydırıcılık

$
0
0

Merhaba Arkadaşlar,

Elimizde veritabanı bağlantı bilgisi, kullanıcı şifresi, uygulamamıza özel port numaraları, finansal oranlar gibi hassas olabilecek içerikleri tutan bir sınıf olduğunu düşünelim. Bu sınıfı kullanmak için doğal olarak bir şekilde örneklenmesi gerekir. Nesnenin kullanılabilir olması içeriği ile birlikte belleğe açılması anlamına da gelir. Uygulama, .Net'in çalışma zamanı ortamında kendisi için oluşturulan Application Domain içerisinde yaşar.

Peki bu metinsel içeriklerin bellekte güvenli bir şekilde durduklarını söyleyebilir miyiz? Belleğe açılan uygulamaların izlerini takip etmek aslında mümkün. RedGate ve benzeri araçlar yada uygulamanın çalışma zamanındaki bellek hareketliliklerini indiren Memory Dump programları ile bu mümkün olabilir. Dolayısıyla belleğe alınmış bir değişken içeriğinin güvenli şekilde saklanmasını sağlamamız önemlidir. SecureString sınıfı bu ihtiyacı karşılamak için kullanılan .Net sınıflarındandır. Nasıl mı? Aynen aşağıdaki fotoğrafta görüldüğü gibi.

SecureString sınıfını örnekledikten sonra string içeriğin önce karakter katarına dönüştürülmesi sonra her bir karakterin AppendChar sınıfı ile ilave edilmesi söz konusu. MakeReadOnly çağrısı ile ilgili nesne örneğinin Immutable olması sağlanmakta. Protect fonksiyonunu extension metod olarak yazdığımıza dikkat edelim. Tabii buradaki beklenti myPassword değişkeninin şifrelenmiş olarak ekrana basılması değil. Konu, belleğe yerleşen değişken içeriğinin okunma ihtimaline karşı şifrelenerek korunması.

Elbette SecureString ile koruma altına aldığımız içerikleri çalışma zamanı içerisinde elde etmemiz mümkün. Aşağıdaki kod parçası bunun sağlaması gibi düşünülebilir. 

Hafiften StringExtensions sınıfımızı ve Protect metodumuzu bozduk. Marshal tipine ait fonksiyonellikleri kullanarak da Unmanaged Code tarafına geçerek CLR dışı alanlara bulaştık. Sadece işin sağlaması için yaptığımızı tekrar belirtelim. Böylece geldik bir ipucunun daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

Go Dilini Anlamaya Çalışırken

$
0
0

Merhaba Arkadaşlar,

Liseye başladığım 1990 yılından beri arkadaşım ve aynı zamanda adaşım olan sevgili dostum Burak ile üniversite yıllarında öğrenip oynamaya başladığımız GO oyunu geldi aklıma. Öğrenmesi zor, kavramak için yıllar geçmesi gereken, iyi bir oyuncu olmak için sizden daha iyi birisiyle yine yıllarca maç yapmanızı gerektiren zevkli bir strateji oyunu. Ünlü matematikçi John Forbes Nash'ten Albert Einstein'a, Alan Turing'den Bill Gates'e tarihi değiştiren pek çok kişinin de oynadığı bir oyun.

Go oldukça yüksek kombinasyon değerlerine sahip olduğundan bir insanı yenebilecek yapay zekanın geliştirilmesi de zaman aldı. Google'ın DeepMind ekibi tarafından yazılan AlphaGo isimli yapay zeka Ekim 2015'te bu durumu değiştirdi. 19X19luk bir tahtada 9ncu Dan'dan olan Lee Sedol'u 4-1 yenmeyi başarmış bir program. Bu arada IBM'in, Garry Kasparov ile 1-1 biten maçın kahramanı olan Deep Blue'dan sonra geliştirdiği ikinci versiyonu Deeper Blue, Kasparo'u 1997'de yenmeyi başarmıştı. Bundan yıllar yıllar sonra GO'da galip gelebilen bir programın yazılması oyunun ne kadar zorlayıcı olduğunun da bir göstergesi.

Google'ın GO kelimesi ile olan ilk teması AlphaGo değil. 2007 yılında Go isimli bir programlama dili çıkarttılar. Unix'in yaratıcısı olan Ken Thompson(ki bu yeni dilde onun izlerine rastlıyoruz), yine Unix takımından olan Rob Pike ve Google'dan Robert Griesemer tarafından geliştirilen bu dilin ilk etapta sistem programlama için tasarlandığı ifade edilmekte. 2009 yılında resmen duyurulmuş olan dil zaten Google'ın üretim bandındaki sistemlerinde aktif olarak kullanılmakta. Benim en çok ilgimi çeken hususlardan birisi ise TIOBE endeksindeki son bir yıllık yükselişi. 50nci sıradan 16ya sıçrıyor.

O zaman bu GO dili de neymiş? Ben öğrendim ilk iki haftada. İşte okuduğum dökümanlardan derlediğim bazı kısa notlar.

Karakteristiği

İlk başta dilin genel özelliklerine bakmakta yarar var. Okuduğum kaynaklardan şu özet bilgileri çıkartabildim.

  • Nesne yönelimli(Object Oriented) bir dil değil ve bu yüzden sınıf(class), kalıtım(inheritance) gibi kavramlar içermiyor. Inheritance yerine Composition mümkün ama. Güle güle SOLID diyebilir miyiz bilemedim. Bunlara karşın Interface ve Type Embedding desteği mevcut.
  • Derleme süresi yüksek bir dil. Zaten kulislerde dilin yüksek performansından sıklıkla bahsedilmekte.
  • MultiThreading sistemlerin önemli konularından olan Concurrency işleyişi sık kullandığımız C#, Java dillerindeki gibi Actor tabanlı değil de, Communicating Sequential Process isimli diğer bir metodolojiye dayanıyor. CSP'de Process'ler arası mesaj gönderimi karşılıklı anlaşmaya bağlı. Yani bir Process diğerine mesaj göndermek istiyorsa diğer tarafın bu mesajı almaya hazır olması(veya dinliyor olması) gerekiyor. Bir nevi senkronize mesaj trafiği var diyebiliriz. Actor modelde ise Process'ler arası mesajlaşmaların asenkron işleyebildiğini görüyoruz. Yani dinleyicilerin mesajları almaya hazır olup olmamasının bir önemi yok. Diğer yandan CSP modelinde process'ler isimsiz oluşurken Actor model'de benzersiz bir tanımlayıcı değere sahip olmalılar. Actor modelin CSP'den önce geliştirildiğini de belirtelim. Son söz olarak Go dilinin kendi içerisinde light-weight concurrency desteği verdiğini de söyleyelim. Çok parçacıklı işlerde Go doğuştan kabiliyetli diyebiliriz belki de.
  • C ve C++ dillerinden aşina olduğumuz, üniversite eğitimi sırasında kafamızı paramparça eden Pointer kavramı Go dilinde de mevcut. Ne var ki Pointer aritmetiği veya fonksiyonlardan geriye Pointer döndürmek gibi zorlayıcı şeyler yok.
  • Bellek yönetimi için kullanılan bir Garabage Collector mekanizması var.
  • En büyük özelliklerden birisi tabii ki de kodun doğrudan makine diline derlenmesi. Java tarafındaki Java Virtual Machine veya .Net dünyasındaki Common Language Runtime gibi ara katmanlar bulunmuyor.
  • Static tip sistemine sahip. Booelan, Numeric, String gibi ana tipler dışında Pointer, Array, Structure, Function, Slice, Interface, Map ve Channel gibi tipler de söz konusu.
    Integer Types -> uint8,uint16,uint32,uint64,int8,int16,int32,int64
    Floating Types -> float32,float64,complex64,complex128
    Diğer Numeric Tipler -> byte,rune,uint,int,uintptr
    Tip zenginliği içeren bir dil olarak da ifade edilmekte. 8 bitlik işaretli işaretesiz tamsayılar dişında 64 ve 128 bitlik float kompleks sayılara da yer verilmiş. Açıkçası Üniversiteden beri Pointer kullanmayan birisi olarak Map, Channel, Slice,rune gibi tiplerin ne işe yaradığını çok merak ediyorum. Çalışıp öğreneceğiz.
  • Küçük büyük harf duyarlıklı bir dildir(Case Sensitive)
  • Tabii olmayan bir çok şey de var. Bir C# programcısı, Ruby ve Python meraklısı olarak benim de "yok artık" dediğim durumlar söz konusu. Örneğin metodların veya operatörlerin davranışlarını değiştiremiyoruz(Yani overloading desteği yok) Ayrıca generic bir programlama ortamı söz konusu değil. GO dilinde Package odaklı bir geliştirme bulunuyor ve paketler arası Circular Dependency desteği de bulunmuyor. 

Merhaba Diyelim

Bir Hello World desek iyi olmaz mı? E hadi o zaman. Öncesinde GO'nun derleyicisini sistemimize kurmamız gerekiyor. Bu adresten de görebileceğiniz gibi neredeyse tüm platformlar için bir derleyici söz konusu. Linux, Max OS X, FreeBSD ve son olarak Windows. Elinizin altında bir GO derleyicisi olmayabilir. Benim gibi şirket bilgisayarına program indirip yükleme yetkiniz yoksa, alternatif yollara ihtiyacınız var demektir. Cidden tutturduysanız "Go öğreneceğim Go öğreneceğim, yemek aralarında, sabah mesai öncesinde, akşam mesai sonrasında vakir ayıracağım" diye, bu adresteki gibi online IDE'leri de kullanabilirsiniz.

İlk uygulama kodumuzu aşağıdaki gibi geliştirebiliriz.

/*
 Bu benim ilk GO programım.
 Sevdim gibi sanki.
*/
package main

import (
	"fmt"
	"math/rand"
)

func main() {
	fmt.Println("Hoş geldin öğrenci\nBugün ki şanslı sayın")
	fmt.Println(GetRandomNumber(36))
}
func GetRandomNumber(seedValue int64) int{
	rand.Seed(seedValue)
	var luckyNumber int
	luckyNumber=rand.Intn(100)
	return luckyNumber
}

Öncelikle çalışma zamanı çıktısına bir bakalım.

Program temel olarak selamlama yapmakta ve sonrasında rastgele bir sayı üretmektedir(Online çalıştığınız ortam, oturum-session kullanımı sebebiyle sürekli olarak aynı rastgele sayıyı üretebilir. Size tavsiyem kişisel bilgisayarınıza GO yükleyip aynı kodu notepad++ gibi bir editör ile yazdıktan sonra komut satırından go run programadi.goşeklinde çalıştırmanız olacaktır) Program anlamlı bir şeyler yapmasa da üzerinde konuşulması gereken bir çok konuyu içermekte. Şimdi bunlara bir bakalım.

Kodun Analizi

İlk olarak aşağıdaki çizelgeyi ele alalım derim.

Go paket(Package) mantığı üzerine kurulu bir dildir. Uygulama main paketi ile başlamak zorundadır ve programın giriş fonksiyonu main'dir. import ifadesinde bu pakette kullanılacak olan diğer paketlere yer verilmiştir. Eğer programa eklediğimiz pakete ait üyeleri kod içerisinde hiç bir yerde kullanmıyorsak derleme zamanında imported and not used : "os" benzeri bir hata almamız muhtemeldir(os bir Go paketidir. Hata mesajında bunun yerine kullanılmayan hangi paket/paketler varsa onları adı gelecektir) GO dili ile birlikte gelen diğer paketlere şu adresten bakabilirsiniz. 

main metodu entry point'imizdir. İçerisinde fmt paketinden Println fonksiyonunun kullanımı söz konusudur. Tahmin edileceği üzere Println ile ekrana Console ekranına bilgi yazdırıp bir alt satıra geçilmesi sağlanır. İlk ifadede \n gibi bir escape karakteri de kullanılmıştır. İkinci ifade biraz daha dikkate değerdir. Println fonksiynu içerisinde GetRandomNumber metoduna bir çağrı yapılır. Çok şaşırtıcı bir durum değil aslında. Fonksiyona parametre olarak bir başka fonksiyon çağrısının sonucunu veriyoruz. GetRandomNumber, seedValue isimli 64 bitlik bir tamsayı alır ve geriye int tipinden(varsayılan olarak 32 bitlik tamsayıyı işaret eder) bir değer verir. Fonksiyon içerisinde rand paketinden Seed ve Intn isimli fonksiyonlara çağrılar gerçekleştirilmiş ve elde edilen sayı geriye döndürülmüştür.

Metodda ayrıca luckyNumber isimli bir yerel değişken(local variable declaration) tanımlanmıştır. Metod dışında paket seviyesinde değişkenler de tanımlanabilir(Global Variables) Bu tip global değişkenler tanımlandıkları noktadan itibaren kodun kalan kısmında kullanılabilir. luckyNumber değişkeni statik tip tanımlamasına bir örnektir. var anahtar kelimesinden sonra değişken adı ve son olarak değişkenin tipi gelir. Dinamik değişkenler de tanımlayabiliriz. pi:=3.14 gibi bir ifadeyi buna örnek  gösterebiliriz. Tabii ki burada C#'tan tanıdık gelecek Type Inference söz konusudur. Yani derleyici eşitliğin sağ tarafındaki değerin hangi tipe uygun olacağını tahmin ederek işlem gerçekleştirir. Yeri gelmişken Go dilinde de az sayıda anahtar kelime(Keyword) bulunduğunu belirtelim. 

breakdefaultfuncinterface
selectcasedefergo
mapstructchanelse
gotopackageswitchconst
fallthroughifrangetype
continueforimportreturn
var   

Katı Yazım Kuralları

Go katı yazım kurallarına sahip bir dil gibi görünüyor. Burada katılıktan kasıt sadece case-sensitive olma olayı değil. Aşağıdaki hata mesajlarına baktığınızda ne demek istediğimi biraz daha iyi anlayacaksınız.

{ yerleşim durumu

import'taki paket adlarının yerleşimi 

main paketinin olma zorunluluğu

Tanımlanmış ama kullanılmayan paket durumu

main'in ilk fonksiyon olma zorunluluğu

Ha haa...Şaka yaptım. Öyle bir şey yok neyse ki.

Go bende merak uyandıran bir dil. Dokümanları taramaya devam ediyorum. Merak ettiğim pek çok yanı var. Başka dillerle olan benzerlikleri veya farklılıkları söz konusu. İlerleyen zamanlarda farklı Go yazıları ile görüşmek üzere hepinize mutlu günler dilerim.

Tek Fotoluk İpucu 150 - Sertifika Tabanlı REST Çağrısı Yapmak

$
0
0

Merhaba Arkadaşlar,

Geçtiğimiz günlerde üzerinde çalıştığımız projede şöyle bir ihtiyaç oldu: Uygulamanın şirket ağı dışındaki bir kuruma ait REST(Representational State Transfer) tabanlı servis noktalarını kullanması gerekiyordu. Bu noktalara göndereceğimiz HTTP Get,Post taleplerine göre bir takım sonuçlar alacak ve kurum içi süreçleri işletecekti. Söz konusu servis ve sunduğu EndPoint'ler ile olan iletişim ise X509 standardındaki bir sertifika üzerinden gerçekleştirilmeliydi. Test ortamında yaptığımız çalışmada, sunucu sertifikasının doğrulanması sonrası devreye girecek Callback operasyonunda hata mesajı aldık. Kurumla yaptığımız mutabakat sonrasında ise bu adımı atlayabileceğimizi öğrendik. Çözüm olarak küçük bir hile yaptık. Nasıl mı? Aynen aşağıdaki fotoğrafta görüldüğü gibi.

InternalWebClient, WebClient tipinden türetilmiş bir sınıf. Bu nedenle REST servisleri ile iletişim için gerekli temel fonksiyonlara sahip. Önemli olan ise GetWebRequest metodunun ezilmiş(override) olması. Bu fonksiyon bir web kaynağına doğru yapılan çağrılarda devreye giriyor. Metodun içinde ilk olarak HttpWebRequest örneği yakalanıyor. Ardından sertifikayı yüklüyor ve ServerCertificateValidationCallback temsilcisini(delegate) hile yolu ile devre dışı bırakıyoruz(senaryomuzda geriye hep true döndürmek üzere kurgulandı) Böylece InternalWebClient sınıfının tanımlanan ByPassCertValidateCallback özelliğine atanan değere göre sertifika ile ilgili Callback sürecinin atlanması veya atlanmaması sağlanıyor. 

Senaryomuzda WebClient türevli bir sınıf kullanmamızın sebebi, DownloadString DownloadData ve DownloadFile gibi REST servisine yapacağımız çağrı sonrası gelecek içerikleri kolayca almamızı sağlayan metodlar sunmasıydı. Ama sertifika senaryosunda yaşadığımız sorunu aşmak için minik bir takla atıp WebClient sınıfından gelen ve talebin(Request) hazırlandığı sırada devreye giren bir metodun davranışını değiştirmemiz gerekti.

Böylece geldik bir ipucumuzun daha sonuna. Başka bir ipucunda görüşünceye dek hepinize mutlu günler dilerim.

Tek Fotoluk İpucu 151 - C#, Reflection ve About Info

$
0
0

Merhaba Arkadaşlar,

Programlardaki About Info kısımlarını bilirsiniz. Yazdığımız uygulama hakkında bir takım bilgiler verir. Genellikle ürünün adı, bir iki cümle ile ne yaptığı, üreticisi ve hatta versyion numarası ve benzeri bilgiler yer alır. Micorosoft .Net tarafında aslında bu tip bilgileri Assembly'a ait niteliklerde(attribute) belirtiriz. Aynen aşağıdaki ekran görüntüsünde olduğu gibi.

Peki bu bilgileri(en azından son kullanıcı için işe yarar olanları) nasıl elde edebiliriz? Visual Basic tarafında olukça kolayken C# tarafında işin içerisine Reflection'ı katmamız gerekir. Aşağıdaki sınıfa bir bakalım.

Aslında kritik nokta Reflection ile Assembly özelliklerinin tutulduğu niteliklere(Attribute) bir şekilde ulaşmak. O an çalışmakta olan Assembly örneğini yakalamakla işe başlıyoruz. GetName ile ulaştığımız değişken üzerinden Name ve Version gibi bilgilere ulaşmak mümkün. Lakin Title, Description, Product, Copyright, Trademark ve Company bilgileri Assembly için birer nitelik olarak tutulmakta. Dolayısıyla çalışma zamanında ilgili nitelikleri çalışmakta olan Assembly için okumamız gerekiyor. Bu işi biraz olsun kolaylaştırmak adına GetValue isimli generic bir metod kullandık. T ile gelen niteliğin property ile belirtilen özellik değerini, current ile işaret ettiğimiz güncel Assembly nesne örneği üzerinden yakalamaya çalışıyoruz. Generic bilgilerinizi tazelemenin tam zamanı. Çalışma zamanı görüntüsü ise aşağıdaki gibidir.

Görüldüğü üzere projeyi derlemeden önce girdiğimiz temel bilgileri çalışma zamanında yakaladık. Elbette bir Console uygulamasında assembly bilgilerini almak çok mantıklı değil. Windows Forms, WPF, Mobile ve benzeri platformlarda bu fonskiyonellik daha çok işinize yarayabilir. Daha da önemlisi envanterde yer alan ne kadar .Net uygulaması varsa onlar hakkında bilgiler alabilir ve belki de bir portal geliştirebiliriz. Hatta geliştirilen uygulamalar için Assembly seviyesinde eksik nitelik bilgilerini de yakalayabilirsiniz. Gerisi sizde. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.


Gopher Olma Çalışmaları

$
0
0

Merhaba Arkadaşlar,

Geçtiğimiz sene Ruby diliye uğraşmaya başlamıştım. Ruby dilini sevenler ve ona gönül verenlere Rubyist deniyor. Benzer bir yaklaşım meğer Go tarafında da varmış. Onlarda kendilerine logolarına esin kaynağı olan Gopher diyorlarmış. Aslında Go dilinin logosu gerçekten bir canlıdan esinlenilerek tasarlanmış. Yaklaşık 15 ila 20 cm boylarında olan gopher'lar oldukça sevimliler(Bana göre) Elbette logo çok daha sevimli. Bu arada Gopher aynı zamanda TCP/IP tabanlı HTTP öncesi bir internet protokolu olarak da geçiyor. Detaylara Wikipedia adresinden bakabilirsiniz.

Benim 2017 hedeflerim arasında Go dilini en azından orta seviyeye kadar öğrenmek var. Oldukça uzun bir sprint olacak ancak geçtiğimiz hafta kendimle yaptığım Sprint planlama toplantısında onu To Do listesine aldım. Bu hafta itibariyle de durumunu In Progress'e çektim.

Gopher olabilir miyim bilemiyorum ama bir dili çok iyi seviyede öğrenmeden o dil hakkında ahkam kesmemek gerektiğine inanıyorum. Geçtiğimiz zaman içerisinde Go ile ilgili dil özelliklerini öğrenmeye devam ettim. Öğrendiklerimi not almaya başladım. Kısa bir Hello World uygulamasından sonra başka temel kavramları da incelemeye koyuldum. İşte en son baktığım konular

Arrays

Belli tipteki elemanaları(herhangibir Go veri tipi olabilir) bir arada tutan(sunan) koleksiyonlara dizi diyebiliriz. Pek çok programlama dilinde olduğu gibi Go'da da kullanılan çekirdek veri yapılarından(data structures) birisidir. Diziler sabit uzunlukta tanımlanırlar. Yani içereceği eleman sayısı baştan bildirilir(Ya da dizinin tanımlandığı satırda atama işlemi yapıldığında uzunluğu belirlenir). Tabii Go söz konusu olunca ileride de göreceğimiz gibi bellek adresleri de önem kazanacak. Diziler için de birbirini takip eden bellek adresleri söz konusu. İlk eleman(bu arada diziler 0ncı indisten başlamakta) dizinin başladığı son eleman da bittiği bellek adresinde konumlanmakta. Go çok boyutlu(Multi Dimensional) dizi yapısına da sahip ve fonksiyonlara dizileri parametre olarak geçirebiliyoruz. Aşağıdaki basit kod parçasında hem diziler ile ilgili temel işlemeler yer alıyor hem de basit for döngülerine yer veriliyor.

package main

import (
	"fmt"
	"time"
	)

func main(){
	// Arrays
	fmt.Printf("Today : %s\n\n",time.Now())
	
	var points=[]float32{10.45,-30.345,55.90,60.0123}
	var names=[4]string{"sarlok","sumi","varlord","khan"}
	var numbers [7]int
	var matrix=[3][3]int{{1,2,3},{4,5,6},{7,8,9}}
	
	for i:=0;i<len(points);i++{
		fmt.Printf("%d is %f\n",i,points[i])
	}
	for i:=0;i<len(names);i++{
		fmt.Printf("%s\n",names[i])
	}
	var j int
	for j=0;j<len(numbers);j++{
		numbers[j]=j*j
		fmt.Printf("%d\t",numbers[j])
	}
	fmt.Printf("\nSum = %f\n",sum(points))
	for i:=0;i<3;i++{
		for j:=0;j<3;j++{
			fmt.Printf("%d\t",matrix[i][j])
		}
		fmt.Println("")
	}
}

func sum(nmbrs []float32) float32{
	var toplam float32=0
	for i:=0;i<len(nmbrs);i++{
		toplam+=nmbrs[i]
	}
	return toplam
}

Çalışma zamanı çıktısı aşağıdaki gibi olacaktır.

Kodda neler olduğuna kısaca bakalım.

Sırf meraktan günün tarihini ve zamanı ekrana nasıl yazdırırım diye Google'a sordum ve bunu main fonksiyonunun ilk satırındaki ifadede denedim. Tabii kullanabilmek için time paketini import etmemiz gerektiği gözünüzden kaçmamış olsa gerek. Array veri yapısı ile çok alakası olmasa da kodu renklendirdiğini düşünüyorum. En azından biraz daha yeşillendirdi.

Örnekte points, numbers, names ve matrix isimli dört dizi kullanılmakta. points dizisi tanımlanırken eleman sayısını belirtmedik ancak süslü parantezler arasına 4 adet float32 tipinden değişken koyduk. Yani eleman sayısı belli. names dizisinde eleman sayısını da veriyoruz. string tipinden elemanlar içeren bir dizi. 7 eleman içeren numbers dizisi sadece tanımlanmış durumda. Elemanlarını bir döngü yardımıyla doldururken her bir kutuya o anki indisin karesini yerleştiriyoruz. matrix isimli dizimiz aslında çok boyutlu kullanıma basit bir örnek. İki boyutlu dizinin elemanları int tipinden. matrix içeriğini Console ekranımıza olabildiğince jan janlı yazdırmaya gayret ettik.

Döngü kullanımları oldukça basit. matrix dizisini işlerken içiçe döngü kullanıyoruz. Döngülere konu olan dizilerin eleman sayısını len fonksiyonu yardımıyla anlayabiliriz. Dizi indisleri 0 tabanlı başladığından döngü sayaçları da 0dan başlatılmakta. fmt paketindeki Printf fonksiyonu Console penceresine çeşitli formatları uygulamak için kullanılıyor. %d'yi tam sayılar, %f'i kayan noktalı sayılar, %s'i de string tipindeki elemanlar için yer tutucu olarak kullanmaktayız. Pek tabii C#taki gibi {0} {1} gibi bir kullanım burada söz konusu değil. Printf'te ki parametre sırası konumlandırma açısından önemli. \n ve \t bildiğiniz üzere escape karakterlerimiz. Yeni satıra geçmek ve tab bırakmak için kullanılıyorlar. Başka escape karakterleri de var elbette.

KarakterKullanım Amacı
\aalert
\bbackspace
\fForm feed
\rCarriage return
\vVertical tab
\xhhHexadecimal numbers
\oooOctal numbers
\\\
\''
\""
\??

Kod parçasında dikkat çekici noktalardan birisi de sum isimli fonksiyon. Parametre olarak float32 tipinden elemanlar içeren bir dizi almakta. Dizinin eleman sayısı belli değil(ki eleman sayısı belli olacak şekilde verebilirsiniz de) Fonksiyon gelen dizinin boyutuna bakarak elemanların toplamını bulmakta. 

Kodu kurcalamak farklı farklı şeyler yapmaya çalışmak tamamen sizin elinizde. Örneğin matrisler için aritmetik işlemler yapan fonksiyonları tanımlayarak işe başlayabilirsiniz. Hatta eleman sayısı belli olmayan boyutlu dizileri de işin içerisine katabilirsiniz. Diğer yandan fonskiyona parametre olarak gönderdiğiniz bir dizinin elemanlarında yapacağınız değişikliğin orjinal konumdaki dizi elemanlarını etkileyip etkilemediğini de inceleyebilirsiniz. Etkilemiyorsa ve etkilemesini isterseniz ne yapmanız gerektiğinizi de bir araştırın derim.

Fonksiyonlar

Aslında önceki yazımızda olsun bu yazımızda olsun main haricinde kendi yazdığımız bir kaç fonksiyona yer verdik. Tabii fonksiyonlar ile ilişkili başka şeyler de var. Go, fonksiyon çeşitliliği açısından zengin bir dil. Bu anlamda fonksiyonel programlama paradigmasını da desteklediğini ifade edebiliriz. Gopher olmak için bu kullanım şekillerini bilmek çok önemli diye düşünüyorum. Öğrenebildiğim bir kaç tanesini paylaşayım.

Birden Fazla Değer Döndürmek

Bir fonksiyondan n sayıda değer döndürmemiz mümkün. Aşağıdaki kod parçasında bu durumu inceliyoruz.

package main

import (
	"fmt"
	)

func main(){
	var a,b,c,d int
	var x,y int
	x=8
	y=2
	
	a,b,c,d=calc(x,y)
	
	fmt.Printf("%d+%d=%d\n",x,y,a)
	fmt.Printf("%d*%d=%d\n",x,y,b)
	fmt.Printf("%d/%d=%d\n",x,y,c)
	fmt.Printf("%d-%d=%d\n",x,y,d)
}

func calc(x,y int) (int,int,int,int){
	return x+y,x*y,x/y,x-y
}

Örneğin çalışma zamanı çıktısı aşağıdaki gibidir.

calc isimli fonksiyon 4 değer döndürecek şekilde tanımlanmıştır. return ile dikkat edileceği üzere fonksiyona parametre olarak gelen x ve y değerleri için yapılan dört işlem sonuçları döndürülmektedir. main fonksiyonunda calc çağrısının yapıldığı satırda sonuçlar dört farklı değişkene  tek ifade ile atanmaktadır. Aslında bu kullanım şekli Rubyist'lere oldukça tanıdık gelecektir. Bilindiği gibi Ruby'de de n sayıda değer döndürmek ve tek satırda atama yapmak aynıdır(Fonksiyonlardan dönecek olan değerleri blok içerisinde adlanrırarak kullanmamız da mümkün)

params'ın Bir Türevi Variadic Fonksiyonlar

C#çılar bir metoda değişken sayıda parametre göndermenin yollarından birisinin params kullanımı olduğunu bilirler. Go dilinde de bu işlevsellik var. Hatta bu tip fonksiyonlar Variadic olarak ifade ediliyor. fmt paketindeki Println bu tip fonksiyonlara verilebilecek ilk örneklerden birisi. Aşağıdaki kod parçasında da geliştirici tanımlı bir Variadic fonksiyon örneği yer alıyor.

package main

import "fmt"

func main(){
	fmt.Println(sum(1,2,3,4))
	fmt.Println(sum(4,6,77,-2,90,2))
	fmt.Println(sum(0))
}

func sum(numbers ...int)int{
	total:=0
	for _,n:=range numbers{
		total+=n
	}
	return total
}

sum isimli fonksiyon herhangibir sayıda int eleman alacak şekilde tanımlanmıştır. Buradaki ... kullanımının anlamı budur diyebiliriz. Fonksiyon içerisindeki for döngüsü mutlaka dikkatinizi çekmiştir. range ile numbers elemanlarında hareket etme kabiliyeti kazanılır. numbers'a ait her eleman döngü içerisinde n adıyla kullanılır. Fonksiyonun kullanımında farklı sayıda int tipinden değişken gönderilmiştir(bir nevi foreach yazdığımızı düşünebiliriz sanırım)

Metod Kavramı

Gopher olmaya çalışırken metod ile fonksiyon'un Go dilinde aynı anlamda kullanılmadığını fark ettim. Yılların C# programıcısı olarak parametre alıp geriye değer döndüren fonksiyonları metod olarak isimlendirdiğim çok oldu. Hatta Visual Basic'te metod ve procedure ayrımlarına da şahit oldum. Ancak fonksiyon ve metod arasında bir ayrım olabileceği pek aklıma gelmemişti. Peki o zaman Go dilinde metod neye denir bir bakalım. 

package main

import "fmt"

type Vehicle struct{
	id int
	name string
	x,y,z int
}

func(v Vehicle) findLocation() string{
	if v.x>10 && v.x<20 {
		return "Germany"
		}
	return "France"
}

func main(){
	tank:=Vehicle{id:1,name:"Leopard",x:12,y:1,z:-100}
	fmt.Printf("%s\n",tank.findLocation())
	tank.x=5
	fmt.Printf("%s\n",tank.findLocation())
}

Örnekte Vehicle isimli bir struct tanımlı. Bu veri tipine yazının ilerleyen kısımlarında değineceğiz. Vehicle içerisinde id,name,x,y,z gibi alanlar mevcut. findLocation ise bir metod(fonkisyon olarak isimlendirmiyoruz) Tanımlanma şekli normal bir fonksiyondan biraz farklı. func'dan sonra Vehicle isimli bir parametre geliyor. Sonrasında ise metodumuzun adı. Metod içerisnde v isimli değişkeni kullanarak Vehicle örneklerinin niteliklerine ulaşabiliyoruz. Aslında metod ile fonksiyon arasındaki fark kim tarafından sahiplenildiği ile anlaşılabiliyor. Metodu örnekte olduğu gibi bir veri tipine bağladık. Bu yüzden çağırılırken Vehicle tipinden bir değişken üzerinden gidebiliyoruz. Eğer findLocation metodunu main içerisinde herhangibir noktada çağırmaya kalkarsak böyle bir metodun olmadığına dair hata mesajı alırız.

 

Değişken Olarak Fonksiyon Kullanımı ve İsimsiz Fonksiyonlar

Go dilinde bir fonksiyonu değişkene atayabilir ve hatta bu değişkeni bir başka fonksiyona parametre olarak gönderebiliriz. Daha çok fonksiyon alan fonksiyonlarda işimize yarayabilecek bir durum olduğunu ifade edebiliriz. Go'nun hazır paketlerinde bu şekilde çalışan pek çok fonksiyon bulunur. Aşağıdaki kod parçası durumu daha iyi anlamamızı sağlayacaktır.

package main

import (
	"fmt"
	"strings"
)

func main(){	
	f1 := func(r rune) rune {
		switch {
			case r == ' ':
				return '_'
			case r == 'b':
				return 'B'
			}
		return r
	}
	
	fmt.Println(strings.Map(f1, "bugun guzel bir gun"))
	fmt.Println(strings.Map(func(r rune) rune{
		if r>=65 && r <= 90{
			return r + 32
			}
		return r
	},"buGUN de Guzel gAlIba"))
}

Kodda efso şeyler var aslında. strings paketinde yer alan Map fonksiyonunun tanımı ile işe başlamak lazım. 

func Map(mapping func(rune) rune, s string) string

Önemli olan nokta mapping isimli ilk parametre. Aslında burada rune(Unicode değeri gösteren bir int32 tipi olarak ifade ediliyor) tipinden parametre alıp yine rune tipinden değer döndüren bir fonksiyon bildirimi var. Üstelik bu bildirim Map fonksiyonunun ilk parametresi. Dolayısıyla Map fonksiyonuna belirtilen kurala uygun bir fonksiyonu parametre olarak gönderebiliriz. 

f1 isimli değişken bu tanıma uyuyor. Dikkat edileceği üzere rune tipinden parametre alıp yine aynı tipten değer döndürmekte. İçerisinde ise r değişkeninin değeri kontrol edilip bir sonuç üretiliyor. Basitçe boşluk karakterini _ işaretine ve b harflerini de B'ye dönüştürmekte. Anlamlı bir iş yaptığı söylenemez. f1 değişkeni kodun ilerleyen kısımlarında strings paketi üzerinden kullanılıyor. 

İkinci strings.Map kullanımı ise biraz daha enteresan. Bu kez Map fonksiyonunun ihtiyaç duyduğu ilk parametredeki fonksiyonu oradaki ifade içerisinde tanımlamaktayız. Bu arada Map benzeri bir fonksiyon yazmak istersek fonksiyonları tip olarak tanımlayıp ele alabileceğimizi de bilmemiz gerekiyor. Örneğimizde kullanıdığımız fonksiyonları aynı zamanda isimsiz fonksiyonlar olarak da düşünebiliriz.

GO dili daha önce belirttiğimiz üzere fonksiyonel dil özelliklerine de sahip. İsimsiz fonksiyonlar, fonksiyonların değişkenlere atanabilmesi, tip olarak fonksiyon tanımlanabilmesi, fonksiyonlardan fonksiyon döndürülebilmesi bu kabiliyetler arasında yer alıyor. Bunları da ilerleyen zamanlarda makale veya tek fotoluk ipuçlarında ele almaya çalışacağım.

Aslında yeri gelmişken bir fonksiyondan başka bir fonksiyon nasıl döndürülür ve hatta bu fonksiyon içeride isimsiz olarak tanımlandığında Closure adı verilen kapama işlevselliği nasıl vuku bulur, dilerseniz inceleyelim. Aşağıdaki kod parçasını göz önüne alabiliriz.

package main

import ( 
	"fmt"
	)

func add() func(int) int {
    total:=0
	return func(x int) int{
		total+=x
        return total
    }
}

func main(){
    var f1 = add()
    fmt.Println(f1(5))
	fmt.Println(f1(5))
	fmt.Println(f1(5))
	
    var f2 = add()
    fmt.Println(f2(4))
	fmt.Println(f2(4))
}

Kodun yaptığı şeyin hiç bir anlamı yok biliyorsunuz değil mi? Ama Go'nun fonksiyonel kabiliyetleri ile ilgili önemli bilgiler barındırıyor. Her şeyden önce add isimli fonksiyona odaklanalım. add geriye isimsiz bir fonksiyon döndürmekte. Bu fonksiyon int tipinden tek bir parametre alıyor ve yine int tipinden değer döndürüyor. İsimsiz fonksiyon içerisindeyse add fonksiyonunun yerel değişkenine gelen parametre değeri ekleniyor.

main fonksiyonu içerisinde f1 ve f2 isimli iki değişken tanımı var. Bu değişkenler add fonksiyonunu taşıyorlar. Dolayısıyla onları kodun ilerleyen kısımlarında kullanırken aslında birer fonksiyon çağrısı gerçekleştiriyoruz. f1 ve f2'ye verilen parametre değerleri add fonksiyonundan dönen isimsiz fonksiyona gidiyorlar. f1 ve f2 kendi alanları içerisinde bu fonksiyonelliği sunuyorlar. Yani total değişkeni her add fonksiyonu atamasında, atanan değişken için 0 olarak yeniden belirleniyor. 

Kafalar yandı mı? Şahsen benim epey yanmış durumda. Ha bir de fonksiyonları tip gibi tanımlama mevzusu vardı. Az önce dile getirmiştim ama arada devreler yandığı için bu cümleyi yazarken dile getirdiğimi de unuttum. Neyse. Bunu ilerleyen zamanlarda incelersek fena olmaz.

Structure

Metod kavramını incelerken basit bir struct tipi kullandık. Orada çok fazla değinmedik ama Go dilinin önemli veri türlerinden birisi olarak karşımıza çıkıyor. Structure, kullanıcı tanımlı veri tiplerinden(user defined data type) birisi olarak düşünülebilir. Hani nesne yönelimi bir dil değil belki ama en azından kendi sınıflarımızı struct gibi tanımlayabiliriz düşüncesi güzel. Aslında çeşitli tipte elemanları barındıracak bir veri modelini tasarlayıp değişken olarak kullanıma sunuyoruz. Aşağıdaki örnek kod parçasında basit bir struct tanımı ve kullanımı söz konusu.

package main

import "fmt"

func main(){

	phone:=Product{productId:1001,title:"Samsung J5",listPrice:245.50}
	var cpu Product
	cpu.productId=2005
	cpu.title="intel core i5 CPU"
	cpu.listPrice=120.50
	
	var products=[]Product{phone,cpu}
	
	writeToConsole(products)
}

func writeToConsole(prods []Product){
	for _,p:=range prods{
		fmt.Printf("(%d)-%s,%f\n",p.productId,p.title,p.listPrice)
	}
}

type Product struct{
	productId int
	title string
	listPrice float32
}

Örnekte Product isimli bir yapı kullanılmakta. Yapının productId, title, listPrice isimli üyeleri mevcut. main fonksiyonu içerisinde iki struct örneği yer alıyor. Birbirlerinden farklı şekilde oluşturulduklarına dikkat etmişsinizdir. Her iki yapıyı yine Product tipinden olan bir dizide topladık. Bu diziyi writeToConsole fonksiyonuna parametre olarak da gönderiyoruz. Fonksiyon, gelen Product yapılarına ait değerleri ekrana basmakla görevli.

Pointer Demişken

Yukarıda geliştirdiğimiz örneği baz alarak konuyu biraz değiştirelim. Önce aşağıdaki kod parçası ve sonucunu irdelememiz gerekiyor.

package main

import "fmt"

func main(){

	phone:=Product{productId:1001,title:"Samsung J5",listPrice:245.50}
	fmt.Println(phone.listPrice)
	discount(phone,10)
	fmt.Println(phone.listPrice)
}

func discount(p Product,value float32){
	p.listPrice-=value
}

type Product struct{
	productId int
	title string
	listPrice float32
}

discount fonksiyonu ile parametre olarak gelen ürünün liste fiyatını belli bir değerde azaltıyoruz. Fonksiyona phone isimli struct örneğini gönderiyoruz ve içerisinde listPrice değerini değiştiriyoruz. Ekran çıktısına baktığımızda fonksiyon çağrısından önceki liste fiyatı ile sonraki liste fiyatının aynı olduğunu görmekteyiz. Bu zaten beklediğimiz bir sonuç. Nitekim phone değişkeni, discount fonksiyonuna geçerken sahip olduğu değerleri ile birlikte kopyalanıyor ve blok içinde p isimli yeni bir değişken olarak muamele görüyor. Dolayısıyla fonksiyon içerisindeki değişikliker main içerisindeki değişkeni etkilemiyor. Peki etkilemesini istersek!? Yani phone değişkeninin liste fiyatını fonksiyon içerisinde değiştirebilmek istersek. İşte burada ilgili nesneyi fonksiyona referans olarak geçirmenin bir yolunu bulmamız gerekmekte. Bunun için onun bellek adresini taşımayı düşünebiliriz. Sadece iki karakter ile bu işi çözümleyebiliriz. 

package main

import "fmt"

func main(){

	phone:=Product{productId:1001,title:"Samsung J5",listPrice:245.50}
	fmt.Println(phone.listPrice)
	discount(&phone,10)
	fmt.Println(phone.listPrice)
}

func discount(p *Product,value float32){
	fmt.Println("Address is ",&p)
	p.listPrice-=value
}

type Product struct{
	productId int
	title string
	listPrice float32
}

Dikkat edileceği üzere phone değişkeninin fonksiyon çağrısı öncesindeki fiyatı, fonksiyon çağrısı sonrası değişmiştir. Bunun sebebi fonksiyonda bir Pointer tanımlamış olmamızdır. *Product ile tanımladığımız değişkene, &phone ile phone isimli değişkenin bellek adresini taşımız oluruz. Dolayısıyla fonksiyon içerisindeki p değişkeni üzerinde yapacağımız değişiklikler aslında phone isimli değişken için geçerli olur. Kodda &p kullanımı ile gelen bellek adresini de yazdığımızı fark etmişsinizdir. Pointer kavramı oldukça derin bir konu. En sooooooonnnn 1995de üniversite ikinci sınıftayken C++ sınavına hazırlanırken bakmıştım. Dolayısıyla yeniden öğrendiğimi ifade edebilirim.

Yazdığımız kod aynı zamanda bir fonksiyona parametreleri referansları ile aktırmanın da örneğidir(Call by Reference konusu) Normalde fonksiyonlara iki tür parametre geçişi söz konusu. Call by Value ve Call by Reference şeklinde anılıyorlar. Go dilinde fonksiyonlar varsayılan olarak Call by Value yaklaşımını kullanıyor. Referans taşımaları için az önceki örnekte olduğu gibi Pointer'lardan yararlanabiliyoruz. Bir dizi söz konusu olduğunda ise Slice öneriliyor(Bu da benim için yeni bir kavram. İlerleyen zamanlarda öğreneceğim)

Şimdilik Gopher olma çalışmalarım ile ilgili aktaracaklarım bu kadar sevgili arkadaşlar. Bu yazıda dizilere, döngülere, yapılara, fonksiyonlara ve metodlara değinme fırsatımız oldu. Ucundan bir kuple de olsa Pointer dedik. Epeyce yorulduk. Şimdi kısa bir ara verme zamanı. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

Duck Typing Nedir?

$
0
0

Merhaba Arkadaşlar,

Son bir yıldır Ruby ve Python gibi script diller üzerinde araştırmalar yapıyorum. Daha çok bu dilleri öğrenme, anlama gayretindeyim. En azından orta seviye bilgi sahibi olmak benim için yeterli. Bu dilleri incelerken uzun yıllardır çalıştığım dinamik tip sistemli ve derleyici odaklı yaklaşımları da sorgulamak durumunda kalıyoum. Nitekim farklı programlama yaklaşımlarına sahipler.

Ruby, Python vb script diller çoğunlukla dinamik tip sistemini(dynamic type system) kullanıyorlar. Yani C#, Java, C++ benzeri dillerde kullanılan statik tip sisteminden(static type system) farklı bir yaklaşım söz konusu. Ayrıca betik diller kodun çalışma zamanında yorumlanarak(Interpret) yürütülmesine odaklandıklarından, derleme(compiling) yaklaşımını benimseyen dillerden epeyce farklılaşıyorlar. Hal böyle olunca diller arası bazı farklı teknikler ve yazım stilleri ortaya çıkıyor. Bunlardan birisi de Duck Typing.

Tanım

If it walks like a duck, and quakcs like a duck, then it must be a duck.

Enteresan bir tanımlama şekli olduğu aşikar. Kısaca bir şey ördek gibi yürüyor ve ördek gibi konuşuyorsa O bir ördek olarak kabul edilebilir. Bu felsefeyi anlamak beni biraz uğraştırdı doğrusu. Yıllarca karşılaşmadığım Ruby ile uğraşmasam haberdar olamayacağım bir teknik. Öncelikle düşünce yapımı değiştirdim. Programcı olarak bir nesnenin(object) ne olduğundan ziyade ne yapabileceğine odaklanmam gerektiğini benimsemem gerekiyordu.

Duck Typing aslında çalışma zamanı ile ilgili de bir konu. Compile-Time ile Run-Time arasındaki davranış farklılıkları bu teknikte öne çıkıyor. Nitekim duck typing stilinde, sistem çalışmadan önce çeşitli şartların sağlanmasını beklemiyor. Bunun yerine çalışma zamanında herhangibir şeyi(örneğin parametre olarak gelen bir nesne üzerinden bir fonksiyonun çalıştırılması) yürütmeyi deniyor. "Deniyor" diyoruz çünkü icra edilmesi istenen fonksiyonelliğin önceden tanımlanmış bir kuralı veya şablonu olmak zorunda değil. 

Ducy Typing Yokken

Kafalar biraz karıştı değil mi? Aslında benim de karışık. Haydi gelin bir örnek ile konuyu anlamaya çalışalım. İlk olarak Ducy Typing olmadan bir şeyleri görmemiz gerekiyor. Bu anlamda aşağıdaki C# kodunu ele alacağız.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ClassicTyping
{
    class Program
    {
        static void Main(string[] args)
        {
            Car frrari = new Car();
            Plane cesna = new Plane();
            Ship fery = new Ship();
            DriveVehicle(frrari);
            DriveVehicle(cesna);
            DriveVehicle(fery);
        }

        static void DriveVehicle(IVehicleOps vehicle)
        {
            vehicle.Drive();
        }
    }

    interface IVehicleOps
    {
        bool Drive();
    }

    class Car
        : IVehicleOps
    {
        public bool Drive()
        {
            Console.WriteLine("Driver is driving");
            return true;
        }
    }

    class Plane
        :IVehicleOps
    {

        public bool Drive()
        {
            Console.WriteLine("Pilot is driving");
            return true;
        }
    }

    class Ship
    {

    }
}

Kodu dikkatlice inceleyelim. Sizce bu kod derlenir mi? Aslında böyle sorduğuma göre derlenmiyor olması lazım değil mi? Uygulamada bir interface ve üç sınıf bulunmakta. Car ve Plane sınıfları IVehicleOps arayüzünü uyguluyorlar. Bu nedenle Drive isimli bir işlevselliğe sahipler. Ship isimli sınıfın ise bu arayüzü uygulamadığını görüyoruz. Dolayısıyla Drive isimli bir kabiliyete sahip değil. Program sınıfı içerisinde yer alan DriveVehicle metodu parametre olarak IVehicleOps tipinden değişkenler alıyor. Dolayısıyla bu arayüzü uygulayan nesne örneklerini kendisine aktarıp Drive fonksiyonunu çağırabiliriz. Lakin Ship sınıfına ait tasarımda böyle bir yetenek mevcut değil. Nitekim Ship, IVehicleOps tarafından taşınabilecek bir nesne modeli değil. Bu sebepten kod derlenmeyecektir.

Ne zararı var peki? Programcı zaten tipleri önceden tanımlayarak geliştirme yapıyor. Kuralları biliyor. Interface kullanımı sayesinde metoda çok biçimli bir yapı kazandırıp OOP(Object Oriented Programming) ilkelerinden birisini de uyguluyor. Ship nesne örneği üzerinden Drive operasyonunun gerçekleşmemesi normal bir sonuç. Çünkü arayüz tanımına uygun yapıda değil. Burada bir çok  tanımlama söz konusu. Kullanıcı tanımlı tipin önceden tasarlanması, uyacağı kuralların bildirilmesi gerekti.

Ducy Typing Yaklaşımı

Dinamik tip sistemli dillere gelindiğinde farklı bir bakış açısı daha var. Şimdi gelin bu farklılığı ortaya koyan Duck Typing ile aynı senaryonun bir benzerinin nasıl ele alınacağına bakalım. Ruby'de aşağıdaki örnek kod parçasını yazarak işe başlayabiliriz.

class Car
  def drive
    puts "driver is driving"
  end
end
class Plane
  def drive
    puts "pilot is driving"
  end
end
def drive(vehicles)
  vehicles.each{|v|v.drive}
end

frrari=Car.new()
bat=Plane.new()
vehicle_array=[frrari,bat]
drive(vehicle_array)

Ne olduğuna kısaca bakalım. Car, Plane sınıfları içerisinde yine drive isimli birer metodumuz var. Örnekte vehicles isimli değişken alan drive metodunun işleyişi önemli. Dikkat edileceği üzere vehicles dizisinin içerisindeki her v değişkeni üzerinden drive fonksiyonu çağırılıyor(Aslında vehicles'ın Car, Plane gibi araçlar taşıyacağı da kesin değil. Ne demiştik? Yaklaşımımızı farklılaştırmamız gerekiyor. Derleyici gibi değil yorumlayıcı gözüyle bakıp kodu yazmalıyız) Buna göre vehicles değişkenini Car ve Plane gibi sınıflara ait nesne örnekleri ile doldurup topluca drive operasyonunu uygulatmamız mümkün. Ortada bir arayüz bildirimi veya türetme gibi bir şey yok. Çalışma zamanı felsefesi basit. Ruby yorumlayıcısı vehicles elamanlarını gezerken eğer sürüş yeteneği varsa sürerim diyor. Çok doğal olarak Ship isimli ve drive metodu olmayan bir sınıf örneğini bu dizi içerisine alıp kullanmak istesek çalışma zamanında hata alırız(Dikkat edin derleme zamanı değil çalışma zamanı dedim) 

Eğer drive metoduna gelen değişken içindeki nesne drive metodunu destekliyorsa sıkıntı yok. Çalıştırmayı dene! Ama drive metodu o anki nesne için söz konusu değilse çalışma zamanına hata fırlat.

Sanıyorum siz de benim gibi Duck Typing yaklaşımını biraz daha iyi anladınız. Bakalım Ruby, Python gibi dilleri inceledikçe daha farklı nelerle karşılacağız!? Bir başka yazımızda görüşünceye dek hepinize mutlu günler dilerim.

GoLang - Harici Paket(Package) Yazıp Kullanmak

$
0
0

Merhaba Arkadaşlar,

Go dilinin paketler üzerine kurulu bir yapısı olduğunu biliyoruz. fmt, math, strings, net/http, time, log, encoding/json ve benzerleri şu kısa go geçmişimde kullandıklarımdan sadece birkaçı. Geliştirdiğimiz ürünlerde ortak sorumlulukları barındıran fonksiyonellikleri aynı paketler içerisinde toplamak son derece mantıklı. Bu sayede aynı alana ait fonksiyonellikleri bir paket içerisinde toplayıp kullanabilme şansına sahip oluyoruz. Paketler, kodun yeniden kullanılabilirliği(Code Reusability) noktasında da değer bulan bir kavram.

Go dilini sistemimize yüklediğimizde zaten beraberinde pek çok paket geliyor ve bu paketler GOPATH ile belirtilen konumdaki src klasörü altında konuşlandırılıyor. Örneklerimizde çok sık kullandığımız fmt paketine ait kod dosyalarını src klasörü altından görebilir ve kod içeriğine bakıp Println fonksiyonunun nasıl çalıştığını inceleyebiliriz. 

Go programlarının çalışmaya başladığı main fonksiyonunun da main isimli paket(Package) içerisinde yer aldığını hatırlayalım.

Kendi Paketimizi Yazalım

Buna göre kendi yazdığımız paketleri src klasörü altına atıp kullanmaya başlayabiliriz. Gelin bu vakayı basit bir örnekle incelemeye çalışalım. Tabii ilk olarak bir paket yazarak işe başlamamız gerekiyor :) Sözgelimi içerisinde bir kaç metrik dönüştürme işlemi barındıran mtrcvrt(Metric Converter diye isimlendirebiliriz) adlı bir paket geliştirdiğimizi düşünelim. 

package mtrcvrt

//Fahrenheit to Celsius
func FahToCel(f float64) float64{
	return (f-32)/1.8
}

// Celsius to Fahrenheit
func CelToFah(c float64) float64{
	return (c*1.8)+32
}

// Feet to Meter
func FeetToMeter(feet float64) float64{
	return feet/3.2808
}

// Kg to Pound
func KgToPound(kg float64) float64{
	return kg*2.2046
}

// Kilometers to Mile
func KmToMiles(km float64) float64{
	return km*0.621371192
}

Yazdığımız paket içerisinde beş fonksiyon bulunuyor. Fahrenheit'dan Celsius'a, Kilogram'dan Pound'a, Kilometre'den Mil'e, Feet'ten metreye ve son olarak Celcius'dan Fahrenheit'a dönüşüm işlemlerini içeriyor. Kod paket adıyla başlıyor. Kullandığımız fonksiyonlar float64 tipinden birer parametre almakta ve gerekli formüller işletildikten sonra geriye yine float64 tipinden değer döndürmekteler. mtrcvrt'yi sistemde herhangibir main paketinden kullanabilmek için az önce bahsettiğimiz src klasörü içerisine atmamız yeterli. Pek tabi kaynak kodun mtrcvrt klasörü altında konuşlandırıldığına dikkat edelim(Aynı diğer built-in paketler gibi)

Şunu unutmayalım ki paket içerisindeki fonksiyonların adları ve özellikle ilk harfleri çok önemli. Eğer büyük harfle başlamazlarsa paket dışından kullanılamazlar. 

Şimdi örnek bir program dosyası oluşturup yazdığımız pakete ait fonksiyonellikleri test edelim.

package main

import (
	"fmt"
	"mtrcvrt"
	)
	
func main(){
	var (
		iFahrenheit=89.0
		iCelsius=36.5
		iFeet=100.0
		iKg=83.50
		iKm=450.0
		)
	
	oCelcius:=mtrcvrt.FahToCel(iFahrenheit)
	fmt.Printf("%f\n",oCelcius)
	
	oFahrenheit:=mtrcvrt.CelToFah(iCelsius)
	fmt.Printf("%f\n",oFahrenheit)
	
	oMeter:=mtrcvrt.FeetToMeter(iFeet)
	fmt.Printf("%f\n",oMeter)
	
	oPound:=mtrcvrt.KgToPound(iKg)
	fmt.Printf("%f\n",oPound)
	
	oMiles:=mtrcvrt.KmToMiles(iKm)
	fmt.Printf("%f\n",oMiles)
}

import sekmesinde paketin adını belirttik ve main içerisinde sahip olduğu fonskiyonları birer örnekle denedik. var ifadesinde n sayıda değişkene değer ataması gerçekleştiriyoruz ki bunu ilk kez kullandığımı söyleyebilirim. Kodun çalışma zamanı çıktısı ise aşağıdaki gibi olacaktır.

Yazdığımız paketlerin src klasörü altında olması şart değil. Aslında Go dili klasör temelli bir çalışma ortamını(Workspace) baz alıyor. Bu ortamda src, bin ve pkg klasörleri standart olarak bulunuyor. Paket kodları src klasörü altında konuşlandırılmakta. Go ortamı sisteme yüklendiğinde bu klasör hiyerarşisini kullanıyor. Diğer yandan github gibi önemli bir paket deposu da var. Pek çok programlama dilinde olduğu gibi Go ile yazılmış paketleri github'a atabilir ve tüm geliştiricilerin kullanımına açabiliriz. 

Github ile Entegrasyon

Kaynaklardan öğrendiğim kadarı ile Workspace'imizde github için bir klasör ağacı oluşturup senkronize bir şekilde çalışabiliriz de. Böylece commit, rollback gibi standart kaynak kod yönetimi işlemlerini gerçekleştirebiliriz. Ben işleri kolaylaştırmak adına Github Desktop for Windows sürümünü kullandım. Sistemimde yüklü olan src klasöründe mtrk olarak isimlendirdiğim paket için bir repo oluşturdum. Sonrasında kodu hazırlayıp Commit ederek github'a atılmasını sağladım. Bu işlem sonrasında mtrk klasörü içerisinde github ile ilgili dosyalar da otomatik olarak oluşturuldu.

Ardında mtrk.go kod dosyasının commit ederek github'a yüklenmesini sağladım.

Artık bilgisayarımdaki workspace ile github eşleşmiş durumda. Bu yeni yapıdaki paketi kullanmak için tek yapılması gereken import ifadesini uygun bir şekilde değiştirmek.

package main

import (
	"fmt"
	"github.com/buraksenyurt/mtrk"
	)

Peki ya diğer kullanıcılar?

Onlar bu paketi nasıl kullanabilirler? Yazıya konu ettiğimiz örnek için go get komutunu kullanmamız yeterli aslında. Emin olmak adına sistemimdeki Go Repo'sunu sildim. Daha sonra komut satırından go get komutunu aşağıdaki ekran görüntüsünde olduğu gibi kullandım. Src/github.com/buraksenyurt/mtrk klasörünün oluşuturulduğunu ve içerisine go dosyasının indirildiğini fark ettim.

Ayrıca pkg klasöründe paketin derlenmiş dosyasının da oluşturulduğunu gördüm.

Uygulama kodunu tekrar çalıştırdığımda mtrk paketi ve fonksiyonelliklerinin başarılı bir şekilde yürütüldüğünü gördüm. İşin sağlamasını yapmak için mtrk.go dosyasını silip deneyebilirsiniz. Benim karşılaştığım sonucu alacaksınız.

Görüldüğü üzere Go dilinde paketler ile çalışmak oldukça basit. Atladığım pek çok konu olabilir. Örneğin paketler yüklenirken yapılmasını istediğiniz işlemler varsa bunları init fonksiyonu içerisinde gerçekleştirebilirsiniz ki örneğimizde buna değinmedik. Paket yönetimi için github'ı uzak repository olarak kullanabileceğimizi ve local workspace ile eşleştirerek ilerleyebileceğimizi gördük. Bunlara ek olarak bin,src ve pkg klasör hiyerarşisinden azda olsa bahsettik. Böylece geldik bir Gopher olma maceramızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

Ruby Kod Parçacıkları 32 - Singleton

$
0
0

Merhaba Arkadaşlar,

Ruby'nin oldukça geniş bir program kütüphanesi bulunuyor. Fırsat buldukça bazılarını incelemeye çalışıyorum. Geçtiğimiz günlerde Singleton isimli bir modüle rastladım. Kısaca tasarım kalıplarından(Design Patterns) olan Singleton deseninin kolayca uygulanmasını sağlıyor.

Ancak dikkat çekici başka bir özelliği daha var. Nesne durumunun saklanması ve istenen anda saklanan duruma döndürülmesi vakasında da Marshal modülü ile birlikte güzel bir işbirliği içerisinde. Marshalling ile Singleton olan bir nesne örneğinin anlık durumunu(State) sonradan geri yükleme imkanıyla saklayabiliyoruz.

Singleton Tasarım Kalıbının Uygulanması

Öncesinde Singleton tasarım kalıbının amacını hatırlamakta yarar var: Bir sınıfa ait nesne örneğinin çalışma zamanında tek olmasını garantilemek. Örneğin yazdığımız uygulama ayağa kalkarken çeşitli konfigurasyon ayarlarını yükleyen farklı modüldeki bir sınıfı kullanıyor olsun. Sınıfın çalışma zamanında tek bir örneğinin olmasını ve herhangi bir şekilde çoğaltılmamasını(hatta klonlanmamasını) istersek, Singleton deseni bizim için ideal çözüm olacaktır.

Ruby tarafında bir sınıfın Singleton kalıbını uygular hale getirilmesi ise oldukça kolay. Singleton modülünü sınıfa dahil etmemiz yeterli. Aşağıdaki örnek kod parçasını ele alalım.

require "Singleton"

class ConfigurationManager
  include Singleton
  
  attr_accessor :default_host,:default_port,:entry_point
  
  def get_default_host
    "tcpip://#{@default_host}:#{@default_port}/#{@entry_point}"
  end
end

mngr1=ConfigurationManager.instance
mngr1.default_host="localhost"
mngr1.default_port="4500"
mngr1.entry_point="mainProcess"

puts "mngr1 object id =#{mngr1.object_id}"
puts mngr1.get_default_host

mngr2=ConfigurationManager.instance
puts "mngr2 object id =#{mngr2.object_id}"
puts mngr2.get_default_host

puts mngr1==mngr2

reuqire bildirimi ile Singleton modülünü script'e dahil ediyoruz. ConfigurationManager sınıfı içerisindeki include ifadesi ile de Singleton modülünü uygulayacağını belirtiyoruz. Sınıfın üç niteliği bulunuyor. Bunların değerlerini düzgün bir formatta get_default_host metodunu kullanarak geriye döndürüyoruz. 

Kodun ilerleyişinde ilk olarak mngr1 isimli nesne örneğini oluşuyor. Burada dikkat edilmesi gereken nokta instance özelliğinin kullanılması. Normalde bir sınıf örneğini new metodundan yararlanarak üretiriz. Ancak Singleton bir nesne söz konusu ise new metoduna yapılan çağrı aşağıdaki hata mesajının üretilmesine neden olur.

in `<main>': private method `new' called for ConfigurationManager:Class (NoMethodError)

Kodda üretilen her iki ConfigurationManager nesne örneği de aynı object_id değerlerine sahiptir. Hatta bu iki nesne aynıdır ki eşitlik sonrası kod true değeri döndürmüştür. Bir başka dikkat çekici nokta ise, mngr1 üretimi sırasında atanan nitelik değerlerinin mngr2 için de geçerli olmasıdır. Kodun çalışma zamanı çıktısı aşağıdaki gibidir.

Çok doğal olarak ConfigurationManager tipinden n sayıda nesne örneği üretilebilir. Ancak gerçek anlamda çalışma zamanında tek bir ConfigurationManager nesne örneği söz konusu olacaktır. Bu n sayıda nesne örneğinin herhangibirinde yapılan değişiklikler pek tabii diğer değişkenleri de etkiler. Söz gelimi yukarıdaki koda aşağıdaki parçayı eklediğimizi düşünelim.

mngr2.default_host="127.0.0.1"
puts mngr1.get_default_host
puts mngr2.get_default_host

Bu durumda mngr2 ile yapılan değişiklik mngr1 tarafından da görülecektir.

Marshalling ile Nesne Durumunu Korumak

Gelelim Marshaling ile Singleton karakteristiğindeki bir nesne örneğinin anlık durumunun(State) saklanmasına. Bunun için Singleton modülünden gelen _load ve _dump metodlarının çalışma zamanında durumu korumak istenen sınıf için ezilmesi gerekiyor. Aşağıdaki örnek kod parçasında bu durum ele alınıyor.

require "Singleton"

class ConfigurationManager
  include Singleton
  
  attr_accessor :default_host,:default_port,:entry_point
  
  def get_default_host
    "tcpip://#{@default_host}:#{@default_port}/#{@entry_point}"
  end
  
  def _dump(obj)
    state="#{@default_host}|#{@default_port}|#{@entry_point}"
    Marshal.dump(state,obj)
  end
  
  def self._load(name)
    state=Marshal.load(name)
    values=state.split("|")
    instance.default_host=values[0]
    instance.default_port=values[1]
    instance.entry_point=values[2]
    instance
  end
end

mngr=ConfigurationManager.instance
mngr.default_host="azonfactory"
mngr.default_port="5555"
mngr.entry_point="prod"
puts "BeforeMarshalling"
puts mngr.get_default_host
last_state=Marshal.dump(mngr)
puts last_state
mngr.default_host="localhost"
mngr.default_port="8080"
mngr.entry_point="test"
puts "AfterChange"
puts mngr.get_default_host
mngr_backup=Marshal.load(last_state)
puts "AfterLoad"
puts mngr_backup.get_default_host

_dump metodu içerisinde sınıf örneğinin o anki durumu ile ilişkili olarak tutmak istediğimiz ne kadar nitelik varsa ardışıl olarak aralarına pipe işareti koyarar dizdik. Bunu okuduğumuz yerde çözümlüyor ve instance ile eriştiğimiz nesne örneğinin ilgili niteliklerine atıyoruz. Okuma işlemini kolaylaştırmak için | işaretinden faydalandık. Aslında ConfigurationManager içerisindeki _dump ve _load metodları işleyişlerini gerçekleştirirken Marshal modülünün ilgili fonskiyonları kullanılmaktalar. Marshal modülü nesne içeriğinin byte stream olarak serileştirlmesi ve ters okunması noktasında görev alıyor.

Kodu denediğimiz akışta mngr isimli ConfigurationManager sınıf örneğinin anlık durumunu kayıt altına alıyoruz(Bellekte) Ardından niteliklerinde bir takım değişiklikler yapıyoruz. Bu sadece test amaçlı bir işlem. Sonrasında nesne örneğini ilk kayıt ettiğimiz durumuna döndürüyoruz. Farklı bir değişken ile dönmüş olsa da Singleton kalıbı gereği mngr ve mngr_backup aynı nesnelerdir. İşte çalışma zamanı çıktısı.

Böylece geldik bir Ruby kod parçacığımızın daha sonuna. Bu yazıda Ruby dilinde Singleton tasarımın kalıbının ne kadar kolay uygulanabildiğini ve nesne durumlarının saklanması için Marshal modülünden nasıl faydalanabileceğimizi gördük. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

Ruby Kod Parçacıkları 33 - Observer Deseninin Uygulanışı

$
0
0

Merhaba Arkadaşlar,

Bir önceki kod parçasında Singleton kalıbının Ruby tarafında nasıl uygulandığını incelemeye çalışmıştık. Hatırlayacağınız gibi hazır singleton modülünü kullanarak bu işi gerçekleştirmek oldukça kolaydı. Benzer durum Observer tasarım kalıbı için de geçerli. Bu kalıp bir nesnenin durumunda meydana gelen değişiklikler sonrası ilgili diğer nesnelerin uyarılması amacıyla kullanılan popüler yazılım desenlerinden birisi. (.Net tarafındaki uygulanış şekli ile ilgili olarak şu eski yazımdan yararlanabilirsiniz)

Dilerseniz örnek bir senaryo üzerinden hareket ederek bu deseni nasıl uygulayabileceğimize kısaca bakalım. Bir oyun kodunda oyuncuların belirli puan noktalarını aşmaları sonrası oyuncu nesnesi ile ilişkili başka nesnelerin bilgilendirilmesini istediğimizi düşünelim. Söz gelimi bu bilgilendirmeler sırasında oyuncuların seviyelerini bir diğer nesne üzerinden değiştirelim. Tasarım kalıbının uygulanış biçimine göre gözlemlenebilir(observable) bir oyuncu nesnesi ve bu nesnedeki durum değişikliklerini ele alacak bir gözlemci(observer)örneğine ihtiyaç bulunuyor. Aşağıdaki kod parçasını örnek olarak ele alabiliriz.

require 'observer'

class PlayerObserver
  def notify(player,point)
    puts "Player's current point is #{point}"
    player.level="Looser" if player.point<0
    player.level="Pro gamer" if player.point >1000
    player.level="Blackhat" if player.point>2000
  end
end

class Player
  include Observable
  
  attr_accessor :level,:title
  attr_reader :point
  
  def initialize(title)
    @title,@point,@level=title,100,"Standard gamer"
    add_observer(PlayerObserver.new,"notify")
  end
  
  def set_point(v)
      @point=v
      changed
      notify_observers(self,v)
  end  
end

rudi=Player.new("rudii the ram")
puts rudi.level
rudi.set_point(1240)
puts rudi.level
rudi.set_point(2300)
puts rudi.level
rudi.set_point(-300)
puts rudi.level

Neler yaptığımıza kısaca bakalım.

observer kalıbını kullanmak için ilgili modül bildirimini yaparak kodlamaya başlıyoruz. PlayerObserver sınıfı gözlemci rolünü üstleniyor. Bu sınıfta yer alan notify metodu, Player nesne örneklerinin puanlarında olan değişiklilere göre tetiklenecek. notify metodu içerisinde o anki Player nesnesinin point değerine bakıp level niteliğini değiştiriyoruz.

Player sınıfı ise observable modülünü kullanacağını belirterek başlıyor. Standart olarak bir kaç niteliği var. Oyununcun lakabını title niteliğinde tutarken, seviyesini level ve güncel puanını da point özelliklerinde tutuyoruz. Dikkat edilmesi gereken ilk nokta initialize metodundaki add_observer fonksiyonunun kullanımı. Bu metod iki parametre alıyor. İlki gözlemci nesne örneği, ikincisi ise bildirim için tetiklenecek olan fonksiyon adı(Eğer herhangibir metod adı belirtilmezse varsayılan olarak update metodu aranacaktır. Hafiften bir duck typing durumu da söz konusudur) Oyuncunun güncel puanını düzenleyen set_point metodunda ise notify_observers çağrısı yapılıyor. Bu çağrıya göre PlayerObserver sınıfındaki notify metoduna o anki Player nesne örneğinin kendisi(self kullanımı ile) ve puanı taşınıyor. Tahmin edeceğiniz gibi birden fazla observer nesnesinin tanımlanması ve tamamına ait olay yayınlanması mümkün. 

Uygulamanın çalışma zamanı sonuçları aşağıdaki gibi olacaktır.

Görüldüğü gibi oyuncunun puanları değiştikçe bunu gözlemleyen sınıftaki notify metodu tetiklenmiş ve bir takım aksiyonlar oluşmuştur. Bu örnekte sadece ekrana bildirim yapılmış olsa da gerçek hayat örneklerinde ilgili bildirim operasyonlarında çok daha farklı işlemler gerçekleştirebilir. Söz gelimi oyuncu için puanına göre bir promosyon kodunun üretilip kendisine alternatif kanallar ile bildirilmesi ve benzeri kuyruklanabilecek asenkron operasyonlar düşünülebilir. 

Pek tabii set_point metodu içerisinde o anki Player nesne örneğinin level değeri belirlenebilir. Buradaki amaç nesnenin çalışma zamanındaki varlığında olacak değişiklikler sonucu bir diğer nesne(veya nesnelerin) uyarılmasıdır. Farklı nesne örnekleri üzerinde olacak değişiklilerin çeşitli gözlemleyiciler tarafından veya bir nesne örneğinde olacak değişiklilerin n sayıda gözlemci tarafından yakalanması gibi vakalarda değerlendirilebilecek bir tasarım kalıbı olarak düşünülmesinde yarar vardır.

Böylece geldik bir kod parçacığının daha sonuna. Bu kısa yazımızda Observer tasarım kalıbının Ruby tarafında nasıl uygulanabileceğini basitçe incedik. Size tavsiyem Observable modülünü detaylı bir şekilde incelemeniz. Nitekim eklenen bir gözlemcinin nasıl kaldırılabileceği, ilgili gözlemcinin bir bildirim operasyonunun olup olmadığını kontrolü, ortamda kaç gözlemcinin olduğu ve benzeri işlevsellikleri de kullanmanız gerekebilir. Bir başka kod parçasında görüşmek üzere hepinize mutlu günler dilerim.

Viewing all 351 articles
Browse latest View live