发布于 2026-01-06 5 阅读
0

实际发展实践

实际发展实践

几天前,我不得不查一下SOLID原则是什么。我大学时学过吗?然后,我看到了里氏替换原则,开始拼命回忆多年前计算机科学课上的内容。

恐慌和压力消退后,我决定整理思路,写下我认为的基本“实用”原则及其应用。

接下来,我们将撰写一篇更侧重于“代码”的文章,探讨实用的前端原则。

一切皆有可能

编写代码时,开发人员必须考虑以下因素:他们所在的组织、他们合作的团队,以及他们试图解决的一般性和具体问题。没有任何原则或实践适用于所有情况或场景。

  • 代码是否正确?
  • 如何编写可测试的代码?
  • 如何编写简洁、优质的代码?

KISS(保持简单,笨蛋)

这条原则可以应用于我们生活的方方面面。然而,除了最简单的编程项目之外,它在其他所有项目中都是必不可少的。

项目范围界定阶段就应该开始着手简化。当范围足够简化后,再进一步简化;范围蔓延不可避免,所以要尽可能从小处着手。

即使开发已经开始,也要保持代码简洁。复杂的代码设计和编写起来更费时,更容易出现错误和漏洞。此外,日后修改复杂的代码也更加困难。

记住,完美不是无所增益的时候,而是无所删减的时候。

请勿重复

这是软件开发中的一项原则,旨在处理代码重复(针对代码中重复出现的模式),用抽象或数据规范化来代替重复代码,从而避免冗余。

DRY 原则指出,“系统中的每一项知识都必须有单一、明确且权威的表示形式”。当 DRY 原则得到成功应用时,对系统中任何单个元素的修改都不需要更改其他逻辑上不相关的元素。此外,逻辑上相关的元素都会以可预测且一致的方式进行更改,从而保持同步。

YAGNI(你不需要它)

这意味着“不要解决你没有遇到的问题”。

YAGNI(You Agents In No In,你不需要它)的第一个论点是,即使我们假定某个功能是必要的,但我们很可能错了。毕竟,敏捷方法的核心就在于接受需求会发生变化。

编写简洁的代码,而不是巧妙的代码。

大多数开发者都喜欢耍小聪明。事实上,他们当初选择这个行业很可能就是因为喜欢耍小聪明。开发者喜欢编写简洁高效的代码,这些代码运行速度远超人们的预期,同时又让所有阅读代码的人感到困惑。

问题在于,开发领域正在飞速变化。几年前就开始发生的根本性转变如今已然稳固。这种转变体现在软件的复杂性已经从应用程序的各个组成部分转移到了应用程序的整体设计上。因此,几乎所有代码的首要任务都应该是提高代码的可读性和可写性,因为它们所处的系统已经变得极其复杂。

但作为开发者,这些规则同样适用。我们不再会因为编写一个解析速度提升 5% 的例程而获得赞誉,尤其是在它使代码更难读、编写时间更长、调试时间更长或测试难度更大的情况下。这种优化(在大多数情况下)只是毫无意义的徒劳之举,通常只是为了满足开发者的虚荣心。

SOLID 原则

单一职责原则

软件实体(类、模块、函数等)应该只负责软件功能的某一部分,并且该责任应该完全由类来封装。

开闭原理

软件实体应该对扩展开放,但对修改关闭”;[1]也就是说,这样的实体可以允许扩展其行为而不修改其源代码。

里氏替换原则

该原则规定,超类的对象可以被其子类的对象替换,而不会破坏应用程序。这意味着子类的对象必须与超类的对象表现一致。

子类的重写方法必须接受与父类方法相同的输入参数值。这意味着代码可以实现较为宽松的验证规则,但不能在子类中强制执行更严格的验证规则。否则,如果使用子类对象调用父类对象的该方法,则可能会引发异常。

方法的返回值也适用类似的规则。子类方法的返回值需要遵循与父类方法返回值相同的规则。

  • 方法签名必须匹配(必须接受相同的参数)。
  • 任何方法的前提条件都不能大于其父方法的前提条件。
  • 任何继承的方法都不应该有更多会改变该方法返回值的条件语句,例如抛出异常。
  • 后置条件必须至少与其父级条件相同。
  • 继承的方法应该返回与其父方法相同的类型。
  • 异常类型必须匹配
  • 如果一个方法被设计为在发生错误时返回特定的异常,那么继承的方法中的相同条件也必须返回相同的异常。

界面隔离原理

任何客户端都不应该被迫依赖它不使用的方法。过于庞大的接口应该拆分成更小、更具体的接口,这样客户端只需要了解它们感兴趣的方法即可。这一原则旨在保持系统解耦,从而更易于重构、修改和重新部署。

依赖倒置原理

遵循这一原则,以往从高层策略设定模块到底层依赖模块的依赖关系将被颠倒,从而使高层模块独立于底层模块的实现细节。该原则指出:

  • 高层模块不应该依赖于底层模块。两者都应该依赖于抽象概念(例如接口)。
  • 抽象概念不应依赖于细节,细节(具体实现)应依赖于抽象概念。

