如何保持系统的整洁

自顶向下设计

当我们开发或者重构一个软件系统时,需要进行很多框架、中间件上的选型。这些选型的粒度有大有小,解决其中一种或几种系统问题。而我们正是通过将这些框架、中间件进行搭配、组合来完成一个系统的骨骼。

如果把软件系统开发比喻成建造一个城市的话,那么对框架与中间件的选择,则对应各种城市的各种职能设施与其建设的配置。我们需要评估我们的需求,然后选择在最合适的位置上摆放最合适的设施,从而用最低的代价满足我们的需求。

城市不是只有市长一个人管理,它有职责上的划分:教育、医疗、交通;也有地域上的划分:区、街道。城市需要在不同的维度中由专人负责,然后依次向下管理。与城市一样,系统中我们也不可能直接由负责人全权负责所有细节,我们会将系统进行各种程度的抽象,将其划分为不同的模块,让其放入到我们选择的框架并用各种中间件进行串联。

如果这种设计是从最宏观的开始设计的话,我们就将其称为自顶向下设计。在自顶向下设计时,我们要关注系统的核心问题,通过框架、中间件、核心代码解决完核心问题后,便是对系统模块进行层级划分,最后才是编码进行具体业务的实现。

我们将模块根据不同的规模进行划分,同时也将人员根据模块的划分情况进行安排,从而完成了软件团队中的分工。这样做的好处便是,开发人员只需要处理当前分层中的业务就可以完成工作。相反,如果层级之间出现交织,就需要开发者们了解跨越层级的内容,而导致所有人需要掌握的细节变多,开发效率就会变低。

所以,我们需要一些手段来保证这样分层的整洁,让自顶向下的分层设计可以发挥最好的效果。

运行态分离

尽管系统项目的启动过程十分的重要,但与按天、月为单位运行的系统运行时间来比,系统的启动过程就不那么重要了。主要是对于启动的过程,我们往往会投入更多的关注,确保启动完成。相比之下,我们更期待程序的运行状态可以稳定地运行。

对于使用Spring框架的后端开发人员来说,Spring已经通过了各种的手段对启动状态进行分离:例如Application上的启动注解、Spring-boot相应的自动装配能力、以及对于Autoware或者Resource的依赖注入等。一方面我们要理解Spring已经很大程度的帮助我们将注意力从启动状态与运行状态分离了,另一方面我们更不应该破坏这种分离状态。

举一个比较常见的例子就是延迟加载。我们可能会通过一个初始值为null的变量来进行延迟加载,当我们需要的时候才对这数据进行创建,同时在重复使用的时候可以直接使用,而不会重复创建。也可以说这是懒加载的单例模式。

延迟加载有其自身的用途,但是会引入新的问题:将初始化代码和程序运行代码耦合在了一起。而这样直接引来的问题就是我们很难对其进行单元测试(用mock类进行替换)。以及很难确定当出现问题的时候,所有这样的代码处于什么状态。

对应的解决办法就是将这种耦合进行分离,利用诸如抽象工厂类、或者Spring的@Lazy注解来实现。这样我们可以通过直接替换测试用的工厂类或者关闭@Lazy来让程序变得可测试。

统一抽象

我们在实际开发过程中总会有如下需求:对所有指定前缀名称的Service都开启事务、对所有接口调用都打印参数日志。如今,我们很容易就能想到可以使用AOP来实现这样的需求,但是我们经常忽略这个做法背后的思想:对模块的统一抽象。

由于我们对模块之间进行了分层,我们可以以经典的三层模型来举例。假设当我们在编写Controller层的,当我们希望对我们的下游调用的所有入口进行入参日志的输出,那我们可以有三种处理方式:

  1. 在Controller调用前打印

  2. 在Service进入后打印

  3. 在出Controller与进入Service之间

但不论我们是在Controller中还是在Service中执行,我们都需要在所有实际出发代码的时候增加新的逻辑。而如果我们选择在Controller与Service之间进行功能的增加,我们就可以将这部分逻辑剥离到两层业务逻辑之外,放到编程框架层面的,而这种方法就需要我们对模块进行统一抽象。

前面说了一种AOP的实现方式,其中我们一般是通过注解或者包路径来描述处理对象,除AOP外常用的还有Java代理类的方式(尽管Spring本身就包含大量代理)。

统一抽象的主要目的在于,将所有一层级的模块抽象成一个概念,就可以统一为其增加功能,从而使得下层逻辑不用特别的对该功能进行关心。事实上,对于可以进行统一抽象的模块功能,它极大概率是不与下层逻辑耦合的,所以即便我们没有对其进行统一的抽象,也应将它们分离出来然后单独的维护。

所以,Aop和代理类只是为了达到统一抽象目的一种实现手段。

延迟决策

显然,在系统的构建时,所有的功能都应该是经过了设计之后再实施的。但我们很难再一开始就将所有的决策确认完毕。一般来说,如果我们需要进行决策时需要收集到足够的信息,例如:根据具体的TPS值确认是否要增加数据缓存。但如果当前的信息、预备知识不足以支撑我们对问题进行的决策,我们可以延迟我们决策的时间。

延迟决策的优点在于,你可以在你获得了足够的信息后,再进行正确性更高的、更有效的决策,这是你可能有更多的用户反馈、或者更完整的测试数据用来对你的决策进行支撑。

在具体的决策前,我们可以先根据“业界方案”来进行设置,因为这样的好处是可能存在更多的相关经验人员,同时出现问题可能有更多的解决方案。

而为了系统能支持延迟决策,我们需要系统进行模块化设计,并已经基于切面地进行了统一抽象设计。这样才能让我们拥有足够的知识后,具备进行决策的时机后,可以快速地进行业务调整。

最后

系统设计中的耦合危害,比方法层级和类层级更加严重。我们是希望系统具备敏捷能力的,这会让我们在多变的业务中快速进行调整。如果系统开始上下层级耦合,则会让测试变得困难、重构没有保证,直接结果就是生产力降低。本文讨论了三种主要的注意点,让系统在层级上保持抽象,让系统具备单独设计模块,最大程度上简化方案的可能性。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容

  • 一、整洁代码 A.混乱的代价 1.有些团队在项目初期进展迅速,但有那么一两年的时间却慢去蜗行。对代码的每次修改都影...
    ZyBlog阅读 2,024评论 0 2
  • 整洁代码 Leblanc : Later equals never.(勒布朗法则:稍后等于永不) 对代码的每次修改...
    foever_f1eb阅读 795评论 0 0
  • 命名 类名:名词或名词短语;避免使用Manager、Processor、Data、Info之类的类名 方法名:动词...
    MocktioY阅读 583评论 0 0
  • @[TOC](代码整洁之道Clean Code笔记) 在线阅读:书栈网:https://www.bookstack...
    好奇新阅读 281评论 0 0
  • 海到无边天作岸,山登绝顶我为峰。作为猿类的我们,对自己创造的代码有着一种天生的无比自信。这是好事~可是,对于我们的...
    独钓寒江雪_520阅读 1,007评论 0 0