前两天一个在设计院干活的朋友找我吐槽,说他年底差点被领导一个问题给问住了。
他们公司用 AVEVA PDMS 做三维工厂设计,这软件你可能没听过,但在石油化工电力这些行业基本上是标配。管道、设备、钢结构、电缆桥架,全在三维模型里搭出来。这玩意有个特点,自带的宏语言叫 PML,Programmable Macro Language,允许你自己写脚本来扩展功能。
于是这位朋友和他几个同事,三年下来陆陆续续写了得有几十个插件。有模型调整的,有批量导出报表的,有自动命名的,有数据检查的,还有各种奇奇怪怪的辅助功能。每次有人来找他说「这个操作太麻烦了能不能搞个一键的」,他就屁颠屁颠地去写一个。
本来嘛,这事挺有成就感的。写工具嘛,别人用得顺手你也高兴,何乐不为。但年底汇报的时候,领导问了一句。
「你们写了那么多插件,到底有没有实际提升效率?」
朋友当时就愣住了。
不是领导在质疑,他问得特真诚。几十个插件,开发加维护花了多少时间,到底哪个用得多哪个没人碰,哪些真有价值哪些纯属自嗨,全是凭感觉。
你说有用就有用吗,数据呢。
没有数据的时候,所有判断都是在猜。
于是我干了件特实在的事。花了半天时间,写了一个 PML 函数,专门统计每个插件的使用次数。然后把这个函数嵌入到所有已有的插件按钮事件里,静默记录,对使用者完全无感。
不搞数据库,不搭服务,不装任何第三方依赖。就靠文件系统,纯文本 CSV。
坦率的讲,我现在回头看这个方案,第一反应是,这也太朴素了吧。
但转念一想,这不就是最好的方案吗。
你要的是什么,能用、好维护、领导能看懂。数据库还得装环境、配连接串、写 SQL 查询。CSV 呢,Windows 上双击就是 Excel,领导自己能排序筛选拉透视表,你还不用单独写一个管理后台。
真的就是,简单到极致反而最优雅。
说说这个函数是怎么实现的吧。
首先是身份识别的问题。同一个插件可能被不同人在不同电脑上用,你得知道这条使用记录是从哪台机器产生的。我用了一个特别巧妙的方法,读 CPU 的 ProcessorId。
!cpuidfilename = !userfile + '\ProcessorId'!cpuidfile = object file(!cpuidfilename)if(!cpuidfile.exists().not())then syscom 'wmic cpu get ProcessorId | find /v "" > $!cpuidfilename'endif!cpuidarr = !cpuidfile.readfile()这段代码逻辑特简单。先看看用户目录下有没有存过 ProcessorId 文件,没有的话就用 Windows 自带的 wmic 命令获取 CPU ID 存下来,下次直接用。每块 CPU 的唯一标识符,天然就是一个机器指纹。
不用自己写 UUID 生成算法,不用联网验证,一行系统命令就搞定了。
拿到机器指纹之后,下一步是拼记录。每次插件被调用时,函数自动抓几个关键信息,当前项目 ID、当前登录用户名、格式化后的时间戳,然后跟插件那边传过来的参数拼到一起。
!recordarr = !input!recordarr.insertarray(3,!currentinfo)!record = ''do !x from 1 to !recordarr.size() !record = !record + !recordarr[$!x] + ','enddo这设计我自己觉得还挺聪明的。函数接收一个数组,前几项是插件自己传的,表单名、按钮名、清单行号,后面还可以塞自定义内容。然后函数在第三个位置把自动采集的项目 ID、用户名、时间戳、计数插进去,最后遍历数组拼逗号分隔字符串。
插件那边完全不用管统计的事,把自己是谁、被点了什么按钮传进来就行,别的全交给这个函数在后台静默处理。
CSV 写入的部分就更朴实了。
if(!usagecounterfile.exists().not())then !title = '插件名称,按钮名称,项目代号,用户名称,按键时间,按键次数,清单行数,附加内容1,附加内容2,附加内容3' !info.insert(1,!title) !usagecounterfile.writefile('OVERWRITE',!info)else !usagecounterfile.writefile('APPEND',!info)endif文件不存在就新建,先写表头再写数据。文件已存在就直接在末尾追加一行。文件名用的是 CPU ID,所以每台电脑一个独立文件,这台电脑上所有插件的使用记录全归在一起。
你想想看这个设计有多干净。
不用管并发写入冲突,因为每台机器只写自己的文件。不用做数据清理,CSV 那点存储量几乎可以忽略。不用写前端界面,Excel 就是你最好的分析工具。
而且最让我觉得满意的是,它对原有插件的侵入性几乎为零。
在任意一个插件的按钮回调里,就这几行。
!counterarr = array()!formname = !this.name()!buttonname = 'xx按钮名称'!counterarr.append(!formname)!counterarr.append(!buttonname)...!!lyusagecounter(!counterarr)建个数组,填入表单名和按钮名,调一下函数。没了。插件原本的功能一行代码都不用动。
到了年底的时候,打开服务器上的 UsageCounter 文件夹,几十个 CSV 文件安安静静躺在那里。全选导入 Excel,拉个透视表,每个插件的调用次数、使用人数、按项目分布、按月份趋势,全出来了。
哪个插件是真正的效率担当,哪个插件写完之后就尘封了,一眼看穿。
领导看完不光没再问「到底有没有用」,反而主动说要多投点资源做插件开发。因为数据就摆在那,好的插件一年被调用了上千次,每次省五分钟,一年加起来就是几百个小时,换算成人力成本,投入产出比清清楚楚。
这个事让我琢磨了很久。
我们写代码的人,尤其是做内部工具的,特别容易掉进一个坑里,就是「我觉得这个东西很有用」。工具是你写的,你用当然顺手。同事当面也不会说不好用,人情世故嘛。久而久之,你可能一直在维护一个只有你自己在用的东西,还觉得自己做了天大的贡献。
不是说你不努力。真的不是。
是没有那个反馈的闭环。
你不知道有多少人用过,不知道他们在什么时候用,不知道用完之后是不是真的省了时间。你只管写,写完就扔出去,然后期待它自己产生价值。这不叫交付,这叫许愿。
而这个反馈闭环,其实不需要多复杂。
就像这个函数一样,五十行代码,不用数据库,不用框架,甚至不需要单独部署。就静悄悄地挂在每个插件后面,像一个沉默的记账员,一笔一笔地往下记。
但到了年底,它产出的那几张 Excel 透视表,比任何口头的「我觉得很有用」都有说服力一百倍。
数据不会撒谎。好用的插件数据会替你说话,不好用的插件数据也会诚实地告诉你,兄弟,该优化了。
说到底,工程师的价值不是看你付出了多少努力,而是看你的努力在真实世界里改变了什么。
而衡量影响的第一步,不是汇报,不是演示,就是开始记录。
我有时候觉得,这可能就是这个小小的 PML 函数教会我的,最重要的一件事。
完整源码我已经放后台了,有需要的朋友关注公众号,回复「配管提效」就能拿到。
以上,既然看到这里了,如果觉得不错,随手点个赞、在看、转发三连吧,如果想第一时间收到推送,也可以给我个星标⭐~谢谢你看我的文章,我们,下次再见。
夜雨聆风