【学习总结】04 | 项目大了人员多了,架构怎么设计更合理?

938 阅读22分钟

1、前言

首先,我认为学习总结,要有所总,所结,就是有归纳后,能用自己的话告诉别人!有所结,就是有所收获输出,一般我认为是思维导图,所以,每篇文章前,我都会先给出文章的脑图:

iOS开发高手课-04-项目大了人员多了,架构怎么设计更合理?.png

2、正文

注意,本系列总结不会引用或提供原课程文章所有的内容或代码,只会作出思维导图,需要学习可购买课程 《iOS开发高手课 - 极客时间》

带问题找答案

  1. 模块粒度应该如何划分?
  2. 为什么要分层?
  3. 如何分层?
  4. 多团队如何协作?

文中提了4个问题,那么这4个问题怎么解答呢?所以,解答前,我觉得还是要先说说为什么有架构这东西?

项目架构

为什么?

为什么有架构这东西?有过几年开发经验的同学一定听过或看过 23种设计模式SOLID 原则GRASP 原则奥卡姆剃刀定律敏捷开发等,那么为什么设计模式是23种呢? SOLID 分别代表什么呢?如果只是学习设计模式,SOLID 分别代表什么,那样的话,其实并不能理解为什么?只是解答了,是什么!所以,首先,要给大家介绍一下这些历史和背景,大家才能更好的明白这些原则和模式。

1994 年 10 月 21 日,Erich Gamma(埃里希·伽玛)、Richard Helm(理查德·赫尔姆)、Ralph Johnson(拉尔夫·约翰逊)和John Vlissides(约翰·弗利西德斯)合著《设计模式:可复用面向对象软件的基础》(Design Patterns: Elements of Reusable Object-Oriented Software)出版!后以“四人帮”著称,GoF,又称 Gang of Four。该书是软件工程领域有关软件设计的巨著,提出和总结了对于一些常见软件设计问题的标准解决方案,称为软件设计模式,书中提出的 23 种设计模式,书中的设计模式也被成为“四人帮设计模式”。

所以,大家明白了现在很多xx语言的设计模式,从那里来?为什么是23种?这本书很牛逼,并且这四位作者也很利害,大家自行搜索。关于设计模式就先说到这里,下面在看看其它。

1997 年 10 月 30 日,Craig Larman(克雷格·拉曼)出版《UML和模式应用》(Applying UML and Patterns),书中提出 GRASP (General Responsibility Assignment Software Principles,通用职责分配软件原则),与其将 GRASP 称之为设计模式(Pattern),不如称之为设计原则(Principles),因为它是站在面向对象设计(OOD:Object-Oriented Design)的角度,告诉我们怎样设计问题空间中的类与分配它们的行为职责,以及明确类之间的相互关系等,GRASP 核心思想是职责分配,用职责设计对象。而不像 GoF设计模式那样是针对特定问题而提出的解决方案。因此 GRASP 站在一个更高的角度来看待面向对象软件的设计,它是 GoF设计模式 的基础(可以理解为更宏观的角度)。

2001 年 10 月 12 日,Robert C. Martin(罗伯特·C·马丁)出版了《敏捷软件开发:原则、模式与实践》(Agile Software Development: Principles, Patterns, and Practices)一书,描述了面向对象编程(OOP:Object-oriented Programming)和面向对象设计(OOD:Object-Oriented Design)的五个原则,他称之为 SOLID 原则(单一功能、开闭原则、里氏替换、接口隔离以及依赖反转,每个原则的首字母组合在一起)。需要注意的时,这些原则有些在此书前就提出或相似的概念,其中依赖倒转原则就是1996年提出来的。关于世界顶级软件开发大师罗伯特·C·马丁(Robert C. Martin),大家可能更熟悉 Bob大叔鲍勃叔叔 等称呼,因为他已经有50多年的软件开发经验(1969年至今),如今 67 岁啦!其中《架构整洁之道》是创造“Clean神话”的Bob大叔在架构领域的登峰之作,还有《代码整洁之道》(Clean Code: A Handbook of Agile Software Craftsmanship)不知道大家熟悉吗?

以上就是经典的面向对象的设计原则或模式的由来,大家是不是有一点印象啦!总体来说,GRASP 处于最上层,SOLID 基于它再进一步细化阐述,GOF 再根据这些原则进一步的归纳出更具体的模式。

是什么?

不知道大家有没有发现上面提到的 OODOOP,OOD 是:面向对象设计(Object-Oriented Design),OOP 是:面向对象编程(Object-oriented Programming)。

是什么?当我们在谈论项目架构时,我们在说什么?,其实就是面向对象编程!那么面向对象前,又是怎么样的呢?所以,我们不得不回到历史,看看究竟发生了什么,为什么现在如今的面向对象那么流行?

  1. 1940年以前:面向机器
  2. 脱离机器第一步:面向过程
  3. 第一次软件危机:结构化程序设计
  4. 第二次软件危机:面向对象程序设计

面向机器 使用二进制码来表示机器能够识别和执行的指令和数据。简单来说,就是直接编写 0 和 1 的序列来代表程序语言。由于机器语言实在是太难编写了,于是就发展出了汇编语言。

面向过程 相比面向机器的语言来说,已经不再关注机器本身的操作指令、存储等方面,而是关注如何一步一步的解决具体的问题,即:解决问题的过程。

结构化程序设计(Structured Programming)是一种编程范型,它采取“自顶向下、逐步细化、模块化”的指导思想,使用子程序(函数就是一种子程序)、代码区块、for循环以及while循环等结构,来替换传统的goto,希望借此来改善计算机程序的明晰性、质量以及开发时间,并且避免写出面条式代码。结构化程序设计本质上还是一种面向过程的设计思想。

面向对象程序设计 早在 1967 年的 Simula 语言中就开始提出来了,但第二次软件危机促进了面向对象的发展。 面向对象真正开始流行是在 1980s 年代,主要得益于 C++ 的功劳,后来的 Java、C# 把面向对象推向了新的高峰。到现在为止,面向对象已经成为了主流的开发思想。

分支故事1:第一次软件危机最典型的例子莫过于 IBM 的 System/360 的操作系统开发。佛瑞德·布鲁克斯(Frederick P. Brooks, Jr.)作为项目主管,率领 2000 多个程序员夜以继日的工作,共计花费了 5000 人一年的工作量,写出将近 100 万行的源码,总共投入 5 亿美元,是美国的“曼哈顿”原子弹计划投入的 1/4。尽管投入如此巨大,但项目进度却一再延迟,软件质量也得不到保障。布鲁克斯后来基于这个项目经验而总结的《人月神话》(The Mythical Man-Month)一书,成了史上最畅销的软件工程书籍。这本书也值得大家看看,银弹 就是书中提到的经典概念。(引用来源:程序设计思想发展 - 二十一岁的有德

分支故事2:实际上面向对象就是个形容词,那么这个词最早出现在哪里呢?最早大概1970年左右,已经提出了“面向对象系统”这个概念,面向对象系统有两层含义,第一,系统是由对象组成的;第二,对象之间可以互相发消息。从这个角度来讲这两点才是“面向对象”的第一义,后来的封装、继承、多态则是非第一义,或者称为最佳实践。(引用来源:面向对象编程的兴衰-InfoQ

说到这里,大家是不是有什么新想法啦!这个就是为什么大家现在编程和软件开发行业中,只剩下这些原则和模式,因为都是面向对象!详细的历史和资料可以参考查看:编程语言历史 - 维基百科,无法翻墙的可以看:程序设计思想发展 - 二十一岁的有德。这里就不深入描述了,大学时应该学习过,如果忘记了再重温一次吧!

软件开发基本概念

  • 面向过程编程(OPP:Procedure-Oriented Programming)
  • 结构化程序设计(Structured Programming)
  • 面向对象分析(OOA:Object-Oriented Analysis)
  • 面向对象设计(OOD:Object-Oriented Design)
  • 面向对象编程(OOP:Object-oriented Programming)
  • 面向切面编程(AOP:Aspect Oriented Programming)

以上就是软件开发概念一些概念,从历史上了解这些东西,对我们理解项目架构起了必要的作用。现在我们知道了为什么,是什么,软件开发直到现在,都是为了更好的编程!更好的开发!,所以我们理解了编程的历史,知道面对对象编程的重要性后,自然就需要知道有这些原则和模式,优秀的实践,来解决软件危机的银弹!

STUPID 原则

抱歉,你的代码就是那么的STUPID!烂代码有什么特点呢?没有人喜欢听到别人评价他的代码很愚蠢,而且这样做也很容易冒犯别人,所以不要说出来?平心而论:全世界中大部分代码都是不可维护的,因为它们都是乱糟糟一团的!

  • Singleton - 单态
  • Tightcoupling - 紧密耦合
  • Untestability - 不可测试
  • Premature Optimization - 过早优化
  • Indescriptive Naming - 胡乱命名
  • Duplication - 重复代码

本节内容来源:Don't be STUPID: GRASP SOLID!,中文译文:面向对象设计原则:不要STUPID - rcom10002的专栏

SOLID 原则

  1. 单一功能原则(The Single Responsibility Principle):对象功能要单一,不要在一个对象里添加很多功能。
  2. 开放封闭原则(The Open Closed Principle):扩展是开放的,修改是封闭的。
  3. 里氏替换原则(Liskov Substitution Principle):子类对象是可以替代基类对象的。(子类可以扩展父类的功能,但不能改变父类原有的功能。)
  4. 接口隔离原则(The Interface Segregation Principle):接口的用途要单一,不要在一个接口上根据不同入参实现多个功能。
  5. 依赖反转原则(The Dependency Inversion Principle):方法应该依赖抽象,不要依赖实例。iOS 开发就是高层业务方法依赖于协议。

SOLID 原则在前面已经讲解了由来,称为五大设计原则,但后来,又出现六大设计原则、七大设计原则,另外2个原则:

    1. 迪米特法则(Law of Demeter):一个对象对其他对象有尽可能少的了解,不和陌生人说话。
    1. 合成复用原则(CARP,Composition/Aggregate Reuse Principle,合成复用原则(组合/聚合复用原则)):将已有的对象纳入新对象中,使之成为新对象的一部分,作为新对象的成员对象来实现的,新对象可以调用已有对象的功能,从而达到复用。

所以,大家在网上如果看到 x条设计原则面向对象设计原则xxx时,大家是不是能更加理解这些编程思想,而不是看到一条一条的规则,学习怎么使用它们,但是并不清楚为什么要学习,这是学习最可怕的地方,这是我认为最可怕的。另外,这里强调设计原则(Principle),而非设计模式(Patterns),也是需要注意的点。

GRASP 原则

  1. 创造者模式 (Creator Pattern)
  2. 信息专家模式 (Information Expert Pattern)
  3. 低耦合模式 (Low Coupling Pattern)
  4. 高内聚模式 (High Cohesion Pattern)
  5. 控制器模式 (Controller Pattern)
  6. 多态模式 (Polymorphism Pattern)
  7. 纯虚构模式 (Pure Fabrication Pattern)
  8. 中介模式 (Indirection Pattern)
  9. 受保护变化模式 (Protected Variations Pattern)

GRASP (General Responsibility Assignment Software Principles,通用职责分配软件原则) 共有9种模式,这里也不细说了,大家自行搜索学习,如果需要可以购买书本 《UML和模式应用》(Applying UML and Patterns) 。

Design Patterns (设计模式)

  • 创建范例
  1. 抽象工厂 (Abstract Factory)
  2. 构造器 (Builder pattern)
  3. 工厂方法 (Factory Method pattern)
  4. 原型 (Prototype pattern)
  5. 单例模式 (Singleton pattern)
  • 结构范例
  1. 适配器(Adapter pattern)
  2. 桥接(Bridge pattern)
  3. 组合(Composite pattern)
  4. 装饰(Decorator pattern)
  5. 外观(Façade pattern)
  6. 享元(Flyweight pattern)
  7. 代理(Proxy pattern)
  • 行为范例
  1. 职责链(Chain-of-responsibility pattern)
  2. 命令(Command pattern)
  3. 翻译器(Interpreter pattern)
  4. 迭代器(Iterator pattern)
  5. 中介者(Mediator pattern)
  6. 回忆(Memento pattern)
  7. 观察者(Observer pattern)
  8. 状态机(State pattern)
  9. 策略(Strategy pattern)
  10. 模板方法(Template method pattern)
  11. 参观者(Visitor pattern)

设计模式中书 《设计模式:可复用面向对象软件的基础》(Design Patterns: Elements of Reusable Object-Oriented Software)把设计模式分为创建型模式、结构型模式、行为型模式,共有23种,可能后面大家又添加了一些,这里就不补充了,因为还是经典的23条已经很足啦!具体的模式意义大家自行搜索吧。

软件分层

  • 应用层
  • 中间层
  • 底层

一个项目系统模型,基础上都是至少3层,如果不够就多加一层呗!具体大家可以看看 GitHub 上的库和项目等,说到分层都是这样,这是为什么呢?举例来说,HTTPHTTPS,HTTPS 是再 HTTP 基础上加了一层 SSL/TLS,这样对原有的兼容性是最好的,也是最容易实现的,所以这就是分层的意义!我们的项目为什么分层,怎么分层,大家可以思考一下,多问一个为什么?

软件架构

  • MVC(Model-View-Controller)
  • MVP(Model-View-Presenter)
  • MVVM(Model-View-ViewModel)

从 MVC、MVP 到 MVVM,实际上是模型和视图的分离过程。MVC 中模型和视图没有完全分离,造成 Activity 代码臃肿,MVP 中通过 Presenter 来进行中转,模型和视图彻底分离,但由于 V 和 P 互相引用,代码不够优雅。ViewModel 通过 Data Binding 实现了视图和数据的绑定,解决了这种MVP的缺陷。

本节内容来源:MVC、MVP、MVVM架构分析与比较 - 简书

调度

  • URL/Protocol 注册调度
  • Runtime 调度

本文唯一与原文相关的可以就是这一节啦,原文中提到 CTMediator 库来架构 iOS 项目,具体的分析和细节这里就不讨论了,本文后面在做统一的回应吧。所以本节注意说 iOS调度的问题,原文中提到 CTMediator 的2个缺点:

  1. 直接硬编码的调用方式,参数是以string的方法保存在内存里,虽然和将参数保存在Text字段里占用的内存差不多,同时还可以避免.h文件的耦合,但是其对代码编写效率的降低也比较明显。
  2. 由于是在运行时才确定的调用方法,调用方式由 [obj method] 变成 [obj performSelector:@""]。这样的话,在调用时就缺少类型检查,是个很大的缺憾。因为,如果方法和参数比较多的时候,代码编写效率就会比较低。

避免.h文件的耦合 这个大家理解吗?在这个项目后,阿里开源了 BeeHive,基于 Protocol 注册调度,那么它的缺点是什么?就是这个 .h文件的声明 经常找不到,需要很多全局的变量。当然,任何架构都无法百分百完美!,更多问题欢迎留意交流。

代码质量

  • 可读性
  • 可维护性
  • 可拓展性
  • 必要注释?
  • commit规范
  • CodeReview

代码质量不是由开发人员里技术最强的人决定的,前面提到,如果代码很烂,那么很难维护,所以对于项目架构来说,代码质量也是必要关注的!

其它概念

  • DRY(Don’t Repeat Yourself! 不要重复你自己)
  • KISS(Keep It Simple, Stupid! 让事情简单化,傻瓜化) :翻译成中⽂就是“保持简单、愚蠢”。
  • Make it run, then make it right, then make it fast.(先求运行,再求正确,最后求快。)
  • 敏捷开发(Agile Development)
  • 奥卡姆剃刀(Occam's Razo)

例如“奥卡姆剃刀”,爱因斯坦的“一切尽可能简单”、达芬奇的“简单是最终的复杂性” 、安德鲁·圣艾修伯里的“完美不是当它不能再添加时,它似乎是在它不能被进一步刮除时实现的”。“如无必要,勿增实体”,即“简单有效原理”。大量的例子,都是希望在软件开发中,乔布斯的“简洁之道”,希望大家都可以平时多注意~

3、项目架构

大家是不是觉得说了那么多,感觉还是没有说明白项目架构?是的,基本架构就在里面,只是大家没有把它们串联起来,没有从整体上来理解。

上面说到的原则和模式,他们到底是在干嘛呢?不就是在架构嘛!对,这些原则和模型都是希望给项目提供更好的架构,最终目的还是提高开发效率!,敏捷开发就在其中!所以,当我们谈论架构时,就是在说项目的瓶颈在那里?怎么避免进度被拖拉,保持软件开发的顺利上线!

更高视角思考架构师

所以,明白了架构的目的,那么架构是不是必要的呢?如果是一个人的项目,架构是不是必要的呢?如果是5个人的团队项目,架构是不是必要的呢?如果是20个人的团队项目,架构是不是必要的呢?

如果是100个人的团队项目呢? 如果是500个人的团队项目呢? 如果是5000个人的团队项目呢? 如果是50000个人的团队项目呢?

在我看来,不管是多少人的项目,架构都是必要考虑的。当然,针对不同人数的项目,需要的架构必然也不一样!所以,当我们谈论架构时,请先确认项目的大小!,当然,项目的人员数量不可以固定不变,比如创业项目,不同阶段人员变化可能很大,这个时候,你问是不是一开始就需要做一个牛逼的基础架构?其实并不是!因为人员就是减少或增加,减少多少或增加多少,永远是无法评估的,所以最后的答案:万事开头难,只需要评估2~5倍人数,比如开始项目是5个人,那你项目架构就考虑最多10~25个人员的水平就差不多啦!最后,在需要的时候,需要一个牛逼的架构师!,没有解决不了的问题,所以也没有解决不了的架构。

最后,我们平时怎么思考架构?可以从下面3点开始关注:

  1. 现在架构是怎样的
  2. 哪些地方可以改进的
  3. 业界有哪些好的架构思想可以运用

4、总结

  1. 模块粒度应该如何划分?
  2. 为什么要分层?
  3. 如何分层?
  4. 多团队如何协作?

最后,回到本文一开始说的4个问题?现在你能自己想一下答案了吗?明白了吗?

彩蛋

随着时间的流逝,人们开始意识到,严格的面向对象方法会带来很多问题。这些问题往往会使代码更复杂、更难以理解且更难以测试。事实证明,OOP 更适合某些特定的问题领域。例如,OOP 仍然是构建用户界面(窗口和按钮)最自然的方式 。但是,试图将面向对象技术应用于关系数据库一直是一场灾难。

虽然面向对象并不是解决软件危机的银弹,但和面向过程相比,面向对象的思想更加贴近人类思维的特点,更加脱离机器思维,是一次软件设计思想上的飞跃。

引用自:面向对象编程的兴衰-InfoQ

很多人都喜欢跟团队中的其他成员争论某些代码到底属于哪种模式。,架构和模式是不是必要的呢?我认为我们开发过程中不要认为一定要用xx原则/xx模式一用到底!设计模式不是不用,是不能一味地用!。想一想,在1994年就能提出23种设计模式的概念!真的是大神!我想现在大多数人都不没有领悟其中或达到这样的思想深度,不由得心中自发地佩服!而现在很多流行的库都利用模式来架构,比如Spring,用的就是抽象工厂和工厂模式,回调函数用的是观察者模式,servlet中的filter使用的是chain of responsibility模式。最后,我想引用 GoF 书中最后一章的一句话:一般而言,了解 “做什么” 要比 “为什么” 来的容易;而一个模式的 “为什么” 就是它要解决的问题。

作为中国区,我们的软件工程行业确实与美国有一定的差距,从这些书籍和伟人就看出来,30年前美国作为计算机首发站,有先天的优势条件。而现在,我认为我们与美国的技术的底蕴还有较大差距,但是技术的高度,技术创新和新技术,我们是可以弯道超车。同时,作为一名普通的程序员,我认为大家积累足够的软件开发经验,也可以总结出更多的新的理论或模式,这也是我希望中国区未来能做的到,而不是 996 的业务到底,开发的效率不是通过加班提高,而应该通过技术的创新解决!

所以,我们要架构好自己的编程~


注:更多关于 iOS 开发和程序开发相关的内容,可以查看系列,目前还在连载中 【学习总结】iOS开发高手课 -- (连载中) | iHTCboy's blog,以上,希望对你有用!


注:更多关于 iOS 开发和程序开发相关的内容,可以查看系列,目前还在连载中 【学习总结】iOS开发高手课 -- (连载中) | iHTCboy's blog,以上,希望对你有用!

参考


  • 如有侵权,联系必删!
  • 如有不正确的地方,欢迎指导!
  • 如有疑问,欢迎在评论区一起讨论!

注:本文首发于 iHTCboy's blog,如若转载,请注来源