阅读 1272

转转中后台规范落地实践

1. 背景

中台覆盖了多线业务,自然对应的不少后台系统,考虑日后到项目应用,满足业务的快速迭代,无论是技术版本升级、敏捷开发、可复用性和可维护性等。

我们需要针对当下的痛点,切合定一些强制规范和推荐规范。

1.1 痛点

  • 新旧项目差异比较大,升级比较费劲
  • 老项目文档不全 or 没有
  • 组件复用性不高
  • 依赖同类功能的第三方库,五花八门,没有统一
  • 切换项目开发时,代码校验规范不统一
  • 没有实际文档,不便于新人培训等

1.2 项目相关规范

主要分为两大模块:强制规范和推荐规范,大致如下图。

规范内容

2. 如何落地?

2.1 技术方案

开发前,我们在技术选型和技术设计时通常会有调研某类技术或者项目设计方案,但我们通常选择完后,没有的文档的输出,以至于出现重复调研或“时间久了,忘记了”这种现象。所以,为了避免类似事情的发生,我们需要一定的文档积累,但这些文档至少需要包含什么内容呢,这就需要我们协定下一定的规范。

2.1.1 技术选型规范文档

# XX技术方案调研/选择

## 背景

简述下,技术调研/选择背景(应用场景),技术原理,目的是什么(为了解决XX问题)?

## 业界主流技术方案列举

* 典型方案及demo实践
* 对比其优缺点
* 是否需要做方案优点整合?

## 在实践Demo中遇到的典型问题

* 阐述:问题 && 原因 && 解决方案

## 最终选择该方案的亮点

* 阐述目前方案的较业界的优点,或者说优化了某个缺点
* 可以从复用性,功能/兼容性等角度

## 可能存在的问题

* 预估存在的风险(后期的优化规划)

## 方案评审

* 若项目较大或较无把握,可以开一个方案评审会议
复制代码

2.1.2 技术设计文档规范

# 技术方案设计

> 根据具体的项目复杂度,进行项目合理的技术设计。(此设计纬度,仅限前端)

⚠️⚠️⚠️ 注意:

1. 技术设计尽可能的基于目前公共资源,如果发现有设计不合理的地方,可以反馈公共支撑组优化
2. 如果公共资源没有的方案,尽可能的抽取出可公用的部分,返哺给公共组。

## 概要设计

### 架构图

目的:加深对整体的结构足够了解(可以向pm、qa和rd咨询了解)

### 项目基础结构图

目的:对项目的目录/功能结构加深理解

### 流程图

流程图是面向过程的,用于描述一个算法或者业务的过程。

目的:明确业务范围,明确我们到底要做什么,不做什么,帮助识别边界。

## 详细设计

### 时序图(交互图)

目的:根据不同的视角看问题,可以从用户的角度,切身思考🤔会遇到的问题,从而优化用户体验。

### 开发&测试用例-思维导图

目的:梳理需求文档,细化文案、设计和交互功能,每个case,防止文档遗漏。
复制代码

2.2 UI规范

目前,我们整体的布局和大多数的组件风格沿用的是Ant Design,也会根据自身的业务特点,与PM和UI设计配合,制定属于我们的UI规范(主要围绕三个维度:组件规范、页面规范和组件使用规范),具体如表。

规范内容落地方法
组件规范组件库
页面规范(包括色调、间距、页面布局等)脚手架模板
组件使用规范
(比如某个地方应该使用哪个组件;表格是否应该支持列宽度拖动等)
文档及分享

2.3 项目中的规范

2.3.1 README规范

README文档在项目中,相当于项目的门面,好的README可以让 下一任维护者一目了然。主要框架如下:

# 项目名

## 简介(Introduction)

这里可以把项目背景简单介绍下,可以把项目的目标以及后面规划的写下。(可以咨询相关pm)

## 方案选择(Scheme)

包含内容:方案设计选择,可以写调研的方案参考,优缺点,调研实践demo,以及最终选择的原因等。

其他:
* 这部分过复杂,可以单独,对应的项目目录中,然后这里此readme,标注引导
* 可参考规范`【技术方案选择文档编写规范】`

## 项目设计结构(Structure)

包含内容:最终的方案设计,目录 or 功能结构,这部分以图表(流程图或者思维导图等)的形式展示,必要的主流程图,细节交互可以补上对应的测试用例等。

其他:
* 这部分过复杂,可以单独,对应的项目目录中,然后这里此readme,标注引导
* 可参考规范`【技术方案设计文档编写规范】`

## 使用(Usage)

# 安装依赖(如果生成初始化项目时已经安装完毕,无需安装)
npm install

# 开发模式 localhost:8000
npm run dev

# 构建模式
npm run build

# 构建模式 + 分析报告
npm run analyz

# 语法校验
npm run lint

# 自动修复
npm run fix

# 按规范 git commit 并自动生成 changelog
npm run cz

## 开发(Development)

具体开发注意事项,使用的工具包,功能特征等等

### 页面配置

- 页面配置 1
- 页面配置 2

### 页面对应地址

| 页面 | 功能 | 地址 |
|------|-----|------|
| home | 首页 | https://xxxxx/home |
| about | 详情页 | https://xxxxx/about |

## API(Reference)

1. api 1
2. api 2

## FAQ(常见问题解答)

1. 常见问题1
2. 常见问题2

## 附录(Appendix)

- [ChangeLog]()
- [其他文档]()

复制代码

2.3.2 目录规范

目录清晰,能够让开发者清楚的知道,什么地方,该做什么事,也便于维护者的对代码的良好阅读。

  • 项目目录
├── CHANGELOG.md                  // [生成] 更新日志
├── README.md                     // [必选] 导读
├── config                        // [可选] 配置目录
│   ├── config.js                 // [生成] 基本配置
│   └── router.config.js          // [必填] 路由
├── dist                          // [生成] 打包目录
├── docs                          // [可选] 文档
├── mock                          // [可选] mock 数据
│   └── sample.js                 // [可选] demo
├── package.json                  // [必选] 大家都懂
├── public                        // [必选] 不会被webpack编译的资源
└── src                           // [必选] 开发目录
    ├── app.js                    // [必选] 运行时配置文件
    ├── assets                    // [可选] 公共资源(被项目引用的经过webpack处理的资源)
    ├── components                // [必选] 业务组件必须写在这里
    ├── global.jsx                // [必选] 全局执行入口
    ├── global.less               // [必选] 需要重置的样式或者全局样式引用
    ├── layouts                   // [可选] 基本的布局封装
    ├── models                    // [可选] 对异步数据处理
    ├── pages                     // [必选] 页面组件,不允许有其他类型组件混入
    ├── services                  // [必选] 业务接口封装
    └── utils                     // [可选] 工具库(用于一些函数方法之类的库)
├── ...
复制代码
  • components、pages、services、models 具体职能划分和文件格式

⚠️注意:以 mock 中的 samplepages 中的 sampleservices 中的 samplemodels 中的 sample 为例,名字需要一一对应。

├── mock                          // [可选] mock 数据
│   └── sample.js                 // [可选] demo,文件名小写
└── src                           // [必选] 开发目录
    ├── components                // [必选] 可公共业务组件必须写在这里
    │   └── CustomizeForm         // [可选] demo,文件名大写驼峰
    │   │   └── MoneyInput.jsx    // [可选] demo,组件名大写驼峰
    │   │   └── VideoUpload.jsx   // [可选] demo,组件名大写驼峰
    ├── models                    // [可选] 对异步数据处理
    │   └── sample.js             // [可选] demo,文件名小写
    ├── pages                     // [必选] 页面组件,不允许有其他类型组件混入
    │   └── sample                // [可选] demo,文件名小写
    │   │   └── components        // [可选] 页面个性组件
    │   │   │   └── DemoInput.jsx // [可选] demo,页面个性组件名大写驼峰
    │   │   └── index.jsx         // [可选] demo,文件名小写,主入口都统一用index.jsx
    ├── services                  // [必选] 业务接口封装
    │   └── sample.js             // [可选] demo,文件名小写
├── ...
复制代码

2.3.3 代码规范

目前中后台系统,主要用的是 umi3 + antd4,基于此基础,主要针对 react 做一些规范。

2.3.4 基础规范

  • ESLint规范

ESLint 属于一种 QA 工具,是一个 ECMAScript/JavaScript 语法规则和代码风格的检查工具,可以用来保证写出语法正确、风格统一的代码。ESLint 旨在完全可配置,它的目标是提供一个插件化的 javascript 代码检测工具。转转的 ESlint 配置基于 Standard 规则的基础上做了特定的修改。

rules: {
    // 末尾不加分号,只有在有可能语法错误时才会加分号
    semi: 0,
    // 箭头函数需要有括号 (a) => {}
    "arrow-parens": 0,
    // 两个空格缩进, switch 语句中的 case 为 1 个空格
    indent: [
        "error",
        2,
        {
        SwitchCase: 1
        }
    ],
    // 关闭不允许回调未定义的变量
    "standard/no-callback-literal": 0,
    // 关闭副作用的 new
    "no-new": "off",
    // 关闭每行最大长度小于 80
    "max-len": 0,
    // 函数括号前面不加空格
    "space-before-function-paren": ["error", "never"],
    // 关闭要求 require() 出现在顶层模块作用域中
    "global-require": 0,
    // 关闭关闭类方法中必须使用this
    "class-methods-use-this": 0,
    // 关闭禁止对原生对象或只读的全局对象进行赋值
    "no-global-assign": 0,
    // 关闭禁止对关系运算符的左操作数使用否定操作符
    "no-unsafe-negation": 0,
    // 关闭禁止使用 console
    "no-console": 0,
    // 关闭禁止末尾空行
    "eol-last": 0,
    // 关闭强制在注释中 // 或 /* 使用一致的空格
    "spaced-comment": 0,
    // 关闭禁止对 function 的参数进行重新赋值
    "no-param-reassign": 0,
    // 强制使用一致的换行符风格 (linebreak-style)
    "linebreak-style": ["error", "unix"],
    // 关闭全等 === 校验
    "eqeqeq": "off",
    // 禁止使用拖尾逗号(即末尾不加逗号)
    "comma-dangle": ["error", "never"],
    // 关闭强制使用骆驼拼写法命名约定
    "camelcase": 0
}

