软件开发者的时间都去哪儿了?后端开发核心技能——抽象建模

简介: 服务端开发工程师在大部分工作时间里并不是在写代码,而是在抽象建模。工程师需将业务需求抽象成领域模型、模块、服务和系统,面向对象开发时需抽象出类和对象,面向过程开发时抽象出方法和函数。某种意义上,软件的本质就是抽象,建模则是系统地实施抽象的过程。作为一种将事物形象化的有效手段,建模可将现实世界中的事物及事物之间的关系准确地表达出来。本文通过一个实际案例,详细解读业务抽象建模的好处。

0.引言

在互联网行业,软件工程师面对的产品需求大都是以具象的现实世界事物概念来描述的,遵循的是人类世界的自然语言,而软件世界里通行的则是机器语言,两者间跨度太大,需要一座桥梁来联通,抽象建模便是打造这座桥梁的关键。基于抽象建模,不断地去粗取精,从现实世界到业务模型,从业务模型到设计模型,最终完成现实世界到软件世界的转换。

事实上,服务端开发工程师在大部分工作时间里并不是在写代码,而是在抽象建模。工程师需将业务需求抽象成领域模型、模块、服务和系统,面向对象开发时需抽象出类和对象,面向过程开发时抽象出方法和函数。

某种意义上,软件的本质就是抽象,建模则是系统地实施抽象的过程。作为一种将事物形象化的有效手段,建模可将现实世界中的事物及事物之间的关系准确地表达出来。


1.抽象思维

抽象在中文里可作为动词,也可作为名词。作为动词的抽象是指一种行为,这种行为的结果,就是作为名词的抽象。百度百科对抽象的定义为:人们在实践的基础上,对于丰富的感性材料通过去粗取精、去伪存真、由此及彼、由表及里的加工制作,形成概念、判断、推理等思维形式,以反映事物的本质和规律的方法。

事实上,抽象作为一种高级思维形式,与日常生活关系密切,例如数字,人类初期并没有数字这一概念,原始人类或许能够理解三个苹果和三只鸭子,但不存在数字 “三” 这个概念,在他们的意识里,三个苹果和三只鸭子是没有任何联系的。当人类文明发展到一定阶段,发现了这两者之间存在的一种共性,即 “三”,于是就逐渐形成了数字这个概念。此后,人们就开始用数字对各类事物进行计数。


2.软件世界中的抽象

软件的本质就是抽象,在软件世界里,抽象无处不在,典型如命名抽象、分层抽象、原则抽象。

2.1 命名抽象

作为一名软件工程师,最令你头疼的事情是什么呢?是写代码,看别人的代码,需求评审,还是修 Bug?Quora 和 Ubuntu Forum 曾经针对这个问题进行过广泛地调研,结果显示, 最令软件工程师头疼的事情是命名,没错,就是命名!应用名、包名、类名、方法名、字段名、变量名等等。如果你不曾为命名苦思冥想、反复权衡,也许你还不能算是真正的软件工程师。

关于命名,Stack Overflow 的创始人 Joel Spolsky 曾言:“起一个好名字很难,但这是理所应当的,因为一个好名字需要把要义浓缩在一到两个词(Creating good names is hard, but it should be hard, because a great name captures essential meaning in just one or two words)。” 其实,这个浓缩的过程便是抽象的过程。

很多时候,业务代码的复杂,并非业务本身复杂,而是人为因素造成的,命名混乱就是最常见的因素。虽然不合理的命名并不影响需求的实现,但却加重了认知负荷,随着时间的推移,理解代码的成本会越来越高。同时,命名不合理本质上是抽象不合理,往往影响可复用性。

2.2 分层抽象

在软件开发中,经常会用到各种分层架构,如经典的三层模型(展现层、业务逻辑层、数据层)和 MVC (Model、View、Controller)模型。如图 1 所示为阿里广泛采用四层模型,它包括 View、Service、Manager、DAO 四部分,通过分层将数据访问、通用处理、业务逻辑、终端展示四者解耦,各司其职。View 与用户交互;Service 依赖多个 Manager 和 DAO 实现具体的业务逻辑;Manager 负责通用业务逻辑处理和封装外部服务,它是对 Service 层通用能力的下沉,注重复用性;DAO 负责与底层数据库进行数据交互。分层架构的核心其实就是抽象的分层,每一层的抽象只需要而且只能关注本层相关的信息,从而简化整个系统的设计。
截屏2023-09-06 下午7.44.56.png

图 1 四层模型

2.3 原则抽象

在面向对象设计和面向对象编程领域,有一个著名的 SOLID(单一功能、开闭原则、里氏替换、接口隔离以及依赖反转)原则,它是由 Robert Martin 在 21 世纪早期提出。在软件设计和开发中,正确地遵循这些设计原则,有助于提升系统的可维护性和可扩展性。

以依赖倒置原则(Dependency Inversion Principle, DIP)为例,其含义为:抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对抽象(接口)编程,而不是针对实现细节编程。这样做有什么好处呢?一个软件系统通常可划分为多个层次,上层调用下层,上层依赖于下层,如果上层依赖的是下层的具体实现,那么,当下层实现细节发生变化时,上层往往也需要同步修改,这就加重了不同层之间的耦合度。但是,如果上层依赖的只是下层的抽象而不是细节,就完全不同了,抽象变化的频率极低,让上层依赖于抽象,实现细节也依赖于抽象,即使实现细节不断变动,只要抽象不变,上层就不需要变化,如此一来大大降低了耦合度。

Java 的 JDBC 是依赖倒置原则的一个典型应用场景 。如图 2 所示,如果没有 JDBC 这一层抽象,软件系统将直接依赖具体的数据库(如 MySQL、Oracle 等),与实现细节耦合,当需要切换到另一种数据库时,就需要修改大量代码来适应细节的变化。若系统依赖的是抽象的 JDBC 接口,那么通过调用 JDBC 即可完成数据库操作,而无须再关注 JDBC 背后的数据库,因为所有关系型数据库的连接库都实现了 JDBC 接口,当需要换数据库时,作为抽象的 JDBC 并不会变化,系统也就无需感知变化。
截屏2023-09-06 下午7.46.28.png

图 2 依赖倒置原则典型应用场景



3. 经典抽象案例

如图 3 所示,有这样一个关于 “霸屏” 动效的需求,产品文档(Product Requirement Document,PRD)摘要描述如下:

  1. ZFB 会员与 KA(Key Account) 商家合作,升级会员等级特权,因此在会员频道首页通过 “霸屏” 动效提示用户并引导其进入新等级特权页面;
  2. 若用户点击 “看我等级特权” 按钮,则自动跳转到新等级特权页面,引导目标达成,“霸屏” 动效不再出现,以免打扰用户;
  3. 若用户未点击 “看我等级特权” 按钮,“霸屏” 动效展示 3 秒自动收起。由于引导目标未达成,需继续引导,同时为了防止过度打扰用户,“霸屏” 动效每月最多出现 N 次,N 需支持灵活配置。

2lntpqcffxbne_51d7f77dabf1401eb358223987b04ff8.png

图 3 等级特权引导“霸屏”视觉效果


我们来简单分析一下这个需求,核心业务目标在于引导用户进入新等级特权页面,同时兼顾用户体验,避免 “霸屏” 动效过度打扰用户。对于服务端而言,需要实现 “疲劳度” 控制逻辑,即:

  • 若用户点击按钮:持久化用户点击记录,当用户再次访问该页面时,通过查询点击记录就可以判断该用户是否曾点击按钮。若记录存在,则告知前端不要弹出 “霸屏” 动效。
  • 若用户未点击按钮:持久化 “霸屏” 动效对用户的曝光记录,当用户再次访问该页面时,通过查询曝光记录就可以判断该用户是否满足展示 “霸屏” 动效的条件。若当月曝光次数少于 N,则告知前端可弹出 “霸屏” 动效。

3.1 方案一:战术抽象,多快好省,跑步前进

基于上面的需求分析,稍有经验的服务端开发工程师立马就能想出解决方案,如表 1 所示,为每个用户落一条记录即可实现需求。

