說說你使用Elixir/phoenix的實戰項目心得,以及對該語言/框架的前景的看法?


TLDR

手頭上剛有一個Elixir項目結束, 項目不算大也不算小, 開發了半年.

為什麼選擇Elixir? 公司之前是Erlang的codebase, 所以幾個開發對Erlang相對熟悉, 後面幾個小模塊跟小項目用Elixir試驗都覺得比較可行, 所以新項目也選擇Elixir. 整個項目由Elixir 1.0用到現在1.2, Ecto由差不多1.0用到1.1 (Elixir 1.3, Ecto 2.0也差不多正式release了)

項目大致就是目前常見的API伺服器模式, 框架用Phoenix + Maru, 有Job Queue , 有Cache, 各種Web後端里常見的花樣應該都差不多了.

Framework and Architecture:

因為是API伺服器, Phoenix主要用來做scaffold, 類似Grape的Maru才是主要對外的介面, Maru也是一個Plug(類似Ruby的Rack, Python的WSGI), 用這種上往下游去的中間件形式組織的話碰到的問題是: 有時候需要下游反饋到上游, 如何控制中間件覆蓋哪些介面. 前者可以反轉中間件, 後者可以用Phoenix的pipeline來組織中間件跟介面, 不過Phoenix跟Maru的routing一旦混在一起會很蛋疼.

業務邏輯也沒有用Phoenix從Rails那裡學來的MVC, 用了Service Object的形式來組織業務邏輯. 我們自己把這叫做usecase, usecase根據resource來組織. 每個usecase其實是一個"pipe", pipe有點像Plug, 可以是inline形式的函數,也可以是一個module 並且可以compose, "pipe"有兩個參數: 需要transform的value和做transform時context, 一個usecase大概是這樣:

defmodule FooUsecase do
use Pipe

pipe inline_pipe(value, context) do
# do something
# return {new_value, new_context}
end

pipe BarUsecase
pipe BazUsecase
end

# FooUsecase.run(init_value, init_context) =&> {final_value, final_context}

這樣業務邏輯就可以組合起來, "pipe"還有不少helper可以讓它更方便使用, 根據我的理解pipe有點像command pattern還有Haskell的Reader Monad. 底層點的"pipe"封裝讀/寫DB/Cache, 上層點的pipe組合起來不斷地在transform value.

讀寫資料庫的話用Ecto, Ecto個設計得很不錯的庫, 類似ActiveRecord同時提供DDL, DML和Schema Version Control. 但是Ecto並不像AR是個ORM, Ecto更像是一個Query Builder, 用DSL的形式來構建一個Query. ORM在對象上維護狀態, Elixir沒有對象只有Struct, Struc像是Plain Old Object(或者說value object?) 有Ecto里一個叫changeset維護數據的變動. 一般手法是結合上面"pipe"的context, value利用context里的數據生成changeset, 最後更新到資料庫.

最後返回數據給客戶端需要做序列化, 用了一個抄Grape Entity的東西: Maru Entity, 用Declarative的方式來描述model怎麼轉成json, 比較糾結的一點是: 原則是entity里沒有資料庫的訪問, 只是一個純的轉換, 但是entity的caller怎麼知道Entity需要什麼數據? 後來覺得用類似Presenter的方式做這個事情更加合理, 但最後只是折衷實現了個decorator, 先把數據explicit地decorate進去,再交給entity.

坑:

Ops:

Depoly, Release

Monitoring

EcoSystem:

Mix

JSON Parser, Http Client

Driver, Binding

Job Queue

Elixir-lang:

rebinding, lens, comprehension, with, pipe, protocol, behaviour, mixin, macro(stacktrace)

OTP:

Application, Config, Supervisor, Task


斷斷續續用 Elixir 做項目也快2年了,隨便說說吧。

