编写可读艺术的代码

2020-06-28  本文已影响0人  Yue_Q

前言

编写代码,实质是在梳理逻辑,为了完善整个逻辑流程,我们借用编程语言的变量、函数、流程控制、循环、注释、方法等串接起来,完善一套系统的逻辑。

为了完善这套逻辑,我们借助了许多工具:设计方法、架构设计、项目组织等。
意识到没有,代码的好坏一定程度上可以从逻辑层面评判。

逻辑的串接靠的是编程语言的变量、函数、流程控制、循环、注释等。

一、 规范

绝大多数的人,不会从零完整的完成一个复杂的项目,大多是团队共同合作,完成一个大的项目。

这个时候,假如你是中途参与进来。你在实现逻辑的时候,你是照着自己的逻辑来还是依照团队的风格来。

比如项目组织,命名等...

按照团队的命名风格来

1.1 编程语言的规范

每门编程语言,都存在一定的规范,比如 Python 采用的下划线的变量命令规则,Go 则采用驼峰式的变量命令规则等。
Effective Dart: 代码风格
Kotlin 编码规范

另外,Dart语言默认80个字符换行,在团队中需要设置100个字符换行。

二、 命名

给变量,函数,方法命名时易于理解

2.1 领域内单词

天星银行的领域单词分为几大类

类型 不常见的单词
account(账户) biometric(生物识别)、faceID(面容识别)、touchID(指纹识别)
deposit(存款) timeDeposit(定期)、currentDeposit (活期)、
kyc(开户) employment(职业) 、questionnaire(调查问卷)、liveness(活体检测)、document(证件)
loan(贷款) anti frau(反欺诈)、partial repay(部分还款)、credit(信用)
personal(个人) language(语言)、fileMaintain(资料维护)、promotion(促销)
security(安全) softToken(安全令牌)、remain(提醒)
transfer(转账) fps(转数快)、tupta(分享)、

2.2 避免空泛的名字

变量的命名一般要赋予一定的意义,极少情况下可以使用没有什么意义的单词。比如最常见的:

var i int

for (i=0;i<10;i++){
    fmt.Println(i)
}

这种没什么意义的单词,一般适用于局部作用域。

2.3 具体的名字

完成什么任务就使用什么单词。一般变量使用名词居多,函数使用动词开头居多。

String toString() => json.encode(toJson());
 /// 设备硬件支持的生物识别类型 (指纹,面容)
static Future<BiometricType> hardwareDetectedBiometric() async {} 

int pages = 0;
String userName = "";

2.4 带上更多细节

一般命名不建议过长,也不建议过短,最长三个单词的长度吧

如何带上更多的细节。

比如:

String currentFlowName;

VoidCallback onFinishLoad,

List<OtpType> otpTypes;

final BiometricType openedBiometricType;

几组对仗的后缀:

ServerCanStart() 不如 CanListenOnPort()

2.5 不使用令人误解的词

比如:Filter 在数据库操作中容易使用这个单词,这个单词没有带上更多的细节,实质上在使用的过程中,还是需要查看编写的SQL 语句等才能知道具体的过滤细节。整体思考多了几步。不易让人理解。

建议多读几遍自己命名的单词

2.6 布尔值

提到布尔值,因为就存在两种结果。所有,一般使用是否这样意思的词。

通常使用 is,has,can,should这样的词,可以把布尔值变得更明确。

final bool canBack;
final bool backOnFinish;

// 是否有更多收支历史
@JsonKey(name: 'hasMoreRecord', required: true)
final bool hasMoreRecord;

2.7 不建议使用的单词

get、read、util 恰恰这几个单词,在写代码中最容易使用。选择替代方案。

单词 更多选择
send deliver(传送)、dispatch(派遣)、announce(宣布)、distribute(分配)、route(路线)
find search(搜寻)、extract(提取)、locate(位于)、recover(恢复)
make launch(发动)、create(创建)、begin(开始)、open(打开)
start create、set up(建立)、build(建立)、generate(发送)、compose(构成)、add(添加)、new(新)

2.8 带单位的值

static const int resultTimeoutInSecs = 10;

3 设计

好的源代码应当“看上去养眼”。如何使用好的留白,对齐及顺序来让你的代码变得更易读。

这里以设计的四个规范类比代码的组织。

3.1 对齐

编程语言为什么强调缩进?难道不是为了阅读代码的人更容易看懂代码吗?写代码的人更容易组织代码吗?仅仅是设计者为了好玩?

