如何写好Flutter代码?

简介: 如何写好Flutter代码?

作者|意境

1.gif

本文着重分享闲鱼Flutter团队在基础代码规范方面所做的一些实践。


缘起


代码规范作为一个研发团队的核心基因,怎样在团队中高效传承是一个挑战。Flutter作为移动端持续火热的新型框架,正吸引越来越多的研发同学进入这个领域。但是面对全新的技术框架和之前几乎很少接触的dart语言,怎样写好Flutter代码困扰了无数Flutter初学者。文本就着重分享一下闲鱼Flutter团队在基础代码规范方面所做的一些实践。


Flutter 静态代码扫描


Native开发同学都知道Android/iOS都有配套的Linter检查机制。开发者可以通过Linter检查,统一代码风格,检查代码中的明显缺陷。Flutter同样具备这样的能力。通过Linter检查机制,是统一代码风格最简单高效的方式。


lutter Linter机制


Flutter Linter检查的机制植根于Dart Linter检查,同时做了大量的功能拓展。Flutter的Linter规则记录在工程一级目录的analysis_options.yaml文件中。大家可以通过对该文件的定制来获得适合自己团队的代码规则。


Flutter Linter 规则都从属于三个主要的集合:

  • ERROR


规则标识的是代码中可能出现的错误

  • Style


规则标识的是代码风格的问题

  • Pub


规则标识的是Flutter包管理相关的问题
需要注意的是,考虑到实际开发场景中的稳定性。调整Linter规则的时候需要关注规则对应的成熟度。目前主要的成熟度等级包括:

  • Stable - 稳定
  • Experimental - 实验性规则,可能会不太稳定

  • Deprecated - 不再推荐使用的规则,建议废弃


常见的Linter规则集


  • effective_dart


effective_dart是dart语言配套的Linter 规则。规则来源于Effective Dart文档。该文档中有对Dart语言高效使用的各种规范。effective_dart[2] 规则比较老,目前已经废弃。


  • pedantic


google内部dart开发规范集合。目前也已经废弃。


  • flutter_lints


是Flutter团队推荐的Flutter相关规则集。推荐大家在Flutter apps, packages, and plugins中广泛使用。本身是dart recommended 规则集合的拓展版本。该规范会影响到发布到 pub.dev[5] 中 package的得分。


  • lints[6]


Dart团队推荐使用的规则集。核心包括两个子集:core & recommended。


静态代码扫描闲鱼规范的取舍


在众多Liner规则中,选择符合团队需要的规则是一个很大的挑战。闲鱼在做的过程中,遵循了一些基本原则。


表达简洁


在语义等效的情况下,充分利用dart语言的各种高级语法来降低表达的复杂度。简洁表达不仅能提升编码效率,同时也可以提升代码的阅读效率。举几个典型例子:

  • 去除冗余new关键字【unnecessary_new】

闲鱼代码库中有大量的代码都是使用new关键字来进行类初始化的。这一方面是因为闲鱼切入Flutter比较早,有历史包袱;另一方面也是因为客户端同学将其他语言(例如java)的编码习惯带到了Flutter。虽然要修改的地方有很多,但是为了表达简洁,我们依然坚定的加入这条规则。


  • 高效null处理【prefer_conditional_assignment, prefer_null_aware_operators】


dart语法中有很多null处理的语法糖,能大幅提升判空的效率,提升代码的健壮性。这里包括?的判断,??的判空,以及null safety。需要不断引导团队同学更多使用这样的语法来提升效率,而不是继续使用if else的冗杂表达。


减少歧义


代码表达需要准确,同学之间的理解尽可能一致。减少代码之外的“以为”,增加字里行间上的“确定”。典型列子如下:


  • 显式变量类型【always_specify_types】


是否要明确变量类型,团队内部不同技术栈背景的同学有比较大的分歧。前端背景的同学倾向于通过推断的方式进行变量命名,好处是表达简洁。客户端背景同学倾向于直接明确定义,好处是直观,减少不必要的推断。最终经过激烈讨论,大家还是决定采用明确变量类型的方案。从实践角度出发,直接明确变量类型虽然从表达上略冗杂,但是歧义确实更少。


  • 变量/函数状态坚持最小化表达 【annotate_overrides,prefer_const_declarations,prefer_final_fields】


一个变量或者方法如果重写了,请明确加上override注解。一个变量如果确定是const变量,请加上const关键字。一个变量如果没有再被赋值,请定义成final。坚持最小化表达,有如下几点收益:


最小化变量状态表达能精准刻画变量状态


最小化变量状态是指用最严格的属性描述变量。例如一个变量从之前的多处赋值,改为一处赋值。那么变量其实自带了final的隐形属性。最小化状态表达要求必须加上final关键字,而不是推断是final。因为一旦加上final关键字,后续在赋值就会报错。这能减少不必要的理解成本,最大限度避免变量状态的隐形改变。


