Uygulama mimarisi kılavuzu

Bu kılavuz, sağlam, yüksek kaliteli uygulamalar oluşturmak için en iyi uygulamaları ve önerilen mimariyi içerir.

Mobil uygulama kullanıcı deneyimleri

Tipik bir Android uygulaması; etkinlikler, parçalar, hizmetler, içerik sağlayıcılar ve yayın alıcıları dahil olmak üzere birden fazla uygulama bileşeni içerir. Bu uygulama bileşenlerinin çoğunu uygulama manifestinizde beyan edersiniz. Daha sonra Android OS, uygulamanızı cihazın genel kullanıcı deneyimine nasıl entegre edeceğine karar vermek için bu dosyayı kullanır. Tipik bir Android uygulamasının birden fazla bileşen içerebileceği ve kullanıcıların genellikle kısa bir süre içinde birden fazla uygulamayla etkileşimde bulunduğu göz önünde bulundurulduğunda uygulamaların kullanıcı odaklı farklı iş akışlarına ve görevlere uyum sağlaması gerekir.

Mobil cihazların kaynak açısından kısıtlı olduğunu, bu nedenle işletim sisteminin yeni uygulamalara yer açmak için her an bazı uygulama işlemlerini sonlandırabileceğini unutmayın.

Bu ortamın koşulları göz önüne alındığında, uygulama bileşenlerinizin ayrı ayrı ve sıra dışı olarak kullanıma sunulması mümkündür. Ayrıca işletim sistemi veya kullanıcılar bu bileşenleri herhangi bir zamanda yok edebilir. Bu etkinlikler sizin kontrolünüz altında olmadığından, uygulama bileşenlerindeki uygulama verilerini veya durumlarını bellekte depolamamalı veya saklamamalısınız. Ayrıca uygulama bileşenleriniz birbirine bağımlı olmamalıdır.

Ortak mimari ilkeleri

Uygulama verilerini ve durumunu depolamak için uygulama bileşenlerini kullanmamanız gerekiyorsa, bunun yerine uygulamanızı nasıl tasarlamalısınız?

Android uygulamalarının boyutu büyüdükçe, uygulamanın ölçeklendirilmesine olanak tanıyan, uygulamanın dayanıklılığını artıran ve uygulamanın test edilmesini kolaylaştıran bir mimari tanımlamak önemlidir.

Uygulama mimarisi, uygulamanın bölümleri arasındaki sınırları ve her bir bölümün sahip olması gereken sorumlulukları tanımlar. Yukarıda belirtilen ihtiyaçları karşılamak için uygulama mimarinizi birkaç belirli ilkeye uyacak şekilde tasarlamanız gerekir.

Endişelerin ayrılması

Uyulması gereken en önemli ilke endişelerin ayrılmasıdır. Kodunuzun tamamını Activity veya Fragment içine yazmak yaygın bir hatadır. Bu kullanıcı arayüzü tabanlı sınıflar, yalnızca kullanıcı arayüzü ve işletim sistemi etkileşimlerini işleyen mantığı içermelidir. Bu sınıfları mümkün olduğunca yalın tutarak bileşen yaşam döngüsüyle ilgili birçok sorundan kaçınabilir ve bu sınıfların test edilebilirliğini artırabilirsiniz.

Activity ve Fragment uygulamalarının size ait olmadığını unutmayın. Bunun yerine, bunlar yalnızca Android işletim sistemi ile uygulamanız arasındaki sözleşmeyi temsil eden yapıştırıcı sınıflarıdır. İşletim sistemi, kullanıcı etkileşimleri veya düşük bellek gibi sistem koşulları nedeniyle bunları herhangi bir zamanda kaldırabilir. Tatmin edici bir kullanıcı deneyimi ve daha yönetilebilir bir uygulama bakım deneyimi sağlamak için bunlara olan bağımlılığınızı en aza indirmeniz önerilir.

Veri modellerinden Drive kullanıcı arayüzü

Diğer bir önemli ilke de kullanıcı arayüzünüzü veri modellerinden (tercihen kalıcı modellerden) yönlendirmeniz gerektiğidir. Veri modelleri uygulama verilerini temsil eder. Bu modeller, kullanıcı arayüzü öğelerinden ve uygulamanızdaki diğer bileşenlerden bağımsızdır. Diğer bir deyişle, kullanıcı arayüzü ve uygulama bileşeninin yaşam döngüsüne bağlı değildirler, ancak işletim sistemi uygulama sürecini bellekten kaldırmaya karar verdiğinde yine de yok edilirler.

