Flutter Linter Kuralları Bölüm 1: Hata Kuralları 💫 🌌 ✨
Tags: flutter, dart, linter, flutterdev
Published: 2022-02-19 22:17:10

_“Where there are rules, there’s law“_

## Linting Nedir?

Linting , programatik, stilistik hatalar ve biçimlendirilmemiş kod için kaynak kodunu kontrol etme işlemidir. Mantıksal hatalar, kullanılmayan değişkenler, boş if-else ifadeleri gibi kodlama sırasında yapılan bazı yaygın ve yaygın olmayan hataları belirlemede yardımcı olur.

Linting'in amacı, kod kalitesini iyileştirebilecek gizli hatayı veya uygulamayı çalıştırırken sorunlara neden olabilecek hataları belirleme konusunda gerçek zamanlı öneriler almaktır. 

**Linter kuralları 3 gruba ayrılır. Bunlar:**
1. Hatalar: Olası kodlama hataları.
2. Stil
3. Bar: Pub paketi kurulumuyla ilgili olası sorunlar .

Her kuralın ayrıca bir olgunluk düzeyi vardır.

**Kuralların olgunluk düzeyleri de 3'e ayrılır. Bunlar:**

**Kararlı-Stable**
Bu kuralların kullanımı güvenlidir ve Dart dilinin en son sürümleriyle işlevsel oldukları doğrulanmıştır. Deneysel olarak işaretlenmedikçe veya kullanımdan kaldırılmadıkça tüm kurallar kararlı olarak kabul edilir.

**Deneysel-Experimental**
Bu kurallar halen değerlendirme aşamasındadır ve hiçbir zaman istikrara kavuşturulamayabilir. Bunları dikkatli kullanmanız gerekir.

**Kullanımdan kaldırıldı-Deprecated**
Bu kurallar artık kullanım için önerilmemektedir ve gelecekteki bir linter yayınında kaldırılabilir.


## Hata kuralları

Hata kuralları, kodunuzdaki olası hataları ve diğer hataları tanımlar.

**Always_use_package_imports**

lib/. içindeki dosyalar için relative imports'dan (göreli içe aktarmalardan) kaçının.

Aynı üyeyi iki farklı şekilde içe aktarmaktan kaçınmak için  lib/dizindeki dosyalar için mutlak içe aktarmayı (absolute imports) kullandığınızdan emin olun.

Doğru kullanım:

```
import 'package:foo/bar.dart';
import 'package:foo/baz.dart';
import 'package:foo/src/baz.dart';
```

Yanlış kullanım:

```
import 'baz.dart';
import 'src/bag.dart'
import '../lib/baz.dart';
```

**avoid_dynamic_calls**

"dynamic" bir hedefte method çağrılarından veya property erişimlerinden kaçının.

Açıkça veya dolaylı olarak statik olarak yazılan dynamic bir obje üzerindeki method çağrılarından veya özellik(propertie) erişimlerinden kaçının. Dinamik çağrılar, her çalışma zamanı ortamında ve derleyicide biraz farklı olarak ele alınır, ancak çoğu üretim modu (ve hatta bazı geliştirme modları), dinamik çağrılarla ilişkili hem derleme boyutu hem de çalışma zamanı performans sorunlarına sahiptir.

Ek olarak, "dynamic" yazılan hedefler, çoğu statik analizi devre dışı bırakır.

Yanlış kullanım:

```
void explicitDynamicType(dynamic object) {
  print(object.foo());
}

void implicitDynamicType(object) {
  print(object.foo());
}

abstract class SomeWrapper {
  T doSomething<T>();
}

void inferredDynamicType(SomeWrapper wrapper) {
  var object = wrapper.doSomething();
  print(object.foo());
}

void callDynamic(dynamic function) {
  function();
}

void functionType(Function function) {
  function();
}
```

Doğru kullanım:

```
void explicitType(Fooable object) {
  object.foo();
}

void castedType(dynamic object) {
  (object as Fooable).foo();
}

abstract class SomeWrapper {
  T doSomething<T>();
}

void inferredType(SomeWrapper wrapper) {
  var object = wrapper.doSomething<Fooable>();
  object.foo();
}

void functionTypeWithParameters(Function() function) {
  function();
}
```

