Effective Dart: Design

Münevver BAHAR
HardwareAndro
Published in
8 min readJul 18, 2020

Merhaba, bugün “ Effective Dart: Design ” konusundan bahsedeceğim. Uzun bir yazı olacak gibi çayınızı, kahvenizi hazırladıysanız başlıyoruzz☕️

Nelerden bahsedeceğiz?

  • Names Design
  • Libraries Design
  • Classes and Mixins Design
  • Constructors Design
  • Members Design
  • Types Design
  • Parameters Design
  • Equality Design

Names Design

Kod yazarken isimlendirme, okunabilirlik ve devamlılık açısından önemlidir.

✍️Terimleri tutarlı bir şekilde kullanın.

Kodunuz boyunca aynı şeyler için aynı adlandırmaları kullanın. Bazı genel geçer kavramlar vardır kodunuzda bunlara yer verin bu sayede kodunuzun anlaşılmasını kolaylaştırabilirsiniz.

pageCount          // A field
updatePageCount() // Consistent with pageCount
toSomething() // Consistent with Iterable's toList()
asSomething() // Consistent with List's asMap()
Point // A familiar concept

Tek harften oluşan adlandırmalar tam olarak açıklayıcı değil ama neredeyse tüm genel tipler için bunlar kullanılır. Neyse ki, genelde baş harflerini kullanmışlar…

Örneğin;

Bir koleksiyondaki element tipi için E :

class IterableBase<E> {} 
class List<E> {}
class HashSet<E> {}
class RedBlackTree<E> {}

İlişkisel koleksiyonlardaki key ve value içinse K ve V :

class Map<K, V> {} 
class Multimap<K, V> {}
class MapEntry<K, V> {}

✍️En açıklayıcı ismi en sona koyun.

Adlandırmada kullanılan son kelime tanımlanan şeyin ne olduğunu, işlevini en iyi açıklayan kelime olmalıdır.

pageCount              // A count (of pages)  
ConversionSink // A sink for doing conversions
ChunkedConversionSink // A ConversionSink that's chunked CssFontFaceRule // A rule for font faces in CSS

✍️Boolean olmayan bir özellik veya değişken için isim tamlaması tercih edin.

Unutmayın, okuyucunun odağı özelliğin ne olduğudur.

list.length 
context.lineWidth
quest.rampagingSwampBeast
list.deleteItems

✍️Boolean bir özellik veya değişken içinse zorunlu olmayan bir fiil kullanın.

Boolean adları genellikle koşullar için kullanırız, bu nedenle iyi okunan bir ad olması lazım.

if (window.closeable) ...  // Sıfat
if (window.canClose) ... // Fiil

İyi isimler genellikle bir kaç tür fiilden biriyle başlar

  • Bunlardan ilki ve en yaygın olanları “to be” biçimidir: isEnabled, wasShown, willFire
  • İkincisi bir yardımcı fiil ile kullanımı: hasElements, canClose, shouldConsume, mustSave
  • Üçüncüsü etkin bir fiil kullanımı: ignoresInput, wroteFile Bunlar nadirdir çünkü genellikle belirsizdirler.

✍️Ana amacı bir yan etki olan fonksiyon veya methodlar için zorunlu bir fiil kullanın.

Method, fonksiyon gibi çağrılabilir üyeler bir değer döndürebilir veya başka işler, yan etkiler gerçekleştirebilir. Dart dilinde bu tür üyeler genellikle yan etkileri nedeniyle çağrılırlar: bir nesnenin durumunu değiştirebilir, bir çıktı üretebilir veya dış dünya ile konuşabilirler.

Bu tür üyeler, üyenin gerçekleştirdiği işi açıklayan zorunlu bir fiil cümlesi kullanılarak adlandırılmalıdır.

list.add("element"); 
queue.removeFirst();
window.refresh();

✍️Bir değer döndüren fonksiyon veya methodlar için bir isim tamlaması ya da zorunlu olmayan bir fiil tercih edin.

