Go İle Yazılım Geliştirme

Yasin Özmen
Turk Telekom Bulut Teknolojileri
9 min readJun 20, 2023

Bu yazımızda Go programlama dilinin ortaya çıkış süreci, çözmeye talip olduğu sorunlar, Go dilinin syntaxı ve keywordlerinden bahsedeceğiz.

Go programlama dili geçmişte B, C, Unix, Hotspot ve JVM gibi günümüz yazılım teknolojilerinin temelini oluşturan ve devrim niteliğindeki birçok teknolojinin geliştirilmesinde önemli yerlere sahip olan Ken Thampson, Rob Pike ve Robert Griesemer tarafından açık kaynak olarak tasarlandı ve 2007 yılında ilk adımları atıldı. 2009 yılında tanıtılıp, 28 Mart 2012 tarihinde Go 1.0 olarak yayınlandı.

Aşağıdaki eposta Go dilini geliştirmeye başladıkları sırada atılmıştır.

Tam da bu noktada özellikle yazılım alanında başarılı bir öğrenme süreci yürütmek ve bu süreci monotonluktan kurtarmak ile ilgili bahsetmek istediğim bir konu var. Yazılım alanında herhangi bir programlama dili veya aracı öğrenmeye başladığımızda o teknolojiye neden ihtiyaç duyulduğunu, hangi sorunu çözdüğünü ve diğer çözüm önerilerinin neden yetersiz olduğunu anlamaya çalışmak öğrenme sürecimizi hızlandıracak ve o teknolojide derinleşme isteğimizi arttıracaktır. Aksi taktirde yapılan yüzeysel çalışmalar bizleri sıkabilir ve ezber bozan bazı durumlarla karşılaştığımızda bunların ortaya çıkmasında ki temel motivasyonu bilmediğimiz için bu yenilikleri yadırgayıp başarısız bir öğrenme süreci yaşayabiliriz. Bunu somutlaştırmak adına bir örnek verecek olursak; örneğin özellikle kısa mesafelerde hızlı yolculuklar yapmak için tasarlanmış olan ve neredeyse insanın yaya olarak geçebildiği her yerden geçebilen, genelde ayakta kullanılan elektrikli scooterlar hakkında insanların “biz bu aracı 5 kişi aynı anda oturarak kullanmak istiyoruz ama sığmıyoruz” şeklinde bir eleştiri yapması oldukça abestir. Çünkü bu araç geliştirilirken başka bir sorunu çözmeye odaklanılmıştır. Belki bu eleştiri içi dar olan bir SUV araç için yapılabilir ama scooter için yapılamaz. Tabi ki insanlar bir scooterın neden üretildiğini ilk bakışta anlayabildikleri için bu eleştiriyi yapan kişi sayısı oldukça azdır belki de hiç yoktur. Ancak yazılım alanındaki bir teknolojinin neden ortaya çıktığını ismine, syntaxına veya komutlarına bakarak anlamak neredeyse mümkün değildir. Belki bir dilin synataxını diğer dillerle karşılaştırıp aradaki farklara bakarak birtakım yorumlar yapılabilir ancak bir Kubernetes komutuna bakarak Kubernetes’in neden ortaya çıktığını ve hangi sorunu çözdüğünü anlayamazsınız. Ortaya çıkış nedeni ve çözmeye talip olduğu sorunun ne olduğunu bilmeden bir teknolojiyi öğrenmeye çalışmak bana göre o teknolojide derinleşmenin önünü tıkayan bir sebep. Bu nedenle öncelikle Go programlama diline neden ihtiyaç duyulduğuna bakalım.

