余白

https://blog.lacolaco.net/ に移転しました

GraphQLのスキーマについて今日考えてたこと

今日はGraphQLのクエリのスキーマを考えてた

いろんなデータが関連していて、原理的にはどんな入れ子の順番でも解決はできるんだけど、基本的にはデータの寿命が短い順に入れ子になっていくのが良さそうな気がする。

user { organizations {}  }

はユーザーの所属する組織はそんな頻繁に変わるものじゃないから、たいてい userのほうが organizationより更新頻度が高い。

この場合userをクエリしたときのレスポンスをキャッシュできるかどうかはuserがボトルネックになる==ルートレベルなので、キャッシュ可能かどうかがわかりやすい気がする。なんというか、organizationsはuserのフィールドだってのはしっくりくる。

逆の関係の場合

organization { users {} }

は組織に紐付くユーザーは増えたり減ったりするから、たいていusersのほうがorganizationより更新頻度が高くなりそう。 このクエリは本質的にはorganizationを要求しているはずなんだけど、キャッシュはorganizationが変わってなくてもusersが変わるたびに捨てなきゃいけないので、あんまり頭良くない気がする。usersはorganizationのフィールドとはあんまり思えない感じ。

今は直感というか、嗅覚みたいなところでこれ考えてるんだけど、この辺の設計論を理論立てて書いてる本とかあったら誰か教えてください。

「ファスト&スロー(上)」という本がすごく良かったので紹介したい

これは読書感想文です。ダニエル・カーネマンという心理学者が書いた「ファスト&スロー」という本の上巻を読み終わったので、学びだなーとおもったところとかを紹介したい。

なんで読んだのか

ダニエル・カーネマンはノーベル経済学賞を取った心理学者です。 行動経済学みたいな分野に最近興味があり、そのへんを学ぶ上でまず読んだほうが良さそうだなと思って読んでみた感じ。 ちなみに下巻はまだ読み始めたばかり。

印象深かった部分

Kindleで読みながらちょこちょこマーカーいれてたところをシェアします。 ちなみにKindleでいれたマーカーは https://read.amazon.co.jp/kp/notebookにアクセスするとPCから全部見られるので読書感想文に便利。

"学校補助金の増額案に対する賛成票は、投票所が学校の場合、そうでない場合よりも有意に多かった"

これは「プライミング効果」について解説される中での事例で、アメリカのアリゾナ州の選挙で実際に起きたことらしい。 「プライミング効果」は先行して受けた刺激(プライム)によって後の思考・行動・意識が影響される効果のことをいう。 何か重要なことを判断するときには、その判断に影響するようなプライムに触れていないかどうかを振り返ろうと思った。

"人物描写をするときに、その人の特徴を示す言葉の並び順は適当に決められることが多いが、実際には順番は重要である。ハロー効果によって最初の印象の重みが増し、あとのほうの情報はほとんど無視されることさえある"

何か列挙するときには順番に気をつけて、ハロー効果を利用する、というよりはハロー効果によって損しないように気をつけようと思った。 あと、ハロー効果に受ける影響を小さくなるようにしたい。

...議題について討論する前に、出席者全員に前もって自分の意見を簡単にまとめて提出してもらうことだ。こうしておけば、グループ内の知識や意見の多様性を活かすことができる。通常の自由討論では、最初に発言する人や強く主張する人の意見に重みがかかりすぎ、後から発言する人は追随することになり...

これは大事やな、という気がした。仕事にも活かせそうな気がする。

"ストーリーの出来で重要なのは情報の整合性であって、完全性ではない。むしろ手元に少ししか情報がないときのほうが、うまいことすべての情報を筋書き通りにはめ込むことが..."

人間は見たものがすべてで、その断片的な情報を経験とステレオタイプで繋いできれいなストーリーを作ることで納得してしまうという話。

プログラミングしてても似たようなことがある気がして、よくわからんエラーの原因を探るときにどうしても「何か決定的な原因があるはず」と思うところから始めている気がする。 そのエラーが起きそうなストーリーを組み立てて、それを辿っていってバグを見つける作業は多くの場合うまくいくのだけど、たまにうまくいかない。そういうときは複数の並行する処理による副作用だったり、ランダム性の高い複雑な連続した確率の低い現象だったりする。

私たちは、人生で遭遇する大半のことはランダムであるという事実を、どうしても認めたくないのである

