2

Khi tôi đang suy nghĩ về bài viết này vài tuần trước, tôi đã rất phấn khích khi thấy Chris McCord , người tạo ra Phoenix FrameworkElixir , đã ở trên podcast của Elixir Fountain .

Một trong những điều họ đề cập trong chương trình là họ đã mệt mỏi với việc so sánh được thực hiện giữa Rails và Phoenix. Sự thiên vị đến từ nền Rails có thể che mờ tầm nhìn của bạn về khung và khiến bạn nghĩ về nó như là Rails trong Elixir, chứ không phải là thứ gì đó độc lập và đưa ra những ý tưởng mới và khác biệt so với những cái có trong Rails.

Điều đó đang được nói, tôi đang so sánh giữa Rails và Phoenix như một cách để giúp những người quen thuộc với Rails hiểu được một số điểm tương đồng giữa hai khung. Và tất nhiên, nơi họ có thể khác nhau.

Cả Rails và Phoenix đều là các khung web có chung một mục tiêu, đó là giúp bạn làm việc hiệu quả nhất có thể. Trên thực tế, người sáng tạo của Elixir, ông Jose Valim là thành viên của nhóm nòng cốt Rails, và Chris cũng đến từ nền tảng của Rails. Vì vậy, bạn không nên thấy lạ khi thấy một số phần hay nhất của Rails giống với những gì bên trong Phoenix.

Rails và Phoenix là những khung web có chung một mục tiêu. Hãy thông qua @leighchalliday

Trong bài viết này, chúng tôi sẽ khám phá không chỉ các khía cạnh điển hình của khung web MVC (Mô hình, Khung nhìn, Bộ điều khiển), mà chúng tôi cũng sẽ chạm vào Định tuyến, Tài sản và Websockets / Kênh.

Tải ứng dụng của bạn lên và chạy

Sau khi bạn đã cài đặt các phụ thuộc cấp cơ sở để có thể tạo ứng dụng Rails hoặc Phoenix (như Ruby, Elixir và cả hai khung), bạn cần phải tự tạo ứng dụng. Chúng tôi sẽ xây dựng sự khởi đầu của một bản sao Twitter trong cả Rails và Phoenix. Tôi đã làm hết sức mình để tạo ra chúng tương tự nhau để dễ dàng so sánh mã giữa chúng.

Lên và chạy với đường ray

Bước đầu tiên trong việc tạo ứng dụng Rails là chạy lệnh để tạo nó. Điều này sẽ thiết lập cấu trúc thư mục mặc định cùng với tất cả các tệp cần thiết để bắt đầu.

rails new twitter_rails

Khi chúng tôi đã thực hiện điều đó, chúng tôi có thể cdvào thư mục và yêu bundlecầu cài đặt tất cả các phụ thuộc được tìm thấy bên trong Gemfile.

bundle install

Bước cuối cùng là tạo ra giàn giáo. Bạn sẽ nhận thấy rằng lựa chọn mặc định cho JavaScript trong Rails là sử dụng CoffeeScripttrong khi Phoenix quyết định sử dụng ES6thay thế.

Tôi nghĩ rằng Phoenix đã đưa ra quyết định tốt hơn ở đây, vì nó dường như là một cách tiếp cận hiện đại hơn và nơi mọi thứ đang diễn ra. Điều đó nói rằng, bạn chắc chắn có thể viết ES6 trong Rails bằng cách thêm một viên ngọc.

rails g scaffold User name username:string:unique email:string:unique bio
rails db:migrate

Lên và chạy với Phoenix

Điều này sẽ tuân theo một quy trình rất giống với quy trình trong Rails. Để bắt đầu với Phoenix, bạn sẽ chạy mix phoenix.newlệnh. Điều này sẽ tạo cấu trúc thư mục và các tệp cần thiết cho ứng dụng. Lệnh tôi đã sử dụng cho dự án là dưới đây:

mix phoenix.new twitter_phoenix

Bước tiếp theo là cài đặt các phụ thuộc.