关注点分离

模块化设计原则是指将计算机程序划分为不同的模块,使每个模块处理不同的关注点。关注点是指影响计算机程序代码的一组信息。能够很好地体现这一原则的代码被称为模块化程序。模块化,也就是关注点分离,是通过将信息封装在一个具有明确接口的代码模块中来实现的。

关注点分离使得程序在设计、部署或使用方面拥有更大的自由度。其中常见的是代码简化和维护的自由度更高。当关注点分离良好时,模块重用、独立开发和升级的自由度也会更高。由于模块将关注点的细节隐藏在接口之后,因此可以更自由地改进或修改单个关注点的代码段,而无需了解其他代码段的细节,也无需对其他代码段进行相应的更改。模块还可以公开接口的不同版本,这使得复杂系统能够以分阶段的方式进行升级,而不会造成功能中断。

关注点分离是一种抽象形式。与大多数抽象一样,它需要添加接口,并且通常会导致需要执行更多网络代码。因此,尽管关注点分离有很多好处,但往往也会带来一定的执行性能损失。

耦合

软件模块之间的相互依赖程度;衡量两个例程或模块之间联系紧密程度的指标;模块之间关系的强度。

耦合通常与内聚相对。低耦合往往与高内聚相关,反之亦然。低耦合通常是结构良好的计算机系统和优秀设计的标志,并且当与高内聚相结合时,有助于实现高可读性和可维护性的总体目标。

紧密耦合的系统往往表现出以下发展特征,这些特征通常被视为缺点:

  • 一个模块的改动通常会引发其他模块的连锁反应。
  • 由于模块间依赖性增加,模块组装可能需要更多的精力和/或时间。
  • 由于必须包含依赖模块,因此某些特定模块可能更难重用和/或测试。

凝聚

这指的是模块内部各元素之间的关联程度。从某种意义上说,它衡量的是类的方法和数据与该类所服务的某种统一目标或概念之间的关联强度。从另一个意义上说,它衡量的是类的方法和数据本身之间的关联强度。

内聚性是一种序数类型的度量,通常被描述为“高内聚”或“低内聚”。高内聚的模块往往更受欢迎,因为高内聚与软件的几个理想特性相关,例如健壮性、可靠性、可重用性和易理解性。相反,低内聚则与一些不良特性相关,例如难以维护、测试、重用甚至理解。

内聚性通常与耦合性形成对比,耦合性是不同的概念。高内聚性通常与低耦合性相关,反之亦然。

如果满足以下条件,则凝聚力会增强:

  • 类中嵌入的功能,以及通过其方法访问的功能,有很多共同之处。
  • 方法执行少量相关活动,避免使用粗粒度或不相关的数据集。

高内聚力(或“强内聚力”)的优势在于:

  • 降低模块复杂度(它们更简单,操作更少)。
  • 提高了系统的可维护性,因为域中的逻辑更改影响的模块更少,而且一个模块的更改需要对其他模块进行更少的更改。
  • 提高了模块的可重用性,因为应用程序开发人员可以更轻松地在模块提供的一组统一操作中找到他们需要的组件。

原则上,一个模块可以通过仅包含一个原子元素(例如,只有一个功能)来实现完全内聚。然而,在实践中,复杂的任务无法用一个简单的元素来表达。因此,单元素模块的元素要么过于复杂(为了完成任务),要么过于狭窄(从而与其他模块紧密耦合)。由此可见,内聚性需要在单元复杂性和耦合性之间取得平衡。

避免过早优化

开发人员成本高昂,而且似乎供不应求。他们面临的最大挑战之一是如何有效利用时间。在性能调优和优化方面,他们需要不断权衡时间​​分配。

应用程序的性能和可扩展性至关重要。开发人员需要首先确保构建的是正确的功能集。

编写自文档代码

自文档化源代码遵循命名约定和结构化编程约定,使得用户无需事先具备特定知识即可使用该系统。

自文档系统的常见目标包括……

  • 使源代码更易于阅读和理解。
  • 尽量减少维护或扩展旧系统所需的工作量。
  • 减少系统用户和开发人员查阅代码注释或软件手册等辅助文档资源的需要。

结论

虽然 SOLID 原则为开发实践提供了指导,但我认为它绝不应该是我们确保编写出优质、简洁(以及灵活和易于维护)代码的唯一依据。作为开发人员,我们还有很多其他方面需要了解和关注。

  • 一切皆有可能
  • 保持简单,笨蛋 (KISS)
  • 不要重复自己(DRY)
  • 你不需要它(TAGNI)
  • 编写简洁的代码,而不是巧妙的代码。
  • 坚实的原则
  • 关注点分离

  • 耦合

  • 凝聚

  • 避免过早优化

  • 编写自文档代码

是否还有其他内容应该添加到这个列表中……但这些是我经常使用的原则和模式,即使我需要深入挖掘才能记住描述背后的模式。

文章来源:https://dev.to/rfornal/practical-development-practices-301j