写点什么

架构师训练营第二周总结

用户头像
J
关注
发布于: 2020 年 12 月 06 日

架构师训练营第二周总结


1. 为什么要从编程的历史看编程的本质和未来?


编程的近代史是从纸带机、汇编语言开始的,进而不断发展出形形色色的编程语言,这是一个从机器执行角度思考,到从编程语言使用者角度思考的变迁。现在主流的几种编程范式,和各种所谓的高级语言的出现,都是为了提高软件开发人员解决现实问题的效率,降低出错的几率。



2. 面向对象设计——高内聚、低耦合


编程实际上是对现实问题抽象建模的过程,因为现实世界可以通过抽取事物的特性构成对象的方式进行抽象,所以面向对象设计和分析是一种常见和实用的问题解决方式。

但是面向对象编程语言(如 C++、Python、Java 等)的使用,并不代表着解决问题的方式是面向对象的设计,实际上很多场景下,开发人员是用过程化的方式思考和解决问题,抽象程度并不够高,导致设计出的系统不容易扩展,维护也很困难。如果问题的解决方式是面向对象设计的,实现的编程语言即使是常见过程式语言,如 C 语言,也是面向对象编程。

我们可以通过定义,正确的面向对象设计的目的和原则来判断实现是否“面向对象”。

  1. 面向对象设计的目的

  2. 面向对象设计的原则

3. 软件框架和架构师


软件框架是用来实现某一类应用的结构性程序,是对某一类结构方案可复用的设计与实现。

  • 如同大厦的框架

  • 简化应用开发者的工作

  • 实现了多种设计模式,使应用开发者不需要花太大的气力,就能设计出结构良好的程序。

软件框架本质也是程序,是代码和配置构成的。框架不同于一般程序就在于,一个框架都专注于解决某一个应用领域的常见问题,解决的方式是从结构性设计出发,对该领域问题进行抽象,将基本对象和过程定义和实现,而应用开发者在遵守框架制定的规范下,可以不用关注框架的实现细节,就能够快速开发出满足功能和性能要求的应用和服务。


典型的框架例子如 Web 服务器 Tomcat,应用开发者遵守 J2EE serverlet 规范编写的代码,能够被 Tomcat 识别和执行。应用程序和服务开发框架 Spring 也是一种知名框架,开发者通过注解方式定义组件,可以被 Spring Framework 识别和正确运行起来。

所以框架和开发者开发的代码的关系是:框架调用应用程序代码,应用程序代码是在遵守框架制定的规则下编写。因为框架设计和实现时,应用程序代码是还未被开发的。

架构师应该具备有设计和实现框架的能力,框架的存在,能够保证架构师设计的框架正确和有效率的落地。因为框架的存在,使得框架的细节和复杂问题被封装起来,避免业务开发者乱用。业务开发者在遵守框架规范的情况下,能够快速开发更多的应用。

4. 面向对象设计的基本原则


这些基本原则是为了避免软件设计中的“臭味”。软件设计中的臭味就是与软件设计目标“高内聚、低耦合”相违背的行为。这些有“臭味”的行为存在这些特点:

  • 僵硬——不易改变

  • 脆肉——只想改变 A,结果 B 被意外破坏

  • 不可移植——不能适应环境的变化

  • 导致误用的陷阱——做错误的事比做正确的事容易,会引诱程序员破坏原有的设计

  • 晦涩——代码难以理解

  • 过度设计、copy-paste 代码

僵硬性(Rigidity):很难对系统进行改动,因为每个改动都会迫使对系统的其他部分发生改动。这都会带来难以控制的缺陷率和维护性。

脆弱性(Fragility):对系统的改动会导致系统中与改动位置无关的内容出现问题。

出现新问题的地方与改动的地方没有概念上的关联。要修正这些问题又会引出更多的问题,从而使开发团队就像一只不停追逐自己尾巴的狗一样。

牢固性(Immobility):很难解开系统的纠结,所以很难使之成为一些可在其他系统中重用的组件。

设计中包含了对其他系统有用的部分,而把这些部分从系统中分离出来所需的努力和风险是巨大的。

粘滞性(Viscosity):做正确的事情比做错误的事情要困难。

面临一个改动的时候,开发人员常常会发现会有多种改动的方法。有的方法会保持系统原来的设计,而另外一些则会破坏设计,当那些可以保持系统设计的方法比那些破坏设计的方法跟难应用是,就表明设计具有高的粘滞性,作错误的事情就很容易。

不必要的复杂性(Needless Complexity):设计中包含有不具任何直接好处的基础结构。

如果设计中包含有当前没有用的组成部分,他就含有不必要的复杂性。当开发人员预测需求的变化,并在软件中放置了处理那些潜在变化的代码时,常常会出现这种情况。

不必要的重复(Needless Repetition):设计中包含有重复的结构,而该重复的结构本可以使用单一的抽象进行统一。

当 copy,cut,paste 编程的时候,这种情况就会发生。

晦涩性(Opacity):很难阅读、理解。没有很好的表现出意图。

代码可以用清晰、富有表现力的方式编写,也可以用晦涩、费解的方式编写。一般说来,随着时间的推移,代码会变得越来越晦涩。


软件的腐化会导致臭味,那么是什么激发了软件的腐化?答案是需求的变化。由于需求没有按照初始设计预见的方式进行变化(通常也不会按照预设模式进行),从而导致了设计的退化。通常,这些改动都很急迫,并且进行改动的开发人员对原始的设计思路并不熟识。因而,虽然对设计的改动可以工作,但是它却以某种方式违反了原始的设计。随着改动的不断进行,这些违反不断地积累,设计开始出现臭味。

  然而,我们不能因为设计的退化而责怪需求的变化。作为开发人员,我们对需求变化有非常好的了解。事实上,我们中的大多数人都认识到需求是项目中最不稳定的因 素。如果我们的设计由于持续、大量的需求变化而失败,那就表明我们的设计和实践本身是有缺陷的。我们必须要设法找到一种方法,使得设计对于变化具有弹性, 并且应用一些实践来防止设计腐化。

4.1 开闭原则(OCP)


OCP - Open/Closed Principle

  • 对于扩展是开放的(Open for extension)

  • 对于更改是封闭的(Closed for modification)

  • 简言之:不需要修改软件实体(类、模块、函数等),就应该能实现功能的扩展。

4.2 依赖倒置原则(DIP)


DIP - Dependency Inversion Principle

  • 高层模块不能依赖低层模块,而是大家都依赖于抽象;

  • 抽象不能依赖实现,而是实现依赖抽象。

DIP 倒置了什么?

  • 模块或包的依赖关系

  • 开发顺序和职责

软件的层次化

  • 高层决定低层

  • 高层被重用




4.3 Liskov 替换原则(LSP)


一个正确的继承要符合 Liskov 替换原则。

1988 年,Barbara Liskov 描述这个原则:

  • 若对每个类型 T1 的对象 o1,都存在一个类型 T2 的对象 o2,使得在所有针对 T2 编写的程序 P 中,用 o1 替换 o2 后,程序 P 的行为功能不变,则 T1 是 T2 的子类型。

  • 简言之:子类型(subtype)必须能够替换掉它们的基类型(base type)。

需要注意的是,要在问题场景中使用 LSP。比如正方形在数学逻辑上是一种特殊的长方形,但是在软件应用领域中,两者通常是有不同的使用逻辑,会导致正方形不能作为长方形的子类。


4.4 单一职责原则(SRP)


SRP - Single Responsibility Principle

  • 又被称为“内聚性原则(Cohesion)”,意为:

  • 将它与引起一个模块改变的作用力相联,就形成了如下描述:


4.5 接口分离原则(ISP)


ISP - Interface Segregation Principle

不应该强迫客户程序依赖它们不需要的方法。


ISP 和 SRP 的关系

  • ISP 和 SRP 是相关的,都和“内聚性”有关。

  • SRP 指出应该如何设计一个类 —— 只能有一种原因才能促使类发生改变。

  • ISP 指出应该如何设计一个接口 —— 从客户的需要出发,强调不要让客户看到他们不需要的方法。


用户头像

J

关注

还未添加个人签名 2015.06.24 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营第二周总结