表 1:点击、曝光记录模型概要
截屏2023-09-06 下午7.48.33.png

从实现需求的角度来看,上述设计完全可以满足业务当前的需要。如图 4 所示,曝光、点击记录模型几乎完全是由产品文档(PRD)翻译而来,乍看之下,十分的 “信达雅”,简直不要太完美。
截屏2023-09-06 下午7.49.28.png

图 4 将 PRD 翻译为模型


我们再来仔细分析一下,上面的模型真的好么???显然很一般!!!该模型局限于实现当前业务需求,几乎没有进行抽象建模,因此,建立的模型不能准确地刻画业务的本质。这样的模型可扩展性极差,基本就是一锤子买卖。

在笔者看来,直接 “翻译” PRD 是一种战术编程,或者说战术抽象。John Ousterhout 在《A Philosophy of Software Design》一书中提到:几乎每个软件开发组织都至少有一个将战术编程发挥到极致的开发人员,可称之为战术龙卷风(Almost every software development organization has at least one developer who takes tactical programming to the extreme: a tactical tornado)。战术龙卷风有以下几个特点。

  • 快速。他们常以腐化系统为代价换取当前最快速的解决方案,几乎没有人能比他们更快地完成任务。
  • 高产。他们是高产的程序员,代码量极高,堪称 “卷王”。
  • 坑多。他们往往倾向于简单地进行功能堆积,忽视抽象建模,将成本放到未来,由后来人买单。

从战术龙卷风的特点可以看出,战术编程(抽象)是缺乏或者说忽视抽象建模和系统设计的,聚焦于快速交付,系统能用就行,注重短期收益而非长期价值。当然,这并非完全是软件工程师的问题,不合理的评价体系和行业特点亦难辞其咎。

3.2 方案二:深入分析,透过表象,探寻本质

方案一中 “草率” 地进行抽象建模是不可取的,于开发者自身而言,是一种苟且,无能力提升;于软件项目而言,随意堆积一次性代码,将成本放到未来,是一种不负责任的行为。

如果我们深入分析业务,我们会发现,其实有更好的方案,而且并不复杂。如图 5 所示:首先,忽略 PRD 描述中那些无关紧要的细节,可以发现,PRD 涉及两种场景;然后,针对两种场景,进一步抽取共同特征——场景 S : N 次/周期 Q;最后,洞见共同特征背后的本质——周期维度记账。
2lntpqcffxbne_20ac33861a9d495c86f40975fd6ca4d5.png

图 5 基于业务抽象建立模型

基于【周期维度记账】这一需求本质,我们建立的模型不仅可以满足当前业务的需要:

  • 用户点击按钮:DB 里面落一条记录,其中 scene 可设为 “CLICK”。当用户再次进入对应页面时,先根据 userId 和 scene 查询记录,若存在,则说明用户已经点击过按钮,告知前端无需展示“霸屏”动效。
  • 用户未点击按钮:DB 里面落一条记录,其中 scene 可设为 “EXPOSE”。当用户再次进入对应页面时,先根据 userId 和 scene(CLICK)查询、判断用户是否点击过按钮,如果没有点击,则根据 userId 和 scene(EXPOSE)查询、判断并更新曝光次数 count。

与此同时,基于【周期维度记账】这一需求本质,我们建立的模型具有更好的可复用性、可扩展性。举两个例子:

  • 多周期:基于字段 quantum 和 bizDt,可以支持终身、年、月、周、日等时间维度记账。满足不同业务场景的需要。
  • 多场景:基于字段 scene,可以实现不同业务场景的数据隔离,同时支持多个场景,以及数据分析等附加需求。


4. 抽象并非一蹴而就!需要不断假设、验证、完善

如图 6 所示,在人类文明早期,人们基于直观地观测,认为地球是宇宙的中心,因此抽象出了 “地心说” 模型。随着时间的推移和观测手段的进步,人们观察到的天文现象越来越多,逐渐意识到 “地心说” 模型与观测结果存在矛盾,于是,人们开始对 “地心说” 模型进行修正(像极了程序员重构模型),典型如 “本轮-均轮” 模型。

然而,随着更多的天文现象被发现,在 “地心说” 模型的大框架下,无论如何修正都无法自圆其说。在 “地心说” 模型统治人类 “天文世界观” 很长一段时间后,勇敢的先行者推翻了 “地心说” 模型,并提出了在当时看来离经叛道的 “日心说” 模型。
2lntpqcffxbne_0221315354724a73a89d3f65280c3c1e.png

图 6 “地心说”到“日心说”的发展史概略图

从 “地心说” 模型被提出,到 “日心说” 模型被广泛接受,跨越了 1400 多年的时间。这一史实表明,人们对事物本质的探索是一个过程,而非一蹴而就!!!对于服务端开发而言,我们对需求的认知也是如此,初见之下,我们往往很难直接洞见其本质,而需要不断假设、反复推演,最终才能抽象出较好的模型。

你可能会问——抽象建模如此麻烦,开发时间往往又不充裕,何必苦苦探寻所谓的本质呢?能用不就行了么?

如果你确有上述疑问,不妨换个角度,想一下 “核心竞争力” 的内涵。很多时候,我们并不缺乏解决问题的办法、能力和资源,而缺乏的是对问题的识别、理解、抽象。当一个问题被抽象为足以刻画业务本质的模型,并拆解到软件项目维度的时候,面对确定的任务、清晰的目标,可以解决问题的人就非常多了。

某种程度上,解决问题的能力是重要的基础,但若仅仅是解决问题还远远不足以称为核心竞争力。对于服务端开发工程师而言,抽象建模能力比编程落地能力更重要,因为编程解决问题只是一种普通技能而已,而对具象事物(如业务需求)的高度抽象,探索事物的本质,需要我们从新的角度审视旧的问题,需要有创造性的想象力,这才是真正的难点,当然也是核心竞争力所在。



5. 参考与引用

本文内容部分节选自——《服务端开发:技术、方法与实用解决方案》一书。作者为资深服务端技术专家,兼任技术讲师,曾获得阿里第二届技术讲师课程大赛年度冠军。全书分 14 章,约 30 万字,正文 373 页,由机械工业出版社出版发行。
image.png

5.1 适用场景

  • 学习技术:服务端开发工程师、客户端开发工程师、测试开发工程师等IT从业人员。计算机、软件、自动化、电气、通信等专业有志于进入 IT 行业的在校学生。
  • 面试求职:本书涵盖了服务端开发的方方面面,特别是结合案例详细解读了高并发、高可用、高性能、数据一致性、缓存、幂等服务端典型问题的大厂解决方案,助力面试!

5.2 知识脉络

该书体系化、全景式解读了服务端开发,内容从逻辑上可以分为两大部分。

第一部分为第 1~6 章,主题是技术和方法。首先概述服务端开发的职责、技术栈、核心流程和进阶路径,然后从需求分析、抽象建模、系统设计、数据设计、非功能性设计 5 个方面逐一展开,结合案例深入解读服务端开发的实操方法和重难点,为读者清晰呈现服务端开发的全景图。通过学习本篇内容,读者可以快速、体系化地掌握服务端开发的相关知识和方法。

第二部分为第 7~14 章,主题是解决方案。针对高并发、高可用、高性能、缓存、幂等、数据一致性等服务端开发的典型问题,结合业务场景进行系统性分析并给出解决方案。此外,就接口设计、日志打印、异常处理、代码编写、代码注释等实施细节给出行业案例和规范。本篇内容如同一本服务端开发问题手册,当读者在实践中遇到问题时,可以从中查找解决方案。

相关文章
|
19天前
|
存储 缓存 负载均衡
后端开发中的性能优化策略
本文将探讨几种常见的后端性能优化策略,包括代码层面的优化、数据库查询优化、缓存机制的应用以及负载均衡的实现。通过这些方法,开发者可以显著提升系统的响应速度和处理能力,从而提供更好的用户体验。
47 4
|
1月前
|
消息中间件 API 持续交付
后端开发中的微服务架构实践####
【10月更文挑战第21天】 本文深入探讨了微服务架构在后端开发中的应用,从基本概念出发,详细阐述了微服务的核心优势、设计原则及关键技术。通过实际案例分析,揭示了微服务如何助力企业应对复杂业务需求,提升系统的可扩展性、灵活性与可靠性。同时,也指出了实施微服务过程中可能面临的挑战,并提供了相应的解决方案和最佳实践。 ####
31 3
|
10天前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
38 3
|
25天前
|
存储 前端开发 Java
深入理解后端开发:从基础到高级
本文将带你走进后端开发的神秘世界,从基础概念到高级应用,一步步揭示后端开发的全貌。我们将通过代码示例,让你更好地理解和掌握后端开发的核心技能。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供有价值的信息和启示。
|
28天前
|
存储 缓存 监控
后端开发中的缓存机制:深度解析与最佳实践####
本文深入探讨了后端开发中不可或缺的一环——缓存机制,旨在为读者提供一份详尽的指南,涵盖缓存的基本原理、常见类型(如内存缓存、磁盘缓存、分布式缓存等)、主流技术选型(Redis、Memcached、Ehcache等),以及在实际项目中如何根据业务需求设计并实施高效的缓存策略。不同于常规摘要的概述性质,本摘要直接点明文章将围绕“深度解析”与“最佳实践”两大核心展开,既适合初学者构建基础认知框架,也为有经验的开发者提供优化建议与实战技巧。 ####
|
24天前
|
运维 监控 Java
后端开发中的微服务架构实践与挑战####
在数字化转型加速的今天,微服务架构凭借其高度的灵活性、可扩展性和可维护性,成为众多企业后端系统构建的首选方案。本文深入探讨了微服务架构的核心概念、实施步骤、关键技术考量以及面临的主要挑战,旨在为开发者提供一份实用的实践指南。通过案例分析,揭示微服务在实际项目中的应用效果,并针对常见问题提出解决策略,帮助读者更好地理解和应对微服务架构带来的复杂性与机遇。 ####
|
23天前
|
消息中间件 运维 安全
后端开发中的微服务架构实践与挑战####
在数字化转型的浪潮中,微服务架构凭借其高度的灵活性和可扩展性,成为众多企业重构后端系统的首选方案。本文将深入探讨微服务的核心概念、设计原则、关键技术选型及在实际项目实施过程中面临的挑战与解决方案,旨在为开发者提供一套实用的微服务架构落地指南。我们将从理论框架出发,逐步深入至技术细节,最终通过案例分析,揭示如何在复杂业务场景下有效应用微服务,提升系统的整体性能与稳定性。 ####
35 1
|
24天前
|
消息中间件 运维 API
后端开发中的微服务架构实践####
本文深入探讨了微服务架构在后端开发中的应用,从其定义、优势到实际案例分析,全面解析了如何有效实施微服务以提升系统的可维护性、扩展性和灵活性。不同于传统摘要的概述性质,本摘要旨在激发读者对微服务架构深度探索的兴趣,通过提出问题而非直接给出答案的方式,引导读者深入
43 1
|
25天前
|
负载均衡 监控 API
后端开发中的微服务架构实践与挑战
本文深入探讨了微服务架构在后端开发中的应用,分析了其优势和面临的挑战,并通过案例分析提出了相应的解决策略。微服务架构以其高度的可扩展性和灵活性,成为现代软件开发的重要趋势。然而,它同时也带来了服务间通信、数据一致性等问题。通过实际案例的剖析,本文旨在为开发者提供有效的微服务实施指导,以优化系统性能和用户体验。
|
1月前
|
存储 JavaScript 前端开发
深入浅出Node.js后端开发
在数字化时代的浪潮中,后端开发作为连接用户与数据的桥梁,扮演着至关重要的角色。本文将以Node.js为例,深入探讨其背后的哲学思想、核心特性以及在实际项目中的应用,旨在为读者揭示Node.js如何优雅地处理高并发请求,并通过实践案例加深理解。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供新的视角和思考。

热门文章

最新文章