Bạn sẽ nhận thấy rằng mixlệnh này hơi giống như bundleở vùng đất Ruby, nhưng cũng có một chút giống như vậy rake. Một điều nữa cần chỉ ra là trừ khi bạn xây dựng API JSON thuần túy (nơi không cần tài sản), bạn cũng sẽ cần cài đặt Node. Điều này là do quản lý tài sản ở Phoenix được xử lý bởi thư viện JavaScript có tên Brunch , thay vì cố gắng xây dựng đường dẫn tài sản của riêng mình như Rails đã làm.

Các phụ thuộc trong Phoenix được tìm thấy bên trong một tệp ở gốc của ứng dụng được gọi mix.exsbên trong depsphương thức. Ngoài ra còn có một package.jsontập tin nơi tất cả các phụ thuộc tài sản ( npm ) được tìm thấy.

mix deps.get
npm install

Bước tiếp theo sẽ là tạo ra một số giàn giáo. Lệnh bên dưới tạo hoàn toàn mọi thứ: bộ điều khiển, mô hình, khung nhìn, di chuyển cơ sở dữ liệu, tệp kiểm tra, v.v ... Đó là một cách rất thuận tiện để chuyển từ số 0 sang thứ gì đó hoạt động nhanh chóng. Chúng tôi cũng sẽ chạy di chuyển cơ sở dữ liệu ngay lập tức (sau này trong bài viết này, chúng tôi sẽ xem chúng trông như thế nào).

mix phoenix.gen.html User users name username:unique email:unique bio
mix ecto.migrate

định tuyến

Định tuyến thực sự là tiền tuyến của bất kỳ ứng dụng web nào, nơi yêu cầu HTTP được gửi đến Bộ điều khiển được chuẩn bị để xử lý nó.

Định tuyến trong Rails

Định tuyến trong Rails xảy ra thông qua DSL rất dễ sử dụng. Bởi vì đây mới chỉ là khởi đầu của một ứng dụng, chúng tôi chỉ đơn giản là xác định hai tuyến đường. Chúng tôi có một userstài nguyên của chúng tôi và được lồng vào bên trong, chúng tôi có tweetstài nguyên.

Điều này cho phép chúng tôi xây dựng các URL phức tạp trông như thế này: /users/:user_id/tweetsđể xem các tweet thuộc về một người dùng cụ thể. Cả Rails và Phoenix đều tạo ra các tuyến RESTful khi bạn xác định chúng bằng resourcesphương thức như chúng tôi có bên dưới, tạo các tuyến để quản lý các hành động CRUD cho từng tài nguyên.

Rails.application.routes.draw do
  resources :users do
    resources :tweets
  end

  # Serve websocket cable requests in-process
  # mount ActionCable.server => '/cable'
end

Bằng cách xác định định tuyến như thế này, Rails tạo cho chúng ta một loạt các phương thức trợ giúp để giúp việc tạo URL và đường dẫn bên trong ứng dụng dễ dàng hơn. Bạn có thể truy cập chúng trong chế độ xem hoặc trong bộ điều khiển. Để xem tweet cho một người dùng cụ thể, bạn có thể sử dụng phương thức trợ giúp user_tweets_path(user).


Định tuyến trong Rails và Phoenix có thể trông tương tự nhau, nhưng chúng ta hãy nhìn khác về Phoenix.

Định tuyến tại Phoenix

Định tuyến ở Phoenix thoạt nhìn có thể trông giống như cách nó được thực hiện trong Rails, nhưng sự thật là có nhiều thứ ở đây hơn là bắt mắt. Nó dài hơn một chút, vâng, nhưng chúng ta sẽ xem xét các phần khác nhau đang làm gì.

defmodule TwitterPhoenix.Router do
  use TwitterPhoenix.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 "/", TwitterPhoenix do
    pipe_through :browser

    get "/", PageController, :index
    resources "/users", UserController do
      resources "/tweets", TweetController
    end
  end

  # Other scopes may use custom stacks.
  # scope "/api", TwitterPhoenix do
  #   pipe_through :api
  # end
