ElixirのConfigに関する議論が盛り上がっている
これ
課題意識としては、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だと思ってる。atomとatom組み合わせたら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ヶ月近く前で震えた。
Root Fieldとしてはuser
とnippoes
を用意。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で書いていたので、absinthe、absinthe_plug、absinthe_ectoを使って実装した。ただ、ある程度世の中のスタンダードを意識したほうがいいんじゃなかろうかと不安になり、absinthe_relayを使って書き直した。
フロント側
次はフロント側ということで、Vue.jsからどうやってクエリ投げようか、というところ。最悪ナイーブに文字列組み立ててPOSTする手もあるけれどせっかくRelay Compliant気味になっているはずなのでライブラリを探す。vue-relayを発見。
どうやらGraphQLクライアントはRelayとApolloという2大派閥があるようで、比較記事を書かれがちな様子が伺えた。当然のようにvue-apolloも発見。
とりあえずvue-relayをnpm i -S
して使ってみるがよくわからない。新しい概念に触れているのだからよくわからなくて当然と思いながら、Vuexとの食い合わせとか要らんこと考え始めてウウーンとなる。ReactとかFluxアーキテクチャとかも、話としては理解できるけど書いてみるとよくわからんということが何度かあって、頭が悪いかfacebookと気が合わないかどっちかだな...という気持ちになった。
じゃあvue-apolloどうなの、といろいろ調べていたら
のissueで「クライアントサイドの状態管理なんてApolloにやってもらえばええやろ」みたいなことが書かれていて、あーそーゆーことね完全に理解した。GraphQLのAPIを楽に叩けるものくらいに捉えていたけど、どうやらもっと大きな存在であるらしい。例えばこれまでよくやっていた「API叩いてその結果をStoreに入れる」のような流れは全部Apolloに任せてキャッシュしてもらって、Vuexからバシバシ仕事を奪っていくべきなのでした。実際Vuexの仕事はほとんど無くなったし、いま見るとvue-relayも使えそうな気がしてくるので、この辺の認識が大切そう。
このあたりで、クライアントにApolloを使うんであればRelay Compliantが邪魔になるなーということに気づく。せっかく一度書き直したのに戻すのかー思ったところで、なんでクライアントで使うライブラリにサーバの実装が左右されなきゃならんのだなんか間違ってねーかコレと考えた。これまでの感覚だと、クライアントの事情は考えず、サーバはリソース設計として適切と思われるように実装されるべきと自分は捉えていた。あくまでそれは理想で、画面の都合でレスポンスの構造が変わってRESTってなんだっけとなるのはあるあるだとしても、まずはクライアントのこと、とくにライブラリなに使うかなんて考えるのおかしくないですか〜という疑問。自分で考えててもよくわからず、たまたま社内の有識者 id:shiro-16 とランチに行く機会があり雑談したら同じようなことを思っていたようで、あーここは意識を変えるタイミングなんだなと思い納得。あまり汎用的なものにしようとはせず、特定のクライアントのために作る気持ちでよさそう。
サーバ側(再)
edges
とかnode
とかRelayの諸々を消していく。mutationsに関して、absinthe_relayのinput
やoutput
も使うのをやめてしまったけど、ここは残してもよかったと思っている。たぶんあとで復活する。Relay Input Object Mutations Specificationだけ読んでも何が嬉しいのかよくわからなかったけど、引数たくさん書くのダルいよね、という記事を見てまあ確かに、と思った。
まとめ
ということで最終的にApolloに乗っかる形になった。RESTが教えてくれた感覚とか、クライアントサイドの状態管理の方法とか、これまで考えてきたことを一回捨てることが一番大変なんじゃないのという印象。実装はそれほどしんどくないなと今のところ思っていて、ライブラリやらツールやらエコシステムが支えてくれる。
次は守備を考える。