《软件设计的哲学》阅读摘要之设计原则

news2024/12/25 10:38:59

在这里插入图片描述

《软件设计的哲学》(A Philosophy of Software Design)是一本在软件架构与设计领域颇具影响力的书籍,作者 John Ousterhout 在书中分享了诸多深刻且实用的软件设计理念。书中列举的这些设计原则,汇聚了作者丰富的实战经验与深邃的思考,给软件开发者们提供了高屋建瓴的指导,助力大家在项目中打造出更具可维护性、扩展性的软件系统。
本书名称叫做“哲学”,其实更像是一本指导书,里面的具体原则比经常听到的“强内聚,弱耦合,单一原则“等等,更加具有实践指导意义。这里列举一些重要的原则要点16条:

序号原则名称
1复杂性是渐进的,需关注细节(Complexity is incremental; you have to sweat the small stuff)
2工作代码并非足够(Working codes isn’t enough)
3持续进行小的投入以改进系统设计(Make continual small investments to improve system design)
4模块应具有深度(Modules should be deep)
5设计接口应使常见用法尽可能简单(Interfaces should be designed to make the most common usage as simple as possible)
6模块拥有简单接口比简单实现更重要(It’s more important for a module to have a simple interface than a simple implementation)
7通用目的模块应更具深度(General-purpose modules are deeper)
8分离通用目的和特定目的的代码(Separate general-purpose and special-purpose code)
9不同层次应具有不同的抽象(Different layers should be different abstractions)
10将复杂性向下拉(Pull complexity downward)
11定义错误使其不存在(Define errors out of existence)
12设计两次(Design it twice)
13注释应描述代码中不明显的内容(Comments should describe things that are not obvious from the code)
14软件应设计为易于阅读,而非易于编写(Software should be designed for ease of reading, not ease of writing)
15软件开发的增量应是抽象,而非功能(The increments of software development should be abstraction, not features)
16区分重要事项与不重要事项,并着重关注重要的部分(Separate what matters from what doesn’t matter and emphasize the things that matter.)

1. 复杂性是逐步累积的;你必须关注细节 (Complexity is incremental; you have to sweat the small stuff)

  • 含义与理解:软件系统的复杂性并非一蹴而就,而是像滚雪球一般,从项目伊始的细微之处慢慢积攒起来。起初看似微不足道的小决策、小代码片段,随着系统不断拓展与迭代,可能引发一系列连锁反应,使整体复杂度飙升。忽略细节,就如同埋下一颗颗定时炸弹,随时可能引爆大规模的技术难题。
  • 示例:开发一款餐饮外卖 APP,最开始在设计订单备注功能时,如果没仔细考虑字符长度限制、特殊字符过滤这些小细节,短期内或许不影响使用。但当业务量增大,遇到一些恶意输入或者超长备注需求时,就可能导致数据库存储出错、订单处理流程紊乱,后续修复涉及多个模块联动,复杂性大幅提升。

2. 能运行的代码还远远不够 (Working codes isn’t enough)

  • 含义与理解:仅仅实现代码的基本运行功能,只是迈出软件开发的第一步。软件并非一次性产品,后续的升级、维护以及功能拓展需求源源不断。若初期只为“跑起来”而仓促编码,忽略架构的合理性、代码的可扩展性与可维护性,后续项目生命周期里,每一次优化与新增功能都将举步维艰。
  • 示例:一个简单的个人博客网站,早期用最简易的代码拼凑实现了文章发布和浏览。但随着博主想要添加社交分享按钮、评论区实时互动、多设备适配等功能时,由于一开始没有采用模块化架构、分层设计,代码搅成一团乱麻,新增功能的难度呈指数级增长,甚至可能要推翻重来。

