在编程的时候,我们会一直考虑所为的「灵活性」的问题。灵活性,可以降低我们变更的成本,减少部署的频率,进而提供更好的开发体验。而与此同时,追求实现的灵活性,可能会影响用户的体验。如何平衡这两种就是一个非常有意思的问题。
不过呢,我们一直在关注于所谓的用户的体验,但是有时候对于开发者的开发体验。如何开发体验更好的话,那么它就会带来更好的用户体验。
【资料图】
在为 ArchGuard 设计「趋势与洞察」功能,它应对于「架构自治服务」一文所描述的概念,即起向用户提供一个迷你版本的数据自治服务的功能。从功能上来说,有点类似于一个自制的数据湖平台。
这个功能从一个简单的输入框,变成了一个背后有 1000 行代码的「一行代码的编辑器」。在这一个过程中,我们一直在尝试平衡灵活性与体验,也依旧在进这一方面的尝试。因为这一个过程中,非常有意思,也就想简单写个代码记录一下。
尽管,在起初,构建一个迷你的查询语言就是我们的目标。不过,我们并没有一开始就朝向这个宏大的目标,而是一步步的迈进。所以,也就产生了三个版本:
第一个版本,基于下拉框与输入框的 CRUD 查询。
第二个版本,通过正则匹配字段,来生成最后的 SQL。
第三个版本,手写解析器替换正则表达式,构建独立于 SQL 的查询语言。
PS:感谢 @CGQAQ 重构出了第三个版本。
从一开始的 Input,到最后引入 Monaco Editor,我们逐步把一个简单的问题复杂化了。虽然如此,但是这个过程还是颇有意思的 —— 业余,我们不就应该多做一些有意思的吗?
我们构建的第一个版本采用的是常见的数据查询模式:
UI 交互生成数据。
后端检验数据,生成 SQL。
执行 SQL 返回数据。
在 UI 设计上,主要就是结合下拉框 + 输入框来实现:通过复杂的下拉框联动,构建出对于数据的查询;结合下拉框的值与特定的输入值,输入的值进行校验。
这一种模式的典型问题是:
业务间联动过于复杂。复杂的结果,就是导致容易出现 bug。
无尽的需求变更。
没有挑战性。技术实现上,它就是各种 Ctrl + C / Ctrl + V。
它的优点就是胜在实用,学习成本低。
随后,我们在表单联动上遇到了挑战:如何我们字段越来越多的时候,那么表单就会越来越复杂。随着,字段的增长,那么就会出现看上去很炫,但是很难适合人类使用。
于是呢,作为程序员的直觉,就是用编辑器解决 —— Monaco Editor。就像我们之前的架构工作台一样,如果一个编辑器不能解决,那就两个。
对应的模式:
下拉框 + 查询语句生成查询条件。
将查询条件转换为 SQL。
执行 SQL 生成新的数据。
过滤数据,返回数据。
于是,在这个版本里,我们通过正则匹配出 name
和 version
,以及对应的值:
field:name == /.*log4j/ field:version > 2.17.0
容易出现问题,一旦用户输错字符时。
在功能实现上,我们借助于 Monaco Editor 构建了一个一行的输入框,即将一个编辑器封装成一个输入框。于是乎,这个输入框变成了一个搜索框,它具备这么一些功能:
语法高亮。方便用户输入各种字段 。
智能感知。在通过下拉框选择对应的类型时,选择对应的感知类型。
主题。虽然,我们还没实现,但是它明显是可以的。
除了,载入比较慢之后,它似乎没有别的缺点。
不过,由于在这个版本里,它是通过正则表达式来匹配的,所以在感知上出现了一些问题。于是,后来我们在新的版本里,重写了查询语言。
在构建这个工具的时候,我们也在计划在未来引入 MongoDB 替换 MySQL。如此一来呢,用户也可以自定义自己的搜索类型,而不是需要编码做 CRUD 的转换。
于是呢,我们在 MySQL 和 MongoDB 中间,创建一个封层,来隔离两者之间的差异,这个就是:Insight Query Language。再论,如何将一个简单的事情往复杂的办。
这里的查询语言是一个非常迷你的 DSL,只支持非常简单的计划。所以,它的模式是:
编写查询语言解析器。
将查询语言转换为 SQL。
执行 SQL 生成新的数据。
过滤数据,返回数据。
从模式上来说,它类似于一个简化版本的 SQL。考虑到 DSL 存在一个学习成本,所以我们一直尝试将文档内建到搜索框中。
从实现上主要由两部分技术实现:文档内建和自动建议 构建。
智能自动建议。为了实现更好的 Completion,就需要做语法分析,根据用户的输入,调整 Completion。诸如于 sca
在刚输入的时候,有 dep_name
、 dep_verion
等不同的字段;当用户输入过 dep_name
时,它就不会出现在下次的 Completion 列表中。不过,也存在一个问题,这些类型如果写在前端的时候,也会造成更新缓慢的问题。
文档内建。通过 Hover 和 Auto Suggest 来降低用户的学习成本。即当用户放在对应的 Literal 类型上,展示对应的提示文本,如支持的格式等。
在这样的折腾中,你或者还观察到了另外一点,更好的用户体验,依赖于更好的技术实现。而更好的技术实现,也意味着更多的技术成本。
欢迎观摩这一部分代码:https://github.com/archguard/archguard-frontend/tree/master/archguard/src/pages/insights