Yukarıda isimlerini ve yazılım dünyasına katkılarını saydığımız, sektörde çok önemli yerlere sahip olan bu üç mühendis o sırada Google’da çalışıyordu ve şirketin ihtiyaçları için yeni bir programlama dili arayışına girilmişti. Bu arayışa girilmesinin nedeni aslında Google’ın altyapısıyla ilgiliydi. Çoğunlukla C++, Java ve Python dillerinin hâkim olduğu büyük bir altyapı üzerinde, binlerce geliştirici çalışıyordu.Aslında bu dillerin ortaya çıktığı tarihlerdeki sistemlere baktığımızda bu sistemlerin yapısında ve geliştirici ekiplerinde büyük değişikliklerin olduğunu görüyoruz. Günümüzde büyük ölçekli yazılımlar 10 milyonlarca kod satırından oluşuyor ve üzerlerinde binlerce geliştirici çalışıyor. Sistemlere gelen request sayısının bu dillerin ortaya çıktığı dönemlerle karşılaştırılamayacak kadar fazla olduğunu, yazılımların her gün güncellenerek yeni özelliklerle donatıldığını, derleme sürelerinin geliştiricilerin çalışma verimliliğini azaltacak seviyelere ulaştığını ve tüm bu zorluklara rağmen bu yazılımları kullanan kullanıcıların 10–15 yıl önce adını bile duymadıkları bu sistemlerle çok hızlı bir adaptasyon süreci sonunda neredeyse onlardan kopamayacak derecede bağlantı kurduklarını, her hangi bir kesintiye kesinlikle tahammüllerinin olmadığını görüyoruz. Aslında Google’ın servislerine baktığımızda bu saydığımız durumların var olduğunu görürüz. Google, donanım ve yazılım altyapısının bu devasa büyüklüğünü ve bu altyapı üzerinde geliştirme yapmanın yavaş ve verimsiz olması sorununu; basit, modern ve diğer dillerin ek bağımlılıklarla çözdüğü sorunları dil bazında halleden, derleme süresi hızlı ve çıktılarının boyutu oldukça az yer kaplayan yeni bir dil geliştirerek çözmeye karar verdi. Go projesinin amacı Google’daki yazılım geliştirme sürecinin daha verimli ve ölçeklenebilir hale getirilmesiydi. Bu yönüyle Go, büyük ölçekli yazılım geliştirmeyi zorlaştıran sorunları ele alıp bunları çözmek için geliştirildi. Go’nun tasarımcılarından Rob Pike “Go at Google : Language Design in the Service of Software Engineering” adlı makalesinde Google’ın bu problemlerin çözümünün yeni bir dil tasarlamaya değer olduğuna inandığından bahsediyor ve bu bağlamda tasarlanacak bir dilin başarılı olması için gereken bazı nedenlerden söz ediyor. Örneğin tasarlanacak olan bu yeni dilin syntaxının tanıdık olması gerektiğini ve geliştiricilerin genelde C ailesinden olmak üzere prosedürel dillere aşina olduklarını söylüyor. Go’nun syntaxına baktığımızda kabaca C ye çok benzediğini görüyoruz. Ayrıca bir başka madde de ise bu sorunların daha kolay çözülebilmesi için dilin modern olması gerektiğini, C, C++ ve bir nebze Java’nın çok eski olduğunu, çok çekirdekli mimariler, ağ iletişimi ve modern web uygulamaları geliştirilmeden önce tasarlandığını ifade ediyor. Go dili tasarlanırken bu maddeler dikkate alınarak çalışıldı ve syntax olarak C diline benzeyen ancak C’de bulunmayan yerleşik eş zamanlılık ve garbage collector mekanizmasını da içinde bulunduran basit, öğrenmesi kolay ve derlenmiş bir dil ortaya çıktı. Go’nun en önemli özelliklerinden biri de çoğu dilin ekstra bağımlılıklarla çözmeye çalıştığı eş zamanlılık konusunu dil seviyesinde yerleşik olarak sunmasıdır. Eş zamanlılık konusuna başka bir yazıda değinebiliriz ancak Go bu desteği ile aynı anda birden fazla görevi yerine getirebilen programların geliştirilmesini kolaylaştırmıştır ve bu konu birçok modern yazılım için çok önemlidir. Go dilini diğer modern dillerden ayıran özelliklerini verimli, sade, dil bazında eş zamanlılık desteği vermesi ve daha birçok madde sıralayarak tanımlayabiliriz. Tüm bunlarla beraber Google’ın Go dilini açık kaynak olarak paylaşması yazılım dünyasına büyük bir katkı sunuyor. Aslında ilk bakışta açık kaynak yazılımların gücünü tam olarak anlayamayabiliriz. Google’ın sistemlerindeki can sıkıcı durumları düzeltmek için yeni bir dil geliştirmeye başlayıp zaman ve para harcadığı, bu sürecin sonunda programcılarını daha üretken yaptığı ve bu nedenle de geliştirme süreçlerini daha verimli hala getirmesine yardımcı olan bir ürününü açık kaynak yapıp, ücretsiz bir şekilde tüm dünyaya sunmuş olması ilginç gelebilir. Ancak bunun faydalarını göz önünde bulundurursak bu kararın yine en çok Google’a fayda sağladığını görürüz. Aslında yeni bir programlama dilinin hem kendi gelişimi hem de yazılım dünyasında yaygınlaşması için o dili kullanan çok sayıda kişiye ihtiyacı vardır. Bir dilin hatalarını bildiren çok sayıda kişiye ihtiyacı vardır, böylece sorunlar hızlı bir şekilde belirlenir ve giderilir. Açık kaynak olarak sunulmuş bir dilin bir diğer faydası ise o dili birçok farklı amaç için kullanan çok sayıda insana sahip olmasıdır, böylece dil tek bir kullanım alanına sıkışmış olmaz, bu nedenle de hızla gelişen teknoloji ve konseptler karşısında işe yaramaz hale gelmez. Eğer bir dil açık kaynak olursa insanların hakkında kitap yazabileceği, kurslar verebileceği veya konferanslar düzenleyeceği bir pazarı oluşur. Geliştiriciler açısından baktığımızda ise geliştiriciler açık kaynak bir dili tercih ettiklerinde belirli bir araç veya kütüphaneye ihtiyaçları olması durumunda bu konuyu kendilerinden daha iyi bilen ve kendilerinden daha fazla zaman harcayan biri tarafından zaten yazılmış olma ihtimali yüksektir. Go, eğer Google bünyesinde kalmış olsaydı bu saydıklarımızın hiçbiri gerçekleşemezdi. Go’nun standart kütüphanesi de çok geniş ve kullanışlıdır. Web geliştirme tarafındaki framework kısmına bakacak olursak Spring Framework gibi yer edinen bir framework yoktur ancak Go ekosisteminde de birçok web frameworkü vardır. Bunlardan en iyisi hangisidir? diye bir kıyaslamaya gitmeyeceğim çünkü bu ihtiyaçlara göre değişebilir ancak Gin ve Fiber frameworkleri öne çıkmaktadır. Bunlardan Fiber’e bakacak olursak; Go ile yazılmış yüksek performanslı, hafif, öğrenmesi kolay, ölçeklenebilir ve güvenilir olarak tasarlanmıştır. Standart library ve net/http paketini temel alır, birçok şirket tarafından kullanılır ve aktif bir topluluğa sahiptir. Fiber ve Gin dışında Echo, Beego, Gorillo-mux gibi çeşitli frameworklerde vardır.

