53、软件开发中的简单设计与反思性设计实践

软件开发中的简单设计与反思性设计实践

在软件开发领域,追求高效、简洁且易于维护的代码是每个开发者的目标。本文将探讨简单设计与反思性设计的相关概念、方法以及实践案例,帮助开发者提升代码质量和开发效率。

1. 自我文档化代码

在编写代码时,简单性的评判标准并非取决于个人,而是团队其他成员或未来的代码维护者。为避免设计过于复杂,应使用团队和语言通用的习惯用法和模式。若引入新想法,需先与团队成员沟通。

命名是编写自我文档化代码的强大工具,变量和函数的名称应清晰反映其意图。当函数复杂时,可使用提取函数重构方法为每个部分命名;条件语句难以理解时,可使用函数或中间变量为其各部分命名。

编写好的命名和简单的代码并非易事,但有三种方法可使其变得更容易:
- 结对编程或集体编程 :提供更多视角和想法,便于讨论和改进代码表达。
- 重构 :当下尽力编写代码,后续再进行优化。
- 集体代码所有权 :当遇到不清晰的代码时,理解原作者意图并进行重构,使意图更明显。

2. 发布接口

发布接口会限制代码的更改能力。一旦接口发布给团队外部人员,更改接口通常需要大量成本和精力,因此要避免破坏他人依赖的内容。

有些团队将每个公共方法都视为发布接口,认为定义后不应更改,这并非良策,会阻碍设计的改进。更好的做法是根据需要更改未发布的接口,并相应更新调用者。

若代码供团队外部使用,则需要发布接口。但应尽量减少发布接口的数量,仔细权衡每个接口的成本和收益,并尽可能推迟发布决策,以优化设计。对于为第三方创建库的团队,需提前精心设计接口,接口越小越好。

3. 性能优化

现代计算机系统复杂,开发者对性能的直觉往往是错误的。基于简短性能测试的优化技巧并不适用,优化现代系统需采用整体方法,即测量代码的实际性能,找出热点并进行优化,而不是凭猜测和假设,要不断进行性能分析。

通常,字符串拼接、函数调用和装箱拆箱等看似消耗性能的操作并非关键问题,性能往往受网络、数据库或文件系统的影响,也可能是二次算法、线程争用或非顺序内存访问等问题导致。

4. 简单设计的相关问题解答
  • 已知未来需要某个功能,是否应提前设计钩子? :除非该功能是本周工作的一部分,否则不应提前添加钩子,因为计划可能改变,提前添加会增加不必要的复杂性。而且,进化式设计会随着时间降低更改成本,等待越久,更改成本越低。
  • 忽略某个功能会使未来实现更困难怎么办? :可寻找消除风险的方法,而不是直接编码支持该功能,“风险驱动架构”有更详细的介绍。
5. 简单设计的前提和指标

简单设计需要通过重构、反思性设计和增量设计不断改进,否则设计无法随需求演变。但不能将简单设计作为糟糕设计的借口,简单性需要深思熟虑。

创建简单设计时,有以下指标:
|指标|描述|
|----|----|
|不提前编写未来功能代码|团队不会为未来的故事编写代码|
|工作完成更快|不构建当前不需要的东西,提高工作效率|
|支持任意更改|设计能够轻松支持任意更改|
|代码更改局部化|新功能可能需要大量新代码,但对现有代码的更改是局部且直接的|

6. 替代方案和实验

传统的设计方法是预测未来变化并提前构建支持这些变化的设计,称为“预测性设计”。虽然许多团队使用这种方法取得了成功,但它依赖于正确预测新需求和故事。若预测偏差较大,可能需要重写大量基于错误假设的代码,导致代码库出现长期缺陷。

一般来说,本文介绍的简单设计技术比预测性设计更有效,但也可将两者结合。若采用预测性设计,最好聘请在特定行业有丰富经验的程序员,他们更有可能正确预测变化。

7. 反思性设计

传统设计方法假定代码不应更改,通过添加新代码支持新功能,并通过继承、依赖注入等方式构建可扩展性“钩子”,遵循“开闭原则”。而敏捷团队创建的简单设计不预测未来,没有这些钩子,而是具备重构代码和更改设计的能力,这种方法称为反思性设计。

反思性设计与预测性设计相反,它不推测未来,只关注当前的更改。其工作流程如下:

graph LR
    A[分析现有代码] --> B[识别设计缺陷]
    B --> C[选择改进点]
    C --> D[逐步重构代码]
    D --> E{是否完成任务且代码干净}
    E -- 否 --> B
    E -- 是 --> F[结束]
  1. 分析现有代码 :若不熟悉代码,可进行逆向工程,复杂代码可绘制类图或序列图辅助理解。
  2. 识别设计缺陷 :思考难以理解、运行不佳的部分,以及当前任务可能遇到的问题。
  3. 选择改进点 :考虑能清理代码并使当前任务更轻松的设计更改,重大更改需与团队成员讨论。
  4. 逐步重构代码 :注意设计更改在实践中的效果,若不理想则调整方向。
  5. 重复直至完成任务 :确保代码比开始时更干净。
8. 反思性设计的实践案例

曾有一次需要替换网站的登录基础设施,从旧的认证提供商 Persona 切换到新的 Auth0。采用反思性设计方法,逐步进行更改:
- 逆向工程代码设计 :从现有登录端点开始,分析文件的导入和依赖关系。发现登录端点依赖 PersonaClient 和 SubscriberAccount,PersonaClient 依赖 HttpsRestClient,SubscriberAccount 依赖 RecurlyClient,而 RecurlyClient 也依赖 HttpsRestClient。
- 识别设计缺陷
- 逻辑与基础设施未分离,SubscriberAccount 直接依赖 RecurlyClient。
- SubscriberAccount 功能不明确,用户相关逻辑由单独的 User 类负责。
- 基础设施类(PersonaClient、RecurlyClient 和 HttpsRestClient)和登录端点都没有测试,存在风险。
- 确定改进重点 :由于缺乏可测试性是最大问题,决定先使 HttpsRestClient 可空,并添加窄集成测试,然后逐步使其他类可空,最后实现 Auth0Client。
- 逐步重构代码
1. 为 HttpsRestClient 添加窄集成测试并清理边缘情况(3 小时)。
2. 使 HttpsRestClient 可空(1 小时)。
3. 使 RecurlyClient 可空(1.25 小时)。
4. 使 PersonaClient 可空(0.75 小时)。
5. 修改 HttpsRestClient 以更好支持 Auth0Client 的需求(0.75 小时)。
6. 实现 Auth0Client(2 小时)。

完成 Auth0Client 后,实现一个功能标志,用于在生产环境中手动测试 Auth0 登录端点,同时对普通用户隐藏。同样采用反思性设计方法,审查相关类,识别测试问题并进行改进。

9. 逆向工程设计

反思性设计的第一步是分析现有代码并逆向工程其设计。最好的方法是向团队成员请教,通过白板草图进行交流,这种方式学习快且易引发协作改进。

若团队无人了解设计或想自己深入研究,可从思考源文件的职责入手,选择与当前任务最相关的文件,通常可从用户界面开始追踪依赖关系。

打开文件后,浏览方法和函数名,确认或修正对文件职责的猜测,还可查看测试名获取更多线索。分析文件的依赖关系,重复此过程直到依赖与当前更改无关。

了解涉及的文件和职责后,查看它们之间的关系,复杂时可绘制图表,可使用正式建模技术或临时草图,手动绘制能更深入理解代码。

10. 识别改进点

寻找设计改进时,要记住所有代码都有潜在的美感。不要轻易认为代码糟糕,即使代码看似不佳,也可能有其背后的设计意图。开发者应理解代码的原始设计,找出其中的闪光点并进行改进。

综上所述,简单设计和反思性设计在软件开发中具有重要意义。通过合理运用结对编程、重构、集体代码所有权等方法,以及遵循反思性设计的流程,开发者能够提高代码的质量和可维护性,更好地应对不断变化的需求。在实际开发中,应根据具体情况灵活选择设计方法,不断优化代码,以实现高效、简洁的软件开发目标。

软件开发中的简单设计与反思性设计实践

11. 反思性设计的优势和挑战

反思性设计在软件开发中具有显著优势,但也面临一些挑战,以下为你详细分析:

方面 优势 挑战
灵活性 只关注当前更改,能快速响应需求变化,避免过度设计 需要开发者具备较强的分析和重构能力,对开发者要求较高
代码质量 通过不断改进代码,使代码更简洁、易理解和维护 频繁的重构可能引入新的错误,需要完善的测试机制保障
团队协作 促进团队成员交流,有助于知识共享和共同提升 可能因成员理解差异导致重构方向不一致,需加强沟通协调
12. 反思性设计与其他设计方法的比较

为了更好地理解反思性设计,将其与预测性设计进行对比,具体如下:

设计方法 设计理念 适用场景 优点 缺点
预测性设计 预测未来需求,提前构建支持变化的设计 需求相对稳定、可预测的项目 能提前规划,减少后期大规模更改 依赖准确预测,预测偏差会导致大量重写代码
反思性设计 关注当前更改,根据实际情况改进代码 需求变化频繁、不确定的项目 灵活适应变化,逐步优化代码 对开发者能力和团队协作要求高,可能短期效率不高
13. 反思性设计的应用建议

在实际应用反思性设计时,可参考以下建议:
- 培养反思习惯 :开发者在日常工作中要时刻关注代码设计,遇到问题及时反思并寻求改进。
- 加强团队协作 :团队成员之间要积极交流,分享对代码设计的看法和经验,共同推动代码优化。
- 结合测试驱动开发 :在重构代码过程中,利用测试驱动开发确保代码功能的正确性,降低引入新错误的风险。
- 持续学习和实践 :不断学习新的设计理念和技术,通过实践积累经验,提高反思性设计的能力。

14. 反思性设计的未来发展趋势

随着软件开发行业的不断发展,反思性设计也将呈现一些新的趋势:
- 与人工智能结合 :借助人工智能技术分析代码,自动识别设计缺陷并提供改进建议,提高反思性设计的效率和准确性。
- 更注重用户体验 :在设计过程中,不仅关注代码的技术层面,还会更加注重用户体验,使设计更贴合用户需求。
- 跨领域融合 :与其他领域的设计方法和理念融合,如敏捷设计、精益设计等,形成更全面、高效的设计体系。

15. 总结

简单设计和反思性设计是软件开发中非常重要的理念和方法。简单设计通过自我文档化代码、合理处理发布接口、科学进行性能优化等,确保代码简洁、易维护;反思性设计则以关注当前更改、不断改进代码为核心,能够灵活应对需求变化,提升代码质量。

在实际开发中,开发者应根据项目的特点和需求,灵活运用这些设计方法。同时,要不断学习和实践,提高自身的设计能力和团队协作水平。通过持续优化代码,我们能够打造出更高效、更稳定的软件系统,满足不断变化的市场需求。

以下是反思性设计的整体流程 mermaid 流程图,帮助大家更清晰地理解:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px

    A([开始]):::startend --> B(分析现有代码):::process
    B --> C(识别设计缺陷):::process
    C --> D(选择改进点):::process
    D --> E(逐步重构代码):::process
    E --> F{是否完成任务且代码干净}:::decision
    F -- 否 --> C
    F -- 是 --> G([结束]):::startend

希望本文能为软件开发人员在设计和开发过程中提供有益的参考,让大家在面对复杂多变的软件开发任务时,能够更加从容地运用简单设计和反思性设计的方法,提升软件的质量和开发效率。

通过短时倒谱(Cepstrogram)计算进行时-倒频分析研究(Matlab代码实现)内容概要:本文主要介绍了一项关于短时倒谱(Cepstrogram)计算在时-倒频分析中的研究,并提供了相应的Matlab代码实现。通过短时倒谱分析方法,能够有效提取信号在时间倒频率域的特征,适用于语音、机械振动、生物医学等领域的信号处理故障诊断。文中阐述了倒谱分析的基本原理、短时倒谱的计算流程及其在实际工程中的应用价值,展示了如何利用Matlab进行时-倒频图的可视化分析,帮助研究人员深入理解非平稳信号的周期性成分谐波结构。; 适合人群:具备一定信号处理基础,熟悉Matlab编程,从事电子信息、机械工程、生物医学或通信等相关领域科研工作的研究生、工程师及科研人员。; 使用场景及目标:①掌握倒谱分析短时倒谱的基本理论及其傅里叶变换的关系;②学习如何用Matlab实现Cepstrogram并应用于实际信号的周期性特征提取故障诊断;③为语音识别、机械设备状态监测、振动信号分析等研究提供技术支持方法参考; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,先理解倒谱的基本概念再逐步实现短时倒谱分析,注意参数设置如窗长、重叠率等对结果的影响,同时可将该方法其他时频分析方法(如STFT、小波变换)进行对比,以提升对信号特征的理解能力。
先看效果: https://pan.quark.cn/s/aceef06006d4 OJBetter OJBetter 是一个 Tampermonkey 脚本项目,旨在提升你在各个在线评测系统(Online Judge, OJ)网站的使用体验。 通过添加多项实用功能,改善网站界面和用户交互,使你的编程竞赛之旅更加高效、便捷。 ----- 简体中文 ----- 安装 主要功能 安装脚本,你可以获得: 黑暗模式支持:为网站添加黑暗模式,夜晚刷题不伤眼。 网站本地化:将网站的主要文本替换成你选择的语言。 题目翻译:一键翻译题目为目标语言,同时确保不破坏 LaTeX 公式。 Clist Rating 分数:显示题目的 Clist Rating 分数数据。 快捷跳转:一键跳转到该题在洛谷、VJudge 的对应页面。 代码编辑器:在题目页下方集成 Monaco 代码编辑器,支持自动保存、快捷提交、在线测试运行等功能。 一些其他小功能…… [!NOTE] 点击 网页右上角 的 按钮,即可打开设置面板, 绝大部分功能均提供了帮助文本,鼠标悬浮在 ”? 图标“ 上即可查看。 使用文档 了解更多详细信息和使用指南,请访问 Wiki 页面。 如何贡献 如果你有任何想法或功能请求,欢迎通过 Pull Requests 或 Issues 我们分享。 改善翻译质量 项目的非中文版本主要通过机器翻译(Deepl & Google)完成,托管在 Crowdin 上。 如果你愿意帮助改进翻译,使其更准确、自然,请访问 Crowdin 项目页面 贡献你的力量。 支持其他OJ? 由于作者精力有限,并不会维护太多的类似脚本, 如果你有兴趣将此脚本适配到其他在线评测系统,非常欢迎,你只需要遵守 GP...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值