Phoenix를 만나보세요: Elixir의 최신 웹 앱을 위한 Rails와 유사한 프레임워크

게시 됨: 2022-03-11

Phoenix 프레임워크는 Ruby on Rails와 같은 프레임워크의 생산성을 제공하는 동시에 사용 가능한 가장 빠른 프레임워크 중 하나로서 빠른 속도로 인기를 얻고 있습니다. 생산성을 높이려면 성능을 희생해야 한다는 통념이 깨졌습니다.

그렇다면 피닉스는 정확히 무엇입니까?

Phoenix는 Elixir 프로그래밍 언어로 구축된 웹 프레임워크입니다. Erlang VM에 구축된 Elixir는 최신 웹 애플리케이션에서 점점 더 필요한 품질인 저지연, 내결함성, 분산 시스템을 구축하는 데 사용됩니다. 이 블로그 게시물이나 공식 가이드에서 Elixir에 대해 자세히 알아볼 수 있습니다.

Ruby on Rails 개발자라면 Phoenix가 약속하는 성능 향상 때문에 확실히 관심을 가져야 합니다. 다른 프레임워크의 개발자도 따라가서 Phoenix가 웹 개발에 접근하는 방식을 확인할 수 있습니다.

Elixir에서 Phoenix를 만나보세요: 최신 웹 앱을 위한 Rails와 유사한 프레임워크

이 글에서 우리는 당신이 Ruby on Rails의 세계에서 왔다면 명심해야 할 Phoenix의 몇 가지 사항을 배울 것입니다.

Ruby와 달리 Elixir는 함수형 프로그래밍 언어이므로 처리해야 할 수 있는 가장 큰 차이점일 것입니다. 그러나 Phoenix를 배우는 사람은 생산성을 극대화하기 위해 알고 있어야 하는 두 플랫폼 사이에 몇 가지 주요 차이점이 있습니다.

명명 규칙은 더 간단합니다.

이것은 작지만 Ruby on Rails에서 온다면 엉망이 되기 쉽습니다.

피닉스에서는 모든 것을 단수형으로 작성하는 것이 관례입니다. 따라서 Ruby on Rails에서와 같이 "UsersController" 대신 "UserController"를 갖게 됩니다. 이것은 데이터베이스 테이블의 이름을 지정할 때를 제외하고 모든 곳에서 적용됩니다. 여기서 규칙은 테이블 이름을 복수형으로 지정하는 것입니다.

이것은 Ruby on Rails에서 언제 어디서 복수형을 사용해야 하는지를 배운 후에는 별 문제가 아닌 것처럼 보일 수 있지만, Ruby on Rails를 사용하는 방법을 배울 때 처음에는 약간 혼란스러웠고 많은 사람들을 혼란스럽게 했을 것입니다. 다른 사람들도. 피닉스는 걱정할 일이 한 가지 줄어듭니다.

라우팅 관리가 더 쉽습니다.

Phoenix와 Ruby on Rails는 라우팅과 관련하여 매우 유사합니다. 주요 차이점은 요청이 처리되는 방식을 제어하는 ​​방법에 있습니다.

Ruby on Rails(및 기타 Rack 애플리케이션)에서는 미들웨어를 통해 수행되지만 Phoenix에서는 "플러그"라고 하는 것으로 수행됩니다.

플러그는 연결을 처리하는 데 사용하는 것입니다.

예를 들어, 미들웨어 Rails::Rack::Logger 는 Rails에 요청을 기록하고, Phoenix에서는 Plug.Logger 플러그로 수행됩니다. 기본적으로 Rack 미들웨어에서 할 수 있는 모든 작업은 플러그를 사용하여 수행할 수 있습니다.

다음은 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

먼저 파이프라인을 살펴보겠습니다.

이들은 요청이 이동하는 플러그 그룹입니다. 미들웨어 스택으로 생각하십시오. 예를 들어 요청에 HTML이 필요한지 확인하고, 세션을 가져오고, 요청이 안전한지 확인하는 데 사용할 수 있습니다. 이 모든 것은 컨트롤러에 도달하기 전에 발생합니다.

여러 파이프라인을 지정할 수 있으므로 특정 경로에 필요한 플러그를 선택할 수 있습니다. 예를 들어 라우터에는 페이지(HTML) 및 API(JSON) 요청에 대해 서로 다른 파이프라인이 있습니다.

