开发笔记 (8) : 策划公式的 DSL 设计
今天很早就起床了,以至于到了办公室还不到 11 点。中饭前有一个多小时可以做各种杂事。
我把周末做的工作和蜗牛同步了一下信息,然后得到了几个新需求。主要就是还是需要在协议定义中加入 protobuf 中等价于 service 的东西。思索了一下,觉得有必要,就花了一个小时把特性加上。 C Binding API 方面还有一点疏漏的地方。大概是源于基于 Erlang 框架下的一些小困难。略微修改了下 C 接口协议就 OK 了。然后很 happy 的去食堂吃饭。
然后我暂时就可以转向 Client 方面的一些需求分析以及解决了。
在生成动画树的数据方面,我们的交换格式使用了某中文本中间格式,最终利用 protobuf 来做二进制持久化。在解析文本格式方面,我操起了多年前耍过的 LPEG 。(我曾经用 lpeg 写过 protobuf 文本的解析工具)这个绝对是解析文本的利器啊。午饭时在食堂大家围在桌子边吐槽 Java ,说道 Java 社区最二的莫过于抓着个 XML 当救命稻草不放,所以便有了各种淡疼的基于 XML 的框架。如果早期 Java 社区能多那么几个受过 Unix/C 传统熏陶过的程序员,就能知道设计 DSL 来解决问题是多么爽快的事情。也不至于在 XML 的树上吊死了。唉,搞得现在积重难返了。
下午正式和策划进行沟通,观看他们这段时间写的各种 excel 表格。我说,你们放开了想怎么把问题表达清楚吧,只要逻辑清晰有条例,信息不要漏掉,怎么表达那些公式都行。我慢慢看,然后规范写法,最终方便程序解析。
以前见过许多项目,有的设计出繁杂的 excel 表格式,然后 export 给程序用;有的干脆让策划写程序代码;甚至有的做一堆漂亮 UI 的公式编辑器。我想最快也最方便达到效果的,莫过于设计一个最小需求集合的 DSL ,让策划认同其语法,然后使用 DSL 来编辑了。
为什么是 DSL 而不是特定语言代码?因为通用语言往往是为了解决更繁杂的需求,有很多多余的语法会干扰策划的思维。他们会将大量时间浪费在学习语言、检查语法错误上。
另外,限制于特定语言也会局限项目的发展。很有可能以后你会换一种方式去解析公式。比如在性能无所谓的时候,你想用 lua 代码就好。但性能敏感了,你又想用 C 实现,等等。有个中立的 DSL ,为以后留下更多的优化空间。
我们把公式定义和计算这个模块的知识依赖尽量的做小了,只依赖一种简单的 DSL 实现。
当然 DSL 的定义也是在不断发展的,这个需要语言设计的经验以及对问题域的理解。这两点我都不太够。只能试试。我相信对于这样一只小团队,是可以承受某种程度的变化的。更何况 DSL 是我自己实现的,当一些重大修改发生后,我可以自己写工具来批量修正历史代码。
我几个小时来了解需求,并定义 DSL 草稿。
策划需要的大概是列出一些可以做基本四则运算的公式,依靠一些变量(通常是人物属性),计算出新的值,赋给新变量。当公式比较复杂的时候,他们希望可以自定义一些函数,这些函数几乎都是 n:1 的。输入 n 个参数,得到一个值。
最常用的两个外部函数(策划往往不像程序那般思维,他们不把数学运算以外的数据处理称为函数,但程序员却这么看,我们也容易灌输这个观念),一是查表。就是在 excel 里做一张单独的二纬表,查询第几行第几列的值。我想了一下,其实最终这个是一个三纬向量:表名本身是一个维度、行列是另两个;其二是随机数。
有了这些,几乎就可以满足策划的所有计算要求了。
但是有些计算还需要有一点流程控制。以某策划同学爱玩的魔兽世界为例,就需要先产生一个随机数,判定攻击是否被躲闪;一旦被躲闪,后面的计算就不需要了。如果不被躲闪,则算下去。当然在 DSL 中设计流程控制也不无不可。但我觉得仅仅是这种需求还没有必要增加它。我想,如果顺序执行每条表达式的功能足够的话,那么最好不要加新的知识。所以我决定向策划推销 bool 运算规则。
毕竟大家都是理科出生,很快就明白了。lua 风格的 and or not 的短路规则很简单,写几个范例大家就懂了。最后我设计了这么一个粗陋的东西。
DODGE := 50 PARRY := 30 CRITICAL := 20 RACE := "战士" LEVEL := 23 DPS := 100 dodge = roll(DODGE) hit = not (dodge or roll(PARRY)) critical = hit and roll(CRITICAL) _critical (race , level) -> table("cri" , race , level) * 0.1 + 1 damage = hit and (DPS * (critical and _critical(RACE , LEVEL) or 1))
里面有一张 cri 表,我先用文本格式表达,以后再花半小时去支持 excel 格式。
10-19 20-29 30 战士 1 2 3 牧师 2 4 6
今天就不在 blog 上解释了,反正日后总要花时间写文档的。等明天先口头教一下我们的设置策划去用。
实现这么一套 DSL 解析大约花掉了我大半个下午。应该感谢 lua 和 lpeg 的便利,100 多行代码就把整个模块和应用工具写完了。主要是要方便策划测试使用。
今天的流水账就先记在这里了。
Comments
Posted by: babam | (18) June 26, 2012 11:51 AM
Posted by: lqk | (17) January 19, 2012 11:37 AM
Posted by: andy | (16) January 18, 2012 06:56 PM
Posted by: zwc | (15) January 12, 2012 11:10 PM
Posted by: starshine | (14) January 12, 2012 01:38 PM
Posted by: Anonymous | (13) January 12, 2012 09:50 AM
Posted by: Scan | (12) January 11, 2012 05:35 PM
Posted by: Cloud | (11) January 10, 2012 11:25 PM
Posted by: 涛 | (10) January 10, 2012 09:09 PM
Posted by: elmar | (9) January 10, 2012 05:20 PM
Posted by: Dean | (8) January 10, 2012 04:39 PM
Posted by: 吕子熏 | (7) January 10, 2012 10:57 AM
Posted by: dandan | (6) January 10, 2012 01:01 AM
Posted by: lichking | (5) January 10, 2012 12:25 AM
Posted by: sheep426 | (4) January 9, 2012 11:35 PM
Posted by: Cloud | (3) January 9, 2012 11:35 PM
Posted by: tiger | (2) January 9, 2012 11:34 PM
Posted by: Anonymous | (1) January 9, 2012 11:29 PM