《软件设计哲学》随笔

第一章 介绍

         介绍背景:随着程序的发展和获得更多功能,它变得复杂,其组件之间具有微妙的依赖性。随着时间的流逝,复杂性不断累积,程序员在修改系统时将所有相关因素牢记在心中变得越来越难。这会减慢开发速度并导致错误,从而进一步延缓开发速度并增加成本。在任何程序的生命周期中,复杂性都会不可避免地增加。程序越大,工作的人越多,管理复杂性就越困难。

第二章 复杂度本质

2.1 复杂性的定义

        a、复杂性是开发人员在尝试实现特定目标时在特定时间点所经历的。它不一定与系统的整体大小或功能有关。

        b、系统的总体复杂度(C)由每个部分的复杂度(cp)乘以开发人员在该部分上花费的时间(tp)加权。

        c、读者比作家更容易理解复杂性。如果您编写了一段代码,对您来说似乎很简单,但是其他人则认为它很复杂,那么它就是复杂的。

2.2 复杂性的症状

        a、变更放大

      简单的变更需要在许多不同地方进行代码修改,简单事情的重复做。

        b、认知负荷

       这是指开发人员需要多少知识才能完成一项任务。

        系统设计人员有时会假设可以通过代码行来衡量复杂性,即代码行数越少复杂性越低,代码行数越高复杂性越高,但是这种观点忽略了认知负荷的成本。所以有时候需要更多行代码来减轻认知负荷。

        c、未知的未知

       复杂性的第三个症状是,必须修改哪些代码才能完成任务,或者开发人员必须获得哪些信息才能成功地执行任务,这些都是不明显的。

        在复杂性的三个症状中,未知的未知是最糟糕的,无法得知修改哪些东西可以完成任务,无法量化任务,也无法得知修改后会会不会遇到一些问题。

2.3 复杂性的原因

        a、各个部分的依赖关系,应该尽量减少依赖关系的数量,并使依赖关系保持尽可能简单和明显。

        b、晦涩,由于文档不足而导致模糊不清。一些通用变量和方法不为人所知。

2.4 复杂性是递增的

        复杂性不是由单个灾难性的错误导致的,而是随着时间推移成千上万的小依赖性和模糊性逐渐形成。

2.5 结论

        复杂性来自于依赖性和模糊性的积累。随着复杂性的增加,它会导致变化放大,高认知负荷和未知的未知数。结果,需要更多的代码修改才能实现每个新功能。此外,开发人员花费更多时间获取足够的信息以安全地进行更改,在最坏的情况下,他们甚至找不到所需的所有信息。最重要的是,复杂性使得修改现有代码库变得困难且冒险。

第三章 工作代码是不够的(战略与战术编程)

3.1 战术编程

        在战术编程中的主要重点就是完成某些功能(业务),特点就是周期短,几乎不会产生任何良好的系统设计,在开发中,只想尽快使某件事情生效,心里会告诉自己可以增加一些复杂度和小错误,为了尽快的完成自己的开发任务。

        这就是系统变得复杂的方式,如上面所述,复杂度是递增的。不是使系统复杂的特定事物,而是数十或数百个小事物的积累。如果您进行战术编程,每一个编程任务都会有折中的方案进行编程,复杂度就会快速累计。

        成为一名优秀的软件设计师的第一步就是意识到仅工作代码是不够的,引入不必要的复杂度来完成工作任务是不可接受的,最重要的是系统的长期结构,促进将来的扩展,所以代码不应该以”工作代码“未主要目标。主要目标是做出出色的代码设计,并且这种设计也会起到作用,这就是战略计划。

        战略计划需要一种投资心态,必须花时间研究实施代码的设计,这些投资短期内可能会让您放慢脚步,但从长远来看会加快速度。

如下图所示:

3.2 战略规划

        a、仅”工作代码“是不够的,引入更多的复杂度来完成任务是不可接受的,编码重要的是考虑扩展性,做好代码的设计。

        b、战略编码需要一种投资的心态,必须花费时间来改进系统的设计,而不是采用最快的方式来完成编码任务,这些投资短时间内会放慢脚步,长时间来说是会加快速度。

        c、无论前期投入多少时间设计,设计决策中都不可避免地会出现错误,随着时间的流逝,这些错误就会变得显而易见,如果进行战略编程,可以不断对系统进行小幅度调整,反之战术编程就会不断地增加复杂度,这些复杂度就会将来产生问题。

结论 

        好的设计不是免费的,需要不断的花费时间来迭代更新,需要不断的投资,这样小问题才不会累计成大问题,好的设计最终会收回成本,也会比想象中的早。

        当陷入危机的时候容易”延迟清理“,很容易是延迟永久化,等待解决的时间越长,问题就会越大。最有效的办法就是每位工程师都对良好的设计进行连续的少量投资。

第四章 模块应该是深的

        管理软件复杂性最重要的技术之一就是设计系统。以便于开发人员在任何时间只需要面对整体复杂性的一小部分。这种方法被称为模块设计。

4.1 模块化设计

       a、模块化设计理想化目标是每个模块单独绝对独立,但是这种理想化目标是实现不了的,模块之间通过调用方法来协同工作,所以模块化设计的最大目标就是最大程度的减少模块直接的相互依赖关系。

        b、为了管理模块直接依赖关系,模块通常分为接口、实现两个部分,接口包含其他使用者必须知道其内容才能使用的模块,接口描述模块做什么,而不描述模块如何做。实现则是实现接口定义的功能。

 4.2 接口是什么

        楼主的理解就是可以准确指示开发人员使用关联模块的功能的描述,在其他模块使用该模块的时候可以清晰的知道该模块抛出的功能。

4.3 抽象

       抽象是实体的简化视图,在抽象的定义中,“无关紧要”一词至关重要。从抽象中忽略的不重要的细节越多越好。抽象成简单的方法供外部调用。

4.4 深模块

        最好的模块很深:它们允许通过简单的接口访问许多功能。浅层模块是具有相对复杂的接口的模块,但功能不多:它不会掩盖太多的复杂性。

        模块提供的外部方法越简单,往往复杂性越小,暴露出复杂,功能性很多的方法反而不一定是最好的。

4.5 浅模块

        浅模块往往没有隐藏太多的实现细节,导致任何模块都能直接调用其内部方法,暴露出太多的实现细节,不利于其他模块理解,也不易于本模块的维护。

4.6 经典主义

        传统观点类应该多而不是深,导致大量浅模块,类应该是深的,而不是小的。

结论

        通过模块的设计,可以实现:

        a、把复杂的逻辑隐藏起来,使用模块的用户只需要了解抽象出来的简单的方法。

        b、逻辑内聚在模块内,更容易维护,更清晰与其他模块的依赖关系。


第五章 信息隐藏(和泄漏)

5.1 信息隐藏

        实现深模块最重要的技术就是信息隐藏,基本思想就是每个模块都应该封装一些知识,这些知识代表着设计决策。该知识嵌入在模块的实现中,其他模块不可见。

        信息隐藏的优点:在两个方面降低了复杂度。

        a、隐藏了大量细节减少了使用该模块的开发人员的认知负担。

        b、信息隐藏是系统更容易演化,即扩展性更强,如果隐藏了一段信息,那么其他模块就不存在对该信息的依赖,因此该信息相关的设计更改只会影响一个模块。

5.2 信息泄露

        信息隐藏的反面就是信息泄露,当一个设计决策反映在多个模块中时,就会发生信息泄露。导致模块之间建立了依赖关系,对该设计决策的任何更改都将需要对所有涉及的模块都要更改,如果一条信息反映在界面中,该信息已经泄露。

        即使信息没有出现在模块的界面中,也有可能会发生信息泄露,比如两个模块都具有处理相同格式的数据的方法,如果格式更改,则两个模块都需要更改。

        信息泄露是软件设计中最重要的危险信号之一 !!!

        如何重新组织信息泄露的模块:

        a、如果受影响的模块相对较小,且与泄露的信息紧密相关,那么合并到一个模块是有意义的

        b、从所有受影响的模块中提取信息,创建一个封装这些信息的模块。这种方法只有能够找到从细节中找到抽象方法才有效,如果新模块通过方法暴漏出大部分知识,那么这个模块不会提供太多的价值。

5.3 时间分解

        信息泄露的一个常见的原因就是时间分解的设计风格,在时间分解中,系统的结构对应操作的发生的时间顺序。

        顺序通常很重要,但是除非该结构与隐藏信息保持一致(不同阶段使用不同的信息),否则不应该将其反映在模块结构中,在设计模块时,应专注于执行每个任务所需要的知识,而不是任务发生的顺序。

        时间分解中,执行顺序反映在代码结构中,在不同的操作中使用相同的知识,则会在不同位置对其进行编码。从而导致信息泄露。

 5.4-5.9 为实例 可以去阅读原文

结论

        信息隐藏与深层模块密切相关,如果模块隐藏了很多信息,往往会增加模块提供的功能,同时还会减少其暴漏的方法。这使模块变得深,相反,如果一个模块没有隐藏太多信息,要么功能不多,要不接口复杂,无论哪种,模块都是浅的。

        系统分解模块时,尽量不要受操作顺序的影响,多考虑执行任务时所需的不同知识,这将产生带有深色模块的干净简单的设计。

第六章 通用模块更深入

        设计新模块的时候往往面临最普遍的问题就是以通用还是专用的方式来实现。

6.1 使类变得通用

        最有效的方法就是以某种通用的方式来实现新模块。通用方法的好处是 与专用方法对比更简单维护,扩展。

6.2-6.3 为实例 可以去阅读原文

6.4 通用性可以更好的隐藏信息

结论:通用方式往往更简单、使用的方法更少。模块之间分割更清晰,信息更容易隐藏,专用模式更容易信息泄露。

更新中。。。

此内容是楼主读《软件设计哲学》后的感悟与总结,如有异议可评论讨论。

        

        

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值