Ce qui a le plus frappé le hackman passionné alors qu'il commençait à peine à étudier Elixir avec Phoenix.
Remarque
Je suis une personne simple et je ne vais pas approfondir. Par conséquent, il y aura des différences au niveau des paysans-travailleurs, mais rien ne sera dit sur la différence dans le niveau de lancement de l'application, sur les principes de fonctionnement de la machine virtuelle Erlang et le protocole OTP.
Impression principale
Elixir / Phoenix est très similaire à Rails et en même temps pas du tout comme lui. Comme certaines phrases anglaises: individuellement, les mots sont familiers, mais ensemble ce n'est pas clair.
Erlang vs Ruby
Penser en roubles et essayer d'écrire sur un élixir est difficile. Vous vous retrouvez régulièrement dans des impasses, parce que ce que vous voulez est complètement différent de ce que vous faisiez ... ou, en fait, vous ne le voulez pas du tout.
Pour le reste, les gens écrivent des livres sur les différences entre Erlang et Ruby, donc je serai bref. Pour moi, les principales embuscades ont été le remplacement des «locomotives à vapeur» ferroviaires par des tuyaux, avec une réorientation de la pensée vers le fonctionnalisme (l'avantage était inject
vieille expérience de inject
et un amour partagé pour l' inject
/ foldr
) et, subjectivement, des exigences de type de données plus strictes (bien que, officiellement, , deux langues avec typage dynamique strict).
L'appariement de motifs n'a pas causé de surprise, et je ne comprenais toujours pas pourquoi on parlait tellement de lui. Juste un outil intéressant.
Champ d'application général
Dans Elixir, tout réside dans les modules. Pas de portée mondiale. Appelle C #.
En d'autres termes: le rail est plat et à certains endroits gêne la création d'une hiérarchie (je me souviens une fois qu'il y avait des bugs avec des contrôleurs se trouvant dans des modules). Elixir - au contraire, tout est dans des modules. Dans le rail, vous pouvez deviner le but de l'objet par la classe parente, et dans l'élixir, par le nom complet de la classe / module.
Compilabilité
D'une part, c'est ce qui me manquait parfois dans le rail. Puisque vous pouvez trouver une bonne moitié d'erreurs dès la compilation, et non lors de l'exécution en production. La compilation, en revanche, prend du temps. Mais d'un autre côté, c'est un peu nécessaire, et je n'ai pas encore vu de grands projets sur l'élixir (et ce n'est pas selon les préceptes d'erlang d'écrire de gros monolithes). Pour couronner le tout, les gars de l'élixir ont fait un excellent travail de rechargement dynamique du code et de la page. Et jusqu'à présent, la vitesse de travail, couplée au manque de zeus / printemps impies, réchauffe mon âme.
Bien sûr, cela donne également lieu à des inconvénients, mais ils sortent beaucoup plus tard. Quelque part dans le domaine de l'environnement de production et du déploiement. Plus d'informations à ce sujet ci-dessous.
Voici un point intéressant qui ne peut physiquement pas se produire sur le rail: les migrations et autres choses qui, dans les rails via le rake
dans l'élixir, nécessitent la compilation du projet et quelque chose comme cela peuvent se produire: oublié d'écrire des itinéraires, l'assistant de chemin dans la vue s'y réfère, mais les migrations sont tombées. Au début - follement inhabituel.
La documentation
Le site avec la documentation de l'élixir semble beaucoup plus vigoureux que rubidock et apidok. Mais voici la quantité de documentation et d'exemples - c'est là que ruby / rails est loin devant. Elixir manque d'exemples pour tout un peu plus compliqué que les selles. Et la description de certaines méthodes, en fait, ne dépassait pas la signature. Cela a été difficile pour moi, car j'étais habitué à me frotter à une abondance d'exemples et de descriptions, avec certaines méthodes d'élixir. Parfois, je devais fouiner et expérimenter pendant longtemps pour comprendre comment utiliser telle ou telle méthode, parce que je ne connais pas si bien la langue que je peux lire librement les codes sources des paquets.
Indépendance de l'emplacement du fichier par rapport à son contenu
Comme on dit "avec une grande puissance vient une grande responsabilité". D'une part, vous pouvez faire une bacchanale et décomposer des objets pour que l'ennemi ne passe définitivement pas. Et d'autre part, vous pouvez nommer les chemins plus logiquement et plus clairement, en ajoutant des niveaux logiques de répertoires qui ne sont pas dans la hiérarchie des classes. En particulier, nous pouvons rappeler le précurseur et similaires avec l'idée de combiner tout ce qui concerne l'action en un seul endroit. Dans l'élixir, cela peut être fait sans bibliothèques tierces et tas de classes simplement en déplaçant correctement les fichiers existants.
Chemin de demande transparent
Si dans Rails la question du rack est un attribut indispensable de toute interview, car le rail est la pointe de l'iceberg et de temps en temps vous voulez faire votre middleware. Que dans l'élixir d'un tel désir ne se pose pas du tout (même si peut-être je suis encore jeune et tout est en avance). Il existe un ensemble explicite de pipeline par lequel passe la demande. Et là, vous pouvez voir clairement où la session est récupérée, où le flash-messge est traité, où csrf est validé et tout cela peut être contrôlé comme vous le souhaitez en un seul endroit. Dans le rail, toute cette ferme est partiellement clouée et partiellement dispersée à différents endroits.
Itinéraires à l'envers
Dans Rails, une situation où une action peut répondre dans plusieurs formats est la norme. Là même (.:format)
placé à droite dans les itinéraires. Dans l'élixir, en raison de la propriété susmentionnée avec le pipeline, la pensée d'un format analogique n'apparaît pas du tout. Différents formats vont sur un pipeline différent et ont des URL différentes. Pour moi, c'est tellement sain.
Circuit dans le modèle
C'est généralement un conte de fées. Comme vous décrivez les champs du modèle, il en sera ainsi. Aucune conversion implicite de types. De plus, il n'y a pas de béquilles pour restreindre l'accès au champ, qui se trouve dans la base de données, mais pour une raison quelconque, il ne peut pas être utilisé dans une application Web.
Validations et rappels
Il n'y a aucun rappel dans l'élixir. Là, tout est plus simple. Et je pense que j'aime ça.
Au lieu de la voie ferrée dans le jeu de modifications d' élixir, qui combine des paramètres forts, des validations et quelques rappels. Et le reste des rappels passe par Multi , ce qui permet de collecter un tas d'opérations, de les exécuter de manière transactionnelle et de traiter le résultat.
Bref, tout est juste différent. Au début, c'est inhabituel. Ensuite, par endroits, cela me rend furieux, car vous ne pouvez pas simplement coller un autre rappel pour tout et ne pas penser à différentes analyses de rentabilisation. Et puis vous commencez à remarquer le «charme inexplicable» , parce que vous devez le faire correctement, et non plus comme avant.
Travailler avec une base de données
Au lieu d'ActiveRecord, certains Ecto.Repo , Ecto.Query et plusieurs autres de leurs frères sont apparus. Dire toutes les différences est un article séparé. Par conséquent, je dirai les principales sensations subjectives.
En débogage plus pratique que AR. Comme il existe une portée générale, les constantes du chemin de chargement sont chargées lors de leur accès et vous pouvez simplement ouvrir les rails c
, écrire User.where(email: 'Kane@nod.tb').order(:id).first
et obtenir le résultat.
Dans Elixir, la console ne suffit pas. Un certain nombre d'actions doivent être effectuées:
- importer une méthode pour construire une requête SQL:
import Ecto.Query, only: [from: 2]
; - ajoutez des classes pour ne pas épeler leur nom complet:
alias MyLongApplicationName.User
- pour écrire User
au lieu de MyLongApplicationName.User
;alias MyLongApplicationName.Repo
- de même pour accéder à une classe qui peut exécuter sql et retourner des résultats;
- et seulement maintenant vous pouvez écrire à
from(u in User, where: u.email == "Kane@nod.tb") |> Repo.one
D'un autre côté, dans le code d'application, ces «formalités» donnent un code plus lisible, en plus il y a le sentiment que vous contrôlez ce qui se passe, et non qu'il vit sa propre vie. Autrement dit, vous choisissez les méthodes, modèles et autres objets dont vous avez besoin pour travailler, vous les chargez explicitement et les utilisez.
Nom de l'application
À l'image et à la ressemblance de Rails, j'ai supposé que le nom de l'application était utilisé dans une paire de configurations et c'est tout. Par conséquent, je n'ai pas fait attention à la longueur du nom. Mais en vain. Dans Elixir, le module avec le nom de l'application est le niveau supérieur dans la hiérarchie des modules de l'application web et il apparaîtra partout.
J'ai appelé mon bac à sable Comindivion. Et maintenant je souffre un peu, car c'est un nom assez long et vous devez l'écrire constamment. À la fois dans les fichiers de classe et dans la console lorsque vous appelez quelque chose. Au fait, oui, peu importe, voici le bac à sable sur GitHub .
N + 1
Dans Rails, nous l'avons hors de la boîte, mais dans Elixir hors de la boîte, il n'y a pas un tel problème. Là, au stade de l'assemblage de la demande, vous pouvez spécifier quelles relations sont nécessaires et elles seront chargées lors de l'exécution de cette même demande. Pas téléchargé? Vous n'aurez pas accès à ce relationnel. Tout est simple et beau.
Traitement et réponse des demandes
En bref: au phénix, tout est plus évident que dans le rail.
Partout conn
Étant donné que l'état n'est pas stocké dans un tas d'objets différents, il doit être glissé dans un seul objet. Rappelle la request
d' ActionController
, mais plus complète. Il est appelé à Phoenix. Il contient tout: request
, flash
, session
et tout. Il apparaît dans un appel de tout ce qui est lié au traitement de la demande arrivée.
Ici et par contre, puisque le premier est très paresseux pour sculpter partout conn
et qu'on ne comprend pas bien pourquoi. Le rail corrompt à cet égard. Vous écrivez rendu ou flash et il n'y a aucune pensée que cette action avec connexion. Et dans Phoenix conn
vous rappelle constamment de travailler avec une connexion ou une prise spécifique, et pas seulement les méthodes sont appelées et la magie se produit à l'intérieur.
Partiel et modèle
À Phoenix, il n'y a pas de séparation entre partiel et modèle. En fin de compte, toute la fonction. Il y a un autre charme ici: le rail, même dans l'environnement de production, rampe constamment derrière les vues sur le disque et génère des E / S plus une surcharge pour les convertir d'erb / haml / etc en html. Et dans Elixir, tout est fonction, y compris les vues. Compilé la vue une fois pour toutes: récupère les arguments, crache du code HTML, ne va pas sur le disque.
Vues
Dans Rails, la vue est comprise comme partielle et les modèles, tandis que dans Phoenix, ils se trouvent dans les modèles, et dans les vues, en gros, il existe différentes façons de présenter les données. En particulier, il existe des remplacements de rendu.
Autrement dit, par défaut, le contrôleur ne rend rien. Tout est appelé explicitement. Et si vous n'en avez pas de partiel et que vous n'en avez pas vraiment besoin (par exemple, dans le cas de json, quand il est facilement construit par une classe de service), vous redéfinissez le rendu en quelque sorte comme ceci:
def render("show.json", %{groups: groups}) do %{ groups: groups } end
Et le partiel n'est plus nécessaire.
Heplers
Il n'y en a pas à Phoenix. Et c'est génial! Car dans les aides ferroviaires, généralement, tous les déchets sont collectés, ce qui était soit paresseux pour pousser dans les coins, soit juste nécessaire pour remplir rapidement quelque chose.
Cependant, les méthodes du contrôleur, les vues, etc. Vous pouvez ajouter. Cela se fait dans un endroit spécial web/web.ex
et semble assez décent.
Statique
En développement, tout est comme d'habitude, sauf qu'à Phoenix, ils ont toujours foiré le rechargement en direct, le premier appelé "Wow!" effet. C'est à ce moment-là que j'ai changé css, retourné au navigateur, et là les changements eux-mêmes étaient déjà chargés.
En production à Phoenix, le comportement de la statique est légèrement différent de celui des rails. Par défaut, les endroits où vous pouvez faire glisser des statiques sont explicitement enregistrés et vous ne pouvez pas simplement ajouter des fichiers aux actifs pour les distribuer. Il existe toujours un mappage des actifs par défaut, de sorte que vous ne vous promeniez pas à nouveau dans le FS, mais que vous preniez immédiatement le fichier souhaité et le donniez.
Atouts
Hors de la boîte à Phoenix - brunch . Vous pouvez le remplacer par webpack . Mais il y a une blague assez véridique sur le fait que de nombreux projets sont pliés à l'étape de configuration du webpack.
Bref, js et css sont plus ou moins collectés, mais avec le reste de l'électricité statique dans le brunch ce n'est pas très. Soit le copier avec vos mains directement dans le projet à partir de node_modules (je n'aime pas du tout cette option), soit écrire des crochets sur le bash. Par exemple, comme ça .
Travailler avec SSL
Out of the box à Phoenix est un petit serveur http appelé cowboy . Il ressemble à un couguar rubis. Ils ont même le même nombre d'étoiles sur GitHub. Mais d'une manière ou d'une autre, je n'ai obtenu aucun paramètre SSL dans aucun des éléments ci-dessus. Surtout avec Let's Encrypt , un fichier de configuration de serveur Web supplémentaire et un renouvellement régulier des certificats. Donc, en tant que serveur http - ok, mais pour ssl, je prends un proxy pour localhost via apache / nginx.
Déployer
Il est généralement différent du rail. Dans Rails, dans la version minimale, il a conduit le navet au serveur, a dansé avec un tambourin pour les bundles, les configurations, les actifs et a lancé l'application. Et l'élixir se compile et creuser dans le tram persuader un navet ne roulera pas. Besoin de récupérer le colis. Et ici commence:
- vous découvrirez pourquoi les applications sont nécessaires dans
mix.exs
, car sans les indiquer correctement dans mix.exs
, de merveilleuses erreurs; - vous apprenez que les variables d'environnement se compilent au moment de la construction du package, et non au moment de son lancement, et c'est pour la première fois une surprise folle; puis vous en apprendrez plus sur relx avec
RELX_REPLACE_OS_VARS=true
et le laisser aller un peu; - vous êtes surpris que dans le package compilé pour la production, il n'y a rien de similaire au râteau, en particulier il n'y a pas de migrations et vous devez les exécuter d'une manière ou d'une autre, par exemple, de l'environnement de développement via la redirection de port vers la base de données (ou via eDeliver , qui fera la même chose) .
Et puis, alors que vous traitez avec ce qui précède, les pros commencent:
- vous pouvez rendre le package autosuffisant et ne rien mettre des dépendances sur le véhicule de combat; décompressez simplement l'archive tar et exécutez le contenu; sauf si erlang peut être nécessaire pour être déployé, car sa version de compilation croisée est un peu non triviale dans l'assemblage;
- Vous pouvez faire une version de mise à niveau pour déployer sans temps d'arrêt.
Debag
Elixir a Pry et fonctionne exactement comme les rubis. Il existe même un homologue de rails c
qui ressemble à un iex -S mix
.
Mais en production, vous devez utiliser la console différemment, car le package est construit et le mix
n'y est pas. Vous devez vous connecter à un processus de travail. C'est radicalement différent des rails et au début, vous passez beaucoup de temps sur Google pour lancer la console d'élixir en production, car vous recherchez quelque chose de similaire au rail. Par conséquent, vous comprenez que vous devez tout faire différemment et appeler quelque chose comme: iex --name trace@127.0.0.1 --cookie 'from_env' --remsh 'my_app_name@127.0.0.1'
.
À suivre ...
Fuh, j'ai oublié quelque chose. Oh bien. Vous feriez mieux de nous dire ce qui vous a surpris chez Elixir, par rapport à d'autres langues.