다양한 유형의 요청에 정확히 동일한 파이프라인을 사용하는 것이 항상 의미가 있는 것은 아닙니다. Phoenix는 이러한 유연성을 제공합니다.

보기와 템플릿은 서로 다른 두 가지입니다.

Phoenix의 보기는 Ruby on Rails의 보기와 다릅니다.

피닉스의 뷰는 템플릿을 렌더링하고 템플릿이 원시 데이터를 더 쉽게 사용할 수 있도록 하는 기능을 제공합니다. Phoenix의 보기는 템플릿 렌더링이 추가된 Ruby on Rails의 도우미와 가장 유사합니다.

"Hello, World!"를 표시하는 예제를 작성해 보겠습니다. 브라우저에서.

루비 온 레일즈:

앱/컨트롤러/hello_controller.rb:

 class HelloController < ApplicationController def index end end

app/views/hello/index.html.erb:

 <h1>Hello, World!</h1>

불사조:

웹/컨트롤러/hello_controller.ex:

 defmodule HelloWorld.HelloController do use HelloWorld.Web, :controller def index(conn, _params) do render conn, "index.html" end end

web/views/hello_view.ex:

 defmodule HelloWorld.HelloView do use HelloWorld.Web, :view end

웹/템플릿/hello/index.html.eex:

 <h1>Hello, World!</h1>

이 예는 모두 "Hello, World!"를 표시합니다. 브라우저에 있지만 몇 가지 주요 차이점이 있습니다.

먼저 Ruby on Rails와 달리 Phoenix에서 렌더링하려는 템플릿을 명시적으로 지정해야 합니다.

다음으로 컨트롤러와 템플릿 사이에 있는 Phoenix에 보기를 포함해야 했습니다.

이제 뷰가 ​​비어 있는 경우 뷰가 필요한 이유가 궁금할 것입니다. 여기서 핵심은 내부적으로 Phoenix가 템플릿을 아래 코드와 거의 동일한 함수로 컴파일한다는 것입니다.

 defmodule HelloWorld.HelloView do use HelloWorld.Web, :view def render("index.html", _assigns) do raw("<h1>Hello, World!</h1>") end end

템플릿을 삭제하고 새로운 렌더링 기능을 사용해도 동일한 결과를 얻을 수 있습니다. 이것은 텍스트 또는 JSON을 반환하려는 경우에 유용합니다.

모델은 바로 데이터 모델입니다.

Phoenix에서 모델은 주로 데이터 유효성 검사, 스키마, 다른 모델과의 관계 및 표시 방법을 처리합니다.

모델에서 스키마를 지정하는 것이 처음에는 이상하게 들릴 수 있지만 데이터베이스에 유지되지 않는 필드인 "가상" 필드를 쉽게 생성할 수 있습니다. 예를 살펴보겠습니다.

 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

여기에서 "users" 테이블에 name, email, password 및 password_hash의 네 가지 필드를 정의합니다.

여기서 "가상"으로 설정된 "비밀번호" 필드를 제외하고는 그다지 흥미롭지 않습니다.

이를 통해 데이터베이스에 변경 사항을 저장하지 않고 이 필드를 설정하고 가져올 수 있습니다. 암호를 해시로 변환하는 논리가 있기 때문에 "password_hash" 필드에 저장한 다음 데이터베이스에 저장할 수 있기 때문에 유용합니다.

여전히 마이그레이션을 생성해야 합니다. Ruby on Rails처럼 필드가 자동으로 모델에 로드되지 않기 때문에 모델의 스키마가 필요합니다.

Phoenix와 Ruby on Rails의 차이점은 모델이 데이터베이스에 대한 지속성을 처리하지 않는다는 것입니다. 이것은 아래 예와 같이 데이터베이스 정보로 구성된 "Repo"라는 모듈에 의해 처리됩니다.

 config :my_app, Repo, adapter: Ecto.Adapters.Postgres, database: "ecto_simple", username: "postgres", password: "postgres", hostname: "localhost"

이 코드는 config/dev.exs 또는 config/test.exs test.exs와 같은 환경별 구성 파일에 포함되어 있습니다. 이를 통해 Repo를 사용하여 생성 및 업데이트와 같은 데이터베이스 작업을 수행할 수 있습니다.

 Repo.insert(%User{name: "John Smith", example: "[email protected]"}) do {:ok, user} -> # Insertion was successful {:error, changeset} -> # Insertion failed end

이것은 Phoenix 컨트롤러의 일반적인 예입니다.

우리는 사용자에게 이름과 이메일을 제공하고 Repo는 데이터베이스에 새 레코드를 생성하려고 시도합니다. 그런 다음 선택적으로 예와 같이 성공 또는 실패 시도를 처리할 수 있습니다.

이 코드를 더 잘 이해하려면 Elixir의 패턴 매칭을 이해해야 합니다. 함수에서 반환된 값은 튜플입니다. 이 함수는 두 값의 튜플, 즉 상태를 반환한 다음 모델 또는 변경 집합을 반환합니다. 변경 세트는 변경 사항을 추적하고 모델을 검증하는 방법입니다(변경 세트는 다음 섹션에서 설명합니다).

사용자를 데이터베이스에 삽입하려고 시도한 함수에 의해 반환된 튜플의 패턴과 일치하는 위에서 아래로 첫 번째 튜플은 정의된 함수를 실행합니다.

원자 대신 상태에 대한 변수를 설정할 수 있었지만(기본적으로 Ruby에서 기호가 무엇인지), 성공한 시도와 실패한 시도를 모두 일치시키고 두 상황 모두에 대해 동일한 기능을 사용합니다. 일치시킬 원자를 지정하면 해당 상태에 대한 함수를 특별히 정의합니다.

Ruby on Rails에는 ActiveRecord를 통해 모델에 내장된 지속성 기능이 있습니다. 이렇게 하면 모델에 더 많은 책임이 추가되고 결과적으로 모델 테스트가 더 복잡해질 수 있습니다. Phoenix에서는 이것이 의미가 있고 지속성 논리로 모든 모델이 부풀려지는 것을 방지하는 방식으로 분리되었습니다.

변경 세트는 명확한 유효성 검사 및 변환 규칙을 허용합니다.

Ruby on Rails에서 데이터 유효성 검사 및 변환은 찾기 어려운 버그의 원인이 될 수 있습니다. 이는 "before_create" 및 유효성 검사와 같은 콜백에 의해 데이터가 변환될 때 즉시 명확하지 않기 때문입니다.

Phoenix에서는 변경 집합을 사용하여 이러한 유효성 검사 및 변환을 명시적으로 수행합니다. 이것은 내가 피닉스에서 가장 좋아하는 기능 중 하나입니다.

이전 모델에 하나를 추가하여 변경 집합을 살펴보겠습니다.

 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

여기서 변경 집합은 두 가지 작업을 수행합니다.

먼저 Ruby on Rails의 "strong_parameters"와 유사한 허용 필드의 화이트리스트인 "cast" 함수를 호출한 다음 "email" 및 "password" 필드가 포함되어 있는지 확인하여 "name" 필드를 만듭니다. 선택 과목. 이렇게 하면 허용한 필드만 사용자가 수정할 수 있습니다.

이 접근 방식의 좋은 점은 하나의 변경 집합으로 제한되지 않는다는 것입니다. 여러 변경 집합을 만들 수 있습니다. 등록용 변경 세트와 사용자 업데이트용 변경 세트는 공통입니다. 등록할 때만 암호 필드를 요구하고 사용자를 업데이트할 때는 요구하지 않을 수 있습니다.

이 접근 방식을 Ruby on Rails에서 일반적으로 수행되는 방식과 비교하면 "생성"에서만 유효성 검사를 실행하도록 지정해야 합니다. 이것은 때때로 복잡한 모델이 있는 경우 Rails에서 코드가 수행하는 작업을 파악하기 어렵게 만듭니다.

가져오기 기능은 간단하면서도 유연합니다.

"Ecto"라는 라이브러리의 기능 대부분을 모델로 가져옵니다. 모델에는 일반적으로 상단 근처에 다음 줄이 있습니다.

 use HelloPhoenix.Web, :model

"HelloPhoenix.Web" 모듈은 "web/web.ex"에 있습니다. 모듈에는 다음과 같이 "model"이라는 함수가 있어야 합니다.

 def model do quote do use Ecto.Schema import Ecto import Ecto.Changeset import Ecto.Query end end

여기에서 우리가 Ecto에서 가져오는 모듈을 볼 수 있습니다. 여기에서 원하는 다른 모듈을 제거하거나 추가할 수 있으며 모든 모델로 가져옵니다.

