第11章 系统
“复杂要人命。它消磨开发者的生命,让产品难以规划、构建和测试。”。
你能自己掌握一切细节吗?大概不行。
城市能运转,还因为它演化出恰当的抽象等级和模块,好让个人和他们所管理的“组件”即便在不了解全局时也能有效地运转。
将系统的构造与使用分开。
构造与使用是非常不一样的过程。
软件系统将启始过程与启始过程之后的运行时逻辑分离开,每个应用程序都该留意启始过程。
将关注的方面分离开,是软件技艺中最古老也是最重要的设计技巧。
可以使用抽象工厂模式让应用自行控制何时创建对象,但构造的细节却隔离于使用的客户端代码之外。
有一种强大的机制可以实现分离构造与使用,那就是依赖注入(Dependency Injection, DI),控制反转(Inversion of Control, IOC)在依赖管理中的一种应用手段。
控制反转将第二权责从对象中拿出来,转移到另一个专注于此的对象中,从而遵循了单一权责原则。
“一开始就做对系统“纯属神话。反之,我们应该只去实现今天的用户故事,然后重构,明天再扩展系统、实现新的用户故事。
这就是迭代和增量敏捷的精髓所在。
测试驱动开发、重构以及它们打造出的整洁代码,在代码层面保证了这个过程的实现。
在AOP中,被称为切面(aspect)的模块构造指明了系统中哪些点的行为会以某种一致的方式被修改,从而支持某种特定的场景。这种说明是用某种简洁的声明或编程机制来实现的。
编程工具能自动处理大多数代理模板代码。
使用XML配置文件或Java5 annotation,EJB3很大程度上遵循了Spring通过描述性手段支持横切面的模型。
没必要先做大设计(Big Design Up Front,BDUF)。
实际上,BDUF甚至是有害的,它阻碍改进,因为心理上会抵制丢弃既成之事,
也因为架构上的方案选择影响到后续的设计思路。
我们可以从“简单自然”但切分良好的架构开始做软件项目,快速交付可工作的用户故事,随着规模的增长添加更多基础架构。
在没能真正得到使用时,设计得再好的API也等于杀鸡用牛刀。
最佳的系统架构有模块化的切面领域组成,每个切面均用纯Java对象实现。不同的领域之间用最不具有侵害性的切面或类方面工具整合起来。
模块化和关注切面成就了分散化管理和决策。
最好是授权给最有资格的人。
延迟决策到最后一刻也是好手段,它让我们能够基于最有可能的信息作出选择。
有了标准,就更容易复用想法和组件、雇佣拥有相关经验的人才、封装好点子,以及将组件连接起来。
领域特定语言(Domain-Specific-Language, DSL)是一种单独的小型脚本语言或以标准语言写就的API,领域专家可以用它编写读起来像是组织严谨的散文一般的代码。
优秀的DSL填平了领域概念和实现领域概念的代码之间的“壕沟”,就像敏捷实践优化了开发团队和甲方之间的沟通一样。
DSL在有效使用时能提升代码惯用法和设计模式之上的抽象层次。它允许开发者在恰当的抽象层级上直指代码的初衷。
系统也应该是整洁的。
侵害性架构会湮灭领域逻辑,冲击敏捷能力。
当领域逻辑收到困扰,质量也就堪忧,因为缺陷更易隐藏,用户故事更难实现。
当敏捷能力收到损害时,生产力也会降低。
在所有的抽象层级上,意图都应该清晰可辨。
只有在编写POJO并使用类方面的机制来无损地组合其他切面时,这种事情才会发生。
无论是设计系统或单独的模块,别忘了使用大概可工作的最简单方案。