Open Source Pakete Yazdığım Kod Golang Projelerini Nasıl Patlattı, Neler Öğrendim

Emre Savcı
5 min readAug 27, 2022

Merhabalar, bugün sizlere popüler bir open-source projeye yaptığım geliştirmenin, dünya çapında projeyi kullanan kişilerin nasıl hata almasına sebep olduğunu ve bu süreçten neler öğrendiğimi anlatacağım.

İçerik

— Swaggo Projesi
— İhtiyaç ve Yaptığım Katkı
— Yaşanılan Sorun
— Sorunun Sebebi
— Body Barındırmayan Function Tanımları (go:linkname)
— Sorunun Çözümü
— Öğrendiklerim

SWAGGO Projesi

https://raw.githubusercontent.com/swaggo/swag/master/assets/swaggo.png

Go dilinde geliştirdiğiniz API projelerinize swagger dökümanı oluşturmak, Java, C# gibi dillerden biraz farklı. Genellikle yazdığınız kodun içerisinde yorum satırlarında Swagger direktifleri ekleyerek oluşturabiliyorsunuz ve bunun için çok fazla alternatifiniz yok.

swaggo/swag projesi en popüler ve yaygın olarak kullanılan çözümlerden birisi.

Bu projenin yaptığı temel işlem, Go dosyalarını gezip yapılan tanımlamalardaki yorum satırlarını işleyerek swagger dökümanını oluşturuyor. Bu işlemleri de Abstract Syntax Tree (AST) oluşturup gezerek yapıyor.

İhtiyaç ve Yaptığım Katkı

Ekip arkadaşımla beraber bir projemiz için swagger dökümanı oluşturmaya çalışırken swaggo/swag aracını kullanarak istediğimiz tanımlayı yapamadığımızı fark ettik.

Yapmak istediğimiz şey, request ve response objelerini oluşturduğumuz handler fonksiyonunun içerisinde tanımlamak ve sadece fonksiyon içerisinden erişilmesini sağlamaktı. Fakat bunu yaptığımız zaman, ilgili request ve response objelerine swaggo/swag parser paketi erişemiyordu.

Ben de bu sorunu aşmak amacıyla swaggo/swag kütüphanesine bir katkı yapmak istedim.

Öncelikle kütüphaneye issue açıp böyle bir ihtiyacımız olduğunu ve bu geliştirmeyi yaparak katkı sağlamak istediğimi sordum.
Cevap olarak, private tanımlamaları parse etmenin mümkün olmadığını ve nasıl yapacağımı sorduklarında, sunduğum öneriyi merak ettiklerini ve geliştirmeyi beklediklerini söylediler.

Ben de kolları sıvadım. İlk fırsatta geliştirmeyi yaptım ve projeye PR açtım.

Yaptığım geliştirme sonucu request/response objeleri fonksiyon içerisinde tanımlanabilir hale geldi. 💪

https://github.com/swaggo/swag#function-scoped-struct-declaration

Yaşanılan Sorun

Bir cuma akşamı… Mesai bitti bitecek, dakikalar var… Haftasonuna girmeyi iple çekiyorum… Veee… Ekip arkadaşımdan, projelerimizden birinin hata aldığına dair mesaj geldi 😞

Aslında tam konuşmayı paylaşmak istiyorum:

Hemen projenin Github sayfasına gittik ve issue kısmına baktık. Ve gördüğümüz şey beni biraz tedirgin etti.

Birçok swaggo/swag paketi kullanıcısı hata yaşıyordu ve hepsi de benim yaptığım geliştirme sebebiyle CI/CD pipeline’larında veya manuel olarak swagger generate etme işleminde hata alıyordu.

Açıkçası bu duruma şaşırmıştım çünkü yaptığım geliştirme için unit testler yazmıştım ve kod doğru çalışıyordu. Hatta önceki hiçbir geliştirmeyi de bozmadığını mevcut unit testlerin başarılı bir şekilde geçmesi ispat ediyordu.

Peki sorun ne olabilirdi? 🤔

Sorunun Sebebi

swaggo/swag için yaptığım geliştirmeden bir ekran görüntüsü ekliyorum.

https://github.com/swaggo/swag/pull/1283/files#diff-aebc2b97b017fa9527f4d3b954e8718fafbbe3af43a26de7d20c976746abed10R168

Hata mesajlarında da gördüğümüz üzere hataparseFunctionScopedTypesFromFile methodunda alınıyor. Hatta tam olarak hata alınan satır da 168.

Şimdi yazdığım bu methoda daha yakından bakalım.

168. satırda AST geziliyor ve içerisindeki tanımlamalar arasında FunctionDecleration var ise tanımlanan fonskiyonun içerisinde neler yazılmış bunu bir for döngüsü ile geziyor.

Peki bir fonksiyon tanımının var olduğundan eminsek, neden bu fonksiyon tanımını for döngüsü ile gezmeye çalışırken hata alıyoruz?
Nil pointer hatası neyden kaynaklı?

functionDeclaration.Body değişkenine baktığımızda pointer tipinde olduğunu görüyoruz.

Burada bir nil kontrolü yapmamıştım çünkü eğer bir fonksiyon tanımlandıysa o fonksiyonun body tanımı olacağını varsaymıştım.

Fakat gerçekte öyle olmayabilir.👇

Body Barındırmayan Function Tanımları

Bu tabir size yabancı geliyor mu? Bir fonksiyonu body yazmadan tanımlayabilir miyiz?

Aşağıdaki kodu ele alalım, sizce bu kod Go dilinde geçerli bir tanım mıdır?

Çalıştırmayı denersek hata alır mıyız?

Evet tahmin ettiğiniz üzere bu kodu çalıştıramayız, hatta compile edemeyiz çünkü geçerli bir tanımlama değildir.

Peki ya aşağıdaki kodu çalıştırabilir miyiz?

Burada ise bir öncekinden farklı olarak cevap evet çalıştırabiliriz olacak.

Go’nun az bilinen bir özelliği olan go:linkname direktifi ile bir fonksiyon tanımını başka paketlerin fonksiyon tanımlarına linkleyebiliyor olmamız.

Böylelikle body tanımı yapmadan fonksiyon tanımlayabiliyoruz.

Ve hatta dikkat ettiyseniz bu özellik, Go runtime paketi altında tanımlanan private bir fonksiyonu kullanabilmemi sağladı.

Projelerimizde kullandığımız harici bağımlılıklar bu gibi fonksiyon tanımlamalarına sahip olabilir. Ve swag --parseDependency komutu ile swagger dökümanı oluşturmaya çalıştığımızda, bağımlılıkları da parse ettiği için bu tanıma sahip fonksiyonlar yaptığım geliştirmede panic yaşanmasına sebep oluyordu.

Sorunun Çözümü

Hemen sorunu çözmek için geliştirme yapacaktım fakat open-source topluluğun güzel yanı bu ki bir başka geliştirici benden önce hatayı fixleyen kodu yazıp PR oluşturmuş.

Öğrendiklerim

Bu yaşanan sorunla birlikte kendime bazı dersler çıkarttım.

Asla nil pointer kontrolünü varsayımla atlama
Unit testler her zaman yeterli olmayabilir. End to end test adımını atlama
Go ile go:linknamekullanarak body tanımı olmayan fonksiyon yazabilir, private paketlerdeki fonksiyonları import edebiliriz
Asla paket bağımlılıklarını latest version yapma, çalıştığına emin olduğun versionu belirt

Umarım sizler için eğlenceli ve faydalı bir içerik olmuştur. Kendize iyi bakın bugsız kodlar dilerim 🙏

Social

Twitter
Github

Support mstrYoda on Github

--

--

Emre Savcı

Sr. Software Engineer @Trendyol & Couchbase Ambassador | Interested in Go, Kubernetes, Istio, CNCF, Scalability. Open Source Contributor.