因为在公司接触业务比较少,更多的是在想办法做一些工具来帮助快速开发,过程中感觉做业务的思路与做工具(系统)的思路差别比较大。下面分享一下在两个模块中的思考过程。
团队做的业务复杂无比,几百张的数据表导致有非常非常多的报表,通常的做法是这样的:
几十张报表开发起来非常痛苦,而且大部分的代码实现的功能都是相似的!说到相似,那么是不是把不同的部分(取数逻辑)独立出来,相同部分进行复用即可:
配置一个数据接口只需要填写一段SQL就可以了!
其他的操作(数据库、返回数据)不需要你再关心了。YY了一下大部分的需求用SQL绝对绰绰有余,这件事情就这样结束了!图样图森破啊!!马上遇到了这样的需求:
{ title : "xxx", data : [1, 2, 3, 4, 5, 6, 7, 8] }
还有这样(一些常量):
[ {text : 'A', value : 1}, {text : 'B', value : 2} ]
于是火速开发了更多的功能组件来解决问题:
组件越来越多,“新手”进来已经不是特别了解每个的具体含义,配置的成本也越来越大。感觉系统用起来并不想当初想的那么美好!
停下来想一下,从一开始的目标:
我要一个可以干啥干啥的功能!
在实现起来没有任何的拐弯抹角,一步到位完成之后没有考虑过:
系统有多少的灵活性、可以从哪些方面扩展?
仔细想了一想,我们对系统进行了简单的改造:
利用GROOVY脚本极大的灵活性,让系统的适应能力也有所提高!虽然花了很多业务时间来研究ACE的功能来提高编辑体验,但是还是有非常多的同一种吐槽:
写脚本的学习成本太高!
更郁闷的是来吐槽的都是“资深”JAVA开发工程师(GROOVY和JAVA不是很像么)!在现在的系统上面只需要实现一个方法:
static Ojbect execute(){ return [1, 2, 3]; }
即可通过RPC或者HTTP获取数据(在底层已经将参数传递等东西都封装完成),作为一个程序猿对这样写一小段脚本就能实现的方式挺亲切的,不明白为啥其他的同是开发对这种方式极其的排斥,以至于我几乎没有机会去讲我夹下来要做的事情。
接下来要做什么呢?
脚本再简单也只能开发来写,那像原来只会SQL的人就用不来这个系统了。
显然不能让这种情况发生,解决办法也非常简单:
比如一个查询数据库的脚本如下:
static Object execute(sql, datasource){ // 1. 根据datasource获取数据源 // 2. 指定sql // 3. 返回执行结果 }
而此时用户看到的配置页面就小白很多了:
保存时会将其填写的信息以及要使用的目标脚本一起保存下来,执行时将参数传给指定的脚本执行即可(是不是有点像带参数的ln)。
将该功能开放给各个业务系统,那么就可以自己去做各自需要的小白配置页面了。
缺前端是个普遍的问题,如果能将前端的开发简化到后端也能参与,也许能在一定程度上得到解决。
首先,把页面上的各个部分抽象成组件:组件=数据+动作+展示。比如带下拉列表的选择输入框:
在使用的时候就非常简单了(一行代码相当于原来20行左右的HTML+JS):
@input(label="仓库" name="warehouse" items=[{text:"A", value:"1"},{text:"B", value:"2"}])
直观上干了两件事情:
那展示呢?这个显然不应该交给用户来操心,比如:
为了达到这种效果,一个组件的定义可以是这样的:
@import( 'bootstrap.css' // 依赖的CSS文件(需要的时候也可以加JS) ) @component this.width = '10px'; // 一些默认的数据 @render // 在render下定义渲染(有点像JSX吧) <ul> for(i in items){ <li>${items[i]}</li> } </ul>
在做的过程中发现一些好玩的问题:
JS的资源不一定适合SEAJS来加载,因为JS之间可能有依赖关系。
渲染DOM的部分类似JSX,但更暴力:支持JavaScript的各种控制结构,但这一点是有代价的。仔细想一下:
JavaScript和HTML的语法之间天然就是彼此隔离的,除了‘<’之外。
那做到上面这种模板语法也就比较简单自然了。到这里组件就变为一个方便定制、高度聚合的东西了!但是光聚合没用啊,需要把他们拼装成一个页面,需要解决:
简单想了一种方案:
举个例子:
@layout// 布局 @input(name="a") @input(name="b") @input(name="c") @button(label='查询')// 查询 @on(click) // 1. 获取a、b、c的数据 // 2. 请求数据 // 3. 更新table、page的展示 @layout @table // 表格 @page// 分页
当点击查询按钮时,根据三个输入框(a、b、c)的内容查询数据并更新表格的展示。最后我们需要将该页面放到业务系统中,做法也非常的‘土’:
<script> engine.init("page", document.body);// 将page对应的页面渲染到body下面。 </script>
渲染的位置你可以随意指定。到这里用法就说完了,下面来看如何实现:
模块很简单,我用SEAJS的方法,但是作了一些简化和定制。组件的操作包括:
HTML的操作包括:
既然想为以后留好扩展性,那么JavaScript作为中间层应该是一个不错的选择,将对应的HTML操作可以翻译成下面几个方法(组件的也类似):
为了处理层次还需要push、pop方法。为了实现这些我们需要一个翻译器:
将生成的JS文件保存到CDN上面,再结合HTTP缓存,性能应该还是可以的!我们继续,在此基础上可以扩展出更多的玩法:
现在是将结果渲染到某个DOM节点下面,那是否可以直接在Velocity中使用某个组件,像这样:
<div> @input(label="xxx" name="xxx") </div>
上面是对后端Javaer敞开大门,那前端工程师是否可以得到好处,像这样:
<script type="text/engine"> @input(label="xxx" name="xxx") </script>
因为每一步前后都没有耦合,你完全可以去扩展自己想要的东西。
远古时期的程序员在实现业务时可能把:取数据、业务逻辑、渲染都放在一个代码中完成,后来逐渐分成几层来做:
不仅结构更清晰,而且在任何一层你都可以选择不同的方案来实现。我们在做工具时也可以参考这种思路,多分几步来做。
那什么是从下到上呢?和上面的分层的角度不一样:
在对一些场景实现工具,根据灵活度和易用性来分成几步来做,这样不同的技术背景的人都可以使用,而且最关键的是可以扩展出更多的使用场景!:-)