지난 몇 년 동안, 우리는 많은 Dart 코드를 작성했고 어떤것이 제대로 작동하는지 아닌지에 대해 많은 것을 배웠습니다. 우리가 공유하는 정보와 함께라면 일관성있고 견고하며 빠른 코드 작성이 가능할 것입니다. 두가지 중심이 되는 주제가 있습니다.
-
일관되게 작성하세요. 포매팅(foramtting)과 케이싱(casing)과 같은 것들에 대해, 어느 것이 더 나은지에 대한 논쟁은 주관적이며 해결이 불가능합니다. 우리가 알고 있는 것은 일관성이 객관적으로 도움이 된다는 것입니다.
두 코드 피스가 다르게 느껴진다면, 그 둘은 각기 다른 의미를 가져야 합니다. 어떤 코드가 눈길을 끈다면, 눈길을 끌만한 이유가 있어야 합니다.
-
간단하게 작성하세요. Dart는 개발자에게 친숙하도록 디자인 되었습니다. 그렇기 때문에 C, Java, JavaScript와 같은 다른 언어들의 statements나 expressions를 물려받았습니다. 하지만 우리는 그런 언어들을 개선할 여지가 많이 있기 때문에 Dart를 개발하였습니다. 문자열 보간 부터 initializing formals까지, 개발자들의 의도를 간단하고 쉽게 표현하기 위해 Dart는 다양한 기능들을 가지고 있습니다.
코드를 표현할 다양한 방법이 있다면, 일반적으로 간결한 것을 선택하는 것이 좋을 것입니다. 그것이 모든 프로그램을 한 줄로 표현하도록 code golf하라는 의미는 아닙니다. Dart를 사용하는 개발자들의 목표는 불필요하게 빽빽하지 않고 실속있는 코드를 작성하는 것입니다.
가이드
가이드를 쉽게 이해하도록 하기 위해 우리는 가이드라인을 몇 가지 페이지로 구분하였습니다:
-
Style Guide – 이 가이드에서는 코드를 배치하고 구성하는 규칙에 대해 정의하고, dart format에서 다루지 않는 것들을 다룹니다. Style guide에서는
camelCase
,using_underscores
와 같이 식별자들이 어떻게 포맷되는지 구체적으로 알려줍니다. -
Documentation Guide – 이 가이드에서는 주석에 대한 모든 것을 알려줍니다. 문서 주석 부터, 일반적인 코드에 대한 주석을 모두 다룹니다.
-
Usage Guide – 이 가이드 에서는 기능을 구현하기 위해 언어의 기능을 최대한 활용하는 방법에 대해 알려줍니다. Statement나 expression을 여기에서 다룹니다.
-
Design Guide – 이 가이드는 가장 소프트한 파트이지만, 가장 넓은 범위를 다룹니다. 라이브러리를 위한 일관되고 사용 가능한 API를 설계하는 법을 알려줍니다. Type signature나 declaration에 대해 궁금하다면, 이 가이드를 살펴보세요.
모든 가이드의 링크는 다음을 참고하세요 요약.
가이드 읽는 법
각 가이드는 여러 개의 섹션으로 구분됩니다. 섹션은 몇 가지의 가이드라인을 가지고 있습니다. 개별 가이드라인은 아래의 단어 중 하나를 포함합니다:
-
하십시오 해당 가이드라인들은 항상 지켜져야 하는 관례을 말합니다. 이 관례들을 어길 타당한 이유가 거의 없을 겁니다.
-
하지 마십시오 대부분의 상황에서 좋지 않는 아이디어에 대한 것으로, 위와 반대되는 상황에 대한 가이드라인입니다. Dart의 역사적 부담이 적기 때문에, 우리는 다른 언어들 만큼 이러한 지침이 많지 않기를 바랍니다.
-
지향 하십시오 따르는 것이 바람직한 관례에 대한 가이드라인 입니다. 그러나, 이 지침을 따르지 않아야 하는 상황이 존재할 것입니다. 이 가이드라인을 지키지 않는 것의 의미를 충분히 이해했는지 확인하세요.
-
피하십시오 “지향”해야하는 가이드 라인과 반대의 상황을 말합니다: 하지 말아야 할 것들이지만, 드물게 합리적인 이유가 있을 수 있는 것들을 말합니다.
-
고려 하십시오 상황, 전례 그리고 자신의 개인적인 선호도로 인해 따를 수도, 그러지 않을 수도 있는 관례들에 대한 가이드라인입니다.
몇몇 가이드라인들은 위의 규칙들이 적용되지 않는 예외들을 포함하고 있습니다. 그런 예외들이 있다면, 완전하지 않으므로 여러 케이스들에 대해 본인의 판단이 필요합니다.
위의 이야기는 당신이 이 가이드라인들을 지키지 않으면 큰일 날 것처럼 느껴질 수 있지만, 그렇게 극단적이진 않습니다. 위의 가이드라인들의 대부분은 상식적인 것이고 우리는 모두 합리적인 사람들입니다. 우리의 목표는 훌륭하고 가독성이 좋으며 지속가능한 코드를 작성하는 것입니다.
Dart analyzer는 linter를 제공하여 이런 가이드라인들을 지키는 훌륭하고 일관적인 코드를 작성 할 수 있게 해줍니다. 가이드라인들 따르도록 해주는 linter 규칙이 존재한다면, 해당 가이드라인이 규칙과 링크해 줄 것입니다. 그 링크들은 다음과 같은 형식을 따릅니다:
Linter rule: unnecessary_getters_setters
Linter 사용법을 배우고 싶다면, Linter 규칙 활성화하기와 linter 규칙들의 목록을 참고하세요.
용어 해설
가이드라인을 간단하게 유지하기 위해, 몇 가지 약칭를 사용하여 Dart의 구조를 나타냅니다.
-
라이브러리 멤버는 getter, setter나 함수 같은 최상위 필드 입니다. 기본적으로, 타입이 아닌 최상위 수준의 모든 항목들을 말합니다.
-
클래스 멤버는 클래스에 선언되어 있는 생성자, 필드, getter, setter 함수 그리고 연산자들을 의미합니다. 클래스 멤버들은 instance 혹은 static일 수 있고, 추상적이거나 구체적일 수도 있습니다.
-
멤버는 라이브러리 또는 클래스 멤버를 의미합니다.
-
변수는 일반적으로 최상위 변수, 파라미터, 지역 변수를 의미합니다. Static 또는 instance 필드를 포함하지 않습니다.
-
타입은 class, typedef, 또는 enum과 같이 이름이 있는 타입 선언을 의미합니다.
-
프로퍼티는 최상위 변수, getter (클래스 내부 또는 최상위에 위치, instance 또는 static), setter (getter와 동일), 또는 필드 (instance 또는 static)를 의미합니다. 거의 모든 “필드 같이” 명명된 구문들을 나타냅니다.
요약
스타일
식별자
UpperCamelCase
를 사용하여 타입을 명명하십시오.UpperCamelCase
를 사용하여 확장을 명명하십시오.lowercase_with_underscores
를 사용하여 라이브러리, 패키지, 디렉토리 그리고 소스 파일을 명명하십시오.lowercase_with_underscores
를 사용하여 import 프리픽스를 명명하십시오.- 다른 식별자들은
lowerCamelCase
를 사용하여 명명하십시오. - 상수는
lowerCamelCase
를 사용하여 명명하는 것을 지향하십시오. - 두 글자보다 긴 두문자어(acronym)와 약어(abbreviation)는 대문자로 명명하십시오.
- 사용하지 않는 콜백 파라미터를
_
,__
로 나타내는 것을 지향하십시오. - Private이 아닌 식별자의 앞에 언더스코어(_)를 사용하지 마십시오.
- 프리픽스 문자를 사용하지 마십시오.
- 명시적으로 라이브러리를 명명하지마십시오.
순서
- “dart:” import를 다른 import 보다 먼저 작성하십시오.
- “package:” import을 relative import 보다 먼저 작성하십시오.
- Export를 모든 import 이후에 분리된 섹션에서 작성하십시오.
- 섹션을 알파벳 순서로 정렬하십시오.
포매팅
문서화
주석
문서 주석
- 멤버와 타입에 대한 문서 주석을 작성 할 때
///
를 사용하십시오. - 공개 API를 위한 문서 주석 작성을 지향하십시오.
- 라이브러리 수준의 문서 주석 작성을 고려하십시오.
- 비공개 API를 위한 문서 주석 작성을 고려하십시오.
- 한 줄 요약과 함께 문서 주석을 시작하십시오.
- 문서 주석의 문단에서 첫 번째 줄을 분리시키십시오.
- 주변 문맥과 중복되는 문장을 피하십시오.
- 함수 혹은 메서드 주석을 삼인칭 동사로 시작하는 것을 지향하십시오.
- Non-boolean 변수나 프로퍼티에 대한 주석은 명사구로 시작하는 것을 지향하십시오.
- Boolean 변수나 프로퍼티에 대한 주석은 명사구 또는 동명사구가 따라오는 “Whether”와 함께 사용하십시오.
- 프로퍼티의 getter와 setter에 대해 모두 문서를 작성하지마십시오.
- 라이브러리나 타입에 대한 주석은 명사구로 시작하는 것을 지향하십시오.
- 문서 주석에 샘플 코드 추가를 고려하십시오.
- In-scope 식별자를 참조하기 위해 대괄호를 사용하십시오.
- 예외, 반환 값, 파라미터를 설명 할 때 산문체를 사용하십시오.
- 메타데이터 어노테이션(metadata annotation) 선언 전에 주석을 넣으십시오.
마크다운
- 과도한 마크다운 사용을 피하십시오.
- 포매팅(formatting)에 HTML을 사용하는 것을 피하십시오.
- 코드 블럭을 넣을 때 백틱 펜스(backtick fences) 사용을 지향하십시오.
글쓰기
사용법
라이브러리
part of
명령어에 문자열을 사용하십시오.- 다른 패키지의
src
디렉토리에 있는 라이브러리를 import하지 마십시오. - Import 경로를 lib 안팎으로 지정하지 마십시오.
- 상대 경로를 사용하여 import하는 것을 지향하십시오.
Null
- 변수를 명시적으로
null
로 초기화하지 마십시오. - 디폴트 값으로
null
을 명시적으로 사용하지 마십시오. - 항등 연산자에
true
또는false
을 사용하지 마십시오. - 초기화 여부를 확인해야하는 변수를
late
로 선언하는 것을 피하십시오. - 타입 프로모션을 활성화하고 싶다면, nullable 필드를 로컬 변수에 할당하는 것을 고려하십시오.
문자열
- 인접 문자열을 사용하여 문자열 리터럴을 연결하십시오.
- 문자열과 값들을 합성하고 싶다면, 보간(interporation) 사용을 지향하십시오.
- 보간에 불필요한 중괄호 사용을 피하십시오.
컬렉션
- 가능하다면 컬렉션 리터럴을 사용하십시오.
- 컬렉션이 비었는지 확인할 때
.length
를 사용하지 마십시오. Iterable.forEach()
를 함수 리터럴과 함께 사용하는 것을 피하십시오.- 결과 값의 타입을 바꾸려는 것이 아니라면,
List.from()
을 사용하지 마십시오. - 컬렉션을 타입으로 필터하고 싶다면,
whereType()
을 사용하십시오. - 코드의 주변에서
cast()
와 같은 역할을 하는 연산이 있다면,cast()
를 사용하지 마십시오. cast()
사용을 피하십시오.
함수
- 함수의 이름과 함수를 바인드 하려면 함수 선언식을 사용하세요.
- Tear-off 대신 람다를 사용하지 마십시오.
- Named 매개변수와 해당 매개변수의 디폴트 값을 분리시키고 싶다면,
=
을 사용하십시오.
변수
멤버
- 필드에 불필요한 getter와 setter를 생성하지 마십시오.
- 읽기 전용인 프로퍼티를 생성 할 때,
final
키워드 사용을 지향하십시오. - 간단한 멤버를 선언 할 때,
=>
사용을 고려하십시오. - Named 생성자를 리디렉션하고 충돌을 피하는 경우를 제외하고
this.
를 사용하지 마십시오. - 가능하다면 필드의 선언과 함께 초기화를 진행하십시오.
생성자
- 가능하다면 initializing formal을 사용하십시오.
- 생성자 initializer list가 변수의 값을 초기화해준다면,
late
를 사용하지 마십시오. - 비어있는 생성자 바디에
{}
대신에;
을 사용하십시오. new
를 사용하지 마십시오.const
를 불필요하게 사용하지 마십시오.
에러 핸들링
on
절 없이 에러를 캐치하는 것을 피하십시오.on
절로 캐치되지 않은 에러를 버리지 마십시오.- 프로그래밍 오류를 나타내는 경우에만
Error
를 구현하는 예외를 throw 하십시오. Error
또는 이를 구현하는 타입을 명시적으로 캐치하지 마십시오.- 캐치된 예외를 rethrow 하고 싶다면,
rethrow
를 사용하십시오.
비동기
디자인
명명법
- 일관적인 용어를 사용하십시오.
- 약어 사용을 피하십시오.
- 서술하는 명사를 마지막에 두는 것을 지향하십시오.
- 문장 처럼 코드를 읽을 수 있게 작성하는 것을 고려하십시오.
- Non-boolean 프로퍼티나 변수에 명사구 사용을 지향하십시오.
- Boolean 프로퍼티나 변수에 비명령형 동사구 사용을 지향하십시오.
- Named boolean 파라미터에 동사를 생략하는 것을 고려하십시오.
- Boolean 프로퍼티나 변수에 “긍정적인” 이름의 사용을 지향하십시오.
- 주된 목적이 사이드 이펙트인 함수 또는 메서드에는 명령형 동사구 사용을 지향하십시오.
- 함수 또는 메서드의 주된 목적이 값을 반환하는 것이라면, 비명령형 동사구 사용을 지향하십시오.
- 함수나 메서드가 수행하는 작업에 집중하고 싶다면, 명령형 동사구 사용을 고려하십시오.
- 메서드의 이름을
get
로 시작하는 것을 피하십시오. - 객체의 상태를 새로운 객체로 복사하는 메서드는
to___()
로 명명하는 것을 지향하십시오. - 원본 객체가 지원하는 다른 표현을 반환하는 메서드의 경우
as___()
로 명명하는 것을 지향하십시오. - 함수나 메서드의 이름에 파라미터를 묘사하는 것을 피하십시오.
- 타입 파라미터를 명명할 때, 기존에 존재하는 니모닉 컨벤션(mnemonic conventions)을 따르십시오.
라이브러리
클래스와 mixins
- 간단한 함수가 대신할 수 있는, 단 하나의 멤버를 가지는 추상 클래스를 피하십시오.
- 오직 static 멤버들로만 이루어진 클래스를 피하십시오.
- 서브 클래스로 의도되지 않은 클래스를 확장하는 것을 피하십시오.
- 클래스가 확장되는 것을 지원하는 경우 문서를 작성하십시오.
- 인터페이스로 의도되지 않은 클래스를 implement하는 것을 피하십시오.
- 클래스가 인터페이스로 사용되는 것을 지원하는 경우 문서를 작성하십시오.
- Minxin 타입을 정의하고 싶다면,
mixin
을 사용하십시오. - Mixin으로 의도되지 않은 타입을 믹싱(mixing)하는 것을 피하십시오.
생성자
멤버
- 필드와 최상위 변수들을
final
로 선언하는 것을 지향하십시오. - 개념적으로 프로퍼티에 접근하는 연산자의 경우 getter를 사용하십시오.
- 개념적으로 프토퍼티를 변경하는 연산자의 경우 setter를 사용하십시오.
- 대응되는 getter 없이 setter를 정의하지 마십시오.
- 가짜 오버로딩에 런타임 타입 테스트를 사용하는 것을 피하십시오.
- Initializers가 없는 public
late final
필드 정의를 피하십시오. - Nullable
Future
,Stream
, 그리고 컬렉션 타입의 반환을 피하십시오. - 원활한 인터페이스의 활성화를 위해 메서드에서
this
의 반환을 피하십시오.
타입
- Initializer가 초기화하지 않는 변수들은 타입 어노테이트하십시오.
- 필드와 최상위 변수들의 타입이 애매하다면, 타입 어노테이트하십시오.
- 초기화된 지역 변수에 대해 중복된 타입 어노테이트를 하지 마십시오.
- 함수의 선언에서 반환 값의 타입을 어노테이트 하십시오.
- 함수의 선언에서 파라미터의 타입을 어노테이트 하십시오.
- 함수 표현식에서 추론된 파라미터 타입을 어노테이트 하지 마십시오.
- Initializing formal을 타입 어노테이트 하지 마십시오.
- 타입이 추론되지 않은 generic invocation에 대해 타입 인자를 작성하십시오.
- 타입이 추론된 generic invocation에 대해 타입 인자를 작성 하지 마십시오.
- 불완전한 generic 타입의 작성을 피하십시오.
- 타입 추론이 실패하도록 두기 보다
dynamic
으로 어노테이트 하십시오. - 함수 타입 어노테이션에서 시그니쳐 사용을 지향하십시오.
- Setter의 반환 타입을 특정하지 마십시오.
- 오래된 typedef의 문법을 사용하지 마십시오.
- typedef 보다 인라인 함수 타입의 사용을 지향하십시오.
- 파라미터에 함수 타입 문법의 사용을 지향하십시오.
- 정적인 타입 체킹을 비활성화하고 싶은 것이 아니라면,
dynamic
의 사용을 피하십시오. - 값을 생성하지 않는 비동기 멤버의 반환 값으로
Future<void>
를 사용하십시오. FutureOr<T>
를 반환 타입으로 사용하는 것을 피하십시오.
파라미터
- Positional boolean 파라미터의 사용을 피하십시오.
- 이전의 파라미터들을 생략하고 싶다면, optional positional 파라미터의 사용을 피하십시오.
- “no argument” 값을 전달받는 필수 파라미터를 피하십시오.
- 파라미터가 범위를 전달받을 때, 첫 값을 포함하며 시작하고 마지막 값은 포함하지 마십시오.
동등성