首先需要解决的重要的问题:数据工程和软件工程之间有哪些不同之处?

二者非常相似,许多起源于软件工程的最佳实践对数据工程同样有效,前提是需要正确地构建它们。

在本文中,将详细介绍几个软件工程的最佳实践,以及如何更好地创建和维护数据管道。文中将特别关注管道,因为这是我们在Estuary关注的重点,这些原则同样适用于大型数据堆栈。

本次讨论将是在高层进行,虽然我自己不是一个软件工程师,但是希望你能从下属原则中获取到战略和领导价值。

软件工程与数据工程:相似之处和区别

数据产品和软件产品是有区别的,其利益相关者各不相同。

通常,软件产品的构建涉及到高技术团队之间的协作,需要将产品交付给不同的用户群体,通常是商业用途的用户群体。例如,银行可能会为其客户创建一个移动应用程序。

相比之下,数据产品往往驻留在企业的内部,其利益相关者和参与者可以从高技术的工程师到需要利用数据来完成工作的非技术性专业人员。例如,同一家银行可能为其客户创建不同的财务和人口数据产品,以实现不同的安全、销售和战略功能。

在阅读这篇文章过程中,读者将在数据空间中徜徉,可能无需强调二者区别的细节,读者仅需要从业务的角度,来审视数据与软件的不同。

但是从本质上来讲,数据工程和软件工程的实践却基本相同,比如可以编写、维护和部署代码来解决一个可重复的问题,正因如此,某些有价值的软件工程最佳实践可以转换为数据工程最佳实践,许多最新的数据趋势——如数据网格和数据操作程序——以一种全新的方式实现了软件工程实践,并取得了良好的结果。

软件工程与数据工程的历史

通过查看历史数据,理解为什么这些最佳数据实践均来自于软件工程,并了解为什么直到最近才将它们应用到数据工程中的原因。

软件工程学科在20世纪60年代首次得到认可,当时,“软件创建是一种形式的工程”的想法是一种富有挑衅性的想法。事实上,选择“软件工程”这一词的目的是鼓励从业者停下来,将科学原理应用到实际工作中去。在接下来的几十年里,软件工程师对科学和机械工程中的原理进行了测试和改进。

在20世纪90年代,随着对软件需求的日增,整个行业落后于日益增长的软件需求,导致了所谓的“应用程序开发危机”,这次危机促使软件工程师采用敏捷开发和相关的实践,它意味着需要优先考虑快速的生命周期迭代,并对软件背后的人文系统赋予价值。

众所周知,数据工程是一个相对年轻的领域。虽然绝大多数人类历史的数据都早已经存在,但是关系型数据库则是在20世纪70年代创建的。直到21世纪初,数据库还只局限于小部分管理者,在IT领域,数据基础设施通常作为一个具有许多组件的企业内部资源,是一个相对较新的开发(毋庸讳言:是一个快速变化的开发), “数据工程师”这个职位起源于二十一世纪一十年代。

总之,软件工程师已经工作了大约60年,他们今天仍然在做大致相似的工作,期间,他们解决了很多问题。数据工程领域可以利用软件工程这一优势。

闲话少说,下文是一些可以(也应该)应用于数据管道的软件工程最佳实践。

1.设置(较短的)生命周期

软件或数据产品的生命周期包括规划、构建、文档化、测试、部署和维护在内的周期性过程。

敏捷软件开发通过缩短开发生命周期来满足需求,与此同时,继续进行产品迭代和产品改进。

同样地,可以(也应该)为数据管道实现一个快速的生命周期。

在整个组织中,对新数据产品的需求将迅速且频繁地出现,应为生命周期工作流中的全部环节,做好充分的准备。

  • 计划:与利益相关者一起制定计划,以确保管道能够交付所需的产品。
  • 构建:构建管道,根据不同的平台和接口,编写规范或创建DAG。
  • 文档化:记录管道,包括模式、元数据或书面文档(dbt docs 是一个不错的例子,尽管在数据堆栈的不同部分有不同的dbt docs 文档)。
  • 测试:在部署之前测试管道——管道工具可能有内置的测试,也可以编写自己的测试。
  • 部署:部署管道。
  • 监控:查看错误报警并进行更新。
  • 迭代:当用例变更时快速迭代,继续在先前的管道上构建并回收组件。

将敏捷开发方法集成到数据中的概念是DataOps框架的一个重要组成部分,参看我关于这个主题的全文。

2.选择正确的抽象层次

为确保数据生命周期更加紧凑,不要迷失在技术实现细节中,这一点非常重要,需要对技术具体实现细节进行抽象。

