简单之美:软件开发实践者的思考(txt+pdf+epub+mobi电子书下载)


发布时间:2020-07-19 11:57:44

点击下载

作者:倪健

出版社:机械工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

简单之美:软件开发实践者的思考

简单之美:软件开发实践者的思考试读:

前言

为什么写本书[1]

19年前夏日的一天,我正在宿舍里看一本关于禅宗的书。一位朋友走过来,他注意到了书的封面,然后好奇地问我禅宗是什么。当时我也说不清楚,只是觉得禅宗很像唯心主义者的一道逻辑题。

禅宗的心髓是悟,在禅宗思想推广的历史上,有很多具体生动的[2]故事阐释了这个概念。最有名的是六祖慧能的偈句:“菩提本无树,明镜亦非台。本来无一物,何处惹尘埃?”。“本来无一物”——说明了慧能在洞悉事物本质上的境界(后来这首诗的境界又被超越了)。

禅宗的历史就是种种境界被建立和被超越的过程。为了达到无法超越的最高境界,参禅者们发明了机锋公案、棒喝直指、扬眉瞬目、拳打脚踢、斩蛇杀猫这样一些辅助手段,这些手段可以让人快速通过量变到质变的一刹那(没有可以解释的过程),直达内心顿悟。进入顿悟状态后,所有语言、文字和思想都成了阻碍。

唯一例外的词——想入非非——可以作为那种境界的缩影。想入非非的意思是说,那种至高无上的境界不是我们头脑中可以想到的,因为可以想到是一种阻碍;也不是我们头脑中无法想到的,因为无法想到是指除了可以想到之外的。非非,表示否定了否定,这里的双重否定不代表肯定。想入非非,把没有边界的思想通过一种特殊的方式表达了出来。

在这些年的软件开发生涯中,禅宗那种积极反思、不断追求完美境界的精神一直影响着我。凭着这种精神,我把软件开发变成了乐趣。有两个原因使这种转变成为可能:第一,我把想象力和创造力结合了起来;第二,我的软件开发思想已经比较成熟和完整了。这两点很重要。想象力和创造力的运用使人的精神得到了满足,而软件开发思想则使任何事情在开始之前都有了一个合理的解释。合理与满足会给你带来乐趣。

我写本书的主要目的也有两个:第一,回顾自己的软件开发生涯;第二,与读者朋友们分享我自己的体验和感受。我希望在你阅读完本书后,可以发现如何品尝软件开发的乐趣,如何从千头万绪变得线索明朗,如何从复杂世界进入简单世界。

我还想在本书中表达以下几个观点。

首先,思想是解决一切问题(包括软件开发中的问题)的根本。[3]Robert C.Martin在Agile Software Development:Principles,Patterns,and Practices的中文版序言中表达了一个思想,即软件是美的(我喜欢阅读序言,因为那里通常是和作者心灵最接近的地方)。而我想表达的思想是,在你熟悉的软件开发领域,软件不仅是美的,还是简单的。领悟到软件开发中的简单之美是解决软件开发问题的钥匙。在我看来,思想是一种坚定不移的信仰,并且是在经过了足够的实践检验后形成的。在软件开发过程中,稳定的思想会使所有的力量汇聚到一个有效的方向。

其次,思想是一盏明灯,但有时也会成为一种桎梏。像参禅者一样不断追求完美的境界,使思想成为你自己不断成长的体验。

最后,思想必须转换成习惯。我不是个真正意义上的实用主义者(本质上是个追求内驱力的理想主义者),但是在实践中运用思想比停留在思考层面显然更有乐趣。

总之,构建一套完整的思想体系是软件开发能力成熟的标志。只有思想成熟,才会使你的一言一行、举手投足、细节决策等在复杂的实践中收放自如。

软件开发思想的成熟,还需要操作层面上的大力支持。我们不妨以方法论为例来看看软件开发中的问题。

很多软件开发人员在实践中经常处于一种混乱状态。所谓混乱状态,就是当出现问题的时候没有人知道怎么做才算最好,或者人们之间缺乏足够的信任和共识,或者大家不断地讨论却得不到满意的解决方案。

对于软件开发老手而言,经验是帮助他们保持清醒并走出混乱状态的安全绳。可是,要想依靠经验来持续地造福一个团队就比较难。

事实上,造成混乱状态的原因有很多。本书中的所有内容都是在尝试从各个层面来谈论这个话题。如果单从方法论的层面来看主要有两个原因。

首先,没有操作性强的方法论的指导。

软件开发者的很多工作和努力都基于个人经验的积累。即便某些经验丰富的软件开发者掌握了一些必要的方法论知识,也不能在组织范围内有意识地推广,从而成为有实用价值的共享体验。

其次,有经验的软件开发者获取知识和使用知识的方法无法系统地传递给软件开发新手。

无法传递知识,会使新手们在软件开发领域的成长起点变得很低。在这种情况下,软件开发项目的成功通常依赖于个人英雄主义、人海疲劳战和运气。

当你经常对软件开发中的某些现象,如无休止地加班、返工、资源紧张等产生迷惘时,应该停下来认真思考;当你认真思考后仍然没有明确的解决之道,不妨看看别人的想法。

好,还是看看本书里写了些什么吧。

本书不是一本关于方法论的理论性书籍(尽管我已经尝试在大量的思考上进行一些理论归纳),也不是一本关于具体技术的操作手册。本书为读者呈现的是我在软件开发实践中的思考和体验,目的在于探究实践中的问题的根源,并给出思想上的解决之道。

本书以软件开发的基本顺序为主线,以简单、想象和文化的开发思想为线索,以为软件开发实践提供指导价值为目标。本书力图做到传递经过组织的、可操作的软件开发经验,使软件开发领域的新手减少知识(软件开发思想)积累中的弯路,也使软件开发领域的老手可以对照自己的经验把可能的困惑降到最低。有一些例子为那些有趣的思考提供支持。

在本书中,我会尝试对简单、想象和文化做一些形而上的思考。这些思考会比较抽象,但却是很多话题的基础。本书面向的读者

每个人的一生都在获取知识。有些知识来自于被动接受,有些知识来自于主动学习。知识有不同的类型,而学习知识又有不同的方法。

