小简博客 - 计算机科学
type: channel
link: https://blog.ixor.me/tag/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/
items: 简约至上：架构不是搞复杂设计
items: 闯进 Kubernetes 的世界
items: 敏捷开发并非一味的追求交付速度
items: 代码整洁之道[命名篇]

简约至上：架构不是搞复杂设计
type: item
date: 2025-07-04T09:08:17+00:00
description: “优秀的架构不是用来炫技的，而是用来被维护的。”在软件行业，有一种流行病，叫做“复杂崇拜”。你一定见过这样的人 ——— 满口黑话：异步解耦、分布式一致性、熔断限流、消息中间件、CQRS 架构……仿佛不整出一张 10 层箭头的系统设计图，就不足以显得自己高级。他们一边把架构图画得像地铁线路图一样错综复杂，一边暗自觉得自己掌握了“架构的真正奥义”。但真相是：真正高级的架构，不是堆砌复杂，而是穿越复杂之后的极致简单。架构不是炫技，而是做减法架构的真正价值，从来不在于你能画出多炫的图，而在于：三年后新来的工程师是否能看懂代码业务变了十次之后系统还能否撑得住出了线上问题五分钟内是否能排查出原因系统演进不靠“行业大佬”，而靠“新人小白”也能维护一个架构算不算做得好，最大特征是“平淡无奇地稳定运行”。而很多所谓“为未来扩展做准备”的复杂设计，其实都只是自我感动。比如：明明一个本地进程通信就能解决的问题，却非得上分布式消息中间件明明日均几千请求，就开始上 Redis 实现接口缓存来防止所谓的“高并发”明明数据库还跑得飞快，就先分库分表、引入复杂的读写分离设计结果系统没有变强，却让开发流程变得又臭又长，维护人员每天都可能踩到雷。架构的首要目标，从来不是过度的考虑未来可扩展性，而是现在好维护，未来能演进。“敏捷”不是“加班加点”上线还有一个常见误区：把“敏捷开发”当成“加速开发”或“加班上线”的代名词。他们以为敏捷就是快速迭代、天天站会、两天一发布、三天一通宵。结果就是冲着冲着整个系统就废了，开发者还直接被干趴。敏捷，不是“快”，而是“稳”。敏捷的核心思想是：持续演进，不是一次性交付小步快走，每次只动一小部分高频反馈，问题早发现早处理开发健康，不是靠透支时间来冲量敏捷不是“把半年活压缩成一个月干完”，而是“把半年活拆成六个合理的小版本，有节奏地落地”。真正的敏捷，是合理的节奏 + 可持续的开发 + 稳定的输出。不是压榨，不是内卷，不是加班文化的遮羞布。过度设计，是架构师最大的毒瘤很多架构师的“第一性冲动”是：我要做出一个未来 5 年都能承载增长的系统。我得做“大而全”的平台型架构，我要设计出一套“未来也许有用”的系统组件。他们最喜欢说的话是：“以后业务量上来怎么办？”、“以后多个业务线怎么办？”、“以后多人协同怎么办？”听起来很有远见，实际上是：在你没啥用户的时候就分库分表在你没有异步需求时就上 MQ 解耦在你只有 3 个模块时搞微服务拆分在你明明写个 PHP 或者 Node.JS 就能做好的项目时，却非要用 Java + 微服务 + 各种分布式中间件这不是架构设计，是“过度想象下的灾难演练”。一个好架构师，首先是个清醒的人。他懂得判断什么是必要的复杂，什么是自找的复杂。系统的复杂度，应该随着业务真实演进而渐进式增长，而不是一开始就“全副武装”。语言选型，不是炫栈追潮流有些“潮流型架构师”，做技术选型不看场景，而是看热度。比如：一个数据管理后台页面，硬是要用 Java 搞全套分层，Service、Controller、DTO、注解全齐，而不愿意使用 PHP 来快速实现一个脚本型的批处理任务，非得用 Scala 或 Go 来实现所谓的“高性能并发”处理一个小站点访问量不高，还用 Rust 重构，说是为了“未来可扩展”考虑问题是，你连“现在能跑起来”都做不好，还谈什么未来？有时，用 JS、PHP、Python 写清楚、跑得顺，才是真正的工程智慧，而不一定非要去使用SpringBoot 这种庞大的框架。语言没有贵贱，只有适配度。系统没有模板，只有场景匹配。技术选型永远不该成为炫耀的资本，而应是对项目负责的体现。复杂架构的沉没成本与局部理性陷阱复杂架构最可怕的一点，是它一旦落地，就很难回头。比如：为了“提升性能”，加了缓存为了“系统解耦”，加了 MQ为了“统一网关策略”，加了 API Gateway为了“未来扩展”，搭了中台架构每一步看起来都合理，都是“工程常识”。但你最终会发现：一个简单的功能，却要调通五个系统一个小 bug，要翻七份日志、跨三条调用链才能查到新人根本不敢动代码，开发流程极其依赖“老司机”来兜底最恐怖的是，明知道设计多余，但没人敢删，因为大家已经“投入太多”了这就是沉没成本陷阱：一旦系统建起来了，就只能继续堆，一堆便堆出个永远无法重构的庞然巨物。更深层的问题是，很多架构师陷入了“局部理性”陷阱：“缓存是对的，消息队列是对的，分布式锁也是对的。”每一个选择都合理，但加起来系统就不合理了。系统设计不能只看“每一块对不对”，而要看“合起来有没有病”。架构的难点，从来不是“如何加”，而是“懂得何时不加、敢于删减与重构”。真正高级的架构师，是在每一次评审中反复问自己：这个组件我现在真的需要吗？如果不加它，有没有严重后果？如果我加了它，以后能不能容…

