zoukankan      html  css  js  c++  java
  • 软件设计:“度”、“裁剪”与“变通”

        最近一阵子比较清闲,所以又温习了一下《敏捷软件开发:原则,模式与实践》这本经典的著作,并且结合了前一个项目的流程,对号入座,反思了一下我们的不足和有待改进的地方。我发现在真正项目开发的过程中,敏捷的许多过程,我们在使用的过程中是有很多实际困难的,比如严格的TDD开发,结对编程,客户(Customer/Client,有时指的是客户代表)参与,开放的环境等等。而且在这个项目中,与其说我们使用了敏捷开发的过程,倒不如说我们的过程更像是RUP(统一过程)的敏捷版本。经过认真的反思和总结,我发现开发中有几个问题是值得思考的:

    1、架构是演化而来的,那么基础架构(架构的起点)需要提前选定么?

        这个是一个容易让人困惑的问题,问题来源于敏捷开发与RUP开发的不同主张。前者主张根据用例分析软件的核心模型,然后直接编写代码并通过不断测试与重构,逐步演化获得核心架构;而后者讲究的水到渠成,通过用例分析,得到分析模型(核心模型),然后选择架构和框架,再实施编码。两者我都实践过,这里我只说说我的体会。敏捷强调重构到模式和架构,起点要求不是太苛刻的,但是按照这么一直走下去,我发现开发的过程中,代码可以很干净,但是架构的走向比较混乱,走着走着有时就偏离了方向,需要设计和开发者具有高超的重构和抽象功力;RUP过程比较自然,分析模型确定以后,直接选择架构和框架,然后编码,方向明确,目的性比较强,但是一旦后期某些需求(可能是功能上的,也可能是重构的需求)导致选择的架构需要扩充的时候,所做的工作可能就会比较多。

        当我屡屡在这个问题上苦苦纠缠,难以抉择,不断翻书思索的时候?我突然看到一本软件工程书上的一个词:“裁剪”,瞬间,我释然了。敏捷软件开发,RUP开发不都是成熟的开发思想吗?思想不同于准则,具体的执行步骤不是严格按照书上规定的走的,这个实践的过程是需要对过程进行修剪和重组,乃至融合的。就像设计模式,思路是相同的,但是同一个模式实现起来的结果可能是大不相同的。想到这里,我真的觉得以前太过执着,太过追求模仿、追全完美,最终是本末倒置,丢了西瓜,捡了芝麻!

    2、TDD的粒度问题,如何写好测试?

         伟大的哲学家王守仁一生提倡知行合一,从这个层面上说,TDD是一个卓越的思想,也是一次伟大的实践,至少我是这么认为的。TDD是敏捷开发的绝佳组合,更是单元测试最忠诚的伙伴(TDD并不等同于单元测试的)。TDD带来了设计上的低耦合性和可测试性,保证了架构的灵活性和扩展性,也从而保证了产品的质量;而且,测试文件和测试结果也成为了最好的功能说明书和验收文档。

        当TDD带来这么多好处的同时,不可否认的是,它也为开发过程引入了很多复杂的因素:大量的Mock/Stub对象充斥在代码中,而且无法保证Mock对象与真正的对象实现上是可替换的;通常为了达到Mock对象与代码对象可以互换,Mock对象需要实现很多负责的模仿行为;很多的测试就是为了单纯的测试,不在是从代码的使用角度真正的去测试代码;通常测试的过程与真正编写对象的过程是一致的,这无疑造成了一些浪费;测试本身也是代码,也是有Bug的,这个该如何保证呢?关于测试代码的粒度选取上,每个人认识并不一致,这也造成了测试代码比较难以掌控;很多的数据访问组件都是有成熟的技术的,比如Linq,Hibernate, EF,这些如何去测试...

        真正实践TDD的时候,我才发觉这个真的是太难了,也许是经验不足的原因,很多的时候,我只是在关键的业务规则部分使用TDD。大家呢?   

    3、组件是从上而下自然构造的,还是从下而上分析得到的?

        这个又是一个敏捷与RUP互相对立的地方。

        敏捷的实践一般是从类开始,即是从用例中分析核心模型,得到核心的对象,编写测试代码并实现对象,通过不断的迭代逐步构造完整的系统;等到需要分包的时候再根据分包的粒度原则(发布重用原则,共同重用原则,共同封闭原则)和依赖性原则(无环状依赖,稳定抽象原则,稳定依赖原则)来分配对象到不同的组件中,得到最终的软件层次架构。

        而RUP的过程则是在需求和功能分析设计后,从选择基点架构开始,比如常见MVC架构以及各种变体,多层架构以及各种变体,管道架构,分布式架构,一些新的如REST架构等等。选定架构以后,不同的组或者人员分配不同的部分,设计并完成各自的功能。通过不断的迭代和重构,完成各个版本和发布,最终得到软件的层次和架构。

        这里,组件的形成过程其实与架构的形成过程是息息相关的,从上面两种截然相反的过程中,我们又有哪些感悟呢?这个只能说是仁者见仁,智者见智了。我比较认同的观点是:这取决于项目的类型,大小。小型的项目用敏捷是不错的,合作愉快,你好我也好,真的是大家好才是真的好。对于大型的项目,通常是要选定多种过程融合执行(比如RUP+敏捷),一般是应该选定基础的架构,分好模块,初步定义接口结构,然后再不断重构和迭代。

    4、分解开发的规模,独立运行的模块,真的降低了软件变质的风险?

        很多人赞同一个观点:问题以及解决这个问题的人员规模,是导致软件开发架构逐渐变质的直接因素。所以他们认为缩小问题的规模(通常是拆分解决方案),提炼独立运行的模块是相当不错的一种方案。

        独立运行的模块,固然是短小精悍,维护难度大为降低,但是这个过程中,复用的程度似乎是不高的。而且对于很多公用的组件,为了达到让多个进程使用并且不会干涉互相的正常运行,常常是需要将这个模块部署到GAC中,或者是拷贝多个版本,放到各自的运行目录中。在开发的过程中,部署到GAC似乎不是可取的方式;连微软都搞出来一套延迟签名的机制,显然Release之前部署组件到GAC是不好的。那么拷贝多个版本到不同的目录中呢?缺点也很明显,每次组件的更新,都需要更新每个调用的程序目录,当独立程序的数量大幅上升的时候,这个过程变的相当脆弱,容易出错,毕竟这个时候你是无法使用FAR(Find All Reference)来找到所有使用的地方的,当然了,使用Windows的查找功能也许还是可行的,但是这样还是比较麻烦的,最后连脚本都会被用上,用于简单的替换任务。那么如何是好呢?大家有什么好的做法呢?

        我曾经的经历是这样的:支持团队代码开发的是源码管理工具。代码分支(Branch)是经常采用的手段。不同的组工作在不同的Branch上,等到集成的时候,由集成工程师或类似的角色完成整合工作。这样不同分工的团队就可以工作在不同的分支上互不干扰,等集成完成以后,各自就能获得多其他组最新的程序。这个工作是有一个前提的,就是各个组之间,更深一步说,是各个组负责的模块之间,通信必须是畅通无阻或者是通信无关的;或者说通信必须是提前约定好的。这样解决方案的规模其实没有缩小,只是出现很多分支,而且有专门的人负责这方面相关的工作,比如集成和编译程序。这种做法说不上是好是坏,而且实施成本比较高,但是对我们来说效果还是有一点的。

        郑重声明:以上只是个人的感慨与总结,并不是每个问题的标准答案,更不是推荐给大家的成功经验和知识。限于能力,每个想法总是有对与错,如果观众们有不同的意见或者是自己的看法,那也是很正常,大家姑且当个故事,看看罢了!偶尔想到相关的问题,批判的瞅瞅,如果能产生自己的想法,那就更好了!

  • 相关阅读:
    让 vscode 作为 SpringBoot,Java,Maven,甚至于 JavaScript,C,C++,Python,Php等多语言的开发工具吧!
    MySQL 连接错误集锦
    前端开发工具库:包含事件委托,动画处理,以及大部分常用的前端工具
    初探 Node.js 框架:eggjs (环境搭配篇)
    如何快速搭建一个 Node.JS 项目并进入开发?
    关于 JavaSrcipt 前端开发的建议:模块化开发
    Spring-Session 会话共享 -> 基于 Redis 集群,内附各大错误合集,包括配置,类寻找不到、连接错误等
    Java Email 邮件发送
    CSS 显示或隐藏子元素
    Ubuntu美化及配置,常见问题解决方案(仿 Mac 风格)
  • 原文地址:https://www.cnblogs.com/dxy1982/p/2135319.html
Copyright © 2011-2022 走看看