找回密码
 立即注册
首页 业界区 业界 别让理论成为“紧箍咒”!打破开发教条主义做正确的软件 ...

别让理论成为“紧箍咒”!打破开发教条主义做正确的软件

古修蟑 2025-6-26 09:15:15
  “要是看到你在模板中写这种代码,很多人会怒不可遏。别理他们——他们都是教条主义的受害者。在模板里写代码没有任何不对,只要别写太多(尤其是别把业务逻辑放进模板)。”
  —— David Heinemeier Hansson 评论 MVC 模式中,V 中带有少量逻辑判断,摘自《应用 Rails 进行敏捷 Web 开发》中文版 第343页。
  David Heinemeier Hansson 这句直击灵魂的话,撕开了软件开发领域教条主义的虚伪面纱。在追求高效、规范开发的今天,开发模式和理论,本是助力我们的 “利器”,但却逐渐异化成了束缚开发者手脚的 “紧箍咒”。
软件开发的现实困局

  当我们撕开行业光鲜的表象,会发现当代开发者正置身于一个充满矛盾的环境。
  - 需求沼泽 在需求变更中艰难跋涉 需求冻结成为奢望,用户在模糊认知中不断迭代诉求,仿佛让建筑师在施工过程中反复修改蓝图。产品决策链中,缺乏技术背景的决策者以直觉驱动方案,那些违背工程逻辑的设计如同沙上筑塔,开发者在 "专业判断" 与 "执行指令" 的夹缝中进退维谷。
  - 效率绞肉机 内卷化下的工期压缩 行业正陷入 "跑马圈地" 的狂热,人效考核将开发周期压缩至极限。当竞品以 "单机部署非事务架构" 的粗糙方案抢占市场,我们不得不面对一个残酷现实:在资本竞速中,完善的技术架构往往让位于快速交付和低廉的成本。
  - 人才断层 经验传承的时代之殇 35岁职场红线造就年轻化开发团队,知识传承脱节,项目经验严重不足。视频教程催生的 "速成开发者" 虽降低入门门槛,却导致知识体系碎片化,让代码质量的根基悄然松动。很多人都沉迷于视频教程的快餐式知识投喂,鲜少真正触碰键盘敲下一行代码。这类伪专业人士,将大量时间消耗在观摩别人的技术实战,热衷于用精美架构包装空洞概念,动辄抛出 “微服务架构升级”、“AI 驱动转型” 等术语,却连最基础的代码都写不好。
  - AI 冲击 效率革命与职业焦虑的双刃剑 编程助手已能胜任 70% 的常规开发工作,在代码补全、注释生成等场景展现惊人效率。这把双刃剑既为项目提效注入强心剂,也让基础编码岗位面临重构压力,开发者被迫在 "工具依赖" 与 "核心竞争力构建" 之间寻找新平衡点。
不要为了架构而架构

TDD:国内项目我不想再看见它

  大约是2012年,我负责的一个外企的项目,约定使用 TDD 方式开发,并满足高测试覆盖率和交付相应代码和文档。这是我第一次接触 TDD,之前虽然也了解过但没有真正实操过。因为有甲方公司的业务顾问全程参与,需求变更较少,TDD 开发也算顺利。TDD 本身并不复杂,无非是一种开发方式和思维。借助 VS 的重构和单元测试工具进行 TDD 方式开发的过程很丝滑。该项目使我收获了相当宝贵的 TDD 实战经验。但那也是我唯一个没被 TDD 折磨的项目。
  之后的很多年,虽然用 TDD 项目的公司很罕见,但是,还是让我遇到了两家家向 TDD 开发模式转型的公司,两者均以失败告终。太痛苦了!测试用例的变化速度,完全跟不上需求的变更速度。而且,根本不会给你足够的时间设计测试用例、完善文档和单元测试,最终得到的就是——一堆对不齐需求的测试用例,大量无用的单元测试,开发为了测试构建的无用代码,以及项目大幅度延期和海量加班后的疲惫团队。
  TDD 存在以下弊端:
  - 额外提高工作量 TDD 要求在编码前完成测试用例设计,这对简单功能可能产生30%-50% 的额外开发时间。
  - 小型项目的投入产出失衡 在小微项目(如单页面应用、工具类程序)中,TDD 的测试架构搭建成本可能超过功能开发本身。
  - 需求变更时的维护噩梦 测试用例、单元测试代码、业务逻辑代码的连锁修改成本很高。
  - 对开发者技能的高要求 TDD 需要掌握单元测试框架、Mock 工具、重构等。
  - 僵化的设计约束 TDD 要求提前定义接口和行为,这在需求快速迭代的场景中往往导致测试用例成为 “设计枷锁”,限制架构调整,开发者为兼容旧测试而保留过时逻辑,堆积“屎山”
  - 过度设计与代码膨胀风险 为测试而牺牲的代码简洁性,引入不必要的接口(仅为便于 Mock),拆分过细的类(仅为便于测试)等。
  - 维护中的隐性成本 当项目迭代加快时,会出现“需求-测试用例-单元测试-业务逻辑”不同步的情况,逐步失去质量保障作用。
  TDD 的核心价值在于长期的代码质量保障,但其弊端提醒我们:技术实践需与项目特性、团队能力、业务节奏相匹配,盲目追求 “全TDD” 可能适得其反。
DDD:落地它的思想,抛弃它是束缚

  DDD 的本质是帮助开发者理解业务的思维工具,而非用设计模式堆砌的技术秀场。DDD 被炒作的有点神话了,DDD 立了很多规矩,这些规矩正在束缚我们。
  - 聚合根的神圣性 为满足 "聚合内强一致性",把简单的 "实体" 拆成多个聚合,本来一个方法内就能实现的需求,却要分散到多个方法调用实现,代码量暴增,性能却和可维护性下降。
  - 属性、无参构造器的私有化 DDD 强调 “数据与行为绑定”,聚合根的属性变更必须通过其领域方法(而非直接修改属性)完成,因此,就会将属性的 set 方法设为私有。为了不创建 “不完整” 的聚合根(如属性未初始化),就要将无参构造器私有化。私有化属性 set 方法和无参构造器,是实现 “数据只能通过行为变更” 的技术手段。这种做法在 DDD 上很严肃,但现实中真的感觉很难用。首先,代码复杂度增加,需要为每个聚合根设计工厂或领域方法,对简单业务可能 “过度设计”。其次,部分 ORM 框架存在兼容性问题,对私有构造函数支持不佳,需额外配置。
  - 通用语言的偏执 要求数据库表名、API 接口与领域术语完全对齐,会议上对命名争论不休。
  - 充血模型的神化 盲目的相信充血模型,在非复杂核心业务域强行套用充血模型,增加复杂度。在软件项目的“快节奏+高变更”战场中,“贫血模型+服务层”的务实架构反而更具生存力。
  - 领域层与服务层的腐化 领域逻辑与服务层逻辑的混淆是常见问题,两者职责边界模糊会导致系统架构混乱、维护成本激增。不同开发者对方法的具体实现位置存在争议是常见问题,开发过程中很难让全员达成共识。随着业务迭代、赶工,这种腐化会加剧,让“业务逻辑”分散和混乱。
  - 过细的限界上下文 过细领域割据引入了更多的功能划分、防腐层、领域事件问题,开发和调试时像剥洋葱一样痛苦,时常在不同上下文间迷路。
  - 设计文档的成本过高 往往前期需要投入大量的时间和精力完成 DDD 的设计文档,后期开发时间不足,在频繁变更和新需求加持下,前期的设计最终脱离最终现实,成为华丽的废纸。
  总之,能在预算内交付正确功能的系统,比完美却延期的领域模型更有价值。当你学会 "用 DDD 的眼睛看业务,用 CRUD 的手敲代码",就会发现:实现它的思想,抛弃它的束缚,才是对领域驱动最真诚的致敬。毕竟,能在预算内交付并应对变化的系统,才是复杂业务的真正赢家。
前后端分离:不是唯一的选择

  早期的 Web 开发采用 “前后端耦合” 模式,ASP.NET 等技术将页面逻辑与业务逻辑混杂在同一代码文件中。开发人员既要编写 HTML 样式,又要处理数据库查询和业务计算,代码臃肿且难以维护。随着互联网应用规模扩大,用户体验要求提升,这种模式的弊端愈发明显。
  2010 年后,随着 JavaScript 技术的成熟、SPA(单页应用)框架( AngularJS、React、Vue.js等)的兴起,以及 RESTful API 规范的普及,前后端分离迎来了爆发期。前端专注于用户界面渲染和交互逻辑,通过 API 接口与后端通信;后端则负责业务逻辑处理、数据存储与 API 接口提供,两者各司其职,由此开启了 Web 开发的新篇章。
  前后端分离通过技术栈的专业化,让 UI 具备更好的用户体验,更丰富的功能,更高效的交互,更快的刷新速度等。
  思考这样一个常见的场景,写一个后台管理系统,而不使用前后端分离。如果是一名 .NET 后端开发者,可以使用 Razor + 开源的 UI 模板(比如 Layuimini 这类)的方式实现。此时,开发速度将是极快的,后端开发页面的时间是短到可以忽略不计的(模板和样式是现成的,只需 CV 操作)。这样做,无需前后端对齐数据结构和接口,无需前后端联调,加快了开发速度。由后端统一处理校验、安全性、多语言、个性化逻辑等,维持了技术栈的一致性。
  会有哪些缺点呢?会因为缺少组件化损失复用性,还会损失一部分性能,但对于大多数简单 Web 项目,这些并不是关注的重点。
  可见当使用 “传统后端渲染” 时,会带来巨大的开发效率提升,让项目已更短的周期,更低的成本上线。因此,我认为前后端分离并不是唯一选择。
  - 对于复杂交互的页面(流程设计器、策略设计器、表单设计器、聊天窗口等),需要产品化的组件(大屏组件、仪表盘、地图、设备接口、多维度表格、画布等),有分工明确的团队支持,注重前端性能与用户体验的项目,适合“前后端分离”。
  - 对于以表单交互为主的项目(官网、博客、后台管理等),需求简单,需要快速上线的项目,对 SEO 强依赖场景,安全性要求高的项目,团队规模小或资源紧张时,适合“传统后端渲染”。
  单纯依赖 “前后端分离” 或 “传统后端渲染” 易陷入技术局限性 。前者增加开发成本和开发周期,对 SEO 不友好,后者不适合开发复杂交互的页面。最优解是根据模块特性动态组合两种模式,以“前后端分离”+“传统后端渲染”结合的方式开发系统的不同部分,在可复用性、用户体验、开发成本、开发效率之间寻找最优解。
  需要特别说明的是——微服务架构并非必须采用前后端分离模式,两者并无强制依赖关系,微服务架构仍可采用传统后端渲染模式。
  在实际项目中,建议根据业务场景选择适度分离的方案,而非盲从“前后端分离”模式。
打破 N 层架构的 "链式" 困局:从职责分化到极简建模

  在软件架构演进中,N 层设计催生了 PO、DO、BO、DTO、VO 等数据对象类型,本意是通过职责分离提升系统可维护性。但现实中,过度追求 "完美分层" 常导致对象的链式转换、层层包装,反而引发代码膨胀、性能损耗等问题。回归建模本质,我们需要在解耦需求与工程效率间寻找平衡。
  - PO(Persistent Object,持久化对象) PO 主要与数据持久化相关,它对应数据库中的表结构,用于实现对象与数据库表之间的映射。
  - DO(Domain Object,领域对象) DO 起源于领域驱动设计(DDD)思想。DDD 强调对业务领域进行深入分析和建模,DO 就是对业务领域中核心概念的抽象。它包含领域的属性和行为,具有业务语义和完整性约束。在复杂业务系统开发中,DO 能帮助开发者更好地理解和表达业务需求,构建出更符合业务本质的软件系统。
  - BO(BusinessObject,业务对象) 随着业务逻辑复杂度的增加,为了更好地组织和管理业务规则,BO 逐渐形成。它封装了具体的业务逻辑和业务规则,是业务领域的核心对象。
  - DTO(Data Transfer Object,数据传输对象) 起源于分布式系统和远程调用场景。在跨系统、跨服务的数据交互中,为避免直接传输实体对象带来的性能损耗和不必要数据传输,开发者需要一种专门用于数据传输的对象,DTO 应运而生,它只包含需要传输的数据,能有效提升数据传输效率。随着前后端分离架构的流行,DTO 也常用于前后端数据交互,将后端数据处理结果封装成适合前端展示的格式进行传输。
  - VO(View Object,视图对象) VO 主要用于视图展示,它的产生是为了将业务数据转换为适合视图呈现的格式。在 Web 开发中,页面展示的数据可能需要对业务数据进行加工、组合或过滤,VO 就负责承担这一职责,比如常见的 Model 和 ViewModel。
  传统 N 层架构中,对象按层级进行转换,虽然符合分层设计的理论初衷,但在实际工程中会引发一系列复杂性问题:
  - 多层转换的资源开销增加 GC 开销,有一定的性能损耗。
  - 需要处理转换逻辑,且容易引入 bug 而且不易察觉。
  - 字段变更连锁反应使变更成本呈指数级增长。
  - 分层边界模糊导致职责混乱。
  - 代码复杂度激增,可读性与可维护性下降。
  N 层架构中对象的多层转换本质是 "过度工程化" 的产物,其引发的性能损耗、开发膨胀等问题是否超过解耦收益需要谨慎评估。务实的解决方案是:
  中小型项目:用单一模型替代多层对象,以“极简”方式建模,通过特性标记(如[Required])定义业务校验、ORM 映射、序列化、字段权限、导入导出等,统一到单一位置定义,方便扩展和修改。
  大型系统:仅在需要时保留必要转换,并用自动化转换(如 AutoMapper)代替手动转换,减少人工代码,避免引入 bug。
  最终,架构设计应服务于 "以最小成本实现业务价值",而非追求理论上的分层完美。