闯进 Kubernetes 的世界
type: item
date: 2025-06-06T10:04:00+00:00
description: 第一章：Kubernetes (K8s) 入门：容器化应用的智能管理系统你正在构建一个应用程序，它最终会服务成千上万的用户。当你的应用程序只是一个简单的“程序包”时，你可能可以手动管理它。但当这个“程序包”需要运行几十、几百甚至几千份，并且要保证它们随时在线、协同工作时，手动管理就变得不可能。这时候，你会想创建一个系统，它能像一个智能机器人一样，自动帮你管理这些应用程序副本。让我们回到 K8s 诞生的地方——Google。1.1 K8s 的前世今生：Google 的解决方案在 K8s 出现之前，也就是本世纪初的 Google，一群顶尖的工程师也面临着同样的问题，只不过规模要大得多：他们有数以万计的应用程序和数十万台服务器。手动部署、管理、扩缩这些应用程序简直是天文数字般的挑战。于是，Google 内部诞生了一个名为 Borg 的系统。Borg 是一个高度自动化的集群管理系统，它能高效地在 Google 的服务器集群上调度和运行应用程序。Borg 的成功，使得 Google 能够以惊人的效率和规模运行其各项服务，从搜索到 Gmail，无一不是受益于其强大的自动化能力。随着时间的推移，容器技术开始普及。Google 意识到，Borg 的核心理念和实践可以被抽象出来，并推广给更广泛的开发者社区。于是，他们借鉴 Borg 的经验，重新设计并开源了一个全新的项目——这就是 Kubernetes (K8s)。K8s 就像是 Borg 的“开源精华版”，将 Google 内部大规模系统管理的宝贵经验带给了全世界。1.2 K8s 的核心价值：为什么我们需要它？当你的应用程序需要在大规模分布式环境中稳定运行，并具备高可用性、弹性伸缩能力时，手动运维会迅速变得复杂且不可靠。K8s 的存在，正是为了解决这些痛点，它提供了一套完整的解决方案，让你的应用程序能够“活下来、跑得好”：自动化运维： K8s 能够自动化处理应用程序的部署、更新、扩缩容、故障恢复等几乎所有运维任务。你无需手动干预，只需定义应用程序的期望状态，K8s 就会自动使其达到并维持该状态。这极大地减少了人工错误和运维负担。高可用性与自愈： K8s 持续监控应用程序和其运行环境的健康状况。一旦发现故障（如某个应用程序实例崩溃、某个服务器宕机），它会自动进行故障转移、重启受损实例或重新调度，确保服务不中断，实现系统的高可用性。弹性伸缩： 随着业务负载的变化，K8s 能够根据预设规则自动增加或减少应用程序的运行实例数量。这意味着你的应用程序可以根据实际需求动态调整资源，高峰期应对自如，低谷期节约成本。资源高效利用： K8s 能够智能地将应用程序调度到集群中资源最适合的服务器上，优化资源分配。它就像一个精明的“调度员”，确保每台服务器的计算资源都得到充分利用。简而言之，K8s 的核心用处在于将复杂的、手动的、易出错的分布式应用管理过程，转变为自动化、可靠且高效的模式。它让开发者和运维人员能够专注于应用程序本身，而不是底层的基础设施管理。1.3 K8s 与 Docker Compose 有何不同？：适用场景的差异那么，有人就问了：既然 Docker Compose 也能管理多个容器，那 K8s 又有何不同？关键在于它们设计的规模和场景：Docker Compose 更适用于在单台机器上管理和运行少量相互关联的容器。它像一个“小团队的指挥官”，适合本地开发和测试环境。Kubernetes (K8s) 则专为分布式、大规模的生产环境而生。它能将应用程序部署到多台服务器（集群）上，提供自动故障转移、负载均衡、水平伸缩等高级功能。K8s 就像一个“大型舰队的总司令”，能协调成百上千甚至上万个容器在不同服务器上高效运作，即便有服务器宕机，也能保证服务不受影响。1.4 K8s 的核心理念：声明式控制K8s 的强大之处在于它的“声明式”管理模式。你声明目标，K8s 负责实现： 你不需要告诉 K8s 如何一步步执行任务（“先启动服务器 A，再部署程序 B”）。你只需声明你希望的最终状态（“我需要 5 个应用程序实例在运行，版本为 2.0”）。自动调整： K8s 会持续检查当前状态是否符合你的声明。如果发现不符，它会主动采取行动，直到达到你定义的目标状态。并且，它会一直维护这个状态。当然，很多读者可能难以理解上述所说的“声明式”管理模式到底是怎么样的一个机制，不用着急，听我继续娓娓道来。第二章：深入 K8s 世界——核心概念与组件在第一章中，我们了解了 K8s 的诞生背景、其核心价值以及声明式管理理念。现在，是时候揭开 K8s 这座“智能机器人”的内部构造了。我们将从 K8s 的基本组成单位开始，逐步认识那些协同工作，共同支撑你的应用程序稳定运行的关键概念。2.1 K8s 的“骨架”：集群 (Cluster)K8s…

敏捷开发并非一味的追求交付速度
type: item
date: 2025-02-11T06:57:51+00:00
description: 自2001年《敏捷宣言》发布以来，敏捷开发（Agile Development）逐渐成为软件工程领域的主流方法论。然而，许多人对敏捷开发的认知仍停留在“快速交付”、“压缩时间”的层面，甚至将其等同于“加班赶工”或“牺牲质量的短期冲刺”。这种误解不仅背离了敏捷的核心理念，还可能导致团队陷入效率陷阱，最终损害产品价值。本文将从敏捷开发的起源、核心原则、工程方法论及管理实践等多维度展开论述，揭示敏捷开发的本质是通过灵活协作与持续优化实现高质量交付，而非单纯的时间压缩。敏捷开发的核心：为什么‘快’不是首要目标？敏捷开发的起源可以追溯到对传统瀑布模型的反思。20世纪90年代，软件开发面临需求频繁变更和市场不确定性，传统的‘计划驱动’模式逐渐暴露出适应性差的问题。敏捷宣言提出的四大核心价值观：个体与互动高于流程与工具、可工作的软件高于详尽的文档、客户合作高于合同谈判、响应变化高于遵循计划。它们均指向一个核心：以灵活性和适应性应对复杂性。 “快速交付”仅是敏捷的表象，其本质在于通过短周期迭代（如Scrum的Sprint）实现持续反馈与调整。例如，Scrum框架中每个冲刺（Sprint）的结束并非单纯追求功能完成，而是通过评审会议（Review）和回顾会议（Retrospective）确保交付物与客户需求对齐，并优化团队协作流程。因此，敏捷的“快”是通过减少浪费（如无效文档、重复返工）实现的效率提升，而非盲目压缩时间。通过结构化流程保障质量敏捷开发倡导‘完成胜于完美’，但这并不意味着妥协质量。其工程实践确保质量与效率的平衡，具体体现在以下几个方面：测试驱动开发（TDD）与持续集成（CI） XP（极限编程）要求开发者先编写测试用例，再实现代码，确保每一行代码均通过验证。结合持续集成（每日多次代码合并与自动化测试），团队能在早期发现缺陷，避免后期修复的高成本增量式交付与最小可行产品（MVP） 敏捷团队通过拆分需求为“用户故事”（User Story），优先交付高价值功能，逐步扩展产品能力。例如，FDD（特征驱动开发）以“特征”为最小单位，每两周完成一个可测试、可部署的增量。这种模式减少了“一次性交付”的风险，同时确保每个迭代成果具备实际价值。重构与代码集体所有权 XP倡导“持续重构”以保持代码简洁，并通过“结对编程”实现知识共享与质量把控。这种机制避免了因追求速度导致的代码腐化，为长期维护奠定基础。通过协作与自组织提升效率敏捷团队的高效并非源于时间压缩，而是通过透明化协作与自组织机制实现的资源优化：角色定义与职责透明 例如，在Scrum框架中，产品负责人负责确定需求优先级，Scrum Master确保团队的高效协作，开发团队自主规划并执行任务。这种角色分配能够显著提高决策效率，避免传统管理中的层级冗余。每日站会与可视化工具 通过每日15分钟的站会，团队成员同步进展与问题，结合看板（Kanban）或燃尽图（Burndown Chart）可视化进度。这种机制减少了信息不对称，使团队能够快速调整计划而非被动加班。客户持续参与与反馈循环 敏捷强调客户作为团队的“利益相关者”全程参与，例如在迭代评审中直接验证功能。这种闭环反馈机制避免了因需求误解导致的返工，从根源上缩短了无效开发时间。敏捷如何重塑组织基因？敏捷开发的核心挑战在于组织文化与思维方式的转型，这要求企业不仅调整工具与流程，更需在根本上改变工作方式和管理观念。许多企业仅将敏捷视为“项目管理工具”，却忽视了其背后“以人为本”的哲学内核，最终陷入“形似神离”的困境。持续改进（Kaizen）与学习型组织 敏捷文化的核心是拥抱不确定性，并通过“实验-反馈-调整”的循环实现进化。例如，丰田生产体系中的“改善（Kaizen）”理念强调微小但持续的优化，与敏捷回顾会议（Retrospective）的“反思-行动”机制高度契合。麻省理工学院教授彼得·圣吉在《第五项修炼》中指出，学习型组织的核心能力是“系统性思考与自我超越”，而这正是敏捷团队通过迭代实践培养的关键能力。心理安全与赋能型领导力 谷歌‘亚里士多德计划’的研究表明，高效团队的关键特征是心理安全（Psychological Safety）——团队成员能够畅所欲言，不担心被否定。 敏捷框架中的“自组织团队”要求管理者从“命令控制者”转变为“赋能者”，例如Scrum Master的核心职责是移除障碍而非分配任务。这种转变打破了传统层级制的权力结构，使团队能够基于信任快速决策。企业级敏捷的陷阱与突破 当敏捷从团队层面向企业扩展时，规模化框架（如SAFe、LeSS）常因过度流程化而背离敏捷初心。例如，SAFe（Scaled Agile Framework）被批评为“披着敏捷外衣的瀑布模型”，其复杂的角色定义与计划周期可能扼杀灵活性。成功的规模化敏捷需要“原则优先于…

代码整洁之道[命名篇]
type: item
date: 2024-05-19T13:37:00+00:00
description: 好的代码并不是说你写的有多么高深莫测，多么华丽，代码是给开发者来阅读的，能够让人更好的读懂、能够更好的实现业务、能够展示更加清晰优雅的逻辑的代码，就是好代码。本篇章结合《代码整洁之道》以及自身经验阐述的一些方法，欢迎关注我的公众号：栈堆溢出。名副其实使用正确的名称来描述你所定义的内容非常重要！有人说：”思考名称的时间太浪费了，与其花时间想名称，不如直接开始快速编码。“我想说的是，选取一个好的名称可能需要一定的时间，但是这样绝对可以节省你之后维护和其他人阅读的时间成本，作为开发者，要有长远的目光，不能只顾当前，需要综合长远发展考虑。千万莫要只看眼前发展：井蛙不可以语于海者，拘于虚也；夏虫不可以语于冰者，笃于时也；曲士不可以语于道者，束于教也。——《庄子.秋水》一旦发现了更好的名称，就应该换掉旧的名称，如果某一天，你的同事或者其他人来询问你某个属性或者函数等命名是什么意思，那么你就应该思考应该怎样换一个更加容易看懂并且贴合业务功能的名称了。一个好的命名往往比注释更重要，我们不能直接依赖注释，注释主要是对复杂实现和无法简短描述的功能的说明补充，规范的doc注释同时也是为了生成对应语言的doc而考虑。一个好的函数、变量或者类名称它应该能够告诉你它为什么存在，它做什么事情，如何使用。如果名称需要使用注释来解释和补充说明，那它就不是名副其实的，除非过于复杂无法简单描述。比如，当你想要描述一个简单的从数据库直接拿到数据的函数，你可以使用getXXXByDB，当然，你也可以有一套自己或者公司的命名规范，但是一切都是为了让命名更加清晰。如果上述功能涉及到了复杂的查找操作，不妨将名称改为findXXXByDB，你也可以选择将中间的by改为其他词汇，如findXXXInDB。如果你只是getXXX，或许这并不详细，如果代码量较少并且清晰的话，自然没问题，如果场景复杂，你需要从很多不同的数据库中查找相同概念的数据，那么这个名称就需要加上你的操作的具体指向，如getNameInCache、getNameInDB、findNameInCookieBasisUID。当然，如果名称过长也不太好，尽可能思考如何简短并有效的描述，同时结合上下文(比如函数结合类中其他逻辑和属性)来尽可能减少不必要的场景描述词。比如你已经在UserEntity类中了，那么属性命名只需要type name就可以，类名已经可以说明场景了，如：long id在UserEntity中我们自然知晓他是属于User的id。但是，如果你说，其他开发者英语不好，那么就有些为难了，因为中文编程至少现在还不够普及与成熟，更别提大范围的企业级应用了，所以作为开发者，我们还是需要学习学习自己有需要的语言，比如英语。还有！尽可能的避免魔法值或者魔法状态，将魔法值尽可能的内敛，向外抛出更加语义的命名，比如if(xxx == 1)改为if(xxx.isXXX)，事实上，你可以尽可能避免使用==来作为逻辑判断语法中的条件，而是选择将它的判断内敛为一个直接的具有语义的方法，这样可能可读性会增强。如果你不知道魔法值是什么，我相信你聪明的大脑一定可以获取到答案，比如？浏览器！避免误导请避免留下掩藏代码本意的错误线索，比如你感觉某个单词不好看而替换一个语义更加薄弱却美观的词汇，这并不是说不需要注意代码整洁与美观，而是应当可读性优先在前。又或者你想表示一组账户信息的集合，使用accountOfList，但是实际上集合是一个不可重复集合，那么实际上你使用的类型是Set，那么你需要精确的描述它，应当改为accountOfSet。还有！除非某个概念的缩写是独有的，否则不要使用它！比如你使用cos来表示余弦函数，但是不确定是否其他的开发者会给你误解为角色扮演的那个cos，又或者腾讯云的对象存储产品cos。有意义的区分对于有些数据，我们给他命名为xxxData或者xxxInfo，这种命名实际上是冗余的，因为他作为一个属性值，我们已经知道xxx是一个数据了，而Data和Info无疑是在告诉我们，他是一个数据，这是没有必要的，当然，如果你需要在某些特殊场景下强调他是一个数据的话，可以这样做。不说废话会让命名更加简洁和内聚，就像table一词永远不能出现在表名称中，因为你已经知道它是一个表了。你会觉得NameString会比Name更好吗？对于上文的accountOfSet，如果他已经很明确的可以知道他是一个Set的话，那么也没有必要使用OfSet，尤其是有强大的IDE类型反应的情况下。名称标准可读请不要使用非标准的词汇或者由社会发展而衍生出来的网络新词汇，除非他被编入了标准字典。请不要使用自造词汇或者非标准的组合词汇，如果你不需要考虑其他国家开发者的阅读和使用，那么你可以适当使用中式英文词汇，但是最好不要这样。比如，xxxInEvery…