一、内容概述1.从抽象的工程设计理论的角度讲解如何写出好的代码。解释设计模式和设计原则的基本原则。2.解释设计模式和设计原则的适用场景和局限性。工程设计理论是在有限的设计能力下对设计对象进行认知和反演计算的过程。在不满足这个条件的地方,不要卡住设计模式和设计原则。在软件领域,一个明显的例子就是在极度注重性能的代码中不拘泥于设计模式和设计原则。3.解释为什么设计原则中的单一职责原则难以掌握和应用。4.面向接口设计是软件系统设计的最终形式,解释了开发过程中先写单例再开发的原因。二、理论基础1、哲学基础:罗素《哲学问题》。2、数学基础:矩阵论、工程控制论。3.工程基础:一定的工程设计经验,如代码开发等。4.设计的科学依据:《设计科学与设计竞争力》谢友白先生,南苏。3.什么是设计——设计与计算和认知之间的联系?建立一门科学,首先要明确学科的局限性,确定学科最基本的问题和框架。清晰的基本框架应该能够快速得出一门学科的基本结论和研究方法;明确的基本问题可以用来检验以上的结论和方法。指出自然界中每一杯水中都含有黄金,对促进金矿的发现作用不大。目前设计科学的发展应该做减法而不是加法。有许多关于设计特征的描述。这些描述最基本的共性是设计需要达到一定的目标(即需求)。其他功能不是设计的最基本功能。例如,优化设计没有需求变更,标志设计没有系统故障。如果就需求达成一致是设计的共同点,那么弄清楚需求是什么就很重要。大多数人认为在我们实际工作中,需求不明确、不完整。那么我们不妨用辩证的思维来考虑这个问题的反面。什么是清晰完整的需求?一个完整的需求大家都很清楚,不会产生任何不同的理解。那么应该清楚什么样的产品可以满足相应的需求。用集合论的术语来说,一个集合完全由它的外延决定。也就是说,如果需求能够通过单元测试等明确的验收方式来定义,那么需求就可以说是明确的、完整的。我们还需要进一步探讨什么是接受。以单元测试为例,我们使用单元测试输出一个True或者输出一个False;如果单元测试本身被认为是一个函数,那么验收就是要求设计对象在函数下的阶段必须为True。那么,如果我们的需求足够简单会怎样呢?比如我们的要求是找到一个满足x+1=0的x。我们一般称这类问题为解,或者逆运算。可见,当我们对需求及其实现方式有了清晰的认识后,需求就会退化为一个函数,设计就会退化为一个逆向计算的过程。在设计过程中,我们对需求和实现方式的理解并不全面,这是它区别于逆向??操作(而不是需求不明确或需求变化)的核心点。比如化工产品的合成路线设计,比如高效排序算法的设计,不存在需求不明确的问题。不完整的认知迫使我们在设计过程中认识需求及其实现方法,获取更多的知识,并进行逆向计算,以找到能够满足需求的实现方法。4.工程设计过程在工程设计过程中,我们总结了一套认知与计算交替过程的有效经验,即需求拆分与组合。刚才我们讲了需求,本质上是要求一个对象在某种功能下具有一定的特性,本质上是一种约束。而“设计的对象由A和B两部分组成,A有123个特征,B有456个特征”,这与需求的描述没有区别,本质上是一种约束。也就是说,拆分本身也是对设计对象的约束,但满足拆分约束的对象不一定满足需求约束。因此,我们不妨将拆分约束看成是对设计对象的弱约束。因此,工程设计可归纳为以下过程:1.根据需求的相关研究,给出弱约束的实现方法。我们一般采用拆分系统的方法来实现弱约束。在软件领域,最常见的弱约束是对组件划分的约束、组件之间的依赖关系、接口定义、数据交互方式的约束。(认知过程,我们一般称之为需求拆解和架构设计)。2.利用第一步中的弱约束分析解决需求中强约束的实现。(逆运算过程一般称为编码)。我们刚刚解释过分拆本质上是一种约束。第二步的求解结果可能还是对子系统的需求,此时需要继续进行更详细的设计。引入弱约束的概念是因为在对设计对象一无所知的情况下,研究如何达到相应的要求是比较困难的。那么我们不妨假设设计的对象具有某些属性(这种假设往往强烈依赖于个人经验),并以这些假设的属性(例如接口)作为研究如何实现它们的工具和框架。比如在代码设计中,拆分成A和B两个模块进行并行设计时,如果模块A的实现过程根本不知道模块B的信息,就会极大地阻碍模块A的设计(比如因为前端根本不知道后端的数据格式)。不过,模块B的具体实现方式尚未确定。此时模块A不可能完全了解模块B的信息,而且并不是模块B的每条信息都对其他模块有用(比如后端选择数据库格式,其中后端是部署,以及后端是如何实现的)。因此,我们需要通过折中的方式(比如指定接口)来限制B模块,让A模块获取必要的相关信息。学过认识论的同学应该也知道,这个界面本身就是模块B的一种认知(参考罗素的感官数据或者我在前言中提到的“关系”)。我想这就是依赖注入的底层逻辑,也是面向接口设计成为软件设计最终形式的底层基础。公式来描述上述过程,对于一个寻找满意的设计问题,我们将这个问题分为两步:1.将J(X)=0拆分为。2.根据的性质,求出使的具体值,例如;并同时研究,找出的具体形式,例如。在本例中,工程设计与科研后计算的最大区别在于第二步的具体实现过程是并行的。各个组件的并行实现在软件工程中很常见(前后端分开编码,最后进行调试)。当然,我们可以在充分研究J(X)的性质后进行设计。限制我们不这样做的条件不是这样得到的产品一定不能有效,而是设计所需的设计周期和人力是有限的。前端完全设计好之后,当然还可以设计后端,但是这种系列化的工作模式显然会对工期产生负面影响。为了使这种分离可行,需要引入独立负责的原则,以确保最终组装工作的顺利完成。在上一步中,我们的工作是并行完成的,这意味着我们不知道需要获取什么值。如果我们最终研究得到:.那么我们显然是找不到对应的解的。这就需要我们保证f({X})、g({X})、m({X})相互独立。我们进一步探讨分裂的独立性及其负面影响:1.强独立性:存在一个二元空间,其定义域为两个自变量组X,取值范围为自变量组X的函数融合函数U;使任意。2.独立性弱:对any。3.不独立:存在。对于强独立性,只要组合函数J和部分函数f、g的研究求解成功,设计就成功了。强独立性是指如果我们分别找到两个值,使得偏函数f和g的值得到我们想要的结果m和n;那么我们就可以找到一个综合的解决方案,让偏函数f和g同时得到我们想要的值。例如:。那么对于我们要求的f和g的任意值,我们都可以用它来保证。对于弱独立性,同时研究组合函数J和部分函数f、g可能会带来组合上的困难,但不会使设计完全失败。例如对于。对于任意的m,n,我们都可以找到它们来满足我们的需求(注意这里一般是研究组合函数J的同学对某些函数f,g提出详细的取值要求m,n)。由于研究和设计函数g的人可能事先并不知道,所以他们可能会设计路。因此,在这种情况下,需要后期的配合和调试才能完成整个设计。对于非独立性,同时研究组合函数J和部分函数f,g可能会使设计完全失败。例如。研究组合函数J的同学最后可能会得到答案,这显然是无解的。因此这次分裂可以说是失败的。该规则对应于软件领域的单一职责原则,被评论为更难应用和掌握(“单一职责原则是最简单但最难应用的原则”)。确实如此,我们接下来将探讨。换成看起来正确的模棱两可的表达方式,我们更容易找出问题出在哪里。声明是:独立的功能应该由独立的类来实现。那么,问题来了。我们如何判断两个函数之间的独立性?熟悉哲学,接触过哲学中关于“自由”的讨论的人,很快就会意识到,“自由”这个词一定是基于某种映射。说A和B是“免费的”是没有任何意义的。家庭教育和学校教育是独立的吗?德育和智育是独立的吗?不同的角度会有不同的答案。在时间上,家庭教育与学校教育相互独立;在评分标准上,德育与智育也是相互独立的。如果把教育也看作是一种设计,是把教育分为家庭教育和学校教育,还是分为德育和智育?划分的依据应该是什么?显而易见的是,我们可以接受的判断函数之间相互独立的基础应该是在实现方法上相互独立。那么上面这句话可以改写为:实现上独立的函数应该独立实现。这有点像政治正确的胡说八道,其具体应用很大程度上取决于设计者之前在相关领域的经验和判断。没有相关领域的经验,职能划分难免会出现一些搞笑的结果。这就是为什么单一职责原则是最简单也是最困难的原则。五、总结与局限设计是在需求认知不完全的情况下,解决设计对象的过程。这迫使我们在了解设计对象的同时解决问题。为了并行地进行这个过程,并且为了对设计对象的理解有一个初步的研究工具和基础,我们总结了一组使用拆分的弱约束,并在此拆分的基础上进行不同的并行性出去。组件之间的设计流程。依赖倒置和面向接口的设计是必须的,因为解耦只能提供一个较弱的设计视图。为了最终组装并行设计,需要单一职责原则(独立原则)。可见,整个设计理论必须建立在需求认知不完整,需要低成本(首先是时间成本)完成设计的前提下。设计理论不适用于设计周期比较长、认知足够的领域。只用设计模式来衡量设计的好坏是不可取的。这方面有很多反例。恐怕LeetCode中的以上题目都不符合设计模式。比如在链表的倒数第k个节点中寻找双指针就是一个典型的例子。对于人体来说,并没有遵循单一职责原则,甚至可以说耦合度不尽相同。人饿的时候,可以分解蛋白质来供给能量;在飞机设计过程中,我们考虑过当液压油泄漏时,用燃油作为液压油?一些经典设计不遵循设计理论和原则。例如,活塞环不仅可以防止漏气,还可以减少摩擦和磨损。这显然不符合独立公理。只有深入研究设计科学的底层逻辑,这门科学才能真正发挥作用。虽然本文在该领域尽可能做了一些减法运算,省略了一些非核心要素,但无论是在理论上还是在实例上都无法提供一个真正可以验证为正确或错误的想法或命题。这篇文章连错都没有,反正不尽如人意。附件6——使用split设计系统的例子设计领域的很多例子都是一些已有的设计;或者设计一个完全没有市场需求的产品。这种先射箭再画靶子的行为,并不能促进科学的发展。所以,找一个大家比较熟悉的领域,比较难解决,但是需求明确的问题作为例子来讨论。幸运的是,我确实解决了我问自己的问题。在机械领域,平面杆机构的设计是最基本的问题。比如下图中的四杆机构,我们经常会进行摆角设计等工作。那么,在没有恒速电机和平面构件的情况下,是否可以使平面构件上的某一点具有指定的轨迹呢?比如用平面成员画兔子?对于这个问题,我们整理一下已知的知识,给出一些弱约束:1.对于某个平面杆群机构,其上任一点的位置是一个随时间变化的周期函数。我们可以将其表示为复数域上的函数,即:。2、由匀速电机驱动的杆(活动部分)的终点轨迹是一个圆,这个圆的运动规律与其他杆无关。3、非恒速电机驱动的杆(从动件)运动轨迹由主动元件的运动轨迹及其与主动元件的连杆决定。然后,我们通过拆分给出另一个弱约束来解决这个问题:A.最终设计的平面杆组由活动部分和一些连接组组成。这些连接组应该有两个自由端点,并且连接组上的一点在运动过程中始终是这两个自由端点的中点,即。在这样的弱约束下,我们的问题就变成了:1.如何通过一些圆周运动和建立在其上的加法系统来拟合任何周期运动。2、如何找到满足以上条件的连接组。问题一的答案由傅里叶变换给出:。第二个问题可以用下面的杆组来解决,旋转关节2永远是旋转关节1、3的中点:最后的设计,我用了16个活动部件,16个连接组,一共80根杆,得到的结果如上图所示。老实说,我觉得这个例子在说明弱约束和强约束以及拆分对于工程设计的必要性方面,还是很难摆脱先射箭后画靶的嫌疑。但至少,我不认为我设计的机制是解决这个问题的最优方案;我觉得这个问题足以说明工程设计得不到最好的设计。
