辗转多个公司,我从与数据打交道的工作中学到了什么?

开发 前端
工作以来,笔者在各个公司见识了许多确保数据和代码质量的方法。每个公司可能遵循不同的流程和标准,但是有一些通用的原则可用于提高开发速度,改进代码维护,降低数据工作难度。

本文转载自公众号“读芯术”(ID:AI_Discovery)。

数据工程是本世纪发展最快的行业之一。工作以来,笔者在各个公司见识了许多确保数据和代码质量的方法。每个公司可能遵循不同的流程和标准,但是有一些通用的原则可用于提高开发速度,改进代码维护,降低数据工作难度。

[[350241]]

1. 函数式编程

笔者学习的第一种编程语言是Java。尽管深知面向对象编程与创建可重用类和模块相关的好处,但其在处理数据时不便应用。两年后,笔者偶然发现了R语言——一种函数式编程语言,笔者立刻就被它迷住了。

R语言能够使用dplyr包并简单地通过管道传输函数来转换数据并快速查看结果,大大便利了工作。但现在,Python要求将二者结合,编写面向对象的模块化脚本,同时利用函数式编程,这种编程在与R语言中的数据交互时运行良好。

函数式编程极其适用于处理数据,原因就在于几乎任何数据工程任务都可以通过输入数据实现,应用一些函数(也就是说,实现ETL中的T环节,即数据的转换,清洗及加载),将其输出加载到某个集中存储库,或者用于撰写报告或数据科学用例。

函数式编程范型在数据工程中非常常见,许多博客都写过关于它的文章。例如,下面链接的文章,是Apache气流的创始人马克西姆·博切宁在2018年初发表的:

https://medium.com/@maximebeauchemin/functional-data-engineering-a-modern-paradigm-for-batch-data-processing-2327ec32c42a

同样地,人们已经创建了许多数据工程工具来改善这一过程。函数式编程可让创建的代码重用在许多数据工程任务中。

2. 设计专用型函数

要使函数可重用,编写专用型函数是一种很好的实践。可以设计主要功能,并把不同的部分连接在一起。总的来说,笔者发现通过使函数缩小应用范围(即专门用于某项任务),可以更快地开发代码,因为识别和修复单个元素的错误更为容易。

功能范围更小也使得交换单个组件变得更容易,可以将它们像乐高积木一样针对不同的用例组合在一起。

3. 正确的命名规则至关重要

将对象进行命名,这样其他人查看代码时就可以立即理解你的意图,这种做法非常不错。但有些缩写可能不是每个人都能理解,所以最好避免使用,而是选择写出全名。我见过的大多数数据工程师倾向于使用以下协议:

  • 使用动词作为函数名,ex. get_dataframe_from_google_ads()可能比google_ads()更容易理解——较长的版本不仅能显示源系统,还可指出函数执行的操作和它返回的对象类型(数据框架)。它看起来很冗长,但通常只需要编写两次:一次是在定义时编写,一次是在调用时编写。因此,笔者认为编写那些较长的函数名是值得的。
  • 大写全局变量——与笔者工作过的大多数数据工程师都将全局变量定义为大写,以区别于局部变量(例如主函数中的变量)。
  • 许多人认为最好只在脚本的顶部定义导入——理论上,可以在函数或类中导入库,但是如果所有的导入都在脚本的顶部,那么跟踪包依赖关系可能会更容易。

理想情况下,命名可以使代码自我记录,这也可以实现高效编程。

4. 简洁而高质量的代码更便于维护

通常,程序员读代码要比写代码更频繁。因此,使代码易于阅读和理解是非常重要的。

通过进行恰当的命名和建立良好的结构,我们可以便利个人未来的工作,其他人在使用我们代码时也会更容易。代码简洁好处多多:编写的代码越少,需要维护的代码就越少。如果可以用更少的代码完成任务,这也是一种潜在的胜利。

5. 文档是关键,但前提是要做得正确

这听起来可能违反直觉,但是我们不应该记录代码在做什么;相反,我们应该记录为什么代码要做它正在做的事情,很多代码注释老在说明一些显而易见的事情。

例如,get_dataframe_from_google_ads()函数不必说明我们正在从谷歌广告下载数据,而应说明这样做的原因,例如“下载广告支出数据以供稍后的营销成本归因”。使用docstring或类型注释来记录函数的预期输入和输出非常有帮助,它能立马让你摇身一变成为更好的数据工程师。

