通过转换者的眼睛凤凰和Rails之间的差异

当他刚开始与Phoenix一起研究Elixir时,最令他发狂的是什么。

注意事项


我是一个简单的人,我不会深入。 因此,工农级别会有所不同,但是关于应用程序启动级别的差异,Erlang虚拟机的操作原理和OTP协议的内容将一言不发。


主要印象


Elixir / Phoenix与Rails非常相似,但与此同时一点也不像他。 就像一些英语短语一样:各个单词都很熟悉,但在一起不清楚。


Erlang和Ruby


用卢布思考并尝试在长生不老药上写是很难的。 您经常陷入死胡同,因为您想要做的根本不像过去那样……或者,实际上,您根本不想要这样做。


至于其他内容,人们会写有关Erlang和Ruby差异的书,所以我会做简短的介绍。 对我来说,主要的伏击是用管道替换铁路“蒸汽机车”,将思维重新定位为功能主义(好处是inject过往经验和对inject / foldr的共同爱),并且主观上对数据类型的要求更加严格(尽管正式,两种语言都有严格的动态类型)。


模式匹配没有引起任何意外,我仍然不明白为什么这么多关于他的话题。 只是一个有趣的工具。


一般范围


在Elixir中,所有内容都位于模块中。 没有全球范围。 调用C#。


换句话说:导轨是平坦的,并且在某些地方会干扰层次结构的创建(我记得曾经有一些控制器位于模块中的错误)。 Elixir-相反,一切都在模块中。 在轨道中,您可以通过父类来猜测对象的用途,而在长生不老药中,可以通过类/模块的全名来猜测对象的用途。


可编译性


一方面,这就是我有时所缺乏的。 因为您可以在编译时发现很大一部分错误,而不是在生产时的运行时发现。 另一方面,编译需要时间。 但是,从第三方面来看,它需要一点时间,而且我还没有在长生不老药上看到大型项目(并且不是按erlang的规矩写大块巨石)。 最重要的是,灵丹妙药们在动态重新加载代码和页面方面做得非常出色。 到目前为止,工作的速度,再加上缺少无神的宙斯/春天,使我的灵魂更加温暖。


当然,这也带来了弊端,但它们却要晚得多了。 生产环境和部署领域中的某个地方。 有关此的更多信息。


这是一个有趣的事实,实际上是不可能在铁路上发生的:迁移和其他通过elixir的rake进入铁路的事情需要对项目进行编译,并且可能会发生类似的事情:忘记编写路线,视图中的路径助手引用了它们,但是迁移减少了。 起初-非常不寻常。


该文件


带有长生不老药文档的站点看上去比鲁比多克和阿皮多克更有活力。 但是这里有大量的文档和示例-这是ruby / rails遥遥领先的地方。 Elixir缺乏比大便复杂得多的示例。 实际上,对某些方法的描述并没有超出签名范围。 对于我来说,这很困难,因为我习惯于使用一些lix剂方法来摩擦大量的示例和说明。 有时,我不得不四处摸索,并进行了长时间的试验,以了解如何使用该方法或该方法,因为我不太了解该语言,因此无法自由阅读这些程序包的源代码。


文件位置与其内容无关


正如他们所说的“强大的力量伴随着巨大的责任”。 一方面,您可以制作细菌并分解物体,这样敌人绝对不会越过。 另一方面,您可以更逻辑和更清楚地命名路径,添加不在类层次结构中的目录的逻辑级别。 特别是,我们可以将开拓者之类的东西与一个动作相关的所有东西都集中在一个地方,从而回想起开拓者之类的东西。 在长生不老药中,无需第三方库和类堆,只需简单地正确移动现有文件即可完成此操作。


透明的请求路径


如果在Rails中,有关机架的问题是任何采访中必不可少的属性,因为Rail是冰山一角,并且您有时会想要制作中间件。 在这种渴望的灵丹妙药中根本不会出现(尽管也许我还很年轻,并且一切都在前面)。 有一组明确的请求通过的管道。 在这里,您可以清楚地看到在何处提取会话,在何处处理flash-messge,在何处验证了csrf,并且可以随意控制所有这些操作。 在铁路上,整个农场被部分钉住,部分分散在不同的地方。


由内而外的路线


在Rails中,一种动作可以以多种格式响应的情况是常态。 甚至在路由中放置(.:format) 。 在the剂中,由于管道具有上述特性,因此根本不存在格式类似物的想法。 不同的格式在不同的管道上使用,并具有不同的URL。 对我来说很健康


模型中的电路


这通常是童话。 当您描述模型的字段时,情况将会如此。 没有类型的隐式转换。 此外,没有拐杖来限制对数据库中字段的访问,但是由于某些原因,它不能在Web应用程序中使用。


验证和回调


长生不老药中没有回调。 那里的一切都更加简单。 我想我喜欢。


而不是结合了Strong_parameters,验证和一些回调的Elixir changeset中的方法。 其余的回调都经过Multi ,这使得可以收集一堆操作,以事务方式执行它们并处理结果。


简而言之,一切都不同。 起初这是不寻常的。 然后,在某些地方它使我非常生气,因为您不能只为所有内容添加另一个回调,而不必考虑不同的业务案例。 然后您开始注意到“莫名其妙的魅力” ,因为您必须正确地做它,而不是像以前那样。


使用数据库


出现了一些Ecto.RepoEcto.Query和其他几个兄弟而不是ActiveRecord。 分辨所有差异是另一篇文章。 因此,我会说主要的主观感受。


在调试中比AR更方便。 由于存在一个通用范围,因此在访问它们时会从加载路径中加载这些常量,您只需打开rails c ,编写User.where(email: 'Kane@nod.tb').order(:id).first并获取结果。


在Elixir中,控制台是不够的。 需要执行许多操作:


  • 导入用于构建sql查询的方法: import Ecto.Query, only: [from: 2] ;
  • 添加类以避免拼写其全名:
    • alias MyLongApplicationName.UserUser而不是MyLongApplicationName.User
    • alias MyLongApplicationName.Repo类似地,用于访问可以执行sql并返回结果的类;
  • 而且只有现在,您可以from(u in User, where: u.email == "Kane@nod.tb") |> Repo.one

另一方面,在应用程序代码中,这些“形式”使代码更具可读性,而且还有一种感觉,您可以控制正在发生的事情,而不是自己活着。 也就是说,您选择需要使用的方法,模型和其他对象,然后显式加载并使用它们。


申请名称


在Rails的图像和相似之处中,我假设应用程序名称用于一对配置中,仅此而已。 因此,我没有注意名称的长度。 但是徒劳。 在Elixir中,带有应用程序名称的模块是Web应用程序模块层次结构中的顶层,并且随处可见。


我称呼我的沙盒为Comindivion。 现在我有点受苦了,因为这是一个相当长的名字,您需要不断编写它。 调用任何内容时,都在类文件和控制台中。 顺便说一句,是的,谁在乎, 这是GitHub上的沙箱


N + 1


在Rails中,我们开箱即用,但在Elixir中,开箱即用没有问题。 在请求组装阶段,您可以在那里指定需要哪些关系,并将在执行此请求期间将其加载。 尚未上传? 您将无法访问此关系。 一切都简单而美丽。


请求处理和响应


简而言之:在凤凰城,一切都比铁路更明显。


无处不在conn


由于状态没有存储在不同对象的堆中,因此必须将其拖到一个对象中。 提醒ActionController request ,只会更加全面。 在凤凰城的connection他被称为。 它包含所有内容: requestflashsession和所有内容。 他出现在与处理到达的请求有关的所有事务的呼叫中。


在这里和缺点,因为第一个非常懒惰雕刻各地conn并且不完全理解为什么。 铁路在这方面腐败。 您编写渲染或Flash时,没有想到该操作与连接有关。 在Phoenix conn不断提醒您使用特定的连接或套接字,而不仅是方法被调用而且魔术在内部发生。


部分和模板


在Phoenix中,局部和模板之间没有分隔。 最终整个功能。 这里还有另外一个魅力:即使在生产环境中,导轨也不断爬到磁盘上的视图后面,并产生IO和开销,以将其从erb / haml / etc转换为html。 在Elixir中,一切都是功能,包括视图。 一劳永逸地编译视图:获取参数,吐出html,不会进入磁盘。


观看次数


在Rails中,视图被理解为部分视图和模板,而在Phoenix中,视图被理解为模板,而在视图中,粗略地说,存在表示数据的不同方式。 特别是,存在渲染替代。


也就是说,默认情况下,控制器不渲染任何内容。 一切都被明确地调用。 而且如果您没有局部视图,并且您实际上并不需要它(例如,对于json,当它由服务类轻松构建时),则可以按以下方式重新定义渲染:


 def render("show.json", %{groups: groups}) do %{ groups: groups } end 

并且不再需要部分。


Heplers


凤凰城没有。 这太棒了! 对于铁路辅助人员来说,通常会收集所有垃圾,这些垃圾要么懒惰地推到角落,要么只需要快速填充即可。


但是,控制器,视图等中的方法。 您可以添加。 这是在特殊位置web/web.ex ,看起来还不错。


静力学


在开发过程中,一切都照常进行,只是在phoenix中它们仍然搞砸了实时重新加载,第一个调用“哇!”。 效果。 这是当我更改CSS并返回到浏览器时,更改本身已经加载的地方。


在Phoenix的生产中,静力学的行为与导轨的行为略有不同。 默认情况下,可以拖动静态对象的位置已明确注册,并且不能仅将文件添加到资产中以进行分发。 仍然存在默认资产的映射,因此您不必再次在FS上四处走动,而是立即拿走所需的文件并将其分发出去。


资产


在凤凰早午餐中开箱即用。 您可以将其替换为webpack 。 但是,有一个相当真实的笑话是关于许多项目都在webpack设置阶段进行的。


简而言之,js和css或多或少都被收集了,但是早午餐中的其他静态数据并不是很好。 您可以直接将其从node_modules复制到项目中(我根本不喜欢该选项),也可以在bash上编写钩子。 例如, 那样


使用SSL


在Phoenix中,开箱即用的是一个名为cowboy的小型http服务器。 它看起来像红宝石美洲狮 。 它们甚至在GitHub上具有相同数量的星星。 但是以某种方式我没有在上述任何一项中获得SSL设置。 特别是使用Let's Encrypt时 ,额外的Web服务器配置文件和定期的证书续订。 因此,作为http服务器-好的,但是对于ssl,我通过apache / nginx将代理传递给localhost。


部署


与导轨相比,它通常有所不同。 在最低版本的Rails中,他将萝卜带到服务器上,用铃鼓跳舞以获取捆绑软件,配置,资产并启动了该应用程序。 然后长生不老药编译并 挖电车 说服萝卜不会骑。 需要收集包裹。 从这里开始:


  • 您会发现为什么在mix.exs中需要应用程序,因为没有在mix.exs正确地指出应用程序中的奇妙错误;
  • 您将了解到,环境变量是在构建程序包时而不是在启动程序包时编译的,这是第一次令人惊讶。 然后您将了解relx以及RELX_REPLACE_OS_VARS=true并放手一点;
  • 您会惊讶地发现,在用于生产的已编译软件包中,没有什么类似于rake,尤其是没有迁移,并且您需要以某种方式单独运行它们,例如,从开发环境到端口转发到数据库(或通过eDeliver ,这将做同样的事情) 。

然后,当您处理以上问题时,专业人士便开始了:


  • 您可以使程序包自给自足,并且不要将任何依赖项放在战车上; 只需解压缩tarball并运行其中的内容; 除非可能需要推出erlang,否则因为它的交叉编译版本在汇编中有点不平凡;
  • 您可以进行升级发行以进行部署而不会停机。

德巴格


Elixir有Pry ,就像红宝石一样工作。 甚至还有看起来像iex -S mixrails c对应物。


但是在生产中,您必须以不同的方式使用控制台,因为该程序包是内置的,没有mix 。 您必须连接到工作进程。 这与导轨完全不同,一开始您会花大量时间在生产中启动Elixir控制台,因为您正在寻找与导轨类似的东西。 结果,您了解需要做所有不同的事情,并调用类似的命令: iex --name trace@127.0.0.1 --cookie 'from_env' --remsh 'my_app_name@127.0.0.1'


待续...


h,我以某种方式忘记了一些东西。 哦好 与其他语言相比,您最好告诉我们让Elixir感到惊讶的地方。

Source: https://habr.com/ru/post/zh-CN423459/


All Articles