浅谈对象体系 | StartDT Tech Lab 07
这是奇点云全新技术专栏「StartDT Tech Lab」的第 7 期。
在这里,我们聚焦数据技术,分享方法论与实战。一线的项目经历,丰富的实践经验,真实的总结体会…滑到文末,可以看到我们的往期内容。
本篇由奇点云后端技术专家「风雪」带来:
作者:风雪
阅读时间:约 7 分钟
注:如果使用过奇点云的数据中台产品 DataSimba,阅读本文会更顺畅(戳我了解DataSimba)
前言 &背景
一个大型软件系统常常需要划分系统为不同的功能模块。在系统开发时,模块的接口设计尤为重要。
良好的接口设计能够降低系统各部分的相互依赖,提高组成单元的内聚性,降低组成单元间的耦合程度,从而提高系统的维护性和扩展性。
因此在程序设计的实践中,接口设计要使软件系统的职责得到合理划分。
在做平台系统开发时,对比应用型系统接口的设计,我们发现,一般应用由于需求变化比较快,与业务贴合比较紧,在接口设计中常常会出现一些问题,比如:
脆弱性(Fragility):对系统某接口的改动会导致与之关联性并不大的其他部分出现问题。
牢固性(Immobility):设计中包含了对其他系统有用的部分,但难以把这些部分从系统中分离出来。
冗余:设计中包含重复结构,而这些重复结构本应该使用单一的抽象统一。这样重复使得系统的改动代价变高。
晦涩性:难以阅读和理解。
无法复用:由于业务贴合比较紧,接口中往往会携带业务元素,使得接口无法适应新的业务场景。
不过这些问题,跟系统以及接口所对应的场景也有很大的关系。
而平台系统接口设计不仅要避免出现上述问题,还要有很好的通用性和兼容性,更重要的是需要保证系统架构稳定性以及可用性。同时,在接口设计初期要考虑接口将来是否要迁移、是否容易迁移、是否跨平台、是否与操作系统无关等因素。良好的平台接口设计不仅要能够长久稳定的运行,还要能够应对复杂且多变的业务要求。
设计原则
接口设计的优劣往往取决于对接口所操作对象的抽象够不够、质量高不高,以及抽象的对象是否遵循接口设计的一般原则:
单一职责原则(SRP):就一个对象而言,应该仅有一个引起它变化的原因或功能。也就是说,一个对象应该只负责一个功能。
开放—封闭原则(OCP):抽象的对象应该是可以扩展的,但是不可修改。也就是说,可以通过增加类来扩展已有功能,而不需要直接修改已有的代码。
接口隔离原则(ISP):不应该强迫客户依赖于他们不用的方法。接口属于客户,不属于它所在的类层次结构。
稳定抽象原则(SAP):包的抽象程度应该和其稳定程度一致。也就是说,稳定的包应该包含一些抽象类,以方便功能扩展。
而除了一些原则之外,对象还要以需求、场景以及待解决的问题为出发点,再结合实践中总结出的方法论为依据去设计我们的对象。
目标
我们的目标是:在现有大数据平台的基础上,借鉴业界成熟方法论,构建合理的对象、规范文档、接口标准和开发模式,形成一套完整的对象体系架构,以保障平台快速支撑不断变化的业务并驱动业务的发展。
那么究竟如何做呢?下文以奇点云不断探索、实践打磨出的方案为例,介绍我们的对象体系架构方案。
探索:一切皆文件
谈对象体系之前,先了解下 Linux 操作系统的设计,在 Linux 中流传着「一切皆文件」(Everything is a file) 的哲学,怎么理解呢?
系统架构最主要的设计原则是提供一个访问大范围输入/输出资源(包括文件、文件夹、硬盘、CD-ROM、调制解调器、键盘、打印机、显示器、终端机甚至跨进程和网络通讯)的统一的范例。窍门是提供一个所有这些资源的抽象对象,UNIX 之父把这个对象叫做「文件」。因为每个「文件」都由同一个 API 暴露,所以你可以用同一套命令来读写/操作磁盘、键盘、文件或网络设备。
这对于普通文件很好理解,但其他的设备怎么操作呢?这时候就不得不提虚拟文件系统了。
Linux 支持多种文件系统(如 vfat、ext2、ext3 等),为了方便管理,在所有这些文件系统上面提供了一层抽象,即虚拟文件系统(VFS)。如图:
图源:CSDN(作者:confirmwz)
虚拟文件系统为各类文件系统提供了统一的操作界面和应用编程接口,也就是说,不论是什么类型的文件系统,都必须提供符合 VFS 标准的接口。
这就使得 VFS 可以通过统一的接口来访问不同类型的设备。这也正是 Linux 能将所有设备都理解为文件的原因。
以上我们介绍了操作系统中「一切皆文件」的阐释。接下来我们说下针对平台系统,我们应怎样构建我们的「文件系统」或者说「对象体系系统」。
对象
何为对象?
要理解何为「对象」,首先我们先说下「抽象」。其实所有编程语言都提供抽象机制,可以认为,人们所能解决的问题的复杂性直接取决于抽象的类型和质量。
所谓「类型」,就是指所抽象的是什么。你可以抽取待求解问题的任何概念化的东西,如:天空、海洋、山脉、银行、出纳、几何图形等等。这里我们就可简单理解为对象。也就是「类型」的抽象便形成了对象。
由此,我们可以说,对象是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性来区分不同对象。
对象体系
前面分析了对象,那光有对象就能形成系统了?答案是否定的。
一个健全的、稳定的、复杂的系统不能光有一个个对象,因为系统不是提供单一服务的,它是一类请求的复合,是多个对象的组合。此时需要对象与对象能够产生关联、依赖、包含等关系。而这样的关系,概括来说就是程序中对象通过彼此之间建立依赖、引用等关系,形成复杂体系,最后通过简单的 api 接口的方式暴露调用程序,同时将复杂性隐藏在对象的简单性背后,这样由一个个对象所形成的复杂体系便构成了我们今天的对象体系。
而如何构建对象?对象之间是怎么产生关联、依赖的呢?
简单来说,就是针对现有业务发展趋势以及系统的不断迭代,从中不断总结,最终抽象出可应对绝大多数业务需求、场景的一系列可操作的对象,这些抽象出的对象以及对象之间相互关联、依赖,就形成了目前我们所熟悉的对象体系。资源抽象、统一接口,这些是系统架构很重要的设计原则,操作系统遵循这一原则,对象体系也依然坚持这样的设计。
首先我们根据现有系统,总结出了一系列对象以及对象之间的联系,如图:
图源:风雪
1. account:即账号,抽象商户的概念,每个商户、客户都可作为账号对象存在,账号授权不同的工作空间,就可进行跨工作空间数据交换。
2. workspace:即工作空间,每个工作空间就是一个域,其中除了账号可根其他域互通外,其他的对象在不同的域是不互通的。
3. 工作资源:域/工作空间想要提供服务,那么需要底层资源的支持,如工作机、计算引擎。当然为了细粒度的资源隔离,工作机可进行分组,故这里又把工作机器抽象一层,以工作资源组存在。
4. project:项目对象,所有针对项目的操作都可通过此对象进行,并且 DataSimba(奇点云数据中台产品)中权限隔离、资源隔离,均以此对象进行。
5. job:最重要的对象之一,提供针对离线、实时、算法等不同任务、不同调度周期的抽象,用以完成平台绝大部分的工作。
6. scheduler:负责平台的调度工作,如资源调度、任务调度、工作流调度等。
7. resource:与工作资源不同,这里的资源可理解为项目内的资源,如文件资源、函数资源等。
8. metadata:元数据抽象,可能不太好理解,想象一下,给你一个软件安装包,是不是需要环境信息才能安装,比如「此软件只能安装在 windows 上」,那这个操作系统的类型便可作为此软件必要环境的一个元数据对象,而想要我们的软件系统平稳的运行也需要这样的元数据。
以上就是目前 DataSimba 中所抽象出的对象。
有了对象,那他们怎么产生联系、依赖?也就是说,对象之间怎么通信?
其实在系统设计的时候我们也考虑过几种方式,比如 http 调用、rpc 调用等,但是为了使接口更加通用或为了客户极速构建平台系统,我们所有对外提供接口均使用 RESTful 风格的 http/https 的 api,并且接口的设计也遵循着前面所说的接口设计的一般原则。
我们回顾下 DataSimba 整体架构:
图源:风雪
在图中我们可明显看到,对象体系在架构中已经处于很底层位置,所以在实现中考虑高内聚、低耦合的设计原则和兼容性,实行插件式的开发。
例如,抽象的 job 对象,它可以解决什么问题:
1. 可以解决集成、离线、实时、算法等不同任务的 etl 工作;
2. 可以解决数据质量问题,如:规则生成 job 进行后续检测;
3. 可以解决数据地图表元数据问题,如:生成定时 job 进行数据的获取。
通过抽象,某个对象可应对多个业务系统以及模块,不同的对象组合可构建不同的业务系统以及业务场景。
总结 &展望
通过今天的介绍,相信大家对对象体系也有了一定的了解。
借鉴操作系统的抽象思想以及面向对象程序「一切皆对象」的设计原则,我们对现有系统进行抽象,形成如今的对象体系架构。
未来,我们会针对对象体系设计平台性的 CLI 工具,让 DataSimba 用起来更方便。
评论