首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件开发 >

矫捷开发与层展论

2013-11-02 
敏捷开发与层展论敏捷开发与层展论1、什么是层展论(emergence)诺贝尔物理学奖获得者卡丹诺夫说得非常清楚:“

敏捷开发与层展论

敏捷开发与层展论

1、什么是层展论(emergence)

诺贝尔物理学奖获得者卡丹诺夫说得非常清楚:“已经有足够的经验表明,不同的聚集层次自然地成为不同科学家群落的研究对象。据此,一组科学家研究夸克(一族亚核粒子),另一组,原子核;另一组,原子;另一组,分子生物学;另一组,遗传学。在这一序列中,后面的部分是由前面层次的对象所构成。可以认为基本性依次序而递减。但是在每一层次中总有新的而且激动人心的有效普遍原则,却并不能由更加‘基础’的科学自然而然地推导出来。从这一系列中最不基础的层次开始,我们可以一一列出这些科学中的具有代表性和重要性的结论,诸如孟德尔遗传律,双螺旋,量子力学,原子核裂变。谁最根本?谁最基本?谁推导了谁?从这些例子可以看出将科学知识区分等级是十分愚蠢的。宁可说在每一层次的普遍原则中都会呈现宏伟的概念。”

“层展论”是主张各个层次之间“脱耦”与“耦合”相统一的理论。在这个层展论图景中,由能量级所开拓的层级结构实质上成为一切高级运动形态的舞台。粒子之间在各个能级上的相互作用为各个层级中的各种运动形式提供了基础性能量来源。而这些能量表现在各种组织结构中,各种运动形式之中。20世纪后半叶蓬勃兴起的耗散结构理论、协同学、超循环理论等各种自组织理论,自然地以这个层级图景为背景,探索了新的运动形态与物质结构如何在这个背景上生成。而在这些自组织过程中,粒子给在各个不同层级所提供的相互作用能量成为创造性能量,它们不断在各个层级上产生出新的性质,产生出其他层级上不具有的新的相互作用新形态。于是,同一相互作用在不同时空尺度上进行的“层级结构”,在自组织过程中被生成为“层展结构”,无限丰富的新的运动形态、新的结构及其新的性质不断被创造出来。

呈展论(emergence)又译作层展论,也叫整体论(Whoism),是描述自然界的一种观点。其基本思想是客观世界是分层次的,每一个层次都有自己的基本规律,这种规律是无法用更基本层次的规律来解释的。呈展论承认客观现象,并以此为依据找出这个层次上的基本规律,并理解这种现象是如何呈展的。由此可以看出呈展论推导出的理论主要是唯象的。呈展论认为层次间有脱耦,一个整体可能由许多部分组成,但有些性质只有许多部分体在一起时才能体现,而单个部分体根本不具有这种性质。

 

2、为何谈层展论

当前在敏捷实践的几个层面上,我们忽视了上述的层展理论,而是更倾向于还原论(所谓还原论(reductionism)认为世界上的大量规律都可以由基本规律描述,最终可以由一个“万有理论”来描述世界上的所有现象)。

1) 需求分析

在进行Product Backlog的分解之中,很多人存在一个误区:即认为我们需要不断分解,直到分解到我们一些的不可分割单元为止,认为这样分割后,最小粒度的就是最明确的。就像我们拿到一辆汽车,把汽车中的每个零件都拆开,然后再独立加工。这种拆分方法,是符合一个基本原则的:复杂度通过拆分得到降低,从而利于我们在实现时把控。因此拆分这个动作是符合基本规律的。但是不是拆得越细越好就值得探讨。这只是一方面。更为重要的一方面是,我们在拆分的同时,却严重忽略了如何把这些零件组合起来。当开发团队在实现用户故事时,如果仅仅拿Product Backlog中的用户故事来做估算和计划,是远远不够的。因为如果缺乏故事之间的串联,就没法说清楚故事是如何协作运转以满足用户价值的。换句话说,即使你单个用户故事满足了INVEST原则,也不能保证整个功能的完整性和整体价值。而且,系统的分解只是整个需求分析中的一个步骤,在功能间的协作没有弄清楚之前,任何的估算和计划,都是不靠谱的。仔细想想,我们在整个开发过程中,花在联调和最后集成测试上的时间是不是多的吓人,而且这个时间似乎难以控制,往往都是迫于进度压力就先决定交出去进行系统测试了。

这种方式的需求分析,还会导致另外一个看起来不起眼的小东西:帮助文档。帮助文档往往都是交付的最后阶段才完成。抛开文档质量不说,看看内容,其实和还原论很相似。我们写帮助文档,往往都是一个菜单一个菜单写,一个功能一个功能写,看上去每个功能都介绍了,但用户拿到文档和产品,还是不知道如何使用才能解决自己的问题。这是个思维方式问题,即我们认为只要把功能解释清楚就行了,怎么用来解决问题不是我们的职责。在我参与的某个产品开发中,我们改变了这种做法。采用场景描述方式来做帮助,把数据如何准备、如何TroubleShootting、如何解决问题,采用场景方式描述清楚。这个文档也是我入司到现在为止,我觉得是最好(没有之一)的一篇帮助文档。这其中,也暗含了层展论的思想:即在细粒度的功能层和高粒度的场景层上,其实都有其重要价值,而且二者应该是相互支撑的。

2) 代码

以前写代码,在需求弄清楚之后,编码的思维方式往往是这样:先设想一下总体的架构,把功能分成几个层次去实现,然后拿一条具体需求,去驱动出整体架构代码。整个过程可能采用TDD,也可能不用,主要看自己在编码过程中是否有把握。比如如果能够在脑海中把所有实现都装下,这样就会比较有把握。总体下来觉得整个思路还是可以的,也能够比较清楚。

但其中的问题是,由于在不同层次之间频繁切换,容易使得分层不那么明显,而且思维往往会越来越混乱,缺乏一个层次上的整体思考。不像是层展方法论中提到的,先考虑一层,再考虑一层,先在同一层次上思考,然后切到下一层次思考,直到最后的实现层次。这两种思维方式还是有较大的区别。

在和其他同事结对编程的时候,还发现有一种编码过程,可能是大部分程序员都会采用的。比如我在函数A中需要用到函数B,它不是这样写:

Def A(a,b,c):

    …..

    B(b,c)

既先在A中把对B的调用写完,再去写B的实现。而是先写B的实现:

Def B(b,c):

    ….

这两种方式表面上看起来差别不大,但思维方式上却有明显区别:

即B的接口是站在实现者角度看,还是站在使用者角度看的问题。前者往往会导致更多的变更,因为脱离开使用者,就难以根据需要确定输入、输出和异常。后者则相对更加稳定。

此外,如果采用另外一种编码方式,即把功能分解为一个个细小的具备用户价值的原子操作,然后通过定义一系列的原子组合规则,这样就可以采用近似数学推导的方式来构建软件。这种方式是极其灵活的,也是和层展论思维如出一辙:“无限丰富的新的运动形态、新的结构及其新的性质不断被创造出来”。

3) 测试

测试也是分层的。从侧重于功能的验收测试,到侧重于接口的集成测试,到侧重于实现的单元测试,每一层关注的焦点是有区别的。可以这样说,仅仅依靠高覆盖率的单元测试,并不能保证验收测试一定能一次性通过。因为除了单元之外,还有单元之间的关系。可以详见笔者编写的《开发者测试》一文。

而如果我们更进一步思考,是不是可以对一些基本测试进行提炼,形成一套测试语言,从而在语言层面进行高层测试用例的编写。这样组合出来的测试体系,将更具备灵活性。从这个意义上来讲,层展论与测试的分层论基本原理是一样的。

3、层展论如何实施

1)  需求分析中如何应用

在需求分析中,我们不再仅仅关注于功能的分解,而且也更关注于功能的组合。两者要能够有机结合。分解的粒度要合适,而且能够虚拟场景的方式把用户故事进行串联。详见笔者编写的《虚拟场景与用户故事在敏捷开发中的应用》一文。

在进行实际估算和计划时,对于用户故事的组合也要给基本的估算,或者能够在一个较高层面上进行功能估算。如果现实操作中仅以用户故事为粒度进行估算,那么对于每个较大功能,能够给予联调故事卡,从而保证一定的联调估算;也可以把联调估算折算到各个用户故事的估算之中。

2)  代码中如何应用

这里借用孙鸣老师写的《程序设计》学习心得中的一段关于WishFul Thinking的描述:

    “我们应该如何以problem-solving为导向,识别出问题的核心,围绕核心问题的解决来演化以及延伸出整个解决方案呢?这里用到的思维模式可以称之为:Wishful Thinking。Wishful thinking可以帮助我们“从问题本身层面而不是从实现层面考虑如何表达问题”,我们可以假定所有需要的辅助的东东,有个神一样的助手都帮我们做好了,这样,我们就可以用“声明性”的方式来描述问题的解决方法,比如:“做这个,做那个。。。”而不是“如何做这个,做那个”。在应用这种方法时,我们将需要解决的关键问题用“声明性的”简短的话来描述,然后看看我们的手边、使用的语言中是不是有称手的工具来帮助我们表述这个问题如果没有,就需要我们自己去制造”。

这和ArmStrong的说法类似:程序的结构要严格保持与问题的结构一致,即从问题到程序的映射比例为1:1。此时我们就说程序与问题是同构(isomorphic)。

Wishful Thinking的具体做法是:

1.    充分理解问题领域,列出概念清单

2.    精炼这些概念,去除冗余,合并一些本质相同的东西,看清问题的本质;

3.    从最简单的解决方案、数据结构、表示方式着手,直到发现这样的实现不能适应于问题,再逐步向复杂一些的方案过渡。

4.    在信封背面做最初的评估,对初始解决方案的可行性有个正确的认识,避免无用功;

5.    优化解决方案, 打造效率可行的方案

6.    称手的工具

7.    分离不同方面(关注点)的代码,让解决方案清晰,整洁

在把握概念本质性后,对于领域建模,衡量模型好坏的标注,可以从Simple,Generic和Composeable入手。具体例子可以看布局练习以及正则表达式练习。

最后,看看邓辉关于Domain Model的说法:

    “建模时最重要的一点就是要弄清楚事情是如何“计算”的,并选择出最贴切于表达这个计算的数据结构和算法。在建模时,有个常见的误区就是:直接从问题描述中找出“肤浅”的概念和算法,然后运用一堆设计原则和模式去改进。”

这实际上是对层展论的进一步阐释:不管分多少层,层与层之间如何组合和联系,始终都要围绕问题的本质来表达。

3)  测试中如何应用

在实现层面,需要结合TDD和WishFul Thinking。如果完全采用WishFul Thinking,它需要一层层讲解到最底层,才可能使得测试用例通过,这个过程可能会相当长。因此是否先通过最简单的用例,把整个WishFul Thinking的逻辑层次驱动出来。再逐步补充起除最顶层之外的其他层次?这个需要思考。

此外,是否WishFul Thinking就不需要TDD了呢?还是这样做之后,我们的思路更加清晰,从而避免了采用大量测试来保证程序正确性的做事方法?

在这次高级设计培训中,Re的那个问题,是先lit,再star,每次都是TDD+wishful。这样做反馈周期和节奏感比较强。

最后的思索:不要为测试而测试!测试的目的是什么?如果我对某件事情特别有把握,为什么要浪费时间去测试?

具体测试的例子,可以参见Coffee Maker,里面对如何组织测试的TSL(Test Specification Language)有很多很好的启发。

   

 

 

 

 

1楼zhang_qxian1小时前
编码的哲学观

热点排行