end

Phích cắm và đường ống

Trước khi chúng tôi đi vào chi tiết, tôi muốn chạm vào những gì là một plug.

Phích cắm đóng vai trò chính trong khung Phoenix. Mặc dù chúng khác nhau, tôi vẫn nghĩ rằng chúng gần giống nhất middleware, chẳng hạn như những gì được tìm thấy trong các khung Ruby dựa trên Rack . Đây là một đặc điểm kỹ thuật cho phép các máy chủ web khác nhau (như Cowboy trong thế giới Elixir) nói một ngôn ngữ chung liên quan đến yêu cầu / phản hồi của yêu cầu HTTP. Nơi khác biệt là middlewarecó xu hướng xem mọi thứ như requestresponse, trong đó plugxem mọi thứ có thể tổng thể hơn một chút như một connection.

Theo các thuật ngữ đơn giản nhất, các trình cắm là một loạt các phương thức và mô-đun vượt qua connectionvà thêm, sửa đổi hoặc tạm dừng nó khi cần thiết.

Trong Phoenix, các tuyến đường chỉ đơn giản là phích cắm, nhưng bộ điều khiển và mọi thứ khác cũng vậy. Các tuyến và bộ điều khiển chỉ đơn giản cung cấp một DSL hoặc trừu tượng khác cho cách bạn liên quan đến các phích cắm.

Điều này đưa chúng ta đến pipelinemã được thấy trong tệp định tuyến trước đó. Những gì một đường ống làm là để xác định một loạt các phích cắm có thể được áp dụng cho tất cả các yêu cầu tương tự. Tất cả các yêu cầu từ trình duyệt cần những thứ như sessionthông tin, bảo vệ khỏi sự giả mạo và thực tế là họ chấp nhận htmlyêu cầu. Điều này cho phép chúng tôi nói rằng bất kỳ yêu cầu nào trong /phạm vi sẽ có tất cả các phích cắm được tìm thấy trong :browserđường ống được áp dụng cho chúng.

Trong Rails, có --apitùy chọn, tạo ra phiên bản Rails thu nhỏ, không có cookie, phiên, bảo vệ giả mạo, v.v. Điều này không cần thiết ở Phoenix vì chúng ta có thể chọn đường dẫn mà yêu cầu sẽ truyền qua và do đó tập hợp các chức năng được sử dụng.

Phương thức khớp chữ ký

Một điều thú vị khác về định tuyến trong Phoenix là nó thực sự là một loạt các macro tạo ra các phương thức có cùng tên nhưng có chữ ký khác nhau. Elixir là một ngôn ngữ có mẫu phù hợp. Điều này cho phép chúng ta xác định cùng một phương thức hai lần nhưng với các chữ ký khác nhau và Erlang VM, Beam (trên đó Elixir được xây dựng), sẽ chọn một cách hiệu quả để gọi đúng.

Để biết ví dụ về cách hoạt động của mô hình khớp, hãy xem ví dụ đơn giản dưới đây. Có hai phương thức có cùng tên hello, nhưng chúng có chữ ký phương thức khác nhau. Cụ thể, người ta mong đợi một cuộc tranh cãi và người kia thì không. Điều này cũng có thể mang tên đa hình .

defmodule Sample do
  def hello(name), do: "Hello, #{name}"
  def hello, do: "Hello, nameless"
end

IO.puts Sample.hello("Leigh") # Hello, Leigh
IO.puts Sample.hello # Hello, nameless

Hoặc, để đưa ví dụ gần hơn với định tuyến, chúng ta có hai routephương thức bên dưới, cả hai đều chấp nhận một đối số duy nhất. Nhưng lần này, Elixir khớp với phương thức nào để gọi dựa trên hình dạng của chính dữ liệu, cụ thể là các chuỗi có khớp với cùng một mẫu hay không. Do đó tên "khớp mẫu."

defmodule Routing do
  def route("/"), do: "Home"
  def route("/users"), do: "Users"
end

IO.puts Routing.route("/") # Home