Bu tür methodların çok az yan etkisi vardır, ancak çağıran kişiye faydalı bir sonuç verir. Methodlar, bazen mantıksal bir “özellik” için bazı parametrelere ihtiyaç duyar.

Örneğin, elementAt() bir koleksiyondaki bir veri parçasını döndürür, ancak hangi veri parçasının döndürüleceğini bilmesi için bir parametreye ihtiyacı vardır.

var element = list.elementAt(3); 
var first = list.firstWhere(test);
var char = string.codeUnitAt(4);

✍️Nesnenin durumunu yeni bir nesneye kopyalıyorsa to___() yardımcı fiilini kullanın.

Bir dönüşüm methodu tanımlıyorsanız, bu kurala uymak yararlı olur.

list.toSet();
stackTrace.toString();
dateTime.toLocal();

Kısaltma, kısaltılmamış terimden daha yaygın değilse, kısaltmayın!

✔️                               ❌
pageCount numPages
buildRectangles buildRects
IOStream InputOutputStream
HttpRequest HypertextTransferProtocolRequest

Libraries Design

Bir kitaplıkta yapılan genel bir bildirim, diğer kitaplıkların bu üyeye erişebileceği ve erişmesi gereken bir sinyaldir. Ayrıca, bunu desteklemek ve gerçekleştiğinde düzgün davranmak kütüphanenizin adına bir taahhüttür.

Java gibi bazı diller, dosyaların organizasyonunu sınıfların organizasyonuna bağlar, her dosya sadece tek bir üst düzey sınıf tanımlayabilir.

Dart dilinde böyle bir sınırlama yoktur. Kütüphaneler, sınıflardan ayrı ayrı varlıklardır. Tek bir kütüphanenin birden fazla sınıf, üst düzey değişken ve mantıksal olarak bir araya gelmiş fonksiyonları içermesi oldukça iyi bir özellik.💯

Dart’daki gizlilik, sınıf düzeyinde değil kütüphane düzeyinde çalışır, bu C++ ’da yapabileceğiniz gibi “friend” sınıflarını tanımlamanın bir yoludur. Aynı kütüphanede tanımlanan her sınıf, birbirlerinin özel üyelerine erişebilir, ancak bu kütüphanenin dışındaki kodlara erişemez.

Classes and Mixins Design

Dart’ın, başlangıçta diğer sınıflarla mix edilmesi amaçlanan bir sınıfı bildirmek için ayrı bir sözdizimi yoktu. Bunun yerine, belirli kısıtlamaları karşılayan herhangi bir sınıf (varsayılan olmayan yapıcı metodu olmayacak, superclass olmayacak, vb.) bir mixin olarak kullanılabilir. Bu kafa karıştırıcıydı çünkü class’ın yazarı onun karıştırılmasını istememiş olabilirdi.

Dart 2.1.0 açıkça bir mixin bildirmek için bir anahtar kelime ekledi, mixin…

✍️Mixin olarak kullanmak istediğiniz yeni bir tür tanımlarken bu sözdizimini kullanın.

Yalnızca statik üyeler içeren bir sınıfı tanımlamaktan kaçının❗️

Java ve C # ‘da, her tanım bir sınıf içinde olmalıdır, bu nedenle yalnızca statik üyeleri için bir yer olarak görülen “classlar” oldukça yaygındır. Diğer sınıflar ad alanları(namespaces) olarak kullanılır, bir grup üyenin birbirleriyle ilişkilendirmeleri veya isim çakışmalarını önlemek için paylaşılan bir prefix vermenin bir yoludur.

Dart’ın top level fonksiyonları, değişkenleri ve sabitleri vardır, bu nedenle yalnızca bir şey tanımlamak için bir sınıfa ihtiyacınız yoktur. İstediğiniz bir ad alanı ise, kütüphane daha uygun olur. Kütüphaneler prefix ’leri import etmeyi ve birleştiricileri göster / gizle’yi destekler.

Bir fonksiyon veya değişken mantıksal olarak bir sınıfa bağlı değilse, onu en üst düzeye yerleştirin. Ad çakışmaları konusunda endişeleriniz varsa, ona daha kesin bir ad verin veya önekle içe aktarılabilen ayrı bir kütüphaneye taşıyın.

Constructors Design

Tüm alanların final olduğu bir sınıfınız varsa ve constructor onları başlatmaktan başka bir şey yapmıyorsa, constructor’ı const yapabilirsiniz.

Bu kullanım, kullanıcıların sabitinizin gerekli olduğu (diğer büyük sabitler içinde, switch case durumları, varsayılan parametre değerleri vb.) yerlerde sınıfınızın örneklerini oluşturmasına olanak tanır.

Ancak, const bir constructor yapmanın API’nızı herkese açık hale getireceğini unutmayın. Daha sonra constructor’ınızı non-constolarak değiştirirseniz, bu ifadeleri çağıran diğer kullanıcıları da etkileyecektir.

Members Design

✍️Özelliklere kavramsal olarak erişen operation’lar için getter kullanın.

Bir üyenin bir metoda karşı ne zaman alıcı olması gerektiğine karar vermek, iyi API tasarımının zorlu, ince ama önemli bir parçasıdır.

Dart’da tüm noktalı isimler hesaplama yapabilen üye çağrılarıdır. Alanlar özeldir; uygulaması dil tarafından sağlanan alıcılardır. Diğer bir deyişle, Dart’ta getter’lar “özellikle yavaş alanlar” değildir; alanlar “özellikle hızlı alıcılar” dır.

✍️Özellikleri kavramsal olarak değiştiren operation’lar için setter kullanın.

Bir setter’ın bir methoda karşı karar vermesi, bir getter ile bir methoda karar vermekle aynıdır. Her iki durumda da, işlem “alan benzeri” olmalıdır.

Bir setter için “alan benzeri” ne anlama gelir?

  • Operation, tek bir argüman alır ve bir sonuç değeri üretmezse
  • Operation, nesnede bir durum değiştiriyorsa
  • Operation idempotenttir. (Aynı setter’ı aynı değerle iki kez çağırmak, çağırana bağlı olarak ikinci kez hiçbir şey yapmamalıdır. Belki de önbellek geçersiz kılma veya oturum açma işleminiz devam ediyor olabilir. )

Types Design

Type annotation’ları(ek açıklamalar), “static types” dendiğinde düşündüğünüz şeydir. Bir değişkene, parametreye, alana veya dönüş türüne annotation ekleyebilirsiniz.

Aşağıdaki örnekte bool ve String type annotation’larıdır. Kodun statik declarative yapısını kapatırlar ve runtime’da çalıştırılmazlar.

bool isEmpty(String parameter) {   
bool result = parameter.isEmpty;
return result;
}

Kapsamlı çağırma hazır koleksiyon bilgisi, genel bir sınıfın constructor’ına çağrı veya genel bir methodun çağrılmasıdır. Sonraki örnekte, num ve int genel çağrılar üzerinde type argümanlarıdır. Her ne kadar type olsalar da, çalışma zamanında yeniden bir araya getirilen ve çağrışmaya geçen birinci sınıf varlıklardır.

var lists = <num>[1, 2]; 
lists.addAll(List<num>.filled(3, 4));
lists.cast<int>();

✍️Herhangi bir nesneye izin verildiğini belirtmek içinObject yerine dynamic ile açıklama ekleyin.

Bazı işlemler olası herhangi bir nesneyle çalışır. Örneğin, bir log() method toString()ile herhangi bir nesneyi alıp çağırabilir.

Dart'daki iki type tüm değerlere izin verir: Object ve dynamic. Ancak, farklı şeyler taşırlar. Tüm nesnelere izin verdiğinizi belirtmek istiyorsanız, Java veya C # 'da kullandığınız gibi Object kullanın.

