大道初践 - 介绍Bertrand Meyer的程序设计引论教材:Touch of Class -- 软件行者 [an error occurred while processing this directive]
SoftwarePractitioner.org


首页

作文

翻译

随笔

本站

English
  


大道初践

--介绍Bertrand Meyer的程序设计引论教材:Touch of Class

胡健

2009年12月

Bertrand Meyer是位面向对象技术的大师,他具有深厚的计算机科学理论素养与长期的工业界的软件 工程实践经验。他的出色工作奠定了他在OO技术和软件工程方面的地位,在2001年10月被聘为瑞士 联邦技术学院的教授、软件工程主任(Chair of Software Engineering)。

Meyer对于软件工程教学一直有着浓厚兴趣,早在1990年代初,他就提出了基于OO原则的软件教学思想。 Meyer教学思想的立足点是试图在概念和操作(原理和技术)之间保持一种平衡,其核心是(基于OO技术的) 逆向大纲(inverted curriculum)教学法。Meyer认为这种途径能够让学生很好地掌握软件建造的关键概念, 如抽象、信息隐藏、复用、契约等。

Meyer的这套教学思想到他被聘为瑞士联邦技术学院的软件主任(2001年)之后开始计划实施。其中很重要 的一门课程便是引论性程序设计。具Meyer介绍,瑞士联邦技术学院的计算机学科最好的传统之一是 引论性课程的任课教师必须是资深教授。这与有些学校中引论性课程由初级教师任课的观点截然相反, 因为学院认为那些在本学科积累了最多经验的教师应该去教最基础水平的新生。此教学法在“引论性程序 设计”课程中六年的实践和学生对该课程的评分表明逆向大纲教学法是成功的。

Meyer在教课的同时,也在为这门课编写教材,名为“Touch of Class”,在经历了六多年的反复 修改之后终于今年(2009年)9月出版发行。

总纲性的前言

该书有两篇前言:致学生前言和致教师前言。我觉得它们非常重要,是本书的纲领。它们的阐发针对的 读者不同,却都是围绕着作者的教学思想。

致学生前言

开篇两段就说,“编程是件乐事。。。编程也是件苦事。。。”

编程是件乐事。你能找到其他地方能让你花上成天的时间来设计你想象的机器, 不用锤子、不用弄脏你的衣服就能把它做好,让它魔术般地运行,而在 月底还能得到工资?

编程也是件苦事。你能找到其他什么地方发生过最优秀的公司的产品会在最 平常的使用中出故障吗?你能找到在其他什么地方一个工程师花上数小时或数天的时间 试图理解有些应该工作的东西不工作?

计算机科学和技术的发展,使得越来越多的人拥有计算机技能,刚入学的新生可能很多人都有 一些编程经验,但Meyer指出:有基本编程经验的人和一个专业软件工程师是有着很大区别的。 区分专业软件开发和业余编程的因素包括:系统的规模、生存期和变化。在专业软件开发里, 你要参加开发的程序可能会有几十万行甚至上百万行,它必须保持运行,在今后的及年或几十年 里会继续开发,并且会变更多次以适应新的需求。对只有几千行的、只着眼于解决眼前问题的 程序而言,许多很微琐的问题或并不存在的问题都会随着进入专业开发而变得严峻起来。

接着,作者提出有两项技术在专业软件开发中扮演着很重要的角色:面向对象的软件构造和形式化 方法。对面向对象技术,作者使用了新生们能够理解的比喻加以介绍:

面向对象的软件构造是基于如下的认识,一个正规的系统工程需要 一种依靠大规模库存高质量可复用的元器件的能力,就象在电子和 建筑行业一样。面向对象方法定义了这些器件需具备的形式:每个器件 应是基于某种类型的对象。术语“对象”,可以是指某个问题领域的对象, 如图形程序中的圆和多边形,它也是表示纯粹是软件的内部结构,如列表(list)。

同时作者对新生们说,“在学习一开始就熟悉这个技术是一份防止技术老化的出色保险单”。

第二个重要技术是形式化方法,这是基于数理逻辑的系统化的推理技术在建造可靠软件方面的 应用。刚入学时就全面学习形式化方法是不太现实的,但是本书所用的途径是通过用 “契约式设计”(Design By Contract)的思想来展示形式化方法的益处。契约式设计认为, 软件系统的建造其实是实现许多模块之间的契约关系,这些关系是用责任与权益精确定义的。

在学习方法上,作者“安慰”新生们,这本教材不是一本理论著作;它是要让你把所学到的 在计算机系统上实践。在课程的第一天你就会“在你的指尖上拥有EiffelStudio的全部威力”, 所以你可以跳过很多在学习程序设计的传统方法中的“小儿科”练习。Meyer进一步指出: 本书所采取的途径是一种学徒方式,即开始学习一门技术或行当的最佳方法是学习由专业人员 做出的优秀“工件”,使用这个工件,了解它的内部结构,加以扩展,加以改进--然后做你自己 的。

这种“学徒方式”是一种有效的学习方法,而对软件行当来说,还有另一个重要作用。学生使用的 “工件”(复用的类)包括了很多的知识。刚开始使用它们,学生其实只是需要依靠这些类的抽象 接口的描述,这些描述只包含了作为一个消费者所需要的基本信息。这实际上是有助于学生学习 作为一个专业软件开发者所需的一个关键技能:抽象。这里抽象能力是指对任何一个软件部件 能够将它的目的和实现细节区分开来的能力。

从“致学生前言”可以看出,Meyer是假设选这门课的学生们是愿意动手编程,喜欢自己 设计“想象中的机器”并“制作”出来。而这门课的教学方法是“学徒方式”,能让学生 有充分的空间利用现有的软件部件来制作出非“小儿科”的系统(应用)。通过这些, 学生会开始学到两项重要的软件技术,面向对象和形式化方法(通过契约式设计方法), 而为作为专业的软件工程师打下一个良好的基础。

致教师前言

如果说,“致学生前言”是Meyer试图从学生的角度来激励学生的学习兴趣,打消一些顾虑 (如不太喜欢纯理论的课程),对学生循循诱导,那么“致教师前言”则基于作者在学术界和工业界 的经验和观察和思考,从教师的角度比较全面地阐述了程序设计引论(以及软件工程)的教学思想。 其目标是要让学生一开始就沿着正确的途经,让他们能够喜好编程 ,更要学到能终生受益的 不断迎接挑战的能力。为帮助学生达到这个目的,该教材采用了一些新颖的思想:

自外而内:逆向大纲

Meyer教学方法的核心是自外而内(Outside-In)的“逆向大纲”(inverted curriculum) 教学法。这种教学法与传统的程序设计课程的教授次序完全相反。传统的次序是自下而上的:从程序 的建造单元开始,例如变量与赋值,接着是控制语句和数据结构,再进入模块设计与构造大程序的 技术。Meyer认为,这种途径能让学生对程序的基本元素有一个很好的实际理解。但是它并非是教授 系统建造的概念的一个好方法,而这点是一个软件工程师要想在专业上成功所必须掌握的。

逆向大纲的原则是:学生先作为用户来使用一些工具或部件来建造他们自己的应用系统,然后逐步 揭开这些工具或部件的面纱看看它们是怎么做的,并改一改,作一些扩展。这种方法基于 的假设是:学习软件最有效的方法是使用存在的好软件,这里的“好”是指代码本身的质量,同时更 重要的是代码接口的质量,即API的质量。

Meyer认为这种途径的目的是让学生能掌握软件建造的关键概念,特别是抽象。Meyer并提到从他在 工业界的经验中,他不断观察到区分一个优秀的软件开发人员的标志就是抽象的能力:即区分基本 与从属,长久与临时,规范与实现的能力。尽管所有的引论课程都是在灌输抽象,但是有效传授这个概念的 唯一法门便是通过实例,特别是通过给学生展示出他们如何复用已存在的千万行代码在第一周就能 作出令人印象深刻的结果。由于学生一开始就通过接口使用库例程来建造功能强大的应用软件,他不需要 花太多的功夫专门去了解抽象、信息隐藏和复用的益处,这些概念将自然而然地成为他的第二本能。

教学用的软件系统是Eiffel语言及程序库(最基本的是EiffelBase)、EiffelStudio环境和Traffic软件。 EiffelBase实现了计算机科学中的最基本的数据结构,而EiffelVision则是个可移植的图形库, 提供对图形接口的设计与开发。EiffelStudio开发环境使用了现代化的、直观的GUI,具备很多先进、 复杂的功能,如浏览、编辑、查错、自动生成文档(HTML或其他格式)、甚至测度数据。 Traffic软件的应用领域是关于一个城市的交通:建模、规划、模拟和显示。Traffic也是一个程序库, 它提供给学生和教师可复用的部件以建造新的应用。TRAFFIC的示例城市是巴黎,包括它的街道与 交通网络。

这些软件包的源代码提供了一个高质量的代码库供学生模仿。实际上,刚开始时是在自己的程序 中使用这些代码,这是是通过接口来实现的。接口提供了从实际代码抽象出来的 基本信息,依靠这些接口,学生要做的第一个应用只是几行代码的一个程序。 它显示一个地图、在地图上标示出巴黎的Metro交通网络、检索定义好了的路径、给用户用图形 动画展示一条路径。随着课程的推进,他们会学习构造更精巧的程序,同时从内部来理解程序库: 即“打开黑匣子”。

面向对象技术

Meyer注意到,在程序设计引论中使用面向对象语言并不是一个新思想,但有些时候没有完全做到,其教学途经仍然继续了传统的自下而上的次序。只有到学生已经耐心地爬到了传统程序的构造单元时, 他们才能接触类和对象。Meyer认为对待OO如此犹豫是没什么道理的。OO技术的威力是能让我们 把软件系统建成能反映系统要处理的对象和概念的一个清晰而自然的模型。OO技术应该对所有的人都有益, 包括初学者。应该让初学者一开始就接触这个技术。很有趣的是,Meyer借用了在Santa Barbar的一家 点心店里侍应生穿的T恤衫上的一句话:人生无常--先吃甜点(Life is uncertain -- Eat dessert first)!

采用OO技术的一个主要结果是,模型的理念将对学生始终起着引导作用。“模型驱动架构”的出现反映 出对这样一个居于OO技术中心位置的思想的认同,即成功的软件开发依赖于对物理和概念系统的模型建造。 类、对象、继承和相关技术提供了一个教授有效建模技术的理想基准。在教材中,类和对象一开始就出现, 并作为一个根本而贯穿全书。Meyer注意到,只要把OO的概念作为一种常态的、现代的编程方法无保留 无借口地介绍给初学者,他们会热忱地采用OO技术。

当然,另一方面,Meyer也强调,OO技术并不排斥传统途径,而是超越,就象相对论将经典力学作为一个 特例而包含之;一个OO程序由类组成,程序的执行是对对象的操作,而类包含了例程,对象包含了数据。 因此,静态的程序结构和动态的计算结构都涵盖了传统概念。学生们要掌握传统技术,包括:算法 推理、变量与赋值、控制结构、例程、递归……

Eiffel与Design by Contract(契约式设计)

该教材是选用Eiffel语言作为教学语言。Meyer花了不少篇幅来说明为什么选用Eiffel语言。
  • Eiffel语言是完完全全的OO;Eiffel为教授其他程序语言,如C#、Java、Smalltalk或C++ 打下一个良好的基础;Eiffel是非常易于学习的,所有的概念都可以逐步引入,不会在开始学习 基本构造单元时就和还未学习的内容发生冲突干扰。
  • 与其他为教学而设计的工具不同,Eiffel已被用于大型应用系统中,处理数以亿计美元的投资、管理 医疗卫生、进行民用与军事上的模拟、以及其他广阔领域的应用问题。
  • Eiffel有一组程序库,它支持该教材的复用概念,最直接的是EiffelBase,它实现了计算机科学中的 最基本的数据结构,能支持教材第三部分中的数据结构与算法的教学,EiffelTime是关于时间的,而 EiffelVision是个可移植的图形库,EiffelMedia是多媒体和动画的。
  • EiffelStudio开发环境使用了现代化的、直观的GUI,具备很多先进、复杂的功能,如浏览、编辑、查错、 自动生成文档(HTML或其他格式)、甚至测度数据。它能从源码生成自动生成结构框图,或者 反之,让用户画图,然后自动产生源码,并可双向同步。
  • EiffelStudio可运行于许多平台上,包括Windows、Linux、Solaris和 Microsoft .NET。
  • Eiffel不仅是门程序语言,并且是一个方法,它的首要目标已超越了在计算机上表达算法,而是支持对于 问题和解决的正确的思维方法。它能让我们教授一个无缝的、包含了整个软件周期的途径,从分析 和设计到实现和维护。这个无缝开发的概念在EiffelStudio中通过双向 同步的框图工具给予支持,它是与OO技术的建模优点是一致的。

另外,Meyer认为,不能低估句法的作用,尤其是对初学者。Eiffel的句法能促进学习、提高程序的可读性、 防止出错:

  • Eiffel语言避免使用密码型的符号。每一个保留字都是直白的英语,没有简略(如INTEGER 而非int)。
  • 等于符号=与数学中的意义相同,没有违反数百年的数学传统。(当开始学一门用“=”来表示赋值 的语言时,想想多少学生会困惑于a必须是什么值才能使a=a+1有意义?)
  • Eiffel的语法中,作为语句分隔符的分号不是必需的。将每条语句写在不同行,这种标准格式能使程序看 上去很整洁,大大增加可读性。

另外,Eiffel最大的一个特点是它直接实现了Design by Contract(契约式设计)。 通过给类装备上前提条件(preconditions)、后验条件 (postconditions)和类不变量(class invariants),这样大大有助于 训练学生开发出无错误的系统。

适量的形式化方法

Meyer认为,在软件开发中更多一些使用形式化方法是建造可靠系统的一个需要。任何一份严肃的软件 教学大纲都应该至少用专门一门课来讲授基于数学的软件开发,例如在第二年,讲授数学规范语言如 B、Z或HOL。同时,这个思想应该影响整个教学大纲,也包括引论阶段。但是,如何在第一年教授形式化 方法却需要仔细谋划。

Meyer注意到,一年级的学生还没有准备好接受完全的形式化方法。这时如果把程序设计 完全当成一门数学分支来教学,效果可能会适得其反。但另一方面,如果让学生开始时全是使用非形式化方法, 而到若干年后,特别是等到他们在工业上的软件开发遇到困难的时候,他们突然发现,编程实际需要比 “砍码”(hacking)更多的东西,而形式化方法便是其中之一。

Meyer认为,正确的形式化教学方法是渐进循环。在引论阶段介绍契约式设计技术,随着实用技能而引入 形式化推理,这样能让学生认识到编程是基于数学风格的推理,同时又不至于把他们吓跑(Meyer观察到, 一年级学生们对契约式设计技术反应良好)。让他们掌握用这种适量的形式化方法进行软件开发的实践, 稍后大纲中进入形式化开发与形式语义学。这个周期可以重复进行,这样理论和实践可以相互加强。 这种途径可以让学生认识到,正确性并非只是学术上的探讨,而是在软件构造过程 中一个自然的组成部分。

从程序设计到软件工程

程序设计是软件工程的核心,但不是全部。软件工程关心的是建造系统,这些系统规模大、开发周期长、 改动多、质量、时间与费用要求高。尽管相关的技术没有教给初学者,但至少给一点初步的介绍是非常重要的。 包括排错与测试,软件质量,周期模型,需求分析,GUI设计。

教材结构

全书共分五个部分:

第一部分介绍最基本的概念,定义了程序的建造单元,从对象和类到接口、控制结构与赋值。特别强调了契约 的概念,教导学生依赖于所用模块的抽象而精确的描述,作为结果,也要对他们生产的模块同样地 准确定义接口。在“Just Enough Logic”(刚好够用的逻辑)一章将介绍命题演算和谓词演算的基本元素。 后续各章回到程序设计,介绍对象的创建与结构,着重于对象的建模威力以及我们的模型需要反映相应的外部系统; 以及程序控制结构,信息隐藏,赋值与对象指称(references)。

第二部分,“如何工作的”,从内部的角度来介绍关于计算机组织;句法及其描述方法(包括BNF和有限自动机); 以及程序设计语言、工具和软件开发环境。

第三部分介绍计算机科学基础的“算法与数据结构”,包括三章。第一章,基础数据结构,介绍“通用型” (genericity)、算法复杂性以及几个重要的数据结构,如数组(arrays)、列表(lists)和散列表(hash tables)。 第二章,递归,介绍二叉树(特别是二叉搜索树)、定点解释(fixpoint interpretations)、 以及递归的实现技术。第三章,分类算法,覆盖了该算法的数学背景、算法的渐进开发以及(工程意义上的)API设计。

第四部分深入介绍面向对象技术。第一章涵盖了继承,并讨论了许多在引论课程中很少讨论的细节, 如访问者模式(Visitor pattern)。第二章介绍了“功能对象”(function objects)(也称 之为agents),和lambda演算。最后一章介绍事件驱动设计和“观察者模式”(Observer pattern)。

第五部分,也是最后一部分,将超越程序设计,而介绍 在大规模大而长耗时的项目中需要的软件工程的概念。 章节将包括项目管理、需求工程和质量保证等。

附录将介绍一些学生应该有一般性了解的程序设计语言:C# ,Java, 和C。对C的介绍会更详尽一些,因为它对于调用操作系统的低层 功能以及对硬件的控制。对C++也会详细一些,因为它是C和OO世界 的桥梁。

以下将对一些章节作选择性的评介。

第一章 “The industry of pure ideas”

“The industry of pure ideas”,这个题目很有趣。一个“industry”,一个 “pure ideas”点出了软件的特点:工业/产业性和“概念”(非物理)性。在第一节, “Their machines and ours”作者更用“机器”来说明软件行业和其他行业的异同。

首先,作者这样来说明相同之处:

工程师设计并建造机器。轿车是交通机器;电子线路是信号转换机器;桥梁是跨越河流的 机器。程序员/“软件工程师”也设计并建造机器。我们把我们的机器称之为 程序系统

而不同之处在于:

如果他们的机器落下,将会砸伤你的脚,而我们的则不会。程序是非物质的(immaterial), 这样看来,它们更接近数学家的定理或哲学家的命题,而不象飞机或吸尘器那样。但与 定理和命题不同,它们是工程设备,你可以操作一个程序,就象你操作飞机或吸尘器那样, 并得到结果。

作者进一步写到:你可以梦想一个机器,不管大小,你用程序来描述你的梦想机器, 然后把程序送入计算机运行,这样让你的梦想成真。

Meyer似乎特别喜欢用“机器”这个概念/比喻(可以回头看看“致学生前言” 第一段“编程是件乐事。。。”)。我想其中有几个原因:一是从教学法上说,这个 比喻易于被学生理解接受;二是暗示软件的工程性;三是为后面讲解objects(对象)埋下一个 伏笔。

第二章 “Dealing with objects”

本章的头两节是“实验课”,给出了详细步骤说明如何使用EiffelStudio来编出 第一个只有四行语句的程序,


        Paris.display
        Louvre.spotlight
        Line8.highlight
        Route1.animate

即:显示巴黎地图(包括地铁线路);突显卢浮宫;突显第8路地铁线路;动画一条 旅游路线。

接下来,第三节“What is an object”以此四行程序为例,来对object进行了 简单易懂而又准确的描述。首先,Meyer指出,每一行都有一个object,即Paris, Louvre,Line8和Route1。程序所能做的就是操作这些objects。那么如何在来理解 object呢?Meyer指出,我们是在技术的意义上使用了一个日常语言中的非常普通的 词语。这既有很大的吸引力,但又容易引起一些混淆。

现实世界中的objects基本上都是都是实实在在、看得见摸得着的,如卢浮宫。你甚至 可以砸它一拳(Meyer不无幽默地声明,购买此教材并不保证能包销你的医疗费用)。 软件中使用object这个词来描述物理/物质世界中的“物体”只是一种方便。一个软件 里的object实际上是存储于计算机中的一组数据。另外一个重要的区别是,软件中的 object也可以用来表示“非物理/物质”的东西,如以上程序中的Route1,就是一条 旅游线路。

更进一步,软件中的objects的特别之处是它们提供了一组操作(operations),程序 正是通过这组操作来和objects进行交互作用的。从这点来看,Meyer又把objects比作 机器(objects as machines),因为机器的特性就在于给用户提供了一组操作。有趣的 是,Meyer用一个DVD播放机来比拟Route1这个object。


(taken from Touch Of Class, Section 2.3 What is an object, p28)

那么,一个object可以从两个角度来看:

  • 一个object是一组存储于计算机中的数据,这些数据描述了这个object的属性;
  • 一个object可以看作一个机器,它给使用者提供了一组特定的操作。

Meyer认为,这两种视角不是矛盾的,实际上,操作是在数据上进行的。

待续。。。

相关文章

修改记录

  • 2009年12月28日:第一部分(介绍教材前言及第一、二章)发表于SoftwarePractitioner.org。
 
[首页]   [作文]   [翻译]   [随笔]   [本站]   [English]
 
Creative Commons License
Except where otherwise noted, this site is licensed
under a Creative Commons Attribution-NonCommercial 2.5 License
.