Flutter’da Temiz Kod için Yapılabilecekler

 

Merhaba,
Bugünlerde yeni bir mobil uygulama üzerinde çalışıyorum. Kendime bir son tarih belirledim ve uygulamamı Ağustos sonunda GooglePlay’de yayınlamayı planlıyorum. Programın yazma kısmı çoğunlukla bitti, şimdi kodumu nasıl daha temiz, daha sürdürülebilir hale getirebileceğimi, nasıl refactor edebileceğimi araştırıyorum.
Bu aşamada öğrendiklerimi burada paylaşmak istedim. Şimdi temiz kod için neler yapabileceğimizi inceleyelim.

1. Flutter’ın Resmi Yönergelerini Takip Edin

Karşılaştığım ilk öneri Flutter ve Dart’ın kendi dokümantasyonu oldu.

  • Dart’ın etkili uygulamalarını kullanın: Dart’ın Effective Dart olarak bilinen resmi yönergeleri, okunabilir, sürdürülebilir ve etkili Dart kodunun nasıl yazılacağı konusunda kapsamlı tavsiyeler sunar. Stil, dokümantasyon, tasarım ve kullanım yönergelerini kapsar.
  • Flutter belgeleri: Flutter belgeleri kapsamlı öğreticiler, örnek kodlar ve en iyi uygulamaları içerir. Flutter özelliklerini uygulamanın en iyi yolları konusunda güncel kalmak için düzenli olarak başvurun.

2. Projenizi Yapılandırın

Klasörlemenin düşündüğümden daha önemli olduğu ortaya çıktı. Dart dosyalarını sırasıyla lib klasörü altında açıp adlandırıyordum, ancak bu şekilde yapılmamalı.

  • Özellik tabanlı yapı: Dosyaları türüne göre düzenlemek yerine (örneğin, tüm modelleri bir klasöre, tüm görünümleri başka bir klasöre koymak), projenizi özelliklere göre düzenleyin. Örneğin, kimlik doğrulama, ev, profil gibi özellikler için ayrı dizinlere sahip olun. Her özellik dizini modeller, görünümler, denetleyiciler vb. için alt dizinler içerebilir.
lib/
features/
authentication/
models/
views/
controllers/
home/
models/
views/
controllers
  • İş mantığını ayırın: BLoC (Business Logic Component), Provider veya Riverpod gibi kalıplar iş mantığını kullanıcı arayüzü kodundan ayırmanıza yardımcı olur. Bu ayırma kodu daha modüler, test edilebilir ve bakımı yapılabilir hale getirir.

3. Durum Yönetimini Akıllıca Kullanın

Durum yönetiminin türünü de dikkatli seçmek gerekir. Ben Provider’ı öğrendim, bunu tüm projelerimde kullanacağım dememeliyiz.

  • Uygun durum yönetimini seçin: Provider, Riverpod, BLoC ve Redux gibi farklı durum yönetimi çözümlerini değerlendirin. Projenizin ihtiyaçlarına ve karmaşıklığına uygun olanı seçin. Daha basit uygulamalar için Provider yeterli olabilirken, daha büyük uygulamalar BLoC veya Redux’tan faydalanabilir.
  • Widget’ları basit tutun: Widget’lar öncelikle kullanıcı arayüzü oluşturma ile ilgilenmelidir. Widget’ların içine iş mantığı gömmekten kaçının. Bu, kullanıcı arayüzü kodunuzu temiz ve mantığınızı yeniden kullanılabilir tutar.

4. Yeniden Kullanılabilir Widget’lar Yazın

Widget’ları yeniden kullanılabilecek küçük parçalara bölmek, kodu daha sonra düzeltmek veya güncellemek istediğinizde çok kullanışlıdır. Ancak, özellikle kullanıcı arayüzü konusunda, bir widget’a birden fazla görev yüklememek önemlidir.

  • Kullanıcı arayüzünü küçük widget’lara bölün: Büyük, monolitik widget’lar oluşturmaktan kaçının. Bunun yerine, kullanıcı arayüzünü belirli işlevsellik parçalarını kapsayan daha küçük, yeniden kullanılabilir widget’lara bölün. Bu modülerlik, kodun test edilmesini ve yeniden kullanılmasını kolaylaştırır.
  • Widget işlevselliğini kapsülleyin: Her widget tek bir sorumluluğa sahip olmalıdır. Örneğin, bir ProfileCard widget’ınız varsa, yalnızca profil bilgilerini görüntülemekle ilgilenmeli, bir sunucudan getirmemelidir.

5. İsimlendirme Kurallarına Uyun

İsimlendirme kuralları öğrenilmesi gereken ilk şey. Proje büyüdükçe arapsaçına dönmemesi için planlanması gerekiyor, neyse ki şimdilik bunu iyi yapıyorum :)

  • Tutarlı adlandırma: Kod tabanınız boyunca tutarlı bir adlandırma kuralı kullanın. Örneğin, değişken isimleri için camelCase ve sınıf isimleri için PascalCase kullanın.
  • Anlamlı isimler: Değişken veya fonksiyonun amacını ifade eden açıklayıcı isimler seçin. Döngü sayaçları dışında tek karakterli isimlerden kaçının.

6. Kendinizi Tekrar Etmeyin
Yeniden kullanılabilir widget’lar bunun için var.

  • Yinelemelerden kaçının: Kendinizi aynı kodu birden fazla yerde yazarken bulursanız, yeniden kullanılabilir bir işlev veya widget’a dönüştürün. Bu, hata riskini azaltır ve bakımı kolaylaştırır.
  • Yapılandırmaları merkezileştirin: Yapılandırma değerlerini (ör. API uç noktaları, tema verileri) tek bir yerde saklayın. Bu, onları güncellemeyi kolaylaştırır ve tutarlılığı sağlar.

7. Yorum Satırları

Aradan zaman geçtikten sonra neyin nerede yapıldığını hatırlamamıza yardımcı olacak anlamlı yorum satırları yazmak hayat kurtarır.

  • Kodunuzu belgeleyin: Özellikle karmaşık veya açık olmayan kod blokları için belirli kararların neden alındığını açıklayan anlamlı yorumlar yazın.
  • Dartdoc kullanın: Kod tabanınız için faydalı belgeler oluşturmak üzere genel API’lerinize Dartdoc yorumları ekleyin. Bu, diğer geliştiricilerin (ve gelecekteki kendinizin) kodunuzu nasıl kullanacaklarını anlamalarına yardımcı olur.

8. Linting ve Kod Analizini Kullanın

Linter’ı ilk olarak Google Digital Workshop’un Flutter kursunda duymuştum. Proje dosyasına belirli kurallar eklenerek kodlama süreci hızlandırılabilir ya da otomatikleştirilebilir.

  • Linting’i etkinleştirin: Kodlama standartlarını uygulamak ve olası sorunları erkenden yakalamak için Dart analizörünü ve linter’ı kullanın. Analysis_options.yaml dosyası, linting kurallarını belirtmek için yapılandırılabilir.
  • Linter kurallarını özelleştirin: Linter kurallarını ekibinizin kodlama standartlarına uyacak şekilde ayarlayın. Örneğin, tüm genel yöntemlerin belge açıklamalarına sahip olması kuralını uygulayabilirsiniz.

9. Performansı Optimize Edin

const anahtar kelimesinin önemini çok geç öğrenmiş olabilirim, her seferinde yeniden oluşturulması gerekmiyorsa, değişmiyorsa kesinlikle const kullanılması gerekir.

  • Gereksiz rebuildlerden kaçının: Gereksiz widget buildlerini en aza indirmek için const yapıcıları, anahtarları ve verimli durum yönetimini kullanın. Örneğin, const kullanmak Flutter’ın bir widget ağacının yeniden oluşturulmasına gerek olmadığını belirlemesine yardımcı olabilir.
  • Uygulamanızın profilini çıkarın: Performans darboğazlarını belirlemek ve düzeltmek için Flutter’ın profil oluşturma araçlarını (Dart DevTools gibi) kullanın. Bu, uygulamanızın zamanının çoğunu nerede geçirdiğini anlamanıza ve buna göre optimize etmenize yardımcı olabilir.

10. Testler Yazın

Test yazım aşamasını araştırmaya devam ediyorum. Bu konuda ayrı bir yazı yazacağım.

  • Birim testleri: İş mantığınız için birim testleri yazın. Bu, mantığınızın doğru çalışmasını sağlar ve refactoring’i daha güvenli hale getirir.
  • Widget testleri: Kullanıcı arayüzünüzün beklendiği gibi davrandığından emin olmak için widget testleri yazın. Bu, regresyonları yakalayabilir ve kullanıcı arayüzünüzün çeşitli koşullar altında doğru çalışmasını sağlayabilir.
  • Entegrasyon testleri: Uygulamanızın tüm akışını doğrulamak için entegrasyon testleri yazın. Bu testler gerçek veya simüle edilmiş cihazlarda çalışır ve uygulamanızın tüm parçalarının beklendiği gibi birlikte çalışmasını sağlar.

11. Versiyon Kontrolü

Git ve GitHub, proje sürümlerini takip etmek için çok önemlidir. Nerede ne değiştirdim diye geriye dönük bakmak isteyebiliriz ya da olası bir veri kaybının önüne geçebiliriz. Ben de uygulamama eklediğim neredeyse her özellikten sonra mutlaka git’e gönderiyorum.

  • Git’i etkin kullanın: Değişiklikleri anlamlı mesajlarla sık sık commit edin. Ana dalı kararlı tutmak için yeni özellikler ve hata düzeltmeleri için dallar kullanın.
  • Kod incelemeleri: Kod kalitesini korumak ve ekip üyeleri arasında bilgi paylaşımını sağlamak için düzenli kod incelemeleri yapın. Bu, olası sorunları erkenden yakalayabilir ve tutarlı kodlama standartları sağlayabilir.

12. Bağımlılıkları Güncel Tutun

  • Düzenli olarak güncelleyin: Flutter ve Dart SDK’larınızın yanı sıra paket bağımlılıklarını da düzenli olarak güncelleyin. Bu, en son özelliklere, hata düzeltmelerine ve güvenlik yamalarına sahip olmanızı sağlar.
  • Son değişiklikleri kontrol edin: Bağımlılıkları güncellerken kırılma değişiklikleri için değişiklik günlüğünü inceleyin. Bu, güncellemelere uyum sağlamak için kodunuzda hangi değişiklikleri yapmanız gerektiğini anlamanıza yardımcı olur.

13. Uzantıları ve Yardımcı Programları Kullanın

Yardımcı fonksiyonlar basit işlemleri optimize etmek için kullanılabilir. Örneğin son projemde veritabanından gelen kategori isimlerini çoğul hale getirmek istemiştim ve benzer şekilde kullanmıştım.

  • Yardımcı fonksiyonlar oluşturun: Ortak işlevleri yardımcı fonksiyonlara veya uzantılara ayıklayın. Bu, kodunuzun DRY ve düzenli kalmasına yardımcı olur. Örneğin, String üzerinde bir uzantı oluşturarak ilk harfi büyük yazmak için bir yöntem ekleyebilirsiniz
extension StringExtension on String {
String capitalize() {
return this[0].toUpperCase() + substring(1);
}
}

Flutter’da temiz ve sürdürülebilir kod yazmak için neler yapabiliriz diye araştırdığımda bulduklarımı bu başlıklar altında topladım. Sizin de eklemek istedikleriniz varsa yorumlara yazabilirsiniz. Umarım faydalı olmuştur.

