Uygulama mimarisi kılavuzu

Uygulama mimarisi, yüksek kaliteli bir Android uygulamasının temelidir. İyi tanımlanmış bir mimari, telefonlar, tabletler, katlanabilir cihazlar, ChromeOS cihazlar, araç ekranları ve XR gibi sürekli genişleyen Android cihaz ekosistemine uyum sağlayabilen, ölçeklenebilir ve bakımı kolay bir uygulama oluşturmanıza olanak tanır.

Uygulama bileşimi

Tipik bir Android uygulaması, uygulama bileşenleri adı verilen birden fazla öğeden oluşur. Bu bileşenler arasında hizmetler, içerik sağlayıcılar ve yayın alıcılar yer alır. Bu bileşenleri uygulama manifestinizde beyan edersiniz.

Uygulamanın kullanıcı arayüzü de bir bileşendir. Geçmişte kullanıcı arayüzleri birden fazla etkinlik kullanılarak oluşturuluyordu. Ancak modern uygulamalar tek etkinlikli bir mimari kullanır. Tek bir Activity, parçalar veya Jetpack Compose hedefleri olarak uygulanan ekranlar için kapsayıcı görevi görür.

Birden fazla form faktörü

Uygulamalar yalnızca telefonlarda değil, tabletler, katlanabilir cihazlar, ChromeOS cihazlar ve daha pek çok form faktöründe çalışabilir. Uygulamalar dikey veya yatay yönü varsayamaz. Cihazı döndürme veya katlanabilir bir cihazı katlama ve açma gibi yapılandırma değişiklikleri, uygulamanızın kullanıcı arayüzünü yeniden oluşturmasına neden olur. Bu durum, uygulama verilerini ve durumunu etkiler.

Kaynak kısıtlamaları

Mobil cihazlar (büyük ekranlı cihazlar dahil) kaynak açısından sınırlıdır. Bu nedenle, işletim sistemi yeni uygulamalara yer açmak için bazı uygulama işlemlerini durdurabilir.

Değişken başlatma koşulları

Kaynakların sınırlı olduğu bir ortamda, uygulamanızın bileşenleri tek tek ve sırasız olarak başlatılabilir. Ayrıca, işletim sistemi veya kullanıcı bunları istediği zaman yok edebilir. Bu nedenle, uygulama bileşenlerinizde uygulama verilerini veya durumu depolamayın. Uygulama bileşenleriniz bağımsız olmalı ve birbirlerinden ayrı çalışmalıdır.

Sık karşılaşılan mimari ilkeler

Uygulama verilerini ve durumunu depolamak için uygulama bileşenlerini kullanamıyorsanız uygulamanızı nasıl tasarlamalısınız?

Android uygulamalarının boyutu büyüdükçe, uygulamanın ölçeklenmesine olanak tanıyan bir mimari tanımlamak önemlidir. İyi tasarlanmış bir uygulama mimarisi, uygulamanın bölümleri arasındaki sınırları ve her bölümün sorumluluklarını tanımlar.

İlgi alanlarının ayrılması

Uygulama mimarinizi belirli birkaç ilkeye uyacak şekilde tasarlayın.

En önemli ilke ilgi alanlarının ayrılmasıdır. Tüm kodunuzu Activity veya Fragment içinde yazmak yaygın bir hatadır.

Activity veya Fragment'nin asıl görevi, uygulamanızın kullanıcı arayüzüne ev sahipliği yapmaktır. Android işletim sistemi, yaşam döngülerini kontrol eder ve ekran döndürme gibi kullanıcı işlemlerine veya düşük bellek gibi sistem etkinliklerine yanıt olarak bunları sık sık yok edip yeniden oluşturur.

Bu geçici yapı, bunları uygulama verilerini veya durumunu tutmak için uygunsuz hale getirir. Verileri Activity veya Fragment içinde depolarsanız bileşen yeniden oluşturulduğunda bu veriler kaybolur. Verilerin kalıcı olmasını sağlamak ve kararlı bir kullanıcı deneyimi sunmak için durumu bu kullanıcı arayüzü bileşenlerine emanet etmeyin.

Uyarlanabilir düzenler

Uygulamanız, cihaz yönlendirme değişiklikleri veya uygulama penceresinin boyutundaki değişiklikler gibi yapılandırma değişikliklerini sorunsuz bir şekilde işlemelidir. Çeşitli form faktörlerinde optimum kullanıcı deneyimi sağlamak için uyarlanabilir standart düzenleri uygulayın.

Veri modellerinden Drive kullanıcı arayüzü

Bir diğer önemli ilke de kullanıcı arayüzünüzü veri modellerinden (tercihen kalıcı modellerden) yönlendirmeniz gerektiğidir. Veri modelleri, bir uygulamanın verilerini temsil eder. Bunlar, uygulamanızdaki kullanıcı arayüzü öğelerinden ve diğer bileşenlerden bağımsızdır. Bu nedenle, kullanıcı arayüzü ve uygulama bileşeni yaşam döngüsüne bağlı değildirler ancak işletim sistemi uygulamanın işlemini bellekten kaldırdığında yine de yok edilirler.

Kalıcı modeller şu nedenlerle idealdir:

  • Android işletim sistemi, kaynakları boşaltmak için uygulamanızı yok ederse kullanıcılar veri kaybetmez.

  • Uygulamanız, ağ bağlantısının kesintili olduğu veya kullanılamadığı durumlarda çalışmaya devam eder.

Uygulamanızı sağlam ve test edilebilir hale getirmek için uygulama mimarinizi veri modeli sınıflarına dayandırın.

Tek ve doğru kaynak

Uygulamanızda yeni bir veri türü tanımlandığında buna tek bir doğru kaynak (SSOT) atamanız gerekir. SSOT, bu verilerin sahibidir ve yalnızca SSOT bu verileri değiştirebilir veya dönüştürebilir. SSOT, bunu sağlamak için verileri değişmez bir tür kullanarak kullanıma sunar. Verileri değiştirmek için SSOT, diğer türlerin çağırabileceği işlevleri kullanıma sunar veya etkinlikleri alır.

Bu kalıbın birden fazla avantajı vardır:

  • Belirli bir veri türüyle ilgili tüm değişiklikleri tek bir yerde toplar.
  • Verileri, diğer türlerin kurcalayamayacağı şekilde korur.
  • Verilerde yapılan değişiklikler daha kolay izlenebilir ve böylece hatalar daha kolay tespit edilebilir.

Öncelikle çevrimdışı uygulamalarda, uygulama verilerinin doğruluk kaynağı genellikle bir veritabanıdır. Diğer bazı durumlarda ise doğru kaynağı ViewModel olabilir.

Tek yönlü veri akışı

Tek ve doğru kaynak ilkesi genellikle tek yönlü veri akışı (UDF) modeliyle birlikte kullanılır. UDF'de durum yalnızca tek bir yönde, genellikle üst bileşenden alt bileşene doğru akar. Veri akışını ters yönde değiştiren etkinlikler.

Android'de durum veya veriler genellikle hiyerarşinin daha yüksek kapsamlı türlerinden daha düşük kapsamlı türlerine akar. Etkinlikler genellikle daha düşük kapsamlı türlerden tetiklenerek ilgili veri türü için SSOT'a ulaşır. Örneğin, uygulama verileri genellikle veri kaynaklarından kullanıcı arayüzüne akar. Kullanıcı etkinlikleri (ör. düğmeye basma) kullanıcı arayüzünden, uygulama verilerinin değiştirildiği ve değişmez türde kullanıma sunulduğu SSOT'ye akar.

Bu model, veri tutarlılığını daha iyi korur, hata yapma olasılığı daha düşüktür, hata ayıklaması daha kolaydır ve SSOT modelinin tüm avantajlarını sunar.

Genel mimari ilkeler göz önünde bulundurulduğunda, her uygulamada en az iki katman olmalıdır:

  • Kullanıcı arayüzü katmanı: Uygulama verilerini ekranda gösterir.
  • Veri katmanı: Uygulamanızın iş mantığını içerir ve uygulama verilerini kullanıma sunar.

Kullanıcı arayüzü ile veri katmanları arasındaki etkileşimleri basitleştirmek ve yeniden kullanmak için alan katmanı adlı ek bir katman ekleyebilirsiniz.

Tipik bir uygulama mimarisinde, kullanıcı arayüzü katmanı uygulama verilerini veri katmanından veya kullanıcı arayüzü katmanı ile veri katmanı arasında yer alan isteğe bağlı alan katmanından alır.
Şekil 1. Tipik bir uygulama mimarisinin şeması.

Modern uygulama mimarisi

Modern bir Android uygulama mimarisinde aşağıdaki teknikler (diğerlerinin yanı sıra) kullanılır:

  • Uyarlanabilir ve katmanlı mimari
  • Uygulamanın tüm katmanlarında tek yönlü veri akışı (UDF)
  • Kullanıcı arayüzünün karmaşıklığını yönetmek için durum tutucular içeren kullanıcı arayüzü katmanı
  • Eş yordamlar ve akışlar
  • Bağımlılık ekleme ile ilgili en iyi uygulamalar

