Diferencias entre Phoenix y Rails a través de los ojos de un converso

Lo que golpeó al ávido pirateo sobre todo cuando acababa de comenzar a estudiar Elixir con Phoenix.

Nota


Soy una persona sencilla y no voy a profundizar. Por lo tanto, habrá diferencias en el nivel de trabajo-campesino, pero no se dirá nada sobre la diferencia en el nivel de lanzamiento de la aplicación, sobre los principios de funcionamiento de la máquina virtual Erlang y el protocolo OTP.


Impresión principal


Elixir / Phoenix es muy similar a Rails y al mismo tiempo no se parece en nada a él. Como algunas frases en inglés: individualmente, las palabras son familiares, pero juntas no están claras.


Erlang vs Ruby


Es difícil pensar en rublos e intentar escribir en un elixir. Regularmente te encuentras en callejones sin salida, porque lo que quieres hacer no es lo que solías hacer ... o, de hecho, no quieres esto en absoluto.


En cuanto al resto, la gente escribe libros sobre las diferencias de Erlang y Ruby, así que seré breve. Para mí, las principales emboscadas fueron la sustitución de las "locomotoras de vapor" ferroviarias por tuberías, con una reorientación del pensamiento hacia el funcionalismo (el beneficio fue inject antigua experiencia de inject y un amor compartido por inject / foldr ) y, subjetivamente, requisitos de tipo de datos más estrictos (aunque oficialmente , ambos idiomas con estricto tipeo dinámico).


La coincidencia de patrones no causó ninguna sorpresa, y todavía no entendía por qué se hablaba tanto de él. Solo una herramienta interesante.


Alcance general


En Elixir, todo se encuentra en los módulos. Sin alcance global. Llamadas C #.


En otras palabras: el riel es plano y en algunos lugares interfiere con la creación de una jerarquía (recuerdo una vez que hubo errores con los controladores en los módulos). Elixir: por el contrario, todo está en módulos. En el riel, puede adivinar el propósito del objeto por la clase principal, y en el elixir, por el nombre completo de la clase / módulo.


La disponibilidad


Por un lado, esto es lo que a veces me faltaba en el riel. Ya que puede encontrar una buena mitad de errores directamente en la compilación, y no en tiempo de ejecución en la producción. La compilación, por otro lado, lleva tiempo. Pero, por otro lado, se necesita un poco, y aún no he visto grandes proyectos sobre el elixir (y no es por los preceptos de erlang escribir monolitos grandes). Para colmo, los chicos de elixir hicieron un gran trabajo al recargar dinámicamente el código y la página. Y hasta ahora, la velocidad del trabajo, junto con la falta de un dios / resorte impío, calienta mi alma.


Por supuesto, esto también da lugar a contras, pero salen mucho más tarde. En algún lugar del área del entorno de producción y despliegue. Más sobre esto a continuación.


Aquí hay un punto interesante que físicamente no puede suceder en el riel: las migraciones y otras cosas que en los rieles a través de rake en elixir requieren la compilación del proyecto y algo así puede suceder: olvidé escribir rutas, el asistente de ruta en la vista se refiere a ellas, pero las migraciones se cayeron. Al principio, tremendamente inusual.


La documentación


El sitio con la documentación del elixir parece mucho más vigoroso que rubidock y apidok. Pero aquí está la cantidad de documentación y ejemplos: aquí es donde ruby ​​/ rails está muy por delante. Elixir carece de ejemplos para todo un poco más complicado que las heces. Y la descripción de algunos métodos, de hecho, no fue más allá de la firma. Fue difícil para mí, ya que estaba acostumbrado a frotar una gran cantidad de ejemplos y descripciones, con algunos métodos de elixir. A veces tuve que hurgar y experimentar durante mucho tiempo para entender cómo usar este o aquel método, porque no conozco el idioma tan bien que puedo leer los códigos fuente de los paquetes libremente.


Independencia de la ubicación del archivo de su contenido


Como dicen "con gran poder viene una gran responsabilidad". Por un lado, puedes hacer una bacanal y descomponer objetos para que el enemigo definitivamente no pase. Y, por otro lado, puede nombrar las rutas de forma más lógica y clara, agregando niveles lógicos de directorios que no están en la jerarquía de clases. En particular, podemos recordar el pionero y similares con la idea de combinar todo lo relacionado con la acción en un solo lugar. En el elixir, esto se puede hacer sin bibliotecas de terceros y montones de clases simplemente moviendo correctamente los archivos existentes.


Ruta de solicitud transparente


Si en Rails la pregunta sobre el rack es un atributo indispensable de cualquier entrevista, porque el rail es la punta del iceberg y de vez en cuando desea hacer su middleware. Que en el elixir de tal deseo no surge en absoluto (aunque tal vez todavía soy joven y todo está por delante). Hay un conjunto explícito de canalización a través del cual pasa la solicitud. Y allí puede ver claramente dónde se obtiene la sesión, dónde se procesa el flash-messge, dónde se valida csrf y todo esto se puede controlar a su gusto en un solo lugar. En el riel, toda esta granja está parcialmente clavada y parcialmente dispersa en diferentes lugares.


Rutas de adentro hacia afuera


En Rails, una situación en la que una acción puede responder en varios formatos es la norma. Allí incluso (.:format) coloca directamente en las rutas. En el elixir, debido a la propiedad antes mencionada con la tubería, la idea de un formato analógico no aparece en absoluto. Los diferentes formatos van en diferentes canalizaciones y tienen diferentes URL. Para mí es muy saludable.


Circuito en modelo


Esto es generalmente un cuento de hadas. Al describir los campos del modelo, será así. Sin elenco implícito de tipos. Además, no hay muletas para restringir el acceso al campo, que está en la base de datos, pero por alguna razón no se puede usar en una aplicación web.


Validaciones y devoluciones de llamada


No hay devoluciones de llamada en el elixir. Allí todo es más sencillo. Y creo que me gusta.


En lugar de la vía férrea en el conjunto de cambios de elixir, que combina parámetros fuertes, validaciones y algunas devoluciones de llamada. Y el resto de las devoluciones de llamada pasan por Multi , lo que permite recopilar un montón de operaciones, realizarlas transaccionalmente y procesar el resultado.


En resumen, todo es simplemente diferente. Al principio esto es inusual. Luego, en algunos lugares, me enfurece muchísimo, porque no puedes limitar otra llamada para todo y no pensar en diferentes casos de negocios. Y luego comienzas a notar el "encanto inexplicable" , porque tienes que hacerlo bien y no como solías hacerlo.


Trabajar con un DB


En lugar de ActiveRecord, aparecieron algunos Ecto.Repo , Ecto.Query y varios más de sus hermanos. Para contar todas las diferencias es un artículo separado. Por lo tanto, diré las principales sensaciones subjetivas.


En depuración más conveniente que AR. Como hay un alcance general, las constantes de la ruta de carga se cargan al acceder a ellas y simplemente puede abrir los rails c , escribir User.where(email: 'Kane@nod.tb').order(:id).first y obtener el resultado.


En Elixir, la consola no es suficiente. Se deben realizar varias acciones:


  • importar un método para construir una consulta sql: import Ecto.Query, only: [from: 2] ;
  • agregue clases para evitar deletrear sus nombres completos:
    • alias MyLongApplicationName.User : para escribir User lugar de MyLongApplicationName.User ;
    • alias MyLongApplicationName.Repo : de forma similar para acceder a una clase que puede ejecutar sql y devolver resultados;
  • y solo ahora puede escribir from(u in User, where: u.email == "Kane@nod.tb") |> Repo.one

Por otro lado, en el código de la aplicación, estas "formalidades" dan un código más legible, además de que existe la sensación de que usted tiene el control de lo que está sucediendo y no de que está viviendo su propia vida. Es decir, usted elige qué métodos, modelos y otros objetos necesita para trabajar, los carga explícitamente y los usa.


Nombre de la aplicación


En la imagen y semejanza de Rails, supuse que el nombre de la aplicación se usa en un par de configuraciones y eso es todo. Por lo tanto, no presté atención a la longitud del nombre. Pero en vano. En Elixir, el módulo con el nombre de la aplicación es el nivel superior en la jerarquía de módulos de la aplicación web y aparecerá en todas partes.


Llamé a mi sandbox Comindivion. Y ahora sufro un poco, ya que este es un nombre bastante largo y necesitas escribirlo constantemente. Tanto en los archivos de clase como en la consola al llamar a cualquier cosa. Por cierto, sí, a quién le importa, aquí está el sandbox en GitHub .


N + 1


En Rails, lo tenemos listo para usar, pero en Elixir listo para usar no hay tal problema. Allí, en la etapa de ensamblaje de la solicitud, puede especificar qué relaciones se necesitan y se cargarán durante la ejecución de esta misma solicitud. No subido? No tendrá acceso a este relacional. Todo es simple y hermoso.


Procesamiento de solicitud y respuesta


En resumen: en el fénix, todo es más obvio que en el ferrocarril.


En todas partes conn


Como el estado no se almacena en un montón de objetos diferentes, debe arrastrarse en un objeto. Recuerda la request de ActionController , solo que más completa. Se le llama en connection Phoenix. Contiene todo: request , flash , session y todo. Aparece en una llamada de todo lo relacionado con el procesamiento de la solicitud recibida.


Aquí y contras, ya que el primero es muy vago para esculpir en todas partes y no entiendo por qué. El ferrocarril a este respecto corrompe. Escribe render o flash y no hay pensamientos de que esta acción con la conexión. Y en Phoenix conn constantemente te recuerda trabajar con una conexión o socket específico, y no solo se llaman los métodos y la magia ocurre dentro.


Parcial y plantilla


En Phoenix, no hay separación entre parcial y plantilla. En definitiva toda la función. Aquí hay un encanto más: el riel, incluso en el entorno de producción, se arrastra constantemente detrás de las vistas en el disco y genera IO más una sobrecarga para convertirlos de erb / haml / etc a html. Y en Elixir todo es una función, incluidas las vistas. Compiló la vista de una vez por todas: obtiene los argumentos, escupe html, no va al disco.