显然,本书也会提供一些知识。

在推荐谁应该阅读本书之前,了解本书提供的知识类型是很有用的。同时,在获取知识之前对知识本身进行一些思考也有助于学习效率的提升。很多领域内的行家都善于此道。[4]

李敖就是一位获取知识的大师,我非常欣赏他的学习方法。来看看他获取知识的特点:

目标简单、稳定;

围绕目标思考和行动(持续不断地收集历史资料);

享受内心自由乐趣,不盲从权威;

经过特训的大脑,善于知识归类和检索。

他一生都在阐述一个论题,论据的丰富程度达到人生的极限。你可以从主观出发不赞同他的思想,但是却无法对抗那些论据。

李敖是一位历史学家,他所学习的知识类型与软件行业不同。事实上,即便在软件行业内部,知识也有不同的类型。知识类型的不同,决定了学习方法的不同,最终对人的能力和培养提出不同的要求。

下表列出了软件开发中各种工作类型的要求。所有的定义都是非充分性的和非全面性的。它们表达出了我个人的一些偏重。关注这些偏重,对于实现我们最终的目标(成熟的软件开发能力)是有意义的。

在后续的章节中,读者可以体会到这些定义形成的思路。如果仔细阅读,你还会发现,有很多的文字都在间接地解释——这些能力在软件开发中应该是怎样的,以及为什么有助于软件开发工作。

本书提供的知识类型与上表中的知识类型有千丝万缕的联系。但是,本质上又不同于其中的任何一项。相较于务实的软件开发工作,本书提供的知识更接近于虚。所以,我把本书提供的知识类型称作思想型。

当你追溯一切问题的根源时,哲学总是追溯的源头。而当你从事软件开发工作时,当你面对软件开发中的迷惘和失败时,当你寻求解决问题的途径时,你也许会在追溯的过程中用到本书提供的知识。

所以,本书的读者,主要是那些在实际工作中陷入迷惘或存在困惑的软件开发者、管理者和企业经营者。

对于软件开发者来说,他们已经有了一定的软件开发技能,但是还没有或很少有成功的软件开发经历;他们对于软件开发工作存在着抱怨,有一些模糊的或零星的改革想法;他们热爱软件开发工作,但是感觉工作缺少乐趣;他们希望有一个明确的方向、一段可以借鉴的经历、一个行之有效的方法和一种超越以往的境界。

对于管理者和企业经营者来说,他们不满组织生产能力的现状,他们有着变革的决心,对于不成熟的软件开发能力带来的成本也有着切肤之痛,但是对于如何构建一个合理有效的软件开发环境没有思路。

本书主要是为以上三种人准备的。

遗憾的是,世上不存在可以供你直达目标的操作手册。每个人实现目标的方式都是不同的。除了最后一步的领悟之外,有效信息收集和经验积累是必需的基础。

什么样的信息是有效的呢?

简洁明确的思想表述;

层次清晰的分类信息;

令人信服的论证过程。

我一直在努力尝试,希望能为读者提供这样的有效信息。

另外,本书是我的经验之谈和人生体验。我的想法是,也许本书会让你产生共鸣,也许不会。但是有一点我可以许诺,本书的内容是前面表述的各种想法的实现,是独特的和真实的。

就软件开发而言,我根本不顾忌什么,没有任何让我盲从的权威。本书中所有的想法都是自己的真实体验,借鉴来的想法也都经过了自己的“咀嚼”。

本书中的所有内容基本上都以思想讨论为主,伴之一些验证有效的技术实践。思想讨论的内容往往会超出专业和行业的范畴,所以我期望有更多的人来参与这种形式的思想交流。

总而言之,如果你乐意,你可以阅读本书。如何阅读本书

对于读者而言,没有什么比知道如何阅读一本书更重要的了。很多书都是有价值的,从书店中得到它只是第一步。如果不清楚如何阅读这本书最有效,书的价值就不会轻易地转移到读者身上。这一小节将会告诉你如何阅读本书。

可以想象,得到一本书时,有些读者因为欠缺领域经验而需要点拨,有些读者由于相同的体验而产生共鸣,有些读者可以站在更高的层次上对书的内容进行批判。无论哪一类的读者,都期望快速清晰地获得作者的写作思路。

从作者的角度,最诚实的做法就是直白的交流。我认同一种精神,全力表明自己的想法,直到某些读者可以清楚地认识到自己是反对这种想法为止。当然,我也相信另外一些读者会赞同它。基于这种精神,本书中所有问题的表述都是断言式的,不留有任何引申和狡辩的空间。

本书中大多数章节的第一部分是实践场景,场景中包含了虚构的情节和虚构的人物。你可以把这些场景单独挑选出来,当作一篇描写软件开发者生活的文学作品。你也可以忽略这些场景,这不会影响你获取本书中的知识。

场景是一个理想中的美好故事,它不能传递明确的知识信息。写作这个场景故事的主要目的,是想说明现实中的软件开发活动比本书中涉及的讨论要复杂和生动得多。例如,一个人的些许想法可能会给软件开发带来极大的影响。我不是一个不可知论者,即便在复杂多变的现实场景中,简单的原则同样能产生有效的影响。

我一直在考虑一个问题:

业界有很多流行的方法论,也有很多大师的软件开发思想,可是[5]在实践中,好像还是有很多组织找不到方向。比方说,敏捷开发,我真的没有看到多少成功的案例。我知道的是,大家在不断地缩减Scope,不断地提升Schedule评估的时间,从而来适应传统的管理方式。我也听到很多管理者在议论哪种方法论是最好的,好像实施了某种方法论就可以解决所有的问题,可是问题仍然在那里没有变,只是换了个形式。

所以我想,问题的根源也许不在这里。我觉得,无论方法论也好,管理理论也好,都是技术层面的。这些技术层面的东西来自于很多大师长期的总结和提炼,本身是非常好的,但是它们有复杂的上下文,例如在敏捷开发中没有提到或者强调的——注重个体文化、专业化思想以及多元化价值认同等。所以,一旦割裂上下文,机械来运用这些方法论,效果就总是不好。

在本书中,我想从实践者的角度来强调这一点,通过强调软件开发思想和文化来尝试连接实践和方法论。

场景故事也是在这个想法上产生的,我很想反映现实的复杂性,在这种复杂性场景中,读者可以发现自己熟悉的人和事,我希望可以产生共鸣。然后,我想推荐用简单的思想和一些文化反思来应对它,至于效果如何,那肯定是仁者见仁智者见智了。

在大多数章节场景故事之后的第二部分,我会首先列出作者写作本章节的中心思想。这些中心思想是断言式的、概括式的。读者需要通过阅读本章节后续展开论述的内容来了解中心思想的具体含义。

本书想要传递的思想是,用简单的原则、富于想象的精神、文化的视角来认识软件开发。请在阅读时始终关注这个核心思想。

我的E-mail地址是:jianni@hotmail.com,欢迎读者朋友的来信。

[1]禅宗,又称宗门,汉传佛教宗派之一,始于菩提达摩,盛于六祖慧能,中晚唐之后成为汉传佛教的主流,也是汉传佛教最主要的象征之一。汉传佛教宗派多来自于印度,但唯独天台宗、华严宗与禅宗,是由中国独立发展出的三个本土佛教宗派。其中又以禅宗最具独特的性格。禅宗祖师会运用各种教学方法,以求达到这种境界,这又称开悟。其核心思想为:“不立文字,教外别传;直指人心,见性成佛”,意指透过自身实践,从日常生活中直接掌握真理,最后达到真正认识自我。

[2]慧能(638—713),俗姓卢氏,河北燕山人(现今的涿州),生于岭南新州(今广东新兴县)。佛教禅宗祖师,得黄梅五祖弘忍传授衣钵,继承东山法门,为禅宗第六祖,世称禅宗六祖。唐中宗追谥大鉴禅师。他是中国历史上有重大影响的佛教高僧之一。陈寅恪称赞六祖:“特提出直指人心、见性成佛之旨,一扫僧徒繁琐章句之学,摧陷廓清,发聋振聩,固我国佛教史上一大事也!”

[3]Robert C.Martin是Object Mentor公司总裁,面向对象设计、模式、UML、敏捷方法学和极限编程领域内的资深顾问。他不仅是Jolt获奖图书《敏捷软件开发:原则、模式与实践》(中文版)(《敏捷软件开发》(英文影印版))的作者,还是畅销书Designing Object-Oriented C++Applications Using the Booch Method的作者。Martin是Pattern Languages of Program Design 3和More C++Gems的主编,并与James Newkirk合著了XP in Practice。他是国际程序员大会上著名的发言人,并在C++Report杂志担任过4年的编辑。

[4]李敖(1935年4月25日—),字敖之,吉林省扶余县人,祖籍山东省潍县,出生于黑龙江哈尔滨。中国台湾作家、中国近代史学者、时事批评家、思想家。被称作台湾第一狂人、斗士、“文化顽童”。

[5]敏捷软件开发又称敏捷开发,是从20世纪90年代开始逐渐引起广泛关注的一些新型软件开发方法,是应对快速变化的需求的一种软件开发能力。它们的具体名称、理念、过程、术语都不尽相同,相对于“非敏捷”,更强调程序员团队与业务专家之间的紧密协作、面对面的沟通(认为比书面的文档更有效)、频繁交付新的软件版本、紧凑而自我组织型的团队、能够很好地适应需求变化的代码编写方法和团队组织方法,也更注重软件开发中人的作用。第1章无极生太极

在进入软件开发领域之前,我们必须要做一些思想上的准备。这种思想上的准备高于方法论,以及任何一项具体的工作内容,它可以使我们站在一个更高的角度来认识软件开发这项活动。思想认识是解决问题的根本,这一章的内容体现了思想工作的重要性。

我们将围绕三个基本思想展开讨论:首先,软件开发是一项创造性的活动,因为它的创造性,我们要特别关注软件开发中的想象力;其次,我们要把握认知方法的本质,通过有意识地建立自己的思想体系来学习各种知识;最后,我们要力求对软件开发中的各种问题进行简化,只有简化问题,才能高效地解决问题。

在讨论中,我们会结合一些具体的技术背景知识。这些技术背景知识或者比较基础,或者泛泛而谈。事实上,我们的目标不在于详细介绍这些知识本身,而只是为上述三个基本思想的讨论提供一些证据。1.1 创造的根源

软件开发越来越需要创造力。创造的根源在于想象。如何运用想象能力以及提升想象技能,是软件开发成功与否的关键。

什么是创造?最简单的说法就是,经过人的智慧的加工,通过非必然的过程,产生非必然的结果。创造不能复制,每一次都是独特的。[1]

钱学森先生认为,人的思维有三种类型:逻辑思维、形象思维和灵感思维。

逻辑思维是线形的,借助于数学和逻辑学中的公理,可以根据一些信息推导出精确的、必然的结果。

形象思维是面形的,在解决一个具体问题时,由于现象提供的信息非常复杂,无法完全使用逻辑推理的方式产生结果。在这种情况下,非科学性的知识和以往的经验,甚至人体中未被认识的特殊功能都可能帮助我们解决问题。

灵感思维是三维的,人类可以在潜意识中完成一些看似无法解决的问题。潜意识的研究目前还处于非常肤浅的阶段。我们谈论的创造是发生在人类可以控制的显意识方面的,主要是指形象思维。

我们说,软件开发越来越需要创造力,越来越需要形象思维。这种说法是有道理的,它体现在软件开发领域的方方面面。例如,编程语言的发展,就可以作为这个断语的证明。

众所周知,编程语言经过多年的发展,已经从面向机器的低级语言“进化为”面向领域和对象的高级语言。越是高级的语言,抽象程度就越高,人类想象力和创造精神的特征也越明显。

15年前,我刚刚进入工业控制行业,从事嵌入式设备(单片机)的软件开发。这段经历使我有机会从硬件的角度来认识软件的本质。10年前,我开始从事企业级信息系统的开发,在应用软件的构建方面积累了一定的经验。这段经历又使我有机会从领域的角度来认识软件。

为了论证上面提到的关于创造的观点,我想结合自己的经历,谈谈对单片机、编程语言和企业信息系统的认识。这些认识看上去非常基础,涉及的内容听上去有点枯燥,但它们却是想象的基础。

我有一个有趣的想法:如果人们愿意定心敛神,细细体会熟视无睹的事物,一定可以得到超出想象的收获。

在谈单片机之前,必须先提到两个基本的概念:二进制和与或非逻辑。

二进制是计算技术中广泛采用的一种数制。这种数制,只包含0和1两个数,基数是2,进位时逢二进一,借位时借一当二。

与或非逻辑是布尔代数中的基本运算逻辑。在布尔代数中,同样只有两个逻辑值,逻辑1和逻辑0,代表两种相反的逻辑状态。逻辑“与”相当于生活中说的“并且”,在两个条件都同时成立的情况下,逻辑“与”的运算结果是“真”;逻辑“或”相当于生活中说的“或者”,只要两个条件中有任意一个条件满足,逻辑“或”的运算结果是“真”;逻辑“非”表示与本来的情况相反的情况。

与或非逻辑代表了人类的一种思维规律,同时与二进制吻合得天衣无缝。我们来看看二进制运算中的与或非逻辑。

二进制加法有四种情况

0+0=0(逻辑或)

0+1=1(逻辑或)

1+0=1(逻辑或)

1+1=0(进位为1)(逻辑或,然后是一次有趣的移位)

二进制乘法有四种情况

0*0=0(逻辑与)

0*1=0(逻辑与)

1*0=0(逻辑与)

1*1=1(逻辑与)

关于二进制和与或非逻辑的更多知识,大家可以查阅相关的参考书。

我想强调的是,二进制和与或非逻辑这两个概念可以很容易地通过硬件来实现。例如,5V电位(通的状态)代表1,0V电位(断的状态)代表0。逻辑“与”则涉及两个输入电位和一个输出电位,当两个输入电位分别为5V和0V时,输出电位为0V。场效应管CMOS或者双极晶体管TTL这些具有开关特性的电子元件都可以实现这种逻辑要求。

简单来说,电子计算机就是可以进行二进制计算的机器。它可以帮助人类节省逻辑思维的时间和精力,目前它能帮助人类的也仅此而已。

单片机中包含了大量具有开关特性的电子元件。作为一种微型计算机,它几乎具有普通计算机的所有特征。大规模的集成电路给了二进制和与或非逻辑表演的平台;CPU处理自己可以识别的指令,并帮助人类进行逻辑计算;IO系统处理各种数据和地址信息;晶振可以保证电子元件间的同步与协作;中断系统则像一位计算任务的调度员。存储器通常是一个必需的外部系统,存储的内容包括指令(程序)和数据。地址总线和数据总线为CPU建立了与外部系统联系的通道。

单片机的基本组成看上去并不复杂,我们来看看它的工作原理。

首先,单片机需要加电。电子元件的各种特性要依赖于特定的电压和电流。单片机加电后,电子元件有电流通过,晶振开始工作。于是所有的元件有了时间规则,有了合作完成一项任务的基础。中断系统处在待命状态,等待任何一项任务的触发条件。CPU借助于地址总线和数据总线,从存有指令的存储器中获取指令(程序),这些指令全部是二进制的。它们不是任意的,而是CPU指定的二进制格式。指令(程序)中可能涉及一些位于特定存储地址中的数据,CPU还要负责从那些地址中取数。CPU按照指令的要求进行计算(利用电子元件的开关特性),计算的结果可能会存放到指定的存储地址中;也可能暂时存储在和CPU关系更紧密的内部空间(存取速度比外部空间更快),例如累加器或其他寄存器;计算结果(一系列的开关信号)更有可能通过数据总线输出到指定的IO。IO是计算机连接现实世界的桥梁。

我曾经开发过铁路道岔预警系统,那些指定的IO被连接到一些微型开关。这些微型开关控制着一些LED光带,从而可以展示整个道岔系统的状态。

谈到这里,我们终于可以引出软件的概念。什么是软件?本质上就是那些特定于CPU的二进制指令的集合。在我所使用的单片机中,二进制指令是8位的。根据CPU的不同,指令也可能是16位、32位或64位。这些指令,从操作人员的角度看,就是一些语言;从机器的角度看,就是一组开关信号。老实说,当你用示波器去看那些指令、地址或数据时,一定会在软硬件的交界点上感慨万千。

好,我们谈到了语言。当这些语言经过组织、编排,从而让机器自动化工作时,我们又有了程序的概念。

15年前,我使用汇编语言来编写单片机程序。汇编语言与机器语言(完全由0和1组成,可以把机器语言看成是特定于CPU的开关信号)是完全对应的。两者之间的些微区别在于,汇编语言提供了一些人类可以理解的助记符,例如,数据传送符、跳转符、条件符、中断符等。关于汇编语言的细节,可以参考相关的书籍。

在使用汇编语言的时候,需要了解数据存储的地址、数据传送的目的地、二进制数运算的方法以及各种寄存器的特殊用法。

在汇编语言中,数据结构的概念是很淡的,更不要说围绕数据结构展开的算法了。数据结构和算法的繁荣发生在比汇编语言高一级的编程语言中,例如C语言。

出现一种更高级的语言是人类抽象的需要。抽象,是因为发现了逻辑推理中的规律。这些规律具有可以重复使用的特征,但是,规律本身重现起来比较复杂。

例如,用汇编语言来实现一个四则运算就有点复杂。在汇编语言中,既没有足够丰富的对人友好的操作符,而且在处理数学计算时会涉及不少硬件概念。你看,因为CPU的不同(机器语言不同)、硬件调度上下文(使用不同的寄存器)的差异,四则运算的实现也不会完全一样。而C语言(也包括很多其他的高一级语言,BASIC、Fortran)的出现,满足了人类在进行数学计算过程中的抽象要求。

为了实现数学计算的抽象,这些高级语言的背后,还有很多相关的技术在支撑着,例如,C语言编译器、链接器、运行库、操作系统加载器等。C语言编写的程序和其他语言编写的程序,在运用计算机这个硬件资源上没有什么区别;那些隐藏在幕后的技术,使我们可以仅仅关注于抽象的程序,而几乎不考虑硬件的问题。

C语言在一定程度上解决了人类在数学计算和逻辑推理上的抽象。从此,软件的主要关注点转移到数据结构(线性表、栈、队列、串、数组、二叉树、图等)和各种算法(对特定问题的求解过程)上,经过多年的发展,数据结构和算法已经成了计算机专业的一门基础课程,而几乎所有的教科书,都是用规范的数学语言来描述数据结构的。

算法就是数学问题的求解过程。在使用C语言来实现一个软件系统时,逻辑思维占了绝对的比重。

10年前,我又开始从事企业级信息系统的开发。工作中接触最多的是Java语言。从语言的抽象程度来说,Java语言与C语言没有太大的区别。Java语言同样可以解决C语言能处理的一切问题(可以描述相同的数据结构,并给出相同的算法)。一个微妙的不同之处在于,Java语言对于数据结构中的数据类型进行了新的抽象,引入了类和对象的概念。因为这个概念的引入,一次新的面向对象的革命产生了。

当代的企业级信息系统与Java语言结合得非常完美,这不是偶然的。我们知道,企业级信息系统需要解决的是领域问题,而不单单是数学运算问题。

领域问题最终会转化为一个个数学运算,但是在求解领域问题的过程中,仅仅依靠数学知识是远远不够的。

例如,保险公司的承保业务,不仅需要大量的信息数据,还需要复杂的业务逻辑。要描述这些业务逻辑,必须站在领域的高度上进行。此外,复杂多变的用户需求、数不胜数的方案模型、参差不齐的开发团队、成年累月的项目周期,这些各方面的因素都会对信息系统的开发产生影响。

处理领域问题就像战场上的一个个战役,指挥官决策(问题求解)时,可以参考和依据的现象太复杂了,他必须借助面形的思维(经验、习惯以及形象思维)才能指挥队伍朝正确的方向前进。

Java语言恰好是进行面形思维的一个好工具。

为什么这么说呢?因为Java语言引入了类和对象的概念。这使得这种语言的使用者从单纯的逻辑思维中跳了出来。人们开始发现,编程语言与领域世界是如此贴近,以至于人类的想象几乎可以完整地从软件系统中再现出来,换句话说,人们可以使用Java语言进行隐喻式编程了。关于隐喻式编程的详细内容,我会在第4章的某一节展开讨论。

Java语言培养了我在软件开发中的想象能力,这是其他任何一种编程语言都没有给过我的。

多年前,我曾经阅读了Tomcat(一个开源的servlet引擎,用Java语言实现,它也提供Web服务)的源码。我看到一个HTTP的请求被Tomcat监听到以后,它根据请求数据中携带的特征,开启了不同的阀门。开启的阀门引导数据流进入相应的管道。管道中有各种解释器对数据进行分析。分析后再转发给相应的处理器。简直不可思议,我就像阅读一个故事,第一次从软件中体验到了一个想象的世界!

这次阅读使我开始反思自己的软件开发生涯。反思的结果是:

多年来一直在编写程序,而且翻阅了不少软件产品或技术的操作手册;

已经比较善于理解各种需求了,而且可以直接地给予实现;

可以从软件的运行中得到乐趣了,可是还没有开始关注软件本身;

学到了一些知识,但是这些知识总显得杂乱零散;

我的软件开发工作几乎没有任何创造性。

反思中的最后一条使我很震惊,我也因此领悟了一些道理。总结起来只有一句话:软件的美和价值在于创造,创造的根源在于想象。

此后,我按照自己领悟的道理来评价我所接触到的一切事物。我不再觉得迷惘、犹豫,一切仿佛都变得简单了。我开始追求一个富有创造力的想象世界。

当然,想象世界并不依附于编程语言而存在,但是,一种合适的编程语言可以使我们更容易地表达想象。基于这个原因,我认为Java语言是C语言的一个发展。当然,如果你有一个足够抽象的库,如果你不考虑内存分配和释放,如果你不使用寄存器,如果你不使用地址概念和指针,C语言也能和Java一样,让人驰骋在一个更高级抽象的想象世界。

我开始觉得有趣了。编程语言的发展,扩展了我们想象的空间,也帮助我们养成了一些想象的习惯。你看,我们可以把Web服务想象成一个政府的办公流程,甚至可以是一次朋友的聚会。这些想象可以用来创造软件,而且为软件带来了异乎寻常的活力。换句话说,我们的人生阅历,可以用来帮助自己进行想象和创造,并把它们用软件的形式表达出来,这不是很有趣的一件事吗?

不过,在软件开发中,想象和创造是需要一定技能的。这不仅体现在编程上,还体现在软件开发中的方方面面,包括思考方法、项目管理、架构设计,等等。本书中有一些想象和创造的例子。

能够充分展开想象,是创造能力的集中体现。

事实上,在我所经历的一些糟糕的软件开发案例中,最大的问题,往往源于缺乏想象或想法混乱造成的软件架构问题,以及毫无想象力的、僵化的项目管理思想。只有较小的一些问题,来自具体的工作细节,例如,糟糕的算法和糟糕的逻辑思维。这也从另一个角度证明了想象和创造的价值。

[1]钱学森(1911年12月11日—2009年10月31日),浙江杭州人,中国空气动力学家,中国科学院、中国工程院院士,中国两弹一星功勋奖章获得者之一。曾任美国麻省理工学院教授、加州理工学院教授,为中美两国的导弹和航天计划都曾作出过重大贡献,被誉为“中国航天之父”和“火箭之王”。1.2 本质的把握

把握软件和软件开发的本质,可以使知识和技能的积累变得更加高效,而把握认知方法的本质,可以使知识和技能的积累总是走在正确的道路上。

什么是软件的本质?在前一节中,我给出了自己对于软件本质的理解,那就是二进制和与或非逻辑。

我不认为二进制和与或非逻辑是对软件本质的唯一解释,事实上,每个人对软件的本质都有着自己的理解。人们在自己的思想长廊中往前追溯,然后会在一个地方停下来。他们认为,在这个地方,一切都是常识性的知识,虽然可以继续分解和往上追溯,但是已经没有必要。我把这种状态下对软件的认识称作软件的本质。

而软件开发的本质是什么呢?

软件开发是一项具有艺术性的科学工作。一方面,因为软件是逻辑学和数学的应用,所以软件开发是科学性的工作;另一方面,因为软件的实现有无限种结构形式,而且每一种结构形式都富含人类的创造和想象,所以软件开发是艺术性的工作。

有些人还可能会从心理学和管理学角度来阐释软件开发的本质。我不赞同这个观点,但这不是重点。

重点是什么呢?

重点是我们需要形成一个自己的、系统而且完整的观念。这种观念,一定会与你所有的认知融合在一起。它来自经验和实践,反复验证之后会成为你思想的一部分。很显然,要排斥一种观念是容易的。可是,没有自己的思想体系,就更加容易陷入一种迷惘的状态。

如果你尝试建立有体系的观念,你会用自己的观念解释一切,你也会不断地在失败中修正观念,那么你最终会在自己观念的带领下走向成功。举个例子,在现实世界中,苹果会从树上掉下来,你不会怀疑这一点,这就是你的世界观的一部分。可是,在微观世界里,你的观念会遭到重大打击。你需要调整世界观,用更复杂的方法来解释世界。你不断调整,最终得到真谛。这种有体系的观念,我称作思想体系。

思想体系的建立是很有用的。我们不妨以学习为例。你知道吗?最有效的学习方法就是用自己的思想体系来接纳外部知识。这也可以说明一个问题,你看,在计算机书店,有很多大师级的作品,他们的知识向所有人开放,可是很多人从中得到的收获总是非常有限的,为什么?因为思想体系还没有建立,很多人还无法对书中的知识进行有意识地提炼和抽象,所以总是会有很多疑惑和不解。

其实,只要经过足够长的时间,每一位软件开发人员都会不自觉地形成自己的软件开发思想,这和过日子是一样的。

不过,有很大一部分软件开发人员在经历短暂的思想积累以后,却偏离了软件开发的方向。很多软件开发人员,热衷于转向另一个更加不成熟的领域——软件开发管理。糟糕的是,这些不成熟的软件开发管理人员,在不自觉中为其他软件开发人员设置了更多通向成熟的障碍,最终破坏了软件开发的整体环境。

在以后的章节中,我们会详细讨论与软件开发管理相关的问题。这里我想先简单表达一个观点——管理,其实是软件开发中的辅助性工作,它很重要,但不是必需的。好的管理是高效的燃油添加剂,但是,我已经看过太多糟糕的管理,它们对软件开发的负面影响远大于软件开发人员自身。

软件开发思想难以形成体系,除了浮躁和放弃,还有一个原因。

在我们这个时代,很多软件开发人员都比较年轻,他们正在进入一个眼花缭乱的世界。与二十年前的软件开发人员相比,他们面临着更多的选择。而要想做出正确的选择,需要时刻保持清醒的认识和精准的判断。在软件领域中,充满了丰富的创造成果和层出不穷的新概念,毫无目标的追逐会使有限的积累能力稀释,从而使知识和技能的提升变得低效,甚至走向错误的道路上。

我在软件开发生涯中同样走了很多弯路。比方说,我曾经如饥似渴地阅读了大量自己不太理解的软件书籍,可是收效甚微。当我回头反思自己的软件开发生涯时,一方面认识到自己不是一个具有软件开发天赋的人,另一方面也为自己没有幸运地得到正确的指点而深感遗憾。哪方面的指点呢?不是如何使用某一款开发工具,也不是如何实现某一个精妙的算法,而是积累知识和技能的方法。

方法是我们一生中最有价值的知识财富。

谈到这里,我想到一个有趣的社会现象。

很多软件开发人员都接受了4年的大学高等教育,但是他们中的大多数人并不为自己在这期间取得的成绩而骄傲,有些人甚至还抱怨自己没有学到任何有用的知识。这种认识是不够全面和客观的。其实,我们在这4年里学到了最重要的知识——做人和做事的方法。在那段时间里,我们开始独立生活和思考,开始与一些和自己的成长环境不同、但知识和思想层次与自己接近的年轻人互相接触和相互影响,开始独立地为自己的生活和学习做决策等。与这些相比,学科内容本身并不是那么重要。

总之,如果思想体系没有建立,找不到建立思想体系的方法,以及不会应用思想体系来解决问题,我们就无法把握事物的本质。

在进入企业应用领域的这些年,我接触了很多新的概念:包括客户端、服务端、Web服务器、应用服务器、服务端容器、应用框架、[1][2]远程方法调用、Web Service、SOA、ESB、BPMS等。每个概念都有数量庞大的衍生内容。对于新进入这个领域的开发人员来说,一下子面对这么多的概念会有点无所适从。

按照我们前面的说法,建立一个思想体系是最重要的。也就是说,只有在一个完整的上下文中思考才能真正解决问题。所以,我尝试用一条线索把上面的概念串联起来。

在1.1节中,我们提到了编程语言的发展。编程语言是软件开发必须使用的计算工具。在企业应用中,计算工具仍然是这些编程语言,只是计算的平台被推广到了网络上。

很多计算机连接在一起组成一个网络。连接的含义是指,计算机之间可以进行开关信号的传递(有线或者无线),为了保证连接和那些开关信号是有意义的,业界制定了一些标准协议。例如,TCP/IP协议。若想了解网络协议,可以参考相关的书籍。

在企业应用中,网络连接很重要,一方面是因为它能满足基本的信息传递的需求,另一方面还可以通过网络连接来使用其他计算机的计算能力。计算机的价格与计算能力通常存在一个指数关系,所以企业必须充分使用那些昂贵的计算能力。

提供计算能力的计算机就是服务器,而请求利用这些计算能力的计算机就是客户端。

我不认为软件开发人员充分认识了这一点。当系统面临着计算性能问题时候,很多软件开发组织甚至还没有意识到分布计算的重要性。

