前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >每个程序员都应学习的编程原则

每个程序员都应学习的编程原则

作者头像
用户8554325
发布2023-03-10 20:03:15
3110
发布2023-03-10 20:03:15
举报
文章被收录于专栏:热度技术

在这里像是“炒冷饭”的翻出这些编码原则,并不是博取眼球之类,只是工作多年,回过头来思考和看现在的程序猿写的代码,确实会觉得:在这个浮躁的IT开发环境里,大家都忘了初心,忘了是为了赚钱还是为了热爱编程这一行的了。在此,这篇也只是献给真正热爱编程的程序猿,真心想通过基础来升华自己编码技巧的程序猿。

学习这些并不是为了面试和装逼,如果你在掌握了这些,可能会让你面试和装逼的时候更有底气(气质这方面要拿捏的死死的哈)

下面,我们就要说说当前编程里有的原则,当然可能有些编程原则已经不适用于现在的环境,所以就不会再啰嗦,有些原则也只能适用某一些方面,比如专注于OOP编程理论设计、一些注重具体的编码技巧指导等等。

通用原则

不要重复自己(DRY - Don’t repeat yourself)

这大概是编程最基本的原则。也由此产生了很多编程的概念(比如循环,函数,类,等等)。一旦我们开始重复自己,就应该考虑做一下抽象了。

这一点好理解,想想自己项目中碰到一些复用的组件:字符串工具类、Apache Httpclient等等类库。

抽象原则(Abstraction Principle)

抽象原则也和 DRY 原则有关,“程序中的每段核心功能代码应该只在源代码中的一个地方实现”。

保持简单(KISS Keep it simple, stupid!)

代码简洁是一个很重要的目标,写简洁的代码耗费的时间更少、bug 更少、更易于修改。

封装经常修改的代码(Refactor)

一个好的设计可以辨别出最有可能改变的热点,并将它们封装在API之后。当预期的修改发生时,修改会保持在局部。

为什么,在发生更改时,最小化所需的修改。

怎么做,封装API背后不同的概念。将可能不同的概念分到各自的模块。

别超前编程,Avoid Creating a YAGNI (You aren’t going to need it)

如果某个功能你还用不到,就不要去实现它。

低耦合(Minimize Coupling)

代码的任何部分(代码块,函数,类等等)都应该减少对其他部分代码的依赖,要尽量减少变量共享。“低耦合通常是结构优秀的计算机系统和好的设计的标志,配合高内聚,就能实现高可读和易维护的目标”。

高内聚(Maximize Cohesion)

实现一个功能相关的代码,都应在同一个模块中实现。

隐藏实现细节(Hide Implementation Details)

隐藏实现细节,当内部逻辑修改时,能够减少对其他使用者的影响。

避免过度优化(Avoid Premature Optimization)

代码还在正常工作的时候不必考虑优化,除非运行速度不及预期,并且最好在有量化数据对比的前提下进行。“我们应忽略小的影响,大约97%的情况下:过度优化是万恶之源” -- Donald Knuth。

代码复用(Code Reuse is Good)

代码复用可以提高代码可用性并减少开发时间。

拥抱变化(Embrace Change)

这是 Kent Beck 一本书的子题目,也是极限编程和敏捷开发的一个宗旨。很多其他的原则都是基于期望并拥抱变化的初心,一些传统的软件工程原则比如“低耦合”都有利于更简单的修改代码。不管你是不是极限编程爱好者,这个原则对写代码都很有帮助。

减少误导(Principle of least astonishment)

这个原则通常在接口上被提到,但在代码里也很重要,代码不应该误导阅读者。注释的说明要和代码一致,函数名要和函数内容一致,要避免迷惑和误导。

面向对象七大基本原则

在运用面向对象的思想进行软件设计时,需要遵循的原则一共有7个这些我们在进行一个需求分析到落地开发的时候,都是需要拿出来细细考虑的。别等重构的时候才想起,原来当时的设计没遵循xx原则,导致现在加入新特性别扭或者要推到重来。

1. 单一职责原则(Single Responsibility Principle)

