今天所教授的软件工程完全专注于面向对象的编程和“自然的”面向对象的世界观。有一个详细的方法,描述了如何将一个领域模型转换成一个类模型,该方法有几个步骤和很多(UML)工件,比如用例图或类图。许多程序员已经内化了这种方法,并且对如何从头开始设计面向对象的应用程序有很好的想法。

新的宣传是函数式编程,在许多书籍和教程中都有介绍。但是功能性软件工程呢? 在阅读关于Lisp和Clojure的文章时,我发现了两个有趣的陈述:

函数式程序通常是自底向上而不是自顶向下开发的(《论Lisp》,Paul Graham) 函数式程序员使用映射,而oop程序员使用对象/类(《Clojure for Java Programmers》,Rich Hickley谈话)。

那么,在Lisp或Clojure中,系统地(基于模型的)设计功能应用程序的方法是什么呢?常见的步骤是什么,我使用什么构件,我如何将它们从问题空间映射到解决方案空间?


当前回答

面向对象设计与软件工程不是一回事。软件工程与我们如何按时、低缺陷率地从需求到工作系统的整个过程有关。函数式编程可能与面向对象不同,但它并没有消除需求、高级和详细的设计、验证和测试、软件度量、估计以及所有其他“软件工程的东西”。

此外,函数式程序确实表现出模块化和其他结构。你的详细设计必须根据该结构中的概念来表达。

其他回答

老实说,如果你想设计函数式程序,可以看看标准函数库,比如Haskell的Prelude。在FP中,模式通常由高阶过程(对函数进行操作的函数)本身捕获。因此,如果看到了一个模式,通常会创建一个更高阶的函数来捕捉该模式。

fmap就是一个很好的例子。该函数以一个函数作为参数,并将其应用于第二个参数的所有“元素”。因为它是Functor类型类的一部分,所以Functor的任何实例(如列表、图形等)都可以作为第二个参数传递给这个函数。它捕捉了将函数应用于第二个参数的每个元素的一般行为。

一种方法是在所选择的函数式编程语言中创建内部DSL。“模型”是用DSL表示的一组业务规则。

面向对象设计与软件工程不是一回事。软件工程与我们如何按时、低缺陷率地从需求到工作系统的整个过程有关。函数式编程可能与面向对象不同,但它并没有消除需求、高级和详细的设计、验证和测试、软件度量、估计以及所有其他“软件工程的东西”。

此外,函数式程序确实表现出模块化和其他结构。你的详细设计必须根据该结构中的概念来表达。

有一种“程序计算”/“通过计算设计”的风格与Richard Bird教授和牛津大学(英国)的代数编程组有关,我不认为将其视为一种方法论太牵强。

就我个人而言,虽然我喜欢AoP小组的工作,但我自己没有以这种方式实践设计的规程。但这是我的缺点,不是程序计算的缺点之一。

就我个人而言,我发现来自OO开发的所有常见的良好实践也适用于函数式编程——只是在考虑函数式世界观时做了一些小调整。从方法论的角度来看,您实际上不需要做任何根本不同的事情。

我的经验来自于最近几年从Java转移到Clojure。

一些例子:

Understand your business domain / data model - equally important whether you are going to design an object model or create a functional data structure with nested maps. In some ways, FP can be easier because it encourages you to think about data model separately from functions / processes but you still have to do both. Service orientation in design - actually works very well from a FP perspective, since a typical service is really just a function with some side effects. I think that the "bottom up" view of software development sometimes espoused in the Lisp world is actually just good service-oriented API design principles in another guise. Test Driven Development - works well in FP languages, in fact sometimes even better because pure functions lend themselves extremely well to writing clear, repeatable tests without any need for setting up a stateful environment. You might also want to build separate tests to check data integrity (e.g. does this map have all the keys in it that I expect, to balance the fact that in an OO language the class definition would enforce this for you at compile time). Prototying / iteration - works just as well with FP. You might even be able to prototype live with users if you get very extremely good at building tools / DSL and using them at the REPL.