Unterschiede zwischen Phoenix und Rails durch die Augen eines Konvertiten

Was den begeisterten Hackman am meisten beeindruckte, als er gerade anfing, Elixier bei Phoenix zu studieren.

Hinweis


Ich bin eine einfache Person und werde nicht tief gehen. Daher wird es Unterschiede in der Ebene der arbeitenden Bauern geben, aber es wird nichts über den Unterschied in der Ebene des Anwendungsstarts, über die Funktionsprinzipien der virtuellen Erlang-Maschine und das OTP-Protokoll gesagt.


Haupteindruck


Elixir / Phoenix ist Rails sehr ähnlich und gleichzeitig überhaupt nicht wie er. Wie einige englische Sätze: Individuell sind die Wörter vertraut, aber zusammen ist es nicht klar.


Erlang gegen Ruby


In Rubel zu denken und zu versuchen, auf ein Elixier zu schreiben, ist schwer. Regelmäßig geraten Sie in Sackgassen, weil das, was Sie wollen, völlig anders gemacht wird als früher ... oder Sie wollen es überhaupt nicht.


Im Übrigen schreiben die Leute Bücher über Erlang- und Ruby-Unterschiede, daher werde ich mich kurz fassen. Für mich waren die Hauptüberfälle der Ersatz von Schienen- „Dampflokomotiven“ durch Rohre, eine Neuorientierung des Denkens auf Funktionalismus (der Vorteil war inject alte Erfahrung und eine gemeinsame Liebe zu foldr / foldr ) und subjektiv strengere Anforderungen an Datentypen (obwohl offiziell) , beide Sprachen mit strikter dynamischer Typisierung).


Der Mustervergleich überraschte nicht und ich verstand immer noch nicht, warum so viel über ihn geredet wurde. Nur ein interessantes Werkzeug.


Allgemeiner Geltungsbereich


In Elixir liegt alles in den Modulen. Kein globaler Geltungsbereich. Ruft C # auf.


Mit anderen Worten: Die Schiene ist flach und beeinträchtigt an einigen Stellen die Erstellung einer Hierarchie (ich erinnere mich, dass es einmal Fehler mit Controllern gab, die in Modulen lagen). Elixier - im Gegenteil, alles ist in Modulen. In der Schiene können Sie den Zweck des Objekts anhand der übergeordneten Klasse und im Elixier anhand des vollständigen Namens der Klasse / des Moduls erraten.


Kompilierbarkeit


Einerseits fehlte mir dies manchmal in der Schiene. Da Sie eine gute Hälfte der Fehler direkt beim Kompilieren finden können und nicht zur Laufzeit in der Produktion. Die Kompilierung hingegen braucht Zeit. Aber andererseits wird es ein wenig gebraucht, und ich habe noch keine großen Projekte auf dem Elixier gesehen (und es ist nicht nach den Vorschriften von erlang, große Monolithen zu schreiben). Um das Ganze abzurunden, haben die Elixier-Jungs den Code und die Seite dynamisch neu geladen. Und bis jetzt wärmt die Geschwindigkeit der Arbeit, gepaart mit dem Mangel an gottlosem Zeus / Frühling, meine Seele.


Dies führt natürlich auch zu Nachteilen, aber sie kommen viel später heraus. Irgendwo im Bereich Produktionsumgebung und Bereitstellung. Mehr dazu weiter unten.


Hier ist ein interessanter Punkt, der auf der Schiene physisch nicht passieren kann: Migrationen und andere Dinge, die in Schienen über rake in Elixier eine Kompilierung des Projekts erfordern, und so etwas kann passieren: Vergessen, Routen zu schreiben, der Pfadhelfer in der Ansicht verweist auf sie, aber die Migrationen fielen ab. Zuerst - wild ungewöhnlich.


Die Dokumentation


Die Seite mit der Dokumentation des Elixiers sieht viel kräftiger aus als Rubidock und Apidok. Aber hier ist die Menge an Dokumentation und Beispielen - hier liegt Ruby / Rails weit vorne. Elixir fehlen Beispiele für alles, was etwas komplizierter ist als Hocker. Und die Beschreibung einiger Methoden ging tatsächlich nicht über die Signatur hinaus. Es war schwierig für mich, da ich es gewohnt war, mit einigen Elixiermethoden an einer Fülle von Beispielen und Beschreibungen zu reiben. Manchmal musste ich lange herumstöbern und experimentieren, um zu verstehen, wie man diese oder jene Methode verwendet, weil ich die Sprache nicht so gut kenne, dass ich die Quellcodes der Pakete frei lesen kann.


Unabhängigkeit des Speicherorts von seinem Inhalt


