DEF 2.0 的想法
作者: 发布于:

最近接手了 DEF 的维护开发,一直在读代码、读代码、读代码,是时候整体对 DEF 做个总结回顾,同时畅想下未来了。这里面很多都是我自己的理解,如果有不对的地方,欢迎大家指出,一起讨论。

历史

DEF 的全称是 Development Environment for FED(不过,据小道消息已经改名为:Development Ecosystem for FED,更能体现 DEF 的平台性)。DEF 的定位是在硝烟四起(开发工具重复建设)、荆棘密布(规范参差不齐)中建立一个整合前端开发中各种工具、环境的平台。

在 2013 年底 DEF 小组横空出世,于 2014 年 2 月,发布了第一个内测版本。经过 “冷启动” 中 “种子” 用户的试用反馈,DEF 不断优化,在 2014 年 4 月发布了第一个正式版本,开始了漫漫征途。

我们知道,随着应用复杂性的增加,前端项目早已不是简单的几个 JS 文件和 CSS 文件了,而是越发的复杂和精细化。我们会建立标准,统一目录结构,将功能分解为各个小模块(require、exports)。然后,在发布前对代码进行构建(build),执行合并、打包、压缩。

可以看出,这其实就是一种抽象的工作流程。落实到实现上,我们需要解决几个问题:

  • 目录结构需要方便的按约定生成(约定好于配置,基于约定工作效率更高)
  • 本地如何进行调试(手动构建后调试、watch 文件改动并构建后调试)
  • 如何进行上线(本地构建后上线、服务端构建后上线)

DEF 给出了自己的答案:

  • 使用 generator 来生成规范的目录结构
  • 使用按需增量编译的本地服务器 reflect 来进行本地调试(利用 middleware 来实现文件的实时构建,而不是 watch 文件后构建)
  • 使用完美接入代码管理系统(Gitlab)的云构建服务(在服务端使用构建器 builder 构建文件后同步代码)

DEF 解决了前端工程中非常重要的问题:目录结构规范,代码构建。同时通过插件机制,诞生了各种各样的工程规范(标准)。

现状

我们先来看看近 1 个月来 DEF 收集到的 2 组数据。

DEF 插件调用量:

DEF 命令使用量:

从上面的图表里面我们可以分析出下面几个结论:

  • 用户绝大部分时间在使用各种有标准开发规范的插件,比如:无线开发(KIMI)、Node.js 应用开发(Midway)、模块搭建(TMS)。
  • 用户比较频繁的使用代码规范检查(def-lint)、构建(def-build)、发布(def-ff)、持续集成(def-ci)这类和工程相关的插件。
  • 功能型插件(def-tps、def-ssh)的使用量并不是很多。
  • 用户使用的命令集中在本地调试(def kimi dev、def cake dev、def tms dev)、构建(def build)、发布(def ff、def kimi awp)、单元测试(def ci test)、规范检查(def lint)。

如果我们仔细分析会发现,上面这样的使用数据其实反映出前端开发正在形成标准的开发流程。

  • 通过 def init 形成目录规范
  • 通过 def kimi devdef tms dev 进行本地调试
  • 通过 def build 或者云构建进行代码构建
  • 通过 def ffdef kimi awp 进行代码部署和发布
  • 通过 def ci 进行持续集成及单元测试
  • 通过 def lint 进行代码规范检查

标准的开发流程,这不正是工程化吗!有了标准的开发流程,一群搬砖的就可以造出宏伟的高楼大厦,想想都有些小激动呢。

但是 DEF 目前提供的工程化功能不是很规范,还有点点“混乱”的感觉。但是其实这是非常合理的情况,因为必然要经过工具的百花齐放,才能博采众长,通往规范统一的工程之路。

这里试举几个例子。

比如,我在某个目录下进行本地调试应该执行 def dev 就好了,配置里面指定了套件类型,没必要再加上额外参数,因为我不可能去一个 KIMI 的项目里面执行 def tms dev

再比如,代码的部署、发布,我希望执行 def deploy 就部署,至于部署到哪(是存放无线 HTML 页面的 AWP,是存放 JS、CSS 的 CDN、还是 Node.js 应用的服务器),我们通过配置约定好,你照着发就行,我没必要重新用另外的命令操作。

再再比如:执行代码规范检查、单元测试、持续集成,我希望我部署代码到远程以后就给我把该跑的全跑了,有问题再告诉我。当然,也会给对自己严格要求的开发者提供本地运行的命令。

