分类:
2008-04-14 15:33:50
一个关于 PHP/Oracle 开发模型如何在 Myers Internet 缩短应用程序生命周期的案例研究。
对于主要由应收款业务模型驱动的公司而言,其核心的业务功能之一是输入、跟踪和记录订单。在这方面比较出色的公司可以伸缩它们的机构,并提高它们的利润,而不会遇到基础架构的限制。当订单处理很麻烦、容易出错或不一致时,公司将因为直接的成本和降低的生产效率而蒙受经济上的损失。
在我的公司 Myers Internet,核心的业务事项围绕着建立客户基础,为 Myers 提供持续的服务并帮助它在客户问题出现时解决问题。公司正使用许多不同的系统来处理订单输入和实施周期的各个方面。这些系统既不是彼此集成的,也不具备确保每一份订单都得到正确记帐的机制。
Myers 订单跟踪系统 (MOTS)
就像其它许多机构一样,Myers 从一个小型公司成长为一个中型公司,同时在它的整个成长期间始终保留了相同的过程和系统。大多数这些过程在建立时,所有的事务处理都通过电子邮件、纸质记录和实地拜访来人工地完成。5 或 6 年前,Myers 的一个工程师利用 Allaire 的 Cold Fusion 和一个 Microsoft SQL Server 数据库组装了一个系统来跟踪订单实施,这个系统称为 MOTS (Myers 订单跟踪系统),它允许销售和帐目管理部门输入订单,然后由支持、工程、设计、信息系统和会计部门实施这些订单。虽然这个系统是向前迈进的重要的一步,但它仍然留有许多人工的步骤,并且没有和任何其它的业务系统集成在一起。
大概在同一时间,还创建了一个系统,在这个系统中客户和销售代表可以在线订购 Myers 网站的产品。这个系统可以创建新的 Web 站点,并计算提供的 Web 站点程序包的安装和重复性费用的总和。然后它发送电子邮件给各个部门,各个部门可以将订单输入到 MOTS 中,并在帐目管理系统中创建记帐信息。
体系结构障碍
这种类型的体系结构饱受几种系统问题之苦。在 Myers,较明显的问题之一包括启动订单跟踪所需的人工数据输入,以及作为这种人工过程的结果而产生的错误。另一个问题是公司中的订单输入、订单跟踪和记帐系统之间的脱节、订单丢失、信息遗漏和其导致的错误。
另一个仅偶而出现的问题是 MOTS 系统本身有内在的缺陷。由于编写 MOTS 的方式,可以输入没有部门分配信息或者丢失了部门分配信息的订单。当这种情况发生时,订单最终将在系统中丢失。当订单丢失时,准确、及时的记帐就更难实现了。
随着业务的成长,体系结构中的缺陷变得越来越明显,并且随着客户和订单数量的增加,丢失和错误输入的订单出现的频率越来越高,从而给公司收入带来了难于估量的影响。此外,人工输入的数据的数量导致了延迟和处理效率低下。
由于在实施机构内对收入的影响加大和效率降低,很明显必须要有一个替换系统来将一切联系起来,并提高效率和降低错误率。旧系统图示如下。
该图显示了需要人工数据输入的所有区域。由于这些系统都不是集成的,所以数据丢失或失真的可能性非常大。全局需求马上变得明显起来。
虽然一个好的订单输入和跟踪系统可以帮助降低成本,但它本身并不创造收入。
深入结构
在开始模式设计之前,需要解决一些基本的体系结构问题。第一个底层的技术需求是系统必须可配置,且无需额外的编码。本质上,这意味着需要把工作流嵌入到数据库中,而不是用解释/处理代码来进行硬编码。第二,数据库需要包含足够的信息,以便能够表现订单输入界面的主要(和可更改)的方面以及实施处理。
在努力解决上述问题的过程中,该系统逐渐适合于两个部分 — 订单输入和订单跟踪,并在两者之间提供了明确定义的联系。订单输入系统需要知道如何用准确的产品代码、折扣和定价条款来表示订单。订单实施系统需要知道如何跟踪各种类型的任务、相关的作业和各个部门,以处理和记录每份订单。最后,需要定期和可预测地把订单转化成实施作业。下图显示了目前存在的新系统的结构。
该图显示了通向新的订单系统的所有信息路径,新的订单系统位于后端的门户管理站点。所有的初始数据输入都仅一次性完成,并且只需要每个小组在处理的各个阶段验证数据。通过引入从订单系统到帐目管理系统的自动数据传输,至关重要的数据传输的另一个主要的领域也变为自动化。
依赖 PHP
在纯技术的层面上,早期决定使用 PHP 作为主要的开发语言和 Oracle 作为系统的数据信息库,这有几个主要的原因。首先,Myers 现有的后端门户几乎完全是用 PHP 根据一个现有的 Oracle 数据库编写的,这消除了一个产生不兼容性的潜在来源。这还意味着要创建这个新的系统,Myers 可以利用自身的能力,这些能力创建了现有的后端门户。
第二,实验测试显示,与其它开发语言相比,PHP 提供了一个比较高的性能水平。因为 PHP 是作为一个动态加载的资料库驻留在 Apache 服务器内部的,所以每一次与系统连接都无需额外的启动时间。此外,PHP 优化的改善(通过 Zend 项目)意味着在代码内部执行的一般操作不会明显变慢。最后,为 PHP 编写的 OCI 接口模块是用 C 代码编译和优化的,这使得访问 Oracle 数据库非常高效。
第三,我们了解到因为 PHP 代码将其自身嵌入到了 HTML 环境中,所以对于设计人员和编程人员而言,创建协作用户接口功能代码变得更加自然。虽然最后这个特性其它的服务器端脚本语言也具备,但 Myers 发现 PHP 更不可能带来开发人员和设计人员之间的冲突。此外,PHP 的语法和提供的代码库意味着它可以做它需要做的所有事情。
最后,将所有代码嵌入到 HTML 代码中的另一个好处是,仅需要对标准文本文件进行修改控制就可以控制源代码。我们用 CVS 作为它的标准修改控制系统。因为 PHP 代码不一定要用某一种方式进行编译,所以创建系统的一次“编译”仅涉及到从信息库中检索文本源代码文件,然后把它们放到 web 服务器上。这意味着我们可以使用 CVS 中的控制机制为它的测试和生产环境发布增量的 bug 补丁,而无需创建复杂的编译系统。
设计模式来支持可重新配置性
下面的基本模式示意图显示了订单系统是如何构建的。两种主要的模式都分为原型表和事务表。无论何时当业务情况发生变化时,原型表都允许重新配置系统,而无需重新编码。事务表包含实际客户订单的订单详情和作业详情。
这些模式示意图看起来很复杂,当然,它们的确很复杂。不过,如果把它们分开,使得只出现原型表(以 _def 结束的表),那么该体系结构的基本结构就变得很清楚了。订单由行组组成,这些行组包括详细信息、订单行或两者。订单行可以随意地创建作业,作业由一个任务序列组成,并且包含几条详细信息。必需要为各种任务输入这些详细信息。任务出现在不同的队列中,这些队列可以由不同部门的特定用户进行访问。
为了检验系统,策略是分阶段将订单系统原型化。系统要检验的第一部分是它单独从订单原型表中创建一份清楚的订单的能力。一旦完成了最初的模式定义,订单生成器就是原形化的系统的第一个可视部分。
为构建和配置这个系统而组成的小组除含受这个系统影响最大的各个部门的经理之外,还包括三个开发人员。开发人员的分工分别为:构建配置功能、显示功能和事务处理功能。在整个最初的构建周期内,部门经理提供了关于界面(这些界面使用户能够输入和处理数据)类型的有价值的反馈。
利用 PHP 绘制用户界面
要原型化的初始订单是基本的 Web 站点订单,在 上提供。得到的订单是由一个开发人员用 PHP 在三天的时间内创建的。如果订单原型定义 — 依靠只在数据库和浏览器之间的一层 PHP 代码,就能够完全定义订单输入的外观和行为,那么在数据库设计中需要一定程度的折衷。为此,诸如订单行组之类的结构必须支持两个用途:(1) 在输入表单上提供可视化的区分,以使类似的产品组可以绘制在一起 (2) 从功能上对类似的商品分组,比如说打了一定折扣的商品,或一个选项列表,从中可以作出唯一的选择。
因为 PHP 是开发语言,所以原型组建相当快速,从而可以快速地完成模式所需的修改并且为表单生成器重新编码(一前一后)。此外,因为模式是考虑了绘制的用户界面而设计的,所以当在原型构建过程中出现新的可视化需求时,可以容易地进行模式修改和改编。生成的表单外观与下图相似:
创建一个功能完全的系统
在提供订单之后,需要使它变得功能完全。首先,系统需要保存在订单中输入的用于事务处理的订单数据。第二,填写订单的人需要能够根据正在进行中的订单数据来填写订单。第三,对于在提交时需要付款的订单,一个支付过程是必需的。最后,提交的订单需要创建必要的实施作业和它们的任务依赖性。
PHP 开发提供了快速周转时间,允许在两周的时间内,从外观和功能上将系统的整个订单输入部分原型化。这使得对系统体系结构和它的实现可以作出快速反馈和反应。快速周转意味着问题能够在系统在每个人的脑海里仍记忆犹新的时候得到解决。此外,因为在 UI 和后端(如中间层服务器)之间没有额外的代码层,所以创建原型的过程需要的开发步骤和开发人员更少。
一旦能够从事务上创建作为订单的结果的作业,订单实施周期的各个方面就能够得到创建。作业实施过程主要集中在两个 UI 屏幕上:任务分配和任务处理。任务分配页面包括查看队列中未分配的任务(用户能够访问这些任务)以及显示分配给用户的任务(这些任务需要处理)。
开发周期中,对使整个系统保持一致非常关键的一部分是搜索可以提取到代码库中的常用功能。存在几种情况,在这些情况下特定的子功能和数据节点需要在多个页面上使用。无论何时当开发人员发现他们自己在一个接口页面上执行的一系列步骤实质上和他们在先前的一个接口页面上所执行的步骤相同时,就应该评估将这种功能提取到 PHP 代码库中的好处。
任务处理页面需要显示来自订单的相关详细信息和作业的详细信息、以及由先前的用户完成的任务和必须由当前用户完成的任务。这个页面作为一个初始的原型被快速组装起来,但在它真正变得对将要每天使用它的用户有用之前,需要经过若干次演进。
任务处理页面上的最复杂的操作与实现关闭任务的所有数据库步骤有关:
虽然这种逻辑可能已经放在 PHP 代码中了,但因为 Perl 脚本将用于一些自动任务处理,所以决定以一种通用的形式来执行这些操作。对于任务关闭过程,所有的操作都只基于数据库,因此用 PL/SQL 来编写这个过程是合理的。这允许需要关闭任务的任意编程语言调用一个一致的过程来执行所需的所有数据库操作。
自动任务系统是用自动任务定义表作为配置和自动任务运行表作为事务表为各个自动任务而创建的。因为自动任务需要做诸如调用先前编写的 CGI 脚本等事情,所以我们确定 Perl 能够实现所需的所有技术细节。可快速提供的 Perl 模块的巨大资料库允许各种类型的操作,从而提供了所需的全部灵活性。系统本身包括一个服务器进程,该进程驻留在一个每分钟唤醒一次的系统上,以搜寻待处理的自动任务。如果找到了任意的待处理自动任务,就利用相关的任务详细信息和自动任务配置参数来执行它们。自动任务成功或失败都将被记录到数据库中。当自动任务成功时,调用必要的 PL/SQL 过程来关闭任务。
将原型组装在一起
一旦系统拥有了所有主要部分的功能原型,就可以和所需的所有订单类型以及所有当前的商务实施周期配置在一起。订单原型包括新客户订单、现有客户订单和特殊订单。新客户订单一般由销售代表来输入新客户的详细信息,并且通常要求预付安装费用。现有客户订单涉及到从 Web 站点升级到完全和部分取消,再到服务和记帐修改的全部范围。特殊订单一般涉及到仅可由相对高级的人员订购的产品。
随着配置得到创建和系统开始成形,PHP 的快速开发时间的优势再次证明了它们的价值。当这种需求(任务处理页面不仅需要显示当前作业的详细信息,还需要显示作为同一订单一部分的所有其它作业的详细信息)出现时,在仅仅几天的开发和测试之后就增加了那种功能。当需要一个新的自动任务,以使一个作业保持在休眠模式,直到一个特定的日期或直到一定的天数过去之后时,开发、测试和部署仅在一周内就完成了。
在系统配置开始之后变得明显的另一个系统优势是,任务依赖性配置以一种易于查看和调整的方式清楚地显示了当前的业务过程,特别是那些跨部门的业务过程。将数据库依赖性信息与一个来自 AT&T Research Graphviz 程序包(参见 )的名称为 “dot” 的程序包结合意味着实施周期可以根据动态的配置数据进行图形化显示。下图是安装一个 Web 站点程序包所需的作业实施周期的一个简单的示例图。
除事务处理页面之外,系统收集的各种量度允许生成更多的业务过程报表。在业务需求出现和变化时,可以创建和修改基于订购的产品的收入报表和关于订单周转的实施报表。这些报表可以用 PHP 通过标准的 HTML 输出来创建,或者用 Perl 来编写,以按需要创建 Excel 电子数据表。利用 Oracle 的分析和分组功能创建概要视图实现了报表的一致性以及为数据库管理员提供了一种容易的方法来执行优化。
项目时间表
系统开发从 2003 年 5 月开始。到 2003 年 6 月,主要的系统组件全部完成,系统最后的和完整的配置开始。到 2003 年 7 月底,系统全部完成配置,内部培训开始。自 2003 年 8 月以来,系统一直处于生产模式,并且已经为大约 2,000 个客户处理了 4,000 多份订单,以及 6,000 多个实施作业和 20,000 个已完成的任务。自从系统创建以来,用户能够创建新的订单和作业原型,而不需开发人员的介入。此外,现在将配置该系统来充当一个客户故障单系统,且只需新的配置,无需新的编码。
一个灵活的体系结构与快速的开发周转的结合使这个系统成为了一个成功的系统。虽然这个系统可以用几种不同的方式来创建,但我们的选择意味着可以用非常高的灵活性和非常低的开发成本来快速地创建这个系统。
下表显示了创建每个组件和使它们进入生产设置所需的开发时间(以开发人员工时为单位)。此外,它还在适当的地方指出了创建被新订单系统所取代的那个系统所花费的开发时间。
组件 | 新系统开发时间 | 旧系统 |
Web 站点销售订单 | 32 个开发人员工时 7 个业务配置工时 |
200 个开发人员工时 |
升级订单 | 35 个业务配置工时 | NA |
作业分配表单 | 12 个开发人员工时 | 40 个开发人员工时 |
作业处理表单 | 72 个开发人员工时 15 个业务配置工时 |
240 个开发人员工时 |
作业会话日志表单 | 12 个开发人员工时 | NA |
每小时记帐跟踪表单 | 8 个开发人员工时 | 24 个开发人员工时 |
生产效率报表 | 48 个开发人员工时 | NA |
委托报表 | 6 个开发人员工时 | NA |
收入报表 | 40 个开发人员工时 | NA |
销售报表 | 24 个开发人员工时 | NA |
吸取的教训
从这个系统的体系结构和实施中吸取的主要教训是快速周转在这几个方面 — 创建功能原型、创建 UI 配置和 UI 代码之间的紧密集成,以及保持这个系统尽可能多的部分是可配置的而不是需要编码的 — 中的重要性。本文清楚地演示了在 PHP 开发模型的简单性和系统中的灵活的原型配置之间的时间上的最短距离,以及最初的概念、功能原型和生产系统之间的相关内容。