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ı, hizmetler, içerik sağlayıcılar ve yayın alıcılar gibi birden fazla uygulama bileşeninden oluşur. 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 ve ChromeOS cihazlar gibi birden fazla 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 ve birbirinden ayrı olmalı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. Kodunuzun tamamını Activity veya Fragment içine 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, bu etkinliklerin yaşam döngüsünü 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 çok 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.
  • Verilerdeki 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ğruluk 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 bir 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ı sağlar.

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 (diğerlerinin yanı sıra) aşağıdaki teknikler 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 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. 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. Veri katmanının uygulama mimarisindeki 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 dilimlerini kullanıyorsa 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ştirme de bu kapsamdadır. Bir sorunu çözmenin birçok yolu vardır. Örneğin, verileri birden fazla etkinlik veya parça arasında iletebilir, uzaktaki 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 çerçevesi 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, veri önbelleğe alma ve veri bağlama gibi birbiriyle alakasız birden fazla sorumluluğu aynı sınıfta tanımlamayın. Önerilen uygulama mimarisini kullanmak yardımcı olacaktır.

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

Dahili uygulama ayrıntılarını ortaya çı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 harcayın. 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şikliklerinde kullanıcı arayüzü durumunu koruyun.

Uyarlanabilir düzenler için tasarım yaparken ekranı yeniden boyutlandırma, katlama ve yön 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ı test edilebilir hale getirmeyi 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şlemi yapıyorsa bu hesaplamayı doğru işleme taşımakla yükümlü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 dizisini engellemeden ana ileti dizisinden çağrılabilecek şekilde ana ileti dizisi güvenli olmalıdır.

Mümkün olduğunca fazla alakalı ve yeni veriyi saklayın.

Bu sayede kullanıcılar, cihazları çevrimdışı moddayken bile uygulamanızın işlevlerinden yararlanabilir. Tüm kullanıcılarınızı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çeklenmesine izin verir. Daha fazla kişi ve daha fazla ekip, aynı kod tabanına minimum düzeyde 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 hızlı bir şekilde gerekli yetkinlik seviyesine ulaşabilir ve daha kısa sürede 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ı 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: