透过文学经典理解软件设计的抽象思想

简介: 透过文学经典理解软件设计的抽象思想

博尔赫斯(Jorge Luis Borges)有一篇奇文,曰《博闻强记的富内斯》,以纪实手法杜撰了一个具有非凡记忆能力的传奇人物富内斯。博尔赫斯自云:“(《博闻强记的富内斯》)是长夜失眠的隐喻。”博尔赫斯大约是文学大师中最擅长使用隐喻的人了。他在诺顿讲座的演讲中,专门做了一次题为“隐喻”的演讲。极限编程的创始人Kent Beck非常推崇“隐喻”,并将其作为Spike阶段理解架构的重要手段,也是XP敏捷实践之一。


我在读一些文学作品时,常产生对软件设计思想的遐想。这或许可以称之为“比较学”,但我认为可以说是“隐喻”。

回到这篇奇文。博尔赫斯用诗的语言向我们描述了抽象与具象。他写道:

我们能够充分直感的形象是黑板上的一个圆圈、一个直角三角形、一个菱形;伊雷內奥却能直感马匹飞扬的鬃毛、山岗上牲口的后腿直立、千变万化的火焰和无数的灰烬,以及长时间守灵时死者的种种面貌。

伊雷內奥即富内斯,他的超凡记忆力在19岁被马摔下地的时候被神奇的触发。他能记住他之所观、所听、所感的任何一刻纷繁复杂的细节,“非但记得每一座山林中每一株树的每一片叶子,而且还记得每次看到或回想到它时的形状。”然而,富内斯却不具备抽象的能力——“富内斯几乎不会进行一般的、纯理论的思维。他非但难以理解‘狗’这个共性符号包括不同大小、不同形状的许许多多、各色各样的个别的狗;麻烦的是,从侧面看的编号为3-14的狗,名称会和从正面看的编号为3-14的狗一样。”

所以博尔赫斯说:“思维是忘却差异,是归纳,是抽象化。在富内斯的满坑满谷的世界里有的只是伸手可及的细节。”

富内斯可以是一个好的记忆者,他可以用极短的时间学会世间任何一门语言,我想,程序语言自然也不例外,所以他若从事编码工作,一定是一个不错的高效程序员;但是,他却不一定是一个好的软件设计者。Dijkstra就指出:“抽象来自于对真实世界中特定对象、场景或处理的相似性的认知,并决定关注这些相似性而忽略不同之处。”这里所谓的“决定”就是设计时的一种判断,且需要具备抽象的能力去支撑。富内斯显然做不到这一点。

抽象是一种归纳的能力,是一种识别共同特征的能力。抹掉细节,只辨其共同之处,并将其归纳为一个抽象的名词,这是设计者需要具备的。不如此,则不能化繁为简;不如此,则不能应对变化。我们很难成为博闻强记的富内斯,这就意味着当我们面对太多如枝头纷繁堆叠的叶子一般的细节时,我们不可能都能记住它们的样子。从面向对象的角度来讲,远处山林中每一株树都是一个对象实例,但我们可以以抽象的Tree名之。树上生长的每一片叶子都是一个对象实例,但我们可以以抽象的Leaf名之。

在软件设计中,抽象除了是对共同特征的概括之外,还应该是对对象边界的一种控制与分离,即通过抽象将对象分离为“外部视图”与“内部视图”。Abelson与Sussman将抽象的这种能力称之为抽象壁垒。这是用更加强烈的语气强调了“边界的意义”。

在我曾经负责设计的SaaS产品中,需要根据元数据生成报表。报表的所有元素最终需要导出到Excel与Html网页上。我借用了“绘制”的隐喻来表示导出功能,因而Excel的Sheet与Html的Page都可以视为“画布”。基于这么一个隐喻,我提炼出与导出相关的报表元素的共同特征,即针对“画布”而言,它们都是一种“绘制元素”。于是,我得到了两个抽象概念:DrawingElementReportCanvas

public interface DrawingElement {
    public void draw(ReportCanvas canvas);
    public object getElement();
}
public interface ReportCanvas {
    public void addElement(DrawingElement element);
}

DrawingElementdraw()方法负责将绘图元素绘制到ReportCanvas对象中。这种抽象提供了导出功能的外部视图,它隐藏了具体的实现细节,使得该功能是可扩展的。

抽象的方向有二:自上而下又或自下而上。

在进行自上而下的抽象时,我们往往需要遵循一些范式、模式乃至设计风格。例如针对业务模型,我们可以参考Martin Fowler的《分析模式》,直接套用该模式定义的模型对整个设计进行指导。又例如说针对一连串的数据流处理,我们可以参考Pipe-Filter模式,抽象出可以组合和扩展的filter。在自上而下抽象的过程中,偶尔需要设计者利用“隐喻”来给出一个形象而恰当的抽象概念。例如在Facebook的FBML架构中,就引入了“flavor(风味)”来形容不同上下文对输入的约束。

当面对未知领域时,又或者我们无法寻找到已有模式(范式)去follow时,我们就需要自下而上的抽象能力。这个过程就好像整理一堆打散了的扑克牌一样,我们要按照花色分类,然后再按照数值进行排序。扑克牌的花色就是抽象过程中要寻找的“共同特征”,扑克牌的数值以及排序过程则是需要封装的细节。例如在报表处理的上下文中,我们分辨出填充参数的多种实现方式,进而提炼出ParameterFilling这个抽象行为;在租赁系统上下文中,我们分辨出可以租赁的各式物品,进而提炼出Rentable这个抽象特征。

请注意,分类与识别共同特征都属于一种抽象。前者获得的是is-a的关系,后者获得的是can-do或have的关系。无所谓优劣,抽象关系的选择取决于具体的场景。

博尔赫斯杜撰的富内斯能够过目不忘地背诵冗长晦涩的拉丁文《自然史》,超凡的记忆力让他可以拥有海量的知识,但他的思维方式仍然停留在留声机的初级阶段。他记住了知识,却不能有效地运用知识,因为他无法归纳、无法推演、无法演绎,换言之,他缺乏的是提炼知识的抽象能力。

本文链接: http://zhangyi.xyz/thinking-pattern-after-reading-borges/

相关文章
|
消息中间件 架构师 安全
重新认识架构 — 不只是软件设计
通常情况下,人们对架构的认知仅限于在软件工程中的定义:架构主要指软件系统的结构设计,比如常见的 SOLID 准则、DDD 架构。一个良好的软件架构可以帮助团队更有效地进行软件开发,降低维护成本,提高系统的可扩展性和可维护性。这里的架构定义有更多元化的理解:架构不仅是对软件开发设计和流程规范的定义,也包含了参与架构设计的人员、以及项目过程中和架构有关的活动,都可以称为架构。 从广义角度来理解架构,意味着更全面的思考和新的融合。
56 0
|
8月前
|
设计模式 存储 前端开发
【软件设计师备考 专题 】面向对象设计方法:体系结构、类的设计和用户接口设计
【软件设计师备考 专题 】面向对象设计方法:体系结构、类的设计和用户接口设计
124 0
|
消息中间件 架构师 安全
重新认识架构—不只是软件设计
结合自身经历阐述架构师定位、架构活动如何保障企业、组织实现商业价值。
重新认识架构—不只是软件设计
|
设计模式 Java C#
面向对象四大特征-系统学习二
经历了三大结构的学习之后,对于事务本质的理解增加了很多的维度;进而开启了面向对象方法的研究。
|
设计模式 JavaScript 前端开发
从浅入深学习中介者模式
在软件开发中,设计模式是一种用于解决常见问题的重要工具。其中,Mediator(中介者)/Middleware(中间件)设计模式在处理多个组件之间的通信和协调时非常有用。本文将从浅入深地介绍Mediator/Middleware模式,包括其定义、用途以及如何使用JavaScript实现它。
112 0
|
设计模式 资源调度 算法
对软件认知层次的思考
对于软件的认知层次代表着不同的专业程度,也代表着不同层次需要完成的工作的不同。在架构设计过程中需要有效的利用分层的认知,对不同层次的问题进行有针对性的解决确定。
125 0
对软件认知层次的思考
|
人工智能 算法 安全
8种提升程序猿编程能力的方法+编程思维四个核心:分解、抽象、模式识别和算法
对于程序员来说,提高自己的编程能力,算是给自己定的职业发展目标之一,不过定一个成为编程大神的目标很容易,具体做起来可能就不是一件简单的事了。首先,既然决定“我要变得更好”,得先知道“更好”是什么样子的。另外,不能“想变得更好”,却没有任何具体可行的措施。
963 2
8种提升程序猿编程能力的方法+编程思维四个核心:分解、抽象、模式识别和算法
|
监控 数据可视化 测试技术
软工导第一节课 计算机软件工程学作一个简短的概述,回顾计算机系统发展简史 软件工程的基本原理和方法有概括的本质的认识,详细讲解生命周期相关知识讲解8种典型的软件过程模型
软工导第一节课 计算机软件工程学作一个简短的概述,回顾计算机系统发展简史 软件工程的基本原理和方法有概括的本质的认识,详细讲解生命周期相关知识讲解8种典型的软件过程模型
294 0
软工导第一节课 计算机软件工程学作一个简短的概述,回顾计算机系统发展简史 软件工程的基本原理和方法有概括的本质的认识,详细讲解生命周期相关知识讲解8种典型的软件过程模型
|
开发工具
软件设计体系 实验一 经典软件体系结构风格
软件设计体系 实验一 经典软件体系结构风格
软件设计与体系结构 实验二 经典软件体系结构风格(二)
软件设计与体系结构 实验二 经典软件体系结构风格(二)