Wie sie sagen "mit großer Kraft geht große Verantwortung einher". Einerseits können Sie eine Bacchanalia herstellen und Objekte so zerlegen, dass der Feind definitiv nicht vorbeikommt. Auf der anderen Seite können Sie die Pfade logischer und klarer benennen und logische Ebenen von Verzeichnissen hinzufügen, die nicht in der Klassenhierarchie enthalten sind. Insbesondere können wir uns an Wegbereiter und dergleichen mit der Idee erinnern, alles, was mit der Aktion zu tun hat, an einem Ort zu kombinieren. Im Elixier kann dies ohne Bibliotheken und Klassenhaufen von Drittanbietern erfolgen, indem die vorhandenen Dateien einfach korrekt verschoben werden.


Transparenter Anforderungspfad


Wenn in Rails die Frage nach dem Rack ein unverzichtbares Attribut eines jeden Interviews ist, da die Schiene die Spitze des Eisbergs ist und Sie von Zeit zu Zeit Ihre Middleware herstellen möchten. Das im Elixier eines solchen Verlangens entsteht überhaupt nicht (obwohl ich vielleicht noch jung bin und alles vor mir liegt). Es gibt einen expliziten Satz von Pipelines, durch die die Anforderung geleitet wird. Und dort können Sie deutlich sehen, wo die Sitzung abgerufen wird, wo Flash-Message verarbeitet wird, wo csrf validiert wird und all dies an einem Ort nach Belieben gesteuert werden kann. In der Schiene ist diese ganze Farm teilweise genagelt und teilweise an verschiedenen Stellen verstreut.


Routen von innen nach außen


In Rails ist eine Situation, in der eine Aktion in mehreren Formaten reagieren kann, die Norm. Dort wird sogar (.:format) direkt in die Routen gelegt. Im Elixier erscheint der Gedanke an ein Formatanalog aufgrund der oben erwähnten Eigenschaft mit der Pipeline überhaupt nicht. Unterschiedliche Formate gehen in unterschiedliche Pipelines und haben unterschiedliche URLs. Für mich ist es so gesund.


Schaltung im Modell


Dies ist im Allgemeinen ein Märchen. Wenn Sie die Felder des Modells beschreiben, wird es so sein. Keine implizite Besetzung von Typen. Außerdem gibt es keine Krücken, um den Zugriff auf das Feld in der Datenbank einzuschränken. Aus irgendeinem Grund kann es jedoch nicht in einer Webanwendung verwendet werden.


Validierungen und Rückrufe


Das Elixier enthält keine Rückrufe. Dort ist alles einfacher. Und ich denke ich mag es.


Anstelle des Rails-Way im Elixier- Änderungssatz , der strong_parameters, Validierungen und einige Rückrufe kombiniert. Der Rest der Rückrufe erfolgt über Multi , wodurch eine Reihe von Vorgängen erfasst, transaktional ausgeführt und das Ergebnis verarbeitet werden kann.


Kurz gesagt, alles ist einfach anders. Das ist zunächst ungewöhnlich. Dann macht es mich an manchen Stellen wütend, weil Sie nicht einfach für alles einen weiteren Rückruf anbringen können und nicht an verschiedene Geschäftsfälle denken. Und dann merkt man den „unerklärlichen Charme“ , weil man es richtig machen muss und nicht mehr so ​​wie früher.


Arbeiten Sie mit einer DB


Anstelle von ActiveRecord erschienen einige Ecto.Repo , Ecto.Query und einige weitere ihrer Brüder. Alle Unterschiede zu erklären, ist ein separater Artikel. Daher werde ich die wichtigsten subjektiven Empfindungen sagen.


Im Debug bequemer als AR. Da es einen allgemeinen Bereich gibt, werden die Konstanten aus dem User.where(email: 'Kane@nod.tb').order(:id).first beim Zugriff geladen und Sie können einfach die rails c öffnen, User.where(email: 'Kane@nod.tb').order(:id).first schreiben User.where(email: 'Kane@nod.tb').order(:id).first und das Ergebnis erhalten.


In Elixir reicht die Konsole nicht aus. Eine Reihe von Maßnahmen muss durchgeführt werden:


  • Importieren einer Methode zum Erstellen einer SQL-Abfrage: import Ecto.Query, only: [from: 2] ;
  • Fügen Sie Klassen hinzu, um zu vermeiden, dass die vollständigen Namen angegeben werden:
    • alias MyLongApplicationName.User - um User anstelle von MyLongApplicationName.User zu schreiben;
    • alias MyLongApplicationName.Repo - ähnlich für den Zugriff auf eine Klasse, die SQL ausführen und Ergebnisse zurückgeben kann;
  • und erst jetzt können Sie schreiben from(u in User, where: u.email == "Kane@nod.tb") |> Repo.one

