mmag

ハマったことメモなど

ElixirのConfigに関する議論が盛り上がっている

これ

elixirforum.com

課題意識としては、Mixプロジェクトにおけるconfigはアプリケーションが起動するときに読み込まれるけれど、その一方でそれをreleaseビルドするときはコンパイルするときに読み込まれるという違いがあり、混乱のもとになっている、というもの。よくあるのはSystem.get_env環境変数を読み込む場合で、releaseを動かす環境のものを使ってほしいのに、releaseをビルドした環境のものが使われてしまい、開発中は動いてたのにいざ本番へというところで全然動かない、ということがある。

これをどうやって解決しようか、という話で、提案されているのはconfigのファイルをreleaseの中にコピっちゃおうよ、というもの。ただしそれを行うには問題があって、一般的なMixプロジェクトでは

use Mix.Config

config :my_app, foo: :bar

import_config "#{Mix.env()}.exs"  # <- これ

ということをして動的に設定ファイルを読み込んでいる。これをやられると、releaseにコピーするべき設定ファイルを知るためには一度設定を評価しないといけない。しかもMixはreleaseでは使えない。そこで、mix.exsに新しい項目を増やして、使う設定ファイルを明示的に書いておきましょうよ、ということになっている。

# mix.exs
def project do
  [
    ...,
    config_paths: ["config/config.exs", "config/#{Mix.env()}.exs"]
  ]
end

な感じ。これなら設定ファイルを評価する前にどれをコピーすればいいかわかるし、動的にimport_configする必要がなくなるので、設定の評価時にMixも要らなくなる。またこの変更に伴って、:elixirアプリケーションにApplication.Configってのを入れるよ、ということも言われている。


これを書いている時点でコメントが90ほど伸びていて盛り上がっている。若干議論が横道っぽいとこ(runtimeに使われる設定とcompile timeに使われる設定が混在してるの気持ち悪くないか?とか。これは今もそうだし、今回の提案が取り込まれても同じ)に行っている感じもあるけど、大注目スレッドであることは間違いないので今後もウォッチしてく。

Atomic Designのあいつら

Atomic Designという、コンポーネント単位で設計してく手法というか考え方みたいなものがあるわけですが、様々な解釈があるようでみんな違うこと言ってる気がしている。ここ半年くらい仕事とか趣味プロダクトで試したり、あちこちブログ読んだりしてなんとなく自分なりの解釈ができた感じがするので言語化しておく。

atoms

buttonとかh1とか、HTMLのタグにスタイルを付けたもの、くらいの感覚。atomsとatomsを並べるための、レイアウトするためだけのコンポーネントなんかもここに入ると思ってる。これ以上分割できないものとよく言われるけど、分割できそうなものでもいいんじゃないのとか思っている。例えばボタンはatomsの代表例でよく挙げられるけど、ヘリクツを言えば押す部分とテキストに分けられる。あと、ここにCSSを当てるときはmarginを持たせない。与えられた領域いっぱいに広がるようにすると再利用性しやすい。

molecules

atomsをいくつか組み合わせてできたもの。これもmarginを持たせるべきでない。

organisms

atomとかmoleculesをいくつか組み合わせたもの。よくmoleculesとorganismsの区別で迷うけれど、名前にドメインの言葉が入ったら、または入れられるならそれはorganismsだと思ってる。atomatom組み合わせたらorganismsっぽくなっちゃった、というときは、それはmolecules1個から成るorganismsなんじゃないの、くらいの認識。

templates

organismsをレイアウトするだけの存在。レスポンシブな動きはなるべくここで全部吸収する。画面幅が変わったときに配置を変えるだけでカバーできないような変化は、画面幅ごとにorganismsをつくってtemplatesが出し分ける。どうしても無理がある感じになったらpagesが多少この辺りを担う。organisms以下には絶対にmediaクエリを書きたくない。

pages

画面とかURLに対応する。templatesとカブっちゃうことがあるので、templatesいらないならそれもよし。

まとめ

ただ結局、あんまりしっかりルールみたいなの決めると例外ができたときに死んじゃうので、ゆるふわでやるのがよい。

GraphQLやってる

前に書いた社内向けの日報Webサービスで、RESTful(RESTish?)なAPIからGraphQLなAPIに書き直しをしてる。

サーバ側

