程序设计方法学:架构设计中的思路方法学(2)

  简单设计(2)

  考虑未来

  我们的所以考虑未来主要原因就是需求不稳定因此我们如果考虑未来可能发生需求变化就会不知觉在架构设计中增加复杂成分这违背简单精神但是如果你不考虑可能出现情况那些和目前设计格格不入改变将会导致大量返工

  还记得YAGNI吗?原则上我们仍然坚持不要在现有系统中为将来可能情况进行设计但是我们必须研究必须要为将来可能出现情况做些准备其实软件Software中了不起接口思想不就是源于此吗?因此研究未来但等到需要时再实现

  变更案例有助于我们研究未来变更案例就是你在将来可能要(或可能不要)满足但现在不需要满足需求当我们在做架构设计时候变更案例也将会成为设计考虑原因的但它不可能成为进行决策考虑原因很多时候我们沉迷于设计通用系统给我们带来挑战的中其实我们所做工作对用户而言是毫无意义

  架构稳定

  架构简单化和架构稳定性有什么关系吗?我们说架构越简单其稳定性就越好理由很简单1个拥有4个思路方法和3个属性和1个拥有20个思路方法和30属性类相比个更稳定?当然是前者而架构最终都是要映射到代码级别上因此架构简单将会带来架构稳定尽可能让你类小尽可能让你思路方法短尽可能让类的间关系少这并不是我忠告很多设计类文章都是这么说在这个话题上我们可以进阅读同类文章(有关 refactoring 研究)

  辨正简单

  因此对我们来说简单意义就是不要把未来、或不需要实现功能加入到目前软件Software中相应架构设计也不需要考虑这些额外需求只要刚好能够满足当前需求就好了这就是简单定义可是在现实的中总是有这样或者那样原因使得设计趋向复杂般来说如果个设计对团队(Team)而言是有价值那么付出成本来研究、验证、发展、文档化这个设计是有意义反的如果个设计没有很大价值或是发展它成本超过了其能够提供价值那就不需要去考虑这个设计

  价值对区别团队(Team)来说具有区别含义有时候可能是时间有时候可能是用户价值有时候可能是为了团队(Team)设计积累和代码重用有时候是为了获得经验有时候是为了研究出可重用框架(FrameWork)这些也可以称为目因此你在设计架构时请注意先确定好你对实现目有帮助事情才考虑

  Scott W.Ambler在他文章中提到个他亲身经历故事在软件Software开发架构设计过程中花了很多时间来设计数据库到业务逻辑映射架构虽然这是件任何开发人员都乐意专研事情(它很酷)但他不得不承认对用户来说这种设计先进架构是没有太大意义用户并不关心具体技术当看到这个故事时候触动很大个开发人员总是热衷于新奇技术但是如果这个新奇技术成本由用户来承担是不是合理呢?虽然新技术采用能够为用户带来效益但是没有人计算过效益背后成本就我开发过项目而言这个成本往往是大于效益这个问题可能并没有确定答案只能是见仁见智了

  简单并不等于实现简单

  说到这里如果大家有个误解认为个简单架构也定是容易设计那就错了简单架构并不等于实现起来也简单简单架构需要设计者花费大量心血也要求设计者对技术有很深造诣在我们正在进行个项目中开始设计基础架构在实现中被修改了几次但每修改代码量都减少代码可读性也就增强从心理角度上来说对自己架构进行不断修改确实是需要勇气不论是设计还是代码都是开发人员心血但跨出这步是值得

  下面例子讨论了JavaIO设计Java类库设计应该来说是非常优秀但是仍然避免不了重新修改实际上在软件Software开发领域由于原先设计失误而导致后来设计过于复杂情况比比皆是(例如微软OLE)同样我们在设计软件Software时候也需要对设计进行不断修改能够实现复杂功能同时自身又简单设计并不是件容易事情

  例1.JavaIO系统

  从JavaIO系统设计中我们可以感受到简单设计困难

  IO系统设计困难性向来是公认JavaIO设计个目就是使IO使用简单化在Java1.0中JavaIO系统主要是把IO系统分为输入输出两个大部分并分别定义了抽象类InputStream和OutputStream从这两个抽象类出发实现了系列区别功能输入输出类同时JavaIO系统还在输入输出中实现了FilterInputStream和FilterOutputStream抽象类以及相关系列实现从而把区别功能输入输出连接在实现复杂功能这个实现其实是Decorator模式(由于没有看过源码和相关资料这里仅仅是根据功能和使用窍门技巧推测如果大家有区别意见欢迎来信讨论)

  因此我们可以把多个对象叠加在提供复杂功能:

  DataInpuStream in =

   DataInputStream(

   BufferedInputStream(

   FileInputStream("test.txt");

  上面代码使用了两个FilterInputStream:DataInpuStream和BufferedInputStream以实现读数据和缓冲功能同时使用了个InputStream:FileInputStream从文件中读取流数据虽然使用起来不是很方便但是应该还是非常清晰设计

  令设计混乱是既不属于InputStream也不属于OutputStream例如RandomAccessFile这正表明由于功能复杂化使得原先基于输入输出分类设计变得混乱根据我们经验我们说设计需要Refactoring了因此在Java1.1中IO系统被重新设计采用了Reader和Writer位基础设计并增加了新特性但是目前设计似乎更加混乱了我们需要同时使用1.0和1.1两种区别IO设计

  简单设计(3)

  简单设计需要什么样设计师

  简单架构需要全面设计师什么才是全面设计师定义是既能够设计又能够编码我们在团队(Team)设计模式中就已经谈过象牙塔式架构和象牙塔式架构设计师他们最容易犯个毛病就是设计和代码脱离从我们自己经验来看即使在设计阶段考虑非常完美架构在编码阶段也会出现这样或那样问题从而导致架构实现变得复杂最明显特征就是在编码时出现了有大量思路方法或是思路方法很长这表明架构和代码脱钩了在我们开发过程中不只次出现这种现象或者说出现了坏味道(Bad Smell)Refactoring窍门技巧也同样有助于识别坏味道

  架构设计完成后开发人员可以按照设计快速编程可在段时间的后特色不断加入我们发现代码开始混乱代码量增大可读性下降调试变得困难代码不可控制征兆开始出现我们就知道架构设计需要调整了这属于我们在后面所提到Refactoring模式而我们在这里要说如果架构设计师不参和编码它是无法感受到坏味道因此也就不会主动对设计进行改进要解决这个问题最好办法是让设计师参和代码编写尤其是重要架构现实部分需要设计师参和如果设计师没有办法参和编码那就需要种机制能够把代码反馈给设计师让他在适当时候重新考虑改进架构个可能办法是Code Review让设计师审核代码以确保编码者真正了解了架构设计意图

  在分析模式书中有个measurement pattern(测量模式)原来它是为了要解决现实中各种各样纷繁复杂可测量属性例如个医疗系统中可能会有身高多高体重多种血压多少等上千种可测量属性如果分别表示它们必然导致系统复杂性上升因此measurement pattern就从这些属性可测量共性出发研究新解决思路方法提出了measurement pattern想法:

  如图所示把可测量属性(Measurement)做为Phenomenon Type例子此外Person可以拥有多个Measurement同时Measurement还对应处理属性例如图中Quantity就表示了Measurement数量和单位比如个人体重是65公斤那么Phenomenon Type就是体重Quantityamount是65units是公斤

架构设计中<img src='/icons/28473de.gif' />思路方法学(2)

  图 5.measurement pattern 类图

  这其实是个很简单设计但它清楚表示了属性的间关系简化了数千种属性带来复杂性此外我们进步研究就会发现这种架构只是针对目前出现属性众多问题基本解决思路方法它还可以根据具体需要进行扩展例如实现动态添加单位或实现区别单位转化等问题

  因此我们这里展示其实是种研究思路方法假想当你在面对个复杂医疗系统时大量属性和区别处理方式你是不是可以从这样复杂需求中找出简单部分来呢?在我们架构设计篇中我们谈到架构设计本质在于抽象这里例子就是最典型个例子在我们传统想法中我们都会把身高、体重等概念做为属性或是类但是为了满足这里需求我们对这些具体概念做个抽象提出可测量类别概念并把它设计为类(Phenomenon Type)而把具体概念做为例子这种抽象思想在软件Software设计中无处不在例如元类概念

  迭代设计(1)

  迭代是种软件Software开发生命周期模型在设计中应用迭代设计我们可以得到很多好处

  在软件Software生命周期中我们如何对待架构设计发展?

  架构设计往往发生在细节需求尚未完成时候进行因此随着项目进行需求还可能细化可能变更原先架构肯定会有不足或地方那么我们应该如何对待原先设计呢?

  我们在简单设计模式中简单提到了"Planned Design"和"Evolutionary Design"区别XP社团人们推崇使用"Evolutionary Design"方式在外人看来似乎拥护者们从来不需要架构设计他们采用方式是开始就进入代码编写然后用Refactoring来改进代码质量解决未经设计导致代码质量低下功能

  从定程度上来说这个观点并没有错它强调了代码对软件Software重要性并通过些窍门技巧(如Refactoring)来解决缺乏设计问题但我并不认同"Evolutionary Design"方式在我看来定程度上"Planned Design"是必须至少在中国软件Software行业中"Planned Design"还没有成为主要设计方向借用句明言"凡事预则立不预则废"在软件Software设计初期投入精力进行架构设计是很有必要这个架构是你在后续设计、编码过程中依赖基础但是开始我们提到设计改进问题依然存在我们如何解决它呢?

  在简单设计模式中我们提到了设计改进必要性但是如果没有种思路方法去控制设计改进那么设计改进本身就是场噩梦因此何时改进如何改进 如何控制这都是我们需要面对问题

  解决思路方法

  为了实现不断改进我们将在开发流程中引入迭代概念迭代概念在需求实战中已经提到这里我们假设读者已经有了基本迭代概念

  软件Software编码的前工作大致可以分为这样个工作流程:

架构设计中<img src='/icons/28473de.gif' />思路方法学(2)

  上图中流程隐含着个信息损失过程来自于用户需求经过整理的后开发人员就会从中去掉些信息同样事情发生在后面过程中信息丢失或变形情况不断发生这里发生了什么问题?应该说需求信息失真是非常普遍我们缺少种有效办法来抑止失真换句话说就是缺少反馈

  如果把眼睛蒙上那我们肯定没有办法走出条很长直线我们走路时候都是针对目标不断调整自己方向同样漫长软件Software开发过程如果没有种反馈机制来调整方向那最后软件Software真是难以想象

  所以我们引入了迭代周期

  设计和迭代设计

  在团队(Team)设计中我们直在强调设计组最开始得到设计定只是个原始架构然后把这个原始架构传播到每位开发者手中从而在开发团队(Team)中形成共同愿景(愿景(Vision):源自于管理学表示未来愿望和景象这里借用来表示软件Software在开发人员心中样子在后面文章中我们会有个章节专门讨论架构愿景)

  迭代(Iterate)设计或者我们称的为增量(Incremental)设计思想和XP提倡Evolutionary Design有异曲同工的妙我们可以从XP、Crystal、RUP、ClearRoom等思路方法学中对比、体会迭代设计精妙的处:每迭代都是在上次迭代基础上进行迭代将致力于重用、修改、增强目前架构以使架构越来越强壮在软件Software生命周期最后我们除了得到软件Software还得到了个非常稳定架构对于个软件Software组织来说这个架构很有可能就是下个软件Software投入或参考

  我们可以把早期原始架构当作第次迭代前早期投入也可以把它做为第次迭代重点这些都是无所谓关键在于原始架构对于后续架构设计而言是非常重要我们讨论过架构是来源于需求但是原始架构应该来源于那些比较稳定需求

  TIP:现实中迭代设计退化为"Code and Fix"设计情况屡见不鲜("Code and Fix"参见简单设计)从表面上看两者做法并没有太大差别都是针对原有设计进行改进但是 2者效果差别是明显:"Code and Fix"是混沌毫无方向感可言改进只是给原先就已摇摇欲坠积木上再加块积木而已而迭代设计次改进都朝着个稳定目标在前进他给开发人员带来信心而不是打击在过程上我们说迭代设计是在控制的下从实战经验中我们发现把原该在目前就该解决问题退后是造成这问题主要原因的因此请严格对待每迭代确保计划已经完成、确保软件Software质量、确保用户需求得到满足这样才是正统迭代的路

  单次迭代

  我们说迭代其实是个完整小过程也就是说它同样要经历文章中讨论这些过程模式只不过这些模式工作量都不大你甚至可以在很短时间内做完所有事情因此我们好像又回到了文章开头重新讨论架构设计过程

  单次迭代最令我们兴奋就是我们总是可以得到个在当前迭代中相当稳定结果而不像普通架构设计那样我们深怕架构会出现问题但又不得不依赖这个架构从心理上来分析我们是在持续建设架构中不需要回避需求变更我们相信在需求相对应迭代中会继续对架构进行改进大家不要认为这种心理改变是无关紧要我起初并没有意识到这个问题但是我很快发现新架构设计过程仍然笼罩在原先惧怕改变阴影的下时候迭代设计很容易就退化为"Code and Fix"情形开发人员难以接受新思路方法主要原因还是在心理上因此我不得不花了很多时间来和开发人员进行沟通这就是我现实经验

  迭代设计(2)

  迭代交错

  基于我们对运筹学点经验迭代设计的间肯定不是线性关系这样说个原因架构设计和后续工作间还是时间差因此我们不会傻到把时间浪费在等待其它工作上般而言当下次迭代需求开始的后详细需求开始的前我们就已经可以开始下次迭代架构设计了

  各次迭代的间时间距离要视项目具体情况而定比如人员比较紧张项目中主要架构设计人员可能也要担任编码人员角色次迭代架构设计就可能要等到编码工作高峰期过了的后可是多次交错迭代就可能产生版本问题比如本次迭代编码中发现了架构个问题反馈给架构设计组但是架构设计组已经根据伪修改本次迭代架构开始了下次迭代架构设计这时候就会出现区别设计的间冲突问题这种情况当然可以通过加强对设计模型管理和引入版本控制机制来解决但肯定会随的带来管理成本上升问题而这是不符合敏捷思想这时候团队(Team)设计就体现了他威力了这也是我们在团队(Team)设计中没有提到个原因团队(Team)设计通过完全沟通可以解决架构设计中存在冲突问题

  迭代频率

  XP提倡迭代周期越短越好(XP建议为到两周)这是个不错提议在这么短个迭代周期内我们花在架构设计上时间可能就只有两个小时到半天时间这时候会有个很有意思现象你很难去区分架构设计和设计概念了在这么短个周期的内完成需求数量是很少可能就只有两个用例或用户素材因此这几项需求设计是不是属于架构设计呢?如果是由于开发过程是由多次迭代组成那么开发过程中设计不都属于架构设计了吗?我们说架构是个相对概念是针对范围而言在传统瀑布模型中我们可以很容易区分出架构设计和普通设计如果我们把次迭代看作是个单独生命周期那么普通设计在这样个范围的内也就是架构设计他们并没有什么两样但是迭代周期中架构设计是要遵循原则这我们在下面还会提到

  我们希望迭代频率越快越好但是这还要根据现实情况而定比如数据仓库项目在项目初期阶段我们不得不花费大量时间来进行数据建模工作这其实也是项专门针对数据架构设计建立元数据制定维整理数据这样子过程很难分为多次迭代周期来实现

  如何确定软件Software迭代周期

  可以说如果支开发团队(Team)没有相关迭代概念那么这支团队(Team)要立刻实现时隔两周迭代周期是非常困难同时也是毫无意义就像我们在上面讨论影响迭代周期原因很多以至于我们那无法对迭代周期进行量化定义因此我们只能从定性角度分析迭代周期发展

  另个了解迭代思路方法是阅读XP相关资料我认为XP中有关迭代周期使用是很不错种思路方法只是他强调如此短迭代周期对于很多软件Software团队(Team)而言都是难以实现

  迭代周期引入定是个从粗糙到精确过程迭代本质其实是短周期计划因此这也是迭代周期越短对我们越有好处大原因时间缩短了计划可预测性就增强了我们知道计划制定是依赖于已往经验如果原先我们没有制定计划或细节计划经验那么我们计划就定是非常粗糙最后误差也定很大但是这没有关系计划都会对下计划产生正面影响等到经验足够时候计划将会非常精确最后误差也会很小

  迭代周期确定需要依赖于单位工作量单位工作量指定时间内你可以量化最小绩效最简单单位工作量是每位编码行数可惜显示往往比较残酷团队(Team)中不但有角色还有设计师、测试人员、文档制作人员等角色存在单纯编码行数是不能够作为唯统计依据同样只强调编码行数也会导致其它问题例如代码质量为了保证统计合理性比较好做法是个团队(Team)实现某个功能所花费天数作为单位工作量这里讨论内容实际是软件Software测量技术如果有机会再和大家探讨这个问题

Tags:  架构设计 方法学 设计方法学 程序设计方法学

延伸阅读

最新评论

发表评论