3. 持续投入小成本来改进系统设计 (Make continual small investments to improve system design)

  • 含义与理解:系统设计并非一劳永逸,而是需要在开发全程,不间断地投入少量精力与资源去优化。这些微小投入看似不起眼,却能在长期积累下,让系统的架构愈发稳固、高效,从容应对业务的动态变化,避免后期因架构老化而付出高昂的重构代价。
  • 示例:以一款日程管理 APP 为例,每次小版本迭代时,开发团队不只是忙着堆砌新功能,还会抽出部分时间重构数据库查询语句,优化界面渲染逻辑。虽然每次改进的效果不那么显著,但随着时间推移,当用户量持续攀升,APP 在处理海量日程数据时依然流畅,新功能也能毫无阻碍地整合进去。

4. 模块应当有深度 (Modules should be deep)

  • 含义与理解:模块的深度意味着它不应仅仅提供表面、单薄的功能,而是要深入挖掘业务需求,将相关的复杂功能聚合、强化,形成一套完整且强大的能力体系。有深度的模块更具内聚性,对外输出稳定、高效的服务,能显著提升整个系统的处理能力与灵活性。
  • 示例:在视频编辑软件里,特效添加模块不是简单罗列几种预设特效,而是深挖视频处理算法,融合色彩校正、光影变幻、动态跟踪等技术。无论是制作炫酷的短视频,还是专业影视剪辑,它都能深度满足创作者对画面特效的精细调控需求。

5. 接口的设计应使最常见的用法尽可能简单 (Interfaces should be designed to make the most common usage as simple as possible)

  • 含义与理解:接口作为模块与外界交互的桥梁,其设计优劣直接影响系统集成的难易程度。聚焦于最普遍的使用场景,把接口设计得简洁易懂,能极大降低其他模块与之对接的成本与门槛,提升开发效率,促进整个系统各部分的协同工作。
  • 示例:对于地图导航 SDK,众多开发者最常使用的功能就是定位与路径规划。优秀的 SDK 接口设计,只需开发者传入起点、终点位置信息,用极少的代码就能获取精准路线,屏蔽掉后台复杂的地图数据解析、算法优化过程,让接入过程轻松流畅。

6. 对于一个模块而言,拥有简单的接口比拥有简单的实现更重要 (It’s more important for a module to have a simple interface than a simple implementation)

  • 含义与理解:模块内部实现或许涉及复杂高深的算法与逻辑,但对外部使用者而言,他们无需关心这些内部细节。提供简单、清晰的接口,能够隐藏内部复杂性,让其他模块轻松调用,实现系统的低耦合,便于不同团队并行开发,保障整体架构的灵活性与扩展性。
  • 示例:在人工智能图像识别模块中,内部可能运用了深度卷积神经网络,训练过程繁杂且算力消耗巨大。但对外暴露的接口,仅需接收图片路径,就能直接返回识别结果,把复杂的运算封装起来,其他开发者不用钻研图像识别底层技术,就能快速集成该功能。

7. 通用模块更具深度 (General-purpose modules are deeper)

  • 含义与理解:通用模块旨在服务多种不同的业务场景,需要应对各式各样的需求变化,因此必须深挖功能、容纳丰富逻辑,构建起强大的通用能力。通用性越强,模块内部整合的知识、技术就越密集,深度也就自然显现出来。
  • 示例:在各类软件开发项目里,日志记录模块属于通用模块。它不仅要记录基本的时间、事件信息,还要支持不同级别日志分类、多线程安全写入、远程日志同步等复杂功能,以适配从桌面小程序到大型分布式系统的全方位需求。

8. 区分通用代码与专用代码 (Separate general-purpose and special-purpose code)

  • 含义与理解:通用代码具备复用潜力,能在多个不同场景、模块中发光发热;专用代码则服务于特定业务需求,针对性强。明确划分二者,能让代码库条理清晰,便于维护与管理,一方面提高通用代码的复用率,另一方面精准优化专用代码,互不干扰。
  • 示例:电商平台的商品展示页面,有通用的图片加载、布局渲染代码,这些可以抽离成通用模块,应用到其他商品分类甚至不同电商项目。而针对限时折扣商品特有的倒计时、闪烁特效代码,属于专用代码,单独封装,方便后续修改折扣逻辑,不影响通用展示模块。

9. 不同的层级应有不同的抽象 (Different layers should be different abstractions)

  • 含义与理解:软件架构分层构建,各层级肩负不同使命,对应不同的抽象层次。底层靠近硬件或基础资源,抽象程度低,处理具体事务;高层则聚焦业务逻辑,抽象程度高,从宏观视角统筹调度。合理分层与抽象,让系统层次分明,易于理解、开发与维护。
  • 示例:在企业级 ERP 系统里,底层数据库访问层直接操作数据表,执行增删改查,极为具象;中间业务逻辑层将底层操作抽象成订单处理、库存管理等业务单元;最上层的用户界面层,从用户视角抽象出便捷的操作流程与可视化界面,各层级各司其职。

10. 降低复杂性 (Pull complexity downward)

  • 含义与理解:随着软件系统的成长,复杂性悄然攀升,而开发者要主动出击,运用合理的架构调整、代码重构等手段,把复杂的逻辑梳理清晰,隐藏不必要的细节,下沉复杂实现,让核心业务流程简洁明了,提升系统的稳健性与可读性。
  • 示例:一款在线文档编辑工具,初始版本为兼容多种文档格式,代码充斥着大量格式转换的复杂判断与嵌套逻辑。后期重构时,把格式转换部分封装成独立底层模块,上层编辑操作只调用简洁接口,简化了编辑流程,降低了整体复杂性。

11. 将错误消灭在定义阶段 (Define errors out of existence)

  • 含义与理解:在软件开发前期,无论是需求分析、架构设计,还是接口定义环节,都要严谨地梳理规则、限定边界,提前预料可能出现的错误场景,并制定防范措施。从源头上把控,远比在测试、上线后再来处理错误成本更低、效果更好。在实现过程中,也要注意,一旦出现异常,就地解决,尽量减少向外或者向上抛出,减少异常处理的链条,减少复杂性。
  • 示例:开发在线考试系统,在需求定义时就明确规定答题时间格式、答案提交规则,代码编写伊始便严格校验输入合法性。如此一来,考试过程中因格式错误、非法提交引发的系统故障就能被扼杀在萌芽状态。

12. 进行二次设计 (Design it twice)

  • 含义与理解:软件首次设计受限于时间、认知等因素,很难尽善尽美。在获取一定的用户反馈、积累实际运行数据后,进行二次设计,基于真实场景重新审视架构、优化流程,能让软件更贴合市场需求,弥补前期不足,延长软件生命周期。
  • 示例:出行打车 APP 初次上线时,为抢时间匆忙确定了派单算法与司机乘客匹配机制。运营一段时间,收集大量数据与用户投诉后,二次设计优化算法,综合考虑距离、路况、司机服务评价等因素,大幅提升用户打车体验。

13. 注释应当描述那些从代码中看不出来的内容 (Comments should describe things that are not obvious from the code)

  • 含义与理解:代码虽然是程序员之间沟通的主要方式,但有些关键决策背景、设计意图仅凭代码难以呈现。注释就起到补充说明的作用,为后续维护者、协作者点明代码背后隐藏的业务考量、技术权衡,避免他人花费大量时间去揣测代码意图。
  • 示例:一段加密算法代码里,选用了一种非标准加密方式。代码里只能看到算法实现流程,而注释详细说明是因为项目特定的安全合规要求、数据传输环境限制,才采用该小众算法,让接手者瞬间明晰缘由。

14. 软件设计应着眼于便于阅读,而非便于编写 (Software should be designed for ease of reading, not ease of writing)

  • 含义与理解:软件开发是团队协作活动,一份代码在项目存续期会历经多人之手。易于阅读的代码,遵循规范命名、清晰分层、简洁逻辑,能让新成员迅速融入,理解业务流程,降低沟通成本。过于追求编写时的个人便利,会牺牲代码可读性,给后续维护带来巨大困扰。
  • 示例:大型开源项目代码库,变量命名全部采用语义化词汇,函数按功能模块清晰分组,代码注释详尽。即使新手加入团队,顺着代码结构与注释,也能较快搞清楚核心逻辑,投入开发工作。