6. 避免硬编码值

许多与ETL相关的SQL查询使用阈值但没有解释原因。例如,假设有一个脚本从某个表中提取数据,但只针对发生在2020年9月30日之后的事件,而且绝对没有文件证明为什么有人选择了这个特定的日期。

在不解释原因的情况下,人们要如何才能发现为什么这个值是硬编码的?这可能是因为,在那天,公司转向了一个新的源系统,新的数据提供商,或者他们可能改变了一些商业策略。笔者并非指在代码中这种业务逻辑是错误的,但如果不记录为什么有人选择了这样一个任意的阈值,这个硬编码的值在未来几年里可能会一直是下一代数据工程师的一个谜。

7. 避免保留僵尸代码

笔者经常遇到的一种常见的反模式是,有人保留了已弃用但遗留在脚本注释中的代码。也许有人想测试一些新的行为,保留旧版本以防新版本不能运行,或者这个人想要保存历史记录。笔者认为最好避免这种情况,因为它可能会使之后的开发人员很难区分哪个才是真正正确的版本。

例如,笔者曾经历过这样一种情况:被注释的代码片段比没有被注释的版本更有意义。但有时情况却往往相反,因为他或她会认为,被注释掉这个更合乎逻辑的版本是错误的。因此,保留僵尸代码可能是危险的。

8. 正确实现模块化:将业务逻辑与实用程序函数分离

将实用函数和业务逻辑混合在一起具有一定意义,但是将它们分开仍然有用。如果使用得当,公共功能可以被推到不同的包中,并在以后跨多项目重用。这种分离需要更多的前期工作(例如,为这样的包构建一个发布过程),但是从长远来看,可重用性和只定义一个功能的好处是值得的。

9. 简化代码

Python的宗旨是“简单比复杂好。”

许多数据工程师,特别是那些有计算机科学背景的工程师,可以创建复杂的解决方案,却过于繁复无法不够简单明了。例如,如果某些东西可以表示为一个简单的函数,该函数接受一些数据作为输入,并返回转换后的版本作为输出,那么为这种操作编写自定义类对象可能被认为是一种设计过度的解决方案。

10. 放远眼光

有时候我们需要在正确和快速之间做出权衡。创建通用型解决方案,以跨不同用例重用,从长期来看,这将使代码编写工作更为容易,开发更长。

例如,为跨项目共享的模块建立一个发布过程和CI/CD管道可能会在前期花费大量时间,但是这种额外的努力通常会在后期得到回报。花时间创建持续验证和监控数据质量的脚本同样如此。

[[350242]]

图源:unsplash

本文讨论了数据工程中确保数据的高质量和代码的可维护性的最佳方法。大多数数据工程任务可以表示为函数,这些函数接受输入数据并根据特定的任务需求对其进行转换。理想情况下,这些函数应该被设计为专用型,并进行文档记录,以便任何读代码的人都知道函数的输入项和输出项是什么。希望这篇文章能对你有帮助。

 

责任编辑:赵宁宁 来源: 今日头条
相关推荐

2021-03-09 09:55:02

Vuejs前端代码

2016-01-18 10:06:05

编程

2020-12-31 10:47:03

开发Vuejs技术

2021-07-28 07:01:09

薅羊毛架构Vue+SSR

2022-03-27 09:06:04

React类型定义前端

2020-02-22 14:49:30

毕业入职半年感受

2010-01-25 17:14:09

2015-09-06 16:03:57

2020-02-22 15:01:51

后端前端开发

2012-07-12 00:22:03

创业产品

2020-10-13 18:10:46

Kubernetes容器化云计算

2021-10-11 09:55:58

Facebook业务中断网络安全

2013-08-19 12:46:27

2021-07-26 07:47:36

C# 工作面试

2023-11-29 07:29:28

ReactSolid

2023-11-24 13:24:14

CIOOptus

2020-07-07 08:52:16

机器学习机器学习工具人工智能

2024-04-01 10:07:47

应用程序数据数据库

2024-04-12 08:54:13

从库数据库应用

2020-11-03 09:50:26

CIO远程IT在家工作
点赞
收藏

51CTO技术栈公众号