Auf der anderen Seite ergeben diese „Formalitäten“ im Anwendungscode einen besser lesbaren Code, und es besteht das Gefühl, dass Sie die Kontrolle über das Geschehen haben und nicht, dass es sein eigenes Leben führt. Das heißt, Sie wählen aus, welche Methoden, Modelle und anderen Objekte Sie bearbeiten möchten, laden sie explizit und verwenden sie.


Anwendungsname


Im Bild und in der Abbildung von Rails habe ich angenommen, dass der Anwendungsname in zwei Konfigurationen verwendet wird, und das war's. Daher habe ich nicht auf die Länge des Namens geachtet. Aber vergebens. In Elixir ist das Modul mit dem Namen der Anwendung die oberste Ebene in der Hierarchie der Module der Webanwendung und wird überall angezeigt.


Ich rief meine Sandbox Comindivion an. Und jetzt leide ich ein wenig, da dies ein ziemlich langer Name ist und Sie ihn ständig schreiben müssen. Sowohl in Klassendateien als auch in der Konsole, wenn etwas aufgerufen wird. Übrigens, ja, wen interessiert das, hier ist die Sandbox auf GitHub .


N + 1


In Rails haben wir es sofort einsatzbereit, aber in Elixir out of the box gibt es kein solches Problem. Dort können Sie in der Anforderungsassemblierungsphase angeben, welche Beziehungen benötigt werden, und diese werden während der Ausführung dieser Anforderung geladen. Nicht hochgeladen? Sie haben keinen Zugriff auf diese relationale. Alles ist einfach und schön.


Anfragebearbeitung und Antwort


Kurzum: Im Phönix ist alles offensichtlicher als in der Schiene.


Überall conn


Da der Status nicht in einem Haufen verschiedener Objekte gespeichert ist, muss er in einem Objekt mitgeschleppt werden. Erinnert die request von ActionController nur umfassender. Er wird in Phoenix connection . Es enthält alles: request , flash , session und alles. Er erscheint in einem Anruf von allem, was mit der Bearbeitung der eingetroffenen Anfrage verbunden ist.


Hier und Nachteile, da der erste sehr faul ist, überall zu formen und nicht ganz zu verstehen, warum. Schiene in dieser Hinsicht korrumpiert. Sie schreiben Rendering oder Flash und es gibt keine Gedanken, dass diese Aktion mit Verbindung verbunden ist. Und in Phoenix conn erinnert es Sie ständig daran, mit einer bestimmten Verbindung oder einem bestimmten Socket zu arbeiten, und nicht nur die Methoden werden aufgerufen, und die Magie geschieht im Inneren.


Teilweise & Vorlage


In Phoenix gibt es keine Trennung zwischen Teil und Vorlage. Letztendlich die ganze Funktion. Hier gibt es noch einen weiteren Reiz: Die Schiene kriecht selbst in der Produktumgebung ständig hinter die Ansichten auf der Festplatte und generiert E / A sowie einen Overhead, um sie von erb / haml / etc in html zu konvertieren. Und in Elixir ist alles eine Funktion, einschließlich Ansichten. Die Ansicht ein für allemal kompiliert: Ruft die Argumente ab, spuckt HTML aus, geht nicht auf die Festplatte.


Ansichten


In Rails wird Ansicht als Teil und Vorlage verstanden, während sie in Phoenix in Vorlagen liegt, und in Ansichten gibt es grob gesagt verschiedene Möglichkeiten, Daten darzustellen. Insbesondere gibt es Render-Overrides.


Das heißt, der Controller rendert standardmäßig nichts. Alles wird explizit aufgerufen. Und wenn Sie kein Teil haben und es nicht wirklich brauchen (zum Beispiel im Fall von json, wenn es leicht von einer Serviceklasse erstellt werden kann), definieren Sie das Rendering irgendwie neu:


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

Und der Teil wird nicht mehr benötigt.


Heplers


Es gibt keine in Phoenix. Und das ist großartig! Denn in den Bahnhelfern wird normalerweise der gesamte Müll gesammelt, der entweder faul war, in die Ecken zu schieben, oder nur benötigt wurde, um schnell etwas aufzufüllen.


Die Methoden in der Steuerung, Ansichten usw. Sie können hinzufügen. Dies geschieht an einem speziellen Ort web/web.ex und sieht ziemlich anständig aus.


Statik


In der Entwicklung ist alles wie gewohnt, außer dass sie in Phoenix immer noch das Live-Reload vermasselt haben, das erste mit dem Titel "Wow!" Wirkung. Zu diesem Zeitpunkt habe ich CSS geändert, bin zum Browser zurückgekehrt und dort wurden die Änderungen selbst bereits geladen.


