<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>programming | Liao Lile</title>
    <link>https://liaolile.com/tag/programming/</link>
      <atom:link href="https://liaolile.com/tag/programming/index.xml" rel="self" type="application/rss+xml" />
    <description>programming</description>
    <generator>Wowchemy (https://wowchemy.com)</generator><language>zh-Hans</language><lastBuildDate>Fri, 18 Mar 2022 22:15:10 +0000</lastBuildDate>
    <image>
      <url>https://liaolile.com/media/icon_hu0b7a4cb9992c9ac0e91bd28ffd38dd00_9727_512x512_fill_lanczos_center_3.png</url>
      <title>programming</title>
      <link>https://liaolile.com/tag/programming/</link>
    </image>
    
    <item>
      <title>编程原则</title>
      <link>https://liaolile.com/post/tech/base/%E7%BC%96%E7%A8%8B%E5%8E%9F%E5%88%99/</link>
      <pubDate>Fri, 18 Mar 2022 22:15:10 +0000</pubDate>
      <guid>https://liaolile.com/post/tech/base/%E7%BC%96%E7%A8%8B%E5%8E%9F%E5%88%99/</guid>
      <description>&lt;p&gt;[toc]&lt;/p&gt;
&lt;p&gt;有目的的努力方向，才是正确的方向。而编程原则就是抽象于各种编程语言而来的思想，为的就是写下那隽永留千年的代码，因为最经典、最基础的一些思想总是源远流长的！&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;代码发布后故障不断。&lt;/p&gt;
&lt;p&gt;多时之后再看自己的代码，已经不能再忍受，重构。&lt;/p&gt;
&lt;p&gt;修改一行代码，整个程序都崩溃了。&lt;/p&gt;
&lt;p&gt;我的新功能应该在什么地方加入呢？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;系统最本质的内容，我们往往理解的不够，所以出现了很多矛盾和纠结。为啥不深入研究下软件中最基本的内容并且沉淀呢，面对这个最复杂的东西探析清楚，知其所以然。这就是本篇的内容。&lt;/p&gt;
&lt;h3 id=&#34;0-准确定义&#34;&gt;0 准确定义&lt;/h3&gt;
&lt;h4 id=&#34;01-软件&#34;&gt;0.1 软件&lt;/h4&gt;
&lt;p&gt;编程的产物也就是“软件”。我们常说的系统、工具、应用、平台等均是编程的产物，均归类为软件。&lt;/p&gt;
&lt;h4 id=&#34;02-代码&#34;&gt;0.2 代码&lt;/h4&gt;
&lt;p&gt;编程中编写的东西统称为“代码”，包括源代码、程序、源程序等均为代码。&lt;/p&gt;
&lt;h4 id=&#34;03-编程&#34;&gt;0.3 编程&lt;/h4&gt;
&lt;p&gt;编写代码这件事或行为，我们就叫“编程”；也有叫编码、Coding、开发、实现等，均用编程指代。&lt;/p&gt;
&lt;h4 id=&#34;04-程序员&#34;&gt;0.4 程序员&lt;/h4&gt;
&lt;p&gt;负责编程的人统一称作“程序员”，根据不同的场景也区分为开发者、开发人员、软件工程师、程序猿。&lt;/p&gt;
&lt;h4 id=&#34;05-函数&#34;&gt;0.5 函数&lt;/h4&gt;
&lt;p&gt;可供调用的代码块也就是“函数”，还能细化为功能、过程、方法、成员函数等；往往词语指代东西并不一致，功能是有返回值，而过程是无返回值。&lt;/p&gt;
&lt;h4 id=&#34;06-模块&#34;&gt;0.6 模块&lt;/h4&gt;
&lt;p&gt;函数和变量的组合单元可以称为“模块”。包括更多的概念都可以提供如此的组合概念，如类、文件、库、组件、部件等，代表的是关联性较强的代码集合。&lt;/p&gt;
&lt;h4 id=&#34;07-软件架构&#34;&gt;0.7 软件架构&lt;/h4&gt;
&lt;p&gt;软件的整体结构就是“软件架构”，高于模块一层来看整个软件的整体内容，聚焦模块间的交互。&lt;/p&gt;
&lt;h3 id=&#34;1-永恒的真理&#34;&gt;1 永恒的真理&lt;/h3&gt;
&lt;h4 id=&#34;11-no-silver-bullet&#34;&gt;1.1 No Silver Bullet&lt;/h4&gt;
&lt;p&gt;银弹是用来镇住狼人的唯一方法，那就是将银弹射入狼人的体内。软件编程中没有万能解决方案，没有特效药。如果有，软件就是一件简单的事情。&lt;/p&gt;
&lt;p&gt;软件是复杂的，千万行代码的软件比比皆是，而软件要素之间的依赖关系是动态的剪不断、理还乱。软件比其他任何构造物都复杂。&lt;/p&gt;
&lt;p&gt;软件是实时的，需要响应当下的状态，与硬件、网络、人的行为、其它软件等均相关联，这种实时是一种生命的不断向前，如果没有，那就没有软件的价值。&lt;/p&gt;
&lt;p&gt;软件是可变的，软件的生命在于它与现实世界的交互，双方处于螺旋而上升的变化状态中；现实世界因为软件的进步而更美好，更美好的现实世界驱动软件的进步；&lt;/p&gt;
&lt;p&gt;软件是不可见的，是现实生活中概念的虚实映射，进程是没法看见的，对概念的表达是肉眼看不见的东西，对世界是抽象的表达，舍象的呈现，无法全部表现。&lt;/p&gt;
&lt;p&gt;本质，是定义上无法舍去的东西，不可欠缺的性质。非本质是指次要的、附属的性质，不能最终影响事物本质的。&lt;/p&gt;
&lt;p&gt;而软件在本质上具有难度，归因就是软件具有复杂性。通过各种方法和思路，来降低复杂性给软件带来的影响。围绕软件的构建、环境、编程语言、库、框架等都是软件的非本质部分，而非本质的部分对于推进软件本质部分内容具有巨大的贡献，而往往非本质部分能够得到更简单的解决，间接降低软件整体的复杂度 。&lt;/p&gt;
&lt;p&gt;非本质部分的自动化可以大幅改善工作效率和工作质量，而目前对于软件本质来说，需要通过自动化非本质部分而腾出更多的时间给到软件本质，软件真正的价值上。这个和当前的云原生的理念是不谋而合！&lt;/p&gt;
&lt;h4 id=&#34;12-代码即设计文档&#34;&gt;1.2 代码即设计文档&lt;/h4&gt;
&lt;p&gt;软件最终交付的有价值的内容除了代码，别无其它。而编程就是一个设计过程，只不过设计的是代码，而不是文档。产品的性能无法在制造和生产环境得到提升，能够得到提升的过程就是设计过程。不管是哪个环节，最终设计必须使用编程语言来表现，这个过程中编程语言才是最核心的设计要素。&lt;/p&gt;
&lt;p&gt;基本设计、详细设计等上游不应该偏离编程语言，因为编程、调测、测试等下游均是基于编程语言。所以如何端到端的打通整个过程，才是设计的初衷。设计需要创造力，编程就是一种创造行为，与其把不依赖编程语言的设计图翻译为代码，倒不如一开始让设计者编写代码来的省心。代码就是属于设计范畴，应该尽早的开始编写代码。&lt;/p&gt;
&lt;p&gt;代码是设计文档，并不代表代码是唯一文档。代码表达了“怎么做”和“是什么”，代码不能表达为什么这么做。而设计理由需要有地方承载。对于代码中的注释可以承担部分，注释需要弥补代码表达不出来的东西。另一方面，对代码进行说明的注释就是重复，应该避免这点。&lt;/p&gt;
&lt;p&gt;罗塞塔石碑&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;的文档，这是一份写个未来维护负责人的简单手册，描述了理解软件开发环境和软件架构的信息，描述构建和测试过程的执行方法，而其中的测试可以避免维护负责人理解的陷阱，在架构方面描述纵观全部代码的图表。&lt;/p&gt;
&lt;h4 id=&#34;13-一定会被修改的代码&#34;&gt;1.3 一定会被修改的代码&lt;/h4&gt;
&lt;p&gt;代码如果不被修改，那软件的生命周期已经趋于死亡。“代码会被修改”是既定事实标准，我们做选择和判断时候优先考虑的事情。软件产生故障，需要修复；软件的新需求，需要新增；不管是修复还是新增，都是对软件的修改，软件必须迎合变化，没有一开始就能满足所有诉求的软件。&lt;/p&gt;
&lt;p&gt;需要编写经得起修改的代码，这个过程中代码的“可读”尤为重要。不管写代码需要耗费多少时间，只要读代码的时间能够缩短，那么我们就能够把消耗在写代码上的时间赚回来。要相信这点！&lt;/p&gt;
&lt;h3 id=&#34;2-正确的指导方针&#34;&gt;2 正确的指导方针&lt;/h3&gt;
&lt;h4 id=&#34;21-kiss-keep-it-short--simple&#34;&gt;2.1 KISS (Keep it short &amp;amp; simple)&lt;/h4&gt;
&lt;p&gt;保持简洁，容易理解，易于修改和使用。必不可少的最小集是什么，还能否做减法？功能简洁，接口简洁。奥卡姆剃刀，当一个事物存在多种解释时，最简单的哪个解释时正确的，减轻思考的负担、增强可读可理解，最后可敏捷修改。&lt;/p&gt;
&lt;h4 id=&#34;22-dry-dont-repeat-yourself&#34;&gt;2.2 DRY (Don&amp;rsquo;t repeat yourself)&lt;/h4&gt;
&lt;p&gt;禁止重复的拷贝。发现重复应该立即予以消除，避免重复这点没有商量余地。重复的代码可读性下降、难以修改且分散多处测试困难。一定程度上的代码抽象化操作可以消除重复。逻辑执行抽象，就是给整个处理过程命名，将其函数化、模块化。对于数据的重复，需要定义常量来替换；对应的重复内容有了名称，提升了可读性。&lt;/p&gt;
&lt;p&gt;对于自动化作业对软件进行测试、构建和发布的持续集成也是消除重复，消除重复的手动作业，提升自动化水平。对于设计模式是一种防止重复思考的手法。&lt;/p&gt;
&lt;p&gt;WET, Write every time， Write everything twice重复同样的事情，正好也是DRY的反义词。&lt;/p&gt;
&lt;p&gt;对于数据库而言，不应该存储重复的数据，one fact only in one place；&lt;/p&gt;
&lt;h4 id=&#34;23-yagni-you-arent-going-to-need-it&#34;&gt;2.3 YAGNI (You aren&amp;rsquo;t going to need it)&lt;/h4&gt;
&lt;p&gt;不用想太多，坚持只写当前需要的代码。比追求通用性，而复杂设计更应该重视单纯性，能用是第一位的，聚焦具体需求为基础的简单方案。&lt;/p&gt;
&lt;p&gt;想的太远只会增加代码的复杂度，提高修改的成本。所以编码的时候，要思考回到原点，保持纯粹的单纯简单，以代码阅读者的角度做些思考。&lt;/p&gt;
&lt;h4 id=&#34;24-pie-program-intently--expressively&#34;&gt;2.4 PIE (Program intently &amp;amp; expressively)&lt;/h4&gt;
&lt;p&gt;编码更多要在表达上花心思，将软件运行方式直观地传达给阅读代码的人。代码是我们正确、完整地理解软件运行方式的唯一线索。代码是动态变更的，任何的文档都是跟不上的，因而编写可读性高的代码，用代码表达意图是唯一可取的方法。&lt;/p&gt;
&lt;p&gt;读代码的次数远多于写代码的次数，所以追求的是代码可读性而不是代码的易写性。代码只写一次，但是多次阅读，读代码的效率应优先于写代码的效率和执行代码的效率。&lt;/p&gt;
&lt;p&gt;表达意图的终极形态是&lt;code&gt;文学编程&lt;/code&gt;，将代码本身当作文档的编程方法，用于描述文档的语言和编程语言结合在一起。代码即文档，文档即代码。代码要表达作品的意图，并且要有自我说明的能力。&lt;/p&gt;
&lt;h4 id=&#34;25-slap-single-level-of-abstraction-principle&#34;&gt;2.5 SLAP (Single level of abstraction principle)&lt;/h4&gt;
&lt;p&gt;抽象是分等级的，根据功能的复杂程度对象化概念进行分离，然后统一各层的抽象级别。统一各抽象级别之后，代码就可以像图书一样供人阅读。&lt;/p&gt;
&lt;p&gt;将代码分成级别统一的函数，能使代码具有概括性和可读性。函数一览起到目录作用，使代码拥有概括性。分割后的函数时小块代码，提升了代码的可读性。抽象度相同的处理在同一个地方，代码更加顺畅更加可读。函数结构化之后，各函数处理以调用比自己低一个级别的函数为中心。这种由其他函数调用组成的函数称为复合函数，符合函数要尽量小，如果想通过名称来表达意图，即使处理只有一行，也可以写成函数。&lt;/p&gt;
&lt;p&gt;面向对象中，容器时抽象类及其继承类。抽象类存放抽象级别较高的概念，继承类存放级别较低的概念。设计结构和编写内容时两件事情，需要独立的模式去实现。&lt;/p&gt;
&lt;h4 id=&#34;26-ocp-open--closed-principle&#34;&gt;2.6 OCP (Open &amp;amp; closed principle)&lt;/h4&gt;
&lt;p&gt;代码需要满足对扩展开发，对修改关闭的属性。扩展开放表示代码的行为可以扩展，修改关闭表示对代码进行行为扩展时，其他代码完成不会受到影响。&lt;/p&gt;
&lt;p&gt;面向对象的多态是实现OCP的代表技术，领域模型是稳定的，识别系统中的稳定成分和不稳定部分，在这两部分之间通过稳定的接口将交界点包裹起来。受保护变化则使用这层接口防护墙将变更带来的影响抵御在外。&lt;/p&gt;
&lt;h4 id=&#34;27-naming-naming-is-important&#34;&gt;2.7 Naming (Naming is important)&lt;/h4&gt;
&lt;p&gt;命名，一个合适的名字意味着元素被正确理解并正确地设计了出来。一个合适的名字表示设计已经完成了一大半。意图传达地核心概念就是命名，让人充分理解某个东西是怎么样做出来的，所以需要最大限度地在名字上下功夫。&lt;/p&gt;
&lt;p&gt;编码的时候并不是向读代码才去读的，在充分理解代码之后的修改或添加功能才是我们真正的目的。在读代码时，混乱的名字会占用所有的脑部资源，让编码困难。&lt;/p&gt;
&lt;p&gt;名字要能够搜索出来，不能是单个字母或数字，要避免常见的搜索在代码中产生无数个结果。名字要能够念出来，需要在团队中统一概念，传播给各个角色这些概念，大家在理解上是一致的。名字应该是基于标准术语来命名，避免大家心里映射才能理解元素表达的意思。&lt;/p&gt;
&lt;h3 id=&#34;3-unix思想&#34;&gt;3 UNIX思想&lt;/h3&gt;
&lt;p&gt;UNIX是被认为是大量经验的结晶，是编写优秀代码的实用性技术集合。所以在这会讲明白其蕴涵的思想是什么，以及怎么做，而不去分析为什么，因为这就是历史的沉淀，一些约定俗成的规定，被证明是正确的，得到全世界开发者的赞同，并不断的完善。&lt;/p&gt;
&lt;p&gt;对我有些触发内容的点是，3.9 表达性原则和3.17 可扩展性原则。&lt;/p&gt;
&lt;h4 id=&#34;31-模块化原则&#34;&gt;3.1 模块化原则&lt;/h4&gt;
&lt;p&gt;代码中关联性较强的元素聚集在一起就是模块，模块接口要简单明了，而不要冗余繁杂，最少和最小的接口提供最简练的功能。&lt;/p&gt;
&lt;p&gt;多个简单模块组装成软件，而每次修改都把影响控制在模块内。&lt;/p&gt;
&lt;h4 id=&#34;32-清晰原则&#34;&gt;3.2 清晰原则&lt;/h4&gt;
&lt;p&gt;代码不应该复杂，应该清晰，便于理解。在读代码时，不要对难以读懂的部分再三解读。第一次需要解读可能那个时因为碰巧没看懂，如果第二次还需要解读，那就需要小重构了。此时可以添加注释解释为什么，或者把代码修改的更加容易理解。&lt;/p&gt;
&lt;h4 id=&#34;33-组合原则&#34;&gt;3.3 组合原则&lt;/h4&gt;
&lt;p&gt;软件应该尽量做成一个简单的过滤器，接受某种数据流后，加工输出另一种数据流的软件。这种输入输出应该是简单明了的。通过不同的软件组合方式，就能够完成多种多样的任务。&lt;/p&gt;
&lt;h4 id=&#34;34-分离原则&#34;&gt;3.4 分离原则&lt;/h4&gt;
&lt;p&gt;是常说的领域模型，因为每个领域内沉淀的内容是稳定的。同时为机制编写有效的测试代码，机制的寿命比较长，同时独立的机制是可以被其他软件重复使用的。&lt;/p&gt;
&lt;h4 id=&#34;35-简单原则&#34;&gt;3.5 简单原则&lt;/h4&gt;
&lt;p&gt;代码设计的足够简单，只能规定只在必要的情况下添加复杂代码。团队间应该营造简单即美丽的文化氛围。&lt;/p&gt;
&lt;h4 id=&#34;36-简约原则&#34;&gt;3.6 简约原则&lt;/h4&gt;
&lt;p&gt;简约和简单不同在于不写大代码，一方面指代码量大，也指代码复杂指数大。要吝啬，尽量少写，让代码维持小的状态。随着代码的添加而变大，就要尽快对代码进行分割。&lt;/p&gt;
&lt;h4 id=&#34;37-透明性原则&#34;&gt;3.7 透明性原则&lt;/h4&gt;
&lt;p&gt;设计软件时，要从外部清楚看到软件的运行状态，不仅让软件正确运行，还要让人能够看到它是在正确地运行。软件需要一眼就能理解软件正在做什么和软件是怎么做地，同时要呈现并监控其内部状态。正式地代码中加入能够简化调试地机制是一件好事，需要认真对待。这是对于系统可观测能力地提升。&lt;/p&gt;
&lt;h4 id=&#34;38-健壮性原则&#34;&gt;3.8 健壮性原则&lt;/h4&gt;
&lt;p&gt;软件不仅能在一般条件下正常运行，还能再预想之外地条件下提供适当地服务。要想代码具有健壮性，需要保证人们能轻松识别其内部结构。&lt;/p&gt;
&lt;h4 id=&#34;39-表达性原则&#34;&gt;3.9 表达性原则&lt;/h4&gt;
&lt;p&gt;代码中地信息要尽量用数据而非逻辑来表达。将信息固定在数据一侧，可以提高逻辑地可读性和健壮性。数据不论多么复杂都能轻松地模型化，用数据来表达信息也更加简单。使用换算表地数组初始化语句与switch语句相比，数据结构一方面更容易理解。&lt;/p&gt;
&lt;p&gt;我们应当把代码中无法避免的复杂部分交给数据表示。当遇到数据和逻辑必须要有一个复杂化的情况时，毫不犹豫选择的是让数据复杂化。这也就是我们的领域模型，通过模型上的数据来承担过程逻辑。&lt;/p&gt;
&lt;h4 id=&#34;310-最小意外原则&#34;&gt;3.10 最小意外原则&lt;/h4&gt;
&lt;p&gt;接口的设计尽量不要让使用者感到意外，让接口运行符合用户的预期。对于一些约定俗成的东西，我们去遵循就好了，我们往往希望看到熟悉的东西就是自己熟知的东西，而不是还需要一层映射才能理解。当然有时候场景的区分需要通过不同来显示区分，比如get从一个模块获取数据，而fetch用以表示获取远程模块的数据。这个fetch和git中的概念就是保持一致的。&lt;/p&gt;
&lt;h4 id=&#34;311-沉默原则&#34;&gt;3.11 沉默原则&lt;/h4&gt;
&lt;p&gt;软件应该将希纳是的内容控制在最少的程度，除非遇到必须提醒的情况。只输出重要的信息，内部运行的信息不要参杂其中。对于错误发生时只将真正错误的部分作为标准错误输出，不输出所需范围之外的任何数据。对于调试而需要的信息，可以通过一个冗余模式的开关，默认让其处于关闭状态。&lt;/p&gt;
&lt;h4 id=&#34;312-修复原则&#34;&gt;3.12 修复原则&lt;/h4&gt;
&lt;p&gt;软件运行过程中，出现错误且修复失败，就应该立即停止处理，同时还应该有明显的提示。对修复失败情况下继续处理，就会出现最坏的结果，故障可能在不知不觉中破坏所有的数据。&lt;/p&gt;
&lt;p&gt;软件在发生错误时应尽早让人立刻知晓，软件在无法自行修复的时候，需要把控制权交给用户进行判断，这点很重要。&lt;/p&gt;
&lt;h4 id=&#34;313-经济原则&#34;&gt;3.13 经济原则&lt;/h4&gt;
&lt;p&gt;程序员的时间时宝贵资源，值得珍惜。任何浪费程序员的时间都是不经济的。&lt;/p&gt;
&lt;h4 id=&#34;314-生成原则&#34;&gt;3.14 生成原则&lt;/h4&gt;
&lt;p&gt;生成原则指编写用于生成代码的代码，减少手动操作，编写用于生成代码地代码。只在优先的范围内生成代码也是很有效果的，重复的、形式固定的代码尤其适合由代码生成器生成。&lt;/p&gt;
&lt;h4 id=&#34;315-优化原则&#34;&gt;3.15 优化原则&lt;/h4&gt;
&lt;p&gt;在代码优化之前，先要保证代码能够正常运行。代码尚且不能充分运行阶段，对细节进行打磨是一种吃力不讨好的做法。先要确保代码正确运行，再去追求所谓的运行速度，确保足够的简单。代码越简单，可优化的地方就越容易被找到。&lt;/p&gt;
&lt;h4 id=&#34;316-多样性原则&#34;&gt;3.16 多样性原则&lt;/h4&gt;
&lt;p&gt;容许存在多种方法，在软件中没有唯一正确的方法。我们不能相信任何宣传软件开发存在唯一正确方法的言论。应该认可多样性，调动思维，不断寻找更好的方案。&lt;/p&gt;
&lt;h4 id=&#34;317-可扩展性原则&#34;&gt;3.17 可扩展性原则&lt;/h4&gt;
&lt;p&gt;通过代码可扩展，代码能满足多样的需求。可以采用可插拔的设计，对于扩展可插拔接口部分，要采用灵活的设计，并且在代码一旁加上“如果需要xxx”的注释。另外，可扩展性并不是添加非必要的功能，而是要编写能在需要的时候轻松添加相应功能的代码。&lt;/p&gt;
&lt;p&gt;可扩展性同样适用于数据格式，要让数据格式具有自我描述和可扩展性。让数据格式由几个独立的自我描述部分组成能够取得更好的效果，而不依赖顺序，甚至依赖其他数据。这样做的好处，可以在不搞混所读取的代码的前提下添加新的部分和删除旧的部分。&lt;/p&gt;
&lt;h3 id=&#34;ref&#34;&gt;REF&lt;/h3&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://baike.baidu.com/item/%e7%bd%97%e5%a1%9e%e5%a1%94%e7%9f%b3%e7%a2%91/34799?fr=aladdin&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;罗塞塔石碑（古埃及托勒密王朝著名石碑）_百度百科 (baidu.com)&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
  </channel>
</rss>
