Android IDE'de Kotlin kodu ve proje dosya ağacı görüntüleyen geliştirici ekranı, arka planda bir kafe ortamı.

Photo by Author (Gerçekten ben çektim)

Declarative UI, kontrol akışını detaylandırmadan yalnızca hesaplama mantığını tanımlayan bir programlama paradigmasıdır. Daha açık bir ifadeyle, bu paradigma, kullanıcı arayüzünün istenen son durumunu tanımlar; bu sayede, belirli bir çerçeve bu durumu oluşturmayı ve durum geçişlerini yönetmeyi üstlenir. Bu yaklaşım, geliştiricilerin daha az kod ile daha sezgisel çalışmasını sağlar.

Declarative UI denildiğinde hemen hemen hepimizin aklına React ve Flutter geliyor. Hatta Google I/O’da kullanılan sunumun görselini hemen buraya iliştiriyorum:

React, Litho, Jetpack Compose ve SwiftUI gibi deklaratif UI framework'lerinin 2013-2019 arası zaman çizelgesi ve özelliklerinin karşılaştırması.

Image created for presentation in Google I/O Extended 2019, by Na Yoon Ho

Declarative UI ile klasik yöntem olan Imperative UI’ı kısaca kıyaslayalım:

  • Bu iki paradigma da UI yaratımında kullanılır fakat aralarında belirgin farklar bulunur.

  • DeclarativeUI’da, bir objenin neye benzediğini sadece açıklarız. İstediğimiz objenin stilini belirli bir noktaya kadar belirleyebiliriz. Mesela, arayüzde bir buton istediğimizi belirtiriz ancak butonun tam pozisyonunu (x, y) cinsinden belirtmeyiz. Yazılımcı, Declarative UI’da tüm sürecin nasıl işleyeceğini tek tek yazmaz çünkü obje yaratımı ile framework ler ilgilenir.

  • Imperative UI’da ise, altta paylaştığım Gist’ten de anlaşılacağı üzere, UI yaratımının her adımını biz yönetiriz. Bu modelde, kullanıcı arayüzü ögeleri doğrudan manipüle edilir; bu durum genellikle daha fazla ortak koda yol açar ve kullanıcı arayüzü durumlarının ve geçişlerinin manuel olarak işlenmesini gerektirir.

code
//Imperative
val button = Button()
button.text = "click me"
val layout = Layout()
layout.add(button)

// Declerative
Layout  {
   Button("click me")
}


Declarative UI’ın Temel Özellikleri Nelerdir?

  1. Durum Yönetimi:
    Uygulamanın kullanıcı arayüzü (UI), uygulamanın durumuna (state) bağlı olarak render edilir. Durum değiştiğinde, UI otomatik olarak yeniden oluşturulur ve güncellenir. Bu, UI ile veri durumu arasında sıkı bir bağlantı kurulmasını sağlar.

  2. Kodun Sadeliği ve Anlaşılabilirliği:
    Declarative UI -daha önce de dediğim gibi- geliştiricilere yalnızca ne yapılacağını belirtme olanağı tanır; böylelikle nasıl yapılacağıyla ilgili endişeleri ortadan kaldırır. Bu, kodun daha okunabilir ve bakımının daha kolay olmasını sağlar.

  3. Component (bileşen) Tabanlı:
    Declarative UI genellikle bileşen tabanlıdır. Bileşenler, kendilerine ait durumları (state) ve yapıları (props) ile izole edilmiş UI parçalarıdır. Bu, tekrar kullanılabilirliği ve modülerliği artırır.

  4. Memory Friendly:
    Modern Declarative UI frameworkleri, DOM’u yalnızca gerektiğinde ve en minimal biçimde güncelleyecek şekilde tasarlanmıştır; bu da performansı artırır.



Declarative UI’ın Zorlukları

  1. Daha Yüksek Öğrenme Eğrisi:
    Declarative düşünme biçimine geçiş, alışılmış imperative programlamaya alışkın olanlar için zorlayıcı olabilir. Durum değişikliklerinin UI’ı nasıl etkilediğini anlamak, altta yatan çerçevenin durum ve yaşam döngüsü yönetimini iyi kavramayı gerektirir.

  2. Performans Maliyetleri:
    Declarative UI’lar genellikle optimize edilmiş olsa da karmaşık durum bağımlılıkları performans darboğazlarına yol açabilir. Durumun verimsiz kullanımı gereksiz yeniden renderlamaları tetikleyerek uygulamanın tepki süresini ve hızını etkileyebilir; Compose’da buna recomposition denir.

  3. Kontrolün Sınırlı Olması:
    Declarative UI, renderlama süreci üzerindeki kontrolün büyük bir kısmını soyutlar; bu, ince ayar optimizasyonları gerektiren projeler için bir dezavantaj olabilir. Geliştiriciler, çerçevenin sınırlamalarına ve hatalarına bağlı kalabilirler.

Açılmış hard disk'in içi, okuma-yazma kafası ve döner platterle bilgisayar depolama teknolojisini gösteriyor.

Photo by Art Wall - Kittenprint on Unsplash



Popüler Declarative UI Frameworkleri

  • React: Facebook tarafından geliştirilen ve geniş ölçekte kabul gören bir JavaScript kütüphanesi.

  • Vue.js: Çok yönlü ve performanslı bir yapıya sahip, açık kaynaklı bir JavaScript frameworkü.

  • Flutter: Google tarafından geliştirilen ve hem mobil hem de web uygulamaları için kullanılabilen bir framework.

  • SwiftUI: Apple tarafından geliştirilen ve iOS, macOS gibi platformlar için native uygulamalar geliştirmeye yarayan bir framework.

  • Jetpack Compose: Google tarafından geliştirilen, Android için native mobil uygulamalar geliştirmeye yarayan modern, reactive, responsive bir UI toolkit.

Uzun düz bir yol ufka doğru uzanıyor, çöl peyzajında güneş batışıyla aydınlanmış dağlar.

Photo by Johannes Plenio on Unsplash



Gelecek

Bu yazıyı 2019’da kaleme almış olduğum için bugünü (2024 Mayıs) tahmin edebilmek mümkün değildi. O zamanlar daha bebek adımlarında olan SwiftUI ve Jetpack Compose, bugün Apple Store ve Google Play Store’da onlarca uygulama çıkarmış durumda. Bir an önce bunları öğrensek, kod yapısına ve problemlerini çözmeye alışsak, gelişen dünyaya uyum sağlasak iyi olur.

2019:

Okuduk, anladık; güzel, hoş… Declarative UI, Swift UI, Compose… Tamam, haydi, dağılalım… Hemen değil! 🙂 Beyin fırtınası şart. Bu işin geleceği ne olur? Android Studio’da UI tasarlayıp bunu iOS’a da uygulamak mümkün olacak mı? Ya da tam tersi? UI kısmını tek bir kere geliştirip ufak değişikliklerle diğer platforma uygulamak… 🤔

Diyelim ki 3 sene sonra böyle bir şey yapıldı: Cross-platform ama bir yandan da native UI geliştirebileceğimiz ortak bir toolkit, bir framework.

2024:

Henüz yok. Bu iki şirketten izinsiz böyle bir ortak framework geliştirmek mümkün değil ve şu an için hâlâ ikisinin de birbirleriyle konuşmaya bile tahammülleri yok. Evet, UI yazmak kolaylaştı ama o kadar da kolay değil. Şirketler, iOS için SwiftUI, Android için Jetpack Compose kullanıyor olsa bile, benim gördüğüm kadarıyla ekipler ayrı çalışmaya devam ediyor. Tabii ki bunun tek sebebi teknolojilerin birbirine benzememesi değil, kısa zamanda iki tarafta da aynı işi çıkarabilme ihtiyacı.

2019:

Kolaylaştıkça işimiz hızlanıyor, kabul ancak acaba işlerin fazla kolaylaşması kod yazıyor olma hissimi yok eder mi? Tarihte fazla kolaylaşan her şeyde olduğu gibi, yazılımda da değeri ve saygıyı düşürür mü?

2024:

Valla, Android’den aslında biraz sıkılmışlığım var ama bunun sebebi çok kolaylaşması değil. Bu yazıda daha ayrıntılı bir şekilde anlattım. Hiç ‘şöyle kolaylaştı, böyle rezilleşti, ben Java’ya dönüyorum, kod mod yazılmaz, Android olunmaz artık’ düşüncesinde filan değilim. Compose da başka bir challange, başka bir öğrenme fırsatı. Çok da tatlı. Sadece, ben yazılım takım lideri oldum ve yolumu, kullandığım dili değiştirdim.

Boksörler ring'de maçta karşı karşıya, seyirciler arkasında izliyor.

Photo by Hermes Rivera on Unsplash

Yazılımla kalın, esen kalın.

Bu yazıyı 2019'da Peakup’ın blog sayfasında yayınlamıştım ancak orada ismimin yazılmamış olması, ekran görüntülerinin ve resimlerin bozulması ve yazının güncellenme gerekliliği gibi sebeplerle Medium hesabıma aktarıyorum.

Kaynakça:

https://docs.flutter.dev/get-started/flutter-for/declarative
https://codeburst.io/declarative-vs-imperative-programming-a8a7c93d9ad2
https://medium.com/front-end-weekly/imperative-versus-declarative-code-whats-the-difference-adc7dd6c8380