1-Static Code Analysis Detekt in QNB Android Mobile

Arif Mertaslan
IBTech
Published in
8 min read2 days ago

Giriş: Android Uygulamalarında Kod Kalitesi ve Static Analiz Araçları 📢

Herkese Merhaba Ben Arif,

QNB Mobil uygulamamıza bir süredir kattığımız yenilikleri sizlerle paylaşmak istedik. Bunun ilk aşaması olarak da uygulamamıza eklediğimiz detekt static kod analizini, geçiş sürecimizi, deneyimlerimizi paylaştığımız bir yazıyla başlıyoruz. Keyifli okumalar. 😊

Mobil uygulama geliştirme sürecinde, özellikle büyük ekiplerin çalıştığı büyük projelerde kod kalitesi ve tutarlılığı sağlamak önemli bir önceliktir. Bu bağlamda, static kod analizi araçları geliştiricilere büyük faydalar sağlayabilir. Bizim gibi 20'den fazla kişiden oluşan ekiplerde, her yazılımcının da bildiği gibi herkesin o yoğurdu yiyiş şekli farklı oluyor 😊. Bu farklılıklar, genel anlamda güzel olsa da büyük bir projenin ileri süreçlerinde büyük karmaşıklıklar doğurabiliyor. Bu yüzden, herkesin kod yazarken özgürlüğünü kısıtlamasak da projenin genelini kapsayan bir takım standartlar oluşturmak elzem oluyor. Kod tabanındaki hataları tespit etmek, standartlara uygunluk sağlamak ve genel olarak kod kalitesini artırmak için kullanılan static kod analizi araçları, yazılım projelerinin sürdürülebilirliği ve uzun ömürlülüğü için kritik bir rol oynuyor.

Biz de takımımızın sorumluluğunda olan QNB Mobile Android uygulamasında static kod analizini iyileştirmek ve mevcut iş akışlarımızı optimize etmek adına bir dönüşüm süreci yaşadık. Bu makalede, Ktlint ve SonarQube gibi yaygın olarak kullanılan araçların yerine Detekt kütüphanesine geçişimizin hikayesini ve bu sürecin bize kazandırdıklarını paylaşacağız.

Detekt’in sağladığı esneklik, özelleştirilebilirlik ve geniş kapsamı ile var olan standartlarımızın yanına yenilerini ekleyip, geliştirme sürecinde bu standartlara uyulmasını sağlayarak, code review’lerde standartlara odaklanmamızı engelleyip, böylece code review sürelerimizi minimize edebildik. Detekt’i build aşamamıza entegre edip aynı zamanda da CI adımına da entegre ederek, Pull Request’lerde ya da development aşamasında analizin otomatik olarak çalışmasını sağladık.

Detekt Nedir ve Neden Kullanmalıyız? 🤔

Detekt, Kotlin tabanlı projeler için geliştirilmiş açık kaynaklı bir static kod analiz aracıdır. JetBrains tarafından desteklenen bu araç, Kotlin dilinin özelliklerini tam olarak kullanarak kod kalitesini artırmaya yönelik geniş bir yelpazede analizler sunar.

Detekt’i tercih etmenin bizim için bir kaç önemli nedenini aşağıdaki gibi özetleyebiliriz:

  1. Kotlin Odaklı Analizler: Detekt, Kotlin dili için özel olarak tasarlanmış kurallar ve analizler sunar. Bu sayede, Kotlin’in sunduğu güçlü özelliklerden tam olarak faydalanabilir ve dilin sunduğu en iyi pratiklere uygun kod yazabilirsiniz.
  2. Esnek Yapılandırma ve Özelleştirme: Detekt, kullanıcıların ihtiyaçlarına göre kolayca yapılandırılabilir ve özelleştirilebilir. Projenizin gereksinimlerine uygun analiz kurallarını seçebilir, mevcut kuralları değiştirebilir veya kendi özel kurallarınızı ekleyebilirsiniz.
  3. Geniş Kapsam: Detekt, kodunuzdaki geniş bir yelpazede sorunları tespit edebilir. Stil kurallarından başlayarak, performans optimizasyonlarına kadar birçok farklı alanda analiz yapabilir ve kodunuzun genel kalitesini artırabilirsiniz.
  4. Topluluk ve Destek: Detekt, aktif bir topluluğa sahiptir ve sürekli olarak güncellenir. Bu da kullanıcıların karşılaştıkları sorunları çözmelerine ve yeni özelliklerin eklenmesine olanak tanır.

Geçiş Süreci: 👩‍💻

