前阵子我折腾这个“生命竞赛”的安装包,真不是为了做多大的产品,说白了,就是被上个项目的外包公司给气着了,一肚子火没地儿撒,硬逼着自己把软件部署这件事儿从头到尾捋了一遍。
起因:被一套破烂儿系统逼上了梁山
我接手了一个小小的内部数据统计项目,结果前任留下的那套东西,跑起来简直要命。他们找了个外包,那家伙打包的软件,跟狗啃的一样。运行环境要先装.NET Framework 3.5,再装Python 2.7,然后还得手动设置好几个环境变量,启动的脚本里,路径写死了不说,连个错误提示都没有。
有一次,我为了给新来的同事配环境,折腾了整整一个下午,还是卡在一个莫名其妙的DLL文件缺失上。那个外包公司的技术支持电话打过去,永远没人接。当时我真的火了,拍着桌子想,TM谁规定软件部署非得这么痛苦?这哪是工作,这是找罪受。
我当时就下定决心,哪怕我做的东西再小,哪怕只是个计算器,也必须做到一键安装,点击就用。这才有了后来的“生命竞赛”这个小工具,它最初只是用来模拟我们项目资源分配的风险,名字听着玄乎,就是一堆Python脚本。
实践:从一团麻到单文件
以前我图省事,写完代码就直接把文件夹打包成ZIP扔给别人。现在不行了,我得把那个外包公司踩过的坑,一个不落地避开。我的实践过程,核心就两个字:封装。
第一步:解决依赖的内嵌问题
我用Python写的,最大的问题就是环境依赖。我研究了怎么把Python解释器和所有需要的库都打包进去,不让用户自己去装。我尝试了好几种打包工具,一开始用PyInstaller,结果打包出来的文件太大,而且在某些老系统上跑起来会报错,搞得我来回跑去测试兼容性,头都大了。
- 尝试打包,发现某些旧系统自带的杀毒软件会误报,得手动配置白名单。
- 文件路径的问题。打包工具默认用相对路径,但实际安装后路径会变,我不得不把代码里所有涉及文件读取的地方都改成动态获取当前运行目录。
第二步:制作真正的“安装包”
光是一个可执行文件(EXE)还不够,我要的是一个有界面的、能选择安装路径的、能在桌面创建快捷方式的“安装包”。这才是用户习惯的操作。我琢磨了好久,选择了NSIS这个免费的工具。这个学习过程是真的枯燥,它用的是自己的脚本语言,得一行一行写配置:
我记得最清楚的一次,为了让安装程序能自动识别用户是32位还是64位系统,我写了一段判断逻辑,结果安装程序运行到一半就闪退了。我对着那几百行脚本,盯着屏幕看了快四个小时,才发现是其中一个字符串比较写错了,不是`==`,而是`=`。这种低级错误,我以前写业务代码根本不会犯,但在打包工具里,就是能耗死你。
第三步:下载地址的“生成”和测试
我们没有自己的服务器,所谓的“下载地址”就是我用公司的企业网盘服务,生成的一个分享链接。但光生成链接不行,我必须模拟真实用户的下载过程,进行几十次测试。
我找了三个同事,他们用的分别是Windows 7、Windows 10和一台虚拟机。我把链接扔给他们,让他们从下载到安装,全程录屏。结果发现:
- 同事A的Chrome浏览器会把安装包误判成病毒,直接拦截了。
- 同事B安装完后,快捷方式指向了安装目录里的一个临时文件夹,根本打不开。
- 虚拟机里运行,第一次启动慢得像蜗牛,因为它在解压运行时依赖。
这些小问题,代码里是看不出来的,只有真正经历下载、安装、启动这整个流程,才能发现。我前前后后修改了安装脚本七八次,又优化了打包工具的参数,让它把主要的依赖提前解压,才终于做到秒装秒开。
最终实现:一个干净利落的结果
我的“生命竞赛”项目,就一个不到100MB的安装包文件。用户点击下载,双击运行,五秒钟内,图标就出现在了桌面上,点开就能用,不用管什么运行环境,不用管什么DLL缺失。
我把这个干净利落的安装包扔给那几个曾经抱怨过部署问题的同事,他们都惊了,说这比以前那套动辄半小时的安装流程好太多了。这才是TMD软件应该有的样子。
你看,我做这个项目,最初的驱动力不是什么技术理想,就是被那帮不负责任的外包人员气得不轻。他们搞出来那一团糟,浪费了我多少时间,后来我才意识到,把最基础的“交付”环节做比写什么高级算法都重要得多。至少,没人再因为安装问题来烦我了,我的时间也省下来了,这才是最大的胜利。