說說你使用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, ReleaseMonitoringEcoSystem:
MixJSON Parser, Http ClientDriver, BindingJob QueueElixir-lang:
rebinding, lens, comprehension, with, pipe, protocol, behaviour, mixin, macro(stacktrace)OTP: Application, Config, Supervisor, Task斷斷續續用 Elixir 做項目也快2年了,隨便說說吧。
- Mix,提供一站式的項目維護工具,現代語言標配,不用一上來開始擼Makefile, umbrella 模式管理大項目很好。
- Hex,包管理系統, 也是現代語言標配,好處就不用說了。
- 更靈活語法, pipe, with,後聲明變數覆蓋前面聲明的, 媽媽再也不用擔心我寫 State1, State2了。
- 終於不用一個模塊一個文件,文件名必須是模塊名,然後再用 -module() 寫一遍。(旁邊那個 java同學, 你也留下來聽聽)
2. 更活躍的社區, Erlang 原來的社區都是搞電信,搞伺服器的, 明顯沒有做 web 的活躍,願意分享信息(代碼質量另說)
{event: "login", attr: "level", filter: {gt: 10}, action: "doSomething"}
會被翻譯成
if login.level &> 10 do
doSomething()
end
@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 不過是惡作劇而已」是真的嗎?