コンピュータ上は一見すべてに因果関係があり整合した世界にも見えるけども、必ずともそう言いきれないなということもあり、因果関係に縛られず目の前に起きていることをちゃんと受け入れようと思う。バグは解明するものじゃなく解決するものだ。

"自分の選択について、その根拠を多く挙げさせるときのほうが、少ないときより、選択の正しさに自信が持てなくなる"

これは「利用可能性バイアス」についての項で出てくる一節。 たくさんのことを思い出すとき、思い出しやすいことは前半にすぐ出てくるが、だんだん思い出しにくくなってくる(「利用可能性」が下がる)。 そうすると脳はそのことを思い出すことは難しい==あまり存在しないのではないか、と錯覚し始める。

「自己主張をしなかった例を十二個書き出してください」と言われて思い出した人と、「六個書き出してください」と言われた人では、その後の「自分は自己主張が強いと思うか」という質問への傾向がまるで違う、という。 逆の例では、改善点を多く挙げるように指示したクラスほど、講座に高い評価をつける、という。だんだん改善点の利用可能性が下がることで、「改善点あんまりないな」と錯覚し始める。

アンケートの作り方というか、質問の構成で回答者の判断に影響できるのは怖いなと思った。

"このような「結果バイアス(outcome bias)」が入り込むと、意思決定を適切に評価すること、すなわち決定を下した時点でそれは妥当だったのか、という視点から評価することはほとんど不可能になって..."

上巻の終盤はこの「結果バイアス」に関する話だった。一度結果を知ってしまうと、その結果がなかったとしたら、という視点で思考することは困難になるということ。 関連して覚えておきたい文章がいくつもあった。

私たちは、決定自体はよかったのに実行がまずかった場合でも、意思決定者を非難しがちである。また、すぐれた決定が後から見れば当たり前のように見える場合には、意思決定者をほとんど賞賛しない。ここには明らかに、結果バイアスが存在...

.

標準的な業務手続きに従ってさえいれば後からとやかく言われる心配はない、というわけで、自分の決定が後知恵で詮索されやすいと承知している意思決定者は、お役所的なやり方に走りがちになり、リスクをとることをひどくいやがるように...

.

たまたま幸運に恵まれたリーダーは、大きすぎるリスクをとったことに対して罰を受けずに終わる。それどころか、成功を探り当てる嗅覚と先見の明の持ち主だと評価される。その一方で、彼らに懐疑的だった思慮分別のある人たちは、後知恵からすると、凡庸で臆病で弱気ということに...

組織で何かしら問題が起きたときにその犯人探しが執拗に行われ、本質的な解決が後回しになりがちになってしまうようなことは世間ではよくあることだけど、これは「このトラブルを引き起こす決定が何処かに存在したはず」というストーリーを求めているんじゃないかと思う。 「たまたま運が悪かっただけ」ということを受け入れられないのは、年齢を重ねるなかで、自分の人生がストーリーになってしまった人ほど強くなるんじゃないか。 「自身の決断の結果として今の自分がある」という自信が強いほどそういう傾向になるんじゃないかという気がした。

私たちは、人生で遭遇する大半のことはランダムであるという事実を、どうしても認めたくないのである

.

必要なのは、不確実性の存在を認め、重大に受け止めることである

うまくいったときは幸運だったなと思い、うまくいかなかったときは不運だったなと思い、成功や失敗の結果だけで人を判断せず、過信しないように気をつけようと思った。

感想

紹介した引用以外にもたくさんマーカー引いたところもあるんだけど、とにかく示唆に富んでいて、読んでよかった。 多かれ少なかれ、規模の大小はあれど毎日人は何かしら意思決定の連続で生きているわけで、すべての判断に対してバイアスを受けないように慎重に取り組むのはとても心が保たないと思うから、ある程度はどうしようもなく自分が人間であることを受け入れて諦めつつ、 重要な意思決定の場面では、主観・直感はまったく信用出来ないぞ、というのを心に刻んでいきたい。

人間に意思決定はまだ早いし、はやく人間が意思決定しなくてもAIがディープラーニングとかいうやつで全部決めてくれる世界になってほしい。

MANABIYA.techでAngularとWebについて発表したので反省する

3/24に、MANABIYAというカンファレンスイベントで登壇してきました。

manabiya.tech