Bu geçiş sürecini iki ana soruda ele almamız gerekiyordu. Bunlardan ilki, detekt bize neler sunuyor, ne gibi kurallar ve özellikleri var, ikincisi ise bizim uygulamamız bu kural ve özelliklerin ne kadarını kabul edebilir durumda? QNB Mobil Andorid uygulaması çok uzun süredir hayatta olan ve geliştirmeye devam edilen büyük bir uygulama ve bu yüzden uygulamayı yazarken istediğimiz yeni bir standart ya da kuralı her an ekleyemiyoruz. Detekt ise yüzlerce kurala sahip bir kütüphane, burada detekt’in sahip olduğu kuralları inceleyip uygulamamız için uygun bulduklarımızı seçmemiz gerekti. Peki gelin bu süreç nasıl gelişmiş biraz onu inceleyelim.

1. Aşama Detekt Kurallarını İnceleme: 🔎

Buradaki süreci de tam olarak bu iki ana soru üzerine başlatmış olduk ve bu iş için bir çalışma grubu kurduk. İlk olarak detekt kurallarının incelenmesi ve her kuralın bize ne anlatmaya çalıştığını çözümlemiz gerekiyordu. Detekt kural setlerini aramızda paylaştık. Böylece, herkes üzerine düşen kural seti içerisindeki kuralları araştırdı ve tam olarak ilgili kurallarda bizden istenilen davranışın ne olduğunu bir dokümanda topladı. Daha sonra yaptığımız toplantılarda herkes incelediği kuralları çalışma grubu ile paylaştı ve çalışma grubunun belirli bir oranda fikir sahibi olmasını sağladı.

2. Aşama Uygulamamıza Uygun Kuralları Seçme Sürecimiz: ✅

Kuralları anlama ve yorumlama kısmında belirli bir ilerleme sağladıktan sonra, çalışma grubu, incelediği kuralların bizim uygulamada ne gibi bulgulara çözüm getirebileceğini, toplam kaç bulgu çıkardığını, bu bulguların yoğunlaştığı modülleri ve çözülme maliyeti gibi daha çok uygulamamızı ilgilendiren ikinci soruya odaklandı. Yine devam eden toplantılarımızda ilgilendiğimiz kuralları uygulama üzerinde denemiş, çıkan örnek bulguları bir dokümanda toplamış ve ilgili kuralın bulgu sayısını çıkartmış halde katılarak o kuralı bizim uygulamaya entegre etmeli miyiz diye tartıştık. Süre gelen toplantılardan sonra, detekt kural setini içeren yaml dosyamızı tamamlamış olduk. Böylece, detekt uygulamamıza entegre edilmeye hazır hale geldi.

İlk iki aşamada neler yaptığımız daha net anlamak için oluşturduğumuz dokümanlardaki tablolardan bir örneği aşağıda görebilirsiniz.

3. Aşama Detekt Kurallarının Entegre Edilmesi: 🔗

Uygulamamızda mevcutta ktlint ve sonarqube’un kullanıldığından bahsetmiştik, detekt, ktlint ve sonarqube’de yer alan belli başlı kuralları kapsayan kural setleri içerirken, ekstra olarak onlarca kuralı da içerisinde barındırıyordu. Burada çok detaya girmeden detekt kurallarından bahsetmek biraz daha açıklayıcı olabilir.

Yukarıdaki listede detekt’in kural setlerini görüyoruz, kural setlerinin isimlerinden yola çıkarak, Comment, Formatting, Style ve Empty-blocks kural setleri daha çok kodda ya da yorum satırlarında, bırakılacak boşluklarla, fonksiyonların, if-else gibi yapıların formatıyla alakalı kuralları içeriyordu. Bu kural setleri dışında kalan, Complexity, Coroutines, Exceptions, Libraries, Performance, Potential-bugs ve Ruleauthors kural setleri ise daha çok kodumuzun logical ve semantic yapısına odaklı analizleri içeriyordu.

Burada örnek olarak seçtiğimiz bir kaç kuralla karar aşamamızı sizlere özetlemek istiyorum.

İlk örnek olarak aşağıdaki kod parçacıklarında yer alan, takım içerisinde çok kabul gören, MagicNumber kullanımı dediğimiz integer değerlerin hardcoded kullanımının önüne geçecek kuralı aktif ettik. Böylece daha okunabilir kod blokları oluşturabileceğimizi düşündük.

Noncomplient code:

class User {

fun checkName(name: String) {
if (name.length > 42) {
throw IllegalArgumentException("username is too long")
}
// ...
}
}

Complient code:

class User {

fun checkName(name: String) {
if (name.length > MAX_USERNAME_SIZE) {
throw IllegalArgumentException("username is too long")
}
// ...
}

companion object {
private const val MAX_USERNAME_SIZE = 42
}
}

Uygulamada detekt entegrasyonuna kadar çok dikkat edilmeyen ve oldukça fazla bulgu çıkaran aşağıdaki ComplexCondition kuralını da standart olarak kabul edip aktif hale getirdik. Böylece condition case’lerinin de karmaşıklığını azaltıp daha okunabilir kod blokları oluşturabiliyoruz.