首先我們的項目並不是單純的 web 項目,所有的頁面和客戶端都是通過統一的 HTTP API 和伺服器通訊。 因此我們並沒有使用 Phoenix,只用 Plug。同時,我們的資料庫主要是 Mongo,而我們開始做項目時, ecto 並不支持 Mongo, 所以我自己寫了Mongo 的 ORM 庫(目測比 ecto 的好,畢竟 ecto 是在關係型資料庫上做抽象,我們只針對 Mongo。 到最後基於性能考慮我們自己開發和維護了 elixir-mongo & 和 elixir-cbson &庫,歡迎使用)。所以,我很難對 Phoenix 這套框架有啥見解,只能說說 Elixir 語言本身。

Elixir 基於 Beam (Erlang VM), 可以無縫調用全部 Erlang 庫,所以 Erlang 的優點就不用說了,只說說 Elixir 比 Erlang 進步的地方。

1. 更現代化的語言

  • Mix,提供一站式的項目維護工具,現代語言標配,不用一上來開始擼Makefile, umbrella 模式管理大項目很好。

  • Hex,包管理系統, 也是現代語言標配,好處就不用說了。

  • 更靈活語法, pipe, with,後聲明變數覆蓋前面聲明的, 媽媽再也不用擔心我寫 State1, State2了。
  • 終於不用一個模塊一個文件,文件名必須是模塊名,然後再用 -module() 寫一遍。(旁邊那個 java同學, 你也留下來聽聽)

2. 更活躍的社區, Erlang 原來的社區都是搞電信,搞伺服器的, 明顯沒有做 web 的活躍,願意分享信息(代碼質量另說)

3. 真正的乾淨宏系統, FP 系統, 沒有宏系統幫助的話, 很多抽象會相當難做。Erlang 雖然也有一些類似的庫,但終歸還是太麻煩了。 我原來寫過 Protobuf for Erlang 和 Mysql Erlang的binding, 煩躁, 需要引入代碼生成器, 各種重複的手寫函數。 然而這次寫 Mongo ORM 庫,就非常的簡潔優雅。

利用宏系統, 我們還做了另外一個東西, 把業務邏輯配置從資料庫載入進來, 然後直接翻譯成 Elixir 函數, 載入到系統里, 性能目測有提高。

配置大概是這樣的(其實比這個複雜太多 ^_^)

{event: "login", attr: "level", filter: {gt: 10}, action: "doSomething"}

會被翻譯成

if login.level &> 10 do
doSomething()
end

即使不用上面說的這些複雜的宏, 只要記住, Elixir 在編譯時是會執行的, 那麼也會有很多花樣可以玩。

比如我們的 web api 接受的是 json 的請求, 我們希望每個請求都用一個 JsonSchema 來做校驗, 可以寫成這樣

@login_schema JsonSchema.load "./priv/login.json"
post "/login", private: %{schema: @login_schema} do
...
end

JsonSchema.load 幹了什麼呢, 其實就是把json 文件讀進來,交給 JsonSchema 生成一個校驗數據而已。 這是在編譯期做完的, 也就是說, 在運行期, 根本沒有 讀取 login.json 這個文件, 發布也不用發布這個文件。甚至這個文件寫錯了,也是在編譯期就直接發現了。

暫時能想到的就這麼多, 有新想法再來填坑。

至於展望, 我當時選 Elixir 的想法很簡單, Erlang是靠譜的, 然而語法略扭曲, 社區有點沉悶,對新手不是很友好。 考慮到團隊以後招人,Elixir 應該會是更好的選擇,實在出了問題,大不了退回使用 Erlang 嘛。 到現在來看,當時的選擇並沒有錯, Elixir 也是靠譜的,開發者的品味也夠,語言發展應該問題不大,適合用來快速開發高並發的集群系統,社區也有足夠的活力把它推向更多的領域。


我做 Ruby on Rails 開發有 3 年左右,最近累覺不愛,轉投 Elixir 懷抱。近一年來一直在用 Phoenix+React 寫一個類似於 Slack 的項目 ExChat,另外還有一個 七牛的 Elixir SDK,以及自己和其他參與的一些 開源項目 。

先說 Elixir。

1. 語法