**avoid_empty_else**

Boş else ifadelerinden kaçının.

Yanlış kullanım:

```
if (x > y)
  print("1");
else ;
  print("2");
```


**avoid_print**

Üretim kodunda "print" çağrılarından kaçının.

```
void f(int x) {
  print('debug: $x');
  ...
}
```

**avoid_returning_null_for_future**

Future için null döndürmekten kaçının.


**avoid_slow_async_io**

Yavaş asenkron `dart:io` yöntemlerinden kaçının.

Aşağıdaki asenkron I/O methodlarını kullanmaktan kaçının, çünkü bunlar senkron emsallerine göre çok daha yavaştır.

• Directory.exists
• Directory.stat
• File.lastModified
• File.exists
• File.stat
• FileSystemEntity.isDirectory
• FileSystemEntity.isFile
• FileSystemEntity.isLink
• FileSystemEntity.type

Yanlış kullanım:

```
import 'dart:io';

Future<Null> someFunction() async {
  var file = File('/path/to/my/file');
  var now = DateTime.now();
  if ((await file.lastModified()).isBefore(now)) print('before'); // LINT
}
```

Doğru kullanım:

```
import 'dart:io';

Future<Null> someFunction() async {
  var file = File('/path/to/my/file');
  var now = DateTime.now();
  if (file.lastModifiedSync().isBefore(now)) print('before'); // OK
}
```

**avoid_type_to_string**

Sonuçlar küçültülebileceğinden üretim kodunda ".toString()" kullanmaktan kaçının.


Yanlış kullanım:

```
void bar(Object other) {
  if (other.runtimeType.toString() == 'Bar') {
    doThing();
  }
}

Object baz(Thing myThing) {
  return getThingFromDatabase(key: myThing.runtimeType.toString());
}
```


Doğru kullanım:

```
void bar(Object other) {
  if (other is Bar) {
    doThing();
  }
}

class Thing {
  String get thingTypeKey => ...
}

Object baz(Thing myThing) {
  return getThingFromDatabase(key: myThing.thingTypeKey);
}
```


**avoid_types_as_parameter_names**

Tipleri paremetre adı olarak kullanmaktan kaçının.

Yanlış kullanım:  `m(f(int));`
Doğru kullanım:   `m(f(int v));`


**avoid_web_libraries_in_flutter**

Flutter web plugin paketleri dışında yalnızca web kitaplıkları kullanmaktan kaçının.

Web eklentileri olmayan Flutter paketlerinde web kitaplıkları, dart:html, dart:js ve dart:js_util kullanmaktan kaçının. Bu kitaplıklar bir web context dışında desteklenmez; bunlara bağlı olan işlevsellik Flutter mobil runtime da başarısız olur ve Flutter web'de kullanılmaları genellikle önerilmez.

Web kitaplığı erişimine şu durumlarda izin verilir:

• web'i desteklenen bir context olarak bildiren plugin paketleri

aksi takdirde, dart:html, dart:js ve dart:js_util'in import edilmesine izin verilmez.

**cancel_subscriptions**

dart.async.StreamSubscription örneklerini iptal edin.

StreamSubscription örneklerinin (instance) iptal edilmesi, bellek sızıntılarını ve beklenmeyen davranışları (unexpected behavior) önler.

Yanlış Kullanım:

```
class A {
  StreamSubscription _subscriptionA; // LINT
  void init(Stream stream) {
    _subscriptionA = stream.listen((_) {});
  }
}
```

Yanlış kullanım:

```
void someFunction() {
  StreamSubscription _subscriptionF; // LINT
}
```


Doğru kullanım:

```
class B {
  StreamSubscription _subscriptionB; // OK
  void init(Stream stream) {
    _subscriptionB = stream.listen((_) {});
  }

  void dispose(filename) {
    _subscriptionB.cancel();
  }
}
```

Doğru kullanım:

```
void someFunctionOK() {
  StreamSubscription _subscriptionB; // OK
  _subscriptionB.cancel();
}
```

**close_sinks**

Sink örneklerini kapatmak, bellek sızıntılarını(memory leaks) ve beklenmeyen davranışları(unexpected behavior) önler.