Vistas


En Rails, vista se entiende como parcial y plantillas, mientras que en Phoenix se encuentran en plantillas, y en vistas, en términos generales, hay diferentes formas de presentar los datos. En particular, hay anulaciones de renderizado.


Es decir, por defecto, el controlador no representa nada. Todo se llama explícitamente. Y si no tiene un parcial y realmente no lo necesita (por ejemplo, en el caso de json, cuando es fácilmente creado por una clase de servicio), redefine el renderizado de alguna manera así:


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

Y lo parcial ya no es necesario.


Heplers


No hay ninguno en Phoenix. ¡Y esto es asombroso! En el caso de los ayudantes ferroviarios, por lo general, se recolecta toda la basura, que era perezosa para empujar en las esquinas, o simplemente necesitaba llenar algo rápidamente.


Sin embargo, los métodos en el controlador, las vistas, etc. Puedes agregar. Esto se hace en un lugar especial web/web.ex y se ve bastante decente.


Estática


En desarrollo, todo sigue como siempre, excepto que en Phoenix todavía arruinaron la recarga en vivo, la primera llamada "¡Guau!" efecto Esto es cuando cambié css, volví al navegador y allí los cambios ya estaban cargados.


En la producción en Phoenix, el comportamiento de la estática es ligeramente diferente al de los rieles. De forma predeterminada, los lugares donde puede arrastrar estadísticas están explícitamente registrados y no puede simplemente agregar archivos a los activos para distribuirlos. Todavía hay un mapeo de los activos predeterminados, para que no pasee por el FS una vez más, sino que tome inmediatamente el archivo deseado y lo regale.


Activos


Fuera de la caja en Phoenix - brunch . Puede reemplazarlo con webpack . Pero hay una broma bastante veraz sobre el hecho de que muchos proyectos se doblan en la etapa de configuración del paquete web.


En resumen, js y css están más o menos recopilados, pero con el resto de la estática en el brunch no es muy. Cópielo con sus manos directamente al proyecto desde node_modules (no me gusta esta opción en absoluto), o escriba ganchos en el bash. Por ejemplo, así .


Trabajar con SSL


Fuera de la caja en Phoenix hay un pequeño servidor http llamado cowboy . Parece un puma rubí. Incluso tienen el mismo número de estrellas en GitHub. Pero de alguna manera no obtuve la configuración SSL en ninguno de los anteriores. Especialmente con Let's Encrypt , un archivo de configuración del servidor web adicional y la renovación regular del certificado. Entonces, como servidor http, está bien, pero para ssl tomo un proxy para localhost a través de apache / nginx.


Implementar


Generalmente es diferente en comparación con el riel. En Rails, en la versión mínima, condujo el nabo al servidor, bailó con una pandereta para paquetes, configuraciones, activos y lanzó la aplicación. Y el elixir compila y cavar en el tranvía para persuadir a un nabo no se montará. Necesito recoger el paquete. Y aquí comienza:


  • descubrirá por qué se necesitan aplicaciones en mix.exs , porque sin indicarlas correctamente en mix.exs , errores maravillosos;
  • usted aprende que las variables de entorno se compilan en el momento en que se creó el paquete, y no en el momento en que se lanzó, y esto es por primera vez una gran sorpresa; entonces aprendes sobre relx junto con RELX_REPLACE_OS_VARS=true y lo RELX_REPLACE_OS_VARS=true ir un poco;
  • Le sorprende que en el paquete compilado para producción no haya nada similar al rastrillo, en particular no hay migraciones y necesita ejecutarlas de alguna manera por separado, por ejemplo, desde el entorno de desarrollo a través del reenvío de puertos a la base de datos (o mediante eDeliver , que hará lo mismo) .

Y luego, al lidiar con lo anterior, los profesionales comienzan:


  • puedes hacer que el paquete sea autosuficiente y no poner nada de las dependencias en el vehículo de combate; simplemente descomprime el tarball y ejecuta el contenido; a menos que sea necesario implementar erlang, ya que su versión de compilación cruzada es un poco no trivial en el ensamblado;
  • Puede hacer una versión de actualización para implementar sin tiempo de inactividad.

Debag


Elixir tiene Pry y funciona igual que los rubíes. Incluso hay una contraparte de rails c que se parece a la iex -S mix .


Pero en producción, debe usar la consola de manera diferente, ya que el paquete está construido y la mix no está en él. Tienes que conectarte a un proceso de trabajo. Esto es radicalmente diferente de los rieles y al principio pasas mucho tiempo buscando en Google la forma de lanzar la consola elixir en producción, porque estás buscando algo similar al riel. Como resultado, comprende que debe hacer todo de manera diferente y llamar a algo como: iex --name trace@127.0.0.1 --cookie 'from_env' --remsh 'my_app_name@127.0.0.1' .


Continuará ...


Fuh, olvidé algo de alguna manera. Oh bien Mejor cuéntanos qué te sorprendió en Elixir, en comparación con otros idiomas.

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


All Articles