15. 软件开发的增量应该是抽象,而非功能特性 (The increments of software development should be abstraction, not features)

  • 含义与理解:单纯不断堆砌新功能,会让软件陷入无序扩张,臃肿不堪。以抽象作为增量,意味着从现有功能中提炼通用模式、架构模式,用更高级的抽象框架去整合功能,提升软件的柔韧性与扩展性,从容应对未来变化。
  • 示例:一款音乐播放 APP,初期陆续上线本地播放、在线播放、歌单创建等功能。后续开发若以抽象为导向,提炼出媒体资源管理抽象层,就能轻松兼容新的音频格式、流媒体协议,而不是孤立地添加一个个播放功能。

16. 区分重要事项与不重要事项,并着重关注重要的部分 (Separate what matters from what doesn’t matter and emphasize the things that matter.)

  • 含义与理解:软件项目资源有限,无论是开发时间、人力,还是服务器算力。精准甄别核心业务流程、关键用户需求,把资源集中投入,保障关键部分稳定、高效运行,适当弱化次要环节,才能在资源约束下实现最优产出。
  • 示例:电商大促期间,电商平台最关键的是保障订单提交、支付成功、库存扣减这些核心链路顺畅无阻,页面上一些非关键的广告位更新、个性化推荐微调等非核心事务可以暂缓,集中火力服务好抢购用户。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2265237.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

远程控制macOS一直卡在100%,能连接上了却只显示了壁纸?

前言 前段时间有个朋友过来咨询关于Windows使用第三方远程软件(向日葵、Todesk等)远程连接控制macOS系统,但出现了一些奇奇怪怪的问题。 比如在连接的时候,一直卡在100%连接,对方的电脑却已经显示已经被控制的状态。…

Pytorch | 利用FGSM针对CIFAR10上的ResNet分类器进行对抗攻击

Pytorch | 利用FGSM针对CIFAR10上的ResNet分类器进行对抗攻击 CIFAR数据集FGSM介绍FGSM代码实现FGSM算法实现攻击效果 代码汇总fgsm.pytrain.pyadvtest.py 之前已经针对CIFAR10训练了多种分类器: Pytorch | 从零构建AlexNet对CIFAR10进行分类 Pytorch | 从零构建Vgg…

mapbox基础,加载mapbox官方地图

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象…

保护模式基本概念

CPU 架构 RISC(Reduced Instruction Set Computer) 中文即"精简指令集计算机”。RISC构架的指令格式和长度通常是固定的(如ARM是32位的指令)、且指令和寻址方式少而简单、大多数指令在一个周期内就可以执行完毕 CISC&…

【Unity3D】Particle粒子特效或3D物体显示在UGUI上的方案

目录 一、RawImage Camera RenderTexture方式 (1)扩展知识:实现射线检测RawImage内的3D物体 (2)扩展知识:实现粒子特效显示RawImage上 二、UI摄像机 Canvas(Screen Space - Camera模式)方式 &#…

编程新选择:深入了解仓颉语言的优雅与高效

初识仓颉编程语言 仓颉编程语言(Cangjie Programming Language)是一种现代化的、面向未来的通用编程语言,其设计理念是为了降低编程的门槛,同时提供高度灵活性和表达力的开发体验。这种语言以其简洁优雅的语法和直观的设计理念受…

vue3项目history路由模式部署上线405、刷新404问题(包括部分页面刷新404问题)

一、找不到js模块 解决方法:配置Nginx配置文件: // root /your/program/path/dist root /www/wwwroot/my_manage_backend_v1/dist;二、刷新页面导致404问题(Not found) 经过一系列配置后发现进入页面一切正常,包括路由前进和回退&#xff0…

谷歌开发者工具 - 控制台篇

Chrome DevTools - Console控制台篇 一、官网二、主要用途三、控制台篇1.JavaScript/浏览器消息记录(1)演示效果 / 两种记录状态(2)显示导致调用的堆栈轨迹 2.过滤消息(1)按日志级别过滤(2&…

003-aop-切点表达式

spring-aop-切点表达式 spring-aop-pom依赖

【蓝桥杯——物联网设计与开发】基础模块8 - RTC

目录 一、RTC (1)资源介绍 🔅简介 🔅时钟与分频(十分重要‼️) (2)STM32CubeMX 软件配置 (3)代码编写 (4)实验现象 二、RTC接口…

Web3.0安全开发实践:探索比特币DeFi生态中的PSBT

近年来,部分签名比特币交易(PSBT)在比特币生态系统中获得了显著关注。随着如Ordinal和基于铭文的资产等创新的兴起,安全的多方签名和复杂交易的需求不断增加,这使得PSBT成为应对比特币生态不断发展中不可或缺的工具。 …

MaxKB基于大语言模型和 RAG的开源知识库问答系统的快速部署教程

1 部署要求 1.1 服务器配置 部署服务器要求: 操作系统:Ubuntu 22.04 / CentOS 7.6 64 位系统CPU/内存:4C/8GB 以上磁盘空间:100GB 1.2 端口要求 在线部署MaxKB需要开通的访问端口说明如下: 端口作用说明22SSH安装…

【VMware虚拟机】安装win10系统教程双机可ping通

目录 1、下载1.1、点击链接下载媒体创建工具:1.2、下载后得到MediaCreationTool_22H2.exe:1.3、获取ISO镜像 2、安装3、显示4、配置网络4.1、配置4.2、排查4.2.1、关闭防火墙4.2.2、增加路由 1、下载 Windows10微软官网下载链接: https://www.microsoft…

AI一键制作圣诞帽头像丨附详细教程

我用AI换上圣诞帽头像啦~🎅 不管是搞笑表情、宠物头像还是你的自拍!!都能一键添加圣诞帽元素,毫无违和感!🎉 详细教程在P3、P4,手残党也能轻松搞定! 宝子们需要打“need”&#xff0…

活动图的理解和实践

在软件开发和系统设计中,理解系统的工作流程和并发行为是至关重要的。活动图作为一种重要的建模工具,为我们提供了一种直观且有效的方法来描述这些复杂的过程。本文将详细探讨活动图的理解与实践,包括其基本概念、用途、构建方法以及实际应用…

电磁兼容(EMC):一文解读磁芯复合材料——塑磁

目录 01 塑磁的定义 02 塑磁的常见规格型号 03 塑磁材料的优点 04 塑磁的应用 塑磁,也称为注塑磁,是一种将磁性粉末注入到塑料基体中制成的复合磁体材料。以下是塑磁的定义、应用和材料特性的总结: 01 塑磁的定义 塑磁是以塑料为基体,通过特殊工艺在其中加入磁性粒子(…

C语言-结构体内存大小

#include <stdio.h> #include <string.h> struct S1 { char a;//1 int b;//4 char c;//1 }; //分析 默认对齐数 成员对齐数 对齐数(前两个最小值) 最大对齐数 // 8 1 …

设计模式的主要分类是什么?请简要介绍每个分类的特点。

大家好&#xff0c;我是锋哥。今天分享关于【设计模式的主要分类是什么&#xff1f;请简要介绍每个分类的特点。】面试题。希望对大家有帮助&#xff1b; 设计模式的主要分类是什么&#xff1f;请简要介绍每个分类的特点。 1000道 互联网大厂Java工程师 精选面试题-Java资源分…

Java Web开发基础——Web应用的请求与响应机制

在本节中&#xff0c;我们将深入探讨Web应用程序中最为核心的部分之一——请求与响应机制。理解Web应用如何处理客户端请求并生成响应是成为Java Web开发者的关键。我们将从HTTP协议的基础知识开始&#xff0c;逐步过渡到请求参数的获取、响应内容的发送以及会话管理&#xff0…

免杀对抗—Behinder魔改流量特征去除

前言 在现实的攻防中&#xff0c;往往webshell要比主机后门要用得多&#xff0c;因为我们首先要突破的目标是网站嘛&#xff0c;而且waf也往往会更注重webshell的检测。webshell的免杀分为两个&#xff0c;一是静态查杀&#xff0c;二是流量查杀。静态查杀不用多说了&#xff…