软件工程师对抽象的概念感觉良好,抽象是将信息简化为更一般的对象或系统,也可以将其视为泛化或建模。

在软件工程中,相关的抽象层次通常存在于代码的内部。例如,函数或面向对象的编程语言是有用的工具,但它们并没有揭示如何去执行这些细节。

在数据中,需要使用一个高于代码的抽象层级,主要有以下两个原因:

  • 数据产品和它们提供的业务用例之间相互关联,这意味着需要用更“现实”的术语来谈论数据。明确这一级别的抽象意味着需要建立一个通用语义层——并有助于避免在不同的BI工具和用户组中出现多个相互冲突的语义层。
  • 在数据涉众中发现更广泛的技术级别,这意味着谈论一些技术性比较强的东西(比如代码)时,并不是非常适用。

对于数据管道来说,两个相关的抽象是:从一个系统摄取数据并将其推送到另一个系统的行为(在Estuary中使用术语捕获和物化,但二者语义会有所不同)。

当谈论使用 “捕获”和“物化”这样的术语时,无论是工程师还是业务用户都需要将管道的语义价值统一起来(从系统X中获取数据推送到系统Y,这样便可以实现Z)。

3.创建声明式数据产品

理解上述意思之后,便抓住了重点,但这也仅仅是抽象讨论的延续,下面进行更多实质性的讨论。

首先考虑将数据视为一个产品,这是当下流行的数据网格框架的一个核心准则。

数据即产品属于公司内部的不同领域:拥有不同技能的团队,共享数据的操作用例。数据即产品可以快速转换为多种形式的可交付成果,这些成果全部是由用例来驱动的。换句话说:它们关乎“做什么”,而非“如何做”。

软件工程与声明式编程并行,声明式编程关注的是程序可以“做什么”,这与命令式编程恰恰相反,命令式编程关乎任务应该“如何做”。

声明式编程是建立在命令式编程之上的一种抽象程序:在运行时,程序经过编译之后,才能解决“如何做”的问题。声明性编程允许在运行时具备更大的灵活性,从而节省了资源。此外,声明性编程更容易控制,同时也更加容易实现。

使管道具有可声明性:首先在管道的功能基础上进行构建,而非根据管道的机制进行构建,从而能够更好地支持“数据即产品”的文化理念。

项目将从管道所要交付的产品开始,比如说,一个特定的实例化视图,并在此基础上设计管道,声明式管道方法确保不会迷失在技术细节中,忽略了数据的业务价值。

4.预防失效

在软件开发和数据管道中,失效不可避免。很多人都从失效中吸取过教训:努力修复灾难性的系统损坏,避免因中断而失去进度或数据,或者避免将一个低级错误放大。

无论在软件还是数据语境的应用中,都可以利用类似的预防性备份措施来预防失效的发生。

为此需要添加一些重要的考量,管道供货商会提供数据编排工具来实现这些功能。

测试

正如软件工程一样,测试是管道生命周期的一部分。

除了在部署前进行全面的手动测试之外,还应该编写自动化的单元测试,以密切关注量产中的管道。

如何编写这些测试内容取决于平台的种类以及如何与之交互。例如,如果需要在管道中使用Airflow,那么可以创建Python脚本来测试它们。或者,可能更偏向用一个更健壮的监控设置来捕获潜在的问题。

根据经验法则,数据管道应用的转换越多,需要的测试就越多。

版本控制

软件工程师使用版本控制,通常是用Git来协同工作,并保留将软件回滚到先前版本的能力。

如果使用的是来自供应商的产品,它可能会提供GitOps工作流,这意味着工程师可以使用Git在他们首选的开发环境中进行管道协作。然而,并不是所有人都这么做。

即使无法在数据基础设施中使用Git,供应商也会启用一些选项来备份管道,所以一定要充分利用该功能。

分布储存及回填能力

云托管和存储技术的出现降低了数据中断和数据丢失的风险,但它并没有完全消除这些风险。

数据基础设施应该选用分布式的,也就是说,不同的组件应分布到不同的服务器上,从而使其能够容错。对风险的控制程度取决于云提供商及其所选定供应商。

始终迭代

软件工程最佳实践的最后一条策略是:当某些例程不工作时,就进行迭代。

现状和最佳实践总是在不断的变化之中,这既适用于软件工程,也适用于数据工程。

最好的方法总是要经过深思熟虑,安全地引入变革,并得到所有利益相关者的支持。

从上述这些原则开始,通过相互间的合作配合,适配数据团队的系统和文化。始终关注那些积极的影响和需要改进的领域,并从那里开始行动。

Loading

作者 aibbs