本文作者: [景庄]
TangoBoot 是我们面向云音乐的 web 应用开发场景构建的一套标准化的前端应用开发框架,它构建在主流的开源框架基础上。TangoBoot 支持同时在低码开发环境和源码开发环境中使用,极大的降低开发者开发典型 web 应用的门槛。
开发者经常会诟病低代码带来的开发灵活度不足的问题,但业界对于低代码的投资和探索却一直没有中断过。对于开发者而言,低代码始终有一种“教开发者如何开发应用”的感觉,并且业务需求往往复杂多变,所以很难不被喜好自由度的开发者抱怨。我相信,没有能够解决一切问题的银弹,有的只不过是需求场景和解决方案的错配。
在云音乐,我们一直在探索低代码开发与源码开发的平衡,既为业务交付提供高效的交付能力,同时为开发者提供低门槛且灵活的用来响应业务需求变化的开发能力。 云音乐是一个拥有 11 年历史的业务,很多的系统构建在复杂的既有体系中,很难采用单一方案一蹴而就地解决历史积弊。因此,在为业务提供标准能力的同时,技术架构上的可持续性就显得特别的重要。
关于 Tango
Tango 是我们针对云音乐现有业务的特点和开发者的实际诉求构建的一套基于源码的低代码解决方案。支持在现有的代码库和业界主流的开源框架基础上提供低代码可视化开发能力。我始终相信,代码库是技术团队的核心资产之一,同时也相信,源代码可以为开发者提供最保险的逃生舱。通过构建基于源码的低代码开发能力,无论是对业务的可持续迭代,还是对于开发者习惯的渐进式培养,都会更为可靠且可持续。
开源进展
目前 Tango 低代码引擎已经开源,仍然持续更新中,可以通过如下的信息了解到我们的最新进展:
往期系列文章
- Tango 低代码引擎沙箱实现解析
- 网易云音乐 RN 低代码体系建设思考与实践
- 手把手带你走进 Babel 的编译世界
- 网易云音乐低代码体系建设思考与实践
- 云音乐低代码:基于 CodeSandbox 的沙箱性能优化
- 云音乐低代码 + ChatGPT 实践方案与思考
- 网易云音乐 Tango 低代码引擎实现揭秘
- 网易云音乐 Tango 低代码引擎正式开源
- 低代码在云音乐数据业务中的落地实践与思考
基于 AST 操纵实现源码和低码双向同步
Tango 引擎的核心是建立在对源码的 AST 操纵的基础上。AST 的全称是 Abstract Syntax Tree,是编程语言语法的抽象表示,可以将任意的代码片段转为 AST 结构树。Tango 通过将用户的操作转为对 AST 树节点的读取和修改,实现对用户低代码开发的支持。
通过 AST 来修改源码在很多的框架和库中都有实现,例如前端典型的 uglify, eslint plugin 等库都是基于 AST 操纵实现的。但只是通过操纵 AST 来实现代码生成和修改,问题显然会非常的复杂,因为很难预测和应对应对开发者编程过程中的随机性。
图:Tango 基于 AST 驱动的原理示意图
通过应用框架统一前端编程范式
针对编程过程的随机性,我们可以对前端应用的开发行为进行标准化约束,TangoBoot 是我们面向云音乐的 web 应用开发场景构建的一套标准化的前端应用开发框架,它构建在主流的开源框架基础上。TangoBoot 提供了一套标准的前端应用开发范式,包括应用的构建、启动、视图渲染、状态管理、异步数据请求、微前端等。
图:TangoBoot 通过构建标准应用范式统一应用的开发过程TangoBoot 同时支持在低码开发环境和源码开发环境中使用。 对于源码开发者而言,可以轻松的掌握 TangoBoot,并用于实际的应用开发,并且支持快速低成本的与现有代码库集成在一起。对于低代码开发者,Tango 引擎提供了基于 TangoBoot 的标准可视化搭建能力,引擎按照既定的规范生成和修改应用代码,实现低代码搭建过程。
图:在 Tango 低代码设计器中开发应用更少的视图和逻辑代码
通过 TangoBoot,可以让开发者少写约 50% 的视图和逻辑代码。 TangoBoot 的核心是采用响应式状态管理(Reactive States)+响应式视图(Reactive View)的方式来降低开发者对于视图层渲染逻辑的理解门槛:当绑定到视图的数据变化的时候,视图就会自动更新。对于开发者而言,无需掌握复杂的编程语法,即可快速的面向业务场景构建应用程序。下面我们以一个代办列表应用为例,用户可以输入代办事项,点击确认按钮,将计数器添加到页面中。
图:使用 TangoBoot 和 Dva 分别实现 Todo App 的代码对比前端响应式状态管理的实现
TangoBoot 提供的状态管理基于一个基本的事实,当绑定到视图的数据变化的时候,视图就会自动更新。这个被后端同学认为理所应当的事,使用 redux 等前端框架来实现却并不容易。不妨用一个更简单的例子来演示,下面的代码简单的表明了在视图中消费变量 counter.count
计数器,并通过点击按钮实现 counter.count
变量自增,而视图会自动触发重新渲染,无需开发者关注底层实现细节。
const counter = store({ count: 1 });
const Page = view(() => {
return (
{counter.count}
{
counter.count++;
}}>
add
);
});
响应式状态管理意味着,当绑定视图的变量的值变化时,视图自动重新渲染,以反映其变化。当对象的属性被修改时,它会查找属于该(对象,属性)对的所有组件并重新渲染它们 —— 是的,非常符合开发者想象中的那样。这种状态管理方案无论是对前端开发者,还是后端开发者都更易于掌握,也是 Tango 构建简单易用低代码开发能力的基础。
让我们看看如何来实现这一过程。为了构建(对象、属性、组件)关系,我们必须知道 counter 和 Page 在渲染期间使用哪些对象和属性。开发者可以通过看一眼代码就很快识别到这些信息,但框架却不能。我们需要让框架知道对象的属性何时发生变化,以便从保存的关系中收集相关组件并渲染它们。这两个问题都可以通过 ES6 代理来解决。
import { saveRelation, renderCompsThatUse } from './reactiveWiring';
export function store(obj) {
return new Proxy(obj, traps);
}
const traps = {
get(obj, key) {
saveRelation(obj, key, currentlyRenderingComp);
return Reflect.get(obj, key);
},
set(obj, key, value) {
renderCompsThatUse(obj, key);
return Reflect(obj, key, value);
},
};
简单解读下上面的代码,store 代理拦截所有属性获取和设置操作,并分别构建和查询关系表。还有一个问题是,traps 里的 get 中的 currentRenderingComp 是什么?我们如何知道当前正在渲染哪个组件?这就是 view 发挥作用的地方。
view 包装了一个组件并使用简单的逻辑来检测其渲染方法。它在渲染时为组件设置 currentRenderingComp 标志。这样我们就拥有了在 get 中建立关系所需的所有信息。对象和属性来自 get 函数的参数,组件是由 view 包裹的 currentRenderingComp。
通过上面的代码,我们可以简单的了解到如何实现一个基本的响应式状态管理库,但真实的场景往往比这复杂非常多,有众多的边缘情况和设计决策需要权衡。篇幅原因,这里不再详细介绍相关的细节,具体的内容可以参考 The Ideas Behind React Easy State 一文进行详细的了解。当然,TangoBoot 的状态管理实现也并没有重复造一个新的轮子,而是选择了更加成熟的社区方案,感兴趣的同学可以参考 Observer-Utility 和 React-Easy-State。
使用服务函数调用后端接口
对于后端数据请求,Tango 为低码和源码开发场景提供了统一的开发范式 -- 服务函数调用。开发者无需关注请求实现的细节,而是通过配置优先的方式进行接口的数据请求,用户的配置信息会自动生成对应的服务函数调用逻辑。可以通过下面这段简单的代码示例 TangoBoot 的数据请求的配置。值得说明的是,TangoBoot 本身并没有实现请求库,而是直接在 axios 和 fetch 的基础上进行了封装,使得开发者完全可以使用自己习惯的方式进行代码编写。
图:使用 TangoBoot 发起数据请求和使用 axios 发起数据请求的的对比当用户执行某个服务函数的时候,Tango 将会使用服务函数的配置信息通过 TangoGateway 将请求代理给对应的后端服务,并由后端服务进行相应的处理。这意味着,开发者可以非常轻松的在低码环境中执行数据请求,而无需考虑源码开发过程中复杂的鉴权、跨域、Mock 等相关的问题。
图:在 Tango 低码环境中发起数据请求的执行链路前端框架的挑战
与业界大部分低代码方案不一样的是,Tango 并没有发明一个全新的语法或编程语言,而是选择了在社区标准的基础上构建了低代码引擎,并基于低代码引擎构建了低代码可视化设计器。考虑到云音乐的业务现状,为了融合现有的源码开发过程和低码开发能力,通过构建标准化的应用框架 TangoBoot 来统一低代码开发和源码开发过程,使得开发者无论是在低码环境还是源码环境都可以使用一致的概念和范式开发应用。
面向未来,完全私有化的方案不可避免地存在着各种难以预测的可维护问题。对于 Tango 而言,就像现阶段的大语言模型 Copilot,我更愿意将其看作为一个开发者的辅助开发工具,可以降低开发者去开发和交付应用的门槛,让跨技能栈的开发者也可以去交付典型的前端应用,而不是完全取代开发过程。
最后
更多岗位,可进入网易招聘官网查看 https://hr.163.com/这是一个从 https://juejin.cn/post/7368375416930074676 下的原始话题分离的讨论话题