zoukankan      html  css  js  c++  java
  • 从实际项目出发,浅淡什么是设计空间

    前言:

    本人从事小微企业信息化工作已经有10余年了,自己的一个小工作室带着如流水一样的成员开发了一个又一个的项目。在十余年的经历中,我自行研发了一套基于ASP.NET的框架。这套框架从V1到V8体现的是我对软件工程理解的加深,回顾过去,8个版本的框架可以看出我的技术学习走向,也能看出每套框架的设计空间大小,更能看出基于框架开发应用程序的简单程度。那正好,我最近在研发V8的框架中,对这些内容也有了更深的思考和总结。写出来与大家一起分享。

    第一节:背景

    本文所述的概念是有背景和使用范围的。针对的是小工作室开发项目而不是制作产品。由于我所在的团队属于工作室性质,队员的流动性极高。同时,我所涉及的项目大部分是短平快类型的,在统计我所有项目的开发时间后发现我花费时间最多的居然是升级框架,其次才是小型项目。那么,在这个大前提下,我不方便使用自动化构建工具。因为众所周知,自动化构建最麻烦的就是项目一开始的配置工作且这种东西学习成本非常高。如果是产品,那么学习/配置一次你可以永久使用。而我的项目使用自动化构建就有鸡肋(事实上我只对前端使用自动化构建)。

    在此前提下,我的大部分项目都共用一个解决方案,我没有人手单独维护框架项目。只能是在不停的开发和使用过程中,更新项目框架(释放设计空间)。直到有一天,这个框架的设计空间使用完毕,直接重构然后换下一个继续。

    其实,这种构架并不健康。我看了一下,好像也没什么人专门研究这种团队。大部分人认为这种团队其实是失败的,活不久的,同时也是做不大的。不过呢,我见到的不少小型团队都处于这个状态下。毕竟,也不是所有人都能脑子一拍想出一个非常好的产品。哪怕有非常好的产品也不是所有人都能拿到投资。

    于是,本文所对应的团队背景一定要符合以下条件:

    1、你所在的团队开发的是一系列有共性的项目(比如都是CMS,或者都是MIS);

    2、你所在的团队一定是小微团队(5-10人),并且没有足够的人手维护框架;

    3、你所在的团队流动性很大,团队成员的水平参差不齐,且学习成本高;

    4、你的经费非常宝贵,也许你团队的主要支出就是工资;

    5、你在团队中拥有一定的话语权。

    第二节:什么是设计空间

    这是一个我自己对软件架构稳定性的一个定义。设计空间指的在框架代码中,插入多少业务代码且不会影响框架的稳定性和复用性的空间。他有两个子概念,在何处插件代码不会影响框架的稳定性和复用性?插入什么样的代码不会影响稳定性和复用性?总的来说,插件代码的位置数目和代码形式就是设计空间的大小评判标准。

    我对“设计空间”的定义进行一个详细的解释:

    1、添加的代码必须是面向业务的

    软件的代码大致可以分为两大类:业务代码和框架代码。所谓框架代码,指的是可复用的代码,基本上在所有你所在的业务领域中都有的。比如,我专注于制作校企信息化系统。那么在这种系统中,无论哪个都会有:用户,角色,权限和组织机构。而无论哪个系统的用户一定有ID,姓名,学/工号,用户名和密码。那么这些类,这些字段就是属于框架代码,他们是可以复用的,而框架代码不会占用设计空间。

    业务代码指的是专注于某个具体业务的,比如在V3框架时代,我还是一个做学校网站的萌新。当时我开发了“某校网上展馆v1.0”系统。该系统分属于CMS系统,当时做的时候还是使用三层架构。在该系统中,拥有一个类“展板”。那么对于这个类和我所在的业务领域中,除了这个项目,再其它任何项目中我都找不到需要使用这个类的地方。那么这个类就使用了我V3框架的设计空间。

    2、添加后的代码必须会影响架构的稳定性或复用性

    由于是小型化团队,你没有可用的人手维护框架项目。所以,在这种情况下使用自研框架(不要问我为什么不用成品框架,2010年我开始工作的时候,ASP.NET的框架简直没法看),为了保证代码的复用和更新,你唯一的作法就是把所有项目都引用同一个框架部分。比如,在我的V3版本框架中,6个项目都使用了同一个Model。我现在已经没有那时候的设计工具了,直接截个图给大家看看。

     

    图1 所有项目所共有的Context

    在这种情况下,你每增加一个类(一张表)都会使用设计空间。因为除了框架中所需要的类,其它任何类你都无法复用。而小团队有个非常麻烦的问题——人员流动性大,学习成本高。也就意味着,一个新人来到你的团队很可能需要两周甚至三周的学习。这种学习时间和过程,他们就会碰到一堆其实根本用不到的类。所以,在这种情况下,我认为这些类侵占了框架的设计空间。

    再举个例子,比如V3框架的工作流模块,使用的还是WWF。在这里,我写了很多自定义的活动:

     

    图2 V3工作流模块中的某个活动

    请注意,这些活动的复用性绝对是0。因为他们是针对业务开发的,只有在“某校实验室管理系统”项目中,这些活动才有使用的可能。后来者不需要阅读此模块,但需要学习模块中的一些写法。于是他们的存在就非常尴尬,删也不是,不删也不是。他们也侵占了设计空间。

     

    除了这种情况,还有一些代码会影响架构的稳定性。这里需要介绍一下,构架的稳定性和软件的可靠性是不一样的。架构的稳定性指的是需求的变更和代码的变更对软件系统影响大小,这是一个经验量。软件的可靠性指的是在具体的使用环境中,软件系统一段时间内的出错次数(或者说鲁棒性),这是可以量化的。本文讨论的是稳定性。

    这一次来到了V4框架,构架的背景是2015年,那时我对RBAC系统的理解还非常浅,并且完全不懂Claim-based的构架。在这种情况下,我们来看一下获取用户函数的实现:

     

    图3 影响稳定性的代码

    观察上述代码,可以看到user.IsInRole直接把具体需要的角色写在了SecurityService的类里。这是一个完全无法接受的行为,因为,根据统计数字显示,我的框架获取用户的组件调用的就是本函数取数据,而这个组件每天需要被调用数万次。而哪怕换了一个系统,取用户还是这个函数,还是这套代码。那么,换了一个系统还会有“教务处管理员”吗?显然,这是不可能的。再比如,哪天教务处要添加一个新的角色,比如“创新学分管理员”,对就是上述代码里的OR后面的东西。那我需要修改所有受影响的代码,那这种构架就是不稳定的。而编写这种代码,就是在释放设计空间。

     

    第三节:设计空间的意义和度量

    设计空间是我评判一套框架好坏的重要指标,设计空间的意义在于我对系统可以做出多少破坏,也在于我可以对系统进行多少修改。设计空间大的系统,在面临需求变更时,可以通过释放一部分设计空间来换取最高效的修改速度。

    而如何度量设计空间?我一般使用插入点的数目来定大小。我翻阅框架代码就会去理解哪些代码中是可以通过插入业务代码来实现最快速修改需求的目的。把这些数目加起来,就是我度量设计空间的方法。根据我本人的实践而言,设计空间的大小不应该小于需求功能总数的1.5倍。比如V4框架的用户模块设计空间在经过衡量以后就只有20左右。而开发一个用户模块,我就说的简单一点,用户,角色,权限和组织机构的CRUD就有16个。那么在这种情况下,新来的需求虽然也可以通过本框架实现,但修改的时候就会感觉束手束脚,哪都不方便。

    比如,还是上述例子。其实最早的函数(设计空间为2)是长这样的:

     

    这个函数的设计空间就很大(大小为2,基本就是我注释的地方)。因为他完全是不基于业务的。也可以看到,当实际的需求来临的时候(即只有“教务处管理员”等角色才可以根据学号的一部分找到用户,而其它角色只能通过输入完全的学/工号才能找到用户),我可以通过释放设计空间的形式,将上述代码快速复制一份并且变成图3的样式。这一修改可以在5分钟内完成,10分钟内部署,那客户就会认为你的业务能力强,能够快速按他们的要求修改系统。

    所以,维持设计空间的最终目的是为了可以快速的按变更后的需求修改系统。设计空间的大小于与修改需求变更的时间成反比。

     

    第四节:设计空间的释放和侵占

    设计空间既然被定义出来,那一定就是为了被占用的。所以,何时使用设计空间就是一个非常重要的事。我认为,在项目的开发和设计阶段,使用设计空间就是一件非常不好的事。因为这时,明明可以通过对系统设计的修改而保住这些设计空间,甚至可以为将来的修改留下足够的空间。所以,在这种情况下使用设计空间,我称之为:侵占。即,你本来可以不使用,但却使用了将来的空间。

    而在项目实际运行后,由于需求的变化你可能需要以最快的速度响应这些变化。这时,你就要根据实际需求释放设计空间。比如,今天来了一个重要需求,领导要求你半天必须解决。这是,观察需求一看之前留下了设计空间。那就可以通过直接释放的形式使用这些空间来快速完成项目。

    那么,非常容易理解和想到的一点就是。当一个系统的设计空间被释放的差不多时,也就是这个系统应当重构的时候。重构时,不光要把之前的设计空间还回去。还需要根据未来需求变化的可能和方向重新预留设计空间。

     

    第五节:总结

    设计空间的本质是拥抱变化,最终目的是快速修改变化的需求。他体现着开发者对需求未来变更可能性的掌握程度。一个好的设计者可以在看到需求时就想到未来可能发生的需求变化。而使用设计空间的本质是开发者考虑不周或者因为其它原因的妥协,还是图3所示的例子,如果我当时就知道找用户有可能按角色有不同的找法,那么设计上直接给予权限“按部分学/工号查询用户”,使用时,我只要配置哪个角色有此权限即可(即,V5框架中就有)。那么,当需求变更发生时,我就不需要使用设计空间。

    需要知道一点,研发系统是有时间成本的。设计者哪怕在考虑到需求未来变更可能性的时候,也不可能将所有可能性都留下接口和设计(时间成本不接受,开发成本也不定接受)。所以,这时可以留下一个设计空间,在未来需求变更时,直接通过释放设计空间的形式也能快速达成修改需求的目的。

    诸位如果对这个有兴趣的话,不妨可以留言讨论。如果有兴趣的人多的话,我接下来就再写写如何在“设计空间的预留和使用”。

  • 相关阅读:
    LeetCode 81 Search in Rotated Sorted Array II(循环有序数组中的查找问题)
    LeetCode 80 Remove Duplicates from Sorted Array II(移除数组中出现两次以上的元素)
    LeetCode 79 Word Search(单词查找)
    LeetCode 78 Subsets (所有子集)
    LeetCode 77 Combinations(排列组合)
    LeetCode 50 Pow(x, n) (实现幂运算)
    LeetCode 49 Group Anagrams(字符串分组)
    LeetCode 48 Rotate Image(2D图像旋转问题)
    LeetCode 47 Permutations II(全排列)
    LeetCode 46 Permutations(全排列问题)
  • 原文地址:https://www.cnblogs.com/Pray4U/p/13547416.html
Copyright © 2011-2022 走看看