3

面向数据的编程 · Laurent

 2 years ago
source link: https://www.jdon.com/59131
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

面向数据的编程 · Laurent

我学习了DDD领域驱动设计、六边形架构面向数据的编程。我在 Airbnb与Daniel Low在Krispr的工作中使用了前两个。当我们的需求发生变化时,它可以更轻松地扩展项目、重新设计其依赖项和交付机制。然而,今天,我正在写我最近的兴趣:面向数据的编程。

面向数据的编程

Yehonathan Sharvit推广该术语Data-Oriented Programming以包含一组原则,使开发代码库变得更容易。虽然这些原则都不是新颖的,但它们在行业中并不是主流,它们确实使使用代码变得容易得多。

多年来阅读 Yehonathan 的博客文章后,我买了他的书,我很喜欢!当谈到技术写作风格时,这是一股清新的空气。这本书讲述了两个开发人员一起学习面向数据的编程原理的故事。它使用了一种引人入胜的对话风格,让你想更多地了解他们的故事以及他们正在解决的下一个问题。

在这篇文章中,我将解释我从书中得到的 3 个关键思想:

  1. OOP 迫使您一次性同时做出太多限制设计并导致重写的决定
  2. 使用通用和开放的数据结构表示所有数据,更容易探索和扩展系统的状态
  3. 不可变的数据结构是必须的,它使推理程序更容易

1. OOP迫使你同时做出太多限制设计和导致重写的决定

在做一个副业的时候,直到最近,我默认的选择是使用Python的OOP。我注意到,随着项目的发展,我倾向于重写很大一部分代码,以更好地表达我的想法,选择更好的名字,更好的类层次,以不同的方式表示数据或副作用。OOP吸引了我的完美主义倾向,有时会让我想重写系统中没有必要重写的部分。它刺激了我的智力,看我如何能在数据上提出最好的抽象,最容易使用的模式。

在读完面向数据编程的OOP章节后,我改变了主意。我觉得有必要尝试用Clojure构建我所有的副业,并从一开始就实践代码和数据的分离。这就是我在最近的项目中采用的风格:一个跟踪我的预算并自动对进入的交易进行分类的工具(就像Mint,但在对交易进行分类方面做得更好)。我只写了一次项目,还没有感觉到重做它的核心部分的冲动。最近,我也开始重构代码,把所有的数据从Clojure文件中提取出来,放到一个配置文件中,这非常容易,只需要10分钟。

{
 :start "01/01/2021"
 :end "12/31/2021"
 :sources [{:type "folder-recursive" :value "/Users/laurent/Downloads"}]
 :input-folder "/Users/laurent/Downloads"
 :report-name "2021"
 :output-folder "/Users/laurent/Documents/budget"
 :exclusion-rules '[("description%" #{"AUTOPAY PAYMENT"})]
 :categories-rules
 '[
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;; High priority rules                             ;;
   ;; These entries categorize specific transactions  ;;
   ;; with a specific date, they take precedence over ;;
   ;; the other rules                                 ;;
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


   ("venmo"                   "laurent/haircut" {:date "03/25/2021" :amount 40.0 :note "Tried a new hair style, it turned out great, go back there" :rating "A"})
   ...
   ]'
 }

简而言之,我将继续分离数据和代码,并从一开始就为我的副项目采用函数式风格。它只是让我更有效率,并消除了我重构为更好抽象的倾向。

2. 不可变的数据结构是必须的,它使推理程序更容易

阅读代码时,您必须牢记很多上下文和抽象概念。我在与其他人的工作中发现,与阅读散文不同,阅读一段复杂的代码对于最有经验的程序员来说也是一项挑战。在使用不具有不可变数据结构的语言(大多数语言)时,我们要牢记的一个特别考虑因素是操作可能会发生in place或return a new copy.

例如在 Python 中,对列表进行排序:

list.sort() 对列表进行排序并替换原始列表,而 sorted(list) 返回列表的排序副本,而不更改原始列表。

一些语言和社区已经找到了区分这两者的方法,例如 Ruby 社区已经对!字符进行了标准化,以指示发生变化的操作。然而,记住约定并应用它取决于各个程序员。这就是为什么,即使我阅读 ruby​​ 代码,有时我也必须检查我使用的是哪种操作风格。

面向数据的编程中,Yehonathan 提倡不可变和持久的数据结构。首先是一些定义:

  • 不可变数据结构

一旦有了值就不能改变的数据结构。它也被称为“冻结”数据结构。这是一个抽象的概念。

  • 持久数据结构

使用结构共享实现高效的不可改变的数据结构的方法

  • 两个数据结构之间的结构共享

当数据结构引用同一块内存时,即使它们彼此不同。一个例子说明了这一点:对列表 ["a", "b"] 和列表 ["a", "b", "c"] 进行映像。后者可以建立在前者之上,重用内存布局并在其末尾添加“c”。

不可变数据结构是主流,我已经看到它们在业界的应用,特别是在Java的Guava中,但持久性的数据结构不是,这是一种耻辱,因为它们是表示不可变数据结构的有效方法, Clojure是我所知道的唯一一门语言,该语言中的所有数据结构默认都是持久性的。

建议:如果你在面试中提到持久化数据结构作为解决问题的一种方式,请确保你知道如何实现它们(阅读一些论文,例如这篇)。

当你使用不可变数据结构(无论是否持久化)时,一整类bug就会消失,你不必一直考虑操作是否会突变底层数据,它们根本不会这样做。

我喜欢Yehonathan在《面向数据的编程》中解释所有这些概念,并链接到使用这种数据结构的常见语言的库。它为我澄清了这些术语,并使我更加确信,不可变数据结构几乎总是要走的路。唯一的例外是对性能高度敏感的代码,但我的工作中很少写这种代码。

3. 使用通用和开放的数据结构表示所有的数据,这使得探索一个系统的状态和扩展它变得更加容易。

早些时候,我提到我如何配置我的预算分析器。在配置中,你可能已经注意到这一行。

("venmo" "laurent/haircut" {:date "03/25/2021"
                            :amount 40.0
                            :note "Tried a new hair style, it turned out great, go back there"
                            :rating "A"})

项目的代码中没有任何东西知道:note和:rating,我只是在写规则时加入了它们,以对交易进行分类,记录我喜欢那个发型的事实。这之所以可能,只是因为我使用通用和开放的数据结构来表示我的所有数据。在Clojure中,我使用列表、向量、地图和原始类型来表示我程序中的所有数据。如果你习惯于OOP,这听起来可能很可怕,Yehonathan在他的书中再一次很好地驳斥了为什么它一点也不可怕的原因!

由于方法上的这一小小的改变,我能够在数据上使用丰富的通用操作(例如由Clojure标准库提供),我也可以轻松地进行序列化和反序列化,检查系统的运行状态并为数据提供时间旅行机制。

结语

如果你喜欢我上面介绍的一些想法,我鼓励你阅读《面向数据的编程》,看看你如何以不同于你所习惯的角度来处理编程任务。它已经成为我在副业和不受制于OOP代码库时的新工作方式。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK