在 Wolfram 语言中构建大型软件系统

在 Wolfram 语言中构建大型软件系统应遵循适用于构建任何大型软件系统的一般原则. 细节可能是 Wolfram 语言独有的,但许多原则是相当普遍的. 此外,还有一些技术特别适用于 Wolfram 语言. 您应该知道这些,并利用它们.
这些原则不仅对快速原型系统的开发工具有关,而且对任何开发过程都是相关的. 和这些原则相关的系统包括:
把系统分成各个组件
您应该把系统分成各个组件,这可能是需要遵循的最重要的原则. 如果您有一个满意的和自然的划分,那么不需要太多的努力就会获得许多好处. 几乎总是有一种自然的方式将事情分成不同的组成部分. 您应该找出这些组件,并把它们建成一个独立的子系统.
以下是为什么分成组件很有用的原因:

组件可以更快地开发出来

单个组件简单且易于理解,它们需要实现较少的目标,需要较少的执行. 因此初期只需编写较少的代码,后期只需处理较少的代码. 这对于刚开始开发项目的新手尤其有用;无需学太多,便可出成果.

组件可以独立开发

如果您有一个开发小组,可以把项目划分成小部分,并利用组员的专业知识和技能. 把数据库部分分给懂数据库的,如果他们不懂微分方程,就不要让他们接触到需要微分方程知识的代码.

组件可以独立测试

测试,作为开发过程中的一个集成元素, 是软件开发成功的一个重要组成部分. 组件划分对测试过程有极大的帮助. 一些组件,比如用户界面,就非常难以测试,但是其它的相对比较容易. 因此如果系统划分成组件,测试就更容易完成. 另外,当有测试失败时,测试单个组件会更快确定是哪一组件导致错误,所以可以更快地解决问题.

组件可以被替代

开发是一个连续不断的过程,更改是相当普遍的,例如,有新的需求或新的技术出现的时候,常常需要做一些改动. 划分组件有助于切换到另一种新的实现方式. 例如,新类型数据库的出现. 如果所有的连接都属于数据库组件,这将使其更容易更换成一个新的组件.

组件可用于不可预见的方式

划分组件有更多的灵活性. 例如,如果您有一种特殊的方式做插值,另一个应用程序可能需要使用它. 如果这是自己的组件则很容易提供给其他应用程序. 另外,对于那些划分拙劣的应用程序,您就可能想简单的复制执行过程. 这样很糟糕,因为您最终会有两个同样的副本,当有错误或加新功能时,您需要同时修改两个地方. 另外,如果您只改了整个应用的一部分,就会出现另一个问题. 而且糟糕的是:可能有知识产权,商业秘密,或许可证的问题. 最好的办法是只提供想要的组件.
使用组件的另外一个例子是可以更容易地切换您的系统到 webMathematica 语言的网络传输系统.
考虑体系结构,而不是代码
这和划分成组件的原则是密切相关的. 这就是说,您应该去想想系统的整体,尤其是其组成部分,而不是所有的代码的细节. 如果您为项目提供一个很好的体系结构,则代码将很容易遵循. 创建好的体系结构比写代码还难. 许多人即使没有大量的训练或经验也可以编写代码. 此外,差的代码比差的体系结构更容易对付.
有一个原则说,建立一个系统的最后一件事情是是编写任何代码. 您应该尽可能的避免实际编码. 相反,您应该专注于您的体系结构,做测试和编写文档. 太多的开发人员认为他们应该投入地并疯狂地编程;最好的办法是停下来想一想他们要构建什么.
使用 Wolfram 语言代码封装
Wolfram 语言的许多功能都可以把代码分成程序包和应用程序. 重要的是,您要充分利用这些. 在许多情况下,您应该把您的所有代码放到一个程序包中,以 BeginPackage 开始,以 EndPackage 结束. 您的软件包应该被集成到一个应用程序中:这是递交您的应用程序的方式. 一个例外是 Wolfram 语言演示项目的捆绑机制.
设置程序包和应用程序需要一点时间,但是 Wolfram 语言提供了实现这个目的的工具,如 Wolfram Workbench. 他们提供了很多的生产功能,极大地促进 Wolfram 语言的软件开发工作.
使事情简单化
这一原则大部分涉及到实际执行. 建议最好是写小的函数,使用简单的语法来表达. 这在具有极为丰富语法的 Wolfram 语言中尤其重要. 这也是一个好主意,受益于 Wolfram 语言支持的非常文学化编程风格.
另外,要避免产生奇怪的控制结构,如重载(overloading)BeginPackageEndPackage,这是 Wolfram 语言的一个有趣的功能,不过最好避免使用这种情况. 对于那些从系统角度看问题的人来说,这是一个障碍,它们也将限制您的代码的功用.
使用源代码控制
任何系统,您要是使用和工作超过一天,应有源代码控制. 如果有多个开发人员或项目开发生命周期超过数个月的时间,这就变得很关键.
源代码控制系统的例子包括 CVS、SVN 和 Rational ClearCase. 它们提供诸如存储组件文件的不同版本、记录文件变化的原因说明、标签发行版本的文件组、比较不同版本的文件、合并变化等的一般功能. 源代码控制主要是被开发小组使用,但对于单一开发人员开发项目也非常有用.
Wolfram Workbench 包含一个 CVS 客户端,并正在更新,以包含 SVN 客户端. 它可以在更新后包含大多数其他源代码控制系统的客户支持.
若要使用源代码控制,您需要访问源代码服务器或存储库,这些很容易在自己的机器上和公用机器上设置. 请注意,这仅适用于源代码可以公开的应用程序. 此外,许多组织把提供源代码控制作为其标准的 IT 基础设施的一部分.
除了源代码控制,也有建立系统和配置管理的工具. 这些与您的源代码控制一起构建可以发行给最终用户的应用程序版本.
编写文档
有许多不同的方式编写应用文档,这取决于用户.

终端用户文档

Wolfram 语言提供了一个可以和 Wolfram 语言应用程序一起工作,和 Wolfram 语言参考资料中心相集成,还可以生成 HTML 文件的文档系统. 或者,您的系统可以有自己的文档.
好的终端用户文档可以使您的系统看上去更专业且更易使用,并且有益于开发过程. 如果文档设计不合适,会使事情变难或很尴尬. 因此终端用户文档应当作为开发的一个集成部分.

开发人员的文档

这是为开发人员设计的文档,它可以采取不同的形式. 您可以在代码中提供注释,并使用描述函数的名称. 此外,当您使用源代码管理,提交更改时可以写出更改的原因. 其它可能,包括在项目中存储您的文档. 您可以轻松地用 Wolfram 语言笔记本实现这些目的,Wolfram Workbench 提供了从源代码超链接到一个笔记本的系统.
如果您已写您的代码,然后后来改变其运作方式,例如使用不同的算法,您绝对应该花时间来更新所使用的名称. 最好使用描述实际执行的名称. Wolfram Workbench 有一些好的工具来帮助重命名. 您还不应该害怕改变可用于执行的文件名,甚至整个系统的名称.
一个命名规则是避免使用 new 作为前缀. 如果引入新的插值方法,您不应该称该函数为 newInterpolation. 原因是这不会永远是新的,可能最终成为该系统的最古老的部分和有一个完全不恰当的名称. 更糟的是,您可能会再次更换功能,然后您不能使用 new 了.
通常,在 Wolfram Research 我们在我们的内部代码命名上花了很多心血,当需要时,我们很愿意重命名函数、变量、文件等.
编写和使用单元测试
测试应成为现代开发过程的一个关键因素. 一个关于测试的老观念是,它只是由专门负责系统测试的独立小组完成. 虽然软件质量部门发挥着重要作用,但是测试应该在开发中担当集成的角色,应当由写代码的开发人员来做.
Wolfram 语言代码适合单元测试有很多原因,例如数据保存和恢复,不同的 Wolfram 语言函数的调用. 它还提供了一个非常好的单元测试包称为 MUnit,它往往是通过 Wolfram Workbench 运行.
您应该在工作时开发测试,确保包括任何新的功能. 如果您发现任何错误或在代码中的弱点,那么您应该马上编写测试去修改. 您应该经常运行测试,例如,您应该始终先运行它们,然后再提交到源代码控制. 您也应该维护测试,使它们都始终 100% 成功通过. 为了更好地完成测试,您应把您的系统分为不同的组件,这样,每个组件就会有不同的的测试套件.
从连续的测试中,您会得到很多好处.

修正错误更容易

经常运行测试让您更快捕获错误. 一般来说,越早发现错误,越易修改. 一个错误,6个月后才发现,就更难修正. 因此,运行测试,有助于提高您的开发效率.

重构更容易

重构意味着改变应用程序的执行情况而不改变功能. 这可能意味着重新命名,不同地分割系统,或者使用不同的算法. 对于所有这些,如果您有一个很好的测试设置,更改之后,系统仍然工作,您将更自信您的变化是好的.

更新到新版本更容易

当您更新到新的 Wolfram 语言版本,您可以在新版本中运行测试. 这将使您更加自信,您可以升级到新系统.

训练新的开发人员