Aslında Go, çok çekirdekli mimariler, ağ iletişimi ve modern web uygulamaları gibi günümüz teknolojisinin vazgeçilmezi olan kavramlar hali hazırda mevcutken ve bu teknolojiler de dikkate alınarak tasarlanan yeni ve modern bir dil olduğu için çok rahat bir şekilde framework kullanılmadan da web geliştirme yapılabilir.

Yazımızın buraya kadar olan kısmında Go diline neden ihtiyaç duyulduğundan, özelliklerinden ve diğer modern dillerle aralarında ki farklardan bahsettik. Aslında bu konularda daha fazla şey söylenebilir ancak yazıyı daha fazla uzatmamak adına bu kısmı burada noktalıyorum. Şimdi ise Go dilinin keywordlerine ve syntaxına göz atıp yazımızı noktalayalım. Aslında Go diline basit ve sade derken bunun en büyük nedenlerinden biri keyword sayısının az olmasıdır. Go dilinde 25 tane keyword vardır. Bu sayı diğer dillerde göre çok çok azdır örneğin C dilinde 37, C++ da ise 84 keyword bulunmaktadır. Şimdi de bu keywordlerle alakalı örneklere göz atıp yazımızı noktalayacağız. Aşağıda Go dilinde bulunan keywordleri görebilirsiniz.

break, default, func, interface, select, case, defer, go, map, struct, chan, else, goto, package, switch, const, fallthrough, if, range, type, continue, for, import, return

Go ile hello world yazalım;

package main

import "fmt"

func main() {
fmt.Println("Hello World")
}

Go ile değişken tanımlama;

var isim string = “Ahmet”
var yas int = 25
var ogrenci bool = false

Yukarıdaki yazdıklarımızı inceleyecek olursak; var ile değişken atadığımızı belirtiyoruz. isim diye bir değişken adı atadık ve içine “Ahmet” değerinde string tipinde bir değer yerleştirdik. String tipi değerler çift tırnak içine yazılır. Aynı şekilde yas adında değişken oluşturduk. yas değişkeni içerisine int tipinde 25 değerini yerleştirdik Son olarak ogrenci adında bir değişken oluşturduk ve false değerinde boolean tipinde bir atama yaptık.Matematiğin aksine = (eşittir) işareti atamalar için kullanılır. Yani = (eşittir) işaretinin sağ tarafında bulunan değeri alıp, sol taraftaki değişkenin içine atar.

var isim = “Ahmet”
var yas = 25
var ogrenci = false

Değişken atamasında değişkenin veri tipini belirtmemiz zorunlu değildir. Yazdığımız değere göre Golang otomatik olarak veri tipini algılar. isim değişkeninin değerini çift tırnak arasına yazdığımız için string veri tipinde olduğunu anlıyor. Aynı şekilde diğer değişkenlerde de = (eşittir) işaretinin sağ tarafında hangi tipte değer yazarsak ona göre tip algılaması yapıyor.

En sade şekilde değişken ataması yapmak istersek;

isim:=”Ahmet”
yas:=25
ogrenci:= false

Burada var eklemeden de değişken tanımlanabildiğini gördük. Bunu := işaretlerini kullanarak yaparız. Bu yöntemde de verinin tipi otomatik algılanır.

Go dilinde if-else kullanımıyla ilgil basit bir örnek;

if num := 9; num < 0 {
fmt.Println(num, "is negative")
} else if num < 10 {
fmt.Println(num, "has 1 digit")
} else {
fmt.Println(num, "has multiple digits")
}

For, break, continue keywordlerinin kullanımı;

package main

import "fmt"

func main() {
for i := 0; i < 10; i++ {
if i == 5 {
break
}
if i == 3 {
continue
}
fmt.Println(i)
}
}

Switch case;

num := 1

switch num {
case 1:
fmt.Println("The number is 1")
case 2:
fmt.Println("The number is 2")
default:
fmt.Println("The number is neither 1 nor 2")
}

func anahtar sözcüğü: func anahtar sözcüğü bir işlevi tanımlamak için kullanılır.

 func hello() string {                                                          
return "Hello, world!"
}

Defer keywordüne bakalım;

package main                                                                     

import "fmt"

func main() {
defer fmt.Println("world")

fmt.Println("hello")
}
Kodun Çıktısı:
hello
world

Burada defer ile sarmalanan kod en son çalışır. Yazımızın sonunda bu konuyla alakalı bir örnek yapacağız.

Keywordlere baktığımızda exception konusu dikkatimizi çekmiş olabilir. Diğer dillerde bulunan try catch yapısı Go da yoktur. Bunun yerine, anormal bir durumu belirtmek için hata değerlerini kullanır. Örneğin, os.Open işlevi, bir dosyayı açamadığı zaman nil(başka dillerde null) olmayan bir hata değeri döndürür. Go’da hataları işlemenin yaygın olan şekli çoklu dönüş değerlerini kullanmaktır;

Çoklu Dönüş Değerleri

os.Open işlevi iki değer döndürür: bir dosya işaretçisi ve bir hata değeri. Dosya başarıyla açılırsa, dosya işaretçisi nil olmaz ve hata değeri nil olacaktır. Dosya açılmazsa, dosya işaretçisi sıfır olur ve hata değeri nil olmayacaktır. Aşağıdaki kod, hataları işlemek için birden çok dönüş değerinin nasıl kullanılacağını gösterir:

file, err := os.Open("file.txt")
if err != nil {
fmt.Println(err)
return
}

Bu örnekte if ifadesi, os.Open tarafından döndürülen hata değerini kontrol eder. Hata değeri nil değilse, if ifadesi hata mesajını yazdırır ve döndürür. Aksi takdirde, if ifadesi yürütmeye devam eder ve dosya işaretçisi dosyayla bir şeyler yapmak için kullanılır.

Defer keywordünü daha iyi anlamak için bir database connection örneği yapalım.

package main

import (
"database/sql"
"fmt"
)

func main() {
// Open a database connection.
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/database")
if err != nil {
fmt.Println(err)
return
}

// Use the database connection.
defer db.Close()

// Do something with the database connection.
_, err = db.Query("SELECT * FROM table")
if err != nil {
fmt.Println(err)
return
}

}

Bu örnekte, defer ifadesi, veritabanı bağlantısının kapatılması kodunda kullanılmıştır. Defer sayesinde db.Close() komutu programın sonuna ertelenir ve programın çalışması durdurulmadan önce çalışıp database bağlantısını kapatır bu da uzun kod bloklarıyla yapılan işlemlerde db connection bağlantısının kapatılmasını unutmamızın önüne geçer.

Keywordlerden bir kısmını basit ve anlaşılır örneklerle incelemiş olduk. Bir sonraki yazıda concurrency, goroutine gibi konulardan bahsedip geriye kalan keywordleri tanıtmaya çalışacağım. Bir sonra ki yazıda görüşmek üzere…

Buraya kadar okuduğunuz için teşekkürler, umarım faydalı olmuştur..

KAYNAKÇA:

https://pkg.go.dev/os

https://go.dev/tour/flowcontrol/12

https://go.dev/talks/2012/splash.article

https://go.kaanksc.com/boeluem-1

--

--