您当前的位置: 首页 >  架构

阿里云云栖号

暂无认证

  • 0浏览

    0关注

    5305博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

从业务开发中学习和理解架构设计

阿里云云栖号 发布时间:2022-07-25 13:37:11 ,浏览量:0

前言

在软件开发领域经常会接触到架构这个词汇,在我最初的印象中,架构是一个很高级的词汇。它似乎代表了复杂的工程结构、高层次的抽象设计、最新的开发语言特性等等。对于当时只专注于写业务逻辑的我来说,不免心生对架构的敬畏。工作中对架构的讨论很少,出现则是一些高级晦涩的描述,但是从来没有人清楚地解释过架构做了哪些事。所以,架构到底是什么?架构和业务之间是什么关系?

当我们看一些关于架构的书籍或者资料,不免会接触到一些对架构的定义或者描述。比如:约束、规则、边界、实体关系、模型定义等等。但是懂得这些概念并不能帮助我们设计出来更好的架构,当我们套用设计原则进行架构设计时,不免会觉得空洞乏味,总觉得少了点什么。虽然我们为架构设计做了很多事,但是似乎什么也没做。因为只针对架构设计本身来说,很难说清楚它所产生的价值。所以,好的架构设计的出发点是什么?好的架构应该是什么样的呢?

去年我有一个任务:将我们当前工程的代码进行重新的拆分和组合,以厘清模块间的关系,控制工程中模块依赖的复杂度。这看起来是一个很简单的工作,找到一个不同于当前的且更合理的目录划分方案,就可以尝试落地实施。但是这又是一个很困难的工作,因为我们首先要回答有哪些模块、模块间是什么依赖关系的问题。其实,回到任务的本身,我们并不是只想对代码文件进行重新的组织和划分,我们的目标是业务模块解耦合,定义并明确业务模块间的依赖规则。面对这样的目标,我们需要首先从业务视角更清晰地定义和划分模块,然后从工程结构视角确定模块间的关系。所以,代码目录调整实际上是一个对业务场景、工程结构理解和设计的问题。代码目录的结构代表了我们的工程结构,也是业务场景划分的抽象描述,更是模块定义以及模块依赖关系的展现。

在设计代码目录划分方案的过程中,看了一些工程结构设计的资料,读了一些关于架构设计的书。对于架构有了一些理解。本文是对这段学习和任务完成过程的思考和沉淀。我希望能够回答上面提到的几个问题:

  1. 架构到底是什么?架构和业务之间的关系
  2. 好的架构的设计出发点是什么?好的架构应该是什么样的
什么是架构 架构的定义

首先架构是一个汉语词汇。它的定义是:人们对一个结构内的元素及元素间关系的一种主观映射的产物。从这个定义可以看出,传统的架构在描述一个系统中有什么元素,以及元素之间关系。在建筑领域,架构也用于描述建筑物的结构。 作为一个计算机领域的词汇,架构的定义是:有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计。实际上也在定义有什么以及关系的问题。

从工程化解读架构设计的作用

无论是在建筑领域还是计算机领域,我们通常会用工程描述这类工作的项目。比如我所在的部门是工程技术中心,我是一个工程类的程序员等。我们可以称之为工程的工作项目包括:建筑工程、军事工程、水利工程、生物工程、软件工程等。而我们在完成项目的过程中,进行架构设计实际上就是推进实施工程化的一部分。那么进行工程架构设计会考虑哪些因素,它对实施工程化的作用是什么呢?

假设,读者你现在是一位建筑工程师,负责建造一栋房屋。

虽然我们没有真正的盖过房子,但是在进行房屋的整体结构设计时,你一定会关心这些:

  1. 房屋用途。首先要明确这栋房子是干什么用的
  2. 房屋层数。和用途紧密相关,不同用途的房子层数也是不一样的
  3. 房屋外观。定义这栋房屋应该长什么样
  4. 房屋的布局。定义这栋房屋应该怎么更好地被使用

等等。我们称上面这几个属性是房屋的基础能力。作为一个靠谱的建筑工程师,你一定还会着重地设计这些:

  1. 水电走向。这很重要。保证房屋的安全性和使用的便捷
  2. 承重和抗压。房屋的使用寿命很大程度上依赖于此

等等。我们称上面的这几个属性是安全性和性能。

另外一方面,你大概不会关心房屋的装修风格、地板颜色、衣柜品牌等等因素。我们称这些为应用细节。

总结来说,进行房屋的工程架构设计时更多地关系底层设计,而不在乎过多的技术细节。

所以,我们可以给架构的作用下一个定义:在明确用途的基础上定义使用的规则和约束,提供了基础的支撑能力,并保障安全性、性能和使用周期。

软件架构设计的原则和要求

到目前为止,我们已经明确了在做架构设计时必须遵循的前提和原则:明确用途。此外也对架构设计提出要求:提供基础能力、保障安全性、性能等。

同样的,引申到计算机领域。当我们进行软件架构设计时也必须遵循的原则有:

1、架构设计一定要从业务场景出发

这实际上就是明确用途的大前提。架构设计一定是要从业务出发、面向业务变化的。只有在我们明确了我们的业务场景和业务目标后,在此基础上进行的架构设计才是能真正产生业务价值的。一个脱离了业务场景而设计的架构,无论多么新颖和高级,也绝不是一个好的架构。

2、架构设计一定要落到业务场景中去验证

我们不能只从基础能力、安全性或者性能方面去评判一个架构的好坏。架构对业务开发的支持能力,面向业务变化时的灵活度以及持续演进能力等都是评判的因素。 此外,我们要求软件架构必须是灵活的,能够满足未来业务持续发展的要求。

业务场景是不断变化的,架构也要具有跟随业务形态不断演进的能力。架构设计的核心是保证面向业务变化时有足够灵活的响应力,这要求架构设计能够识别到业务的核心领域。所以,无论是面向当前还是面向未来,架构设计都需要真正地识别和理解业务问题。

架构设计的原则

本章节介绍几个软件架构设计时可以遵循的原则,实际上在进行功能模块设计也可以参考这些设计原则。

SRP 单一职责原则
  1. 一个函数只负责完成一个功能
  2. 任何一个模块只对某一类行为者负责
  3. 一个类或者函数应该有且仅有一个被改变的理由

在实际的编码中,我们还是可以看到很多违反单一职责的例子的,比如超长的函数体。一个函数内做了很多事,实际上就是负责了太多的功能,很多的变更都要修改这个函数,这导致很难控制变更影响的范围。

我们可以将大函数拆分成小函数,小函数体负责的功能更加单一,相应的也会更加灵活。所以我们建议大家多写一些小的函数体。但是不要在函数拆分的过程中进行过度的封装和抽象。

OCP 开闭原则
  1. 易于扩展,抗拒修改

模块要易于扩展,控制修改。这是我们在初学编程语言时就会被教育到的设计原则。开闭原则帮助我们设计更加灵活的模块,同时还能控制模块变更的影响范围。

LSP 里氏替换原则
  1. 所有引用父类的地方都可以替换成子类,而行为不发生改变

使用里氏替换原则可以保证父类的复用性。它主要是用来判断抽象和继承关系设计是否合理,即某个类是否应该具有某个属性,以及一个类到底是不是另外一个类的子类。

举一个典型的例子,乘马是乘马,乘白马也是乘马,乘黑马也是乘马。那么白马和黑马就是马的子类,是符合LSP的。

下面是两个典型的违反LSP原则的例子。也是网上也特别常见的例子。

第一个是正方形不是矩形。

class Rectangle {
 public:
     int32_t getWidth() const {return width;}
     int32_t getHeight() const {return height;}

     virtual void setWidth(int32_t w) {
         width = w;
     }
     virtual void setHeight(int32_t h) {
       height = h;
    }
private:
    int32_t width = 0;
    int32_t height = 0;

};
class Square : public Rectangle {
 public:
     void setWidth(int32_t w) override {
         Rectangle::setWidth(w);
         Rectangle::setHeight(w);
     }
     void setHeight(int32_t h) override {
          // …
     }
 };
void reSize(Rectangle rect) {
     while (rect.getHeight()             
关注
打赏
1664438436
查看更多评论
0.0832s