今天教授的软件工程完全专注于面向对象的编程和“自然的”面向对象的世界观。有一个详细的方法描述了如何通过几个步骤和许多(UML)工件(如用例图或类图)将域模型转换为类模型。许多程序员已经内化了这种方法,并且对如何从头开始设计面向对象的应用程序有很好的想法。
新的炒作是函数式编程,它在许多书籍和教程中都有讲授。但是功能软件工程呢?在阅读有关 Lisp 和 Clojure 的信息时,我想到了两个有趣的陈述:
函数式程序通常是自下而上而不是自上而下开发的(’On Lisp’,Paul Graham)
函数式程序员使用映射,而 OO 程序员使用对象/类(’Clojure for Java Programmers’,Rich Hickley 的演讲)。
那么,在 Lisp 或 Clojure 中系统化(基于模型?)设计功能应用程序的方法是什么?常见步骤是什么,我使用什么工件,如何将它们从问题空间映射到解决方案空间?
感谢上帝,软件工程人员还没有发现函数式编程。以下是一些相似之处:
这些高阶函数通常带有某些编程定律,也就是“自由定理”。
那些使用类型的函数式程序员通常认为“一旦你得到了正确的类型,代码实际上就是自己编写的”。
并非所有的函数式语言都使用显式类型,但是How To Design Programs这本书是一本学习 Scheme/Lisp/Clojure 的优秀书籍,它在很大程度上依赖于与类型密切相关的“数据描述”。
那么,在 Lisp 或 Clojure 中系统化(基于模型?)设计功能应用程序的方法是什么?
任何基于数据抽象的设计方法都行之有效。我碰巧认为当语言具有显式类型时这会更容易,但即使没有它也可以工作。一本关于抽象数据类型设计方法的好书,很容易适应函数式编程,是Barbara Liskov 和 John Guttag 的 程序开发中的抽象和规范, 第一版 。Liskov 获得图灵奖的部分原因是这项工作。
Lisp 独有的另一种设计方法是确定哪些语言扩展在您正在工作的问题域中有用,然后使用卫生宏将这些构造添加到您的语言中。阅读这种设计的好地方是 Matthew Flatt 的文章 Creating Languages in Racket 。该文章可能位于付费墙后面。您还可以通过搜索术语“特定领域的嵌入式语言”找到有关此类设计的更多通用材料;对于 Matthew Flatt 所涵盖的特定建议和示例,我可能会从 Graham 的 On Lisp 或 ANSI Common Lisp 开始。
有哪些常见步骤,我使用哪些工件?
常用步骤:
识别程序中的数据及其上的操作,并定义一个抽象的数据类型来表示这些数据。
识别常见的操作或计算模式,并将它们表示为高阶函数或宏。期望将此步骤作为重构的一部分。
如果您使用类型化的函数式语言,请尽早并经常使用类型检查器。如果您使用 Lisp 或 Clojure,最佳实践是首先编写函数契约,包括单元测试——最大限度地发挥测试驱动的开发。而且您将希望使用已移植到您的平台的任何版本的 QuickCheck,在您的情况下,它看起来像是称为ClojureCheck。它是一个非常强大的库,用于构建使用高阶函数的代码的随机测试。