每一个类应该专注于做一件事情。

2. 里氏替换原则(Liskov Substitution Principle)

超类存在的地方,子类是可以替换的。

3. 依赖倒置原则(Dependence Inversion Principle)

实现尽量依赖抽象,不依赖具体实现。

4. 接口隔离原则(Interface Segregation Principle)

应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。

5. 迪米特法则(Law Of Demeter)

又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。

6. 开闭原则(Open Close Principle)

面向扩展开放,面向修改关闭。

7. 组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)

尽量使用合成/聚合达到复用,尽量少用继承。原则:一个类中有另一个类的对象。

第一职责(Single Responsibility Principle,SRP)

一个类不应该有多个修改的原因。每个类都应该有一个单独的职责,并且该职责应该完全由该类封装。职责可以定义为修改的原因,一次类或模块应该有且仅有一个修改的原因。提高类的可读性,提高系统的可维护性;变更引起的风险降低,变更时必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的修改。

需要说明的一点是单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。

为什么

可维护性:仅有一个模块或类中需要修改。

怎么做

使用 科里定律(科里定律是关于为任何特定代码选择一个明确定义的目标:仅做一件事。)

里氏替换原则(Liskov Substitution Principle)

程序中的对象应该可以替换为其子类型的实例,而不会改变该程序的正确性。

详细解释:

里氏替换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。里氏替换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。

使用里氏替换原则时需要注意,子类的所有方法必须在父类中声明,或子类必须实现父类中声明的所有方法。尽量把父类设计为抽象类或者接口,让子类继承父类或实现父接口,并实现在父类中声明的方法,运行时,子类实例替换父类实例,我们可以很方便地扩展系统的功能,同时无须修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现。

依赖倒置原则(Dependence Inversion Principle)

具体依赖抽象,上层依赖下层。假设B是较A低的模块,但B需要使用到A的功能,这个时候,B不应当直接使用A中的具体类;而应当由B定义一抽象接口,并由A来实现这个抽象接口,B只使用这个抽象接口;这样就达到了依赖倒置的目的,B也解除了对A的依赖,反过来是A依赖于B定义的抽象接口。通过上层模块难以避免依赖下层模块,假如B也直接依赖A的实现,那么就可能造成循环依赖。

采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,减少并行开发引起的风险,提高代码的可读性和可维护性。

从大局看Java的多态就属于这个原则。

接口隔离原则(Interface Segregation Principle)

因为:

提供尽可能小的单独接口,而不要提供大的总接口。暴露行为让后面的实现类知道的越少越好。譬如类ProgramMonkey通过接口CodeInterface依赖类CodeC,类ProgramMaster通过接口CodeInterface依赖类CodeAndroid,如果接口CodeInterface对于类ProgramMonkey和类CodeC来说不是最小接口,则类CodeC和类CodeAndroid必须去实现他们不需要的方法。将臃肿的接口CodeInterface拆分为独立的几个接口,类ProgramMonkey和类ProgramMaster分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则。

所以:

建立单一接口,不要建立庞大的接口,尽量细化接口,接口中的方法尽量少。也就是要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。依赖几个专用的接口要比依赖一个综合的接口更灵活。接口是设计时对外部设定的约定,通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。

从大局来说Java的接口可以实现多继承就是接口隔离原则的基础保障。

迪米特法则(Law Of Demeter)

因为:

类与类之间的关系越密切,耦合度也就越来越大,只有尽量降低类与类之间的耦合才符合设计模式;对于被依赖的类来说,无论逻辑多复杂都要尽量封装在类的内部;每个对象都会与其他对象有耦合关系,我们称出现成员变量、方法参数、方法返回值中的类为直接的耦合依赖,而出现在局部变量中的类则不是直接耦合依赖,也就是说,不是直接耦合依赖的类最好不要作为局部变量的形式出现在类的内部。

所以:

一个对象对另一个对象知道的越少越好,即一个软件实体应当尽可能少的与其他实体发生相互作用,在一个类里能少用多少其他类就少用多少,尤其是局部变量的依赖类,能省略尽量省略。同时如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一方法的话,可以通过第三者转发这个调用。

从大局来说Android App开发中的多Fragment与依赖的Activity间交互通信遵守了这一法则。

开闭原则(Open Close Principle)

因为:

开放封闭原则主要体现在对扩展开放、对修改封闭,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。软件需求总是变化的,世界上没有一个软件的是不变的,因此对软件设计人员来说,必须在不需要对原有系统进行修改的情况下,实现灵活的系统扩展。

所以:

可以通过Template Method模式和Strategy模式进行重构,实现对修改封闭,对扩展开放的设计思路。

封装变化,是实现开放封闭原则的重要手段,对于经常发生变化的状态,一般将其封装为一个抽象,拒绝滥用抽象,只将经常变化的部分进行抽象。

组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)

因为:

其实整个设计模式就是在讲如何类与类之间的组合/聚合。在一个新的对象里面通过关联关系(包括组合关系和聚合关系)使用一些已有的对象,使之成为新对象的一部分,新对象通过委派调用已有对象的方法达到复用其已有功能的目的。也就是,要尽量使用类的合成复用,尽量不要使用继承。

如果为了复用,便使用继承的方式将两个不相干的类联系在一起,违反里氏代换原则,哪是生搬硬套,忽略了继承了缺点。继承复用破坏数据封装性,将基类的实现细节全部暴露给了派生类,基类的内部细节常常对派生类是透明的,白箱复用;虽然简单,但不安全,不能在程序的运行过程中随便改变;基类的实现发生了改变,派生类的实现也不得不改变;从基类继承而来的派生类是静态的,不可能在运行时间内发生改变,因此没有足够的灵活性。

所以:

组合/聚合复用原则可以使系统更加灵活,类与类之间的耦合度降低,一个类的变化对其他类造成的影响相对较少,因此一般首选使用组合/聚合来实现复用;其次才考虑继承,在使用继承时,需要严格遵循里氏代换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及系统的复杂度,因此需要慎重使用继承复用。

编程多年经验积累的原则

从事开发多年,总会有自己的经验,积累下来就是相当于知道自己开发和带新人的一些原则了。这里可以给大家说说,一些开发多年积累下来的原则一本有哪些可以当做“原则”来指导自己日后的编码。

做事莫要纠结开发工具

不管是库、编程语言、开发平台、开发工具等。尽可能用当前社区发展的方向上的工具框架库之类,不要因为那一门语言牛逼、哪一个框架牛逼就走“剑走偏锋”。这样会让团队或者自己付出沉重的代价。我们选择的时候,要为解决的问题选择合适的工具(语言、平台)。不要歪曲技术、也不要歪曲了问题的本身。正时问题当前所处的环境和限制约束。

代码要时刻记住:代码是写给人看的(未来的同事或未来的自己)

不要给同事和未来的自己找麻烦,为了一时之爽(或者一时怄气),写下难以捉摸的代码,要多考虑一下初级开发者,会接手你代码的同事,他们会把你的代码作为参考。

不要把自己与代码捆绑在一起,要想办法让其他人也能修改你的代码或者添加新的功能,这样你才能更容易脱身去参与其他项目,或者去其他公司。不要捆绑自己,否则你很难成长。

分而治之

为分离的关注点开发单独的低耦合模块。进行单独的模块测试和集成测试。尽可能按照实际情况测试,同时也要测试到各种边界情况。

寻找解决方案,需要有优先级

在寻找解决方案时,请按照这样的优先级进行决策:安全性>可用性(可访问性和用户体验)>可维护性>简单性(开发者体验)>简洁性(代码量)>性能。但不能盲目照搬,而是要根据产品的特点进行取舍。你积累的经验越多,就越是能够在这些因素之间做出权衡。例如,在设计游戏引擎时,性能享有最高的优先级,但在开发银行应用程序时,安全性则最为重要。

写代码的时候要不仅要考虑正常代码,也要处理好异常的代码

让人们明白为什么会发生异常、如何检测到的以及怎样解决。对所有的系统输入(包括用户输入)进行验证:尽早失败,并尽可能从错误中恢复。我们要假设用户手里握着一把枪:你努力让用户输入一些其他的东西,而不是让他们的子弹射在你的脑门上。

没有彻底了解过问题,不要急着写代码

花在倾听和了解问题上的时间通常比花在写代码上的时间要多。在写代码之前要先了解问题域。问题就像迷宫一样,你要循序渐进,反复进行“编码 - 测试 - 改进”,直到把问题解决为止。

不要浪费公司请的需求(产品经理),有疑问必须了解清楚,别一说就自己已经知道了,每一种业务可能总的方面是一样,但落地的业务总会有一点不太一样。

不要尝试去解决不存在的问题

不要进行投机性编程。只有在确定代码确实需要具备扩展性之后才让代码具备可扩展性。通常情况下,当代码被扩展之后,你会发现问题会变得与原先认为的不一样了。

总结

以上所列都是原理性,如何结合到实际编码中,还是需要各位多思考,灵活应用,别为了用而用,这样会导致你的代码或者设计都很僵硬。个人比较认可的一点:在理解系统和这些原理之后,随着自己对系统的深入认识和了解,进行架构设计,同时回过头根据原则思考一下;不断重复这一步,如果实际和理论有出入,可以先根据实际的情况作出取舍,不用严格遵守,但别脱离原则的目标:都为了好的设计和架构,要懂得根据实际情况进行取舍,如果硬要遵守原则要付出极大成本,就别盲目遵守了,产出和投入始终都很真实!

每个开发都想成为大牛,但大牛不仅仅是表面看到的做了很多牛逼的系统(神马高并发、高性能等等),也是因为他们本身就比其他开发人员积累更多的深厚的基础知识(操作系统、编译原理、设计模式、数据结构算法等等)。

划重点:从现在开始就是最好的开始,不要纠结别人领先你多少时间,而是要看自己从现在开始付出了多少时间!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-11-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 聊聊电商业务与技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 通用原则
    • 不要重复自己(DRY - Don’t repeat yourself)
      • 抽象原则(Abstraction Principle)
        • 保持简单(KISS ,Keep it simple, stupid!)
          • 封装经常修改的代码(Refactor)
            • 别超前编程,Avoid Creating a YAGNI (You aren’t going to need it)
              • 低耦合(Minimize Coupling)
                • 高内聚(Maximize Cohesion)
                  • 隐藏实现细节(Hide Implementation Details)
                    • 避免过度优化(Avoid Premature Optimization)
                      • 代码复用(Code Reuse is Good)
                        • 拥抱变化(Embrace Change)
                          • 减少误导(Principle of least astonishment)
                          • 面向对象七大基本原则
                            • 第一职责(Single Responsibility Principle,SRP)
                              • 里氏替换原则(Liskov Substitution Principle)
                                • 依赖倒置原则(Dependence Inversion Principle)
                                  • 接口隔离原则(Interface Segregation Principle)
                                    • 迪米特法则(Law Of Demeter)
                                      • 开闭原则(Open Close Principle)
                                        • 组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)
                                        • 编程多年经验积累的原则
                                          • 做事莫要纠结开发工具
                                            • 代码要时刻记住:代码是写给人看的(未来的同事或未来的自己)
                                              • 分而治之
                                                • 寻找解决方案,需要有优先级
                                                  • 写代码的时候要不仅要考虑正常代码,也要处理好异常的代码
                                                    • 没有彻底了解过问题,不要急着写代码
                                                      • 不要尝试去解决不存在的问题
                                                      • 总结
                                                      相关产品与服务
                                                      项目管理
                                                      CODING 项目管理(CODING Project Management,CODING-PM)工具包含迭代管理、需求管理、任务管理、缺陷管理、文件/wiki 等功能,适用于研发团队进行项目管理或敏捷开发实践。结合敏捷研发理念,帮助您对产品进行迭代规划,让每个迭代中的需求、任务、缺陷无障碍沟通流转, 让项目开发过程风险可控,达到可持续性快速迭代。
                                                      领券
                                                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档