54、代码设计与DevOps实践指南

代码设计与DevOps实践指南

1. 代码设计的艺术

在代码设计领域,我们追求的是发现代码背后隐藏的美。当面对已有的代码设计时,即使它不再完全适用,也不必急于全盘推翻,而应先理解其核心思想。许多时候,原设计仍有其合理性,只需进行微调,而非彻底重构。

以认证示例来说,登录端点依赖于 PersonaClient ,而 PersonaClient 又依赖于 HttpsRestClient ,导致代码无法测试,出现了难以维护的登录代码。但创建基础设施包装器的核心思想是合理的。通过使基础设施包装器可空,我们能够采用测试驱动开发来创建新的、更简洁的Auth0登录端点。

1.1 代码异味

代码异味是关于设计问题的智慧结晶,能帮助我们发现代码中的改进机会。发现代码异味并不一定意味着设计存在问题,就像厨房中的怪味,可能只是需要倒垃圾,也可能是有人用了刺鼻的奶酪烹饪。无论如何,当闻到异味时,都应仔细检查。

常见的代码异味包括:
- 霰弹式修改(Shotgun Surgery)和发散式变化(Divergent Change) :霰弹式修改指为了进行单一更改而需要修改多个模块或类,这表明需要将相关概念集中化,为其赋予独立的名称和模块。发散式变化则相反,当不相关的更改影响到同一模块或类时,说明该模块承担了过多职责,应将这些职责拆分为多个模块。
- 基本类型偏执(Primitive Obsession)和数据泥团(Data Clumps) :基本类型偏执是指重要的设计概念用通用类型表示,如用小数表示货币、用日期表示订阅续订日期,这会导致相关代码分散,增加重复并降低内聚性。数据泥团是指几个变量总是一起出现,代表某个概念,但没有相应的类或类型来表示它们,如代码中经常传递 street1 street2 state country postalCode 字符串来表示地址。解决这两种问题的方法是将概念封装在专用的类型或类中。
- 数据类(Data Class)和代码类(Code Class) :常见的面向对象设计错误是数据和代码分离在不同类中,这会导致数据操作代码重复。数据类是指只包含实例变量和 getter/setter 方法的类,代码类则是只包含函数而没有实例状态的类。代码类本身不一定有问题,但常与数据类、基本类型偏执或数据泥团一起出现。应将代码和数据重新组合,将操作数据的方法放在与数据相同的类中,以提高内聚性。
- 错误压制(Squashed Errors)和空值溺爱(Coddled Nulls) :优秀的程序员与普通程序员的区别之一在于强大的错误处理能力。很多时候,原本编写良好的代码在遇到错误时会放弃处理,常见的做法是捕获异常、记录错误,然后返回空值或无意义的值,这在 Java 中尤为常见。错误压制会导致后续问题,因为空值可能会在代码的其他地方被当作真实值使用。应在能够提供有意义的替代方案(如重试或提供有用的默认值)时处理错误,否则将错误传播给调用者。空值溺爱则是当函数收到意外的空值时,程序员检查空值后自己也返回空值,导致空值在应用程序中级联,引发不可预测的故障。应采用快速失败策略,除非空值有明确的语义,否则不允许将其作为参数,也不要返回空值来表示错误,而是抛出异常。
- 时间依赖(Time Dependencies)和半成品对象(Half-Baked Objects) :时间依赖指类的方法必须按特定顺序调用,半成品对象是时间依赖的特殊情况,需要先构造,再通过方法调用初始化,最后才能使用。时间依赖和半成品对象通常表明存在封装问题,类期望调用者管理其部分状态,这会导致调用者出现错误和重复代码。应寻找更有效地封装类状态的方法,在某些情况下,可能需要将类拆分为多个类。

1.2 反思性设计

反思性设计有两个重要的盟友:重构和测试驱动开发。在决定要更改的内容后,应通过一系列小的重构逐步进行更改,每次重构后确保测试通过。每个重构步骤最多花费一两分钟,有时可能需要添加缺失的函数或方法,可使用测试驱动开发来构建。

可以进行反思性设计练习,帮助团队培养分析现有代码设计和识别改进机会的能力。具体步骤如下:
1. 组队 :每次练习时与不同的人组队。如果人数为奇数,多余的人可以单独工作或组成三人小组。
2. 选择分析单元(限时15分钟) :浏览代码,选择一个离散的单元进行分析,如函数、方法、模块、类或整个子系统。不要花费太多时间选择,如果难以决定,可以随机选择。通过阅读代码反向工程设计,使用序列图、类图、CRC 卡或其他喜欢的技术对设计进行建模,识别代码和设计中的缺陷并讨论如何修复,创建一个新的模型来展示修复后的设计。
3. 讨论(限时15分钟) :选择三对人员,每对进行五分钟的讨论,分享他们的发现。

持续进行这个练习,直到所有参与者能够在 30 分钟内高效完成任务且不感到匆忙。

以下是反思性设计练习的流程图:

graph LR
    A[开始] --> B[组队]
    B --> C[选择分析单元]
    C --> D[反向工程设计]
    D --> E[识别缺陷并讨论修复]
    E --> F[创建新模型]
    F --> G[选择三对人员讨论]
    G --> H{是否所有参与者能高效完成}
    H -- 否 --> B
    H -- 是 --> I[结束]

反思性设计与重构有所不同,反思性设计是决定方向,重构是具体操作。在工作中,应将反思性设计作为正常且不可或缺的一部分,不必追求代码完美,只要比原来更好即可。同时,要保持计划的灵活性,频繁提交代码,以便回退不成功的改进想法。

2. DevOps实践

在软件开发的早期,开发人员的工作往往局限于构建软件,然后将其交付进行发布,后续的操作流程则由专门的部门负责,这种开发与运维分离的模式在一定程度上阻碍了软件的高效交付和质量提升。而DevOps运动的兴起打破了开发、运维和安全之间的壁垒,使得团队能够创建更安全、可靠且易于管理的软件。

2.1 DevOps的核心实践

DevOps包含以下四个核心实践,这些实践相互配合,共同推动软件的高效开发和稳定运行:
- 为运维而构建(Build for Operation) :DevOps的基本理念是将具备运维和安全技能的人员纳入团队,从开发的一开始就将可操作性和安全性融入软件,而不是在后期才考虑这些因素。具体做法是让运维和安全人员参与团队决策和规划会议,创建关于软件监控、管理和安全的故事,并根据其重要性进行优先级排序。例如,当添加一个需要新数据库的功能时,应同时添加关于数据库配置、安全、监控、备份和恢复的故事。
- 特性开关(Feature Flags) :特性开关允许团队部署未完成的软件。通过在代码中设置开关,可以控制某些功能是否对用户可见,从而在不影响用户体验的情况下进行功能开发和测试。
- 持续部署(Continuous Deployment) :持续部署能够降低生产部署的风险和成本。它基于持续集成的理念,实现软件的自动化部署,使得新功能能够快速、稳定地发布到生产环境。
- 进化式系统架构(Evolutionary System Architecture) :进化式系统架构将XP的进化式设计理念应用于系统架构,确保系统保持简单、可维护和灵活。

实践名称 描述
为运维而构建 将运维和安全融入开发,从开始就考虑软件的可操作性和安全性
特性开关 允许部署未完成的软件,通过开关控制功能可见性
持续部署 降低生产部署风险和成本,实现自动化部署
进化式系统架构 应用进化式设计理念,保持系统简单、可维护和灵活
2.2 为运维而构建的具体操作

为运维而构建涉及到两个重要方面:威胁建模和配置管理。

威胁建模 :这是一种安全技术,同时对运维也有帮助。它通过回答四个问题来理解软件系统及其可能面临的威胁:
1. 明确构建内容 :绘制系统架构图,包括部署软件的组件、组件之间的数据流以及信任或授权边界。
2. 识别潜在问题 :使用头脑风暴法思考每个组件和数据流可能受到的攻击方式,然后通过点投票确定团队认为的主要威胁。
3. 制定应对措施 :针对主要威胁进行头脑风暴,提出检查或解决方法,再次通过点投票确定方案,并创建故事卡添加到可视化计划中。
4. 检查分析结果 :先搁置一段时间,然后再次检查工作,确保没有遗漏。定期重复这个过程,结合新信息和见解,使用盲点发现技术找出思考中的漏洞。

配置管理 :根据《十二要素应用》,部署的软件由代码和配置组成。配置是指在不同环境中不同的部分,如数据库连接字符串、第三方服务的URL和密钥等。部署时,相同的代码会部署到各个环境,但配置会根据环境进行调整。环境配置应与代码分离,通常存储在单独的仓库中。而对于其他可配置项,如网站页脚的版权日期,应将其视为软件行为的一部分,与代码一起进行版本控制。

以下是为运维而构建的操作流程图:

graph LR
    A[开始] --> B[威胁建模]
    B --> B1[明确构建内容]
    B --> B2[识别潜在问题]
    B --> B3[制定应对措施]
    B --> B4[检查分析结果]
    B --> C[配置管理]
    C --> C1[分离环境配置]
    C --> C2[版本控制其他配置]
    C --> D[结束]

通过以上的代码设计和DevOps实践,我们能够提高代码的质量和可维护性,实现软件的高效开发和稳定运行。在实际工作中,应根据具体情况灵活运用这些方法和技术,不断优化软件的设计和开发流程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值