Galapagos Tech Blog

株式会社ガラパゴスのメンバーによる技術ブログです。

Phoenix Framework v1.3のおはなし

ご機嫌よう、ガラパゴスのおとめです。

今日は、先日RC版がリリースされたPhoenix Framework v1.3を見ていこうと思います。

大きく変わったところ

v1.3の変更点を眺めていて、次の点が興味深いと思いました。

  • web/ディレクトリが引っ越しました。
  • umbrellaがサポートされました。
  • contextがサポートされました。
  • action_fallbackが追加されました。

さて、これらの変更は、個々に見ていくよりも、まずは全体を見て概念をつかんだほうがいいのかな、と思いますので、背景から見てみましょう。

境界について考える

これまでのPhoenix Frameworkには、おおよそ以下のような問題があった、と考えられていたようです。

  • web/の下に何でもかんでも詰め込まれていて全体で一つのアプリケーションになっていて、ぜんぜん関係なくても全てに依存している。
  • modelに色々なロジックが詰め込まれていて見通しが悪いし、それでもロジックはmodelに集中して、分かりにくくなりがち。

でも、誰もが必要なことだけに集中したいですね。境界を、ここでの境界というのは境界線上のことではなく責任を明確にするとうことですが、はっきりさせたい。そのためにはどうしたらいいのかしらん?

ここに二つの鍵があります。コンテキスト境界と、アンブレラプロジェクトです。

コンテキスト境界

コンテキスト境界はドメイン駆動開発の概念ですが、軽くおさらいしておきましょう。

あるmodelがあったとして、そのmodelはあちこちで使われていて、それぞれに必要な色々なメソッドがあるとします。ことによると、あちらとこちらでは同じ言葉で違う意味、みたいな場合まであったりして、仕方がないので修飾語をくっつけてsome_method_of_a_contextとかsome_method_of_other_contextとか、みたいな感じになったりします。もちろんこういうのは、くんずほぐれつ、コード上のあちこちに散らばっていて、なんかもう全体として巨大な一つのmodelになっていて、この世に、少なくともオフィスには、呪いを生み出しますね。

無理。

ですので、共通な部分と、ある特定の部分と、別の特定の部分と、という風に分けましょう。

でも、どうやって? 概念としては分かりますが、例えばある特定の言語で書かれたコードでは?

Phoenix Framework v1.3では、複雑になる一方のmodelに対してコンテキストが導入されました。例えばこんな風になります。

$ mix phx.gen.json Followers User users username:string

ディレクトリ構造はこのようになります。

+- lib
   +- my_app
      +- followers
      +- users
      +- web

この例はマイクロブログ風にユーザーにはフォロワーがいて、という世界観を表現しています。フォローを承認してみましょう。モデルの.コンテキストの.メソッド、という呼び出しになります。

user
|> Followers.unaccepted
|> Followers.accept

もちろんこの単純な例では、そんなのUsersにあっても全然構わないように見えますが、それでも、ある種の責任を綺麗に分離できましたね。

アンブレラプロジェクト

Elixirにはアンブレラプロジェクトという、プロジェクトが大きくなった時に、複数の子プロジェクトに分割して管理するための機能があります。

そして、Phoenix Framework v1.3は、このアンブレラプロジェクトに対応しました。

まず、mix newで親プロジェクトを作ります。この時に--umbrellaオプションを指定します。

$ mix new my_app --umbrella

するとappsconfigだけのプロジェクトができます。

my_app
+- apps
+- config
|  +- config.exs
+- mix.exs

例えばガラパゴスは主にスマートフォンアプリを開発していますが、スマートフォンアプリはAPI(アプリ向け)とWEB(管理画面)がセットになっている場合がほとんどです。

それでは、子プロジェクトを作ってみましょう。

$ cd my_app/apps
$ mix phx.new.ecto my_app_core # 共通のコア機能
$ mix phx.new.web my_app_web # 管理画面
$ mix phx.new.web my_app_api # API

するとこのように、appsの下にそれぞれ独立したプロジェクトができました。御機嫌よう世界。

my_app
+- apps
|  +- my_app_api
|  |  +- assets
|  |  +- config
|  |  +- lib
|  |  +- priv
|  |  +- test
|  |  +- mix.exs
|  +- my_app_core
|  |  +- config
|  |  +- lib
|  |  +- priv
|  |  +- test
|  |  +- mix.exs
|  +- my_app_web
|     +- (ry
+- config
+- mix.exs

例えばAPIに管理画面関連の依存関係があっても全く無駄ですし、逆もそうですし、アプリケーションがロードされた時に必要ない依存関係が色々なオーバーヘッドになっているのとかも。

でも、こうしてアンブレラプロジェクトにすることで、スッキリしました。子プロジェクトという形で、責任の範囲も明確になりました。

さいごに

コードを書いていると、これはここにあっていいのかしら? みたいなことを感じることも多々ありますが、境界を綺麗に分割できると嬉しいですね。

さて、ガラパゴスでは人類の進化に貢献したいエンジニアを大絶賛超募集しています。皆様の応募をお待ちしています。

www.glpgs.com

では、御機嫌よう。

この記事は業務の一環として業務時間を使って書きました