Okuduğunuz için teşekkürler.

Selin.

print and debugPrint in Flutter

 

test with print and debugPrint

Hello,

When I was looking at the do’s & dont’s posts about Flutter, there was a topic I came across: print and debugPrint. I use the console screen as much as putting breakpoints while writing a program to test with print, to see where I am in stages. However, if I proceed with print, I get the warning “Don’t invoke ‘print’ in production code”. If I write the same line with debugPrint, this warning disappears. So today I wanted to investigate the difference between these two, why one gives a warning and the other doesn’t. Let’s examine both in detail.

What is print?

print is the standard output function of the Dart language. It prints the text specified in the terminal or console.

void main() {
print("This is an example of the print function.");
}

What are the disadvantages?

  • The first disadvantage is that when we want to print long texts or too many lines of output, it can give an “output truncated” error in the console (this has happened to me before, I encountered it when I researched debugPrint). So, we can have problems when printing a lot of data at the same time.
  • The second issue is actually related to the first one. When we want to output a lot of data or a large amount of data, there can be a performance loss. So it is less efficient in terms of performance.

What is debugPrint?

debugPrint is a Flutter framework specific function optimized for Flutter applications. It prints text to the console in the same way, but prevents long text from being split and truncated.

void main() {
debugPrint("This is an example of the debugPrint function.");
}

What are the advantages?

  • The debugPrint function checks the line boundaries of text and splits the output into chunks if necessary. This way, long texts are printed without being properly truncated.
  • This makes debugPrint more performant when printing large data and does not negatively affect the performance of the application.
  • debugPrint limits the output to 800 characters by default. However, we can use debugPrint’s “wrapWidth” parameter for longer output.

wrapWidth Usage

The wrapWidth parameter of the debugPrint function allows us to control how long text is wrapped. Here wrap means to determine after how many characters each line is divided.

String longText = 'This is an example of a very long text.' * 20;  //This means printing the text 20 times in a row.

// debugPrint without wrapWidth (standard)
debugPrint("without wrapWidth:", wrapWidth: 800);
debugPrint(longText);

// usage of debugPrint with wrapWidth parameter (split after the 50th character)
debugPrint("\nwith wrapWidth (50 characters):", wrapWidth: 800);
debugPrint(longText, wrapWidth: 50);
  • Without wrapWidth: debugPrint is used with the default wrap width (800 characters).
  • With wrapWidth (50 Characters): the wrapWidth parameter is set to 50 characters, so that each line is split after 50 characters.

Below we will see the output of these codes: texts will move to a new line after the specified number of characters. This is particularly useful for making long log messages more readable.

without wrapWidth:
This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.This is an example of a very long text.

with wrapWidth:
This is an example of a very long text.This is an
example of a very long text.This is an example of
a very long text.This is an example of a very long
text.This is an example of a very long text.This
is an example of a very long text.This is an
example of a very long text.This is an example of
a very long text.This is an example of a very long
text.This is an example of a very long text.This
is an example of a very long text.This is an
example of a very long text.This is an example of
a very long text.This is an example of a very long
text.This is an example of a very long text.This
is an example of a very long text.This is an
example of a very long text.This is an example of
a very long text.This is an example of a very long
text.This is an example of a very long text.

Which one to use in which situation?

Short and Simple Printouts: For simple and short outputs we can still use print (if we don’t mind the yellow warning).
Long and Complex Output: When you need to print long text or a lot of data, it is wiser to use debugPrint.
General Use: It is still generally more convenient and reliable to use debugPrint when debugging Flutter projects.

As we can see, small changes in the application can make a big difference in performance and usability. After doing my research, I decided to use debugPrint instead of print in all my tests and got rid of the yellow warning. I hope this was useful.

Thank you in advance for your valuable feedback.

Selin.