当新的开发人员加入开发项目,在改进和加强单元测试中工作,往往是一个很好的方式让他们了解该项目.
使用 Wolfram Workbench
Wolfram Workbench 是 Wolfram 语言的一个集成开发环境. 它是基于一种广泛应用于许多商业环境的 IDE 平台,叫 Eclipse. 可以直接使用 Workbench,也可以在 Eclipse 上安装 Wolfram 语言
Workbench 为构建大型应用程序提供很多有用的工具. 它包含一个调试器、分析器和一个单元测试器. 它也支持包含不同资源类型的项目,如代码、文档、Java 类和笔记本文档. 工作项目视图非常适合把您的系统分成不同的组件,这是提高开发效率的一个重要方法.
Workbench 还包含一个特殊的 Wolfram 语言代码编辑器,有很多关于 Wolfram 语言程序包和应用程序的知识. 这一切都可以帮助您以这种方式开发和工作. 它也包含了与 CVS 的良好集成,可以很容易地扩展到其它源代码控制系统.
它大力支持使用其它语言开发如 Java、Python 或 C 和 C++. 因此,如果您的系统需要这些和 Wolfram 语言结合起来,您可以很容易这样做.
Workbench 的一个有趣的功能是,它提供了帮助您在 Wolfram 语言中进行并行计算的工具. 您可调试和分析并行程序,并帮助您添加您的并行编程到您的系统.
下面是 Workbench 特有的一些有助于大型项目的功能.

项目组织

所有您在 Workbench 的工作都集合在项目中,每个项目都包含不同类型的资源,如 Wolfram 语言代码、文档、Java 类和笔记本文档. 和一些基于项目的系统不同的是,在 Workbench 中的项目特别简单且易于维护. Workbench 有许多特殊工具,诸如,打开文档的特殊编辑器、对不同组件的专门搜索和报告. 它还与 Wolfram 语言笔记本前端紧密集成.

启动和运行代码

Workbench 提供从项目中启动和运行 Wolfram 语言的高级接口. 它允许您为您的项目初始化 Wolfram 语言,改善所有您正在开发的不同资源类型,如代码、Java 类、笔记本样式和面板. 如果您把您的工作分成一组相关的项目,启动器也会意识到这些. 它还便于在不同的 Wolfram 语言版本中切换.

调试器/分析器

Workbench 提供了一个 Wolfram 语言调试器和分析器的接口. 您可以检查许多种 Wolfram 语言的程序,包括并行和用户界面代码. 如果在您的项目中有 Java 代码,您可以同时调试 Wolfram 语言和 Java 代码,这是一个非常独特的功能.

单元测试器

Workbench 为 MUnit(Wolfram 语言单元测试器)提供一个接口. 您可以运行个别的测试文件或测试文件的整个套件.

重构

Workbench 提供了重命名变量等等的重构工具,也有专门查找/替换工具,使用 Wolfram 语言模式语言来查找和修改代码工具. 它们可用于带有模式的实际表达式树,而不是用于在带有字符串搜索/替换工具的源代码文本上.

错误/警告

Workbench 发现和报告项目中所有 Wolfram 语言源文件的错误和警告,不管源文件是否已经打开. 快速发现源代码中存在的问题的概要,能够很大程度上提高您的生产率,特别是当您有很多源文件的时候.

TODO 代码文档

Workbench 发现和报告项目中的所有 Wolfram 语言源文件的要做(TODO)注释. 不管源文件已经打开与否,这个功能都是可用的. 这是一个编写文档和跟踪源代码中需要完成的任务的简单而又强大的方式.

源代码控制

Workbench 提供了 CVS 的一个客户端,它可以扩展到大多数其它源代码控制形式.
Wolfram 语言优点
Wolfram 语言提供了许多对软件开发特别有用的功能,但往往被忽视. 然而,它们都有强大的优势,您应该充分利用它们.

轻松实现数据序列化

Wolfram 语言的基础是一个表达式. 所有一切,包括程序和数据,都是一个表达式. 由于表达式可以很容易地写入一个文件,然后加载回 Wolfram 语言,这使得它很容易保存您的系统状态,然后再加载回来.
这使得以组件形式测试和开发您的系统变得非常容易. 例如,假设您需要数据库中的数据,您可以开发一个数据库组件,然后用它来准备一些数据文件. 当您开发您的计算组件,您只需加载数据和运行计算. 此外,您可以编写单元测试来加载这些数据文件. 重要的是要确保您只测试一个组成部分,这是一个非常好的工作方式.
保存数据是一个简单的过程,从字面上只需一行,如 Save[file,data]. 如果您是用 Java 或 C++ 您需要写很多行代码,如果您的数据发生变动,您需要重写代码. 这同样适用于加载回 Wolfram 语言,简单的 data=Get[file] 可以恢复数据.

