Flutter Uygulamalarında Endişelerin Ayrılması
Engineering at ClickUp

Flutter Uygulamalarında Endişelerin Ayrılması

Kısa bir süre önce, ClickUp'a yeni katılanlar için bir oryantasyon kılavuzu hazırlamam gerekti! Bu çok önemli bir görevdi, çünkü birçok yeni kullanıcı, Super Bowl'da yayınladığımız inanılmaz komik reklamla platformumuzu keşfetmek üzereydi! ✨

clickUp aracılığıyla

Bu kılavuz, ClickUp'ı henüz tanımayan çok sayıda yeni kullanıcımızın, uygulamadaki çeşitli işlevleri nasıl kullanacaklarını hızlı bir şekilde anlamalarını sağlar. Bu, sürdürdüğümüz yeni ClickUp Üniversitesi kaynağı gibi devam eden bir çabadır! 🚀

Neyse ki, ClickUp Flutter mobil uygulamasının arkasındaki yazılım mimarisi, uygulamanın gerçek bileşenlerini yeniden kullanarak bile bu işlevselliği oldukça hızlı bir şekilde uygulamama olanak tanıdı! Bu, adım adım kılavuzun dinamik, duyarlı ve uygulamanın gerçek ekranlarıyla tam olarak eşleştiği ve bileşenler geliştikçe de bu şekilde kalacağı anlamına gelir.

Ayrıca, ilgi alanlarının doğru bir şekilde ayrılması sayesinde bu fonksiyonelliği uygulayabildim.

Ne demek istediğimi görelim. 🤔

Endişelerin ayrılması

Yazılım mimarisi tasarımı, mühendislik takımları için en karmaşık konulardan biridir. Tüm sorumluluklar arasında, gelecekteki yazılım gelişmelerini öngörmek her zaman zordur. Bu nedenle, iyi katmanlanmış ve birbirinden bağımsız bir mimari oluşturmak size ve takım arkadaşlarınıza birçok konuda yardımcı olabilir!

Küçük, birbirinden bağımsız sistemler oluşturmanın en büyük avantajı şüphesiz test edilebilirlik! Ve bu, uygulamadaki mevcut ekranların bir demo alternatifini oluşturmama yardımcı oldu!

Adım adım kılavuz

Peki, bu ilkeleri bir Flutter uygulamasına nasıl uygulayabiliriz?

ClickUp'ı oluşturmak için kullandığımız birkaç tekniği basit bir örnekle paylaşacağız.

Örnek o kadar basit ki, arkasındaki tüm avantajları ortaya çıkarmayabilir, ancak inanın bana, karmaşık kod tabanlarına sahip çok daha kolay bakım yapılabilir Flutter uygulamaları oluşturmanıza yardımcı olacaktır. 💡

Uygulama

Örnek olarak, her yıl ABD'nin nüfusunu gösteren bir uygulama oluşturacağız.

clickUp aracılığıyla

Burada iki ekran var:

  • HomeScreen : 2000'den günümüze kadar tüm yılları listeler. Kullanıcılar bir yıl kutucuğuna dokunduklarında, seçilen yıla ayarlanmış bir navigasyon argümanıyla DetailScreen ekranına yönlendirilirler.
  • DetailScreen : navigasyon argümanından yılı alır, bu yıl için datausa.io API'sini çağırır ve JSON verilerini ayrıştırarak ilişkili nüfus değerini çıkarır. Veriler mevcutsa, nüfusla birlikte bir etiket görüntülenir.

Asenkron çağrısı ile en ilgi çekici olan DetailScreen uygulamasına odaklanacağız.

Adım 1. Naif yaklaşım

Naif yaklaşım Durum bilgisi olan bileşen
clickUp aracılığıyla

Uygulamamız için en bariz uygulama, tüm mantık için tek bir StatefulWidget kullanmaktır.

Yıl navigasyon argümanına erişim

İstenen yıla erişmek için, ModalRoute bileşeninden RouteSettings'i okuruz.

HTTP çağrısı

