zoukankan      html  css  js  c++  java
  • 研发的那些事2—设计之惑

         设计真是件奇妙的事情,能造就璀璨的明珠,也能带来一堆万年不去核废料;能让人享受释放智慧的乐趣,也能品尝挫败的沮丧。Why?

    设计的过程

         工程角度,设计是一个过程,包含三种不同层次的活动:架构设计,概要设计和详细设计。三者由全局到局部,依次展开,逐渐深入细节,最终完成一个技术解决方案,给出可行的如何实现需求的答案。此三者的一般性过程如下:

      

    架构设计

    目标:定位全局,确定技术方案的方向、后续技术活动策略。

    输入:需求文档。敏捷过程常常是是一组用户故事。

    输出:架构设计文档。敏捷过程称之为应用全局视图Application Overview。

    角色:架构师

    任务:

    1.分析需求,识别关键功能、质量需求和约束

    2.分析目标系统为达成以上目的,需要哪些流程,流程中有多少环节,各环节涉及哪些角色,这些角色的职责及他们之间的协作关系。

    3.将角色按逻辑分类抽象,变成子系统。角色的职责即是子系统的接口,角色间的协作关系即为各子系统间的关系。

    4.各子系统内部,根据职责拆分模块,确定它们的交互方式。

    5.针对关键功能,确定完成这些功能的流程,在时序上由各子系统,模块协同工作的顺序。

    6.考虑各子系统的部署方式。

    7.将各子系统、模块转换成实现语言的元素。如对于.net,规划各子系统有哪些namespace,namespace如何分配到assembly,assembly之间的依赖关系。再将assembly分配到project中。期间需要注意避免循环依赖,明确接口(作为接口的assembly和project)。

    8.规划project在SCM中的组织结构。

    9.根据质量需求确定全局性的技术策略(方案):如线程控制,错误处理,数据存储等。

    10.分析其余需求,验证当前方案是否能支持,根据发现的问题做必要调整。

      

    概要设计

    目标:在具体实现语言层面上展开工作,确定每个project的主要类及交互过程和总体算法。

    输入:架构设计文档和需求。

    输出:概要设计文档。

    角色:高级程序员

    任务:

    1.设计提供暴露服务的接口的具体实现类,补充所需的相类,通常可按界面(接口)、活动和存储三方面考虑。进一步落实对项目外接口的依赖关系和位置。

    2.设计算法实现接口暴露的相关功能。

      

    详细设计

    目标:确定概设提出的每个方法的具体实现。

    输入:概要设计

    输出:伪代码。

    角色:程序员

    任务:用伪代码描述每个方法。

         这里看到的是一个按需求->系统->子系统->模块->类->方法,自顶向下逐步求精的过程。

    设计的技术

         技术角度,设计是一系列方法和工具,通过应用这些方法和工具给出一个可行解决方案的描述。常用方法有:

         OO:面向对象方法。其目的是统一问题的描述与解决方法,通过一致的抽象提高开发效率。核心思想是,将问题空间映射到计算机模型上,在计算机中建立一个同我们日常感知世界相同的模型,解决问题。实践中,通过类描述问题空间的概念,通过类的消息描述这些概念的交互形成一个模型,再将模型落实到OOP的语言中,如C++,C#,Java等。

         AOP:面向方面的方法。期望将主要业务同这些业务中散落的支撑功能(服务)如日志,权限等分离。结合OOP应用时,通过横切点定义跨多个类的支持服务,由方面(特殊类)实现这些服务,再通过切入点连接方面与横切点,达到运行时自动提供服务的目的。

         DDD:领域驱动的设计。采用传统OO方法时,一般的需求分析结果是用自然语言描述的与OOD存在脱节,容易生造出问题域中不存在的概念,建立与实际需求不一致的模型。因此,从需求分析起,首先为问题域即领域建模,完全不考虑如何设计、实现,用客户能理解的方法仅描述问题现状。常用的建模方法是OOA,模型可用UML表达,也可以用类似框图联系,总是以能让用户明白这就是问题的描述,方便沟通为原则。

         在不断使用这些方法的过程中,一些大师们发现了某些经常重复的解决方案,便对它们进行了提炼和总结,以便后来者这能利用这些经验,提高工作效率和质量,少走弯路。这些经验有:架构风格,架构模式,设计模式和反模式。

    架构风格

         架构层次的,根据系统的架构呈现出的总体特点进行架构分类的方式。主要的风格有:

    1.客户-服务器:系统分为客户与服务端两部分,客户端发送请求,服务端执行并响应。

    2.分层(级)架构:系统按关注点水平分层,每一层为上层提供一个抽象。近一步,可将层分布到不同计算机上。

    3.面向对象:系统分成单独的可重用的对象,每个对象包含数据及处理它们的行为。

    4.基于消息(事件):系统各部分通过发送和接收约定格式的消息工作,无需关心实际的收发者。

    5.面向服务(SOA):系统通过约定的契约暴露功能,并根据这些契约工作。

    6.基于组件:系统分解为逻辑的可重用位置透明的组件,通过明确定义的通信接口工作。

    7.管道-过滤器:由管道连接过滤器一组,处理流经的数据。

    8.微内核:分离最小功能核心和可扩展部分。

         它们在最高层次根据问题的类型给出了一般的解决方向。如:

    1.通信问题:基于消息、管道-过滤器

    2.部署问题:客户/服务器、分层架构

    3.重用与可扩展:OO、基于组件、SOA

         但是,不同风格并不是互相排斥的,相反,一个实际系统通常同时呈现出多种风格。如一个分布系统,功能可通过语言无关的契约暴露,用OOP实现这些契约,实现对象又被组织成一个个组件,每个组件定义了彼此的通信接口,而通信又可是基于消息的,组件本身运行在一个支持插件的容器中,可随时添加新组件,提供新服务。这里表现出了SOA、OO、Component、Messaging和Mico-Kernel多种风格。

    架构模式

         一系列可重用的架构设计方案,每个方案在满足适用场景的前提下,解决一种或一类问题。经典的POSA给出了一些常用的模式分类:

    1.服务访问和配置:包装器(Wrapper Facade)、组件配置器(Component Configurator)、截取器(Interrceptor)、扩展接口(Extension Interface)

    2.事件处理:反应器(Reactor)、主动器(Proactor)、异步完成标记(ACT)、接收-连接器(Acceptor-Connector)

    3.同步:界定枷锁(Scoped Locking)、策略化加锁(Strategized Locking)、线程安全接口(Thread-Safe Interface)、双检查加锁优化(Double-Checked Locking Optimization)

    4.并发:主动对象(Active Object)、监视器对象(Monitor Object)、半同步/半异步(Half-Sync/Half-Asynce)、领导者/追随者(Leader/Followers)、线程特定存储器(Thread-Specific Storage)

    5.资源获取:查找(Lookup)、懒加载(Lazy Acquistion)、预加载(Eager Acquistion)、分步加载(Partial Acquisition)

    6.资源生命周期:缓存(Caching)、池(Pooling)、协调器(Coordinator)、资源生命周期管理(Resource Lifecycle Manager)

    7.资源释放:租约(Leasing)、清除者(Evictor)

    此类模式给出了全局性问题的一般处理方案,大都是关于子系统、模块及相互之间关系的粗粒度的描述。

    设计模式与反模式

         设计模式指OO的设计模式,是可反复使用的代码经验总结。通过GoF经典的《设计模式》广为人知。GoF将它们分类为:

    1.创建型:简单工厂(Simple Factory)、工厂方法(Factory Method)、抽象工厂(Abstract Factory)、创建者(Builder)、原型(Prototype)、单例(Singleton)

    2.结构型:外观(Facade)、适配器(Adapter)、代理(Proxy)、装饰(Decorator)、桥接(Bridge)、组合(Composite)、享元(Flyweight)

    3.行为型:模板方法(Template Method)观察者(Observer)、状态(State)、策略(Strategy)、职责链(Chain of Responsibility)、访问者(Visitor)、调停者(Mediator)、备忘录(Memento)、迭代器(Iterator)、解释器(Interpreter)

    它们在代码层面给出解决上述三类问题的一般做法及使用场景。

         设计模式如红日般普照大地,光芒万丈,导致做OO的言必称设计模式,不用上几个都不好意思拿去见人。免不了被乱用、误用,明明需要避光保存的,偏偏加个LED增加照明,还曰节能、低碳。所以不得不需要反模式来拨乱反正。反模式说明了,当在错误的时间,错误的地点,使用了错误设计模式后,出现的严重后果,提醒人们过犹不及。

    设计的人员

         今天,从人员角度,设计是一系列扮演不同角色的人员的协作,他们通过某种过程,应用某些技术,相互配合,共同完成一个解决方案。一个采用传统设计过程的大型系统涉及的角色通常有:

    1.架构师:一个人或者一个团队,负责将系统分解成子系统和模块,去顶它们之间的关系(开发期、运行期)并制定相关的技术决策,如部署、开发、性能等。

    2.高级程序员(设计师):负责完成一个或多个子系统、模块的概要设计。

    3.程序员:负责详细设计。

    4.项目经理:负责整个活动的任务协调,并根据架构安排开发任务。

    其中,架构师是核心,其工作成果是后续管理和实现的基石。有什么样的架构,便会有什么样的开发组织结构。如分层架构,必然会存在界面、业务、持久化及公共模块的开发职责分配,由不同人(团队)完成不同层的工作。

         现代软件,因为规模和复杂性,再也无法由个人独立完成所有工作,必须依靠协作。协作首先需要分工,明确各工种的职责,个人依照职责行事。分工之后便有了工作的先后次序,不同次序的串联需要一定规则,便形成了一些过程规范,大家依照规范协同。所以,才有了那么多的软件工程方法论,开发才有了架构师,设计师和程序员的细分。不能简单的认为架构师>设计师>程序员,他们主要的区别在于工作范围的广度和深度的侧重点不同。架构师更广,程序员工作的更深入。

         为了使用一致的思维考虑问题与问题的解决方法,诞生了OOP。为了分离业务与支持服务,让不同的人在不同的时间和地方分别解决不同问题,诞生了AOP。为了便于开发人员与用户达成待解决问题的一致认识,诞生了DDD。

         设计时无论采用何种种过程、技术和人员组织方式,根本目的只有一个:给出关于需求的技术解决方案。

         实际工作中还会碰到一个严重的问题,常常发现,要解决的问题,并不是地上的石头,静静的躺在那儿,等你照剑谱挥剑的。经常是,哦,我要砍的不是这块,是那块,甚至不是碎石而是需要劈柴,一身武艺无处使。不由怒从心头,不时问候需求人员或者客户,干嘛不一次说清楚,写的仔细点。害我改这改那儿的。对此,Brooks在《设计原本》说:设计的本质是帮助客户发现他们想要的需求

    设计的本质!

         根本上,解决方案和问题是共同变化的,甚至会相互影响。现实中,需求阶段给出的需求,往往是初始需求,随设计过程的推进,它会奇妙的发生一些变化:

    1.需求描述更精确了:随着设计深入,发现原来的描述存在模糊的方,需要更精确才能做出设计决策。

    2.需求描述错了:设计着,突然,卡住了,一交流,发现,哦原来这不是用户要的,他们要那样的,其实很简单。

    3.出现新需求:会发现之前不曾注意的需求,会加入系统性的需求,如缓存等。

         设计必须能适应这些变化,有些需要通过技术方法,柔性的容纳新变化,将变化点抽象成接口,隔离变化,新需求只要设计成新的实现了即可。有些则只能通过总体过程来适应,如敏捷过程的高迭代,分批交付,在每个迭代间能响应变化。企图一次就做出美妙的设计是不现实的,设计必须具备响应变化的能力。因此,设计人员需要:

    1. KISS:时刻注意保持简单性,简单的方法往往也是最正确高效的。
    2. 关注需求:时刻注意什么是真正的需求,遇到困难,不妨先想想,真的需要解决这个问题吗,能换种方式吗?
    3. 适度的远见:预见同类需求发生的可能性,并提前考虑对策。如看到报表需要导出成excel,想想是否有生成pdf的可能性,如有必要尽早隔离这种变化。
    4. 系统性思维:时刻注意用需求去验证设计,确认设计是否满足需求,满足的是否牵强,是否因假想了需求而增加了额外的复杂性。
    5. 全局性思维:思考设计会对开发、测试和部署运营造成什么样的影响,因为这些方面往往存在致命的隐含需求。
    6. 提升抽象层次:从一次一个系统转换到一次一个系统族,考虑所有同类系统的共性和可变性,将共性做成框架,可变性提炼成配置,DSL留到具体项目实施时完成。
  • 相关阅读:
    HDU 1114 Piggy-Bank
    HDU 2955 Robberies
    NTOJ 290 动物统计(加强版)
    POJ 3624 Charm Bracelet
    HDU 2602 Bone Collector
    POJ 1523 SPF(无向图割顶)
    HDU 5311 Hidden String
    HDU 1421 搬寝室
    HDU 1058 Humble Numbers
    POJ 3259 Wormholes(spfa判负环)
  • 原文地址:https://www.cnblogs.com/Chaos/p/1961167.html
Copyright © 2011-2022 走看看