Effective Dart 읽어보기
Dart 공식 문서의 Overview ~ Usage를 내맘대로 요약해봄.
Design 파트는 Dart에 국한된 내용이 아니라 '클린 코드'로 다루어지는 범용적인 원칙과 겹치는 내용이 많음.
왜 Flutter는 Dart를 사용하는가? - Flutter의 특징과 장점이 정리된 글
Dart의 두가지 핵심 컨셉
- Be consistent (일관성 있게) : 코드 컨벤션에 대한 논쟁은 주관적이고 정답이 없지만, 일관성을 유지하는건 객관적으로 도움이 된다.
- Be brief (짧게) : Dart는 C, Java, JavaScript 등의 언어와 비슷한 구문이 많다. 저 언어들을 이미 알고있다면 친숙한 형태로 보이지만, 더 쉽고 간결하게 사용할 수 있도록 설계되었다.
주요 용어
- library member : top-level field, getter, setter, or function
- class member : constructor, field, getter, setter, function, or 클래스 내부에 선언된 연산자
- member : library member or a class member.
- variable : top-level variables, parameters, and local variables. static or instance fields를 포함하지 않는다
- type : 타입을 정의할때 사용한다 (class, typedef, enum)
- property : top-level variable, getter (inside a class or at the top level, instance or static), setter (same), or field (instance or static).
Code Style
클래스, enum, typedef, type 파라미터는 UpperCamelCase 사용
class SliderMenu { ... }
class HttpRequest { ... }
typedef Predicate<T> = bool Function(T value);
libraries, packages, directories, source file은 스네이크_케이스 사용
library peg_parser.source_scanner;
import 'file_system.dart';
import 'slider_menu.dart';
그 외 변수, 상수명엔 lowerCaseCamel 사용 (처음엔 자바처럼 상수명을 대문자로만 작성했지만, 가독성 문제로 컨벤션을 변경)
const pi = 3.14;
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');
dangling else를 사용하지 말것 (body가 한줄이어도 괄호를 붙여주기)
if (isWeekDay) {
print('Bike to work!');
} else {
print('Go dancing or read a book!');
}
예외적으로, else문이 없고 if문이 간결할 경우 괄호를 생략할 수 있다.
if (arg == null) return defaultValue;
그 외에도...
- private이 아닌 변수명의 앞에 _를 사용하지 말것
- prefix letter를 사용하지 말것
- 한 라인이 80글자를 넘어가는 것을 피할 것
Usage
null을 명시적으로 할당하지 말 것. nullable 타입은 따로 null로 초기화하지 않아도 null이 암시적 할당이 되기 때문에 코드로 직접 작성하지 않아도 된다.
// O
void error([String? message]) {
stderr.write(message ?? '\n');
}
// X
void error([String? message] = null) {
stderr.write(message ?? '\n');
}
nullable 타입을 boolean으로 변환할 때 ==
대신 ??
를 사용할 것
// O
if (optionalThing?.isEnabled ?? true) {
print('Have enabled thing or nothing.');
}
// X
if (optionalThing?.isEnabled != true) {
print('Have enabled thing or nothing.');
}
- 둘다 실행해보면 동일한 결과가 나오지만, ??를 권장하는 이유
- ?? 연산자는 연산식이 null과 관련되었음을 명확하게 나타낸다
- == true 같은 구문은 불필요한 연산자로 여겨져서(redundant) 지울 수 있는 실수를 유발한다.
Dart는 List, Set, Map 컬렉션을 생성할 때 이름을 생략할 수 있도록 지원한다. 가급적 Collection literals를 사용할 것
// good
var points = <Point>[];
var addresses = <String, Address>{};
var counts = <int>{};
// avoid
var address = Map<String, Address>();
함수에 이름을 선언해야 할 경우 람다식 변수를 만드는 대신 함수를 직접 선언할 것
// good
void main() {
void localFunction() {
...
}
}
// avoid
void main() {
var localFunction = () {
...
};
}
Dart는 (레거시 때문에) 파라미터에 기본값을 부여할 수 있도록 :
, =
연산자를 둘 다 지원하지만 일관성을 위해 가급적 =를 사용하는 것을 권장한다.
void insert(Object item, {int at = 0}) { ... }
변수를 선언할 때 var
, final
을 사용하는 규칙의 일관성을 지킬 것. 널리 사용되는 두가지 규칙은 다음과 같다.
두가지 규칙 중 하나를 취사 선택했다면 프로젝트 전체에 일관성을 유지하자.
- final은 불변하는 지역 변수 선언 시 사용, var은 재할당 가능한 지역변수 선언 시 사용
- var을 모든 지역 변수에 붙이고, 재할당은 절대 불가능하다. final은 field랑 top-level 변수 선언에만 사용 가능
그 외에도...
- 초기화 여부를 체크해야하는 변수면 late(지연 초기화를 위한 키워드)를 사용하지 말 것
- nullable field를 local 변수로 사용해야 할 경우 ! 연산자를 붙이는 대신 지역 변수로 값을 복사해서 사용하는 것을 고려할 것
- 긴 문자열을 사용해 줄바꿈이 필요할 경우 + 연산자를 사용하지 말고 나란히 문자열을 나열할 것
- 문자열에서 ${ }를 사용할 때 괄호를 생략할 수 있는 상황이면 생략할 것
- 컬렉션이 비었는지 확인할 때 .length 대신 .isEmpty를 사용할 것
- 컬렉션의 forEach, from, cast 함수는 가급적 사용하지 말 것
- 컬렉션에 타입을 기준으로한 필터링이 필요할 경우 whereType 함수를 사용할 것
- final은 가급적 읽기 전용 property를 만드는데 사용하자
- member를 단순하게 표현하기 위해
=>
를 사용하자. (=> 뒤로 읽기 어려운 코드가 오지 않게할 것) - this는 생성자를 초기화할 때 필드와 파라미터의 이름이 동일할 경우 구분하는 용도로만(shadowing) 사용하고, 그 외엔 가급적 사용하지 말자
- 가급적 선언과 동시에 필드를 초기화하자
- 생성자 바디가 비어있을 경우 {} 대신 ;를 사용하자.
- 불필요한 new, const 키워드를 사용하지 말 것
- 불필요하게 async 키워드를 사용하지 말 것
'if (study) > 잡다구리' 카테고리의 다른 글
bitbucket에서 two-step verification 설정하기 (0) | 2021.05.26 |
---|---|
Mac에서 Flutter 시작하기 (개발 환경 만들기) (0) | 2021.05.20 |
블로그 위젯 수리 완료 (0) | 2021.05.16 |