そもそもそんなに大きなアプリケーションではないので、雑にhas manyやらassociationsを辿っていく程度のものはすぐにできた。認証はAuthorizationヘッダにJWTをつけてる。ちょっと前にブログ書いたはずと思ったら3ヶ月近く前で震えた。

joe-noh.hatenablog.com

Root Fieldとしてはusernippoesを用意。userはユーザ名を引数に取る。nippoesは日付と順序を受け付けて日報のリストを返す。こんなクエリをイメージしていた。

query ($name: String!, $date: String!) {
  user (name: $name) {
    nippoes (date: $date, orderBy: {field: DATE, direction: ASC}) {
      id
      date
      content
      isMine
    }
  }
}

APIはElixir/Phoenixで書いていたので、absintheabsinthe_plugabsinthe_ectoを使って実装した。ただ、ある程度世の中のスタンダードを意識したほうがいいんじゃなかろうかと不安になり、absinthe_relayを使って書き直した。

github.com

フロント側

次はフロント側ということで、Vue.jsからどうやってクエリ投げようか、というところ。最悪ナイーブに文字列組み立ててPOSTする手もあるけれどせっかくRelay Compliant気味になっているはずなのでライブラリを探す。vue-relayを発見。

github.com

どうやらGraphQLクライアントはRelayとApolloという2大派閥があるようで、比較記事を書かれがちな様子が伺えた。当然のようにvue-apolloも発見。

github.com

とりあえずvue-relayをnpm i -Sして使ってみるがよくわからない。新しい概念に触れているのだからよくわからなくて当然と思いながら、Vuexとの食い合わせとか要らんこと考え始めてウウーンとなる。ReactとかFluxアーキテクチャとかも、話としては理解できるけど書いてみるとよくわからんということが何度かあって、頭が悪いかfacebookと気が合わないかどっちかだな...という気持ちになった。

じゃあvue-apolloどうなの、といろいろ調べていたら

github.com

のissueで「クライアントサイドの状態管理なんてApolloにやってもらえばええやろ」みたいなことが書かれていて、あーそーゆーことね完全に理解した。GraphQLのAPIを楽に叩けるものくらいに捉えていたけど、どうやらもっと大きな存在であるらしい。例えばこれまでよくやっていた「API叩いてその結果をStoreに入れる」のような流れは全部Apolloに任せてキャッシュしてもらって、Vuexからバシバシ仕事を奪っていくべきなのでした。実際Vuexの仕事はほとんど無くなったし、いま見るとvue-relayも使えそうな気がしてくるので、この辺の認識が大切そう。

このあたりで、クライアントにApolloを使うんであればRelay Compliantが邪魔になるなーということに気づく。せっかく一度書き直したのに戻すのかー思ったところで、なんでクライアントで使うライブラリにサーバの実装が左右されなきゃならんのだなんか間違ってねーかコレと考えた。これまでの感覚だと、クライアントの事情は考えず、サーバはリソース設計として適切と思われるように実装されるべきと自分は捉えていた。あくまでそれは理想で、画面の都合でレスポンスの構造が変わってRESTってなんだっけとなるのはあるあるだとしても、まずはクライアントのこと、とくにライブラリなに使うかなんて考えるのおかしくないですか〜という疑問。自分で考えててもよくわからず、たまたま社内の有識者 id:shiro-16 とランチに行く機会があり雑談したら同じようなことを思っていたようで、あーここは意識を変えるタイミングなんだなと思い納得。あまり汎用的なものにしようとはせず、特定のクライアントのために作る気持ちでよさそう。

サーバ側(再)

edgesとかnodeとかRelayの諸々を消していく。mutationsに関して、absinthe_relayのinputoutputも使うのをやめてしまったけど、ここは残してもよかったと思っている。たぶんあとで復活する。Relay Input Object Mutations Specificationだけ読んでも何が嬉しいのかよくわからなかったけど、引数たくさん書くのダルいよね、という記事を見てまあ確かに、と思った。

dev-blog.apollodata.com

まとめ

ということで最終的にApolloに乗っかる形になった。RESTが教えてくれた感覚とか、クライアントサイドの状態管理の方法とか、これまで考えてきたことを一回捨てることが一番大変なんじゃないのという印象。実装はそれほどしんどくないなと今のところ思っていて、ライブラリやらツールやらエコシステムが支えてくれる。

次は守備を考える。

dev-blog.apollodata.com