写代码这件事,迈入第七个年头才有了一些心得(第二章 抽象)


写代码这件事,迈入第七个年头才有了一些心得(第二章 抽象)

一、抽象概念

眼见的自然形式会蒙蔽真实的本质,简化事物的形象,才能显露艺术的真实面目。

-- [荷兰]蒙德里安

抽象是一种思维,也是一种艺术,它是现实世界与机器语言之间的桥梁。

抽象就是在特定的环境,特定的视角,特定的维度,对事物进行分析、提炼、精简、归纳、推演、概括等行为,从具体到抽象,探索事物的规律和本质。

规避细节,提炼共性, 推演归集。下图是一幅展示牛的抽象图演进的示意图:

过往六七年的经历,也告诉了我一个道理,抽象思维是编程中最为重要的思维。

二、抽象要素

在软件领域,关于抽象,根据过往经验提炼了以下几个核心要素:

抽象之分层

分层架构的关键就在于层次的抽象,因此大型复杂业务系统,才能被软件所理解和解释。 这里的抽象分层,也有拆分,将整体分成局部之意。

  • 没有分层的软件是混乱的,是不灵活的,甚至生命周期也是短暂的。
  • 分层是降低软件的复杂度(也是降低耦合);同时分层也增强了软件的灵活度,也在变化时容易扩展。

软件应该被分层抽象。简单举几个例子:

  • 网络七层协议, 复杂的网络传输通信被拆分成多层
  • 软件应用中的三层架构模型。软件系统都是被分层实现的。

三层架构,每一层职责清晰,每一层都具备可扩展,如数据层,就可选择不同的存储介质。 而分层的关键在于抽象,做好边界划分,明确层级之间的职责,分而治之。

软件也应该被抽象成多层,抽象成多个模块组成,而不是又大又全的一个独立个体。

抽象的粒度

在谈粒度之前,先举两个例子:

例子一: 在计算机的世界,数据被抽象成 0 和 1 ; 0 和 1 高度抽象,对于没有计算机背景的人来讲,用 0 和 1 来表达数据,因为信息细节少,所以理解晦涩。 虽然 0 和 1 被抽象得如此简单; 但要形成一个可传输的数据包,却需要经过复杂的协议组装。

发送报文 TCP报文

例子二,在计算机中要理解乘法的实现,首先需要先学习源码、补码、反码;再到定点数的表示;再到定点数的加法减法、再到乘法,这样才能从计算机的角度理解1 X 1 = 1

通过这两个例子,告诉我们一个道理,所有的抽象是有粒度的(层次): 抽象的粒度越高(层次),泛化能力越强,但丢失的细节也越多。就像 0 和 1 一样, 要表达任何一个符号都需要复杂的组装。

简而言之,抽象是有粒度(层次),需要有权衡判断。

  • 过度抽象,丢失细节,信息少
  • 不抽象,累赘,成本高,复用性差,信息多

"万物皆对象", 就像在 Java 中,可以使用 Object 表示所有的类; 但是要访问对象内部的信息,却需要强制转换。但如果毫无抽象,代码会呈现爆炸式增长,最后臃肿累赘,无法维护。

放之四海而皆准的抽象是简单的,信息量是很少的; 抽象就应该允许细节,有特定属性特征;同时给他们留有扩展。

抽象的极致等于没有抽象!!! 就像下图一样,从五边形,到消失的点,随着抽象的高度化,信息越来越少,最后消失。

可以将抽象的粒度理解为抽象的层次、抽象的程度;另外抽象的层次越高,也越好理解,抽象的层次越低则越难理解,举例说一个经验:

  • 在阅读学习一个新框架、新仓库代码时。首先应该从层级较高入手,即先了解设计,因为这一层抽象层次高,容易理解,信息也精炼;其次再查看流程;最后再看代码细节。不要一上来就一头扎进代码细节里面。这样会理解变得换乱,增加学习成本,甚至可能把自己绕晕,困于其中。

开发中需先有设计,再有编码,如果一上来就编码,容易造成混乱,千万不可本末倒置!!!

抽象的角度

横看成岭侧成峰,远近高低各不同。

抽象是按照不同维度和视角进行总结归纳的。视角不同,维度不同,抽象出来的概念就是有区别的。

还记得小学课本《画杨桃》杨桃被画成五角星那篇文章,它也告诉了我另外一个道理,抽象是有角度和立场的。

不妨再尝试说一下下面这些物体的相同点和不同点:

  • 都是家具
  • 都是没有生命
  • 形状不同
  • 面向不同
  • .....

不同的人会说出不一样的观点。抽象,是有维度、角度、立场的

一个在互联网行业荒诞又无处不在的故事......

背景:客户想知道本月产品销售额,如果能用图表查看就更好了。

产品思维 研发平台思维
定制开发 1 周上线,让报表看起来美观一些,注重用户体验。 做一个报表引擎平台,这样再来新需求,简单配置一下就能复用

总有那么一部分人,总想着什么都往平台、往引擎做。 又常常搞个半吊子;最后用户不买单,因为客只想要一个指标数据,而不是平台。而这群人却还妄图忽悠客户购买他们的平台呢......

回归正题: 抽象有很强的主观性,有视角、维度和立场,因此它有局限性,上下文。因为这些因素的存在,抽象可能是错的。

抽象的边界

软件需要边界,抽象也需要有边界。

  • 边界不清楚,容易内部混乱; 边界不清楚,容易职责模糊。
  • 边界常常是容易引起变化的部分,是造成软件雪崩的罪魁祸首。

DDD 和 三层架构混合

一些插曲故事:应用程序开始用DDD,部分同学对模型抽象不够清晰,边界模糊,分层最后混乱; 最后 DDD 又回到了三层架构。模块之间十分混乱,新手同学一脸懵逼,竟然不知道代码写在何处,最后只能还笑着说:能跑的代码就是好代码😂😂😂😂😂😂

边界不清晰,会导致混乱。

经过上面几个点的分析,总结提炼了一个点:抽象是有陷阱的。

抽象的陷阱

那些细节变化点需要特别注意,因为往往是导致我们系统需要重构的点。甚至推翻重来。

错误的立场,它可能让你推倒重来,付出惨痛教训。

一个真实的案例:也是一个惨痛的案例。前期想做 saas 产品,后期又说做成平台。最后无疾而终,白白辛苦 6 个月......

saas产品 & 平台一些区别
设计建模上,抽象的层次不一样,平台抽象层次更高
业务属性上:saas产品业务属性更强,平台会弱化
立场、理念、用户群体等不同,抽象是不一样的,实现就差别更大了,比如各种权限

必须要明确和告诫自己,抽象有可能是错误的,是有陷阱的

  1. 抽象不应该放之四海而皆准,需要有细节,不要过度抽象; 也不要不抽象。有合理的粒度
  2. 抽象有主观色彩,有上下文,有角度;有维度;偏听则暗,兼听则明
  3. 抽象不是真理,甚至是错误的。

抽象既简单又不简单。那么如何进行抽象呢

三、正确抽象

抽象是站在更高地方看问题,它需要全面、清晰、正确

简单总结两个点:

  • 方法论和经验
  • 训练和演进

部分经验

    1. 自顶向下,自下而上。就像金字塔一样,一层层的
    1. 通用往下沉,个性往上浮,细节留扩展
    1. 下层不依赖上层,根据不依赖具体,不依赖细节
    1. 系统建模:从整体到局部; 业务建模:从局部到整体
    1. 由粗到细,由大到小,保持一定的秩序
    1. 更多的场景输入,用例驱动
    1. 多参与一些业务、数据建模,积累经验
    1. 学习,总结,实践
  • .......

警惕:所有别人的经验都是别人的!!!

一个故事: 毕业的第二年,针对一个业务做 ER 图设计,错误的分了一个对对多的场景,经导师指导修正了;同时也给我留下了深刻印象。抽象可能是错误的;也可能需要修正。感谢那些给我指导的大佬们......

代码应用

如何将抽象应用到编码中,那些经典的范式,早已被提炼总结出来了,如下所示:

就像 SpringBoot 中的所有扩展点,皆是面向接口编程,而变得异常灵活。如果你一直写重复的代码,不知道程序如何扩展,可能还没有学会抽象。

✒️下篇内容,会考虑抽象在代码中的实践应用。

四、最后总结

本文主要从抽象的概念,抽象的要素,再到如何抽象编写。其实抽象本身也很抽象。

  • 分层、粒度、角度、边界是关键要素。
  • 警惕抽象陷阱
  • 抽象是一个演进的过程
  • 抽象是一种思维
  • ......

工作进入第七年,才慢慢明白一个道理,编程拼的不是技巧,而是思想,而抽象思想是其中之一

推荐阅读

📚最后关于抽象能够联想的两本书籍。

书籍 描述
《金字塔原理》 讲解总分结构,结构化思维,金字塔结构等
《代码大全》 如何写好代码,非常实用

写代码这件事,迈入第七个年头才有了一些心得(第一章 关注点分离)

相关推荐
姑苏洛言5 分钟前
编写产品需求文档:黄历日历小程序
前端·javascript·后端
秋千码途35 分钟前
小架构step系列08:logback.xml的配置
xml·java·logback
飞翔的佩奇37 分钟前
Java项目:基于SSM框架实现的旅游协会管理系统【ssm+B/S架构+源码+数据库+毕业论文】
java·数据库·mysql·毕业设计·ssm·旅游·jsp
姑苏洛言1 小时前
搭建一款结合传统黄历功能的日历小程序
前端·javascript·后端
你的人类朋友1 小时前
🍃认识一下boomi
后端
苏三说技术1 小时前
MySQL的三大日志
后端
时来天地皆同力.1 小时前
Java面试基础:概念
java·开发语言·jvm
豌豆花下猫1 小时前
让 Python 代码飙升330倍:从入门到精通的四种性能优化实践
后端·python·ai
找不到、了1 小时前
Spring的Bean原型模式下的使用
java·spring·原型模式
阿华的代码王国2 小时前
【Android】搭配安卓环境及设备连接
android·java