Phoenix-rammeverket har vokst med popularitet i et raskt tempo, og tilbyr produktiviteten til rammer som Ruby on Rails, samtidig som den er en av raskeste rammer tilgjengelig. Det bryter myten om at du må ofre ytelse for å øke produktiviteten.
Så hva er egentlig Phoenix?
Phoenix er et nettrammeverk bygget med programmeringsspråket Elixir. Elixir, bygd på Erlang VM, brukes til å bygge lavt ventetid, feiltolerante, distribuerte systemer, som blir stadig mer nødvendige kvaliteter til moderne webapplikasjoner. Du kan lære mer om Elixir fra dette blogginnlegget eller deres offisiell guide .
Hvis du er en Ruby on Rails utvikler , bør du absolutt interessere deg for Phoenix på grunn av prestasjonsgevinsten det lover. Utviklere av andre rammer kan også følge med for å se hvordan Phoenix nærmer seg webutvikling.
I denne artikkelen vil vi lære noen av tingene i Phoenix du bør huske på hvis du kommer fra Ruby on Rails-verdenen.
I motsetning til Ruby er Elixir et funksjonelt programmeringsspråk, som sannsynligvis er den største forskjellen du måtte ha å takle. Imidlertid er det noen viktige forskjeller mellom disse to plattformene som alle som lærer Phoenix bør være klar over for å maksimere produktiviteten.
Dette er lite, men det er lett å rote til hvis du kommer fra Ruby on Rails.
I Phoenix er konvensjonen å skrive alt i entall. Så du vil ha en 'UserController' i stedet for en 'UsersController' som du ville gjort i Ruby on Rails. Dette gjelder overalt unntatt når du navngir databasetabeller, der konvensjonen er å navngi tabellen i flertallsform.
Dette virker kanskje ikke som en stor avtale etter å ha lært når og hvor jeg skal bruke flertallsformen i Ruby on Rails, men det var litt forvirrende i begynnelsen, da jeg lærte å bruke Ruby on Rails, og jeg er sikker på at det har forvirret mange andre også. Phoenix gir deg en ting mindre å bekymre deg for.
Phoenix og Ruby on Rails er veldig like når det gjelder ruting. Hovedforskjellen er i hvordan du kan kontrollere måten en forespørsel behandles på.
I Ruby on Rails (og andre Rack-applikasjoner) gjøres dette gjennom mellomvare, mens det i Phoenix gjøres med det som kalles 'plugger'.
Plugger er det du bruker for å behandle en tilkobling.
For eksempel mellomvare Rails::Rack::Logger
logger en forespørsel i Rails, som i Phoenix ville bli gjort med Plug.Logger
støpsel. I utgangspunktet kan alt du kan gjøre i Rack mellomvare gjøres ved hjelp av plugger.
Her er et eksempel på en ruter i Phoenix:
defmodule HelloWorld.Router do use HelloWorld.Web, :router pipeline :browser do plug :accepts, ['html'] plug :fetch_session plug :fetch_flash plug :protect_from_forgery plug :put_secure_browser_headers end pipeline :api do plug :accepts, ['json'] end scope '/', HelloWorld do pipe_through :browser get '/', HelloController, :index end scope '/api', HelloWorld do pipe_through :api end end
La oss først se på rørledningene.
Dette er grupper av plugger som forespørselen vil reise gjennom. Tenk på det som en mellomvarestabel. Disse kan for eksempel brukes til å verifisere at forespørselen forventer HTML, hente økten og sørge for at forespørselen er sikker. Alt dette skjer før du når kontrolleren.
Fordi du kan spesifisere flere rørledninger, kan du velge hvilke plugger som er nødvendige for bestemte ruter. I ruteren vår har vi for eksempel en annen pipeline for sider (HTML) og API (JSON) forespørsler.
Det er ikke alltid fornuftig å bruke nøyaktig samme rørledning for forskjellige typer forespørsler. Phoenix gir oss den fleksibiliteten.
Visninger i Phoenix er ikke det samme som utsikten i Ruby on Rails.
Visninger i Phoenix har ansvaret for gjengivelse av maler og funksjoner som gjør rådata enklere for malene å bruke. En utsikt i Phoenix ligner nærmest en hjelper i Ruby on Rails, med tillegg av gjengivelse av malen.
La oss skrive et eksempel som viser 'Hello, World!' i nettleseren.
app / kontrollere / hello_controller.rb:
class HelloController app / views / hallo / index.html.erb:
') end end
Du kan slette malen og bruke den nye gjengivelsesfunksjonen, så får du det samme resultatet. Dette er nyttig når du bare vil returnere tekst eller til og med JSON.
Modeller er nettopp det: datamodeller.
I Phoenix håndterer modeller primært datavalidering, skjemaet, forholdet til andre modeller og hvordan det presenteres.
Å spesifisere skjemaet i modellen kan høres rart ut i begynnelsen, men det lar deg enkelt lage 'virtuelle' felt, som er felt som ikke er vedvarende i databasen. La oss se på et eksempel:
defmodule HelloPhoenix.User do use HelloPhoenix.Web, :model schema 'users' do field :name, :string field :email, :string field :password, :string, virtual: true field :password_hash, :string end end
Her definerer vi fire felt i 'brukere' -tabellen: navn, e-postadresse, passord og passord_hash.
Ikke mye er interessant her, bortsett fra 'passord' -feltet som er angitt som 'virtuelt'.
Dette lar oss sette og få dette feltet uten å lagre endringene i databasen. Det er nyttig fordi vi ville ha logikk for å konvertere passordet til en hash, som vi vil lagre i 'password_hash' -feltet og deretter lagre det i databasen.
Du må fremdeles opprette en migrasjon; skjemaet i modellen er nødvendig fordi feltene ikke lastes automatisk inn i modellen som i Ruby on Rails.
Forskjellen mellom Phoenix og Ruby on Rails er at modellen ikke takler utholdenheten til databasen. Dette håndteres av en modul kalt “Repo” som er konfigurert med databaseinformasjonen, som vist i eksemplet nedenfor:
config :my_app, Repo, adapter: Ecto.Adapters.Postgres, database: 'ecto_simple', username: 'postgres', password: 'postgres', hostname: 'localhost'
Denne koden er inkludert i de miljøspesifikke konfigurasjonsfilene, for eksempel config/dev.exs
eller config/test.exs
. Dette gjør at vi deretter kan bruke Repo til å utføre databaseoperasjoner som å opprette og oppdatere.
Repo.insert(%User{name: 'John Smith', example: ' [email protected] '}) do {:ok, user} -> # Insertion was successful {:error, changeset} -> # Insertion failed end
Dette er et vanlig eksempel i kontrollere i Phoenix.
Vi gir en bruker et navn og en e-post, og Repo prøver å opprette en ny post i databasen. Vi kan deretter, valgfritt, håndtere det vellykkede eller mislykkede forsøket som vist i eksemplet.
For å forstå denne koden bedre, må du forstå mønstermatching i Elixir. Verdien som returneres av funksjonen er en tupel. Funksjonen returnerer en tuple med to verdier, en status, og deretter enten modellen eller et endringssett. Et endringssett er en måte å spore endringer og validere en modell (endringssett vil bli diskutert i neste avsnitt).
Den første tupelen, fra topp til bunn, som samsvarer med mønsteret for tupelen som returneres av funksjonen som forsøkte å sette brukeren inn i databasen, vil kjøre den definerte funksjonen.
Vi kunne ha satt en variabel for status i stedet for et atom (som i utgangspunktet er hva et symbol er i Ruby), men da ville vi matche både vellykkede og mislykkede forsøk og ville bruke den samme funksjonen i begge situasjoner. Når vi spesifiserer hvilket atom vi vil matche, definerer vi en funksjon spesielt for den statusen.
Ruby on Rails har utholdenhetsfunksjonaliteten innebygd i modellen gjennom ActiveRecord. Dette tilfører modellen mer ansvar og kan noen ganger gjøre testing av en modell mer komplisert som et resultat. I Phoenix har dette blitt skilt på en måte som gir mening og forhindrer oppblåsthet hver modell med utholdenhetslogikk.
Endringssett tillater klare validerings- og transformasjonsregler.
I Ruby on Rails kan validering og transformering av data være kilden til vanskelige å finne feil. Dette er fordi det ikke er umiddelbart åpenbart når data transformeres av tilbakeringinger som 'før_opprett' og valideringer.
I Phoenix gjør du eksplisitt disse valideringene og transformasjonene ved hjelp av endringssett. Dette er en av favorittfunksjonene mine i Phoenix.
La oss ta en titt på et endringssett ved å legge til en i forrige modell:
defmodule HelloPhoenix.User do use HelloPhoenix.Web, :model schema 'users' do field :name, :string field :email, :string field :password, :string, virtual: true field :password_hash, :string end def changeset(struct, params \ %{}) do struct |> cast(params, [:name, :email, :password]) |> validate_required([:email, :password]) end end
Her gjør endringssettet to ting.
Først kaller den 'cast' -funksjonen, som er en hvitliste over tillatte felt, som 'strong_parameters' i Ruby on Rails, og deretter validerer den at 'e-post' og 'passord' -feltene er inkludert, noe som gjør 'name' -feltet valgfri. På denne måten kan bare feltene du tillater endres av brukerne.
Det fine med denne tilnærmingen er at vi ikke er begrenset til ett endringssett. Vi kan opprette flere endringssett. Et endringssett for registrering og et for oppdatering av brukeren er vanlig. Kanskje vi bare vil kreve passordfeltet når vi registrerer oss, men ikke når vi oppdaterer brukeren.
Sammenlign denne tilnærmingen med det som ofte gjøres i Ruby on Rails. Du må spesifisere at valideringen bare skal kjøres på 'create'. Dette gjør det noen ganger vanskelig i Rails å finne ut hva koden din gjør når du har en kompleks modell.
Import av funksjonalitet er grei, men likevel fleksibel.
Mye av funksjonaliteten til et bibliotek kalt “Ecto” importeres til modellene. Modeller har vanligvis denne linjen nær toppen:
use HelloPhoenix.Web, :model
“HelloPhoenix.Web” -modulen ligger i “web / web.ex”. I modulen skal det være en funksjon kalt “modell” som følger:
def model do quote do use Ecto.Schema import Ecto import Ecto.Changeset import Ecto.Query end end
Her kan du se hvilke moduler vi importerer fra Ecto. Du kan fjerne eller legge til andre moduler du vil ha her, og de vil bli importert til alle modeller.
Det er også lignende funksjoner som 'view' og 'controller' som tjener samme formål for henholdsvis visningene og kontrollerne.
quote
og use
søkeord kan virke forvirrende. For dette eksemplet kan du tenke på et tilbud som kjører den koden direkte i sammenheng med modulen som kaller den funksjonen. Så det tilsvarer å ha skrevet koden i sitatet i modulen.
Bruke nøkkelordet lar deg også kjøre kode i sammenheng med hvor det heter. Det krever i hovedsak den spesifiserte modulen, og kaller deretter __using__
makro på modulen som kjører den i sammenheng med hvor den ble kalt. Du kan lese mer om sitat og bruk i den offisielle guiden.
Dette hjelper deg virkelig å forstå hvor bestemte funksjoner er plassert i rammeverket, og bidrar til å redusere følelsen av at rammeverket gjør mye 'magi'.
Samtidighet er kjernen.
Samtidighet kommer gratis i Phoenix fordi det er et hovedtrekk ved Elixir. Du får et program som kan gyte flere prosesser og kjøre på flere kjerner uten bekymringer om trådsikkerhet og pålitelighet.
Du kan gyte en ny prosess i Elixir dette ganske enkelt:
spawn fn -> 1 + 2 end
Alt etter spawn
og før end
vil kjøre i en ny prosess.
Faktisk blir hver forespørsel i Phoenix håndtert i sin egen prosess. Elixir bruker kraften fra Erlang VM til å gi pålitelig og effektiv samtidighet 'gratis.'
Dette gjør også Phoenix til et godt valg for å kjøre tjenester som bruker WebSockets, siden WebSockets trenger å opprettholde en åpen forbindelse mellom klienten og serveren (noe som betyr at du må bygge applikasjonen din slik at den kan håndtere tusenvis av samtidige tilkoblinger).
Disse kravene vil legge til mye kompleksitet i et prosjekt bygget på Ruby on Rails, men Phoenix kan oppfylle disse kravene gratis gjennom Elixir.
Hvis du vil bruke WebSockets i Phoenix-applikasjonen din, må du bruke den Kanaler . Det tilsvarer ActionCable
i Ruby on Rails, men mindre komplisert å sette opp fordi du ikke trenger å kjøre en egen server.
Phoenix gjør bygging av moderne webapper smertefri.
Mens vi i stor grad har fokusert på forskjellene, har Phoenix noen ting til felles med Ruby on Rails.
Phoenix følger omtrent det samme MVC-mønsteret som Ruby on Rails, så det å finne ut hvilken kode som går, burde ikke være vanskelig nå som du vet om hovedforskjellene. Phoenix har også lignende generatorer som Ruby on Rails for å lage modeller, kontrollere, migrasjoner og mer.
Etter å ha lært Elixir, vil du sakte nærme deg Ruby on Rails produktivitetsnivå når du er mer komfortabel med Phoenix.
De få gangene jeg ikke føler meg like produktiv, er når jeg støter på et problem som ble løst av en perle i Ruby, og jeg kan ikke finne et lignende bibliotek for Elixir. Heldigvis fylles disse hullene sakte av det voksende Elixir-samfunnet.
Forskjellene i Phoenix hjelper til med å løse mye av smerten som fulgte med å håndtere komplekse Ruby on Rails-prosjekter. Selv om de ikke løser alle problemer, hjelper de deg med å skyve deg i riktig retning. Å velge et tregt rammeverk fordi du ønsker produktivitet er ikke lenger en gyldig unnskyldning, Phoenix lar deg ha begge deler.