In der Produktion in Phoenix unterscheidet sich das Verhalten der Statik geringfügig von dem der Schienen. Standardmäßig werden Orte, an denen Sie Statiken ziehen können, explizit registriert, und Sie können Assets nicht einfach Dateien hinzufügen, um sie zu verteilen. Trotzdem gibt es eine Zuordnung der Standard-Assets, damit Sie nicht noch einmal im FS herumwandern, sondern sofort die gewünschte Datei nehmen und weitergeben.


Vermögenswerte


Out of the Box in Phoenix - Brunch . Sie können es durch Webpack ersetzen. Aber es gibt einen ziemlich wahrheitsgemäßen Witz über die Tatsache, dass viele Projekte in der Phase der Einrichtung des Webpacks verbogen sind.


Kurz gesagt, js und css werden mehr oder weniger gesammelt, aber mit dem Rest der statischen Aufladung im Brunch ist es nicht sehr. Kopieren Sie es entweder mit Ihren Händen direkt von node_modules in das Projekt (diese Option gefällt mir überhaupt nicht) oder schreiben Sie Hooks in die Bash. Zum Beispiel so .


Arbeiten Sie mit SSL


In Phoenix ist ein kleiner http-Server namens Cowboy sofort einsatzbereit . Es sieht aus wie ein Rubinpuma . Sie haben sogar die gleiche Anzahl von Sternen auf GitHub. Aber irgendwie habe ich in keiner der oben genannten Versionen SSL-Einstellungen erhalten. Insbesondere mit Let's Encrypt , einer zusätzlichen Webserver-Konfigurationsdatei und einer regelmäßigen Zertifikatserneuerung. Also als http-Server - ok, aber für ssl nehme ich einen Proxy zu localhost über Apache / Nginx.


Bereitstellen


Es ist im Allgemeinen anders als die Schiene. In Rails, in der Mindestversion, fuhr er die Rübe zum Server, tanzte mit einem Tamburin für Bundles, Konfigurationen, Assets und startete die Anwendung. Und das Elixier kompiliert und in der Straßenbahn graben eine Rübe zu überzeugen wird nicht reiten. Müssen das Paket abholen. Und hier beginnt:


  • Sie werden herausfinden, warum Anwendungen in mix.exs benötigt mix.exs , denn ohne sie korrekt in mix.exs anzugeben, wunderbare Fehler;
  • Sie erfahren, dass Umgebungsvariablen zum Zeitpunkt der Erstellung des Pakets und nicht zum Zeitpunkt des Starts kompiliert werden. Dies ist zum ersten Mal eine wilde Überraschung. dann lernst du relx zusammen mit RELX_REPLACE_OS_VARS=true und lässt es ein wenig los;
  • Sie sind überrascht, dass das kompilierte Paket für die Produktion nichts Ähnliches wie Rake enthält, insbesondere keine Migrationen, und Sie müssen sie irgendwie separat ausführen, z. B. von der Entwicklungsumgebung durch Portweiterleitung an die Datenbank (oder über eDeliver , was ungefähr dasselbe bewirkt ). .

Und dann, wenn Sie sich mit dem oben Gesagten befassen, beginnen die Profis:


  • Sie können das Paket autark machen und nichts von den Abhängigkeiten vom Kampffahrzeug ablegen. Entpacken Sie einfach den Tarball und führen Sie den Inhalt aus. es sei denn, erlang muss möglicherweise ausgerollt werden, da die Cross-Compile-Version in der Assembly nicht trivial ist.
  • Sie können ein Upgrade-Release durchführen, um es ohne Ausfallzeiten bereitzustellen.

Debag


Elixier hat Pry und funktioniert wie Rubine. Es gibt sogar ein rails c Gegenstück, das aussieht wie iex -S mix .


In der Produktion muss die Konsole jedoch anders verwendet werden, da das Paket erstellt wurde und kein mix ist. Sie müssen eine Verbindung zu einem Arbeitsprozess herstellen. Dies unterscheidet sich grundlegend von den Schienen und am Anfang verbringst du viel Zeit damit, den Weg zu googeln, um die Elixierkonsole in der Produktion zu starten, weil du nach etwas ähnlichem wie der Schiene suchst. Als Ergebnis verstehen Sie, dass Sie alles anders machen und so etwas wie: iex --name trace@127.0.0.1 --cookie 'from_env' --remsh 'my_app_name@127.0.0.1' .


Fortsetzung folgt...


Fuh, ich habe irgendwie etwas vergessen. Na ja. Sagen Sie uns besser, was Sie bei Elixir im Vergleich zu anderen Sprachen überrascht hat.

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


All Articles