Noncomplient code:

val str = "foo"
val isFoo = if (str.startsWith("foo") && !str.endsWith("foo") && !str.endsWith("bar") && !str.endsWith("_")) {
// ...
}

Complient code:

val str = "foo"
val isFoo = if (str.startsWith("foo") && hasCorrectEnding()) {
// ...
}

fun hasCorrectEnding() = return !str.endsWith("foo") && !str.endsWith("bar") && !str.endsWith("_")

4. Aşama Detekt Bulgularının Çözülmesi ve Detekt’in Tamamen Aktif Edilmesi: 🔧

Yukarıda kural dosyamızın düzenlemesini eklediğimiz örnekteki gibi tüm kuralların üzerinden tek tek geçerek tamamladık. Çalışma grubumuzun aslında burada işi de bitmiş oldu, şimdi tüm takıma düşen iş detekt bulgularını temizlemekti. Burada ilk olarak amacımız detekti build time’da aktif hale getirmekti. Ancak eklediğimiz bulgulu kurallar çözülmeden build alamadığımız için detekt’i tamamen aktif hale getiremedik. Sırasıyla burada nasıl ilerlemişizi gelin bir bakalım.

Detekt’in ktlint’i içeren kurallar ile build time entegrasyonu: İlk olarak zaten ktlint kullandığımız için onu kapsayan Formatting kural setinin ilgili kuralları ile detekt_formatting_config isimli yaml dosyamızı oluşturduk ve detektFormatting isimli gradle task’imizi tanımladık ve build time’da bunu aktif hale getirdik, ktlint engtegrasyonumuzu yeni eklediğimiz detekt rule’un ktlint’i kapsamış olmasından dolayı kaldırmış olduk.

Detekt’in ktlint dışındaki kuralların entegre edilmesi ile ortaya çıkan bulguların çözülmesi: Paralelde tüm seçtiğimiz kuralları içeren detekt_config isimli yaml dosyası ile de ana detekt taskimizi oluşturduk. Multi modular olan uygulamamızda zaten belirli seviyede her modülle ilgilenen bir ya da birden fazla kişi bulunuyordu. Burada da modul bazlı ayırıma giderek, tüm kuralların oluşturduğu modul bazlı bulgu sayısını çıkardık. Yapı olarak hesaplar, krediler gibi toplam 15 adet ui ve bunlara bağlı ayrı ayrı data modülleri bulunan uygulamamızda, detekt entegrasyonu ile buradaki bulguların çözümlerini modül sahibi arkadaşlar ile sıfırlayacak şekilde takım hedefi olarak belirledik.

Bulguların takip edilmesi ve sıfırlanan modüllerin build time entegrasyonu: Bulgu çözümüne start verdiğimizde her modülle ilgili kişi, modül içerisindeki bulguları incelemeye ve çözmeye başladı. Bu süreci her hafta cuma günü development branchinden detekt bulgu sayısı raporu alıp, takıma mail atarak takip ettik. Herhangi bir modülde bulgu sayısının sıfırlanması durumunda ilgili modülün build time’da çalışan detekt taskini detekFormatting olandan detekt ana taski olacak şekilde değiştirdik. Detekt bulgularının çözümü sırasında uygulamanın farklı yerlerinde oluşan itirazları da bir yerde toplayıp ihtiyaç halinde ilk oluşturduğumuz çalışma grubuyla değerlendirip aksiyon aldık. Bu şekilde tüm modüllerde bulgular sıfırlanana kadar ve ana detekt taskini tüm uygulama için build time’da aktif hale getirene kadar bulgularımızı çözdük.

Deneyimler ve İpuçları 🧩