当日のスライドはこちら。発表タイトルは「The Angular World」で、Angularの現在と未来、あとWebの世界との関わりについて話そうと思ってました。 内容はだいたいスライドのとおりなので、読んでもらえればよいかと思います。時間がない人は最後のConclusionから先だけ読んでください。

イベント自体はとても良かったと思う(運営おつかれさまでした)んだけど、自分の発表については反省点もあるので、公開KPTします。

Keep

言いたいことは言えた感じする

結局言いたかったのは

  • SPAがコモディティ化した今、WebフロントエンドはGUIアプリケーション開発だってことをちゃんと認識しよう
  • ユーザーが最初に出会うインターフェースをより良いものにする責任と使命をもってフロントエンドエンジニアやっていこう
  • そうやってプロダクトのことを考えるために、そうでないWebの泥臭い部分をアウトソーシングする先が、Angularのようなフレームワークという物の存在意義

っていう話。いいビューはいい状態から生まれる、状態管理こそがUXの肝っていう感じ。

スライドはそこそこまとまりがあるいい感じになった気はする

スライドはけっこう早めに作って練ってたので、仕上がりは悪くない感じだと思う。

及川さんの基調講演の裏番組にしては人が来てくれてありがたかった

もはやKeepではないんだけど、いちおう座席は埋まっていて安心しました。でも僕も及川さんの基調講演聞きに行きたかったよ。

Problem

タイトルが悪い

2ヶ月くらいまえにテーマだけ先に決めなきゃいけなくて、その時のふわふわした感じでなんとなくつけたタイトルだったけど、説明文読まないと何話すか全然わからんタイトルにしたのはよくなかった。何が「The Angular World」じゃ。

久々にリモコンで発表したら機材トラブルでgdった

15分放置したらMacbookがスリープになることを忘れており、スマホでスライド操作してたら2、3回スクリーン暗転しちゃって、見に来てくれてた方々申し訳ありませんでした。次から気をつけます。

時間配分がダメ

これは言い訳なんだけど、45分だと思ってた。

Angular Platformのくだり、ちょっと長い

AngularをFramework / Platform / Ecosystemの3面から見ていくのは今回はじめてだったんだけど、ちょっと間延びした感じがする。 Platformはもうちょっと省いて、Developer Toolsに絞ってもよかったかも。 むしろEcosystem側にIonicとかNativeScriptとかIgniteUIとかNgRxとか、サードパーティ系の広がりを寄せてみたほうが面白かったかも。

Try

デモ入れたいね

2018年のAngularのところで、ngIvyとAngular ElementsとABC Projectと紹介したんだけど、どれもエクスペリメンタルでデモするのがちょっと難しかったし時間配分もアレだった。 デモも入れていきたいですね

kazuponさんの発表のVue.jsコアチームの名前出していく感じOSSっぽくて真似したい

このモジュールの面倒見てるのは誰々で〜っていう話、OSSを当たり前にしないで、ちゃんと誰かの貢献によって成り立っているってのを再確認させてくれて個人的にとてもよかったので、今度の発表ではAngularもコアチームのメンバーとかよく活動してるコントリビューターとか名前だして紹介してみたい。


まとめ

発表としては今回はギリギリ赤点回避、くらいの自己評価なので、2018年もうちょっと気を引き締めてやっていこうと思う。 ちょと油断してました。自戒!

クロスセッションは楽しかったので、やっぱひとりで偉そうに話するよりディスカッションしたいですね。

ミートアップの参加費をKyashで集めてみた話

「えーマジ現金!?キモーイ」 「現金が許されるのは諭吉までだよねー」 「キャハハハハハ」

―2020年、マックの女子高生


昨日開催した ng-sake #11 にて、実験的にKyashを使って参加費を集めてみました。

ng-sake.connpass.com

結果

自分を除いた参加者18人中、8人がKyashで先払いしてくれました。ご協力いただきありがとうございました!

現金の場合の受付処理は、

  1. connpassの名前を聞く
  2. リストを確認する
  3. 参加費を受け取る
    • 「財布を取り出す」→「お金を取り出す」→「金額を確かめる」→(「必要ならお釣りを返す」)→「受け取る」
  4. done

なんですが、一番時間を取るのが3ですね。人間の体は財布からお金を取り出すために進化したわけではない。

一方Kyashで払ってくれてた場合は、

  1. connpassの名前を聞く
  2. リストを確認する
  3. Kyashの送金履歴を見せてもらう
  4. done