Bu örnek, datausa.io API'sinden verileri almak için http paketinden get fonksiyonunu çağırır, dart:convert kütüphanesinden jsonDecode yöntemi ile sonuçta ortaya çıkan JSON'u ayrıştırır ve Future'u _future adlı bir özellik ile durumun bir parçası olarak tutar.

Oluşturma

Bileşen ağacını oluşturmak için, _future asenkron çağrımızın mevcut durumuna göre kendini yeniden oluşturan FutureBuilder kullanıyoruz.

İnceleme

Tamam, uygulama kısa ve yalnızca yerleşik bileşenleri kullanıyor, ancak şimdi ilk amacımızı düşünün: bu ekran için demo alternatifleri (veya testler) oluşturmak. Uygulamanın belirli bir durumda görüntülenmesini zorlamak için HTTP çağrısının sonucunu kontrol etmek çok zordur.

İşte burada kontrolün tersine çevrilmesi kavramı bize yardımcı olacaktır. 🧐

Adım 2. Kontrolün tersine çevrilmesi

Kontrolün sağlayıcıya ve API müşteriye tersine çevrilmesi
clickUp aracılığıyla

Bu ilke, yeni geliştiriciler için anlaşılması zor olabilir (ve açıklaması da zor), ancak genel fikir, bileşenlerimizin dışındaki sorunları ayıklamak ve böylece bunların davranış seçiminden sorumlu olmamalarını sağlamak ve bunun yerine bu görevi devretmektir.

Daha yaygın bir durumda, bu işlem basitçe soyutlamalar oluşturmak ve bileşenlerimize uygulamaları eklemekten ibarettir, böylece gerektiğinde uygulamalar daha sonra değiştirilebilir.

Ancak endişelenmeyin, bir sonraki örneğimizden sonra her şey daha net hale gelecektir! 👀

API müşteri nesnesi oluşturma

API'mıza yapılan HTTP çağrısını kontrol etmek için, uygulamamızı özel bir DataUsaApiClient sınıfına ayırdık. Ayrıca, verilerin daha kolay işlenebilmesi ve bakımı için bir Measure sınıfı oluşturduk.

API müşterisi sağlayın

Örneğimizde, ağaç yapımızın köküne bir DataUsaApiClient örneği eklemek için iyi bilinen sağlayıcı paketini kullanıyoruz.

API müşterisini kullanma

Sağlayıcı, herhangi bir alt bileşenin (DetailScreen gibi)* ağaçtaki en yakın DataUsaApiClient üstünü okumasını sağlar. Ardından, gerçek HTTP uygulaması yerine getMeasure yöntemini kullanarak Future'ımızı başlatabiliriz.

Demo API müşterisi

Artık bundan yararlanabiliriz!

Bilmiyorsanız: dart'taki tüm sınıflar , ilişkili bir arayüzü de dolaylı olarak tanımlar. Bu, getMeasure yöntem çağrılarından her zaman aynı örneği döndüren DataUsaApiClient'ın alternatif bir uygulamasını sağlamamıza olanak tanır.

Bu yöntem

Bu yöntem

Demo sayfası görüntüleme

Artık DetailPage'in bir demo örneğini görüntülemek için tüm anahtarlara sahibiz!

DetailScreen'i, bunun yerine bir DemoDataUsaApiClient örneği oluşturan bir sağlayıcıya sararak, mevcut DataUsaApiClient örneğini basitçe geçersiz kılıyoruz!

Hepsi bu kadar — DetailScreen, bunun yerine bu demo örneğini okur ve HTTP çağrısı yerine demoMeasure verilerimizi kullanır.

İnceleme

Bu, kontrolün tersine çevrilmesi için harika bir örnektir. DetailScreen bileşenimiz artık verileri alma mantığından sorumlu değildir, bunun yerine bu görevi özel bir müşteri nesnesine devreder. Artık ekranın demo örneklerini oluşturabilir veya ekranımız için bileşen testleri uygulayabiliriz! Harika! 👏

Ama daha iyisini yapabiliriz!

Örneğin, yükleme durumunu simüle edemediğimiz için, bileşen düzeyinde herhangi bir durum değişikliğini tam olarak kontrol edemiyoruz.

Adım 3. Durum yönetimi

Flutter uygulamalarında ifade yönetimi
clickUp aracılığıyla

Bu, Flutter'da çok popüler bir konu!

Flutter için en iyi durum yönetimi çözümünü seçmeye çalışanların uzun konu başlıklarını okuduğunuzdan eminim. Açıkça belirtmek gerekirse, bu makalede yapacağımız şey bu değil. Bizim görüşümüze göre, iş mantığınızı görsel mantığınızdan ayırdığınız sürece sorun yok! Bu katmanları oluşturmak, bakım açısından gerçekten önemlidir. Örneğimiz basit, ancak gerçek uygulamalarda mantık hızla karmaşık hale gelebilir ve bu tür bir ayrım, saf mantık algoritmalarınızı bulmanızı çok daha kolay hale getirir. Bu konu genellikle durum yönetimi olarak özetlenir.

Bu örnekte, bir Sağlayıcı ile birlikte temel bir ValueNotifier kullanıyoruz. Ancak flutter_bloc veya riverpod (veya başka bir çözüm) kullanabilirdik ve bu da harika bir şekilde işe yarardı. İlkeler aynı kalır ve durumlarınızı ve mantığınızı ayırdığınız sürece, kod tabanınızı diğer çözümlerden birinden taşıyabilirsiniz.

Bu ayrım, bileşenlerimizin her durumunu kontrol etmemize yardımcı olur, böylece her şekilde simülasyonunu yapabiliriz!

Özel bir durum oluşturma

Artık, çerçeve yapısından AsyncSnapshot'a güvenmek yerine, ekran durumumuzu bir DetailState nesnesi olarak temsil ediyoruz.

Nesnemizi değere göre karşılaştırılabilir hale getirmek için hashCode ve operator == yöntemlerini uygulamak da önemlidir. Bu, iki örneğin farklı olarak değerlendirilip değerlendirilmeyeceğini tespit etmemizi sağlar.

💡 Eşlenebilir veya dondurulmuş paketler, hashCode ve operator == yöntemlerini uygulamanıza yardımcı olacak harika seçeneklerdir!

💡 Eşlenebilir veya dondurulmuş paketler, hashCode ve operator == yöntemlerini uygulamanıza yardımcı olacak harika seçeneklerdir!

Durumumuz her zaman bir yılla ilişkilidir, ancak kullanıcıya göstermek istediğimiz şeye göre dört farklı durumumuz da vardır:

  • NotLoadedDetailState: veri güncelleme henüz başlamadı
  • LoadingDetailState: veriler şu anda yükleniyor
  • LoadedDetailState: veriler ilişkili bir ölçü ile başarıyla yüklendi
  • NoDataDetailState: veriler yüklendi, ancak kullanılabilir veri yok
  • UnknownErrorDetailState: bilinmeyen bir hata nedeniyle işlem başarısız oldu

Bu durumlar, kullanım örneklerimizi gerçekten temsil ettiği için AsyncSnapshot'tan daha açıktır. Ve yine, bu da kodumuzun bakımını daha kolay hale getirir!

💡 Mantık durumlarınızı temsil etmek için frozen paketindeki Union türlerini kullanmanızı şiddetle tavsiye ederiz! Bu, copyWith veya map yöntemleri gibi birçok yardımcı işlev ekler.

💡 Mantık durumlarınızı temsil etmek için frozen paketindeki Union türlerini kullanmanızı şiddetle tavsiye ederiz! Bu, copyWith veya map yöntemleri gibi birçok yardımcı işlev ekler.

Mantığı Notifier'a yerleştirme

Artık durumumuzun bir temsilini elde ettiğimize göre, bunun bir örneğini bir yerde saklamamız gerekiyor — DetailNotifier'ın amacı budur. Mevcut DetailState örneğini değer özelliğinde tutacak ve durumu güncellemek için yöntemler sağlayacaktır.

NotLoadedDetailState başlangıç durumu ve API'dan verileri yüklemek ve mevcut değeri güncellemek için bir yenileme yöntemi sağlıyoruz.

Görünüm için bir durum sağlayın

