开发和测试*佳实践的任何新公司,都是艰巨的经历
发表时间:2023-10-11 21:02:20
文章来源:炫佑科技
浏览次数:195
菏泽炫佑科技
开发和测试*佳实践的任何新公司,都是艰巨的经历
加入任何具有既定文化和编程实践的新公司都是一次令人畏惧的经历。 当我加入团队时,我决定写下我多年来努力学习的软件工程实践和原则。 这是一个非详尽、非详尽的原则清单,应明智、灵活地应用。
我对测试充满热情,因为我相信良好的测试实践既可以确保*低的质量标准(这是许多软件产品所严重缺乏的),又可以指导和塑造开发本身。 其中许多原则与测试实践和理想相关。 其中一些原则是具体的,但大多数则不是。 (对于开发人员来说,PEP 8 应该是您了解编程风格和指南的**站。)
总的来说,我们程序员都是固执己见的人,强烈的意见通常是热情的表现。 考虑到这一点,请随意不同意这些观点,我们可以在评论中讨论和辩论。
开发和测试*佳实践
1. YAGNI:“你不需要它”。 不要编写您认为将来可能需要但现在不需要的代码。 这是针对虚构的未来用例进行编码的,不可避免地,该代码将成为死代码或需要重写,因为未来用例的工作方式总是与您想象的略有不同。
如果您将代码放入未来的用例中,我会在代码审查中提出问题。 (例如,您可以而且必须设计 API 以适应未来的用例,但这是一个不同的问题。)
注释掉代码也是如此; 如果一段带注释的代码即将发布,它就不应该存在。 如果代码可恢复,请制作票证并引用提交哈希以删除代码。 YAGNI 是敏捷编程的核心元素。 *好的参考是 Kent Beck 的《极限编程解释》。
2.测试不需要测试。 用于测试的基础设施、框架和库都需要进行测试。 除非确实需要,否则不要测试浏览器或外部库。 测试您编写的代码,而不是其他人的代码。
3. 第三次编写同一段代码是将其提取到通用助手中(并为其编写测试)的正确时机。 被测试的辅助功能不需要测试; 当你分解它们并重新使用它们时,它们确实需要测试。 当你第三次编写类似的代码时,你通常会清楚地了解你要解决的一般问题的形状。
4、关于API设计(外部接口和对象API):简单的事情就应该简单; 复杂的事情应该是可能的。 如果可能,首先针对简单情况进行设计,*好使用零配置或参数化。 添加选项或其他 API 方法以实现更复杂和灵活的用例(根据需要)。
5. 快速失败。 请尽早检查输入并在无意义的输入或无效状态下失败,*好有异常或错误响应,以便调用者清楚确切的问题。 但是开发和测试*佳实践的任何新公司,都是艰巨的经历,允许代码的“创新”用例(即除非确实需要,否则不进行输入验证的类型检查)。
6、单元测试测试的是行为单元而不是执行单元。 目标是在不改变行为或改变任何测试的情况下改变实现,尽管这并不总是可能的。 因此,如果可能,请将测试对象视为黑匣子,通过公共 API 进行测试,而不调用私有方法或修改状态。
对于某些复杂的场景(例如,测试特定复杂状态下的行为以发现模糊的错误),这可能是不可能的。 首先编写测试确实对此有帮助,因为它迫使您在编写代码之前考虑代码的行为方式以及如何测试它。 测试首先鼓励使用更小、更模块化的代码单元,这通常意味着更好的代码。 Kent Beck 的示例驱动测试开发(测试者)是开始使用测试优先方法的一个很好的参考。
7. 对于单元测试(包括测试基础设施测试),应测试所有代码路径。 100% 的覆盖率是一个很好的起点。 您无法涵盖所有可能的状态排列/组合(组合爆炸),因此需要考虑这一点。 仅当有充分理由时才应测试代码路径。 缺乏时间并不是一个好的理由,*终会花费更多的时间。 可能的充分理由包括:确实无法测试(以任何有意义的方式),在实践中无法命中,或在其他测试中涵盖。 没有测试的代码是一种责任。 衡量影响力并拒绝降低影响力的 PR 是确保您随着时间的推移朝着正确方向前进的一种方法。
8. 代码是敌人:代码可能会出错并且需要维护。 少写代码。 删除代码。 不要编写不需要的代码。
9.随着时间的推移,代码注释不可避免地变成谎言。 事实上,很少有人在事情发生变化时更新评论。 通过良好的命名约定和已知的编程风格,努力使您的代码具有可读性和自记录性。
不明显的代码(围绕一个模糊的错误或不太可能的情况,或必须完成的优化)确实需要注释。 评论代码的意图,以及它为什么做某事而不是它做了什么。 (顺便说一句,关于评论是谎言的这一点是有争议的。我仍然认为这是真的,《编程实践》和 Pike 的作者也同意我的观点。)
10. 防御性写作。 始终思考什么可能会出错、无效输入会发生什么以及什么可能会失败,这将帮助您在错误发生之前发现它们。
11. 如果逻辑是无状态且无副作用的,则很容易进行单元测试。 将逻辑分解为单独的函数,而不是将逻辑混合到有状态且充满副作用的代码中。 将有状态代码和具有副作用的代码分解为更小的函数,使它们更容易模拟和单元测试,而不会产生副作用。 (更少的测试开销意味着更快的测试。)副作用测试确实需要完成,但测试一次并在其他地方模拟它们通常是一个很好的模式。
12. 不好。 功能胜过类型。 对象可能比复杂的数据结构更好。
13. 使用内置类型及其方法将比编写自己的类型更快(除非您使用 C 语言编写)。 如果性能是一个问题,请尝试找出如何使用标准内置类型而不是自定义对象。
14. 依赖注入是一种有用的编码模式,可以清楚地表明您的依赖项是什么以及它们来自哪里。 (让对象、方法等接收它们的依赖项作为参数,而不是自己实例化新对象。)这确实使 API 签名更加复杂,因此这是一种权衡。 *终得到一个需要 10 个参数才能满足其所有依赖项的方法是一个好兆头,表明您的代码无论如何都做得太多了。 关于依赖注入的权威文章是“控制容器反转和依赖注入模式”。
15. 你模拟代码来测试的次数越多,你的代码就会变得越糟糕。 为了实例化特定行为而实例化和放置的代码越多,代码的性能就越差。 目标是构建小型、可测试的单元,以及更高级别的集成和功能测试,以测试这些单元是否正确协同工作。
16. 面向外部的 API 是“预先设计”和考虑未来用例的一个重要方面。 更改 API 对于我们和我们的用户来说都是一种痛苦,并且造成向后不兼容性是可怕的(尽管有时是不可避免的)。 精心设计面向外部的API,仍然遵循“简单的事情应该简单”的原则。
17. 如果一个函数或方法超过 30 行代码软件开发,请考虑将其分解。 一个好的*大模块大小约为 500 行。 测试文件往往比这长。
18. 不要在对象构造函数中工作,它很难测试并且令人惊讶。 不要将代码放入 .py 中(命名空间导入除外)。 程序员通常不希望 .py 找到代码,因此会出现“惊喜”。
19. DRY(不要重复)在测试中比在生产代码中重要得多。 单个测试文件的可读性比可维护性(将其划分为可重用的块)更重要。 这是因为测试是单独执行和读取的,而不是它们本身作为更大系统的一部分。 显然,过多的重复意味着可以为了方便而创建可重用的组件,但这远不如生产那么令人担忧。
20. 每当你看到需求和机会时就进行重构。 编程是关于抽象的,抽象越接近问题领域,代码就越容易理解和维护。 随着系统的有机增长,他们需要改变结构以扩展其用例。 系统的发展超出了它们的抽象和结构,如果不进行改变,系统就会变得技术上繁重,使工作变得更加痛苦(并且越来越慢且有更多错误)。 将清理技术债务(重构)的成本纳入功能工作的估算中。 偿还债务的时间越长,产生的利息就越高。 () 有一本关于重构和测试的好书。
21.先把代码写对,然后再快速写对。 处理性能问题时,请务必先进行分析,然后修复它们。 通常,瓶颈并不是你想象的那样。 只有当您对代码进行了分析并证明它确实值得时,才值得编写晦涩的代码,因为它更快。 编写一个测试来按时执行您想要分析的代码可以更容易地知道它何时完成,并且可以保留在测试套件中以防止性能下降。 (通常需要注意的是,添加计时代码总是会改变代码的性能特征,从而使性能工作成为更令人沮丧的任务之一。)
22. 更小、范围更紧密的单元测试在失败时提供更有价值的信息——它们具体告诉你出了什么问题。 占用一半系统来测试行为的测试需要更多的调查来确定出了什么问题。 一般来说,耗时超过 0.1 秒的测试不是单元测试。 不存在缓慢的单元测试这样的事情。 通过严格定义单元测试的测试行为,您的测试成为代码事实上的规范。 理想情况下,如果有人想理解您的代码,他们应该能够使用测试套件作为行为的“文档”。 Gary 的《快速测试,慢速测试》是关于单元测试实践的精彩演讲:
23.“不是这里发明的”并不像人们说的那么糟糕。 如果我们编写代码,那么我们就知道它的作用,我们知道如何维护它,并且我们可以随意扩展和修改它。 这遵循 YAGNI 原则:我们为需要的用例提供特定的代码,而不是为不需要的事情提供复杂的通用代码。 另一方面,代码是敌人,过多的代码是不好的。 引入新依赖项时要考虑权衡。
24. 共享代码所有权是目标; 孤立的知识是不好的。 至少,这意味着讨论或记录设计决策和重要的实施决策。 代码审查是开始讨论设计决策的*糟糕的时间,因为很难克服编写代码后进行大量更改的惯性。 (当然,在审查过程中指出并更改设计错误总比根本不更改要好。)
25. 发电机震撼了! 与有状态对象相比,它们比迭代或重复执行的对象更短且更容易理解。 David 的《系统程序员的生成器技巧》是对生成器的很好的介绍。
26.让我们成为工程师吧! 让我们考虑设计和构建强大且实施良好的系统,而不是让有机怪物生长。 然而,编程是一种平衡行为。 我们并不总是建造火箭飞船。 过度工程(洋葱架构)与设计不良的代码一样痛苦。 几乎所有 的文章都值得一读,《Clean : A 's Guide to and 》是关于这个主题的很好的资源。 《设计模式》是一本每个工程师都应该阅读的经典编程书籍。
27. 间歇性失败的测试会侵蚀测试套件的价值,*终每个人都会忽略测试运行结果,因为总会有一些失败。 修复或删除间歇性失败的测试很痛苦,但值得付出努力。
28. 一般来说,尤其是在测试中,等待特定的变化而不是等待任意的时间。 sleep 很难理解并且会减慢测试套件的速度。
29. 总是看到你的测试至少失败一次。 放入故意错误并确保它们失败,或者在完成被测行为之前运行测试。 否则,您可能不知道自己在测试什么。 很容易意外地编写出实际上没有测试任何内容或永远不会失败的测试。
30. *后,管理要点:持续的功能磨练是一种糟糕的软件开发方式。 不要让开发人员为他们的工作感到自豪,以确保您无法充分利用他们。 不解决技术债务会减慢开发速度,并使产品变得更糟并且更容易出现问题。
感谢团队,特别是 Wayne,为改进此列表中建议的原则提供的意见和建议。
想要摆脱 IT 流程和复杂性的限制,从而实现*佳性能吗? 下载这本免费电子书:教大象跳舞。
译自:
软件开发*佳实践
炫佑科技专注互联网开发小程序开发-app开发-软件开发-网站制作等