Yanlış kullanım:

```
class A {
  IOSink _sinkA;
  void init(filename) {
    _sinkA = File(filename).openWrite(); // LINT
  }
}
```


Yanlış kullanım:

```
void someFunction() {
  IOSink _sinkF; // LINT
}
```

Doğru kullanım:

```
class B {
  IOSink _sinkB;
  void init(filename) {
    _sinkB = File(filename).openWrite(); // OK
  }

  void dispose(filename) {
    _sinkB.close();
  }
}
```



Doğru kullanım:

```
void someFunctionOK() {
  IOSink _sinkFOK; // OK
  _sinkFOK.close();
}
```


**comment_references**

Yalnızca belge yorumlarındaki kapsam tanımlayıcılarına (scope identifiers) başvurun.

Değişken, method veya köşeli parantez içinde adlar yazarsanız, dartdoc adı arar ve belgelerine bağlanır. Tüm bunların işe yaraması için, parantez içine alınmış belgelerdeki tüm tanımlayıcıların kapsam içinde olduğundan emin olun.


Örneğin:

Doğru kullanım:

```
/// [a] veya [b]'den büyük olanı döndürün.
int max_int(int a, int b) { ... }
```
Öte yandan, outOfScopeId'in kapsam dışı olduğunu varsayarsak:

Yanlış kullanım:

```
/// [value], [outOfScopeId] değerinden büyükse true değerini döndürün.
bool isOutOfRange(int value) { ... }
```


Köşeli parantez yorum biçiminin, açıklamaların oldukça doğal bir biçim kullanarak bildirimlere başvurmasına izin verecek şekilde tasarlandığını, ancak keyfi ifadelere izin vermediğini unutmayın. Özellikle, köşeli parantez içindeki kod referansları, aşağıdakilerden herhangi birini içerebilir:

• Tanımlayıcının comment kapsamındaki herhangi bir tanımlayıcı(identifier) olduğu tek bir tanımlayıcı (doküman yorumlarında kapsamda ne olduğuna ilişkin spesifikasyona bakın),

• ilk tanımlayıcının kapsamdaki bir sınıfın adı ve ikincisinin sınıfta bildirilen bir üyenin adı olduğu bir nokta ile ayrılmış iki tanımlayıcı,