Kalıcı modeller aşağıdaki nedenlerle idealdir:

  • Android OS, kaynakları boşaltmak için uygulamanızı kaldırırsa kullanıcılarınız veri kaybı yaşamaz.

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

Uygulamanızın mimarisini veri modeli sınıflarına dayandırırsanız uygulamanızı daha test edilebilir ve sağlam hale getirirsiniz.

Tek doğru veri kaynağı

Uygulamanızda yeni bir veri türü tanımlandığında bu veri türüne Tek Doğruluk Kaynağı (TOAT) atamanız gerekir. TOAT, bu verilerin sahibidir ve bu verileri yalnızca TOAT değiştirebilir veya değiştirebilir. Bunu başarmak için TOAT, verileri sabit bir tür kullanarak ortaya çıkarır. TOAT, verileri değiştirmek için işlevleri kullanıma sunar veya diğer türlerin çağırabileceği etkinlikleri alır.

Bu düzen birden çok avantaj sağlar:

  • Belirli bir veri türünde yapılan tüm değişiklikleri tek bir yerde toplar.
  • Diğer türlerin kurcamaması için verileri korur.
  • Verilerdeki değişiklikleri daha izlenebilir hale getirir. Böylece hataları fark etmek daha kolay olur.

Çevrimdışı öncelikli bir uygulamada, uygulama verileri için doğruluk kaynağı genellikle veritabanıdır. Diğer bazı durumlarda, bilginin kaynağı ViewModel, hatta kullanıcı arayüzü olabilir.

Tek Yönlü Veri Akışı

Tek doğruluk kaynağı ilkesi, kılavuzlarımızda genellikle Tek Yönlü Veri Akışı (UDF) kalıbıyla birlikte kullanılır. UDF'de eyalet yalnızca tek yönde akar. Veri akışını ters yönde değiştiren etkinlikler.

Android'de durum veya veriler genellikle hiyerarşinin daha kapsamlı türlerinden daha düşük kapsamlı olanlara gider. Etkinlikler genellikle ilgili veri türü için TOAT'ye ulaşana kadar alt kapsamlı türlerden tetiklenir. Örneğin, uygulama verileri genellikle veri kaynaklarından kullanıcı arayüzüne geçer. Düğmeye basma gibi kullanıcı etkinlikleri, uygulama verilerinin değiştirildiği ve sabit bir türde gösterildiği TOAT'ye kullanıcı arayüzünden aktarılır.

Bu kalıp daha iyi veri tutarlılığını garanti eder, hatalara daha az eğilimlidir, hata ayıklaması daha kolaydır ve TOAT kalıbının tüm avantajlarını sunar.

Bu bölümde, uygulamanızı önerilen en iyi uygulamalara göre nasıl yapılandıracağınız açıklanmaktadır.

Önceki bölümde bahsedilen ortak mimari ilkeleri dikkate alındığında, her uygulamada en az iki katman bulunmalıdır:

  • Ekranda uygulama verilerini gösteren kullanıcı arayüzü katmanı.
  • Uygulamanızın iş mantığını içeren ve uygulama verilerini gösteren veri katmanı.

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 bulunan isteğe bağlı alan katmanından alır.
Şekil 1. Tipik bir uygulama mimarisi şeması.

Modern Uygulama Mimarisi

Bu Modern Uygulama Mimarisi, diğerlerinin yanı sıra aşağıdaki tekniklerin kullanılmasını teşvik eder:

  • Reaktif ve katmanlı bir 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 sahiplerinin bulunduğu bir kullanıcı arayüzü katmanı.
  • Ortaklar ve akışlar.
  • Bağımlılık yerleştirme ile ilgili en iyi uygulamalar

Daha fazla bilgi için aşağıdaki bölümlere, içindekiler tablosundaki diğer Mimari sayfalarına ve en önemli en iyi uygulamaların özetini içeren öneriler sayfasına göz atın.

kullanıcı arayüzü katmanı

Kullanıcı arayüzü katmanının (veya sunu katmanının) rolü, uygulama verilerini ekranda görüntülemektir. Kullanıcı etkileşimi (bir düğmeye basma gibi) veya harici giriş (ağ yanıtı gibi) nedeniyle veriler her değiştiğinde, kullanıcı arayüzü değişiklikleri yansıtacak şekilde güncellenmelidir.

Kullanıcı arayüzü katmanı iki şeyden oluşur:

  • Ekrandaki verileri oluşturan kullanıcı arayüzü öğeleri. Bu öğeleri, Görünüm veya Jetpack Compose işlevlerini kullanarak oluşturabilirsiniz.
  • Verileri tutan, kullanıcı arayüzüne maruz bırakan ve mantığı işleyen durum sahipleri (ör. ViewModel sınıfları).
Tipik bir mimaride, kullanıcı arayüzü katmanının kullanıcı arayüzü öğeleri durum sahiplerine bağlıdır. Durum sahipleri ise veri katmanındaki veya isteğe bağlı alan katmanındaki sınıflara bağlıdır.
Şekil 2. Kullanıcı arayüzü katmanının uygulama mimarisindeki rolü.

Bu katman hakkında daha fazla bilgi edinmek için kullanıcı arayüzü 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, sakladığını ve değiştirdiğini belirleyen kurallardan oluşur.

Veri katmanı, her biri sıfır ila birçok 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 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ğıdaki görevlerden sorumludur:

  • Uygulamanın geri kalanına veriler gösteriliyor.
  • Verilerdeki değişiklikleri merkezileştirme.
  • Birden çok veri kaynağı arasındaki çakışmaları çözme.
  • Uygulamanın geri kalanındaki veri kaynaklarını soyutlama.
  • İş mantığını içerir.

Her veri kaynağı sınıfının; dosya, ağ kaynağı veya yerel veritabanı olabilecek tek bir veri kaynağıyla çalışma sorumluluğu taşıması gerekir. Veri kaynağı sınıfları, veri işlemleri için uygulama ve sistem arasındaki köprüdür.

Bu katman hakkında daha fazla bilgi edinmek için veri katmanı sayfasına bakın.

Alan adı katmanı

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

Alan adı katmanı, karmaşık iş mantığını veya birden fazla ViewModel tarafından yeniden kullanılan basit iş mantığını kapsamaktan sorumludur. Bu gereksinimler tüm uygulamalarda olmayacağından bu katman isteğe bağlıdır. Yalnızca gerektiğinde (örneğin, karmaşıklığı yönetmek veya yeniden kullanılabilirliği tercih etmek için) kullanmalısınız.

İ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ü.

Bu katmandaki sınıflar genellikle kullanım alanları veya etkileşimleyiciler olarak adlandırılır. Her kullanım alanı, tek bir işlevden sorumlu olmalıdır. Örneğin, birden fazla ViewModel, ekranda doğru mesajı görüntülemek için saat dilimlerine güveniyorsa uygulamanızın bir GetTimeZoneUseCase sınıfı olabilir.

Bu katman hakkında 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, düzgün şekilde çalışabilmeleri için diğer sınıflara bağlıdır. 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 yerleştirme (DI): Bağımlılık yerleştirme, sınıfların bağımlılarını oluşturmadan, tanımlamalarına olanak tanır. Çalışma zamanında başka bir sınıf bu bağımlılıkları sağlamaktan 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 yinelemeden 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. Ayrıca bu kalıplar, test ve üretim uygulamaları arasında hızlıca geçiş yapmanızı sağlar.

Android uygulamalarında bağımlılık ekleme kalıplarını takip etmenizi ve Hilt kitaplığını kullanmanızı öneririz. Hilt, bağımlılık ağacını yürüterek nesneleri otomatik olarak oluşturur, bağımlılıklar üzerinde derleme süresi garantileri sağlar ve Android çerçeve sınıfları için bağımlılık container'ları oluşturur.

Genel en iyi uygulamalar

Programlama, yaratıcılık gerektiren bir alandır ve Android uygulamaları geliştirmek de bir istisna değildir. Bir sorunu çözmenin birçok yolu vardır. Birden fazla etkinlik veya parça arasında veri iletebilir, uzak verileri alıp çevrimdışı mod için yerel olarak saklayabilir veya sıra dışı uygulamaların karşılaştığı diğer yaygın senaryoları ele alabilirsiniz.

Aşağıdaki öneriler zorunlu olmasa da çoğu durumda kod tabanınızı uzun vadede daha sağlam, test edilebilir ve sürdürülebilir hale getirir:

Uygulama bileşenlerinde veri depolamayın.

Uygulamanızın giriş noktalarını (ör. etkinlikler, hizmetler ve yayın alıcıları) veri kaynağı olarak tanımlamaktan kaçının. Bunun yerine, yalnızca söz konusu giriş noktasıyla ilgili veri alt kümesini almak için diğer bileşenlerle koordine olmalıdır. Her uygulama bileşeni, kullanıcının cihazıyla etkileşimine ve sistemin genel mevcut durumuna bağlı olarak oldukça kısa ömürlüdür.

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