线程安全:只有并发场景下才真正需要线程安全代码

  只有在真实的并发场景中,线程安全代码才具有不可替代的价值。我们既要警惕因忽视线程安全引发的数据一致性问题,也要避免盲目添加同步机制造成的性能损耗。
  部分追求 "代码洁癖" 的开发者,可能会对线程安全过度苛责。需要明确的是:线程安全机制虽能有效解决多线程环境下的资源竞争,但并非所有场景都需强制应用。若在单线程环境或无共享资源的场景中强行使用线程安全代码,犹如 "无病服药",徒增资源消耗与代码复杂度。
  唯有当业务逻辑确实面临并发访问时,才需引入线程安全策略——这既是对性能的保护,也是对代码简洁性的维护。
过度设计:不用把“弹弓”设计成“上帝之杖”

  在软件设计领域,"为架构而架构" 的过度设计现象屡见不鲜。典型表现为:用重型方案解决轻量需求,将简单问题复杂化,徒增成本却背离实用价值。
  比如,用户需求仅是高可用,结果设计成了一个多租户的云原生 SaaS;比如,总用户数和数据量都不大,但非要按照200并发和单表1500w数据做设计;再比如,一个三层架构足以支撑的业务,偏要叠加领域驱动、微服务等多层框架。
  中小型项目本可通过简单架构快速落地,却因盲目追求 "完美设计" 陷入开发泥潭。过度架构不仅推高编码与维护成本,更会因系统复杂度激增导致迭代效率暴跌。现实中,许多开发者并非不懂轻量级原则,而是困于 "怕被质疑专业度" 的心态,在 "技术优越感" 与 "业务实效性" 间选择了前者。对轻量级需求而言,能跑通的简单架构远优于 "看起来厉害" 的复杂方案 ,正如“杀鸡焉用牛刀”。真正的架构能力,体现在用最小成本解决实际问题,而非用技术炫技。
小结

  AI 编程的强势崛起,正重塑软件开发者的价值体系。市场竞争的本质始终指向商业价值——当 AI 能在数秒内完成代码编写,传统设计模式所追求的复杂度控制、模块解耦与复用性,正面临效率维度的重新审视。曾被奉为圭臬的架构美学,在 AI 编程的降维打击下,其工程价值正逐渐让位于 "性价比三角":廉价实现、稳定运行与功能完整性。
  这一变革揭示了残酷的现实:过度沉溺于设计模式的 "表现欲",执意构建 "看起来高级" 的架构,本质是对业务本质的背离。任何开发范式都不应沦为教条——它们是解决问题的工具,而非彰显技术优越感的图腾。架构选择必须基于用户需求、项目规模、团队能力与业务场景,让 "合适" 取代 "完美" 成为新的评判标准。
  软件开发没有“银弹”。当 AI 重构代码的效率颠覆传统认知,开发者的核心竞争力正从 "代码审美" 转向 "业务洞察力"—— 聚焦于构建 "正确的软件",而非 "看起来高深的代码"。跳出教条主义的桎梏,让开发模式为我们所用,而不是我们为模式所困,才能真正释放代码的力量,打造出高效、优质的软件产品。
1.webp

 
 
 

   

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册