Ekranımızın durumunu örneklendirmek ve gözlemlemek için, sağlayıcıya ve onun ChangeNotifierProvider'ına da güveniyoruz. Bu tür sağlayıcılar, oluşturulan tüm ChangeListener'ları otomatik olarak arar ve bir değişiklik bildirildiğinde (bildirici değerimiz bir öncekinden farklı olduğunda) Consumer'dan yeniden oluşturmayı tetikler

İnceleme

Harika! Uygulama mimarimiz oldukça iyi görünmeye başladı. Her şey, belirli sorunlara göre iyi tanımlanmış katmanlara ayrıldı! 🤗

Ancak test edilebilirlik için hala eksik olan bir şey var: ilişkili DetailScreen'in durumunu kontrol etmek için mevcut DetailState'i tanımlamak istiyoruz.

Adım 4. Görsel özel düzen bileşeni

Flutter uygulamalarında görsel özel düzen bileşenleri
clickUp aracılığıyla

Son adımda, DetailScreen bileşenine biraz fazla sorumluluk verdik: DetailNotifier'ı örneklendirmekle sorumluydu. Ve daha önce gördüğümüz gibi, görünüm katmanında herhangi bir mantık sorumluluğundan kaçınmaya çalışıyoruz!

Bunu, ekran bileşenimiz için başka bir katman oluşturarak kolayca çözebiliriz: DetailScreen bileşenimizi ikiye böleceğiz:

  • DetailScreen, mevcut uygulama durumundan (navigasyon, bildirimler, durum, hizmetler vb.) ekranımızın çeşitli bağımlılıklarını ayarlamaktan sorumludur
  • DetailLayout, DetailState'i özel bir bileşen ağacına dönüştürür.

İkisini birleştirerek, DetailLayout demo/test örneklerini kolayca oluşturabilir, ancak uygulamamızdaki gerçek kullanım durumu için DetailScreen'e sahip olabiliriz.

Özel düzen

Daha iyi bir ayrım sağlamak için, Tüketici bileşeninin altındaki her şeyi özel bir DetailLayout bileşenine taşıdık. Bu yeni bileşen yalnızca verileri tüketir ve herhangi bir örneklendirme işleminden sorumlu değildir. Yalnızca okuma durumunu belirli bir bileşen ağacına dönüştürür.

ModalRoute. çağırma ve ChangeNotifierProvider örneği DetailScreen'de kalır ve bu bileşen, önceden yapılandırılmış bir bağımlılık ağacı ile DetailLayout'u döndürür!

Bu küçük iyileştirme, sağlayıcı kullanımına özeldir, ancak herhangi bir alt bileşenin bir DetailState'i doğrudan kullanabilmesi için bir ProxyProvider eklediğimizi de fark edeceksiniz. Bu, verileri taklit etmeyi kolaylaştıracaktır.

Bileşenleri özel sınıflar olarak ayıklama

Bir bileşen ağacını özel bir sınıfa ayırmaktan asla çekinmeyin! Bu, performansı artıracak ve kodu daha kolay yönetilebilir hale getirecektir.

Örneğimizde, ilişkili durum türlerinin her biri için bir görsel düzen bileşeni oluşturduk:

Demo örnekleri

Artık ekranımızda neyi taklit edip görüntüleyebileceğimiz üzerinde tam kontrol sahibiyiz!

Düzenin durumunu simüle etmek için bir DetailLayout'u bir Sağlayıcı ile sarmalamamız yeterlidir.

Sonuç

Bakımı kolay bir yazılım mimarisi oluşturmak kesinlikle kolay değildir! Gelecekteki senaryoları öngörmek çok çaba gerektirebilir, ancak paylaştığım birkaç ipucunun gelecekte size yardımcı olacağını umuyorum!

Örnekler basit görünebilir, hatta aşırı mühendislik gibi bile gelebilir, ancak uygulamanızın karmaşıklığı arttıkça, bu standartlara sahip olmak size çok yardımcı olacaktır! 💪

Flutter ile eğlenin ve blogumuzu takip ederek bunun gibi daha fazla teknik makaleye ulaşın! Bizi takip etmeye devam edin!

ClickUp Logo

Hepsini değiştirmek için tek uygulama