語法像 Ruby,又有從 Erlang 那裡繼承來的 pattern match、guard 等殺器,還有很多自己的特點,寫起來非常舒服。宏的引入,大大增強了代碼的表現力,提高了開發者的生產力。

2. 函數式

immutable variables、更少的副作用等函數式的特點都使得代碼更容易書寫、測試、維護,尤其是測試,相比 OO 的語言,優勢很大。

3. Erlang VM OTP

Actor 模型、輕量級進程、監督樹等,為容錯的、分散式的項目提供了堅實可靠的基礎。

4. 生態

包管理工具、測試工具、與 Erlang 的兼容性等各方面都做的很好,給開發者體驗很好。

可以參考我之前的一個 keynote: https://speakerdeck.com/tony612/why-i-love-elixir

再談 Phoenix

1. Rails 的優點很多它都有

比如 CoC(約定優於配置)、MVC、generator等等,就不贅述了。

2. 更 Explicit

不管是Phoenix 還是 Ecto 甚至是其他 Elixir 項目都在傳遞一種信息,代碼應該更加明確,少一些 magic、不確定性。我認為 Rails 的 implicit、過於追求約定,使得靈活性大大降低了,特別是項目會變大、變複雜、定製需求越來越多。

3. Ecto

我估計很多使用 Phoenix,默認都會用 Ecto 來和資料庫交互,而 Ecto 確實是很優秀的抽象,具體可以看我寫的一篇關於 Ecto 和 ActiveRecord 比較的博客 http://tony612.com/activerecord-vs-ecto

4. 實時通信的抽象 — Channel、Presence

整體使用下來挺好用的,不管是 client 端還是 sever 端。又因為都是 Elixir 實現的,不必有其他依賴(比如 Redis,當然也可以配置來選擇用 Redis 來做 pubsub)。Phoenix 1.2 藉助 CRDT 實現了一個 Phoenix.Presence,能用來實現分散式狀態同步,最簡單的應用場景就是實現用戶在線狀態這個功能。

5. 性能

我現在的項目並不需要考慮性能問題,所以沒有太多經驗。但應該表現不錯,畢竟這是它的賣點,相信網上一搜就一大堆,比如 The Road to 2 Million Websocket Connections in Phoenix ?· Phoenix 。

6. 缺點

a. Explicit 也帶來了一些缺點,會稍稍降低一點生產力,每次 Phoenix 升級的時候,有一些額外代碼要改等。(但其實你一旦接受了 Explicit 是好的之後,可能這些缺點並不是什麼問題)。

b. 上手很容易,Elixir 代碼也不難理解,但因為基於 Erlang,所以後邊一定是要去了解 Erlang 的,這部分有點門檻。

c. 生態系統,相比 Ruby/Rails 這類成熟的語音/框架還是弱了點。但其實從我自己的使用上來講,基本問題不大,社區也蠻活躍的,而且大不了自己擼個工具唄,造輪子多有趣了。

我個人覺得 Elixir 或者 Phoenix 是非常不錯的,也是很有潛力的,但很多時候一個技術的流行還受到太多太多其它因素影響,比如開發者的口味、公司的採用、競爭者。但整體感覺還是很值得一試的。

(最後再黑一下 Rails,如果不是公司限制、學習目的或者確定項目規模不大,還是不要用 Rails。)


暫時沒用過 Phoenix,所以只能說下使用 Elixir 的想法。

做過的東西:

用 Elixir 做過的東西不少,公司用的 Web 框架、ORM、隊列、緩存 什麼的,全部自己造的。並不是說 Phoenix、 Ecto 之類的框架不好,原因大概如下幾個吧:

1. 有強自定義的需求。

2. Ecto 不穩定,到現在 2.0 仍然有非常重大更新,學習和維護成本過高。

3. 用 Elixir 實現這些東西並不困難。

使用感受:

Elixir 的安利文網上也不少,我只寫一點我最喜歡的特點,這也是我從 Erlang 轉到 Elixir 的原因,那就是「編譯時」,這點其實樓上 @林卓毅 提到過了。編譯時可以做非常多的事情,只要使用得當不僅能簡化編程,還可以極大提高運行時效率。

前景?

這個完全不想說,說不定明年就會出來一個我更喜歡的語言,然後我馬上就會棄 Elixir。但是現在,Elixir 是我用起來最舒服的語言,所以我現在在用它。


謝邀。Elixir 很像ruby,但本質是不同的。剛開始有很多的不適應。包括,元編程,代碼和數據是分開的,模式匹配,函數式思維,otp等。這種不適應不是不理解,是寫oo的東西太多了,習慣性以oo思維。於我而言,學習這些東西很值得,但是在實際項目中並不是所有人都願意學。所以引入Elixir一定要考慮團隊。

而Phoenix絕對是殺手級的框架,結合mix開發效率非常高。mix非常棒。

Phoenix魔法很少,比rails容易理解。

了解了Plug和Phoenix的關係,理解了Ecto的特點,基本上用起來會非常順手。但是,還是需要一段時間的學習。對於不喜歡玩技術的人會比較枯燥。

整體而言,學習Elixir/Phoenix是非常值得的。度過一段時間的不適應,你會發現就應該那樣做。等適應了Elixir/Phoenix,你就不想再用其他框架了。我預測Phoenix/Elixir 會成為超越Rails的框架。


用了Elixir寫了兩個小項目,一個是從某寶上抓取數據的爬蟲,一個是網站的後端。

Elixir的語法寫起來很舒服,只是有些地方要時間去適應一下,高級特性有宏,有OTP,都是Erlang里的特性,還是回頭要看一下Erlang。入門應該不會太難。

Hex.pm上的三方包也多,基本夠用,或能直接用Erlang的庫。

mix 工具,類似Rust里的cargo, 包依賴,啟動腳本等,很方便。

開發的過程,可以直接在iex里敲代碼並運行出結果,再把代碼放到文件里。效率更高。

如果說Elixir是Erlang系的Ruby, 那麼Phoenix 框架有點像Rails, 一般web單應用,或者API,開發效率可以是JAVA幾倍。還有channel的性能也比較不錯。Ecto的ORM也很直觀,性能也還不錯,只是有些地方,像載入排序等,需要自己想辦法解決。

程序執行效率上,百萬級的postgresql表,建了索引的查詢時間差不多是30ms, 如果preload多,會有所下降。如果對時間要求高到幾ms以下的,應該就不適合用這個了吧。同配置的機器 ,執行時間和JAVA屬於同一級別,但是內存會吃的比較多。

如果是想做一些創業快速開發的web項目,或者基於微服務架構,Phoenix是一個不錯的選擇,最大的優點是生產力高。至於說到它的前景,應該要有一定的時間吧,要有一定的人群使用它。今天在招聘網上看到有招elixir程序員了,這是個好現象。

Elixir是我喜歡的語言,當然,它適合後端。本人才疏學淺,有說的不對的地方,望請指正。

希望更多人關注這門語言。


首先要看Elixir創始人背景,是否有運作能力和人脈關係,

其次看資金支持,

最後看發展方向。

三個方面都完美。


Elixir是個不錯的語言,但是很多地方仍然需要完善。

宏和編譯器黑魔法有點多,但是理解了,是個非常好用的東西,不過一段時間不用就會忘記,不過為了完成抽象很多時候的選擇還是宏。

寫Web嘛,感覺還好。

不過Elixir已經走完了一個從入門到放棄的過程了。


沒寫過正經項目。給我感覺就是社區活躍度和Ruby比還差挺多,尤其在國內。找不到國內的源,裝包很難,慢,被牆得厲害。


推薦閱讀:

C++中有变量a,b,c,d,e,f作为条件表达式:如果其中任意2个及以上相同则表达式为假。怎样写?
C++高級編程、Windows程序設計和MFC,這三者學習的順序?
MFC 中 CString 與 std::string 如何相互轉換?
倘若用文言文語法編程會怎樣?
「作者都承認 C 和 Unix 不過是惡作劇而已」是真的嗎?

TAG:編程語言 | Elixir |