뷰와 컨트롤러에 각각 동일한 목적을 제공하는 "보기" 및 "컨트롤러"와 같은 유사한 기능도 있습니다.

quoteuse 키워드가 혼동될 수 있습니다. 이 예에서 인용문은 해당 함수를 호출하는 모듈의 컨텍스트에서 해당 코드를 직접 실행하는 것으로 생각할 수 있습니다. 따라서 모듈의 따옴표 안에 코드를 작성한 것과 같습니다.

use 키워드를 사용하면 호출된 컨텍스트에서 코드를 실행할 수도 있습니다. 본질적으로 지정된 모듈이 필요한 다음 호출된 컨텍스트에서 모듈을 실행하는 모듈에서 __using__ 매크로를 호출합니다. 견적 및 사용에 대한 자세한 내용은 공식 가이드에서 확인할 수 있습니다.

이것은 프레임워크에서 특정 기능이 있는 위치를 이해하는 데 실제로 도움이 되며 프레임워크가 많은 "마법"을 수행하고 있다는 느낌을 줄이는 데 도움이 됩니다.

동시성은 핵심입니다.

동시성은 Elixir의 주요 기능이기 때문에 Phoenix에서 무료로 제공됩니다. 스레드 안전성과 안정성에 대한 걱정 없이 여러 프로세스를 생성하고 여러 코어에서 실행할 수 있는 애플리케이션을 얻을 수 있습니다.

다음과 같이 간단하게 Elixir에서 새 프로세스를 생성할 수 있습니다.

 spawn fn -> 1 + 2 end

spawn 이후와 end 이전의 모든 것은 새 프로세스에서 실행됩니다.

사실, 피닉스의 모든 요청은 자체 프로세스에서 처리됩니다. Elixir는 Erlang VM의 기능을 사용하여 "무료"로 안정적이고 효율적인 동시성을 제공합니다.

또한 WebSocket은 클라이언트와 서버 간의 열린 연결을 유지해야 하기 때문에 Phoenix는 WebSocket을 사용하는 서비스를 실행하는 데 탁월한 선택입니다(즉, 수천 개의 동시 연결을 처리할 수 있도록 응용 프로그램을 빌드해야 함을 의미함).

이러한 요구 사항은 Ruby on Rails에 구축된 프로젝트에 많은 복잡성을 추가하지만 Phoenix는 Elixir를 통해 이러한 요구 사항을 무료로 충족할 수 있습니다.

Phoenix 애플리케이션에서 WebSocket을 사용하려면 채널을 사용해야 합니다. Ruby on Rails의 ActionCable 과 동일하지만 별도의 서버를 실행할 필요가 없기 때문에 설정이 덜 복잡합니다.

Phoenix를 사용하면 현대적인 웹 앱을 손쉽게 구축할 수 있습니다.

우리는 주로 차이점에 중점을 두었지만 Phoenix는 Ruby on Rails와 몇 가지 공통점이 있습니다.

Phoenix는 Ruby on Rails와 거의 동일한 MVC 패턴을 따르므로 주요 차이점에 대해 알게 되었으므로 이제 어떤 코드가 어디로 가는지 알아내는 것이 어렵지 않습니다. 또한 Phoenix에는 모델, 컨트롤러, 마이그레이션 등을 생성하기 위한 Ruby on Rails와 유사한 생성기가 있습니다.

Elixir를 학습한 후 Phoenix에 익숙해지면 Ruby on Rails의 생산성 수준에 천천히 접근하게 됩니다.

Ruby의 gem으로 해결된 문제에 직면했을 때 생산성이 좋지 않다고 느끼는 경우가 몇 번 있는데 Elixir에 대한 유사한 라이브러리를 찾을 수 없습니다. 운 좋게도 이러한 격차는 성장하는 Elixir 커뮤니티에 의해 서서히 채워지고 있습니다.

Phoenix의 차이점은 복잡한 Ruby on Rails 프로젝트를 관리할 때 발생하는 많은 문제를 해결하는 데 도움이 됩니다. 모든 문제를 해결하지는 못하지만 올바른 방향으로 나아가는 데 도움이 됩니다. 생산성을 원하기 때문에 느린 프레임워크를 선택하는 것은 더 이상 유효한 핑계가 아닙니다. Phoenix는 두 가지 모두를 허용합니다.