Mã được viết như thế này có thể kể một câu chuyện thẳng thắn hơn. Mặc dù điều này có thể được thực hiện bằng các ifcâu lệnh hoặc logic luồng điều khiển khác, trong trường hợp này, mỗi phương thức có một mục đích duy nhất cho một đầu vào cụ thể.

Kiến trúc ứng dụng

Microservice là chủ đề nóng những ngày này. Tôi đã viết một bài viết về kiến trúc ứng dụng Rails dưới dạng microservice , tập trung vào việc giao tiếp giữa các ứng dụng đơn mục đích nhỏ hơn thông qua các yêu cầu HTTP (và JSON) hoặc không đồng bộ thông qua một số loại hàng đợi. Mặc dù có những tranh luận qua lại giữa microservice và cái gọi là "nguyên khối hùng vĩ", đây thực sự không phải là điều bạn cần suy nghĩ khi làm việc với khung Phoenix.

Dịch vụ micros micros vs đá nguyên khối. Không phải là điều bạn phải suy nghĩ với Phoenix. Hãy thông qua @leighchalliday

Elixir được xây dựng dựa trên ngôn ngữ lập trình Erlang, một ngôn ngữ có tính đồng thời cao bởi chính bản chất của nó. Một trong những tính năng của Erlang là một thứ gọi là OTP (Giao thức viễn thông mở), ban đầu được xây dựng để quản lý các hệ thống viễn thông phân tán lớn.

Những gì OTP mang lại cho chúng ta ở mức rất cao là khả năng có một cây giám sát ứng dụng. Mỗi phụ huynh sẽ theo dõi các ứng dụng con và có thể được cấu hình với những việc cần làm nếu có vấn đề với các ứng dụng mà nó đang giám sát.

Bản thân ứng dụng Phoenix của chúng tôi chỉ là một ứng dụng OTP khác có thể nằm trong cây giám sát của một ứng dụng lớn hơn, có thể liên quan đến các "ứng dụng" khác. Đây thường sẽ là nơi bạn bắt đầu nghĩ đến việc tạo microservice. Nhưng, nó bị cuốn vào ngôn ngữ.

Bên trong mix.exstệp có một applicationphương thức xác định TwitterPhoenixứng dụng của chúng tôi cùng với các ứng dụng khác cần thiết để chúng tôi chạy. Đây là tất cả các quy trình nhẹ có thể giao tiếp qua lại với nhau, tất cả được quản lý bởi Erlang VM, Beam.

def application do
  [mod: {TwitterPhoenix, []},
   applications: [:phoenix, :phoenix_html, :cowboy, :logger, :gettext,
                  :phoenix_ecto, :postgrex]]
end

Một tính năng thú vị của thiết lập này là nó đi kèm với trình hiển thị trực quan tích hợp được gọi là observercho phép chúng ta xem qua từng quy trình để xem trạng thái của chúng và nơi chúng phù hợp với cây giám sát OTP lớn hơn. Nó có thể được bắt đầu từ bên trong iex(Elixir REPL) bằng lệnh :observer.start().

Chúng tôi sẽ để nó ở mức cao ở đây. Để biết thêm thông tin, bạn có thể tham khảo tài liệu Elixir về người giám sát và ứng dụng cùng với Lập trình Phoenix của Chris McCord, Bruce Tate và José Valim, có một chương về Mix và OTP chi tiết hơn.

Phần kết luận

Điều này kết thúc Phần I của sự so sánh giữa Rails và Phoenix. Trong Phần II, chúng ta sẽ bắt đầu với Mô hình và tiến hành thông qua Bộ điều khiển và Chế độ xem. Tôi hy vọng bạn đã bắt đầu thấy rằng, mặc dù tương tự, các ý tưởng và mẫu được tìm thấy trong mỗi khung làm việc khác nhau, trong khi hoàn thành mục tiêu quen thuộc là nhận yêu cầu HTTP và xây dựng phản hồi phù hợp.

Bài viết này được viết bởi Leigh Halliday

|