です。僕が「この人から送金あったな」と覚えてれば3番はスキップされます。 あきらかにボトルネックだった現金の受領ステップがなくなっていてハッピーでした。

次回もぜひKyashで集金したいです。

課題

Kyashの名前とconnpassの名前がひも付きにくい

知ってる人だったらわかったけど初対面の人でconnpassのハンドルネームとKyashの名前が違うと混乱がありました。 送金のメッセージにconnpass上のIDを書いてもらうように運用で回避できそう。

受付が交代できなかった

自分のKyashの画面と照らし合わせながらやったので、受付が交代できませんでした。 はじめてだったので送金した画面だけで大丈夫なのか不安で、自分の受領履歴と突き合わせていたのが原因。

特定の請求リンクに紐付く履歴をリストとしてエクスポートしたい気持ちと、送金画面だけで信用すればよいのでは、という気持ち。connpassの「受付票」みたいな、フォーマットされたいわばレシートみたいなのがバシッとアプリの画面で出てくると安心っぽい。今の送金履歴の画面は名前と金額は見やすいけど品目(最初のメッセージがそういう役割になるけど、ホントは請求の品目はちゃんと設定したい)と日時も見やすい表示が欲しい。なんなら画面の偽造できないようにサーバーに問い合わせして検証できるバーコードがあってもいいと思う。8人だったからよかったけどもっと増えるともっとKyash側を信用出来ないとスケールしなさそう。


小規模なミートアップを主催している方々、Kyash良いですよ。現金集めるのやめていきましょう!

ngIvyメモ

lacolaco.hatenablog.com

ngIvyのSeparate Compilationについてのプロポーザルを読み、実装中のRenderer3のコードを読み、ベータ版のcompilerが生成するコードを読み、毎晩毎晩考えを巡らせた結果、ngIvyについてある程度体系的な理解が得られたという錯覚があるので、ここで言語化しておきます。 単なるメモなので、何か伝えたいとかではないです。ng-sake #11 - connpass の話のネタにはなるかもしれません。

また、予め断っておきますが、この内容はAngularの内部処理を理解している上級者向けです。これはブラックボックスの内側です。 これがわからないからといってAngularが使えないわけではないですし、まったく自信を失わなくてよいです。 知らないほうが素直にライブラリを使える可能性のほうが高いです。

いままでのAoTコンパイル

f:id:lacolaco:20180310123120p:plain

v5までのAoTコンパイルは、以下の流れで greeting.component.tsコンパイルします。

  1. Analysis phase: AoTコンパイルのエントリポイントとなるNgModuleから再帰的にすべての参照をたどり、以下の操作をおこなう。
    1. それが.tsファイルである場合は、そのファイルからexportされているすべてのシンボルを*.metadata.jsonに記録し、関連付ける
    2. それが.jsファイルである場合は、隣接する*.metadata.jsonを関連付ける
  2. Codegen phase: 1でコンパイルに関連付けられたすべての.metadata.jsonについて、以下の操作をおこなう
    1. .metadata.json@Component@NgModuleなどのAngularデコレータが存在する場合は、それぞれについてNgFactoryのTypeScriptコードを生成する
    2. 生成されたTypeScriptコードをコンパイルし、.ngfactory.jsを生成するか、型チェックが通らない場合はエラーを出力する
  3. Compilation phase: 通常のtscの挙動と同じようにすべての.tsファイルをコンパイルする

すべての操作が正しく完了すると、AoTコンパイルが成功します。 結果として、GreetingComponentに対して出力されるファイルは次の3つです。

greeting.component.js

greeting.component.tsJavaScriptコンパイルしたものです。 コンパイル過程で、デコレータの情報は静的フィールドに変換されることがあります。 ( annotationsAs オプション )

greeting.component.ngfactory.js

greeting.component.jsからexportされるGreetingComponentを、Angularがコンポーネントとして利用するために機械生成されたコードで、 GreetingComponentNgFactoryクラスをexportします。 GreetingComponentNgFactoryクラスの主な役割は次の2つです。

  • GreetingComponentインスタンス生成: コンストラクタで要求する引数の解決(Dependency Injectionの実行)
  • GreetingComponentのビュー生成: テンプレートから生成されるビュー組み立て関数の提供

greeting.component.metadata.json

greeting.component.tsを静的解析した結果得られたメタデータです。公式ドキュメントではある種の抽象構文木(AST)と見ることもできると書かれています。 メタデータはNgFactoryの生成だけでなく、language-serviceによるテンプレートエラー検知にも使われています。

メタデータ中に保存される情報は、TypeScriptの型情報 + Angularデコレータ中の値情報 です。前者だけであれば.d.tsファイルで事足りますが、NgFactoryの生成には@Componentなどのデコレータに渡される実際の値情報が必要になるため、ngcはこれを*.metadata.jsonという形で記録します。

で、ngIvyって何?

ここからが本題で、上述のコンパイル処理はngIvyにより次のように変わります。

f:id:lacolaco:20180311131044p:plain

ngIvy方式のAoTコンパイルは、以下の流れで greeting.component.tsコンパイルします。

  1. コンパイル対象の.tsファイルについて、以下の操作をおこなう
    1. Angularデコレータが存在する場合は、それぞれのデコレータに対応したAngular定義をTypeScriptコード中に生成し、対応するメタデータ.metadata.jsonに記録する
    2. TypeScriptコードをコンパイルし、.jsを生成するか、型チェックが通らない場合はエラーを出力する

それぞれのデコレータに対応する定義とメタデータについては DESIGN DOC (Ivy): Separate Compilationを読む - らこらこブログ を参照してください。

手書き定義と脱ngc

ngIvyのコンパイル過程において、「Angularデコレータが存在する場合は、それぞれのデコレータに対応したAngular定義をTypeScriptコード中に生成」と書きましたが、 裏を返せば「Angularデコレータが存在しなければただTypeScriptをコンパイルするだけ」ということです。

ngIvyでは、本来はAngularデコレータから生成されるngComponentDefngInjectorRefのような定義を事前にTypeScript中に記述しておくと、ngcにおけるコード生成過程をスキップできます。 機械生成された定義と手書きの定義は区別されないため、この場合はngcではなくtscだけでコンパイル可能です。

f:id:lacolaco:20180311131157p:plain

手書きでなくとも、例えばBabelや他のシステムによってソースコードが変換されたとしても、最終的にngIvyの期待する出力があれば、AngularのAoTコンパイル結果として受け入れられます。 プラグインさえ書けばJSXからAngularコンポーネント定義を生成することも不可能ではないでしょう。

このポイントは、

  • ngIvyにより @Component などのAngularデコレータは「Angular定義を生成する手段のひとつ」となる。
  • サードパーティのツールやマニュアルでの記述により、Angularデコレータを排除したピュアなJavaScriptとしてコンポーネントを作成できるようになる。

実際にngIvyによって、tscrollupだけで動作するアプリケーションのサンプルはこちらです。

この例ではHelloWorldコンポーネント@Componentデコレータを持たず、ngComponentDefを手書きしているので、コンパイルtscだけで完了します。

分離コンパイル

ngIvyでは従来のAoTコンパイルの非効率性を解決することに重きをおいています。ここでいう非効率性とは、

  • NgFactoryの生成はアプリケーションコンパイル時にしかおこなえない(npmライブラリはNgFactoryを含まない.jsファイルとNgFactoryの元になる.metadata.jsonを提供する必要がある)
  • NgModuleのスコープ内で何かしらの変更があった場合には、そのNgModuleごと再コンパイルしてmetadata.jsonやNgFactoryを再生成する必要がある

重要なポイントは、このプロポーザルにおいてはこれらを解決するために、ngIvyによるAoTコンパイルは単純にデコレータをもとにコードを変換する仕組みになっていて、アプリケーション自体の整合性を担保する役割は失っていることです。

Ivyにおいては、ランタイムはこれまではコンパイラによって事前計算されたもののほとんどを、実行時に処理することで分離コンパイルを可能にする方法で作られています。

とあるように、アプリケーションが実行可能かどうかのチェックは事前計算ではなくJITでの処理に切り分けられると予想されます。 この場合、Language Serviceとどのように協調するのかは今のところ不明です。

今後

上記仕様はまだ実装されていない(定義の生成部分は見て取れるけど、まだ.metadata.jsonの生成が古いように見える)ので、分離コンパイルが最終的にどういう形になるのかはまだ観察が必要です。とはいえ、現状ではngIvyのターゲットはライブラリとアプリケーションだけでパッケージは対象外なので、実質的に.metadata.jsonは不要といえば不要なのかもしれません。