static Future<void> start(FlutterDriverWrapper driver) async {
    driver.log('register test begin...');

    /// home page
    await driver.waitFor(KeyManager.homeBtnLogin);
    await driver.takeScreenshot();
    await driver.tap(KeyManager.homeBtnLogin);

    /// login page
    await driver.waitFor(KeyManager.loginBtnRegister);
    await driver.takeScreenshot();
    await driver.tap(KeyManager.loginBtnRegister);

    /// validate new username page
    await driver.enterText(KeyManager.validateNewUsernameInputUsername, TestConfig.username);
    await driver.takeScreenshot();
    await driver.tap(KeyManager.validateNewUsernameBtnNext);
」

3.2 重复、亲密、比较、审美

最应该避免的其实就是写重复的代码,一般的做法往往是提炼,将重复的抽象出一个函数之类的。这里的重复,是风格的统一。

  static double get s1 => s(3);

   /// Loan pages
  static const String loanCreditPrepare = '/loanCreditPrepare';
  ...

  /// Coupon
  static const String couponList = '/couponList';
   ...

  /// Transfer pages
  static const String transferPrepare = '/transferPrepare';
   ...
}

可以结合比较下 student.go 和 teacher.go

这样的组织方式,讲道理,并不太会给阅读代码的人带来太多的认知负担。

3.3 留白

设计领域页面的设计,并不强调内容越多越好,恰当的在页面上留有空白,使整体设计有呼吸感。

那编程如何实现留白?

假如你一个函数需要写 100 多行,不好意思,我可能建议你,不要这么做。

static Future<void> start(FlutterDriverWrapper driver) async {
    driver.log('kyc test begin...');

    /// home page
    await driver.tap(KeyManager.notifyBtnOk);

    /// prepare page
    await driver.tap(KeyManager.bottomBtnRight);

    /// kyc terms page
    await driver.delayed(TestConfig.pageStartDelay);
    await driver.scrollIntoView(KeyManager.bottomBtnRight);
    await driver.tap(KeyManager.bottomBtnRight);
    ...

4 注释

帮助阅读代码的人对代码了解的和写代码的人一样多

4.1 什么时候不需要注释

4.2 什么时候需要注释

关键点:
有些时候,仅仅靠之前的“表面工作” 已经不能完全能够满足让人易于理解。这个时候需要在关键点添加注释。

缺陷点:
是的,承认自己的代码写的不是最优的,仅仅只是实现,还存在更优的办法,所以需要在有缺点的地方加上注释。

  // TODO: move to remote config
  static const String customerServicePhoneNumber = '9288321';

  /// TODO: 更好的方案是:现有的图形上做动画,而不是重置动画。
  @override
  void didUpdateWidget(TotalAssetsWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    ...
  }

常量:
给常量注释,赋予了更多的意义。

  ///
  /// Area codes
  ///
  static const String areaCodeHK = '852';

全局注释:
一般在文件开头,表明文件内代码完成的任务。

class TestConfig {
  TestConfig._();
  ///
  /// Environment variables are used to configure the tests.
  /// It's more convenient to modify the env than to change the code.
  ///
  /// They are just key value pairs like following:
  ///
  /// ------------------------------
  ///   username = "bob010"
  ///   password = "bob0100"
  ///
  ///   accountGroup = "login"
  ///   kycGroup = "login, kyc"
  /// ------------------------------
  ///
  /// Note: line 'accountGroup = "login"' means which tests should be run
  /// for [accountGroup] test group.
  ///
  static void loadEnv() {
    load();
    env.removeWhere((k, v) => Platform.environment.containsKey(k));
    env.forEach((k, v) => log('[ENV] $k = $v'));
  }

5 流程控制

5.1 条件参数的顺序

涉及流程控制的话,一般涉及条件判断,条件判断语句中的参数的顺序。

if (number < 10) {} // A

if (10 > number) {} // B

if (receivedNumber < expectedNumber) // C

if (expectNumber > receivedNumber) // D

通常我们会选择 A,C
那么应该准从什么样的尊则?

左边倾向于变量,右边倾向于常量;

5.2 if...else 语句块的顺序

可以参照下面的下面准则:

  void _listenScrollPosition() {
    if (widget.bottomButtonText == null) return;
    ...
  }

5.2 避免使用三目运算符

三目运算符一定程度上能够精简代码,减少代码的行数,但是却存在另外一个缺点,即:不容易理解(虽然大学教材总会考这类题目,判断执行的顺序和结果)

只在简单场景下使用三目运算符。

5.4 函数什么时候返回

经常我们编写函数的时候,喜欢声明一个变量用来存储结果,到所有的逻辑结束后返回这个变量作为函数的返回值。

5.5 减少多层级的嵌套

层级的增多,增加了认知的负担。而且容易出现不容易发现的 bug。

如何减少嵌套:

5.6 表达式

建议使用短表达式

if createParam.Data.ShopType == RegionEntrances {}
// 感觉表达式长了,怎么做:

var shopTypeEqual = createParam.Data.ShopType == RegionEntrances

if shopTypeEqual {}

6. 重新组织代码,持续迭代

有下面几条准则:

不相干的任务,提取出来
一次只专注干一件事
梳理逻辑时,如果你能使用自然语言表述出来,对你写出逻辑清晰的代码很有帮助
单函数行数不宜过长 30 ~ 50 为佳。再一个评判方法是,查看函数的内容无需滚动鼠标进行翻页。
少些代码:每写一行都需要维护;不需要的功能,砍掉,不需要的代码,删掉

上一篇 下一篇

猜你喜欢

热点阅读