📜 ⬆️ ⬇️

Phoenix and Rails Differences through Convert Eyes

What most caught his eye to the avid rubist when he had just begun to study Elixir with Phoenix.

Note


I am a simple man and I will not go deep. Therefore, there will be differences between workers and peasants, and nothing will be said about the difference at the level of application launch, about the principles of the Erlang virtual machine and the OTP protocol.


Main impression


Elixir / Phoenix is ​​very similar to Rails and at the same time does not look like him at all. Like some English phrases: individually, the words are familiar, but together it is not clear.


Erlang vs Ruby


Thinking on ruby ​​and trying to write on elixir is hard. You regularly come to a dead end, because what you want is done not at all like you used to do ... or, in fact, you don’t want it at all.


And the rest, about the differences between Erlang and Ruby, people write books, so I will be brief. For me, the main ambushes were replacing rail "locomotives" with a pipe, reorienting thinking to functionalism (since Haskell had an old experience and a common love of inject / foldr ) and, subjectively, more stringent requirements for data types (although, officially , both languages ​​with strict dynamic typing).


The pattern-matching did not cause any surprise, and I still did not understand why there was so much talk about him. Just an interesting tool.


Common scop


In Elixir, everything lies in the modules. No global scoop. Bounces C #.


In other words: a flat rail doesn’t make it possible to create a hierarchy in some places (I remember there were once bugs with controllers lying in modules). Elixir - on the contrary, all by modules. In the rail, the object's purpose is guessed by the parent class, and in the elixir - by the full name of the class / module.


Compilability


On the one hand, this is what I sometimes lacked in the rail. Since you can find a good half of the errors right at compilation, and not in runtime on production. On the other hand, compilation takes time. But on the third hand, it needs a bit, and I have not yet seen large projects on the elixir (and not according to Erlang’s covenants to write large monoliths). Finally, the guys from the elixir did a great job on dynamically reloading the code and page. And so far, the speed of work, coupled with the lack of godless zeus / spring, warms my soul.


Of course, this also creates disadvantages, but they come out much later. Somewhere around the production environment and deployment. This will be below.


Immediately, there is an interesting moment that cannot physically happen in the rail: migrations and other things that in rails through rake , in elixir require compilation of the project and something like this could happen: forgot to write the routes, the path-helper in them is referenced, and migrations have fallen off. At first - wildly unusual.


Documentation


The site with the elixir documentation looks much more cheerful than rubidok and apidok. But here the volume of documentation and examples is that in what ruby ​​/ rails far ahead. In Elixir there are a lot of examples for everything that is a little more complicated than a stool. And the description of some methods, in fact, did not go beyond the signature. I, as accustomed by rubies to an abundance of examples and descriptions, was difficult with some methods of the elixir. Sometimes I had to poke and experiment for a long time in order to understand how to use one or another method, because I don’t know the language so well as to read the source code of the packages freely.


Independence of file location from its content


As they say "with great power comes great responsibility". On the one hand, you can mess up the orgy and decompose objects so that the enemy will not pass. On the other hand, you can call paths more logically and visually, adding logical levels of directories that are not in the class hierarchy. In particular, we can recall the trailblazer and his ilk with the idea of ​​combining everything connected with action in one place. In the elixir, this can be done without third-party libraries and heaps of classes simply by correctly shifting existing files.


Transparent query path


If in Rails the question about rack is an indispensable attribute of any interview, because the rail is the tip of the iceberg and periodically you want to make your middleware. Then in the elixir of such a desire does not arise at all (although maybe I'm still young and everything ahead). There is an explicit set of pipeline through which the request passes. And there you can clearly see where the session is fetching, where the flash-messge is processed, where the csrf is validated and all this can be managed as it pleases in one place. In the rail all this farm is partially nailed and partially scattered in different places.


Routes inside out


In Rails, the situation when one action can respond in several formats is the norm. There even (.:format) laid right into the routes. In the elixir, due to the above mentioned property with the pipeline, the thought of the analog format does not appear at all. Different formats go on different pipeline and have different urls. For me it is so great.


Scheme in the model


This is generally a fairy tale. How to describe the fields of the model, so be it. No implicit caste of types. Plus, there are no crutches to deny access to the field that is in the database, but for some reason it cannot be used in the web application.


Validations and Callbacks


There are no callbacks in the elixir. There is more and more rectilinear. And it seems I like it.


Instead of the rails-way in the changeset elixir, which combines strong_parameters, validations and some callbacks. And the remnants of callbacks go through Multi , which makes it possible to collect a bunch of operations, execute them transactionally and process the result.


In short, everything is just different. At first it is unusual. Then in places he is wildly annoyed, because you cannot just insert another callback for everything and not think about different business cases. And then you begin to notice the "inexplicable charm" , because you have to do it right, and not as accustomed.


Work with DB


Instead of ActiveRecord, some Ecto.Repo , Ecto.Query and a few of their fellows appeared. To tell all the differences - this is a separate article. Therefore, I will say the main subjective feelings.


In debug it is more convenient than AR. Since there is a common scoop, the constants from the load path are loaded when they are accessed and you can simply open rails c , write User.where(email: 'Kane@nod.tb').order(:id).first and get the result.


In Elixir, the console is not enough. You need to do a number of actions:



On the other hand, in the application code, these "formalities" give more readable code, plus there is a feeling that you control what is happening, and not it lives its own life. That is, you yourself choose which methods, models and other objects you need to work with, obviously you load and use them.


Application Name


In the image of Rails, I thought that the name of the application is used in a couple of configs and that's it. Therefore, the length of the title did not pay attention. And in vain. In Elixir, the module with the name of the application is the top level in the module hierarchy of the web application and it will appear everywhere.


I've called my sandbox Comindivion. And now I suffer a little, since this is a rather long title and you need to write it constantly. Both in class files and in the console when you call anything. By the way, yes, who cares, here's a sandbox on GitHub .


N + 1


In Rails, we have it out of the box, and in Elixir there is no such problem out of the box. There, at the request build stage, you can specify which relays will be needed and they will be loaded during the execution of this request itself. Did not upload? You will not have access to this report. Everything is simple and beautiful.


Request processing and response


In short: everything is more obvious in the phoenix than in the rail.


Everywhere conn


Since the state is not stored in a heap of different objects, it has to be dragged along in one object. Reminds request from ActionController , only more comprehensive. He is called in Phoenix connection . It contains everything: request , flash , session and everything, everything. He also appears in the call for everything related to the processing of the incoming request.


Here and minuses, as the first is very lazy to sculpt conn everywhere and not fully understand why. Rail in this regard corrupts. You write a render or flash and there is no thought that this is an action with a connection. And in Phoenix conn constantly reminds of working with a specific connection or socket, and not just methods are invoked and magic happens there inside.


Partial & template


In Phoenix, there is no separation between partial and template. Ultimately, all function. Immediately, there is another delight: the rail, even in the prod environment, constantly climbs behind the views on the disk and generates IO plus an overhead to convert them from erb / haml / etc to html. And in Elixir everything is a function, including views. We compiled the view once and that’s it: it takes arguments, spits out html, it doesn't go to disk.


Views


In Rails, view means the partial and templates, while in Phoenix they are in templates, and in views, roughly speaking, there are different ways of presenting data. In particular, there are "overrides" of the render'a.


That is, by default, the controller renders nothing. Everything is called explicitly. And if you don’t have a partial and you don’t need it (for example, in the case of json, when it is easily built by the utility class), you redefine the render like this:


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

And the partial is no longer needed.


Heplers


They are not in Phoenix. And this is awesome! For in rail helpers, usually, any rubbish is collected that was either lazy to shove in the corners, or just needed to quickly stuff something.


However, the methods in the controller, views, and so on. You can add. This is done in a special place web/web.ex and looks pretty decent.


Statics


In development, everything is as usual, except that in the phoenix they have also attached a live reload, the first one to cause "Wow!" Effect. This is when I changed css, I returned to the browser, and there the changes were already loaded.


In production in Phoenix, the behavior of statics is slightly different than that of the rails. By default, there are clearly defined places where you can drag statics and you cannot just add files to assets to distribute them. There is also a mapping of default assets, so that once again you don’t wander over the file system, but immediately take the necessary file and give it away.


Assets


Out of the box in Phoenix - brunch . You can replace the webpack . But there is quite a true joke about the fact that many projects are bent at the stage of setting up a webpack.


In short, js and css are more or less collected, but with the rest of the statics in the brunch is not very. It is either copy-paste it directly into the project from node_modules (I don’t like this option at all), or write hooks on the bash. For example, so .


Work with SSL


Out of the box in Phoenix there is a small http server called cowboy . It looks like ruby puma . They even have the same number of stars on GitHub. But somehow I didn’t go to the SSL setting in any of the above. Especially with Let's Encrypt , an additional file of the web server config and regular certificate renewal. So, as an http server, it's ok, and for ssl, I take a proxy on localhost via apache / nginx.


Depla


It is generally different compared to the rail. In Rails, in its minimal form, he bent his turnip to the server, danced with a tambourine for a bundle, configs, assets, and launched the application. And the elixir is compiled and bury the tram bow turnip is not a ride. Need to build a package. And here begins:



And then, as with the above described, you will understand, the advantages begin:



Debag


Elixir has Pry and works like rubies. There is even an analogue rails c that looks like an iex -S mix .


But in the production console, you have to use it differently, since the package is assembled and there is no mix in it. You have to connect to a running process. This is radically different from the rails and at the beginning you spend a lot of time googling the way to start the elixir-console in production, because you are looking for something similar to the rail. As a result, you understand what you need to do everything differently and call something like: iex --name trace@127.0.0.1 --cookie 'from_env' --remsh 'my_app_name@127.0.0.1' .


To be continued...


Fuh, anyway, I forgot something. Anyway. Better tell me what surprised you in Elixir, compared to other languages.


')

Source: https://habr.com/ru/post/423459/


All Articles