反应是死了吗?对于Ruby on Rails开发人员,Obie Fernandez说

2020-10-07 17:39:18

让我告诉你当我作为一个软件开发人员遇到一些准备给我的工作带来革命性变化的事情时,我的感觉是什么。骨头上特定的、有形的身体感觉;皮肤上的刺痛感和指尖的嗡嗡声。就像吸了太多的可卡因,如果你明白我的意思的话。

第一次是在2000年,当时我读到了“务实的程序员”和Kent Beck的第一本XP书,他们彻底颠覆了我对软件工程师意味着什么的想法。在此之前,老实说,我只是对我赚的钱感到兴奋,但手艺和极端编程让我成为了一个布道者,以至于我最终创立了敏捷亚特兰大(Agile Atlanta)。

第二次是在2005年2月,当时我和ThoughtWorks的Carlos Villela一起编写了我的第一个Ruby on rails应用程序。它是OkCupid的克隆,但它是为了让人们在咨询项目团队中一起工作,而不是为了浪漫。我是认真的;它叫Twix。(我仍然认为这是一个很酷的主意!)。然后我继续领导一些世界上第一个付费的“企业”Ruby on rails项目,剩下的就是历史了。

下一次是在2009年使用NoSQL(总体上)和MongoDB(具体地说)。我们在HashRocket的第一个Mongo项目带来了100多万美元的收入,也是Mongoid的发源地。

2015年,当AWS Lambda的发布让我成为一名早期的、热情的无服务器应用设计布道者,并让我如此兴奋,以至于我写了一本关于它的书时,我再次掀起了一股狂热。我确信这将是我的下一条铁路,但生活阻碍了我,试图写一本关于变化如此迅速的东西的书就是没有成功。(我确实计划有朝一日完成它,但我需要一些帮助。)。

反应式Rails,假设我们会这样称呼它,是我最新的痴迷。我认为这个名字听起来很好听,我在这里想做的一部分就是增强它的信号。

撇开名字不说,这不是您母亲的Rails代码。向Rails添加StimulusReflex和ViewComponent会改变一切。它给了我同样令人眼花缭乱的轻松感觉,就像我在2005年从J2EE切换到Rails时一样,以至于我正在以同样的方式在博客上谈论它。

到目前为止,我看到了反应式Rails的未来,反应式Rails意味着代码行减少了一个数量级,而生产力提高了一个数量级。请注意,Ruby on rails在正确的人手中已经是一个非常高效的堆栈,但自从采用WebPacker以来,它也变得超级复杂,以及它总是处于大规模爆炸状态的Javascript生态系统。

郑重声明,我个人对Javascript没有问题。请允许我吹嘘一下,好吧,因为你们大多数读到这篇文章的人可能不知道我的历史。早在21世纪初,在我还没有听说过Ruby之前,我就在使用不可见的Java applet和JSObject API编写复杂的富客户端应用程序,以完成多年后称为Ajax的工作。我的框架有数十万行高级Javascript代码,用于在Internet Explorer(当时最先进的浏览器)中实现整个基于JS的呈现子系统。那份工作是让我被ThoughtWorks录用的一个重要因素,然后是JBoss,然后是ThoughtWorks。我甚至听说有些今天还在生产。(有没有想过为什么有些公司不能脱离IE6?是的,我的错。对不起。)。

在过去的几年中,我实际上编写并维护了大量的反应代码。世界上最顶尖的反应专家之一在Kickass Partners为我工作。“反应”显然没有死。我知道它是一个庞然大物,而且ReactNative在它所做的事情上也是超级酷的。但我现在要说的是,Rails开发人员在技术上完全不需要再使用RESPECT了。别费心了。Reaction对我来说是死的,对你来说也应该是死的。因为事实证明,你可以吃到你的SPA蛋糕,它也可以,主要用Ruby烘焙,只撒一些Javascript糖霜。

在过去的三年里,我一直专注于(有时是全职)我的音乐事业,我是一名表演DJ和电子音乐制作人。然而,我仍然定期编写代码,主要是在副业项目上,偶尔也会通过我以前的咨询精品公司Kickass Partners(现已与MagmaLabs合并)进行有偿工作。

PromoGuru是我和音乐极客本·弗雷泽(Ben Fraser)在过去的六个月里一直致力于的一个附带项目,朝着最初的公开发布取得了缓慢而稳定的进展。直到本周,它还只是一个普通的Rails应用程序,在使用JQuery的过程中有一些交互性。

上周,当我们的1.0积压工作耗尽时,我从特性开发中退了一步,开始考虑清理和重构。我特别关注我们的主Javascript事件处理程序文件,它刚刚超过1000行。

自从10分钟内看了内特·霍普金斯精彩的Twitter克隆视频后,我一直对Stimulus Reflex很好奇。而鲁斯·汉曼那段愚蠢的视频完全把我逼到了悬崖边上,因为我真的想试一试。

我已经在PromoGuru上接受了Turbolinks和ActionCable,就像任何在Rails 6上启动新应用的人应该做的那样。结果是,获得Stimulus Reflex设置和攀登最初的学习曲线感觉相对来说没有痛苦。文档也很棒。

我做的第一件事是将一些非CRUD控制器动作重写为反射,这给我留下了非常深刻的印象。本想,“你不会在1.0发布之前全部重写吧?”

不,那可能不是个好主意。但我确实想解决与我们的对话框和音频预览播放器相关的一些明显的反模式,为此,我记得曾经读到过一个名为View Component的库正在获得的吸引力。另外,StimulusReflex的医生在显著位置提到了这一点。

引入面向对象视图的尝试几乎和Rails本身一样古老,我从来没有发现与仅仅使用分词相比,它们特别引人注目或特别方便。但这个想法的化身似乎不同,项目贡献者名单中包括TenderLove本人,所以我决定试一试。PromoGuru充满了UX比特和BOB,感觉他们无论如何都想成为组件,所以这感觉像是一个富有成效的实验。

有了我的新gem,我很快就遇到了关于尝试呈现组件的问题,我通过从rails 6升级到edge(6.1RC)修复了这个问题。它是无痛的,这并不令人惊讶,因为Basecamp,Shopify和Github都在边缘运行,所以它必须是稳定的。

一旦我掌握了模式的诀窍,我很快就变得如此高效,以至于它变成了一场疯狂的编码狂欢。我不仅进行了重构,还处理了一些边缘情况,并添加了一些可能要到项目后期才会涉及的细节。我欣喜若狂。我开始感觉到我刚才描述的那种刺痛感。

我已经看到了Rails编程的未来。它感觉像是Reaction编程,只不过…复杂度较低。

尽管我没有仔细记录我的工作时间,但我怀疑我花了大约15个小时才遇到了通常我通常会立即遇到的第一个尖端障碍。而且是在凌晨3点,所以可能更多的是与疲惫有关,而不是框架。就像我第二天早上起床10分钟就跨过了障碍,你知道吗?

各位,我已经看到了Rails编程的未来。感觉就像是Reaction编程,只不过复杂度更低,样板更少(是的,更神奇),Javascript代码行也少了很多。

现在,一个全面的描述从字面上讲就是写一本小书,但让我试着用项目符号来总结一下这个方法:

应用程序数据的规范状态保存在服务器端(数据库和缓存层),就像香草Ruby on rails整体一样。

多亏了Turbolinks,运行时客户端状态(谈论维护UX的状态和行为的Javascript对象)很容易在页面更改时保持不变。

所有模板呈现都是使用传统的Rails呈现技术在服务器端进行的(我是HAML的铁杆传道者,从来没有遇到过不立即鄙视的客户端呈现技术。(jsx,ugh)。

反射是响应客户端操作而改变服务器端状态的极小代码,并负责许多本来会编码为控制器操作的交互。

当您调用Reflex时,它会执行它需要做的任何事情,并且用户看到的屏幕会自动为您重新呈现。我不能夸大这节省了多少开发人员的工作!

在这种方法中,使用常规的基于JS的刺激控制器是可选的,但是您很快就会意识到它们的用处。当与您的反射相匹配时,它们为面向方面的服务器端交互增强提供了简单的挂钩。

…。或者,您可以编写完全与反射无关的刺激控制器,只处理客户端交互。(下面我将提供一些示例。)。

就像Reaction一样,只有需要更新的DOM部分才会不断更新,从而产生一些巨大的性能提升,也就是DOM差异。

对于某些操作,您可以完全不使用DOM,而使用CableReady全面的DOM操作API或StimulusReflex变形来更改UX的目标部分。(这样做的性能好处是巨大的!)。

CableReady使得从服务器端Ruby进程触发实时DOM更改变得简单,因为它都是基于WebSocket的。

ViewComponent允许您替换大量部分模板,并迫使您以组件化的心态考虑UX的构建块(这是件好事!)。

ViewComponent视图对象是普通的Ruby对象,具有定义良好的接口,这意味着它们非常容易推理和测试,而且比部分参数(加速10倍)要快得多。

ViewComponent的可选呈现功能极大地减少了您的普通视图模板中所需的条件逻辑量。

ViewComponent的“Sidecar”打包意味着您可以将Ruby代码与任何相关的部分代码、Javascript代码和CSS代码捆绑在一个名称空间(模块/文件夹)中。我已经可以断定,与在项目目录树上下涂抹这些内容相比,这是一个巨大的生产力提升。

我上面描述的每一件事都可以很容易地以进步的方式应用,这意味着这不是一件要么全有要么什么都没有的事情。让您的新项目的MVP成为一个普通的Rails+JQuery应用程序,然后用我上面描述的东西让它活跃起来,这正是我当前项目正在发生的事情。

正如我在上面最后一个要点中提到的,逐步增强一个普通的HTML应用程序是一件很大很大的事情,如果我对自己诚实的话,这可能是我最兴奋的事情。渐进式增强是大多数新Web项目的明智选择,但这种情况几乎不会再发生。

对于像我这样自豪的全栈工程师(和团队效率)来说,一旦决定使用Reaction,工程就会被一分为二,前端专家负责100%的Javascript SPA(Reaction、Vue.js等),而Rails人员只编写服务器API层。真没意思。

Turbolinks保证了单页面应用程序的性能优势,而不会增加客户端JavaScript框架的复杂性。据我所知,早在2016年,它就在版本5中大踏步前进,此后获得了广泛采用。

刺激是Basecamp的人发明的,用刚刚好的行为来增强HTML,让它发光(用他们的话说)。可能因为我已经沉浸在REACTIVE的用法中了,所以在这周之前我从来没有注意到它。事实上,我对在这上面投入时间有一定程度的犹豫,因为这看起来像是DHH为了它而反向操作的情况。我现在认为在这一点上我错了。

StimulusReflex承诺在不放弃高性能反应式用户体验的情况下,消除全栈前端框架带来的复杂性。

到目前为止,CableReady是我使用最少的部分,主要是因为我最初的印象是它只是一个StimulusReflex的支持库。它有点像在WebSockets上重生的RJS。我不会太多地谈论这一点,只是因为我还没有做太多的事情。然而,我得到的承诺是,它比Stimulus Reflex更能改变游戏规则。

让我分享我第一次从Promo Guru改写音频预览播放器的一些代码。这是一个截图,这样你就知道我在说什么了。

我从视图组件开始,因为我可以实际向您展示它的样子,然后我们将开始服务器端交互。

我计划制作很多组件,所以我将它们组织成代表功能的模块。到目前为止,我已经有了音频和Dropbox,但在这篇博客文章中,我只会谈论音频组件。

请注意,我使用的是SideCar资产,这意味着除了组件之外,我还包括Javascript和CSS文件。这使得它们很容易找到,并且保持了良好的组织。(如果它们不在这里,它们应该在资产中某个Components文件夹下。)。

这里有几个帮助器方法,但唯一与本文相关的是reflex_link_to。

好的,这就是开始有趣的地方。在此功能的第一次迭代中,我们简单地将一个隐藏的播放器放入曲目的部分模板中。这在渲染性能和膨胀的标记大小方面都是非常低效的,但是对于MVP来说已经足够好了。

当我想把它重构成更高效、更优雅的东西时,我的第一个倾向是制作一个始终位于屏幕底部的单个播放器,它有一个Javascript API,我可以用与正在播放的曲目相对应的参数来调用它。

这看起来很正常,对吧?但这需要编写大量的Javascript,并考虑播放器的(对象,而不是用户)界面,诸如此类。此外,我已经有了一个播放器,只要它拥有对Track实例的完全访问权限,它就可以工作。

反应式Rails设计的关键是要记住,服务器是客户端状态(或类似情况)的规范真相来源。即使在不明显的情况下也是如此!

考虑到这一建议,当正在播放曲目时,曲目对象可以驻留在@TRACK_TO_PLAY实例变量中。而在其他时候,它可能是空的。

请注意,要让Render接受组件对象实例而不会导致ActionView崩溃,您需要Rails 6.1,这意味着在撰写本博客文章(2020年10月)时,您必须运行Edge。据我所知,Basecamp,Shopify,甚至Github都快崩溃了。如果您运行的是Rails的发布版本,那么您必须使用Google来解决一些问题,不值得在这里讨论。

那我刚才说到哪儿了?哦,是的,我总是呈现组件,有时变量@Track_to_play是零,因为用户没有收听曲目,这很好,因为如果它是零,那么组件知道不呈现。全部不涉及模板中的任何条件(IF/ELSE)代码。

Class Audio::player<;ApplicationComponent attr_read:Track def Initialize(Track:)@Track=Track End Def Render?赛道,现在呢?终点终点。

那个效果图?方法是ViewComponent API的一部分。很难夸大它会让我从模板中去掉多少条件逻辑。

当您调用Reflex时,它会做它所做的事情,然后StimulusReflex会自动重新呈现当前屏幕,并将其发送到客户端,在客户端使用DOM差异魔术来计算出刷新可以避免多少屏幕。

点击Play(播放)按钮,然后即刻,Changeo!播放器出现在屏幕底部并开始播放。说到播放按钮,下面是它在使用中的样子。

在我结束之前,让我向你们展示一下常规(非反射)刺激行动是如何实施的。播放器有“上一步”和“下一步”按钮。我们的原始代码有一系列Javascript后空翻,以找到合适的玩家并隐藏可能正在玩的任何其他玩家,等等。

使用新的反应式方法,我所需要的就是以某种方式更改服务器上的Magic@Track_to_Play变量的状态,我应该会做得很好。其他一切都应该自动发生。

在这段从玩家模板中提取的代码中,需要注意的最重要的一点是,顶级元素有一个data-Controller属性,该属性标识哪个刺激控制器要连接到该元素。可以说,它是会受到刺激的东西。

目前,Rails 6.1和ViewComponent并没有很好地结合在一起。如果您按照我上面向您展示的所有操作进行操作,您很快就会发现,获取对ViewComponent模板的更改需要重新启动服务器。唉哟。

我做了一些调查,很快就想出了一个解决办法:

这似乎是一种倒退,所以我猜它很快就会修复的。解决办法也不是世界上最糟糕的。

对我来说,这感觉就像是一件大事的开始。我已经在想它有足够的肉来写一本新书了。而且似乎社区正在准备成为一场运动,而不仅仅是一个利基市场。因此,如果您对接下来发生的事情感兴趣,现在可能是点击Follow按钮的好时机!

为了一直读到我的博客帖子的底部,我想给你一份小礼物!