最后,为了减少用户切换 context 的消耗,所有这些信息应该在一个平台展示,就算背后系统是多个,也应该“伪装”成一个展示给用户。

未来

有了对“现状”的分析,我觉得 DEF 对工程的支持应该是这个样子:

最左侧是相关的工程套件,上面是工程生命周期相关的命令(目前暂时统一为 5 个)。命令会根据不同的工程套件,使用底部的一系列服务、系统(对使用者其实是透明的)来提供不同功能。

由于复杂性都隐藏在内部,暴露的命令是统一、标准的,这对使用者来说就变得非常简单。

比如我要开始一个 web 项目,执行 def init 后选择相关的套件类型(kit-web),此时套件类型已经确定,后面执行的命令都将依据套件来做出不同的表现。

本地调试执行 def serve 开启服务器(可能会加参数来开启远程调试 sync 服务)。

构建一般来说直接走云构建,如果你非要本地构建,执行 def build 后会从云端下载套件对应的构建器 builder 在本地执行构建过程。

检测会是一个包含很多东西的操作,理论上是执行部署时会在云端去运行配置好的检测任务(比如:安全检查),也会暴露本地检测的命令供开发者使用(比如:单元测试、规范检查),有些检测过程可能还需要用户参与(比如:代码 Review)。

最后部署发布,直接执行 def deploy 就可以将各种资源(比如:JS、CSS、HTML、甚至是 Node.js 应用等等)进行发布(通过参数区分发布到日常还是线上)。

于是,DEF 2.0 可以这样来描述:整合插件及各种系统,将流程标准化,为开发者提供统一的、工程化的服务——工程套件。

体系

整体架构

DEF 平台由 3 大部分组成:

  • DEF 客户端(DEF Client)
  • CLI(或者 GUI、或者 XXX)+ Core
  • DEF 服务端(DEF Server)
  • DEF Store:插件、套件的在线“商店”服务
  • DEF Analytics:用户使用数据的收集、展示服务
  • DEF UserAuth:跨应用、安全、便捷的用户验证服务
  • DEF Notify:服务端向命令行的实时消息推送服务
  • DEF 生态圈(DEF Ecology)
  • 插件、套件、及其背后的系统,开发者,开发规范

整体的架构图如下所示:

DEF Client

DEF 客户端是离用户最近的部分。包括:

  • 可编程的 DEF Core
  • 命令行工具 DEF CLI(或者图像界面 GUI,或者 whatever)
  • 存放安装的插件(套件)、配置文件的用户目录 DEF Home

命令行工具 DEF CLI 类似操作系统里面的 shell,接受用户输入,处理参数,调用内核来完成具体功能。

可编程的 DEF Core 类似于操作系统的内核,是真正做事情的,能够基于内核进行二次开发(比如,我们完全可以调用内核来打造一个拥有图形化界面的 DEF GUI)。

DEF Home 类似于操作系统里面的用户目录,用来存放用户安装的插件(套件),用户的配置信息。DEF Core 会加载此目录下的插件(套件)来提供功能。

DEF Server

DEF 服务端是给客户端提供各种丰富接口(API)的后台服务。包括:

  • DEF Store:管理插件(套件)发布、上架、展示的在线商店服务
  • DEF Analytics:收集用户使用数据,并进行可视化展示的数据分析服务
  • DEF UserAuth:安全、跨应用的用户验证服务
  • DEF Notify:服务端向命令行推送实时消息的通知服务

DEF Store

DEF Store(在线商店)想要解决的问题是:

  • 插件(套件)的发布能够自动化、形成规范。开发者只需和代码管理系统(Gitlab)交互,执行一条命令即可由服务端将模块推送到 npm 仓库。
  • 管理员可以管理插件(套件)的上架、下架,只有在 DEF Store 上架的插件(套件)才能被下载使用,从而可以把控插件(套件)的质量。
  • 可以在 DEF Store 做基于插件(套件)安装数、使用数的浮现、排名机制,从而激励开发者,活跃生态圈。

整个 DEF Store 的结构图如下:

可以看到有 4 部分流程走向:

  • 开发者:使用 DEF 提供的命令,执行 1.1 ~ 1.3。本地检查;代码 push;通知上架
  • 云端发布服务:收到上架通知,执行 2.1 ~ 2.3。获取仓库;运行持续集成;发布到 tnpm
  • DEF 客户端安装器:收到安装命令后,执行 3.1 ~ 3.2。从 DEF Store 获取插件(套件)信息;如果能获取到,将插件(套件)安装到 DEF Home 目录
  • 管理员:通过 DEF Store 的 web 界面执行插件(套件)的上架、下架等管理

DEF Analytics

想要对产品做好优化迭代,收集用户的使用数据是十分必要的。DEF Analytics 就是一个用户行为日志的打点及可视化服务。整体的结构图如下:

在客户端:命令行 CLI 通过 commands 来分发命令的同时会将命令传递给 analytics 模块,此模块会先将使用数据暂时写入配置(不做实时发送,降低服务器的压力),待收集一定数据后(比如:50 条),请求服务端提供的 API 一次性将数据进行发送。

在服务端:会将使用数据进行存储,然后会提供可视化的数据展示界面。DEF Store 也会获取 Analytics 服务的数据(插件的使用量、套件的使用量等)进行展示、做浮现等。

DEF UserAuth

DEF 客户端里经常需要知道当前使用的用户是谁,该如何安全优雅的进行登录验证是一个问题。同时,DEF 作为一个平台,接入的插件(套件)背后可能还有自己的一套系统,如何方便、安全的告诉这些系统当前用户是谁同样是一个需要解决的问题。这就是 DEF UserAuth 服务。

DEF 的做法是,用户登录后为每个用户生成一个随机的私人 token(private token),并在本地记录这个私人 token,后面使用私人 token 请求远程服务时,服务根据私人 token 来获取用户信息。这个 token 每个人都不一样,而且具有随机,不容易“猜到”。而且可以为 token 设置一个过期时间,防止 token 泄露造成的风险。

DEF 登陆验证流程图如下:

这其实就是一种 session 机制,就像我们在浏览器端使用 cookie 记录下 session id,每次请求服务都会再传递 session id,直到 session 过期了就要求用户重新登录。

跨应用的用户验证

现在假设用户在 DEF 成功进行了登录,某个插件 X 获取了用户信息后需要请求插件背后提供服务的应用 X 的 API 来操作用户的记录。应该怎样安全、方便的告诉应用 X 当前用户是谁呢?

DEF 实现的验证流程如下:

这种方法的关键点包括:

  • DEF UserAuth 不直接返回用户信息,而是返回加密后的信息(使用 JSON Web Token),密钥等于应用事先在 DEF UserAuth 申请后获得的随机串
  • 插件向应用传递信息时不传递工号,而是传递 jwt
  • 应用使用事先在 DEF UserAuth 申请后获得的密钥解析 jwt 后获得用户信息
  • 为 jwt 设置过期时间,防止 jwt 遭到泄露

这样各个应用只需要申请 secret,使用 DEF 提供的 jwt sdk,即可直接解析出用户信息,不再需要各自实现 token 验证。

DEF Notify

DEF Notify 其实是一个 YY 中的概念。

我们平常发现,一些比较重要的旺旺消息提醒、邮件提醒等真正被用户注意到的还是比较少的。而 DEF 命令行作为一个极“大”的入口,大家其实是需要频繁“关注”的。我们希望实现一种从服务器实时的向命令行推送消息的服务,这样可以保证一些重要的通知(比如:构建出错、代码检查出错等)可以很快被用户注意到。

整体的交互图如下:

这里实现了一个“抽象”的消息服务,“消息”可以是各种各样的内容,拥有很多想象空间。

比如说:

  • 发送构建、检查错误的实时通知
  • 推送每日 ATA 必读一刻
  • 在命令行直接提交 DEF 的 bug 并通知开发人员
  • 用 DEF 命令行跟人聊天
  • 制造一个 DEF Robot,作为客服“美眉”为你随时答疑解惑(直接输入 def robot,然后向他提各种开发、文档、行政、生活的问题,都会得到解答)

DEF Ecology

DEF Ecology 里面的内容其实很多,包括:偏功能性的各种插件、拥有标准流程的工程套件、贡献插件(套件)的开发者、DEF 插件(套件)的开发规范、支撑插件(套件)的各种系统。

这是一个充满自由又满是约束的世界。自由在通过插件贡献各种各样的工具。约束在通过套件封装标准统一的工作流程。

这一部分的美丽图片应该是每位开发者一起携手来画出的!

总结

这篇文章把 DEF 梳理了一遍,并提出了我们未来努力的目标,说的比较多,可能干货比较少。等真正开始实现时,会对里面的一些实现、技术细节进行更加详细的解说。

关于题图:在大海航行的船,https://pixabay.com/zh/日落-船海-船舶-675847/,DEF 2.0 也正杨帆起航。