Uygulama bileşenleriniz yalnızca Context veya Toast gibi Android çerçeve SDK'sı API'lerini kullanan sınıflar olmalıdır. Uygulamanızdaki diğer sınıfları diğerlerinden uzaklaştırmak test edilebilirlik kazanmaya yardımcı olur ve uygulamanızın içindeki birleştirmeyi azaltır.

Uygulamanızdaki çeşitli modüller arasında iyi tanımlanmış sorumluluk sınırları oluşturun.

Örneğin, ağdan veri yükleyen kodu, kod tabanınızdaki birden çok sınıfa veya pakete yaymayın. Benzer şekilde, aynı sınıfta birbiriyle alakasız birden fazla sorumluluk (ör. veri önbelleğe alma ve veri bağlama) tanımlamayın. Önerilen uygulama mimarisini izlemek bu konuda size yardımcı olur.

Her modülde mümkün olduğunca az bilgi verin.

Örneğin, bir modülden dahili uygulama ayrıntılarını açığa çıkaran bir kısayol oluşturmaktan çekinmeyin. Kısa vadede biraz zaman kazanabilirsiniz ancak kod tabanınız geliştikçe teknik borcla pek çok kez karşılaşacaksınız.

Diğer uygulamalardan öne çıkması için uygulamanızın benzersiz temeline odaklanın.

Aynı ortak kodu tekrar tekrar yazarak tekerleği yeniden icat etmeyin. Bunun yerine, zamanınızı ve enerjinizi uygulamanızın benzersiz yanlarına harcayıp Jetpack kitaplıklarının ve önerilen diğer kitaplıkların tekrarlanan ortak metinlerle ilgilenmesine izin verin.

Uygulamanızın her bir bölümünü tek başına test edilebilir hale nasıl getireceğinizi düşünün.

Örneğin, ağdan veri getirmek için iyi tanımlanmış bir API'ye sahip olmak, bu verileri yerel bir veritabanında tutan modülün test edilmesini kolaylaştırır. Bunun yerine bu iki modülün mantığını tek bir yerde toplar veya ağ kodunuzu tüm kod tabanınıza dağıtırsanız etkili bir şekilde test etmek çok daha zor ve imkansız hale gelir.

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

Bir tür, uzun süreli engelleme çalışmaları gerçekleştiriyorsa bu hesaplamayı doğru iş parçacığına taşımaktan sorumlu olmalıdır. Bu özel tür, yaptığı hesaplama türünü ve hangi iş parçacığında yürütülmesi gerektiğini bilir. Türler, "main" güvenliğinde olmalıdır. Diğer bir deyişle, engellemeden ana iş parçacığından güvenli bir şekilde çağrılabilirler.

Olabildiğince çok alakalı ve güncel veriler sunun.

Bu şekilde, kullanıcılar, cihazları çevrimdışı moddayken bile uygulamanızın işlevselliğinin keyfini çıkarabilir. Tüm kullanıcılarınızın sabit ve yüksek hızlı bağlantıya sahip olmadığını ve bunu yapsalar bile kalabalık yerlerde kötü tepkiler alabileceğini unutmayın.

Mimarinin Avantajları

Uygulamanızda iyi bir Mimari'nin uygulanması, proje ve mühendislik ekiplerine birçok avantaj sağlar:

  • Genel olarak uygulamanın sürdürülebilirliğini, kalitesini ve dayanıklılığını iyileştirir.
  • Uygulamanın ölçeklendirilmesini sağlar. Daha fazla kişi ve daha fazla ekip, minimum kod çakışmasıyla aynı kod tabanına katkıda bulunabilir.
  • İlk katılıma yardımcı olur. Mimari projenize tutarlılık getirdiğinden, ekibin yeni üyeleri daha kısa sürede hızla adapte olabilir ve daha verimli olabilir.
  • Test etmek daha kolaydır. İyi bir Mimari, test edilmesi genellikle daha kolay olan basit türleri teşvik eder.
  • Hatalar, iyi tanımlanmış süreçlerle düzenli olarak incelenebilir.

Mimariye yatırım yapmanın kullanıcılarınız üzerinde doğrudan etkisi de vardır. Daha kararlı bir uygulamadan ve daha üretken bir mühendislik ekibi sayesinde daha fazla özellikten faydalanırlar. Ancak Mimari de önden zaman yatırımı yapmayı gerektirir. Bu süreyi şirketinizdeki diğer çalışanlara gerekçelendirmek için diğer şirketlerin uygulamalarında iyi bir mimariye sahip olduklarında başarı öykülerini paylaştıkları bu örnek olaylara göz atın.

Sana Özel

Aşağıdaki Google örnekleri, iyi uygulama mimarisini göstermektedir. Bu rehberliği pratikte görmek için bunları keşfedin: