Follow

Follow

Go 1.11 ile gelen yeni Module özelliği — 1. Bölüm

Tarik Guney's photo
Tarik Guney
·Sep 4, 2018·

8 min read

Module kavramını anlatmadan önce, Module ile ne çözülmek isteniyor sorusuna cevap verebilmek adına biraz genel kavramlardan başlamak lazım. Ama bu kısımları biliyorsanız, o zaman background kısmını direk atlayabilirsiniz. Bu makaleyi anlamak için aşağıda Go bilgilerini bilmeniz gerekiyor: Workspace kavramı, Go paketleri, Go CLI. Kısacası Go dilini hiç kullanmadıysanız, o zaman bu makaleyi çokta anlamayacaksınız.

Background

Başkalarının geliştirdikleri kütüphaneleri kullanmadan en basit uygulamaları bile neredeyse yazamadığımız zamanlardan geçiyoruz. Bundan dolayı her programlama dilinin belkide en önemli özelliği olarak karşımıza çıkıyor paketler. Paket (Package) ya da diğer bir ismi ile yeniden kullanılabilir kod üniteleri, örneğin kütüphaneler, hızlı ve güvenilir kod yazmak ve gelişen endüstride iş değeri olan ürünler çıkarmak için fazlasıyla dominant bir konsept. Farklı diller bunu farklı isim ve formatlarda sunuyorlar. Mesela, Java da .jar dosyaları, .NET ortamında .dlldosyaları, ve asıl konumuz olan Go programlama dilinde ise go get library-name demek suretiyle indirilen ve kendi kodunuza import ettiğiniz paketler. Çoğu zaman derlenmiş halde indirir ve kullanırsınız bu paketleri. Ama, Go diğer dillerden farklı olarak, derlenmiş kodu değil, kaynak kodları paket olarak indirir, indirdiği bu dosyalar src klasörü altına koyar. Derlemeyi hızlandırmak içinde bu kaynak kodları pkg klasörü altında object dosyaları olarak saklar.

Yazılım çoğu zaman iterative bir süreçtir ve bundan dolayı projelerimiz devamlı değişir. Bu hem kendi uygulamalarınız hem de uygulamalarınızın kullandığı kütüphaneler için geçerlidir. Bu devamlı geliştirme sürecinde amaç daha kaliteli ürünler çıkarmak olsa da, ciddi bazı sorunlarında beraberinde getirir. Güncellediğiniz kütüphanelerin API’larında büyük değişimler, kodunuzu büyük bir ihtimalle bozacaktır. Versiyonlama bundan dolayı çok önemlidir. Hangi versiyonlar ile çalıştığınızı bilmek zorundasınız. Projeniz de kullandığınız kütüphanelerin versiyonları değişmediği sürece beklenmedik bir problem ile karşılaşma riskiniz ciddi oranda azalacaktır.

Kullandığınız kütüphaneler de bu versiyon sorunlarından kurtulmanın en kolay yöntemi, onları da kodunuzla beraber Git (ya da başka bir VCS) reponuz içinde saklamak olacaktır. Tabi bu kesin çözüm olmayabilir.

Ama sundukları önemli artılardan dolayı package managers (NPM, NuGet, vs) kullanıyorsanız, o zaman package.json gibi dosyalar içinde bir kütüphanenin hangi versiyonunu kullandığınızı belirtmek daha bir önem kazanıyor. Aksi halde kütüphaneleri her download edişte, en yeni versiyonları indirileceği için API’lar arasında ki uyumsuzluktan dolayı kodunuz her an break edebilir. Bu ciddi bir sorun olduğu için, bazı package manager uygulamaları lock isminde, versiyonları birebir saklayan dosyaları projelere eklemeye başladılar.

Paket kavramlarına ve versiyonlamanın önemine kısaca değindikten sonra şimdi Go da Module kavramını anlatabiliriz.

Modules in Go

Module, versiyonlanmış kaynak kodları kümesi. .DLL ya da .JAR gibi düşünülebilir. Tabi farklılıkları var. Bu farklılıkların ne olduğunu ise bu yazı dizimde anlatmaya çalışacağım.

Problem

Go ilk çıktığından beri paketleri için native olarak versiyonlama desteği vermedi. Bu soruna cevap olması için araçlar geliştirenler oldu ama herkes tarafından kullanılan ortak çözümler olmadı. Sonrasında Go tarafından dep diye bir araç geliştirildi. Go 1.11 ile dep yerini vgo ya bırakmaya başladı. Bunların dışında Go içinde vendor özelliği vardı. Yani go get ile getirmek istemediğiniz paketleri, vendor klasörü altında saklıyordunuz. Bu da farklı vendorların kaynak kodlarının sizi kodunuz ile birlikte kaynak kod kontrol sistemlerinde saklanması demekti. Bu sayede versiyonlama sorunlarından bir nebze kurtulabiliyordunuz.

dep gibi araçlar kullanmadığınızda, Go package meselesinde sorunlu olan bir dil. Diyelim ki, kullandığınız uygulama aşağıdakine benzer bir dependency durumu mevcut:

YourApp 3.0 > HelloMars 2.0 > HelloWorld 1.0

Yani sizin YourApp uygulamanız, HelloMars kütüphanesine bağımlı. HelloMars kütüphanesi de HelloWorld kütüphanesini kullanıyor. Bir zaman sonra yeni bir kütüphane daha eklediniz ve o da HelloWorld 2.4 kütüphanesini kullanıyor:

YourApp 3.0 > HelloJupiter 2.1 > HelloWorld 2.4

Bu arada Go da bu şekilde versiyonlama anlayışı yok ama kütüphaneyi develop eden arkadaş bu şekilde versiyonlama yapıyor diyelim. Paketler de workspace’de ki src klasöründe saklandığı için, go getile HelloJupiter kütüphanesi getirdiğinizde, önceden HelloWorld paketi indirilmiş olduğu için o zaman yeniden indirmeyecek ve dolayısıyla HelloJupiter paketi, HelloWorld 1.0 versiyonu kullanıyor olacak. Sonuç? 2.4 versiyonu nu bekleyen bir kütüphaneye 1.0 versiyonu verirseniz, olacak şey, kodun bozulması olacaktır. İşte bugüne kadar Go bu şekilde versiyonları ayırt etmediği için, başınıza buna benzer problemler geliyordu. Eğer go get -u derseniz, o zaman bu paketler güncellenecek ve HelloWorld 2.4 versiyonu indirilecek. Sonrasında? Sonrasında ise HelloMars, HelloWorld 1.0 kullanmak yerine HelloWorld 2.4 versiyonunu kullanıyor olacağından kodunuz yine break etme riski ile karşı karşıya kalacaktır. Kısacası yukarı tükürsen bıyık, aşağı tükürsen sakal.

Çözüm

Versiyonlama. Go 1.11 ile Go CLI içinde destek verildi. Bir süredir vgo ile prototip olarak test ediliyordu. vgo, command line üzerinde çalıştırabilecek ayrı bir app. Go dan ayrı olarak indirip kullanmanız gerekiyordu. Artık onda ki özellikler go CLI içine entegre edildi ve dolayısıyla ayrı bir şekilde download edip kullanmanıza gerek yok. Ama unutmadan söyleyeyim, Go yazılımcıları hala bu modules sistemi üzerine çalışıyorlar ve ileride ufak bazı değişikler olabilir ama genel konseptin değişeceğini düşünmüyorum.

Go eksi sisteme verdiği desteği kaldırmadı. Dolayısıyla, modules özelliğini kullanacağınızı açık bir şekilde belirtmeniz gerekiyor. Bunun için aşağıda ki yöntemleri kullanabilirsiniz:

  1. go komutunu $GOPATH/srcklasörü dışında kullanın ve go projenizin go.mod dosyasına sahip olduğuna emin olun.

  2. Command line içinde GO111Module ortam değişkenine on değerini atayın.

  3. vgo uygulamasını indirip kullanın.

Yukarıda ki yöntemlerden her biri modules özelliğini kullanmanızı sağlayacaktır.

Yeni modules özelliğini kullandığınızda artık paketlerinizi import ederken, aşağıda ki koda benzer şekilde import edeceksiniz:

import “example.com/my/module/v2/pkg/foo”

Bu şu demek, foo paketini v2 den getir.

Aynı zamanda NPM de kipackage.json dosyasına benzer olarak ayrı bir dosya geldi go.mod isminde. İçerisinde ki kod ise Go yazılımcılarına familiar gelecektir:

module github.com/my/module/v3

require (
    github.com/some/dependency v1.2.3
    github.com/another/dependency v0.1.0
    github.com/additional/dependency/v4 v4.0.0
)

Eğer var olan bir projeye module desteği eklemek isterseniz, o zaman go mod init demekle go.moddosyasının projenize otomatik olarak eklenmesini sağlayabilirsiniz. Sonrasında go build demekle ya da bu komutu çağıran başka bir komut kullanmak ile kaynak kodlarınızın otomatik olarak incelenmesini ve kullandığınız kütüphanelerin versiyonları ile birlikte go.moddosyasına eklenmesini sağlayabilirsiniz.

Modüller seçilirken, eğer versiyonları belirtilmemiş ise, o zaman en yüksek versiyonları ile go.mod dosyasına eklenecekler.

Peki nereden geliyor bu versiyon numaraları?

go get dediğiniz zaman paketler GitHub gibi yerlerden geliyor. Git reponuzda tag kullanarak istediğiniz commitlere versiyon verebiliyorsunuz. İşte, yeni versiyon numaraları buralardan geliyor.

Devamı Sonra

Buraya kadarki kısım Go modülleri hakkında kısa bir bilgi vermek içindi. Bundan sonra ki yazılarımda detaylara inerek yeni Modules sisteminin farklılıklarını ve nasıl çalıştığını daha derinlemesine incelemeye çalışacağız.

 
Share this