C# 代码整洁指南(六)
原文:
zh.annas-archive.org/md5/0768F2F2E3C709CF4014BAB4C5A2161B译者:飞龙
第十五章:评估
第一章
-
糟糕代码的一个结果是,你可能最终得到一段非常糟糕的难以理解的代码。这往往会导致程序员压力和软件出现错误,难以维护、测试和扩展。
-
好代码的一个结果是它易于阅读和理解,因为你知道程序员的意图。这会减轻程序员在调试、测试和扩展代码时的压力。
-
当你将一个大项目分解成模块化的组件和库时,每个模块可以由不同的团队同时进行工作。小模块易于测试、编码、文档化、部署、扩展和维护。
-
DRY代表Don't Repeat Yourself。寻找可重复的代码,并重构它,以便删除重复的代码。这样做的好处是程序更小,因为如果这样的代码包含错误,你只需要在一个地方进行更改。
-
KISS 意味着简单的代码不会让程序员困惑,特别是如果你的团队中有初级程序员。KISS 代码易于阅读和编写测试。
-
S是Single Responsibility Principle,O是Open/Closed Principle,L是Liskov Substitution,I是Interface Segregation Principle,D是Dependency Inversion Principle。
-
YAGNI是You Aren't Going to Need It的缩写。换句话说,不要添加不需要的代码。只添加绝对需要的代码,不要多余。
-
奥卡姆剃刀原则是指:实体不应该被无必要地增加。 只处理事实。只有在绝对必要的情况下才做假设。
第二章
-
同行代码审查中的两个角色是审阅者和被审阅者。
-
项目经理同意参与同行代码审查的人员。
-
在请求同行代码审查之前,通过确保你的代码和测试都能正常工作,对项目进行代码分析并修复任何问题,以及确保你的代码符合公司的编码准则,可以节省审阅者的时间和精力。
-
在审查代码时,要注意命名、格式、编程风格、潜在错误、代码和测试的正确性、安全性和性能问题。
-
反馈的三个类别是积极的、可选的和关键的。
第三章
-
我们可以将我们的代码放在文件夹结构中的单独源文件中,并将类、接口、结构和枚举包装在映射到文件夹结构的命名空间中。
-
一个类应该只有一个职责。
-
你可以在代码中添加注释,用于文档生成器,放置在要记录的公共成员的正上方的 XML 注释。
-
内聚性是将处理相同职责的代码逻辑分组在一起。
-
耦合指的是类之间的依赖关系。
-
内聚性应该很高。
-
耦合应该很低。
-
你可以使用 DI 和 IoC 来设计变更。
-
DI代表Dependency Injection。
-
IoC代表Inversion of Control。
-
不可变对象是类型安全的,因此可以在线程之间安全地传递。
-
对象应该暴露方法和属性,并隐藏数据。
-
数据结构应该暴露数据,不应该有方法。
第四章
-
没有参数的方法称为 niladic 方法。
-
只有一个参数的方法称为单元方法。
-
具有两个参数的方法称为二元方法。
-
具有三个参数的方法称为三元方法。
-
具有三个以上参数的方法称为多元方法。
-
你应该避免重复的代码。这不是一种有效的编程方式,会使程序变得不必要地庞大,并有可能在整个代码库中扩散相同的异常。
-
函数式编程是一种将计算视为不修改状态的数学计算的软件编码方法。
-
函数式编程的优势包括在多线程应用中的安全代码和更小、更有意义的易于阅读和理解的方法。
-
输入和输出对于函数式程序可能会产生问题,因为它依赖于副作用。函数式编程不允许副作用。
-
WET 代码是 DRY 的反义词,因为每次需要时都会编写代码。这会产生重复,并且相同的异常可能会在程序的多个位置发生,使得维护和支持更加困难。
-
DRY 代码是 WET 的反义词,因为代码只会被写一次,并在需要时被重复使用。这减少了代码库和异常足迹,使得程序更易于阅读和维护。
-
通过重构来消除重复的代码,使 WET 代码变 DRY。
-
长方法笨重且容易出现异常。它们越小,阅读和维护就越容易。程序员引入逻辑错误的机会也更小。
-
为了避免使用 try/catch 块,你可以编写参数验证器。然后在方法的开头调用验证器。如果参数未通过验证,则会抛出适当的异常,并且方法不会被执行。
第五章
-
已检查的异常是在编译时检查的异常。
-
未经检查的异常是在编译时未经检查或简单忽略的异常。
-
当高阶位无法分配给目标类型时,会引发溢出异常。在检查模式下,会引发
OverflowException。在未经检查的模式下,无法分配的高阶位会被简单忽略。 -
尝试访问空对象的属性或方法。
-
实现一个
Validator类和一个Attribute类,检查参数是否为空,并抛出ArgumentNullException。你会在方法的开头使用Validator类,这样在方法执行到一半之前就会引发异常。 -
业务规则异常(BRE)。
-
BREs 是一种不好的做法,因为它们期望异常被引发以控制程序流程。
-
正确的编程不应该通过期望异常作为输出来控制计算机程序的流程。因此,鉴于 BRE 是不好的,因为它们期望异常输出并用它来控制程序流程,更好的解决方案是使用条件编程。在条件程序中,你使用布尔逻辑。布尔逻辑允许两种可能的执行路径,并且不会引发异常。条件检查是显式的,并且使程序更易于阅读和维护。你还可以轻松地扩展这样的代码,而对于 BRE,你无法这样做。
-
首先,从已知的异常类型开始进行错误捕获,比如使用 Microsoft .NET Framework 中已知的异常类型
ArgumentNullExceptions和OverflowExceptions。但是当这些不够用,并且不能为特定情况提供足够的数据时,你会编写并使用自定义异常,并应用有意义的异常消息。 -
你的自定义异常必须继承自
System.Exception,并实现三个构造函数:默认构造函数,接受文本消息的构造函数,以及接受文本消息和内部异常的构造函数。
第六章
-
一个好的单元测试必须是原子的、确定性的、可重复的和快速的。
-
一个好的单元测试不应该是不确定的。
-
测试驱动开发。
-
行为驱动开发。
-
一个小的代码单元,其唯一目的是测试只执行一件事的单个代码单元。
-
单元测试使用的虚假对象,用于测试真实对象的公共方法和属性,但不测试方法或属性的依赖关系。
-
一个虚假对象与一个模拟对象相同。
-
MSTest、NUnit 和 xUnit。
-
Rhino Mocks 和 Moq。
-
SpecFlow。
-
不必要的注释、死代码和冗余测试。
第七章
-
从头到尾测试完整系统。这可以手动、自动或两种方法结合进行。
-
集成测试。
-
所有功能的手动测试,所有单元测试都应通过,并且我们应编写自动化测试来测试两个模块之间传递的命令和数据。
-
工厂是实现工厂方法模式的类,其意图是允许创建对象而不指定它们的类。我们会在以下情况下使用它们:
-
该类无法预测必须实例化的对象类型。
-
子类必须指定要实例化的对象类型。
-
类控制其对象的实例化。
-
DI 是一种产生松散耦合代码的方法,易于维护和扩展。
-
使用容器可以轻松管理依赖对象。
第八章
-
线程是一个进程。
-
一个。
-
后台线程和前台线程。
-
后台线程。
-
前台线程。
-
Thread.Sleep(500); -
var thread = new Thread(Method1); -
将
IsBackground设置为true。 -
死锁是两个线程被阻塞并等待另一个线程释放资源的情况。
-
Monitor.Exit(objectName); -
使用相同资源的多个线程根据每个线程的时间产生不同的输出。
-
使用 TPL 与
ContinueWith(),并使用Wait()在退出方法之前等待任务完成。 -
使用其他方法共享的成员变量,并传递引用变量。
-
是的。
-
线程池。
-
它是一种一旦构建就无法修改的对象。
-
它们允许您在线程之间安全共享数据。
第九章
-
应用程序编程接口。
-
表述性状态转移。
-
统一接口、客户端-服务器、无状态、可缓存、分层系统、可选可执行代码。
-
超媒体作为应用状态的引擎(HATEOAS)。
-
RapidApi.com。
-
授权和认证。
-
声明是实体对自身的陈述。然后根据数据存储对这些声明进行验证。它们在基于角色的安全性中特别有用,用于检查作出声明的实体是否对该声明有授权。
-
发出 API 请求并检查它们的响应。
-
因为您可以根据需求更改数据存储。
第十章
-
将软件正确分区为逻辑命名空间、接口和类,有助于测试软件。
-
通过了解 API,您可以通过不重复发明轮子并编写已经存在的代码来简化代码并使其保持干燥。这样可以节省时间、精力和金钱。
-
结构。
-
第三方 API 由软件开发人员编写,因此容易出现引入错误的人为错误。通过测试第三方 API,您可以确信它们按预期工作,如果不是,则可以修复代码或为其编写包装器。
-
您的 API 容易出错。通过根据规范及其验收标准测试它们,您可以确保以商业期望的质量水平交付准备进行公开发布。
-
规范和验收标准提供了正常程序流程。通过它们,您可以确定在执行的正常流程方面进行测试,并确定将遇到什么异常情况并对其进行测试。
-
命名空间、接口和类。
第十一章
-
横切关注点是不属于核心关注点的业务需求的关注点,但必须在代码的所有领域中进行处理。AOP代表面向切面编程。
-
方面是应用于类、方法、属性或参数时,在编译时注入代码的属性。您在应用属性之前在方括号中应用属性。
-
属性为项目赋予语义含义。您在应用属性之前在方括号中应用属性。
-
属性赋予代码语义含义,而方面则消除样板代码,使其在编译时注入。
-
当代码正在构建时,编译器将插入切面隐藏程序员的样板代码。这个过程被称为代码编织。
第十二章
-
代码度量是几个源代码测量,使我们能够确定软件的复杂程度和可维护性。这些测量使我们能够确定可以通过重构使代码更简单和更易维护的代码区域。
-
圈复杂度,可维护性指数,继承深度,类耦合,源代码行数和可执行代码行数。
-
代码分析是对源代码的静态分析,目的是识别设计缺陷,全球化问题,安全问题,性能问题和互操作性问题。
-
快速操作是由螺丝刀或灯泡标识的单个命令,它将抑制警告,添加使用语句,导入缺少的库并添加使用语句,纠正错误,并实现旨在简化代码并减少方法中行数的语言使用改进。
-
JetBrains 的 dotTrace 实用程序是用于对源代码和编译的程序集进行性能分析的工具,以识别软件的潜在问题。您可以执行采样,跟踪,逐行和时间线分析。您可以分析执行时间,线程时间,实时 CPU 指令和线程周期时间。
-
JetBrains 的 ReSharper 实用程序是一个代码重构工具,它帮助开发人员识别和修复代码问题,并实现语言特性以改进和加快程序员的编程体验。
-
源代码的反编译可用于检索丢失的源代码,为调试生成 PDB,并用于学习。您还可以使用反编译器查看您的代码混淆得有多好,以使黑客和其他人难以窃取您的代码秘密。
第十三章
-
应用级别,类级别和方法级别。
-
布尔盲目,组合爆炸,人为复杂,数据团,除臭剂注释,重复代码,意图丢失,变量突变,古怪解决方案,散弹手术,解决方案蔓延和不受控制的副作用。
-
圈复杂度,分歧变更,向下转型,过多的文字使用,特征嫉妒,不当亲密,不雅曝光,大类(也称为上帝对象),懒惰类(也称为吃白食者和懒惰对象),中间人类,变量和常量的孤立类,原始偏执,拒绝遗赠,推测性泛化,告诉,不要问!和临时字段。
-
害群之马,圈复杂度,人为复杂,死代码,过多的数据返回,特征嫉妒,标识符大小,不当亲密,长行(也称为上帝行),懒惰方法,长方法(上帝方法),长参数列表(太多参数),消息链,中间人方法,古怪解决方案和推测性泛化。
-
使用 LINQ 而不是循环。使类只负责一件事。使方法只做一件事。用参数对象替换长参数列表。使用创建性设计模式来提高昂贵对象的创建和利用效率。保持方法不超过 10 行。使用 AOP 从方法中删除样板代码。解耦对象并使它们可测试。使代码高度内聚。
-
代表分支和循环数量的值。
-
减少分支和循环的数量,直到圈复杂度值变为 10 或更少。
-
使事情变得比必要的更复杂。
-
保持简单,愚蠢(KISS)。
-
用不同的方法和不同的参数组合做同样的事情。
-
创建通用方法,可以对不同数据类型执行相同的任务,这样你只需要一个方法和一组参数。
-
修复糟糕的代码并删除注释。
-
寻求帮助。
-
堆栈溢出。
-
长参数列表可以用参数对象替换。
-
将其重构为只执行一件事的较小方法,并使用 AOP 将样板代码移入方面。
-
不超过 10 行。
-
0-10;超过这个范围,您就会自找麻烦。
-
一。
-
未使用的变量、类、属性和方法。摆脱它们。
-
选择最佳的实现方法,然后重构代码以只使用该实现方法。
-
将临时字段和操作它的方法重构为它们自己的类。
-
在不同类中使用相同的变量集。将变量重构为它们自己的类,然后引用该类。
-
一个类继承自另一个类,但不使用其所有方法。
-
迪米特法则。
-
只允许类与其直接邻居交谈。
-
一个类或方法在另一个类或方法中花费太多时间。
-
将依赖关系重构为它们自己的类或方法。
-
工厂方法。
-
从基类继承,然后创建从基类继承的新类。
-
单一责任在应用程序的不同层中的不同类的不同方法中实现。将责任重构为自己的类,以便它只存在于一个位置。
-
数据应该放在操作数据的同一个对象中。
-
当您创建一个对象,该对象请求另一个对象的数据,以便它可以对其执行操作。
-
单一更改需要在多个位置进行更改。消除重复,消除耦合,提高内聚性。
-
失去意图是因为类或方法的原因不清楚,因为有许多不相关的项目被聚集在一起。重构代码,使得所有方法都在正确的类中。这样,类和方法的意图就变得清晰了。
-
您可以使用 LINQ 查询重构循环。LINQ 是一种不改变位置变量并且比循环执行得快得多的函数语言。
第十四章
-
GoF是Gang-of-Four模式的缩写。这些模式被分为创建、结构和行为设计模式。它们被认为是所有软件设计模式的基础。它们共同工作以产生清晰的面向对象的代码。
-
创建模式使抽象和继承能够以面向对象的方式消除代码重复,并在对象创建昂贵时提高性能。创建模式包括抽象工厂、工厂方法、单例、原型和生成器。
-
结构模式使对象之间的关系得到正确管理。我们可以使用结构模式使不兼容的接口一起工作,将抽象与其实现解耦,并提高性能。结构模式包括适配器、桥接、组合、装饰器、外观、享元和代理。
-
行为模式规定对象如何相互交互和通信。我们可以使用它们来生成管道,封装命令和将来执行的信息,调解对象之间的关系,观察对象的状态变化,等等。行为模式包括责任链、命令、解释器、迭代器、中介者、备忘录、观察者、状态、策略、模板方法和访问者。
-
是的。
-
单例只允许在应用程序的整个生命周期中存在一个对象实例。该对象对所有需要它的对象都是全局可访问的。当我们需要确保有一个集中的对象创建和对象访问点时,我们使用此模式。
-
当我们需要创建对象而不指定要实例化的确切类时,我们使用工厂方法。
-
外观。
-
使用享元设计模式。
-
桥接。
-
使用生成器模式。
-
您将使用责任链模式,因为您可以拥有一系列处理程序,每个处理程序执行一个任务。如果它们无法处理任务,处理程序将将任务传递给它们的后继者来处理。