架构原则和方法论 — 是一套规则和建议,帮助开发人员创建可维护、可扩展且易于理解的代码。根据TIOBE Index (2025),遵循架构原则的项目严重缺陷减少40%。本文将介绍SOLID、GRASP、DRY、KISS、YAGNI等原则,并讨论技术债务和Code Smell。
要点
架构原则 — 是高质量代码的基础。SOLID是由Robert Martin(「鲍勃大叔」)引入的首字母缩写,描述了面向对象设计的五个原则。遵循SOLID使代码更灵活、更可测试、更适应变化。违反架构原则是技术债务的主要原因之一。
让我们检查每个原则。Single Responsibility Principle (SRP) — 每个类应该只有一个改变的原因。Open/Closed Principle (OCP) — 类应该对扩展开放,对修改关闭。Liskov Substitution Principle (LSP) — 子类型对象应该能够替换基类型对象而不破坏逻辑。Interface Segregation Principle (ISP) — 多个专用接口优于一个通用接口。Dependency Inversion Principle (DIP) — 依赖抽象,而不是具体实现。
根据SonarQube分析(2025),SOLID原则的违反发生在68%的商业项目中。最常见的问题是SRP违反(35%)和ISP违反(22%)。在IT Sectr,我们在架构审查阶段实施SOLID — 这有助于在问题演变为技术债务之前发现它们。
SRP(单一职责原则)— 最重要同时也是最常被违反的SOLID原则。它指出:一个类应该只有一个改变的原因。如果一个类做得太多,就很难测试、修改和理解。
一个典型的违反是一个同时处理数据、保存到数据库和发送电子邮件通知的类。下面的例子展示了Kotlin中的SRP违反以及如何修复。
// 违反SRP — 类做了三件不同的事
class UserService {
fun registerUser(email: String, name: String) {
// 1. 数据验证
if (!email.contains("@")) throw IllegalArgumentException("Invalid email")
// 2. 保存到数据库
val user = User(email, name)
database.save(user)
// 3. 发送通知
emailService.sendWelcomeEmail(email, name)
}
}
// 修复 — 拆分为三个类
class UserRegistrationService {
fun register(email: String, name: String) {
UserValidator().validate(email)
val user = User(email, name)
UserRepository().save(user)
NotificationService().sendWelcome(user)
}
}
在修复版本中,每个类负责自己的任务:UserValidator — 负责验证,UserRepository — 负责保存,NotificationService — 负责通知。这使得代码可测试且可重用 — 您可以在不更改验证逻辑的情况下替换数据库实现。
GRASP (General Responsibility Assignment Software Patterns) — 由Craig Larman描述的九个用于分配对象间责任的架构原则。与SOLID不同,GRASP回答了「哪个类应该包含这个方法?」的问题。关键模式:Information Expert、Creator、Controller、Low Coupling、High Cohesion、Polymorphism、Pure Fabrication、Indirection、Protected Variations。
Law of Demeter (LoD,最小耦合原则) — 一个简单的规则:一个对象应该只与它的直接邻居通信。不应该写a.getB().getC().doSomething() — 这会在类之间创建紧密耦合。LoD提高了可重用性并简化了测试。
在IT Sectr,我们在代码审查期间检查LoD的遵守情况。如果一个方法「穿过」三个或更多对象,这表明架构需要简化。LoD违反是大项目中最常见的Code Smell之一。
DRY (Don't Repeat Yourself)、KISS (Keep It Simple, Stupid) 和 YAGNI (You Ain't Gonna Need It) — 每个开发人员都知道的三个基本架构原则。尽管简单,但违反却不断发生。
DRY — 不要重复代码。如果相同的逻辑出现在两个地方,请将其提取到公共方法或类中。重复是错误的主要来源:一个地方的修复忘记了在另一个地方应用。DRY并不意味着不能有相似的代码 — 重要的是业务逻辑不被重复。
KISS — 越简单越好。具有许多抽象和继承的复杂解决方案通常是过度的。从简单的解决方案开始,只在必要时使其复杂化。YAGNI — 不要为「以后可能」需要的功能编写代码。这会导致代码库臃肿并增加维护复杂性。
DRY — 这不仅仅是缺少复制粘贴。这是一个原则,即每部分知识或逻辑都应在系统中具有单一、明确的表示。重复可以是显式的(复制的代码)和隐式的(不同层中的相同逻辑)。
在IT Sectr,我们使用代码分析指标来检测重复。SonarQube和Detekt等工具显示重复代码的百分比。超过5%的值是重构的理由。然而,重要的是要记住:DRY不应该以错误的抽象为代价来实现 — 有时将两个相似的代码片段保持原样更好,如果合并它们会使理解复杂化。
关注点分离 (SoC) — 一种架构原则,将系统划分为独立的部分(关注点),每个部分解决自己的任务。一个经典的例子是分层:表示层、业务逻辑层、数据访问层。每层只依赖于其下层。
模块化 — 系统可以被分解为模块的程度。模块是具有明确定义接口的逻辑相关的类组。模块应该是松耦合(low coupling)和高内聚(high cohesion)的。
内聚 (Cohesion) — 衡量同一模块内元素之间相互关联的程度。高内聚是好的:一个类做一件事并把它做好。低耦合 (Low coupling) — 衡量模块彼此独立程度的指标。低耦合是好的:更改一个模块不会破坏其他模块。
理想的架构是高内聚和低耦合。在实践中,这意味着:一个类包含操作相同数据的方法(内聚),并且只依赖于抽象,而不是具体实现(耦合)。不平衡会导致「上帝对象」或「意大利面条式代码」。
技术债务 (Technical Debt) — 由Ward Cunningham引入的比喻,描述了团队为次优架构决策和违反架构原则而支付的「利息」。与金融债务一样,技术债务可以是故意的(我们决定快速完成,以后重做)和非故意的(由于缺乏经验导致的糟糕架构)。
Code Smell — 代码中深层问题的表面迹象。这个词由Martin Fowler在《Refactoring》一书中推广。典型的Code Smell:长方法、大类、长调用链、代码重复、过度使用注释(代替清晰的代码)。
在IT Sectr,技术债务在Jira中作为单独的任务进行跟踪。每个Sprint,我们分配20%的时间用于重构和偿还债务。系统地处理技术债务是避免添加新功能比从头开发花费更长时间的唯壹方法。
常见问题
Single Responsibility Principle (SRP) — 最重要,因为它的违反会自动导致其他原则的违反。具有多重职责的类难以测试、扩展和维护。从SRP开始 — 其余的会随之而来。
内聚 (Cohesion) — 模块内部的联系(越高越好)。耦合 (Coupling) — 模块之间的联系(越低越好)。良好的架构追求高内聚和低耦合。
不,原则是指导方针,不是绝对法则。在小型项目或原型中,过度遵循SOLID可能导致过度工程化。重要的是在「足够好」的架构和开发速度之间找到平衡。
使用静态分析器(SonarQube、Detekt、ESLint)、代码审查和代码指标。债务的迹象:代码难以测试,一个地方的更改破坏了另一个地方,添加新功能的时间从一个Sprint增加到下一个Sprint。定期重构是控制债务的唯壹方法。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。