Detekt entegrasyonu sürecinde QNB Mobil Android uygulamamızda edindiğimiz deneyimler ve kazandığımız ipuçları, statik kod analizi ve kod kalitesi yönetimi konularında bize önemli öğretiler sundu. İşte bu süreçte öğrendiklerimiz ve diğer geliştiriciler için ipuçları:

  1. Kural Seçimi ve Önceliklendirme: Detekt’in sunduğu geniş kural setleri arasında, uygulamamızın ihtiyaçlarına en uygun olanları seçmek kritik öneme sahipti. İlk aşamada, ktlint ve sonarqube kurallarını kapsayan setlere odaklanarak başladık ve sadece uygulamamız için standartlarımıza uyan ya da bizler için anlamlı gelen yeni kuralları entegre ettik.
  2. Çalışma Grubu ve İşbirliği: Detekt kurallarını değerlendirme sürecinde çalışma grubu oluşturarak, farklı bakış açılarından yararlandık. Haftalık toplantılar ve düzenli geri bildirimlerle, herkesin katkı yapmasını sağlayarak karar verme sürecini iyileştirdik.
  3. Bulguların Yönetimi ve Çözümleme: Detekt tarafından rapor edilen bulguların etkili bir şekilde yönetilmesi için modül bazlı bir yaklaşım benimsedik. Her modüldeki bulguların, sorumlu kişiler tarafından yönetilmesi ve çözülmesi, genel kod kalitesini artırmak için önemli bir adım oldu.
  4. Entegrasyon ve Süreç Optimizasyonu: Detekt’in build sürecine entegrasyonu için Gradle task’ları ve YAML konfigürasyon dosyaları oluşturduk. Bu sayede, statik kod analizinin sürekli olarak yapılmasını ve hataların erken tespit edilmesini sağladık.
  5. CI Adımına Entegrasyon ve Code Review Süreçlerinin Kısaltılması: Detekt’i CI adımında da aktif hale getirerek, açılan pull requestlerde otomatik olarak çalışmasını sağladık. Bu sayede uyumsuz bir kod parçası varsa, build işlemi başarısız oluyor ve pull requestin ilerlemesi engelleniyor. Bu yapı sayesinde code review sürelerimizi de minimize ettik.
  6. Gelecek İyileştirmeler ve Sürdürülebilirlik: Entegrasyon sürecinin ardından, detekt tarafından rapor edilen bulguların sıfıra indirilmesi ve sürekli olarak kod kalitesini gözden geçirmeye devam etme çabalarımızı sürdürüyoruz. Gelecekte, yeni Detekt sürümlerinin ve güncellemelerinin uygulamamız üzerindeki etkilerini izleyerek, kod standartlarımızı güncel tutmayı hedefliyoruz.
  7. Build Süresi: Detekt’i build time’da çalıştırmamız, yazdığımız kodların build aşamasında onlarca kural tarafından analiz edilmesi, maalesef build zamanımızı bir miktar arttırdı. Build time da bizim için başka makalelerde gelecek farklı bir challenge Şu an detekt’in development bittikten sonra pre-commit aşamasında bir hook entegrasyonu ile değişiklik olan dosyalarda analiz yapması için çalışıyoruz farklı bir makalede oradaki entegrasyon sürecimizi de anlatıyor olacağız. Build time’daki bir miktar artışı ise bu şekilde tekrar eski haline getirmeyi hedefliyoruz.

Sonuç

Detekt’in entegrasyonu süreci boyunca elde ettiğimiz kazanımlarla birlikte, QNB Mobil Android uygulamamızın kod kalitesini önemli ölçüde artırdık. Yeni kuralların ve analiz yöntemlerinin entegrasyonu sayesinde, kod tabanımızın daha tutarlı hale gelmesini sağladık. Detekt’in sunduğu çeşitli kural setleriyle yapılan değerlendirmeler ve geliştirmeler, uygulamamızın performansını ve bakımını optimize etmeye yönelik stratejilerimizin temelini oluşturdu.

Çalışma grubumuzun aktif katılımı ve detaylı analizleri sayesinde, her bir kuralın uygulamamız üzerindeki etkilerini anlamak ve en iyi uygulama yöntemlerini belirlemek mümkün oldu. Detekt’in modül bazlı entegrasyonu ve bulgu sayılarının azaltılması süreci, kod kalitesini sürekli olarak izlememize ve iyileştirmemize olanak sağladı ve bu sayede teknik borçları azaltma hedefimizde önemli adımlar attık.

Gelecekteki geliştirme süreçlerimizde, Detekt ile elde ettiğimiz bu kazanımları sürdürerek, QNB Mobil Android uygulamamızı daha da güçlendirmeyi ve yenilikçi çözümler sunmayı hedefliyoruz. Detekt’in bize sağladığı araçlar ve kılavuzlar, kod kalitesi standartlarımızı yüksek tutmamıza ve geliştirici ekibimizin verimliliğini artırmamıza yardımcı olacak. Örneğin, artık bizde kimse 30 satırdan uzun fonksiyon yazamıyor Böylece gerçekten her fonksiyonun sadece bir işi oluyor, uzarsa o kod derlenmiyor ve bir nevi SOLID prensiplerine de, eklenen detekt kuralları sayesinde daha çok uymuş oluyoruz. Ayrıca isimlendirme standartlarıyla bir değişkenin boolean olup olmadığını bir bakışta anlıyoruz.

Şimdilik detekt ve geçiş sürecimizle ilgili anlatacaklarımız bu kadardı, önümüzdeki makale olan Kotlin DSL Migration in QNBAndroid Mobile’de görüşmek üzere, sağlıcakla kalın.

Detekt dokümantasyon linki: https://detekt.dev/docs/intro

--

--