【外刊IT评论】Web编程是函数式编程

先声明一下,此文章只是本人转载的。本一直在jdon上潜水,近日在OSChina正好看到这篇文章,文中观点与Jdon上的大力弘扬的OO思想有点出入,大家可以看下老外的文章是否也靠谱。

任何一位在两个领域里——本地应用程序和Web应用程序——都做过长期开发的人都会告诉你,web应用开发和传统的应用开发有很大的不同。这指的并 不是编程语言。同样用Java,或者是Python,甚至C++,你既能开发本地应用,也能开发出web应用。不同之处在于web的载体介质。它体现出的 是一种完全不同的部署和运行环境。它实现了一种不同的服务模式。它使用的是一种不同的应用架构。它需要程序员采用一种不同的思维方法,因为web编程所体 现出的哲学体系跟我们传统的编程派系都相去甚远。在此,对于web编程范式,我们有一些有趣的事情需要去认识清楚。虽然很明显,很真实,但却被现代强势的 编程范式的阴影遮蔽着,被眩目的新技术和工具的光芒淹没了。

“究竟是什么?” – 你会问。

我们就来看看。

我们从看看典型的本地应用程序的生命周期开始,拿它跟典型的Web应用程序的相比较。我将会一直使用“生命周期”这个词来表示应用程序的活动周期,运行时的,指的不是包括不同开发和维护阶段的项目周期。

一个典型的本地应用程序的生命周期是什么样子的?一个用户启动这个程序,程序被加载到内存里,开始运行。它能对用户的输入起反应,从磁盘上读取文 件,或通过网络传输数据。它能跟其它的软件或硬件进行交互,调用其它服务,或响应一个外部调用。它可以收集数据,累计数据,以某种方式处理这些数据。简言 之,这些都是一个本地应用程序启动后,运行时能做的事情。

一个典型的web应用程序的生命周期是什么样的呢?用户在浏览器里点击一个链接。浏览器向web服务器发送一个请求,然后会接收到响应信息,把它展 示给用户。非常的简单。但应用程序并非是运行在用户机器上的浏览器中的。它运行在web服务器中。在那里,应用并不是持续的运行。服务器只是短暂使应用苏 醒来完成处理请求的任务,准备好要回复的东西。这些事情发生在眨眼之间。在两个请求之间应用并不处于运行状态。它只是被调用很短的一段时间,当完成请求服 务后会立即停止运行。而且应用也不会被整个的加载到内存里,只会加载对于目前的任务真正有必要的部分。你可以认为web应用程序只有一个瞬时的生命期。只 有它的运行所在的环境,也就是web服务器在持续的运行。事实上会有一些变通的策略,例如session和数据序列化,来帮助在应用程序的生命期之间保持 数据,来模仿有状态的操作,例如某些框架,像ASP.NET的WebForms或JSP就是这样做的,但毕竟,这都是些技术上的技巧,跟本文所讨论的问题 不相干。我们关注的是普通的web应用,关注它们处理请求的过程。这些web应用程序都只享有一个非常短暂的运行存在状态。

对于开发本地应用程序,有很多技术被证明非常有用。面向对象的方法可以用来构造问题环境,帮助降低问题的复杂性。一些设计模式能体现出一种高效的, 而且优雅的设计方案。分层的架构把代码责任分离,最小化各层的依赖性。这些全是典型的最佳方案,它们在开发本地应用程序的过程中被充分的证实过。

而在web应用程序里对这些技术方案的使用却是另外一种不同的情形了。我们积极的使用面向对象的方法来定义我们的业务模型,我们采用各种设计模式, 我们实现分层架构。这些帮助我们提高代码质量,增加复用性,把应用程序组织成概念上的各个模块。这些都很有效,是我们最常用的技术路线。但即使如此,我还 是忍不住要提醒你,这些东西看起来有些多余,有大炮打蚊子的感觉。时不时我会盯着这些精巧而且深思熟虑的代码,一种无由的想法会袭上我的心头:干嘛不把这 些全都剥离掉,直接做要做的事情呢?

什么是直接做?想想一个应用处理一个请求的典型处理方式。在主要步骤里发生了什么?应用程序接收用户输入,校验它,把它转换成业务领域相关的格式, 把它传进一个SQL语句里,保持到数据库里。下面又发生了什么?程序从数据库里读出一些数据,格式化信息,使之能够被用户识别,以一段HTML的形式返回 给用户使用。就是这样。这就是大多数web应用程序在其幕后所做的事情。在它们的运行期里没有什么特别的对象,它们发送和接收消息,智能的在其内部交互运 作来实现高层的行为。不,只是一些数据在用户和数据库之间旅行,送出去,返回来。就是一个接一个的数据流。实现这些任务的程序代码本质上就像一个函数式程 序,不管它们被构造出来的风格是什么样的。

有个讨论直指这个主题: Is functional programming relevant to web development? 其中一个雄辩的用户写道:

“函数式编程跟web应用开发非常的匹配。web应用接收一个HTTP请求,生成一个HTML返回结果。这应当被认做是一个从请求到页面的函数式功能。”

而我要补充下面的东西。实现这些功能的代码本质上反映的就是函数式的风格。我们并没有用真正的对象把应用程序的状态保存在内存里、用它们来实现应用 逻辑操作,我们使用的是数据库来保存应用程序的状态,整个的代码基本上就是一个巨大的,复杂的函数式功能编码,它来管理特定数据流的走向:数据库或用户。

从这些讨论我们能得到什么?狂热的强制使用面向对象的风格、对web应用使用复杂的架构未必总会有好处。你不一定就能从这种架构方式中获得有价值的 好处,但从性能和日后维护的角度看,它们却能使你的应用过于复杂和效能低下。我们必须针对每个项目的各自情况来掂量采用某种方式的好处和坏处。

当一个程序员编写一个web应用程序,如果突然代码中显示出了函数式编程风格的印记时,不要马上批评和嘲笑他。也许他是特意这样做的。也许这是一种敏锐的感觉到web编程本身就是天生的函数式编程的潜意识表现。

[英文出处]:Web programming is functional programming

[译文来源]:外刊IT评论

不会批评函数式的,函数式(声明式)的优点我们是有目共睹的。众多语言的对声明式的探讨相当盛行的,如我暂时比较欣赏的scala。

话说回来,文中对WEB应用的理解可以说是片面的,单纯的增删改,的确很难体现OO思维,但看看DDD,DCI,EDA等思想,可以发现原来WEB应用也可以这样思考的。“只是一些数据在用户和数据库之间旅行”理解得太简单了,例如现在我思考中几乎很难找到数据库的概念了,有都已经替换为仓储了。在内存中拥有着我们领域中的真实模型,要是可以的话,真想把它具现化,哈哈。

世界观是多种,语言也一样:-)

2010年12月07日 12:19 "william26"的内容
也许这是一种敏锐的感觉到web编程本身就是天生的函数式编程的潜意识表现 ...

什么屁股决定你能够闻出什么味道,如果你狗的屁股,就能闻出屎味,哈哈,开个玩笑,这只是一家之言。

我的屁股让我潜意识感觉Web编程就是天生的分布式,这个观点见这里:
回复:转一个大牛对分布式系统和cqrs的反思文章

如果把分布式通讯行为看成某个方法调用,从而认为其有函数式编程味道,也说得通。

如果是这样,我觉得OO与函数式之争有点象GoF设计模式中结构型模式和行为型模式的争论。到底以谁为第一考虑因素?呵呵,以应用为第一考虑因素呗。

另外,有人认为“文中观点与Jdon上的大力弘扬的OO思想有点出入”,我认为该文主要是强调其WEB请求调用时的一种函数式特征,这是该文的一个亮点,当然由于其数据库屁股背景,他试图把它的数据库概念也拉进来,进而和OO较劲,我想应该分清楚,这些都不是一码事。

关于该文这段"我们积极的使用面向对象的方法来定义我们的业务模型,我们采用各种设计模式, 我们实现分层架构。这些帮助我们提高代码质量,增加复用性,把应用程序组织成概念上的各个模块。这些都很有效,是我们最常用的技术路线。但即使如此,我还 是忍不住要提醒你,这些东西看起来有些多余,有大炮打蚊子的感觉。时不时我会盯着这些精巧而且深思熟虑的代码,一种无由的想法会袭上我的心头:干嘛不把这 些全都剥离掉,直接做要做的事情呢?"

看看,多熟悉,“干嘛不把这 些全都剥离掉,直接做要做的事情呢?”这多符合初学者心声啊,都符合大老粗的大干快上的劲头。这其实一种忽悠噱头,让我们看看它“直接做”的内容是什么?

文章中“直接做”的意思就是提倡REST架构风格,REST架构建议将Http请求和响应直接暴露给程序员,而我们传统的JSF或MVC框架,都是将请求和响应以面向对象的名义封装起来,从而破坏了WEB本质,这是我一向反对的。

在如今物联网+云计算时代(Web已死),真正和以前的区别就是:一切可分布,一起可异步;而封装本身有时和切分是矛盾的,分久必合,合久必分,对业务逻辑采取封装为主的领域模型是符合我们的认识论的;但是在面对技术领域的平台架构,则不能采取一刀切的封装方式,这也是目前所谓中间件技术或组件构件技术走向没落的原因,今天你用JSF或Web Service将http的请求和响应封装成组件,明天我们用REST又将其暴露,然后我们发现WEB本质就是分布式的函数调用。

所以,关键还是在什么领域侧重封装,在什么领域侧重切分暴露,都是一个相对尺度问题。这些都和OO无关,错在不合适地方用错了方法。


[该贴被banq于2010-12-08 11:50修改过]
[该贴被banq于2010-12-08 13:53修改过]

2010年12月07日 12:19 "william26"的内容
事实上会有一些变通的策略,例如session和数据序列化,来帮助在应用程序的生命期之间保持 数据,来模仿有状态的操作,例如某些框架,像ASP.NET的WebForms或JSP就是这样做的,但毕竟,这都是些技术上的技巧,跟本文所讨论的问题 不 ...

不知道为什么,既然作者列举了这些变通的技术,而又笔锋一转,把他们说成“都是技术上的技巧,跟本文所讨论的问题不相干”。事实是——在传统的b/s应用程序中,正是诸如session、ajax和数据序列化等技术的应用,已经发展衍生出富客户端应用程序这一最大分支。他们的应用已经很大程度上解决了对象的生命周期问题。
当然,认识到这一层,确实经历了了解——毁灭——再了解的过程。但是,现在的问题不是基于web应用程序的OO方法论的滥用,而是不足。并且,基于我以上的观点,解决了web应用对象生命周期问题,就已经解决了作者的根本性问题。不知道作者这篇文章发表于何时,如在今日,则可以认为是无病呻吟之举。
[该贴被showerxp于2011-01-20 11:17修改过]

“而在web应用程序里对这些技术方案的使用却是另外一种不同的情形了。我们积极的使用面向对象的方法来定义我们的业务模型,我们采用各种设计模式, 我们实现分层架构。这些帮助我们提高代码质量,增加复用性,把应用程序组织成概念上的各个模块。这些都很有效,是我们最常用的技术路线。但即使如此,我还 是忍不住要提醒你,这些东西看起来有些多余,有大炮打蚊子的感觉。时不时我会盯着这些精巧而且深思熟虑的代码,一种无由的想法会袭上我的心头:干嘛不把这 些全都剥离掉,直接做要做的事情呢?”

对于这个观点亦是不敢苟同。
如今web应用,很多服务器处理过程已经非常复杂了。试想,淘宝网每天千万笔查询记录本身就有很多相关性。比如,查询“鞋子”的人,很可能对于“衣帽”有潜在的购买需求。如果做出能智能的感知客户的这种关联需求的程序本身很可能是一个非常复杂的应用程序了,不是简单的用几条sql语句在数据库操作几下就能完成。