• tek bir tanımlayıcı ve ardından bir parantez çifti, burada tanımlayıcı kapsamdaki bir sınıfın adıdır (sınıfın adsız constructor'ına atıfta bulunmak için kullanılır),

• veya bir nokta ile ayrılmış ve ardından bir çift parantez ile ayrılmış iki tanımlayıcı; burada ilk tanımlayıcı kapsamdaki bir sınıfın adı ve ikincisi adlandırılmış bir constructor'ın adıdır (kesinlikle gerekli değildir, ancak tutarlılık için izin verilir).


**control_flow_in_finally**

Son bloklarda kontrol akışı kullanmaktan kaçının.
Son bloklarda kontrol akışının kullanılması, kaçınılmaz olarak, hata ayıklaması zor olan beklenmeyen davranışlara neden olacaktır.


Doğru kullanım:

```
class Ok {
  double compliantMethod() {
    var i = 5;
    try {
      i = 1 / 0;
    } catch (e) {
      print(e); // OK
    }
    return i;
  }
}
```

Yanlış kullanım:

```
class BadReturn {
  double nonCompliantMethod() {
    try {
      return 1 / 0;
    } catch (e) {
      print(e);
    } finally {
      return 1.0; // LINT
    }
  }
}
```

Yanlış kullanım:

```
class BadContinue {
  double nonCompliantMethod() {
    for (var o in [1, 2]) {
      try {
        print(o / 0);
      } catch (e) {
        print(e);
      } finally {
        continue; // LINT
      }
    }
    return 1.0;
  }
}
```

Yanlış kullanım:

```
class BadBreak {
  double nonCompliantMethod() {
    for (var o in [1, 2]) {
      try {
        print(o / 0);
      } catch (e) {
        print(e);
      } finally {
        break; // LINT
      }
    }
    return 1.0;
  }
}
```

**diagnostic_describe_all_properties**
Debug methodlarında tüm public property'leri implemente edin.

Diagnosticable'ın uygulayıcıları, çalışma zamanında hata ayıklanabilirliğini iyileştirmek için bir debugFillProperties(...) veya debugDescribeChildren(...) methodu tüm public özelliklere başvurmalıdır.


Yanlış kullanım:

```
class Absorber extends Widget {
  bool get absorbing => _absorbing;
  bool _absorbing;
  bool get ignoringSemantics => _ignoringSemantics;
  bool _ignoringSemantics;
  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<bool>('absorbing', absorbing));
    // Missing reference to ignoringSemantics
  }
}  
```

Doğru kullanım:

```
class Absorber extends Widget {
  bool get absorbing => _absorbing;
  bool _absorbing;
  bool get ignoringSemantics => _ignoringSemantics;
  bool _ignoringSemantics;
  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<bool>('absorbing', absorbing));
    properties.add(DiagnosticsProperty<bool>('ignoringSemantics', ignoringSemantics));
  }
}  
```

**empty_statements**

Boş ifadelerden kaçının.

Boş ifadeler genellikle bir hatayı gösterir.

Örneğin,


Yanlış kullanım:

```
if (complicated.expression.foo());
  bar();
```

Dart formatı ile biçimlendirilen hata bariz hale gelir:

```
if (complicated.expression.foo()) ;
bar();

```

Doğru kullanım:

```
if (complicated.expression.foo())
  bar();
```

**invariant_booleans**

Koşullu ifadeler koşulsuz olarak true veya false olarak değerlendirilmemelidir.

_Bu kural şu anda deneyseldir. (experimental)_

Derleme zamanında çıkarılabilecek koşulları test etmeyin veya aynı koşulu iki kez test etmeyin.

False'dan başka bir şey olamayacak bir koşul kullanan koşullu ifadeler, kod bloklarını işlevsiz hale getirme etkisine sahiptir. Koşul, true dışında hiçbir şeyi değerlendiremezse, koşullu ifade tamamen gereksizdir ve kodu daha az okunabilir hale getirir. Kodun programcının amacı ile uyuşmaması oldukça olasıdır. Ya koşul kaldırılmalı ya da her zaman true veya false olarak değerlendirilmemesi ve gereksiz testler yapmaması için güncellenmelidir.

Yanlış kullanım:

```
// foo aynı ifadede bara hem eşitdir hem de eşit olamaz
if(foo == bar && something && foo != bar) {...}
```

Yanlış kullanım:

```
void compute(int foo) {
  if (foo == 4) {
    doSomething();
   // bu noktada foo'nun 4'e eşit olduğunu biliyoruz, bu nedenle sonraki koşul her zaman false
    if (foo > 4) {...}
    ...
  }
  ...
}
```

Yanlış kullanım:

```
void compute(bool foo) {
  if (foo) {
    return;
  }
  doSomething();
  // burada foo'nun değeri her zaman false'dır
  if (foo){...}
  ...
}
```

Doğru kullanım:

```
void nestedOK() {
  if (foo == bar) {
    foo = baz;
    if (foo != bar) {...}
  }
}
```


Doğru kullanım:

```
void nestedOk2() {
  if (foo == bar) {
    return;
  }

  foo = baz;
  if (foo == bar) {...} // OK
}
```


Doğru kullanım:

```
void nestedOk5() {
  if (foo != null) {
    if (bar != null) {
      return;
    }
  }

  if (bar != null) {...} // OK
}
```


**iterable_contains_unrelated_type**

İlişkisiz(unrelated) türlerin referanslarıyla Iterable.contains çağrısı.


Yanlış kullanım:

```
void someFunction() {
  var list = <int>[];
  if (list.contains('1')) print('someFunction'); // LINT
}
```


Yanlış kullanım:

```
void someFunction3() {
  List<int> list = <int>[];
  if (list.contains('1')) print('someFunction3'); // LINT
}
```


Yanlış kullanım:

```
void someFunction8() {
  List<DerivedClass2> list = <DerivedClass2>[];
  DerivedClass3 instance;
  if (list.contains(instance)) print('someFunction8'); // LINT
}
```


Yanlış kullanım:

```
abstract class SomeIterable<E> implements Iterable<E> {}

abstract class MyClass implements SomeIterable<int> {
  bool badMethod(String thing) => this.contains(thing); // LINT
}
```


Doğru kullanım:

```
void someFunction10() {
  var list = [];
  if (list.contains(1)) print('someFunction10'); // OK
}
```

Doğru kullanım:

```
void someFunction1() {
  var list = <int>[];
  if (list.contains(1)) print('someFunction1'); // OK
}
```

Doğru kullanım:

```
void someFunction4() {
  List<int> list = <int>[];
  if (list.contains(1)) print('someFunction4'); // OK
}
```

Doğru kullanım:

```
void someFunction5() {
  List<ClassBase> list = <ClassBase>[];
  DerivedClass1 instance;
  if (list.contains(instance)) print('someFunction5'); // OK
}

abstract class ClassBase {}

class DerivedClass1 extends ClassBase {}
```


Doğru kullanım:

```
void someFunction6() {
  List<Mixin> list = <Mixin>[];
  DerivedClass2 instance;
  if (list.contains(instance)) print('someFunction6'); // OK
}

abstract class ClassBase {}

abstract class Mixin {}

class DerivedClass2 extends ClassBase with Mixin {}
```


Doğru kullanım:

```
void someFunction7() {
  List<Mixin> list = <Mixin>[];
  DerivedClass3 instance;
  if (list.contains(instance)) print('someFunction7'); // OK
}

abstract class ClassBase {}

abstract class Mixin {}

class DerivedClass3 extends ClassBase implements Mixin {}
```


**list_remove_unrelated_type**

İlişkisiz türlerin referanslarıyla `remove` çağrısı.


Parametre türünden farklı türde bir örnekle(instance) listede remove yöntemini çağırmayın.

Bunu yapmak, liste elemanları üzerinde == öğesini çağırır ve büyük olasılıkla false döndürür.

Yanlış kullanım:

```
void someFunction() {
  var list = <int>[];
  if (list.remove('1')) print('someFunction'); // LINT
}
```


Yanlış kullanım:

```
void someFunction3() {
  List<int> list = <int>[];
  if (list.remove('1')) print('someFunction3'); // LINT
}
```


Yanlış kullanım:

```
void someFunction8() {
  List<DerivedClass2> list = <DerivedClass2>[];
  DerivedClass3 instance;
  if (list.remove(instance)) print('someFunction8'); // LINT
}
```


Yanlış kullanım:

```
abstract class SomeList<E> implements List<E> {}

abstract class MyClass implements SomeList<int> {
  bool badMethod(String thing) => this.remove(thing); // LINT
}
```


Doğru kullanım:

```
void someFunction10() {
  var list = [];
  if (list.remove(1)) print('someFunction10'); // OK
}
```

Doğru kullanım:

```
void someFunction1() {
  var list = <int>[];
  if (list.remove(1)) print('someFunction1'); // OK
}
```


Doğru kullanım:

```
void someFunction4() {
  List<int> list = <int>[];
  if (list.remove(1)) print('someFunction4'); // OK
}
```


Doğru kullanım:

```
void someFunction5() {
  List<ClassBase> list = <ClassBase>[];
  DerivedClass1 instance;
  if (list.remove(instance)) print('someFunction5'); // OK
}

abstract class ClassBase {}

class DerivedClass1 extends ClassBase {}
```


Doğru kullanım:

```
void someFunction6() {
  List<Mixin> list = <Mixin>[];
  DerivedClass2 instance;
  if (list.remove(instance)) print('someFunction6'); // OK
}

abstract class ClassBase {}

abstract class Mixin {}

class DerivedClass2 extends ClassBase with Mixin {}
```


Doğru kullanım:

```
void someFunction7() {
  List<Mixin> list = <Mixin>[];
  DerivedClass3 instance;
  if (list.remove(instance)) print('someFunction7'); // OK
}

abstract class ClassBase {}

abstract class Mixin {}

class DerivedClass3 extends ClassBase implements Mixin {}
```


**literal_only_boolean_expressions**
Boole ifadesi yalnızca literal'lerden oluşur.

False'dan başka bir şey olamayacak bir koşulu kullanan koşullu ifadeler (conditional statements), kod bloklarını işlevsiz hale getirme etkisine sahiptir. Koşul, true dışında hiçbir şeyi değerlendiremezse, koşullu ifade tamamen gereksizdir ve kodu daha az okunabilir hale getirir. Kodun programcının amacı ile uyuşmaması oldukça olasıdır. Ya koşul kaldırılmalı ya da her zaman true veya false olarak değerlendirilmemesi için güncellenmelidir.


Yanlış kullanım:

```
void bad() {
  if (true) {} // LINT
}
```


Yanlış kullanım:

```
void bad() {
  if (true && 1 != 0) {} // LINT
}
```

Yanlış kullanım:

```
void bad() {
  if (1 != 0 && true) {} // LINT
}
```



Yanlış kullanım:

```
void bad() {
  if (1 < 0 && true) {} // LINT
}
```


Yanlış kullanım:

```
void bad() {
  if (true && false) {} // LINT
}
```


Yanlış kullanım:

```
void bad() {
  if (1 != 0) {} // LINT
}
```

Yanlış kullanım:

```
void bad() {
  if (true && 1 != 0 || 3 < 4) {} // LINT
}
```

Yanlış kullanım:

```
void bad() {
  if (1 != 0 || 3 < 4 && true) {} // LINT
}
```

NOT: (;;) eşdeğerine tercih edilen while (true) { } deyimi için bir istisna yapılmıştır.

Doğru kullanım:
```
void good() {
  while (true) {
    // Do stuff.
  }
}
```

**no_adjacent_strings_in_list**

Listede bitişik stringleri kullanmayın.

Doğru kullanım:

```
List<String> list = <String>[
  'a' +
  'b',
  'c',
];
```

Yanlış kullanım:

```
List<String> list = <String>[
  'a'
  'b',
  'c',
];
```

**no_duplicate_case_values**

Aynı değerde birden fazla case kullanmayın.

Bu genellikle bir yazım hatası veya constant'ın değiştirilmiş değeridir.


Doğru kullanım:

```
const int A = 1;
switch (v) {
  case A:
  case 2:
}
```

Yanlış kullanım:

```
const int A = 1;
switch (v) {
  case 1:
  case 2:
  case A:
  case 2:
}
```


**no_logic_in_create_state**

"createState" içine herhangi bir mantık koymayın.

createState() uygulamaları, bir state nesnesinin yeni bir örneğini (instance) döndürmeli ve başka bir şey yapmamalıdır. Widget alanı aracılığıyla durum erişimi tercih edildiğinden, verilerin özel constructor parametreleri kullanılarak state nesnelerine iletilmesinden de kaçınılmalıdır ve , state constructor'ına hiçbir argüman iletilmemelidir.

Yanlış kullanım:

```
MyState global;

class MyStateful extends StatefulWidget {
  @override
  MyState createState() {
    global = MyState();
    return global;
  } 
}
```

```
class MyStateful extends StatefulWidget {
  @override
  MyState createState() => MyState()..field = 42;
}
```

```
class MyStateful extends StatefulWidget {
  @override
  MyState createState() => MyState(42);
}
```



Doğru kullanım:

```
class MyStateful extends StatefulWidget {
  @override
  MyState createState() {
    return MyState();
  }
}
```

**prefer_relative_imports**

lib/ altındaki dosyalar için relative import'u tercih edin.

Relative(göreceli) ve absolute(mutlak) içe aktarmaların her ikisini birden kullanırken aynı üyenin iki farklı şekilde içe aktarıldığı bir durumla karşılaşılması mümkündür. 
Bundan kaçınmak için lib/ klasöründeki dosyalar için sürekli olarak relative importları (göreceli içe aktarmaları) kullandığınızdan emin olun.


Doğru kullanım: `import 'bar.dart';`

Yanlış kullanım: `import 'package:my_package/bar.dart';`


**prefer_void_to_null**

Void'in çalışacağı yerlerde Null türünü kullanmayın.


Yanlış kullanım:

```
Null f() {}
Future<Null> f() {}
Stream<Null> f() {}
f(Null x) {}
```


Doğru kullanım:

```
void f() {}
Future<void> f() {}
Stream<void> f() {}
f(void x) {}
```

Bazı istisnalar, özel işlev türlerinin formüle edilmesini içerir:

`Null Function(Null, Null);`

ve herhangi bir map veya list türü için read-only konumlara geçmek için güvenli olan empty literal'ler (değişmezler) yapmak için:


```
<Null>[];
<int, Null>{};
```

**test_types_in_equals**

Türlerin test edilmemesi, sınıfınızın tüketicileri için beklenmeyen null pointer (boş işaretçi) istisnalarına (exceptions) neden olabilir.

Doğru kullanım:

```
class Field {
}

class Good {
  final Field someField;

  Good(this.someField);

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) {
      return true;
    }
    return other is Good &&
        this.someField == other.someField;
  }

  @override
  int get hashCode {
    return someField.hashCode;
  }
}
```


Yanlış kullanım:

```
class Field {
}

class Bad {
  final Field someField;

  Bad(this.someField);

  @override
  bool operator ==(Object other) {
    Bad otherBad = other as Bad; // LINT
    bool areEqual = otherBad != null && otherBad.someField == someField;
    return areEqual;
  }

  @override
  int get hashCode {
    return someField.hashCode;
  }
}
```


**throw_in_finally**

Son bloklarda istisna(exceptions) atmaktan kaçının.

Nihai bloklarda istisnalar atmak, hata ayıklaması zor olan beklenmeyen davranışlara(unexpected behavior) neden olacaktır.

Doğru kullanım:

```
class Ok {
  double compliantMethod() {
    var i = 5;
    try {
      i = 1 / 0;
    } catch (e) {
      print(e); // OK
    }
    return i;
  }
}
```



Yanlış kullanım:

```
class BadThrow {
  double nonCompliantMethod() {
    try {
      print('hello world! ${1 / 0}');
    } catch (e) {
      print(e);
    } finally {
      throw 'Find the hidden error :P'; // LINT
    }
  }
}
```


**unnecessary_statements**

Gereksiz ifadeler kullanmaktan kaçının.

Açık bir etkisi olmayan ifadeler genellikle gereksizdir veya bölünmelidir.

Örneğin,

Yanlış kullanım:
```
myvar;
list.clear;
1 + 2;
methodOne() + methodTwo();
foo ? bar : baz;
```

Bunun gibi kodlar eksik bir düşünceyi gösterir ve bir hatadır.


Doğru kullanım:

```
some.method();
const SomeClass();
methodOne();
methodTwo();
foo ? bar() : baz();
return myvar;
```


**unrelated_type_equality_checks**

Eşitlik operatörünü ilişkisiz türlerin referanslarını karşılaştırırken kullanmayın.

Hiçbirinin diğerinin alt türü olmadığı bir türün referanslarını karşılaştırmak, büyük olasılıkla false döndürür ve programcının amacını yansıtmayabilir.

package:fixnum'daki Int64 ve Int32, int2in sağ tarafta olması koşuluyla int ile karşılaştırmaya izin verir. Lint, buna özel bir durum olarak izin verir.

Yanlış kullanım:

```
void someFunction() {
  var x = '1';
  if (x == 1) print('someFunction'); // LINT
}
```


Yanlış kullanım:

```
void someFunction1() {
  String x = '1';
  if (x == 1) print('someFunction1'); // LINT
}
```

Yanlış kullanım:

```
void someFunction13(DerivedClass2 instance) {
  var other = DerivedClass3();

  if (other == instance) print('someFunction13'); // LINT
}

class ClassBase {}

class DerivedClass1 extends ClassBase {}

abstract class Mixin {}

class DerivedClass2 extends ClassBase with Mixin {}

class DerivedClass3 extends ClassBase implements Mixin {}
```


Doğru kullanım:

```
void someFunction2() {
  var x = '1';
  var y = '2';
  if (x == y) print(someFunction2); // OK
}
```


Doğru kullanım:

```
void someFunction3() {
  for (var i = 0; i < 10; i++) {
    if (i == 0) print(someFunction3); // OK
  }
}
```


Doğru kullanım:

```
void someFunction4() {
  var x = '1';
  if (x == null) print(someFunction4); // OK
}
```


Doğru kullanım:

```
void someFunction7() {
  List someList;

  if (someList.length == 0) print('someFunction7'); // OK
}
```

Doğru kullanım:

```
void someFunction8(ClassBase instance) {
  DerivedClass1 other;

  if (other == instance) print('someFunction8'); // OK
}
```

Doğru kullanım:

```
void someFunction10(unknown) {
  var what = unknown - 1;
  for (var index = 0; index < unknown; index++) {
    if (what == index) print('someFunction10'); // OK
  }
}
```

Doğru kullanım:

```
void someFunction11(Mixin instance) {
  var other = DerivedClass2();

  if (other == instance) print('someFunction11'); // OK
  if (other != instance) print('!someFunction11'); // OK
}

class ClassBase {}

abstract class Mixin {}

class DerivedClass2 extends ClassBase with Mixin {}
```

**unsafe_html**

Güvenli olmayan HTML API'lerinden kaçının.


• Bir AnchorElement öğesinin href alanına doğrudan atama
• Bir EmbedElement, IFrameElement, ImageElement veya ScriptElement • öğesinin src alanına doğrudan atama
• Bir IFrameElement öğesinin srcdoc alanına doğrudan atama
• Element'in createFragment yöntemini çağırma
• Window open methodunu çağırma
• Element'in setInnerHtml yöntemini çağırma
• Element.html constructor'ını çağırma
• DocumentFragment.html constructor'ını çağırma


Yanlış kullanım:

```
var script = ScriptElement()..src = 'foo.js';
```

**use_build_context_synchronously**

Asenkron boşluklarda BuildContexts kullanmayın.

BuildContext'i daha sonra kullanmak üzere saklamak, teşhis edilmesi zor çökmelere yol açabilir. Asenkron boşluklar örtük olarak BuildContext'i depolar ve kod yazarken gözden kaçırılır.

Bir StatefulWidget'tan bir BuildContext kullanıldığında, asenkron bir boşluktan sonra mounted property kontrol edilmelidir.

Doğru kullanım:

```
void onButtonTapped(BuildContext context) {
  Navigator.of(context).pop();
}
```

Yanlış kullanım:

```
void onButtonTapped(BuildContext context) async {
  await Future.delayed(const Duration(seconds: 1));
  Navigator.of(context).pop();
}
```


Doğru kullanım:

```
class _MyWidgetState extends State<MyWidget> {
  ...

  void onButtonTapped() async {
    await Future.delayed(const Duration(seconds: 1));

    if (!mounted) return;
    Navigator.of(context).pop();
  }
}
```

**use_key_in_widget_constructors**

Widget constructor'larında key kullanın.

Public widget'lar oluştururken key kullanmak iyi bir yoldur.

Yanlış kullanım:
`class MyPublicWidget extends StatelessWidget {}`

Doğru kullanım:

```
class MyPublicWidget extends StatelessWidget {
  MyPublicWidget({Key? key}) : super(key: key);
}
```

**valid_regexps**

Geçerli bir regular expression syntax'ı kullanın.

Regular expression (normal ifade örnekleri) oluştururken geçerli regular expression söz dizimini kullanın.

Geçersiz syntax ile oluşturulan düzenli ifadeler, çalışma zamanında bir FormatException oluşturacaktır, bu nedenle bunlardan kaçınılmalıdır.

Yanlış kullanım: `print(RegExp(r'(').hasMatch('foo()'));`

Doğru kullanım: `print(RegExp(r'\(').hasMatch('foo()'));`


Bu yazıda Linter kurallarının ilk grubu olan error kurallarını inceledik. Bir sonraki yazıda stil kurallarını inceleyeceğiz.

References:
https://medium.com/podiihq/setting-up-lint-rules-in-dart-flutter-1ebbed0418a6
https://medium.flutterdevs.com/lint-rules-in-flutter-efbcf05daeb5
https://dart.dev/tools/linter-rules#directives_ordering
https://dart-lang.github.io/linter/lints/
https://sourcelevel.io/blog/what-is-a-linter-and-why-your-team-should-use-it