Effective Dart란?
"Effective Dart"는 Dart 프로그래밍 언어에 관한 베스트 프랙티스와 권장 사항을 제공하는 가이드다. 각각의 언어에 특화된 권장 사항, 팁, 트릭 등을 제공하여 개발자들이 더욱 효과적이고 깔끔한 코드를 작성할 수 있도록 도와준다.
요점
지난 몇 년 동안의 Dart 코딩 경험을 바탕으로 두 가지 중요한 주제를 강조한다.
첫째, 코드는 일관성 있게 작성되어야 한다.
코드의 스타일이나 형태가 다르다면 그것은 의미 있는 차이 때문이어야 한다.
둘째, Dart는 다양한 기능을 통해 코드를 더 간결하게 작성할 수 있도록 디자인되었기 때문에, 가능한 한 간결하게 코드를 작성하라.
가이드라인
Dart에 대한 지침을 4개의 주제로 분류한다:
1. 스타일 가이드는 코드의 레이아웃과 식별자 형식에 관한 규칙을 제공한다.
2. 문서화 가이드는 주석 작성에 관한 지침을 다룬다.
3. 사용법 가이드는 Dart 언어의 기능을 어떻게 효과적으로 사용할지에 대한 방법을 가르친다.
4. 디자인 가이드는 라이브러리 API 설계에 대한 권장사항을 제시한다.
해당 내용은 별도로 다룰 것이다.
가이드라인 읽는 법
가이드는 DO, DON'T, PREFER, AVOID, CONSIDER 등의 단어로 시작하는 여러 지침으로 구성되어 있으며, 각 지침은 특정 코딩 스타일이나 관행을 제안한다. Dart 분석기는 이러한 지침을 준수하는 데 도움을 주는 linter를 제공한다.'
DO - 100% 해라
DON'T - 100% 하지 마라
PREFER - 하는 게 낫다(100%는 아님)
AVOID - 하지 않는 게 낫다(100%는 아님)
CONSIDER - 한 번 고려해 보쇼
용어집
라이브러리 멤버는 최상위 필드, 게터, 세터, 또는 함수를 의미합니다. 기본적으로 타입이 아닌 최상위에 있는 모든 것을 말합니다.
클래스 멤버는 클래스 내부에 선언된 생성자, 필드, 게터, 세터, 함수, 또는 연산자를 의미합니다. 클래스 멤버는 인스턴스 또는 정적, 추상 또는 구체적일 수 있습니다.
멤버는 라이브러리 멤버 또는 클래스 멤버 중 하나를 의미합니다.
일반적으로 사용되는 변수는 최상위 변수, 매개변수, 지역 변수를 의미합니다. 정적 또는 인스턴스 필드는 포함하지 않습니다.
타입은 이름이 지정된 타입 선언을 의미합니다: 클래스, typedef, 또는 enum.
프로퍼티는 최상위 변수, 게터(클래스 내부 또는 최상위, 인스턴스 또는 정적), 세터(동일), 필드(인스턴스 또는 정적)를 의미합니다. 대략 “필드와 유사한” 이름이 지정된 구성 요소를 말합니다.
가이드라인 요약
스타일, 문서화, 사용법, 디자인 가이드라인은 별도 문서로 자세히 설명되고 있다.
그런데 내용이 짧지 않다.
페이지 하나하나를 뜯어 보는 건 여기서 크게 중요하지 않다 생각해 요약을 제공한다.
스타일 가이드라인
- 식별자
- 타입의 이름은 UpperCamelCase를 사용하여 지정하세요.
- 확장의 이름은 UpperCamelCase를 사용하여 지정하세요.
- 패키지, 디렉터리, 소스 파일의 이름은 lowercase_with_underscores를 사용하여 지정하세요.
- import 접두사의 이름은 lowercase_with_underscores를 사용하여 지정하세요.
- 다른 식별자의 이름은 lowerCamelCase를 사용하여 지정하세요.
- 상수 이름은 lowerCamelCase를 사용하는 것이 좋습니다.
- 약어나 두 글자보다 긴 약어는 단어처럼 대문자로 시작하세요.
- 사용되지 않는 콜백 매개변수의 이름은 _, __ 등을 사용하는 것이 좋습니다.
- 비공개가 아닌 식별자에는 밑줄(_)을 사용하지 마세요.
- 접두사 문자를 사용하지 마세요.
- 라이브러리의 이름을 명시적으로 지정하지 마세요.
- 순서
- 다른 import보다 dart: import를 먼저 배치하세요.
- 상대적인 import보다 package: import를 먼저 배치하세요.
- 모든 import 이후에는 별도의 섹션에서 export를 지정하세요.
- 섹션은 알파벳순으로 정렬하세요.
- 포맷팅
- 코드 포맷에는 dart format를 사용하세요.
- 포맷터에 더 적합하게 코드를 변경하는 것을 고려하세요.
- 80자보다 긴 줄은 피하세요.
- 모든 흐름 제어 문에 중괄호를 사용하세요.
문서화 가이드라인
- 주석
- 주석은 문장처럼 포맷하세요.
...아니, 문장처럼 포맷하는 게 뭔데?
// Not if anything comes before it.
if (_chunks.isNotEmpty) return false;
첫 단어는 대소문자 구분이 필요한 식별자가 아닌 경우 대문자로 시작하세요. 마침표(또는 "!" 또는 "?")로 끝내세요. 이것은 모든 주석에 대해 동일하게 적용됩니다: doc 주석, 인라인 주석, 심지어 TODOs에서도 마찬가지입니다. 문장의 일부라도 마찬가지입니다.
상세 내용이랑 요약이랑 다른 것도 어이 없는데
주석을
// 나는 지금 허니콤보가 먹고.
// 싶다. 왜냐하면.
// 나는 허니콤보를 좋아하기 때문이다.
이렇게 쓰라는 것도 어이 없다.
그러나 이게 가이드라인이니까...
나는 지금 여유가 없어서 Effective Dart를 그냥 훑고 가지만
나중에 시간이 되면 다른 사람들이랑 꼭 스터디를 하고 싶다.
- Doc 주석
- 멤버와 타입을 문서화하기 위해 /// doc 주석을 사용하세요.
- 공용 API에 대한 doc 주석을 작성하는 것이 좋습니다.
- 라이브러리 수준의 doc 주석을 작성하는 것을 고려하세요.
- 비공개 API에 대한 doc 주석을 작성하는 것을 고려하세요.
- doc 주석은 한 문장 요약으로 시작하세요.
- doc 주석의 첫 문장을 별도의 단락으로 분리하세요.
- 주변 컨텍스트와의 중복을 피하세요.
- 함수나 메소드 주석은 제3인칭 동사로 시작하는 것이 좋습니다.
- 부울이 아닌 변수나 속성 주석은 명사 구로 시작하는 것이 좋습니다.
- 부울 변수나 속성 주석은 "Whether" 다음에 명사나 동명사 구로 시작하는 것이 좋습니다.
- 속성의 getter와 setter 모두에 대해 문서화를 작성하지 마세요.
- 라이브러리나 타입 주석은 명사 구로 시작하는 것이 좋습니다.
- doc 주석에 코드 예제를 포함하는 것을 고려하세요.
- doc 주석에서 범위 내 식별자를 참조하기 위해 대괄호를 사용하세요.
- 매개변수, 반환 값, 예외를 설명하기 위해 문장을 사용하세요.
- 메타데이터 주석 앞에 doc 주석을 배치하세요.
- 마크다운
- 마크다운을 과도하게 사용하는 것을 피하세요.
- 포맷팅을 위해 HTML을 사용하는 것을 피하세요.
- 코드 블록에 대해 백틱 기호를 사용하는 것이 좋습니다.
- 작성법
- 간결하게 작성하는 것이 좋습니다.
- 약어와 두문자어를 사용하지 않는 것이 좋습니다, 단, 분명한 경우는 제외합니다.
- 멤버의 인스턴스를 참조하기 위해 "the" 대신 "this"를 사용하는 것이 좋습니다.
사용법 가이드라인
- 라이브러리
- 문자열을 'part of' 지시문에 사용하세요.
- 다른 패키지의 src 디렉토리 내부에 있는 라이브러리를 가져오지 마세요.
- import 경로를 통해 lib 내부나 외부로 접근하지 마세요.
- 상대 import 경로를 사용하는 것이 좋습니다.
- Null
- 변수를 명시적으로 null로 초기화하지 마세요.
- 명시적인 기본값으로 null을 사용하지 마세요.
- 동등 연산에서 true나 false를 사용하지 마세요.
- 초기화되었는지 확인해야 할 경우 'late' 변수를 사용하지 마세요.
- 타입 프로모션을 활성화하기 위해 nullable 필드를 로컬 변수에 할당하는 것을 고려하세요.
- 문자열
- 문자열 리터럴을 연결하기 위해 인접 문자열을 사용하세요.
- 문자열과 값을 구성하기 위해 보간을 사용하는 것이 좋습니다.
- 필요하지 않은 경우 보간에서 중괄호를 사용하지 마세요.
- 콜렉션
- 가능한 경우 컬렉션 리터럴을 사용하세요.
- 컬렉션이 비어 있는지 확인하기 위해 .length를 사용하지 마세요.
- 함수 리터럴로 Iterable.forEach()를 사용하지 마세요.
- 결과의 타입을 변경하려는 의도가 없는 경우 List.from()을 사용하지 마세요.
- 타입별로 컬렉션을 필터링하기 위해 whereType()을 사용하세요.
- 인접한 작업이 있을 때 cast()를 사용하지 마세요.
- 가능한한 cast() 사용을 피하세요.
- 함수
- 함수를 이름에 연결하기 위해 함수 선언을 사용하세요.
- tear-off로 충분할 때 람다를 생성하지 마세요.
- 명명된 매개변수와 기본값을 구분하기 위해 =를 사용하세요.
- 변수
- 지역 변수에 대해 var와 final을 일관되게 사용하세요.
- 계산할 수 있는 것을 저장하지 마세요.
- 멤버
- 필요 없는 경우 필드를 게터와 세터로 감싸지 마세요.
- 읽기 전용 속성을 만들기 위해 final 필드를 사용하는 것이 좋습니다.
- 간단한 멤버에 대해 =>를 사용하는 것을 고려하세요.
- 명명된 생성자로 리디렉션을 사용하거나 섀도잉을 피하기 위해 제외한 경우를 제외하고 this.를 사용하지 마세요.
- 가능한 경우 선언 시 필드를 초기화하세요.
- 생성자
- 가능한 경우 초기화 중인 형식을 사용하세요.
- 생성자 초기화 목록으로 충분할 때 'late'를 사용하지 마세요.
- 비어 있는 생성자 본문에 대해 {} 대신 ;를 사용하세요.
- new를 사용하지 마세요.
- const를 불필요하게 사용하지 마세요.
- 오류 처리
- on 절 없이 catch를 사용하지 마세요.
- on 절 없이 catch에서 오류를 무시하지 마세요.
- 프로그래밍 오류에 대해서만 Error를 구현하는 객체를 던지세요.
- Error나 그것을 구현하는 타입을 명시적으로 catch하지 마세요.
- 잡은 예외를 다시 던지려면 rethrow를 사용하세요.
10.비동기성
- 원시(raw...) futures보다 async/await를 사용하는 것이 좋습니다.
- 유용한 효과가 없는 경우 async를 사용하지 마세요.
- 스트림을 변환하기 위해 고차 함수를 사용하는 것을 고려하세요.
- Completer를 직접 사용하지 마세요.
- FutureOr< T >의 타입 인수가 Object일 수 있을 때 Future< T >를 테스트하세요.
디자인 가이드라인
- 이름
- 용어를 일관되게 사용하세요.
- 약어 사용을 피하세요.
- 가장 설명적인 명사를 마지막에 두는 것이 좋습니다.
- 코드가 문장처럼 읽히게 만드는 것을 고려하세요.
- 부울이 아닌 속성이나 변수에 명사구를 선호하세요.
- 부울 속성이나 변수에 비지령형(non-imperative...) 동사 구를 선호하세요.
- 명명된 부울 매개변수의 동사를 생략하는 것을 고려하세요.
- 부울 속성이나 변수에 "긍정적"인 이름을 선호하세요.
- 주요 목적이 부작용인 함수나 메소드에 지시형 동사구를 선호하세요.
- 값을 반환하는 것이 주요 목적인 함수나 메소드에 명사구나 비지령형 동사구를 선호하세요.
- 수행하는 작업에 주목하게 만들고 싶다면 함수나 메소드에 지시형(imperative... 왜 어떨 땐 지령형이고 어떨 땐 지시형임? ChatGPT 번역 똑바로 안 하나...) 동사구를 고려하세요.
- get으로 메소드 이름을 시작하지 마세요.
- 객체의 상태를 새 객체로 복사하는 경우 to___()로 메소드를 명명하는 것이 좋습니다.
- 원래 객체를 기반으로 다른 표현을 반환하는 경우 as___()로 메소드를 명명하는 것이 좋습니다.
- 함수나 메소드의 이름에서 매개변수를 설명하지 마세요.
- 타입 매개변수의 이름을 지정할 때 기존의 기억법 규칙을 따르세요.
- 라이브러리
- 선언을 private으로 만드는 것이 좋습니다.
- 동일한 라이브러리에서 여러 클래스를 선언하는 것을 고려하세요.
- 클래스와 믹스인
- 간단한 함수로 충분할 때 일원 멤버 추상 클래스를 정의하지 마세요.
- 오직 정적 멤버만 포함하는 클래스를 정의하지 마세요.
- 서브클래스화하기 위한 목적이 아닌 클래스를 확장하지 마세요.
- 클래스가 확장될 수 있도록 지원하는 경우 문서화하세요.
- 인터페이스가 아닌 목적으로 클래스를 구현하지 마세요.
- 클래스가 인터페이스로 사용될 수 있도록 지원하는 경우 문서화하세요.
- 믹스인 타입을 정의하기 위해 mixin을 사용하세요.
- 믹스인이 아닌 목적으로 타입을 혼합하지 마세요.
- 생성자
- 클래스가 지원하는 경우 생성자를 const로 만드는 것을 고려하세요.
- 멤버
- 필드와 최상위 변수를 final로 만드는 것을 선호하세요.
- 개념적으로 속성에 접근하는 작업에 게터를 사용하세요.
- 개념적으로 속성을 변경하는 작업에 세터를 사용하세요.
- 대응하는 게터 없이 세터를 정의하지 마세요.
- 오버로딩을 가짜로 만들기 위해 런타임 유형 테스트를 사용하지 마세요.
- 초기화자가 없는 public late final 필드를 사용하지 마세요.
- nullable Future, Stream, 및 컬렉션 타입을 반환하지 마세요.
- 유창한 인터페이스를 활성화하기 위해 메소드에서 this를 반환하지 마세요.
- 타입
- 초기화자가 없는 변수를 타입으로 주석처리하세요.
- 타입이 분명하지 않은 경우 필드와 최상위 변수를 타입으로 주석처리하세요.
- 초기화된 지역 변수에 중복 타입 주석을 사용하지 마세요.
- 함수 선언에 반환 타입을 주석처리하세요.
- 함수 선언에 매개변수 타입을 주석처리하세요.
- 함수 표현식에서 추론된 매개변수 타입에 주석을 달지 마세요.
- 초기화 중인 형식에 타입 주석을 사용하지 마세요.
- 추론되지 않은 제네릭 호출에 타입 인수를 작성하세요.
- 추론된 제네릭 호출에 타입 인수를 작성하지 마세요.
- 불완전한 제네릭 타입 작성을 피하세요.
- 추론이 실패할 경우 dynamic 대신 주석을 달아주세요.
- 함수 유형 주석에서 서명을 선호하세요.
- 세터에 반환 타입을 지정하지 마세요.
- 레거시 typedef 문법을 사용하지 마세요.
- typedef 대신 인라인 함수 타입을 선호하세요.
- 매개변수에 함수 유형 문법을 사용하는 것이 좋습니다.
- 정적 검사를 비활성화하려는 경우가 아니면 dynamic을 사용하지 마세요.
- 값을 생성하지 않는 비동기 멤버의 반환 타입으로 Future< void >를 사용하세요.
- 반환 타입으로 FutureOr< T >를 사용하지 마세요.
- 매개변수
- 위치적 부울 매개변수를 피하세요.
- 사용자가 이전 매개변수를 생략하길 원할 경우 선택적 위치 매개변수를 피하세요.
- 특별한 "인수 없음" 값을 수용하는 필수 매개변수를 피하세요.
- 범위를 받아들이기 위해 포괄적 시작 및 배타적 종료 매개변수를 사용하세요.
- 동등성
- ==를 재정의하면 hashCode도 재정의하세요.
- == 연산자가 수학적 동등성 규칙을 준수하도록 만드세요.
- 가변 클래스에 대해 사용자 정의 동등성을 정의하지 마세요.
- ==에 매개변수를 nullable로 만들지 마세요.
정리하며
지금은 진짜 급해서 대충 눈에만 바르지만
언어나 프레임워크가 제시하는 베스트 프랙티스를 잘 따를 수 있으려면
문서를 하나하나 꼼꼼히 읽어야 한다.
'주석은 문장처럼 포맷하세요' 부분을 내가 별도로 설명한 것도 이 부분을 말하고 싶어서였다.
아~ 나중에 다른 사람들이랑 플러터 스터디 하고 싶다~
수준이 비슷하다 싶으면 언제든 댓글로 스터디 같이 하자고 얘기해 주세욘!!!