提升代码性能


增加的final const关键字能让编译器做更多优化,提升代码的整体性能。


风格一致


多人开发的团队中,每个人都有自己的喜好。代码管理应该避免出现“破窗效应”。一个人把代码写烂了,后面的同学照着写都烂了。正所谓,无规矩不成方圆。基础代码的表达,不追求绝对的对与错,追求的是在风格上的尽可能统一。这里有太多典型例子:

  1. 命名规范大体遵循驼峰的方式【camel_case_types,non_constant_identifier_names,constant_identifier_names 】
  2. 控制流中尽量使用大括号【curly_braces_in_flow_control_structures】
  3. import顺序按照先dart引用,再package引用,再相对引用方式分模块,模块内引用按字母表排序【directives_ordering】
  4. required 关键字标识的变量请排到前面 【always_put_required_named_parameters_first】
  5. flutter布局中优先使用SizedBox而不是Container【sized_box_for_whitespace】
  6. flutter颜色定义使用8位16制整识颜色【use_full_hex_values_for_flutter_colors】
  7. flutter widget在构造函数中加入key参数【use_key_in_widget_constructors】


这里的每一条都不具有非这样不可的理由。但是在闲鱼写代码就必须遵循这个规范。不为别的就为了风格的统一,为了提升团队同学业务轮转的效率。


代码质量


Linter检查的另一个重要的目标是发现潜在的代码缺陷。这对代码管理来说就更为重要了,因为这直接关系到稳定性的大局。稳定性是开发人员的底线,再怎么小心也不为过。同样举几个典型的例子:
1.避免给void赋值 【void_checks】2.变量比较之前先判断类型 【unrelated_type_equality_checks】3.避免catch 空实现【empty_catches】4.避免使用隐形类型传递 【avoid_shadowing_type_parameters】5.避免await 非future对象 【await_only_futures】6.集合的remove需要传递符合集合的类型的参数【list_remove_unrelated_type】
如果这些问题代码带到生产环境,轻者出现exception,重则功能不可用。防患于未然,在代码最开始编写阶段,就及时处理这些问题,代码才能更健壮。


维护成本


效率对一个团队固然很重要,但是追求一时的效率,而不顾及代码生命周期内整体的效率是非常短视的行为。我们今天越发关注代码在后期的维护成本。基于此,文档&注释的重要性正越发凸显出来。一个好的注释,能省下很多的答疑,很多的试错,很多的猜疑。不断引导大家写并维护文档及注释,是闲鱼代码规范明确的目标。举几个明确的例子:
1.Deprecated函数需要给出明确的注释[provide_deprecation_message]2.注释中的变量引用,符合引用的约束[comment_references]


规则权威


闲鱼团队Liner规则的制定,不是一家之言。邀请了团队所有同学参与到规则的制定过程。一个规则的权威性来源于所有执行者发自内心的认同。举一个典型例子:
在讨论标准格式化的时候,团队同学集中讨论了一个规则:【- lines_longer_than_80_chars # 争议规则,每行长度不超过80字符】
大家认同统一格式化代码风格的重要性。大家争议的焦点是:80字符在很多高分辨率显示器上太短了。这会导致很多不必要的换行,降低代码阅读体验。我们听取了开发同学反馈,把该条规范去掉了。改为统一android studio配置来执行。最终标准是12号字,一行最多160字符。
写在最后


体系体系,将规范规则化。通过持续快速检测,实时给使用者反馈,降低规范落地的成本。代码是研发团队的核心资产,需要我们共同守护。


附录


上面介绍的规则细节,如果有不清楚的,可以在下面的链接中找到更详细的解释。
linter-rules[7]


闲鱼核心Liner规则


附上闲鱼的核心Liner规则,给大家一点参考。


命名

2.jpg

排序

3.jpg

格式化

4.jpg

评论

5.jpg

库使用

6.jpg

NULL

6.jpg

字符串

7.jpg

集合

8.jpg

函数

9.jpg

成员变量

10.jpg

构造函数

11.jpg

异常处理

12.jpg

Mixin

13.jpg

类型

14.jpg

参数

15.jpg

质量

16.jpg

Core集合融合部分

18.jpg

Recmmended集合融合部分

193.jpg

Flutter 集合融合部分

20.jpg其他规则融合部分21.jpg

Reference


[1] effective_dart: https://pub.dev/packages/effective_dart
[2] effective_dart: https://pub.dev/packages/effective_dart
[3] pedantic: https://pub.dev/packages/pedantic
[4] flutter_lints: https://pub.dev/packages/flutter_lints
[5] pub.dev: https://pub.dev/
[6] lints: https://pub.dev/packages/lints
[7] linter-rules: https://dart.dev/tools/linter-rules#lints



相关文章
|
Dart Linux API
Flutter 上使用 C/C++ 代码(上)
Flutter 上使用 C/C++ 代码(上)
3041 0
Flutter 上使用 C/C++ 代码(上)
|
1月前
|
存储 开发框架 开发者
flutter:代码存储&基本组件 (五)
本文档介绍了Flutter中的一些基本组件和代码示例,包括代码存储、基本组件如AppBar的简单使用、可滑动切换的标签栏、TextField的多种用法(如简单使用、登录页面、文本控制器的监听与使用、修饰等),以及如何实现点击空白区域隐藏键盘等功能。通过这些示例,开发者可以快速掌握在Flutter应用中实现常见UI元素的方法。
|
1月前
|
IDE 调度 开发工具
鸿蒙Flutter实战:08-如何调试代码
本文介绍了鸿蒙Flutter项目的开发环境搭建、配置、日志查看及调试方法。首先按照指南搭建开发环境,安装IDE插件;接着配置vscode的launch.json文件;通过IDE调试控制台或命令行查看日志;提供两种调试Flutter的方式,包括IDE直接运行和使用DevEco;最后介绍ArkTs和Webview的调试方法。
49 0
|
1月前
|
小程序 Java Android开发
flutter:注意点&快速代码&链接虚拟机&改配置 (一)
这段内容主要介绍了Flutter开发中的一些注意事项和快速代码示例。首先,在构建Flutter小程序时,`setState`方法只能在`StatefulWidget`和`State`类中使用,且初始化数据应放在`initState`方法内。接着,通过一个简单的示例展示了如何构建一个包含`Scaffold`的基本Flutter应用,并指出了在`MaterialApp`中移除调试横幅的方法。此外,文档还提供了关于搭建Flutter开发环境、配置虚拟机、解决安装错误以及配置相关文件(如`build.gradle`)的指导信息。
|
3月前
|
Dart
Flutter之ExpansionTile实现以代码方式码折叠、展开
Flutter之ExpansionTile实现以代码方式码折叠、展开
125 4
|
3月前
|
Dart
Flutter笔记:手动配置VSCode中Dart代码自动格式化
Flutter笔记:手动配置VSCode中Dart代码自动格式化
469 5
|
6月前
|
Dart 安全
简化代码、提高效率:Dart和Flutter开发小技巧
在日常开发中,我们常常会使用一些常用的技巧或语法糖,以简化代码、提高开发效率。本文将分享一些在Dart和Flutter中常用的小贴士,帮助你更轻松地编写优雅高效的代码。
简化代码、提高效率:Dart和Flutter开发小技巧
|
6月前
|
Dart 前端开发 Android开发
【Flutter前端技术开发专栏】Flutter中的平台特定代码实现
【4月更文挑战第30天】Flutter旨在实现跨平台移动应用开发,但有时需针对iOS或Android编写特定代码。平台通道是关键机制,允许Dart代码与原生代码交互。通过`MethodChannel`等实现跨平台通信,然后在iOS和Android上响应调用。条件编译则在编译时决定特定平台代码。本文展示了如何在Flutter中处理平台特定功能,包括示例代码和总结。
154 0
【Flutter前端技术开发专栏】Flutter中的平台特定代码实现
|
6月前
|
Dart 前端开发 Android开发
【Flutter前端技术开发专栏】Flutter与原生代码的集成与交互
【4月更文挑战第30天】本文探讨了如何在Flutter中集成和交互原生代码,以利用特定平台的API和库。当需要访问如蓝牙、特定支付SDK或复杂动画时,集成原生代码能提升效率和性能。集成方法包括:使用Platform Channel进行通信,借助现有Flutter插件,以及Android和iOS的Embedding。文中通过一个电池信息获取的例子展示了如何使用`MethodChannel`在Dart和原生代码间传递调用。这些技术使开发者能充分利用原生功能,加速开发进程。
110 0
【Flutter前端技术开发专栏】Flutter与原生代码的集成与交互
|
前端开发 JavaScript Android开发
React Native 和 Flutter对比,包含代码实例
@[TOC](目录) React Native 和 Flutter 都是流行的跨平台移动应用开发框架。虽然它们在很多方面都有相似之处,但它们也有一些不同之处。在本文中,我们将详细比较这两个框架,讨论它们的优缺点、应用场景、性能以及包含的代码。 # 1. 框架概述 React Native 是由 Facebook 开发的一个开源框架,它允许开发者使用 JavaScript 和 React 来创建原生移动应用。React Native 可以用于开发 iOS、Android 和 Web 应用。它使用 JavaScript 的生态系统和工具,如 Babel、ESLint 和 React 工具链,使得开
185 0