复制代码
  • ignore规范

gitignore:主要是在git提交的时候忽略掉某些目录或者文件。

eslintignore:eslint校验执行时,忽略某些文件。

prettierignore:不使用prettier格式化的文件填写在项目的.prettierignore文件中。


# gitignore 规范

# dependencies
**/node_modules
# roadhog-api-doc ignore
/src/utils/request-temp.js
_roadhog-api-doc

# production
/dist
/.vscode

# misc
.DS_Store
npm-debug.log*
yarn-error.log

/coverage
.idea
*bak
.vscode

# visual studio code
.history
*.log
functions/*
.temp/**

# umi
.umi
.umi-production

# screenshot
screenshot
.firebase
.eslintcache

build

# --------------------------------------------------------

# eslintignore 规范

bash
/lambda/
/scripts
/config
.history
node-build.js

# --------------------------------------------------------

# prettierignore 规范

**/*.svg
package.json
.umi
.umi-production
/dist
.dockerignore
.DS_Store
.eslintignore
*.png
*.toml
docker
.editorconfig
Dockerfile*
.gitignore
.prettierignore
LICENSE
.eslintcache
*.lock
yarn-error.log
.history
.prettierrc
复制代码
  • prettier规范

Prettier是近期比较火的代码美化工具,其中文意思是“漂亮的、机灵的”,它能够解析代码,使用你自己设定的规则来重新打印出格式规范的代码。

{
    // 在ES5中有效的结尾逗号(对象,数组等)
    trailingComma: 'es5',
    // 不使用缩进符,而使用空格
    useTabs: false,
    // tab 用两个空格代替
    tabWidth: 2,
    // 仅在语法可能出现错误的时候才会添加分号
    semi: false,
    // 使用单引号
    singleQuote: true,
    // 一行最多 100 字符
    printWidth: 100,
    // 对象的 key 仅在必要时用引号
    quoteProps: 'as-needed',
    // jsx 不使用单引号,而使用双引号
    jsxSingleQuote: false,
    // 大括号内的首尾需要空格
    bracketSpacing: true,
    // jsx 标签的反尖括号需要换行
    jsxBracketSameLine: false,
    // 箭头函数,只有一个参数的时候,也需要括号
    arrowParens: 'always',
    // 每个文件格式化的范围是文件的全部内容
    rangeStart: 0,
    rangeEnd: Infinity,
    // 不需要写文件开头的 @prettier
    requirePragma: false,
    // 不需要自动在文件开头插入 @prettier
    insertPragma: false,
    // 使用默认的折行标准
    proseWrap: 'preserve',
    // 根据显示样式决定 html 要不要折行
    htmlWhitespaceSensitivity: 'css',
    // 换行符使用 lf
    endOfLine: 'lf'
}
复制代码
  • stylelint规范

stylelint 有一百多条的校验规则,并且还在逐步增加...尽管如此,但是他们都是默认关闭的我们是基于 stylelint-config-standard。

  rules: {
      'no-descending-specificity': null,                                     // 禁止低优先级的选择器出现在高优先级的选择器之后,https://github.com/stylelint/stylelint/issues/4114
      'function-calc-no-invalid': null,                                      // 非法calc方法
      'font-family-no-missing-generic-family-keyword': null,                 // 颜色16进制指定为长符号,iconfont
      'plugin/declaration-block-no-ignored-properties': true,
      'unit-no-unknown': [true, { ignoreUnits: ['rpx'] }]
  }

  // 官方文档来源

  [@umijs/fabric stylelint](https://github.com/umijs/fabric/blob/master/src/stylelint.ts)

  [stylelint 更多中文解释](http://stylelint.cn/user-guide/rules/)

  [stylelint-config-standard](https://github.com/stylelint/stylelint-config-standard)

  [stylelint-config-css-modules](https://github.com/css-modules/css-modules)

  [stylelint-config-rational-order](https://github.com/constverum/stylelint-config-rational-order)

  [stylelint-config-prettier](https://github.com/prettier/stylelint-config-prettier#readme)
复制代码
  • 还有其他,包括编辑规范都是基于公共规范定,等等,这里就不一一列举了。

规范落地结构

3. 为什么这么做?

当然,规范化,并不是说定好后就能立马彻底解决以上所有痛点,而是优先针对增量的项目进行规范,逐步的积累我们的公共基础能力,提高可复用和可维护性。

等我们对老项目重构的时候,按照规范开发,是不是以后迭代开发和维护就会更轻松了呢?

规范化,不仅仅是规范项目,也同时规范我们的良好习惯。

努力完善吧,老铁们~加油!!!

4. 福利部分

预告下,接下来我们会陆续发布转转在微前端、Umi、组件库等基础架构和中台技术相关的实践与思考,欢迎大家关注,期望与大家多多交流。文章在 “大转转FE” 公众号也会发送,并且公众号有抽奖活动,本文奖品是转转纪念T恤一件,欢迎大家关注 ✿✿ヽ(°▽°)ノ✿