如何利用服务器的计算能力呢?有很多种方式。这些年,业界最流行的是Web服务模式。在这种服务模式中,客户端变成了浏览器(甚至屏蔽了计算机的概念),服务端则是遵循Web协议的任意实现。换句话说,采用这种服务模式的企业应用,只是借用了Web服务与客户端交互,位于延伸空间中的各种概念与创造并不依赖于Web服务。

通常情况下,应用服务器是Web服务器之后的第一个延伸。Web服务器对客户端请求信息(URL)进行分拣,具有指定特征的信息交由应用服务器来处理。

为什么需要应用服务器,而不是直接面对应用程序?这是因为很多有价值的公共任务需要应用服务器来处理。以Java EE应用服务器为例,应用服务器负责建立一个企业应用程序空间,把JSP页面编译成Servlet,管理服务线程,维护各种寄居于容器中的组件生命周期,提供事务服务、安全服务和消息服务,还有像配置管理、外部资源连接、数据库连接池等。应用服务器的作用是很大的。

我们提到了服务端容器,这又是个有趣的概念。我们知道,为了使用应用服务器提供的各项服务,你必须按照容器定义的接口来开发组件。这些组件往往无法独立存在,甚至连生命周期也掌握在容器的手中。这有点类似于回调函数,但是比回调函数的想象丰富多了。

很多软件开发人员毫无节制地开发容器组件,程序中到处散布着和容器相关的参数。这种做法是不对的。尽管容器提供了丰富的功能,但仍然要尽量使应用程序和容器隔离,经过这样隔离的应用程序才具有良好的移植性。实际上,应用程序应该与任何第三方的框架和平台隔离。

对于企业应用来说,有了应用服务器和服务端容器还不够,有很多第三方的应用框架对应用服务器的功能做了一些补充。例如,Struts使用MVC模式为页面与后台应用之间建立了一种新的联系方[3]式,Spring提供了一个轻量级的容器实现等。这些第三方应用框架中的优点正在被缓慢地引入到应用服务器的标准中。

为了更好地使用服务端的计算能力,我们要用到服务端的分布式计算。事实上,应用服务器早就支持了这种计算模式。服务端的分布式计算是高性能企业应用的基础,而远程方法调用则是分布式计算的基础。

远程方法调用使分布式应用与单机应用从程序代码这个级别看上去变得没有什么不同。当然,远程方法调用有一些额外的工作要做,例如,对于RMI(Remote Method In-vocation,远程方法调用)来说,需要使用RMI注册服务器来获取远程方法的引用。

RMI的问题在于,首先它是Java特有的(虽然可以与其他语言进行映射);其次它使用了特定的服务协议。于是,业界提出了Web Service的概念。这使远程方法调用被提到一个新的高度。与RMI这类的实现截然相反,Web Service独立于任何平台。它可以附加在HTTP这类最普遍使用的协议上,完成异构平台间程序代码级别的整合。

在Web Service出现的头几年,业界并没有找到使用它的最佳场景。直到某一天,它悄然成为SOA的一块重要基石。

我们正处在SOA概念泛滥的年代,有些人拥抱它,有些人排斥它。其实SOA一点也不神秘,它只是远程方法调用的变体。不过,这种变体是革命性的,它改变的不仅仅是一种技术实现,它改变的是构架企业应用软件的思想。

为什么呢?

企业应用软件传统的构建方法是,首先进行数据或对象建模,然后基于这些模型来完成业务功能。这个过程不是一次就能成功的。

因此,在分析和实现业务功能的时候,要时时对数据或对象模型[4]进行修改。修改的工作比较烦人,涉及大量遗留的应用。MDA希望完成模型到业务功能的自动化,从而尽量减少烦人的修订工作。

当然,传统的构建方法也不是刻板的,在数据或对象建模前,通常会尽早地使用用例来描述业务功能。即便如此,传统方法的首要目标仍然是数据或对象模型。

而与传统方法不同,SOA面向服务来建模。它更偏重于用例中的行为,而不是实体。之所以关注行为,是因为SOA有一项特殊的使命,那就是整合企业中的所有应用,包括新规划的系统和已有的系统。

对于已有的系统(软件资产),考虑数据和对象模型意义不大,考虑如何利用已有系统的功能才是关键。所以,如何快速有效地抽取已有系统的功能,是首先要考虑的事情。

由于Web Service的发展和普及,抽取功能已经是一件很容易的事情了。这为SOA的推广铺平了道路。

对于新规划的系统,使用传统构建方法更好。很多软件开发组织,总在追寻解决问题的银弹。其实,没有打中目标,通常不是弓箭不好,而是你还没有掌握使用弓箭的技能。

因为SOA的普及,ESB也变得引人注目。注意到了SOA的特殊使命了吗?企业服务总线就是用来整合企业的所有应用的,它支持异构的系统在一个共同的契约下发生关系。就这么简单。

与之类似,BPMS也应运而生。SOA确立了整合系统的思想,ESB提供了准备就绪的服务,业务流程管理系统就是使用这些服务的工具和平台。

好了,以上就是我对那些概念的思考。

我把那些概念串成了一条线索。现在,线索中的每一个节点,都有了一个合理的解释。我不认为自己的解释和线索是唯一的,甚至也许有些还不够准确。但重要的是,我现在有一个体系来接纳新的概念了。

根据以往的经验,思考新的概念,经过解释、修正、再解释,最后把这些新概念转化成为思想体系的一部分。这应该就是认知方法的本质了。

[1]ESB(Enterprise Service Bus,企业服务总线),是指由中间件基础设施产品技术实现的、通过事件驱动和基于XML消息引擎,为更复杂的面向服务的架构提供的软件架构的构造物。企业服务总线通常在企业消息系统上提供一个抽象层,使得集成架构师能够不用编码而是利用消息的价值完成集成工作。

[2]BPMS(Business Process Management System,业务流程管理系统)的思想以一种统一、中性的表示方法描述业务流程模型,使业务流程模型从实现逻辑中抽取出来,被各个企业应用程序所使用,从而灵活地构建基于流程的信息系统。

[3]如果你有兴趣通过研究Spring的源码来理解Spring的架构、设计和实现原理,从而更好地应用Spring进行开发,推荐阅读《Spring技术内幕——深入解析Spring架构与设计原理》一书。

[4]MDA(Model Driven Architecture,模型驱动架构)是由OMG定义的一个软件开发框架。它是一种基于UML以及其他工业标准的框架,支持软件设计和模型的可视化、存储和交换。与UML相比,MDA能够创建出机器可读和高度抽象的模型,这些模型独立于实现技术,以标准化的方式储存。MDA把建模语言用作一种编程语言而不仅仅是设计语言。1.3 简单的追求

软件开发,尤其是企业应用软件开发,最根本的原则是简单化。简单可以使表达准确、思路清晰,可以实质性地、最大限度地降低软件开发成本。简单化不是天方夜谭,它是可以实现的。

在讨论软件开发中的简单化原则之前,我们不妨先来认识两个[1][2]人。他们是中国近现代哲学史上的两位大家——金岳霖和冯友兰。很有趣,这两个人在表述哲学观点时,风格截然不同。金先生总是喜欢把简单的事情表述得很复杂,而冯先生呢,总是能把复杂的事情表述得很简单。我们来欣赏两段文字。

金先生在《论道》的“第8章——无极而太极”中写道:

道无始。所谓无始就是说无论把任何有量时间以为底始,总有此时间之前的道;或者说从任何现在算起,把有量时间往上推,推得无论如何的久,总推不到最初有道的时候。可是,道既然无始,为什么又有极呢?如果有极,那极岂不就是道底始!这极是极限的极,是达不到的极。它虽然是达不到的,然而如果我们用某种方法推上去,无量地推上去,它就是理论上推无可再推的极限,道虽无有量的始,而有无量地推上去的极限。我们把这个极限叫做无极。

冯先生在《中国哲学简史》中论述自己对于哲学的看法:

哲学,和其他各门知识一样,必须以经验为出发点。但是哲学,特别是形上学,又与其他各门知识不同,不同之处在于,哲学的发展使它最终达到超越经验的“某物”。在这个“某物”中,存在着从逻辑上说不可感只可思的东西。例如,方桌可感,而“方”不可感。这不是因为我们的感官发展不完全,而是因为“方”是一“理”,从逻辑上说,“理”只可思而不可感。

在这个“某物”中,也有既不可感,而且严格说来,亦不可思者。在第一章中,我说哲学是对于人生有系统的反思的思想。由于它的反思的性质,它最终必须思想从逻辑上说不可能成为思想的对象的“某物”。例如,宇宙,由于它是一切存在的全体,从逻辑上说,不可能成为思想的对象。我们在第十九章已经知道,“天”字有时候在这种全体的意义上使用,如郭象说:“天者,万物之总名也。”由于宇宙是一切存在的全体,所以一个人思及宇宙时,他是在反思地思,因为这个思和思的人也一定都包括在这个全体之内。但是当他思及这个全体,这个全体就在他的思之内而不包括这个思的本身。因为它是思的对象,所以与思相对而立。所以他思及的全体,实际上并不是一切存在的全体。可是他仍须思及全体,才能认识到全体不可思。人需要思,才能知道不可思者;正如有时候人需要声音才能知道静默。人必须思及不可思者,可是刚一要这么做,它就立即溜掉了。这正是哲学的最迷人而又最恼人的地方。

从逻辑上说,不可感者,超越经验;既不可感又不可思者,超越理智。关于超越经验和理智者,人不可能说得很多。所以哲学,至少是形上学,在它的性质上,一定是简单的,否则它又变成了简直是坏的科学。它虽然只有些简单的观念,也足够完成它的任务。

我本人偏好冯先生的那种简单表述。不过,哲学家的工作,是一种个人的行为。岳先生的文字尽管复杂晦涩,但读者有充裕的时间去揣摩他的观点。从这个角度来看,复杂性没有太大的问题。可是,在软件开发的过程中,复杂形式的思想交流就有点不可思议了。我们总是希望接触到最直白的常识。

要想用最直白的常识来交流,把握事物的本质是关键。而为了把握本质,我们首先需要认识事物。

一般来说,人们认识事物从简单开始,经过简单认识的不断堆积,然后在混乱复杂中摸索,最后又回归简单的认识。这样的认识过程同样适用于软件开发领域。

因此,在软件开发实践中,我们应该有意识地向认识的最高形式——简单化——靠拢。事实上,简单与否,常常可以成为衡量我们对事物认识程度的一个标准。我们不妨按照简单的标准来认识一下企业应用软件。

在我看来,企业应用软件很简单。它主要包括三个部分:一个领域模型,一组基于领域模型的计算,以及用来和用户交互的界面。这是一个基本的思路。

任何时候都不要轻易丢弃一个非常简单的原则性想法,同时,在任何时候都不要固执于一个具体的想法细节。

不过,当我们把这个基本思路应用到软件开发实践中去的时候,可能会发现,还有一些相关的工作要做。例如,领域模型在工作时会涉及信息的使用和存储。因为存储的需要,所以要了解数据库(现在的OR Mapping工具使你不用更多地了解它)。

老实说,为了恪守简单的原则,我们应该逐渐进入细节。在这个例子中,思考领域模型的时候不要立即开始考虑数据库的因素。可以做到吗?

答案是,很多软件开发人员都做不到。他们总是忍不住会立即去考虑效率、领域模型中各元素的关系如何在数据库中的表达、OR Mapping工具在使用中的一些限制等。

忍不住的结果就是,他们停留在一个点上,想了很多方法来解决他们担心的事情。因为这样的事情总是有很多,所以简单的原则总是被违背,而复杂性总是不期而至。

具有讽刺意味的是,在软件开发实践中,很多设计人员提出的针对性能的解决方案往往是性能的最大瓶颈。

假设我们恪守了简单化原则,同时有了一个满意的领域模型,接下来的事情就是基于领域模型的计算。

在系统工作期间,领域模型会产生很多的实例,这些实例拥有自己的数据。企业应用软件的主要工作内容基本上就是围绕这些数据做些加加减减的工作。

当然,除了加加减减,我们还需要了解一些相关的知识。

第一,业界有很多的平台和框架支持加加减减,例如Java EE、Spring、Seam等。而这些平台和框架又提供了一些服务,例如,分

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载