不变性的逆向观点
TL/DR:在 JavaScript 中,不变性更像是一种时尚趋势,而不是必需品。如果您使用 React,它确实为状态管理中的一些 confusing design choices 提供了一个巧妙的解决方法。然而在大多数其他情况下,它不会为它引入的复杂性增加足够的价值,为pad up a resume 提供更多服务而不是满足实际的客户需求。
长答案:阅读下文。
为什么 javascript 中的不变性如此重要(或需要)?
嗯,很高兴你问到!
前段时间,一位名叫Dan Abramov 的非常有才华的人编写了一个名为Redux 的javascript 状态管理库,它使用纯函数和不变性。他还制作了一些really cool videos,使这个想法非常容易理解(和销售)。
时机恰到好处。 Angular 的新颖性正在消退,JavaScript 世界已准备好专注于具有适当酷度的最新事物,这个库不仅具有创新性,而且与 React 完美匹配,而 React 正在被另一个 @ 兜售987654328@.
虽然可悲的是,时尚在 JavaScript 世界中占据主导地位。现在阿布拉莫夫被誉为半神,而我们所有凡人都必须服从Dao of Immutability...不管这是否有意义。
改变对象有什么问题?
什么都没有!
事实上,程序员一直在变异对象,呃……只要有对象需要变异。 50+ years 换句话说就是应用程序开发。
为什么要把事情复杂化?当你有对象cat 并且它死了,你真的需要第二个cat 来跟踪变化吗?大多数人只会说cat.isDead = true 就可以了。
(变异对象)不是让事情变得简单吗?
是的! .. 当然可以!
特别是在 JavaScript 中,它在实践中最有用的是呈现在其他地方(例如在数据库中)维护的某些状态的视图。
如果我有一个新的 News 对象需要更新怎么办? ...在这种情况下我该如何实现?删除商店并重新创建它?向数组中添加对象不是成本更低的操作吗?
好吧,您可以采用传统方法并更新 News 对象,因此您在内存中对该对象的表示会发生变化(以及向用户显示的视图,或者希望如此)...
或者……
您可以尝试性感的 FP/Immutability 方法并将您的更改添加到 News 对象到跟踪每个历史更改的数组中,这样您就可以遍历数组并找出正确的状态表示应该是(呸!)。
我正在尝试了解这里的内容。请赐教:)
时尚来来去去,伙计。给猫剥皮的方法有很多。
很抱歉,您不得不忍受一组不断变化的编程范式所带来的困惑。但是,嘿,欢迎来到俱乐部!!
关于不变性,现在需要记住几个重要的点,你会以只有天真才能聚集的狂热强度将它们扔给你。
1) 不变性对于避免race conditions in multi-threaded environments非常有用。
多线程环境(如 C++、Java 和 C#)会在多个线程想要更改对象时锁定对象。这对性能不利,但比数据损坏的替代方案要好。但还不如让一切都变得不可变(上帝赞美 Haskell!)。
但是唉!在 JavaScript 中你总是operate on a single thread。甚至网络工作者(每个都在separate context 中运行)。因此,由于在执行上下文(所有那些可爱的全局变量和闭包)中不能有 线程相关 竞争条件,支持不变性的主要观点就不再适用了。
(话虽如此,在 Web Worker 中使用纯函数有一个优势,那就是你不会期望在主线程上摆弄对象。)
2) 不变性可以(以某种方式)避免应用状态中的竞争条件。
这是问题的真正症结所在,大多数 (React) 开发人员会告诉您,不变性和 FP 可以通过某种方式发挥这种魔力,让您的应用程序的状态变得可预测。
当然,这并不意味着您可以避免race conditions in the database,要实现这一目标,您必须协调所有浏览器中的所有用户,为此您需要一个后端推送技术,例如 WebSockets(更多内容见下文),它将向运行应用程序的每个人广播更改。
这也不意味着 JavaScript 中存在一些固有问题,即您的应用程序状态需要不变性才能变得可预测,任何在 React 之前编写前端应用程序的开发人员都会告诉您这一点。
这个相当令人困惑的说法只是意味着如果您使用 React,您的应用程序很容易出现竞争条件,但这种不变性可以让您摆脱这种痛苦。为什么?因为 React 很特别.. 它首先被设计为带有状态管理 subverted to that aim 的 highly optimised rendering library,因此组件状态通过优化渲染的 asynchronous chain of events(又名“单向数据绑定”)进行管理,但是您无法控制和依赖你remembering not to mutate state directly...
在这种情况下,很容易看出对不变性的需求与 JavaScript 无关,而与 React 有很大关系:如果在你的新应用程序中有一堆相互依赖的变化,并且没有简单的方法来计算找出您当前的状态,you are going to get confused,因此使用不变性来跟踪每个历史变化是非常有意义的。
3) 竞争条件非常糟糕。
好吧,如果您使用 React,它们可能是。但如果你选择不同的框架,它们就很少见了。
此外,您通常还有更大的问题需要处理……诸如依赖地狱之类的问题。就像一个臃肿的代码库。就像你的 CSS 没有被加载一样。就像一个缓慢的构建过程或被困在一个单一的后端,这使得迭代几乎不可能。就像没有经验的开发人员不了解正在发生的事情并把事情弄得一团糟。
你知道的。现实。但是,嘿,谁在乎呢?
4) 不变性利用Reference Types 来减少跟踪每个状态变化对性能的影响。
因为说真的,如果您要在每次状态更改时都复制内容,那么您最好确保自己对此很聪明。
5) 不变性允许您撤消操作。
因为呃..这是您的项目经理要求的第一个功能,对吧?
6) 不可变状态与 WebSockets 结合有很多很酷的潜力
最后但并非最不重要的一点是,状态增量的累积使得与 WebSockets 的结合成为一个非常引人注目的案例,它允许轻松使用 state as a flow of immutable events...
一旦这个概念(状态是事件的流动——而不是代表最新观点的一组粗略记录)下降,不变的世界就变成了一个神奇的栖息地。一片充满event-sourced 奇迹和可能性的土地,超越了时间本身。如果做得好,这绝对可以让实时应用程序更容易完成er,您只需将事件流广播给所有感兴趣的人,这样他们就可以build their own representation 当前并将他们自己的更改写回社区流动。
但在某个时刻,你醒来并意识到所有的奇迹和魔法do not come for free。与你热心的同事不同,你的利益相关者(是的,付钱给你的人)很少关心哲学或时尚,而很关心他们为构建可以销售的产品而支付的钱。最重要的是,它更难为不变性编写代码并且更容易破坏它,而且如果你没有后端来支持它,那么拥有一个不变的前端就没有什么意义了。当(如果!)你最终说服你的利益相关者你应该通过 push techology 像 WebSockets 一样发布和消费事件,你会发现 pain it is to scale in production 是什么。
现在请教一些建议,如果您选择接受的话。
选择使用 FP/Immutability 编写 JavaScript 也是使您的应用程序代码库更大、更复杂且更难管理的选择。我强烈主张将这种方法限制在你的 Redux reducer 上,除非你知道你在做什么......如果你要继续使用不变性,那么应用immutable state to your whole application stack,而不仅仅是客户端,因为你错过了它的真正价值。
现在,如果您有幸能够在工作中做出选择,那么请尝试使用您的智慧(或不使用)和do what's right by the person who is paying you。你可以根据你的经验、直觉或你周围发生的事情来做这件事(诚然,如果每个人都在使用 React/Redux,那么有一个有效的论点是更容易找到资源来继续你的工作)。或者,您可以尝试Resume Driven Development 或Hype Driven Development 方法。它们可能更适合你。
简而言之,不变性要说的是,它将让你在同龄人中变得时髦,至少在下一个热潮到来之前,到那时你会很高兴搬家开。
在本次自我治疗之后,我想指出我已将此作为文章添加到我的博客中 => Immutability in JavaScript: A Contrarian View。如果您有强烈的感觉也想摆脱胸膛,请随时在那里回复;)。