效率
有经验的程序员可以很容易地分辨出架构的好坏,但如果被要求用几句话来描述它,他们不太可能做到。好的架构没有单一的标准,也没有单一的定义。
然而,如果你仔细想想,你可以写出一些好的架构应该满足的标准。一个好的架构首先是一个逻辑架构,它可以让程序的开发和维护过程更简单、更高效。
当程序具有良好的体系结构时,总是很容易理解它是如何工作的以及在何处编写代码。一个结构良好的程序更容易更改、测试、调试和开发。聪明人制定了以下优秀架构的标准:
- 效率;
- 灵活性;
- 可扩展性;
- 可扩展性;
- 可测试性;
- 代码可维护性。
系统效率。当然,该程序必须解决分配的任务并在各种条件下良好地执行其功能。似乎任何程序都在做它应该做的事情(如果它被编写的话),但通常情况并非如此。
你会经常遇到一些程序,它们并没有按照他们声称的那样去做。
- Libre Office 是 Microsoft Office 的完全替代品(不是真的);
- Edge 浏览器支持所有网络标准(不是真的);
- 银行关心其用户个人数据的安全(实际上不关心)。
而且我们还没有涉及性能、可靠性、及时的错误修复或有关已知漏洞的信息的发布。
很明显,没有人是完美的,但程序必须解决其主要任务。因此,没有效率,无处可去。
灵活性
在我看来,唯一比效率更重要的是灵活性。任何应用程序都必须随着时间的推移而变化,随着需求的变化,新的需求会被添加。对现有功能进行更改越快、越方便,引起的问题和错误越少,系统架构就越灵活。
很多时候,新手程序员/架构师认为他们需要一个理想的架构来完成当前的任务。不。你需要一个理想的架构来完成一年后向你宣布的任务。你,现在已经不知道未来的任务,应该知道它们会是什么。
试图预测它们是没有意义的,因为总会有意想不到的事情发生。但是您必须考虑到会出现此类任务。因此,在开发过程中,尝试根据需要如何更改来评估正在获得的内容。
问问自己:“如果当前的架构决策被证明是错误的,会发生什么?”、“将更改多少代码?”。更改系统的一个片段不应影响其其他片段。
只要有可能,架构决策不应该一成不变,架构错误的后果应该合理限制。“良好的架构允许您延迟关键决策”(Bob Martin)并最大限度地减少错误的“成本”。
其中一种方法是将应用程序拆分为微服务:很容易将已经存在的逻辑分解成单独的部分。但最大的问题是为了实现一个小功能而同时对十几个服务进行未来更改。
可扩展性
可扩展性是通过向项目中添加新人员来减少开发时间的能力。该体系结构应允许并行化开发过程,以便许多人可以同时处理该程序。
似乎这条规则是自己执行的,但实际上一切恰恰相反。甚至还有一本超级流行的书,《人月神话》,它解释了为什么当一个项目中加入新人时,开发时间会增加。
可扩展性
可扩展性是在不破坏系统核心结构的情况下向系统添加新功能和实体的能力。在初始阶段,只将基本和最必要的功能放入系统中是有意义的。
这就是所谓的YAGNI 原则——你不会需要它,“你不会需要它”。同时,该体系结构应该允许您根据需要轻松地增加额外的功能。因此,最有可能的变化的引入需要最少的努力。
系统架构的灵活性和可扩展性(即能够改变和进化)的要求是如此重要,以至于它甚至被制定为一个单独的原则——“开放/封闭原则”。开闭原则是五个 SOLID 原则中的第二个:软件实体(类、模块、函数)应该对扩展开放,但对修改关闭。
换句话说:应该可以在不重写系统现有部分的情况下改变和扩展系统的行为。
这意味着应用程序的设计方式应该是通过编写新代码(扩展)来更改其行为和添加新功能,而无需更改现有代码。
在这种情况下,新需求的出现并不需要对现有逻辑进行修改,而是主要通过扩展来实现。这个原则是“插件架构”(Plugin Architecture)的基础。稍后将讨论实现这一点的技术。
还记得 servlet 和过滤器吗?如果实际上可以使用 servlet 实现所有相同的逻辑,为什么还需要过滤器,甚至使用单独的接口?
过滤器(服务 servlet)概念的发明使得将各种服务功能移动到单独的层成为可能。并且在未来,当改变过滤器的行为时,没有必要改变 servlets。
在过滤器发明之前,所有负责重定向请求的服务逻辑都位于 servlet 本身中。通常逻辑上的一个小变化会导致需要遍历所有 servlet 并对所有 servlet 进行各种更改。
可测试性
如果您是 Java 后端开发人员,那么您的服务器应用程序通常会将一组方法公开为 REST API。为了检查你所有的方法是否按预期工作,它们需要被测试覆盖。
一般来说,API 测试覆盖率是一种很好的风格。它使您能够确保您的 API 确实按照预期的方式工作。而且,更重要的是,您可以更改服务器逻辑并轻松检查您是否不小心破坏了任何东西。
一旦开始编写测试,您就会意识到大多数代码根本无法进行测试:私有方法、强耦合、静态类和变量。
“如果代码有效,为什么我们需要测试?”,初学者会问。
“如果无法测试,为什么我们需要工作代码?”,专业人士会问。
易于测试的代码将包含更少的错误并且更可靠。但测试不只是提高代码质量。几乎所有的开发人员最终都得出结论,“良好的可测试性”的要求也是一种自动导致良好设计的指导力量。
引用 Ideal Architecture 一书中的一句话:“将类的“可测试性”原则作为良好类设计的“试金石”。即使你不写一行测试代码,在 90 年内回答这个问题% 的案例将有助于了解他的设计是如何“好”或“坏”的。
有一整套基于测试来开发程序的方法,称为测试驱动开发(TDD)。这当然是另一个极端:先写代码再写代码。
代码可维护性
通常,很多人都在为这个项目工作——有些人离开了,新人来了。程序员在IT公司的平均工作时间是一年半。所以如果你来到一个 5 年前的项目,那么你的同事中只有 20% 从一开始就参与其中。
维护和开发别人编写的程序是非常困难的。即使程序已经写好了,也常常需要继续维护它:修复错误并进行小的修正。通常这必须由没有参与编写的人来完成。
因此,一个好的架构应该能够让新人相对容易和快速地理解这个系统。该项目必须是:
- 结构良好。
- 不包含重复。
- 有格式良好的代码。
- 最好包括文档。
- 有必要为程序员应用标准和熟悉的解决方案。
您可以轻松地以 5 分制对您正在从事的项目进行评分。只需为这些要求中的每一项算两分。如果你得到 5 个或更多,那么你很幸运。
程序员甚至有一个最少惊奇原则:系统越奇特,别人就越难理解。通常,它与用户界面有关,但也适用于编写代码。
GO TO FULL VERSION