Daha fazla bilgi için Android mimarisiyle ilgili öneriler başlıklı makaleyi inceleyin.

Kullanıcı arayüzü katmanı

Kullanıcı arayüzü katmanının (veya sunum katmanı) görevi, uygulama verilerini ekranda göstermektir. Veriler, kullanıcı etkileşimi (ör. düğmeye basma) veya harici giriş (ör. ağ yanıtı) nedeniyle her değiştiğinde kullanıcı arayüzü, değişiklikleri yansıtacak şekilde güncellenmelidir.

Kullanıcı arayüzü katmanı iki tür yapıdan oluşur:

  • Ekrandaki verileri işleyen kullanıcı arayüzü öğeleri. Bu öğeleri, uyarlanabilir düzenleri desteklemek için Jetpack Compose işlevlerini kullanarak oluşturursunuz.
  • Verileri tutan, kullanıcı arayüzünde gösteren ve mantığı işleyen durum bilgisi depolayıcılar (ör. ViewModel)
Tipik bir mimaride, kullanıcı arayüzü katmanının kullanıcı arayüzü öğeleri durum tutuculara, durum tutucular ise veri katmanındaki veya isteğe bağlı alan katmanındaki sınıflara bağlıdır.
Şekil 2. Uygulama mimarisinde kullanıcı arayüzü katmanının rolü.

Uyarlanabilir kullanıcı arayüzlerinde, ViewModel nesneleri gibi durum koruyucular, farklı pencere boyutu sınıflarına uyum sağlayan kullanıcı arayüzü durumunu gösterir. Bu kullanıcı arayüzü durumunu elde etmek için currentWindowAdaptiveInfo() kullanabilirsiniz. Bunun ardından NavigationSuiteScaffold gibi bileşenler, bu bilgileri kullanarak mevcut ekran alanına göre farklı gezinme kalıpları (ör. NavigationBar, NavigationRail veya NavigationDrawer) arasında otomatik olarak geçiş yapabilir.

Daha fazla bilgi edinmek için UI katmanı sayfasına bakın.

Veri katmanı

Bir uygulamanın veri katmanı iş mantığını içerir. İş mantığı, uygulamanıza değer katan unsurdur. Uygulamanızın verileri nasıl oluşturduğunu, depoladığını ve değiştirdiğini belirleyen kurallardan oluşur.

Veri katmanı, her biri sıfır ila çok sayıda veri kaynağı içerebilen depolardan oluşur. Uygulamanızda işlediğiniz her farklı veri türü için bir depo sınıfı oluşturmanız gerekir. Örneğin, filmlerle ilgili veriler için bir MoviesRepository sınıfı veya ödemelerle ilgili veriler için bir PaymentsRepository sınıfı oluşturabilirsiniz.

Tipik bir mimaride, veri katmanının depoları uygulamanın geri kalanına veri sağlar ve veri kaynaklarına bağlıdır.
Şekil 3. Uygulama mimarisinde veri katmanının rolü.

Depo sınıfları aşağıdakilerden sorumludur:

  • Uygulamanın geri kalanına veri gösterme
  • Verilerde yapılan değişiklikleri merkezileştirme
  • Birden fazla veri kaynağı arasındaki çakışmaları çözme
  • Veri kaynaklarını uygulamanın geri kalanından ayırma
  • İş mantığı içerme

Her veri kaynağı sınıfı, yalnızca bir veri kaynağıyla (dosya, ağ kaynağı veya yerel veritabanı olabilir) çalışma sorumluluğuna sahip olmalıdır. Veri kaynağı sınıfları, veri işlemleri için uygulama ile sistem arasındaki köprüdür.

Daha fazla bilgi edinmek için veri katmanı sayfasını inceleyin.

Alan katmanı

Alan katmanı, kullanıcı arayüzü ve veri katmanları arasında isteğe bağlı bir katmandır.

Alan katmanı, karmaşık işletme mantığını veya birden fazla görünüm modeli tarafından yeniden kullanılan daha basit işletme mantığını kapsüllemekten sorumludur. Tüm uygulamalar bu şartları karşılamadığından alan katmanı isteğe bağlıdır. Yalnızca gerektiğinde kullanın. Örneğin, karmaşıklığı gidermek veya yeniden kullanılabilirliği tercih etmek için kullanabilirsiniz.

İsteğe bağlı alan katmanı, dahil edildiğinde kullanıcı arayüzü katmanına bağımlılıklar sağlar ve veri katmanına bağlıdır.
Şekil 4. Alan katmanının uygulama mimarisindeki rolü.

Alan katmanındaki sınıflara genellikle kullanım alanları veya etkileşimciler adı verilir. Her kullanım alanı, tek bir işlevden sorumlu olmalıdır. Örneğin, birden fazla görünüm modeli ekranda doğru mesajı göstermek için saat dilimlerine bağlıysa uygulamanızda GetTimeZoneUseCase sınıfı olabilir.

Daha fazla bilgi edinmek için alan katmanı sayfasına bakın.

Bileşenler arasındaki bağımlılıkları yönetme

Uygulamanızdaki sınıfların düzgün çalışması için diğer sınıflara bağlı olması. Belirli bir sınıfın bağımlılıklarını toplamak için aşağıdaki tasarım kalıplarından birini kullanabilirsiniz:

  • Bağımlılık ekleme (DI): Bağımlılık ekleme, sınıfların bağımlılıklarını oluşturmadan tanımlamasına olanak tanır. Çalışma zamanında, bu bağımlılıkları sağlamaktan başka bir sınıf sorumludur.
  • Hizmet bulucu: Hizmet bulucu kalıbı, sınıfların bağımlılıklarını oluşturmak yerine elde edebileceği bir kayıt defteri sağlar.

Bu kalıplar, kodu kopyalamadan veya karmaşıklık eklemeden bağımlılıkları yönetmek için net kalıplar sağladığından kodunuzu ölçeklendirmenize olanak tanır. Bu kalıplar, test ve üretim uygulamaları arasında hızlıca geçiş yapmanızı da sağlar.

Genel en iyi uygulamalar

Programlama, yaratıcılık gerektiren bir alandır ve Android uygulamaları geliştirmek de bu kapsamdadır. Bir sorunu çözmenin birçok yolu vardır. Örneğin, verileri birden fazla etkinlik veya parça arasında iletebilir, uzaktan verileri alıp çevrimdışı mod için yerel olarak kalıcı hale getirebilir ya da önemsiz olmayan uygulamaların karşılaştığı diğer yaygın senaryoları işleyebilirsiniz.

Aşağıdaki öneriler zorunlu olmasa da çoğu durumda bu önerilere uyarak kod tabanınızı daha sağlam, test edilebilir ve bakımı kolay hale getirebilirsiniz.

Verileri uygulama bileşenlerinde depolamayın.

Uygulamanızın giriş noktalarını (ör. etkinlikler, hizmetler ve yayın alıcılar) veri kaynağı olarak belirlemekten kaçının. Giriş noktaları yalnızca söz konusu giriş noktasıyla alakalı veri alt kümesini almak için diğer bileşenlerle koordineli çalışmalıdır. Her uygulama bileşeni, kullanıcının cihazıyla etkileşimine ve sistemin kapasitesine bağlı olarak kısa ömürlüdür.

Android sınıflarına olan bağımlılıkları azaltın.

Uygulama bileşenleriniz, Context veya Toast gibi Android framework SDK API'lerini kullanan tek sınıflar olmalıdır. Uygulamanızdaki diğer sınıfları uygulama bileşenlerinden ayırmak, test edilebilirliğe yardımcı olur ve uygulamanızdaki bağlantıyı azaltır.

Uygulamanızdaki modüller arasında net sorumluluk sınırları tanımlayın.

Ağdan veri yükleyen kodu, kod tabanınızdaki birden fazla sınıf veya pakete yaymayın. Benzer şekilde, aynı sınıfta veri önbelleğe alma ve veri bağlama gibi birbiriyle alakasız birden fazla sorumluluk tanımlamayın. Önerilen uygulama mimarisini kullanmak yardımcı olacaktır.

Her modülden mümkün olduğunca az bilgi gösterin.

Dahili uygulama ayrıntılarını açığa çıkaran kısayollar oluşturmayın. Kısa vadede biraz zaman kazanabilirsiniz ancak kod tabanınız geliştikçe teknik borçlanma olasılığınız artar.

Uygulamanızın benzersiz özüne odaklanarak diğer uygulamalardan öne çıkmasını sağlayın.

Aynı standart kodu tekrar tekrar yazarak zaman kaybetmeyin. Bunun yerine, zamanınızı ve enerjinizi uygulamanızı benzersiz kılan özelliklere odaklanarak geçirin. Tekrarlanan standart kodları Jetpack kitaplıkları ve diğer önerilen kitaplıklar işlesin.

Standart düzenler ve uygulama tasarım kalıpları kullanın.

Jetpack Compose kitaplıkları, uyarlanabilir kullanıcı arayüzleri oluşturmak için güçlü API'ler sağlar. Uygulamanızda standart düzenleri kullanarak kullanıcı deneyimini birden fazla form faktöründe ve ekran boyutunda optimize edin. Kullanım alanlarınıza en uygun düzenleri seçmek için uygulama tasarım kalıpları galerisini inceleyin.

Yapılandırma değişiklikleri sırasında kullanıcı arayüzü durumunu koruyun.

Uyarlanabilir düzenler için tasarım yaparken ekranı yeniden boyutlandırma, katlama ve yönlendirme değişiklikleri gibi yapılandırma değişikliklerinde kullanıcı arayüzü durumunu koruyun. Mimariniz, kullanıcının mevcut durumunun korunduğunu doğrulayarak sorunsuz bir deneyim sağlamalıdır.

Yeniden kullanılabilir ve birleştirilebilir kullanıcı arayüzü bileşenleri tasarlayın.

Uyarlanabilir tasarımı desteklemek için yeniden kullanılabilir ve birleştirilebilir kullanıcı arayüzü bileşenleri oluşturun. Bu sayede, önemli bir yeniden düzenleme yapmadan çeşitli ekran boyutlarına ve duruşlarına uyacak şekilde bileşenleri birleştirip yeniden düzenleyebilirsiniz.

Uygulamanızın her bölümünü ayrı ayrı nasıl test edebileceğinizi düşünün.

Ağdan veri getirmek için iyi tanımlanmış bir API, bu verileri yerel bir veritabanında kalıcı hale getiren modülün test edilmesini kolaylaştırır. Bunun yerine bu iki işlevin mantığını tek bir yerde karıştırırsanız veya ağ kodunuzu tüm kod tabanınıza dağıtırsanız test etmek imkansız olmasa da çok daha zor hale gelir.

Türler, eşzamanlılık politikalarından sorumludur.

Bir tür uzun süreli engelleme işi yapıyorsa bu hesaplamayı doğru iş parçacığına taşımaktan sorumlu olmalıdır. Tür, yaptığı hesaplamanın türünü ve hesaplamanın hangi iş parçacığında yürütülmesi gerektiğini bilir. Türler, ana ileti dizisinden engellemeden çağrılabilecek şekilde ana ileti dizisi güvenli olmalıdır.

Mümkün olduğunca çok sayıda alakalı ve yeni veriyi saklayın.

Bu sayede kullanıcılar, cihazları çevrimdışı moddayken bile uygulamanızın işlevlerinden yararlanabilir. Kullanıcılarınızın tamamının sürekli ve yüksek hızlı bağlantıdan yararlanmadığını, yararlansalar bile kalabalık yerlerde kötü sinyal alabileceklerini unutmayın.

Mimari yapının avantajları

Uygulamanızda iyi bir mimarinin uygulanması projeye ve mühendislik ekiplerine birçok avantaj sağlar:

  • Uygulamanın genel olarak sürdürülebilirliğini, kalitesini ve sağlamlığını artırır.
  • Uygulamanın ölçeklendirilmesine izin verir. Daha fazla kişi ve daha fazla ekip, aynı kod tabanına minimum kod çakışmasıyla katkıda bulunabilir.
  • İlk katılım sürecine yardımcı olur. Mimari, projenize tutarlılık kazandırdığı için ekibin yeni üyeleri kısa sürede uyum sağlayabilir ve daha az zamanda daha verimli olabilir.
  • Test etmek daha kolaydır. İyi bir mimari, genellikle test edilmesi daha kolay olan basit türleri teşvik eder.
  • Hatalar, iyi tanımlanmış süreçlerle metodik olarak incelenebilir.

Mimarideki yatırımlar da kullanıcıları doğrudan etkiler. Daha üretken bir mühendislik ekibi sayesinde daha kararlı bir uygulamadan ve daha fazla özellikten yararlanırlar. Ancak mimari için önceden zaman yatırımı yapılması da gerekir. Bu zamanı kuruluşunuzun geri kalanına açıklamanıza yardımcı olması için diğer şirketlerin uygulamalarında iyi bir mimari kullanmayla ilgili başarı hikayelerini paylaştığı örnek olay incelemelerine göz atın.

Örnekler

Aşağıdaki örneklerde iyi bir uygulama mimarisi gösterilmektedir: