踏入职场后写代码已经有 14 个年头,保守估计应该垒了有 50 万行的代码。尤其最近 2 年从 0 开始写起 Bytebase,日常也会 review 同事的代码,趁着端午也总结了一些经验。这些经验聚焦在具体写代码的细节上,在道,法,术,技中更多归之于技。而这些技是用来帮助写出更可维护的代码,而不是更快地写出代码。
命名篇
- 字母使用小写。有些系统对大小写不敏感。
- 名词使用单数。英文的复数规则比较复杂,尤其对于非母语的我们来说,用复数容易造成代码命名不一致。如果是表示数组的话,可以加上 List 后缀。
- 动词使用一般时态。同样英文的动词被动时态规则也有好多种,使用被动时态容易造成命名不一致。
使用 Reversed domain name notation (reverse-DNS) 来命名。比如在 Bytebase 里定义 issue 创建 这个活动,我们可以用 bb.issue.create。而成员的创建可以用 bb.member.create。名字定义本身包含了结构,具备更好的可读性,同时搜索的时候也可以使用 bb.member 这样的前缀搜索。
范式篇
使用 Command Pattern,把每一个变更的行为都包装成一个 Command,具体 Command 的名字定义使用前面提到的 Reversed domain name notation。这样的好处是我们能提取出一个中央的组件来处理这些命令,像 undo/redo, logging 这些就变得相当容易。绝大多数应用框架其实都有 Command Pattern 的身影。
- 考虑使用 Soft Delete 而不是 Hard Delete,通常在数据库表结构里加上一列 status, 其中一个值是 PENDING_DELETE,可以有效防止误操作,让 undo 的实现也变得简单。
除非有必须的理由,尽量避免持久化状态。持久化状态会大大增加将来迁移和升级的复杂度。
架构设计篇
先设计 Schema / 领域建模,再设计 API,再其他。
- Schema / 领域建模设计的 4 个要点,实体本身,实体的行为,实体的约束以及实体间的关联。
- 大型项目需要尽早采用 Plugin 架构,区分 Core 和 Plugin 部分。Linux 的 core 其实很小,绝大多数都是 Driver 代码 (Plugin 的一种类型)。Bytebase 的代码也做了类似的拆分。
技术选型篇
- 使用 Restful 而不是 GraphQL。
- RESTful 是更成熟的技术,有成熟的生态。
- RESTful 帮助团队更早关注领域建模,因为需要识别出对象以及对象上的行为。
- RESTful 帮助架构做更好分层。RESTful 定义了更加克制的接口,界定了前后端的边界。而 GraphQL 很容易穿透界定的边界和抽象。
- 使用关系型数据库而不是 NoSQL。
- 想走得快用 MySQL,要走得远用 PostgreSQL。
- 除非业务本身需要对接多种数据库,否则谨慎考虑使用 ORM。ORM 通常只支持所有数据库功能的最大公约数,一些特色功能要么不支持,要么要用晦涩的语法。而且你无法精确控制生成的 SQL,影响代码可读性。
- 新的后端项目都应该优先考虑使用 Go。
最后
写代码,正确性是第一位的,可读性是第二位的,性能是最末位的。
光代码写得好并没有用,技术总是服务于业务的,理解业务是更重要的事情。最好的做法是不加任何额外的代码就能解决业务问题,而能比这更好的做法是可以删除代码来解决问题。
Deleted code is debugged code.
上面提到的不少实践在 Bytebase 中也有体现,感兴趣可以翻阅我们的代码 https://github.com/bytebase/bytebase。同时可以关注我们的公众号
以及加入我们的用户群