当前位置: 首页 > 科技观察

我从处理多家公司的数据中学到了什么?

时间:2023-03-16 11:51:15 科技观察

本文转载自公众号《核心阅读》(ID:AI_Discovery)。数据工程是本世纪发展最快的行业之一。工作以来,笔者在各个公司看到了很多保证数据和代码质量的方法。每个公司都可能遵循不同的流程和标准,但有一些通用原则可用于提高开发速度、改进代码维护并使数据处理更容易。1.函数式编程我学习的第一门编程语言是Java。虽然面向对象编程与创建可重用类和模块相关的好处是众所周知的,但在处理数据时应用起来并不方便。两年后,我偶然发现了一种函数式编程语言R,并立即被吸引住了。R语言可以使用dplyr包,简单的通过pipeline传递函数进行数据的转换,并快速查看结果,极大的方便了工作。但是现在,Python需要两者的结合,编写面向对象的模块化脚本,同时利用函数式编程,这在与R中的数据交互时效果很好。函数式编程非常适合处理数据,因为几乎任何数据工程任务都可以通过输入来实现数据,应用一些功能(即在ETL中实现T-link,即转换、清洗和加载数据),并将其输出加载到集中存储库中,或用于编写报告或数据科学用例。函数式编程范式在数据工程中非常普遍,许多博客都写过它。例如,下面链接的文章由ApacheAirflow创始人MaximeBocherin于2018年初发表:https://medium.com/@maximebeauchemin/functional-data-engineering-a-modern-paradigm-for-batch-data-processing-2327ec32c42a同样,已经创建了许多数据工程工具来改进流程。函数式编程允许创建的代码在许多数据工程任务中重复使用。2.设计专用函数为了使函数可重用,编写专用函数是一个很好的做法。可以设计主要功能并将不同的部分连接在一起。总的来说,作者发现通过缩小函数的范围(即专用于某项任务),可以更快地开发代码,因为它更容易识别和修复单个元素中的错误。更小的功能范围也使得更换单个组件变得更容易,这些组件可以像乐高积木一样针对不同的用例进行组合。3.正确的命名规则至关重要。给对象起个名字是非常好的,这样别人一看代码就能立刻明白你的意图。但是有些缩写可能不是每个人都看得懂,所以最好避免使用,而选择写全称。我见过的大多数数据工程师倾向于使用以下协议:使用动词作为函数名称,例如。get_dataframe_from_google_ads()可能比google_ads()更容易理解——更长的版本不仅显示了源系统,还指明了函数执行操作及其返回的对象类型(数据框)。它看起来很冗长,但通常你只需要写两次:一次在定义时,一次在调用时。因此,我认为写那些较长的函数名是值得的。将全局变量大写——与我合作过的大多数数据工程师都将全局变量定义为大写,以将它们与局部变量(例如main函数中的变量)区分开来。许多人认为最好只在脚本顶部定义导入-理论上,您可以在函数或类中导入库,但如果所有导入都在脚本顶部,跟踪包依赖性可能会更容易.理想情况下,命名将使代码自我记录,这也可以实现高效的编程。4.简洁优质的代码更容易维护通常,程序员阅读代码的频率要高于编写代码的频率。因此,让代码易于阅读和理解是非常重要的。通过适当地命名事物并建立良好的结构,我们可以使我们以后的工作对其他人来说更容易,其他人也将更容易使用我们的代码。简洁代码的优点有很多:编写的代码越少,需要维护的代码就越少。如果可以用更少的代码完成任务,这也是一个潜在的胜利。5.文档是关键,但前提是做对了这听起来可能违反直觉,但我们不应该记录代码的作用;相反,我们应该记录为什么代码正在做它正在做的事情。陈述一些显而易见的事情。例如,get_dataframe_from_google_ads()函数不必说明我们正在从GoogleAds下载数据,而是说明为什么要这样做,例如“下载广告支出数据以用于以后营销成本的归因”。使用文档字符串或类型注释来记录函数的预期输入和输出会非常有帮助,并且会让您立即成为更好的数据工程师。6.避免对值进行硬编码许多与ETL相关的SQL查询使用阈值而没有解释原因。例如,假设有一个脚本从某个表中提取数据,但仅适用于2020年9月30日之后发生的事件,并且绝对没有关于为什么有人选择该特定日期的文档。如何在不解释原因的情况下找出为什么这个值是硬编码的?可能是因为在那一天,公司迁移到了新的源系统、新的数据提供商,或者他们可能改变了某些业务策略。我并不是说这种业务逻辑在代码中是错误的,但是如果不记录为什么有人选择这样一个任意的阈值,这个硬编码的值可能在未来几年对下一代数据工程师来说仍然是个谜。7.避免持久化僵尸代码作者经常遇到的一种常见反模式是有人保留脚本注释中留下的已弃用代码。也许有人想要测试一些新行为,保留旧版本以防新版本不起作用,或者也许这个人想要保留历史。我觉得最好避免这种情况,因为这可能会让后来的开发者很难区分哪个才是真正正确的版本。例如,作者遇到过这样一种情况,即注释代码片段比未注释版本更有意义。但有时情况往往恰恰相反,因为他或她会认为注释掉的更合乎逻辑的版本是错误的。因此,保留僵尸代码可能很危险。8.正确实现模块化:将业务逻辑与实用功能分开将实用功能和业务逻辑混合在一起是有意义的,但将它们分开仍然有用。如果使用得当,可以将通用功能推送到不同的包中,然后在多个项目中重复使用。这种分离需要更多的前期工作(例如为这样的包构建发布过程),但从长远来看,可重用性和只定义一个功能的好处是值得的。9.简化代码Python的座右铭是“简单胜于复杂”。许多数据工程师,尤其是具有计算机科学背景的数据工程师,可以创建过于复杂而不够简单的复杂解决方案。例如,如果某些东西可以表示为一个简单的函数,它将一些数据作为输入并返回一个转换后的版本作为输出,那么为这样的操作编写一个自定义类对象可能被认为是一种过度工程的解决方案。10.放眼长远有时我们需要在正确和快速之间做出权衡。创建可以在不同用例中重复使用的通用解决方案将使编码更容易,从长远来看开发时间更长。例如,为跨项目共享的模块设置发布流程和CI/CD管道可能会在前期花费大量时间,但这种额外的努力通常会在以后得到回报。花时间创建脚本来持续验证和监控数据质量也是如此。来源:unsplash本文讨论了在数据工程中确保高质量数据和可维护代码的最佳方法。大多数数据工程任务都可以表示为获取输入数据并根据特定任务要求对其进行转换的函数。理想情况下,这些函数应该专门化并记录在案,以便任何阅读代码的人都知道函数的输入和输出是什么。希望这篇文章能帮到你。