代码易于访问

您可以轻松地调用软件包中不同的函数,只需在 Wolfram 语言笔记本前端输入名称. 这将使用 Wolfram 语言的解释性质,大大减少了准备工作量,例如,开发代码时在调试进程之前.

使用可视化工具

Wolfram 语言包含了很多绘制数据和曲面的可视化工具. 有一些工具专业化程度很高,如绘制图形. 这些都可以是非常有用的,可帮助您了解您的应用程序是如何运行的. 您可以制作运行时间的图表,看看它是否与输入增加成比例,也可以研究转化数据的分布特征,看是否有意想不到的特征需要进一步的调查研究.

互动探索

您可以使用 Wolfram 语言互动工具,来探索您的函数. 例如,在单个行上用 Manipulate 函数来创建一个调用您的函数的工具,这可能有助于发现一些奇怪的意想不到的结果.

建立随机模式

如果应用程序需要特殊的数据来看,您当然可以从数据库中读取. 在开发和测试您的一些组件时,您可以使用序列化技术来存储和检索数据. 另一种,特别是和结构化数据有关的,是利用 Wolfram 语言的随机数生成技术建立随机数据. 这样做的额外好处是所生成的数据并不含有实质内容,因此,当对真正的数据有更多限制时,可以用它来发行.
考虑其他开发人员
每个开发人员要时刻想着其他开发人员. 您应该遵循诸如记录代码和保持它简单的原则. 即使您是唯一工作在该系统上的人,虽然这可能在任何时候都是成立的,也可能并不总是如此;最终,可能会有另一个开发人员加入. 管理者不应该让开发者把代码的一部分作为自己的私人领域,这会阻止良好开发的习惯规则.
升级您的系统
有可能您的项目不遵循这些原则. 例如,您是从一个小的部分开始工作,逐步增长,您从来没有停下来思考您是如何开发的. 或许,您想改变您的做法,但还没有(或许您在考虑成本变化). 另外,您可能看不到任何改变的意义,认为这是纯理论的,并不真正适用于我.
正如硬件和软件技术不断迅速发展和变化,因此软件开发也是这样. 如果您花大量的时间开发软件,同样也值得花时间思考如何做到这一点,什么样的新技术和理念,您可以进行学习. 本文档就如何可以在 Wolfram 语言开发中做到这些给出一些建议. 改善您的工作方式并从中受益,这是永远不会太晚的.
如果您想尝试和运用本文档中的一些想法,您可能应该首先考虑体系结构和系统组成部分的性质. 决定已经分成组件的系统是否需要一定的调整. 一个极端的例子是,一个大型的应用程序完全写在 Wolfram 语言笔记本文档的一个单元格中. 在这种情况下,您的应用程序可能是完全单一的,不能划分成组件.
无论您的实际执行情况,您首先应该重新审核您的系统,并确定其组成部分. 通常这会比较明显,例如:您的应用程序可能有一部分是提供一个用户界面,它可能与数据库一起工作,并可能进行一些计算. 计算可能有一些特殊的功能,例如:他们可能需要一些特别的插值方法. 这每一种都是一个潜在的组件.
一旦您已经确定您的组件,您就可以重构系统并划分成这些组件. 首先,开发一个测试套件,可以让您比较重构系统的前后. 但是,缺乏组件的性质可能是一大障碍. 例如,如果您的应用程序只有通过用户界面且总是要连接到数据库才能运行的话,会使得编写和运行测试很难. 不管您做什么,当您划分您的应用程序时,应确保代码使用相应的程序包格式. 您也可以找到并使用源代码库.
把您的系统按本文件讨论的想法来做的话,您可以提高您的生产力.
总结
本文档所述的原则对于所有软件工程都是很普遍的. 但我们的目标是展示如何在 Wolfram 语言中实现,所以讨论和例子都是说明 Wolfram 语言这一方面的. 这更有助于说明 Wolfram 语言很适用于开发强劲的软件工程项目,尤其是那些最新的工具,例如 Wolfram Workbench,以及最新的实践操作,如单元测试. 此外,Wolfram 语言的某些功能,如表达式序列化和图形可视化,领导一些创新和独特的方法进行软件开发. 我们认为,Wolfram 语言是一个伟大的大型软件开发系统;遵循这些规则和惯例,并使用合适的工具就能够更好地完成任务.

Wolfram 语言资源

请确保您充分利用 Wolfram 语言的资源优势:许多资源都可以通过 Wolfram Research 网站访问: