在典型的编程中,几乎失去平衡的方面之一是对最终用户体验结果的忽视。我们都花很多精力去编写优秀而有用的程序;但是,把这些程序交付到用户手中这件事却是我们开发者做得最糟糕的标志性事情之一。在这个月中,Cameron 将讲解解决这个问题的技术性办法。
您的组织投资了很多 ― 可能是为期一周或十五个月的工程时间或 385,000 美元的许可费 ― 到某个软件上。这个软件在您设置的演示主机上运行得非常不错。然而,当最终用户设法从中获益时,获得的却只有沮丧:惹人心烦的不正确安装,神秘复杂的配置,不可再现的信息读取失败,或者程序根本就什么也不做。
有些事错误得非常严重,而且非常离谱。我给计算技术的这一方面贴上的标签是“部署”。当某个软件在您的屏幕上时,您的老板或客户说,“我喜欢这个东西!”,从此时一直到最终用户打电话或写信来说,“这正是我们一直在等待的东西。”,这期间发生的所有事情都是部署。
从原则上说,那只是一个简短的步骤。部署不是一个像算法理论、网络负载分析或者甚至是需求获得那样深奥难懂的问题。然而,作为一个产业,我们总的来说对部署重视不够,处理不当,投资也不足。其后果不难想像:软件开发中一些最严重的浪费都与部署有关。本月的“服务器诊所”将为您讲解如何能在您自己的工作中做得更好。
具体示例
首先,我们来看一个示例,以对部署涉及到什么有个一般的“感觉”。假设您曾与某化学专业的同事合作开发一个有趣的水泥养护计算机仿真程序。您们两个对该程序在您们的开发服务器上的表现颇引以为豪 ― 程序能处理各种大气情势以及地面状况等等。真是棒极了!
但是,与其他工程师合作共事并不像您预想的那么顺利。所安装的 C 和 Qt 运行时库的一点点改动就会产生莫名其妙的结果,甚至会导致进程异常终止。有些对等机在 AXP 上的 Linux 可以运行,但在 Intel 上的 Linux 却不行。有一位研究人员,他为之工作的组织要求所有的安装都必须装在 /var 目录下,而 /usr/local 下则不可以装任何东西。
好消息是,该工作组的每位成员都有了 Linux,不需要坐在位于瑞典和南非的键盘前就可以完成安装。坏消息是,即使有了远程登录,每次交付程序所花费的时间平均下来还是要半个小时以上。要不了多久,您安装程序所花费的时间加起来就会超过第一次实现程序时所用去的时间。
真正令其糟糕的是这种情况很具有典型性。信息技术(IT)文化已经约定俗成地容忍了这类灾难。我们承认安装是脆弱和易出错的。
但是,您可以不接受它。这里是使事情有所不同的办法:
部署的原则
不要从购买安装产品入手。有几个事项都很有价值,其中理解更具有决定性意义。
需要理解的最重要的事项是,与计算技术的许多方面一样,良好的部署也始于良好的分析。对于上面所述的示例,您若想要取得成功,就得要求自己写出明确的需求,例如:
应用程序应可以作为一个单文件映象进行传送和安装。
应用程序应可以在任何配置有 glibc 2.2-2.2.5 的 Intel Linux 主机上运行。
应用程序应不要求装有其它的库(如 Qt)。
应用程序在第一次注册期间必须具有 IP 连接。
当应用程序检测到它的某项要求未得到满足时,它会写一条明确的诊断信息到控制台,然后得体地退出。
还有其它……
为贯彻执行这些编写要求,我喜欢从第一天起就让安装过程保持是可执行的。请考虑一下著名的极端编程者(Extreme Programmer)(要了解背景情况,请参阅参考资料),他们须在实现要被测试的应用程序之前编写测试。同理,我会在那些测试之前至少编写一些简单的安装。通过使安装具有可回归性,我就可以确信,在任何时候,我都可以可靠地以低廉的代价把我的开发的任何版本安装到某个客户的机器上。
我属于同意这一点的少数派。许多组织都把大量投资投到了前端分析、框图绘制、培训以及开发的其它方面上,却只在开发周期的后期才偶而让程序员们去探察有助于部署的编译器、交叉编译器、许可证管理器以及其它工具。就我所知,还没有人对每种办法的可取之处进行过正式研究。而本专栏所能提供的只是澄清各种看法。我自己的工作证明了从一开始就把部署计划考虑进去是有可能的。我的经验使我确信,这是一种更好的工作方式。让您的选择成为一个明确的选择吧,而不只是保持过去的做法的结果。
部署的重要观念
除一般的管理原则 ― 计划、使事情明晰、对比成本和收益 ― 之外,部署还涉及几个您要学习的特定观念:
没有安装程序能够解决所有问题
部署可能涉及把软件交付给 6 位移动技术专家,或者是安装到位于一幢建筑物内的 1,800 台台式机上,或者是交付给遍布于全世界的 300 个最终用户。部署的对象可能是一组完全相同的硬件,或者也可能每台主机都有所不同。
不要指望哪个部署系统能很好的适用于所有这些场合。但也别灰心;尽管问题可能比您一眼看上去要严重,但基本上是肯定可以解决的。在这一点的考虑上,存在的一个危险是,组织轻易就会试图通过准备好一个简单的答案来解决这些问题,有时甚至连问题都还不知道。
有时,热心人会说使用 Java,或者某种特殊的动态链接模式,或者软件仓库(software depot),或者配置管理产品,或者其它技术窍门均应该能解决部署问题。然而,这些办法没有一个是放之四海而皆准的。它们的成本和收益各半。请考虑一下共享对象库。假设您的一台服务器上有 79 个全都有缺陷的应用程序,原因在于它们都依赖于发生故障的系统 printf()。有了动态链接,您就可以只更新一个 C 运行时库,然后修正所有 79 个应用程序的共同问题。不过,这个方案要求所有应用程序使用库的同一个版本,或者至少有一些新的过程来管理库的版本。更糟的是,您的针对最终用户的安装过程必须既管理应用程序可执行文件,又管理任何它所依赖的共享对象库。这恰好导致了 Microsoft Windows 管理员们称之为“DLL 地狱”的一类组合式复杂性。
更新问题
在您认真仔细地把您的部署要求写下来的时候,对更新问题要给予特别的关注。当更新一台安装了您的软件的主机时,将会发生什么?如果现有的安装来自于某个不同的版本,将会如何?单台主机的不同用户可以看到不同版本吗,还是整台机器上应该只有一个版本?
程序、数据和配置
考虑部署和安装的一种富有成效的方法是从以下三个方面进行考察:
程序
数据
配置
假设您负责的是一个文字处理器应用程序。要称心如意地安装这个应用程序,您需要
将程序装到合适的地方
保护用户已经编制好的任何文档
识别出环境首选项、字体、宏、显示颜色以及用户所创建的其它交叉文档约定
安装产品极少能做到“取出即可用”,原因之一是上述三个方面的每一个很可能有一个不同的更新生命周期。
不管这听起来有多么苛刻,还是请您记住,在开发的早期就找出这些要求要明智得多。
利用文件系统
面对这么多的困难,您如何取得成功的结果呢?首先,请让事情保持简单。对于大多数的开发,我都放弃了复杂的组 ID、信号处理以及其它一些次要的事情;许多站点并未合理管理这些事情,而试图去“纠正”其模式,如此便只会加重您自己以及您的客户的挫折感。
非常适合于部署的一种模型是文件系统模型。请利用它。尽管有缺陷,但文件系统的用户界面至少是多数最终用户所熟悉的。我强烈建议安装单文件的可执行文件(无附加动态库之类)或者那些将其本身解包至单个目录下的映像,其原因就在于此。这些简单的方案使用户有可能知道究竟是否安装了某个产品、如何卸载该产品以及如何对其进行备份。
采用简单的面向文件系统的安装这种倾向的存在使得我最欣赏的部署技术 ― 商业安装程序(commercial installer)、自解包二进制随附软件、“脚本化文档(scripted document)”以及“虚拟文件系统(virtual file system(VFS))”― 自然也会得到一点偏爱。脚本化文档和 VFS 是宏大的主题,值得开辟它们自己的专栏。现在我将给出简要的定义,提供一些在线参考资料,您可以从中读到更多信息,将来的“服务器诊所”专栏将提供关于这些话题的更详细信息,到时也欢迎您回来。
脚本化文档
“脚本化文档”是独立顾问 Jean-Claude Wippler 给他发明的一种文件格式所贴的标签。他分两部分提供应用程序:一个与应用程序无关的、特定于平台的可执行文件,另一个是与平台无关的、特定于应用程序的“脚本化文档”,这个脚本化文档随附有可执行代码、用户数据以及一些持久性方法。这些脚本化文档用起来很方便,至少对于我所碰到的许多部署情形是如此。就像文件系统中的普通文件一样,它们可以被复制 ― 甚至复制到操作系统上,除了 Linux!― 重命名、删除、备份,以及进行其它操作。同时,这些文档包括了较为传统的应用程序分布在安装文件或目录中的所有信息。
在“服务器诊所”回来讨论这个主题之前,您可以在下面的参考资料中读到一些我的关于脚本化文档的摘记。同时,请记住,部署是一件要做正确的很重要的事,而要把这件事做正确,第一步就是给要求编写文档。