缘起
代码对研发团队的重要性不言而喻。代码规范作为一个研发团队的核心基因,怎样在团队中高效传承是一个挑战。多人开发的团队中,每个人都有自己的喜好。代码管理应该避免出现“破窗效应”。一个人把代码写烂了,后面的同学照着写都烂了。正所谓,无规矩不成方圆。基础代码的表达,不追求绝对的对与错,追求的是在风格上的尽可能统一。
代码风格
驼峰
- 类、枚举、typedef和类型参数
class SliderMenu { ... }
class HttpRequest { ... }
typedef Predicate = bool Function(T value);
- 使用小写加下划线来命名库和源文件
library peg_parser.source_scanner;
import 'file_system.dart';
import 'slider_menu.dart';
不推荐如下写法:
library pegparser.SourceScanner;
import 'file-system.dart';
import 'SliderMenu.dart';
- 使用小驼峰法作为常量命名
const pi = 3.14;
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');
class Dice {
static final numberGenerator = Random();
}
- 不使用前缀字母
因为Dart可以告诉您声明的类型、范围、可变性和其他属性,所以没有理由将这些属性编码为标识符名称。
defaultTimeout
不推荐如下写法:
kDefaultTimeout
- required 关键字标识的变量请排到前面
ChangeNotifierProvider({
Key? key,
required Create create,
bool? lazy,
TransitionBuilder? builder,
Widget? child,
})
- 去除冗余new关键字
BaseOptions options = BaseOptions(
connectTimeout: 10 * 1000,
receiveTimeout: 10 * 1000,
sendTimeout: 10 * 1000,
contentType: contentType);
不推荐使用
BaseOptions options = new BaseOptions(
connectTimeout: 10 * 1000,
receiveTimeout: 10 * 1000,
sendTimeout: 10 * 1000,
contentType: contentType);
flutter布局中优先使用SizedBox而不是Container
flutter颜色定义使用8位16进制整数标识颜色值
flutter widget在构造函数中加入key参数
高效null处理
dart语法中有很多null处理的语法糖,能大幅提升判空的效率,提升代码的健壮性。这里包括?的判断,??的判空,以及null safety。需要同学更多使用这样的语法来提升效率,而不是继续使用if else的冗杂表达。
排序
import顺序按照先dart引用,再package引用,再相对引用方式分模块。每个“部分”应该用空行分隔。
- 在其他引入之前引入所需的dart库
import 'dart:async';
import 'dart:html';
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
- 第三方包的导入先于其他包
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'package:my_package/util.dart';
- 在所有导入之后,在单独的部分中指定导出
import 'src/error.dart';
import 'src/foo_bar.dart';
export 'src/error.dart';
不推荐如下写法:
import 'src/error.dart';
export 'src/error.dart';
import 'src/foo_bar.dart';
格式化
- 所有流控制结构,请使用大括号
这样做可以避免悬浮的else问题
if (isWeekDay) {
print('Bike to work!');
} else {
print('Go dancing or read a book!');
}
- 例外
一个if语句没有else子句,其中整个if语句和then主体都适合一行。在这种情况下,如果你喜欢的话,你可以去掉大括号
if (arg == null) return defaultValue;
如果流程体超出了一行需要分划请使用大括号:
if (overflowChars != other.overflowChars) {
return overflowChars < other.overflowChars;
}
不推荐如下写法:
if (overflowChars != other.overflowChars)
return overflowChars < other.overflowChars;
注释
- 要像句子一样格式化
除非是区分大小写的标识符,否则第一个单词要大写。以句号结尾(或“!”或“?”)。对于所有的注释都是如此:doc注释、内联内容,甚至TODOs。即使是一个句子片段。
greet(name) {
// Assume we have a valid name.
print('Hi, $name!');
}
不推荐如下写法:
greet(name) {
/* Assume we have a valid name. */
print('Hi, $name!');
}
可以使用块注释(/…/)临时注释掉一段代码,但是所有其他注释都应该使用//
减少歧义
- 显式变量类型
好处是直观,减少不必要的推断。最终经过激烈讨论,大家还是决定采用明确变量类型的方案。从实践角度出发,直接明确变量类型虽然从表达上略冗杂,但是歧义确实更少。
final bool autofocus;
final String obscuringCharacter;
final bool obscureText;
final bool autocorrect;
- 变量/函数状态坚持最小化表达
一个变量或者方法如果重写了,请明确加上override注解。一个变量如果确定是const变量,请加上const关键字。一个变量如果没有再被赋值,请定义成final。坚持最小化表达,有如下几点收益:
- 最小化变量状态表达能精准刻画变量状态
2.最小化变量状态是指用最严格的属性描述变量。例如一个变量从之前的多处赋值,改为一处赋值。那么变量其实自带了final的隐形属性。最小化状态表达要求必须加上final关键字,而不是推断是final。因为一旦加上final关键字,后续在赋值就会报错。这能减少不必要的理解成本,最大限度避免变量状态的隐形改变。
提升代码性能
3.增加的final const关键字能让编译器做更多优化,提升代码的整体性能。
代码质量
- 避免给void赋值 【void_checks】
- 变量比较之前先判断类型 【unrelated_type_equality_checks】
- 避免catch 空实现【empty_catches】
- 避免使用隐形类型传递 【avoid_shadowing_type_parameters】
- 避免await 非future对象 【await_only_futures】
- 集合的remove需要传递符合集合的类型的参数【list_remove_unrelated_type】