dynamic kullanmak daha karmaşık bir sinyal gönderir. Bu Dart'ın type sisteminin, izin verilen type kümesini temsil edecek kadar sofistike olmadığı veya değerlerin birlikte çalışabilirliğin ya da static type sisteminin dışından geldiği veya programdaki o noktada runtime dinamizmini açık olarak istediğiniz anlamına gelir.

✍️ Herhangi bir değer üretmeyen asenkron üyelerin geri dönüş değeri olarak Future<void> kullanın.

Bir değer döndürmeyen eşzamanlı bir fonksiyonunuz olduğunda dönüş type’ı olarak void kullanırsınız. Future<void>ise değer üretmeyen ancak çağıranın beklemesi gerekebilecek bir method için asenkron olarak buna eşdeğerdir.

Yararlı bir değer döndürmeyen ve hiçbir çağrının asenkron işi beklemesine veya asenkron bir hatayı işlemesine gerek duymadığında asenkron fonksiyonlar için dönüş type olarakvoidkullanın.

✍️Fonksiyon tipi ek açıklamalarında imzaları kullanın.

Tanımlayıcı fonksiyon, tek başına herhangi bir dönüş tipi veya parametre imzası olmayan özel bir fonksiyon tipini ifade eder. Bu tip, dynamic kullanmaktan daha yararlıdır. Açıklama ekleyecekseniz, fonksiyonun parametrelerini ve dönüş tipini içeren tam bir fonksiyon türünü tercih edin.

bool isValid(String value, bool Function(String) test) => ...
bool isValid(String value, Function test) => ...

Tanımlanan yerel değişkenlere ek açıklama eklemekten kaçının!

Yerel değişkenler, özellikle fonksiyonların küçük olduğu modern kodda kapsamları da oldukça küçüktür. Tipi atlamak, okuyucunun dikkatini daha önemli olan değişkenin adına ve başlangıç ​​değerine odaklar.

İlk kullanım ikinci kullanıma göre daha sağlıklı ve yaygın olandır.

Parameters Design

✍️Aralığı kabul etmek için kapsamlı başlangıç ve özel bitiş parametreleri kullanın.

Bir kullanıcının integer bir diziden, bir dizi eleman veya item seçmesine izin veren bir method veya fonksiyon tanımlıyorsanız, ilk ögeyi ve son ögenin dizininden bir daha büyük olan bir bitiş dizinini ifade eden bir başlangıç ​​dizini alın.

[0, 1, 2, 3].sublist(1, 3)    // [1, 2]'abcd'.substring(1, 3)        // 'bc'

Özel bir “argüman yok” değerini kabul eden zorunlu parametrelerden kaçının!

Kullanıcı mantıksal olarak bir parametreyi atlıyorsa, parametreyi nullveya boş bir string bırakmaya zorlamak yerine parametreyi isteğe bağlı yaparak bunları atlamasını sağlayın.

var rest = string.substring(start);var rest = string.substring(start, null);

Equality Design

✍️" == " Operatörünüzün matematiksel eşitlik kurallarına uymasını sağlayın.

Bir denklik ilişkisi şöyle olmalıdır:

  • Reflexive: a == a her zaman truedönmelidir.
  • Symmetric: a == b ile b == a aynı şeyi döndürmelidir.
  • Transitive: Eğer a == b ve b == c de truedönüyorsa, a == c olmalıdır.

Kullanıcılar ve == kullanılan kodlar tüm bu yasalara uyulmasını bekler. Sınıfınız bu kurallara uymuyorsa o zaman ‘==’ ifade etmeye çalıştığınız işlem için doğru isim değil demektir.

Effective Dart: Design oldukça kapsamlı bir konu ama elimden geldiğince özet şeklinde vermeye çalıştım, zaman ayırıp okuyan herkese teşekkür ederim😇

Bir sonraki yazıda görüşmek üzere, hoşçakalıın…

--

--