基于自然语言的软件工程和程序设计(中)
系列文章导航:
软件发展至今,无论是编程语言,还是软件工程,乃至是互联网的趋势发展,都是飞速发展。于是,我们便迷茫于这样形形色色的语言和概念之间,无所适从。其实,我们不妨返璞归真,回到最初,让我们从语义出发,来讨论这形形色色的种种,你是否恍然大悟呢?
5. 面向过程是先总后分的行文顺序
相信大多数程序员都和我一样,C语言都是自己的第一门语言,那么面向过程的这个概念也自然深入人心。其实,我相信,每个人心中的思维都是面向过程的。
“我们应该先干嘛,再干嘛”。这是每个人在做一件事情前的常规思维,编程时也是一样,我们在实现一个方法,或者在完成一个功能时,都会去想,应该先做什么,再做什么,然后我们会相应地把一个方法拆分成若干个子方法,这就是我们传统的面向过程的编程。
我们把这种方式称之为“自顶向下”的编程思维。在做一件事情之前,我们要了解这件事情是什么,然后再去想这件事情应该怎么做。
这种与我们常规的对应叫做记叙文,说得难听一些我们可以称之为流水账。
我们不妨说得偏激一点,面向过程的核心不在于方法,而在于过程。面向过程本是没有方法的,后来为了可读性才增加了方法这个概念。本就是辅助,当然可有可无。
概括起来,面向过程的编程方式是先总后分的行文方式,先知道总体意思,再逐条去写。
6. 面向对象是先分后总的行文顺序
逐渐地,我们开始接触了Java、C#等面向对象的语言,但是我们是否却始终没有办法扭转思维,来找到如何来面向对象呢?抑或是我们经常为了面向对象而面向对象呢?
我们究竟错在了哪?我就是按照常规的语义来分析整个的项目,那为什么无法面向对象呢?错只错在我们解析语法的角度出现了问题。
在上文中,我提到了我在高中时非常常用的一种记叙方式,就是我会在文章的题记前,先把开场的主人公全部都陈列出来,其中包括他们的主要性格,以及简要概括他们的陈年往事。如此做的原因是因为文章的故事结构比较复杂。
那么我会做的是,首先在提纲上列去所有的主人公,然后想清楚他的主要性格,之后再去根据他的性格来为他设定一些事件,最后根据这些事件安排这些主人公的出场顺序,以及人物之间的关系。
这也得出了我对面向对象的核心思想的概述:以人为本。这里的人不仅仅是人,是指所有存在的生物,乃至非生物。换句话说,所有需要有行为的物体。可以是人,可以是计算机,甚至可以是一个衣柜。
面向对象的核心不在于业务逻辑的过程,而在于找到所有的“人”,然后知道每个人都能做什么,最后我们再把这些行为加以组装而已。
概括起来,面向对象的编程方式是先分后总的行文方式,在文章伊始,每件事情都不知道自己是在干嘛,只是在表达着自己。知道最后,才会发现,原来这些事情的作用是这个样子的。
有这样一本书,叫像堆积木一样做软件。我不清楚这本书的内容是什么,但是这个题目很形象,面向对象在分析过程实际上就是在做积木,每个积木都不知道自己未来会干嘛,而当积木都做好了之后,堆积木就变得简单而易行了。
7. 并发式编程是交错式的行文顺序
随着软件对性能要求的逐渐提升,并发已经成为了我们不可回避的话题,从Erlang到C#4.0的并行库,再到显卡编程的盛行,并发编程已经逐渐走到了我们的面前。
在高中时,有一种文体非常盛行,我也曾多次尝试,最后的分数也还不错。这种问题是在行文时,分别描述两件事情或多件事情,这几件看上去毫无关系,只是由每一段的ABCD、abcd等不同的符号来标识,然而这些事情到最后却揭示的同一道理,或者是最后他们在同一场景汇聚,来构成了故事的结局。
这种文体在新概念作文大赛上屡有出现。其实这就对应着我们常规意义上的并发编程。每件事情和每件事情之间从局部上没有着直接联系,但是最后宏观上,他们都是在为了做同一件事情,达到同一个目的。就像装配脑袋某天在群里讨论的冒泡排序的并发版——奇偶排序一样,从微观上,对奇数排序和对偶数排序没有必然联系,实则他们在完成着同一项工作。
8. 重谈总体行文
我一直在编程中都很强调一点,语义的重要性!
完美的编程语言应该是与自然语言完全对应的,可以把一篇文章翻译成与之对应的计算机语言,发展到那时,程序员就真的变成了翻译工作,只需要把对应的需求文档无需设计,翻译成计算机认识的一串串代码就可以了。
我们究竟如何分析一个软件需求。在我看来,软件的创造过程实则就是语义的分析过程。
当拿到一份需求时,按照面向对象的软件工程思想,我们应该首先做到提取出这份需求文档中所有的“主人公”,然后找到这些主人公每个人都可以干嘛,能干嘛,要干嘛。然后为之建立模型。这是面向对象的过程。
然后是每个行为的分析过程,要做这个行为,我们要先怎么做,再怎么做,为这个行为建立相应的流程图,这是面向过程的分析过程。
接下来,我们可以分析某个行为怎么做,是否可以一边干嘛,一边干嘛。这是面向并发的建模过程。
当我们要描述某个算法时,我们可以说这个算法要怎么做,只是基于语义的描述,例如斐波那契数列要用第一个数加上第二个数,这其实就很有可能是一个函数式编程的产生过程。
最后是组装,也就是堆积木的过程。我们的积木都已经做好了,我们只需要按照不同的业务逻辑,去把这些积木搭起来就可以了。
也就是说,当我们建立一个项目时,首先建立人物传记(面向对象),然后对人物的经历进行描述(面向过程)。最后成文时,我们可以用交错式行文方式对其重组(并发式)。
那么好,我们概括下整个的过程:面向对象分析-->面向过程分析--->在过程的细节上并发或者函数式--->组装时再次考虑并发。
9. 小议过时说
经常会听到这样的声音,未来是面向服务的,未来是面向对象的,面向函数的,面向过程已经过时了之类的话。
其实,看过我上面的分析过程,一个完整的工程只靠着某一种编程范式是行不通的,一个工程的搭建需要的是各种范式的配合使用,每种范式都有着它所擅长的部分。
就像面向对象再好用,也无法脱离了面向过程而单独存在,哪怕你的原子拆分得再细,也无法逃开对每件事情进行分析的过程,况且还有着业务逻辑组装过程的存在。
而面向函数,面向并发再强大,他也无法取代面向对象在分析一个大型项目中自底向上这样巨大的优势。因此任何编程范式皆无过时说。就像语言之争一样,每种语言都有着其合适的应用范围,谈语言优劣,过时与否,我觉得毫无必要。
下文简介:
在下文中,我会对对全文进行一个总体的总结,以及语义与面向对象的关系,设计模式与语义的关系,并且会浅谈个人认为未来语言的发展方向等等,敬请关注,谢谢。