「エンジニアリング組織論への招待」を読んだ
エンジニアリング組織論への招待 ~不確実性に向き合う思考と組織のリファクタリング
- 作者: 広木大地
- 出版社/メーカー: 技術評論社
- 発売日: 2018/02/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
1章の「get wild and tough」でいきなり引き込まれ、2章で自分がメンタリングされている気分になっていた。読んでるだけで気分がよくなってきたので、自分が今まず欲しているのはこれなのかもしれない。これらを序盤に持ってくるあたり、「まずは自分のスタンスを変え、個々人間の情報の非対称性をなくしていくことが重要だ」と言われているように感じていた。3~4章ではチームビルディングやアジャイル・そしてそこから派生したプロジェクトのイテレーション手法について触れているが、どれもやはり「個人の情報の非対称性が少ない」というのが前提に立った話のように僕は捉えた。裏を返すと、情報の非対称性に対処するという基本的な部分の努力が払われないままリーンやアジャイル、スクラムといった手法を取り入れても、ただ恰好だけ真似しただけで早晩破綻するだろう、とも受け取れる。事実、自分たちのチームのスクラムの体制は半分くらい崩壊しかかっている。導入した当時は「今必要だからスクラムを導入するしかない」と思っていたつもりだったが、今振り返ると、その前にやることがあっただろうと思える。
結構注意しなくては、と思ったのは、4章後半~5章にかけて「適切に権限移譲せよ」と書いてあったのだが、これを微妙な形で適用して結局「プリンシパル・エージェント関係」に陥らないかというのが心配になった。それを抑制するために、まずは個々人間で情報の非対称性を減らし、メンバーが増えてきたらチーム間の合意のためのプロトコルを作って、という形を適用していくのがいいのではと思うが、恥ずかしながら自分にはそうした世界を実感したことはない。
とりあえずこの本は目から鱗が落ちまくってるので、読み終わる前からすでに事業部の何人かにパワープッシュしている。「不確実性を減らす」というエンジニアリングの本質ができる環境を作りたい。
「GraphQL over WebSocket Protocol」という仕組みが提案されてるらしい
というのをたまたま調べものをしてる時に見つけた。 github.com
(以下このプロトコルは GoWP
と書きます)
GoWPだとどのクエリでもWebSocket通信上でできるように、ということが想定されているが、何より主眼に置かれてるのはsubscription
への対応ではないだろうか。
コネクション確立からクエリの登録までのプロトコルが明文化されているので、そうした足回りは対応ライブラリがあれば任せられそうというのがいいな、と。
例えば、golangでのGoWP対応ライブラリは以下のようなのがある。
これを見つけてから、
subscription
でストリーミングしたいデータはHTTP通信で外から登録チャンネル毎に受け渡せる- 部外者に見せたくないデータが誤って流れるのを防ぐために、ユーザを指定できるようにしてもいいかも
- アプリケーション上でのIDはJWTで受け渡してAuthenticateのタイミングでライブラリ上でコネクションIDとマッピング
なんてことができるプロキシサーバがあるといいかも。。。と妄想が一気に膨らんだところだった。
ただ、恐らくまだGraphiQLが対応してないので、今までと同じような開発体制が組めないというのはデメリットとしてありそう。
あと、ユーザ指定して任意のメッセージをサーバから送りたい、というための仕組みとしては kuiperbeltが既にあるので、そもそもserver pushの土管が用意できればいいだけなのにそこまでGraphQL使わないといけないのかとか、色々考えることはある。
GraphQLのMutationのビジネスロジックのエラーはどうハンドリングすればいいのか
最近調査していた内容のメモ。
GraphQLのJSONレスポンスは data
と errors
の2つのキーに内容が大別される。
基本的に、期待するレスポンスが返せないときは errors
にエラー内容が入るというのがGraphQLでやろうとしていることだが、特にMutationにおけるビジネスロジックのエラーはどう記述すればいいだろうか。
恐らくFacebook的には「ダメです!」とエラーダイアログを表示させて終了なのかもしれないが、世の中のサービスが全部それに倣っているということはなく、エラーとなった要素をクライアント側で特定して赤くしたりエラー文言を添えたりしたい、なんてケースはよくある。自分の担当しているサービスもそんな感じだ。
ひとまずRelayのドキュメントを開いてみる→ Mutations · Relay
ざっくりと「レスポンスには(追加・削除含め)変更のあったTypeのオブジェクトを返せ」という風に僕は読んでいる。エラーについては特に記述はなく、 GraphQLのレスポンスとしての errors
に全て委ねているようだ。
RelayだけがGraphQLのプロトコルではないので(強力ではあるが)、他にないかと自分が軽く調べてみた限り、大きく2つの方法があるらしい。
1. errors
のデータ構造を拡張する
にその一例がある。確かに、という気持ちはあるが、今自分の使っているPerl版GraphQLライブラリはパラメータがかなり厳密に定められているので、そこに手を入れるとなるとモンキーパッチが必須になる。本家にpr送っても通るイメージが湧かない。パス。
だと、ライブラリのエラーオブジェクト自体を差し替えるというアイディアもある。が、これもPerl版GraphQLライブラリだと errors
に入れられるのは GraphQL::Error
オブジェクトが要素となる配列しか認められてないので、上記と同様のコメントになる。
2. data
側のレスポンスの型としてビジネスロジックでのエラーを返せるようにする
結論が出ないままcloseされていて悲しみしか感じない。が、このissueを参照する形で
Rust版GraphQLライブラリでのやりとりを見つけた。 data.<mutation>.errors
なら自分で専用の型を作ればいいだけなので、僕が見てきた方法の中ではこれが一番穏当で現実的なプランに見える。
もうちょっと調べてみたら、Ruby版GraphQLライブラリのドキュメントでも同様の内容があった→GraphQL - Mutations
が、これだと独自のレスポンス形式になるので、この取り決めがサービス内全体で適用できればいいが、Relayからはかなり逸脱しているようにも見える。その点の注意は必要そうだ。
まとめ
現時点だと、自分の担当サービスもビジネスロジックのエラーは data.<mutation>.errors
を入れる方向で進めようとしている。Relayを踏襲するかどうかは実は検討中。
Perl版GraphQLライブラリにおけるresolverの定義方法(修正版)
これについて、自分がライブラリの実装方法について大きな誤解をしていたのでここに訂正させていただきます。
開発環境にGraphiQLを導入しようとしてinspectがうまくいかず、
原因の調査していたところ、どうやらresolverの定義方法が想定と違っていたのがわかりました。
Perl版GraphQLライブラリの場合、GraphQL::Execution::executeの引数に一次請けとしてのresolverを入れておく必要があり、この中でどのfieldなのかをまず解決する必要がありました。
ということで、以前提示したサンプルは以下のように修正されます。
gistc9aa7a6db938d4f0ad9abae4e25836a5
この組み方でGraphiQLが正常に動作することは確認しています。resolverを特定するために $info
の値を解析する必要があるというところでまだ改善の余地はありそうですが、変な注入の方法よりはずっとよさそう。
今年買って読んだ(途中も含む)本
amazonの購入履歴のうち、書籍の購入履歴の一部を抜粋。
仕事に直接絡むところだとこんな感じ
- 作者: ヴァーン・ヴァーノン
- 出版社/メーカー: 翔泳社
- 発売日: 2015/03/19
- メディア: Kindle版
- この商品を含むブログ (2件) を見る
- 作者: ダグ・ローゼンバーグ,マット・ステファン
- 出版社/メーカー: 翔泳社
- 発売日: 2016/01/28
- メディア: Kindle版
- この商品を含むブログ (1件) を見る
現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法
- 作者: 増田亨
- 出版社/メーカー: 技術評論社
- 発売日: 2017/07/05
- メディア: Kindle版
- この商品を含むブログ (2件) を見る
この辺の顛末は
にある通り。
アジャイル開発とスクラム 顧客・技術・経営をつなぐ協調的ソフトウェア開発マネジメント
- 作者: 平鍋健児,野中郁次郎
- 出版社/メーカー: 翔泳社
- 発売日: 2013/06/20
- メディア: Kindle版
- この商品を含むブログを見る
9月末くらいに買ったらしい。チームの開発フローをもう少し整備したくて、スクラムの本を読んで徐々に導入を進めている。
開発フローについては未だに悩みが尽きない。
- 作者: 中井悦司
- 出版社/メーカー: 技術評論社
- 発売日: 2015/10/17
- メディア: Kindle版
- この商品を含むブログを見る
最近BIもできるエンジニアと話すことが多く、今までのスキル(とその延長)だけで今後も生きていこうとすると自分の場合は先が危ういなと思い始めている。
個人的な興味だと
- 作者: DaveThomas
- 出版社/メーカー: オーム社
- 発売日: 2017/07/14
- メディア: Kindle版
- この商品を含むブログを見る
- 作者: 長澤太郎
- 出版社/メーカー: リックテレコム
- 発売日: 2017/03/21
- メディア: Kindle版
- この商品を含むブログを見る
扱える言語の幅を増やしたいと思って読むだけ読んだ。
Kotlinについては実際少し触ってみて、better javaっぽさがよかった。
今度ElixirでDDDを使った設計を考えてみたいという野望もある。
ただ、上記の機械学習のことも考えると、直近はPythonの方がいいのではという思いもある。
難しいことはわかりませんが、お金の増やし方を教えてください!
- 作者: 山崎元,大橋弘祐
- 出版社/メーカー: 文響社
- 発売日: 2015/12/04
- メディア: Kindle版
- この商品を含むブログ (1件) を見る
- 作者: 浅井佐知子
- 出版社/メーカー: ソーテック社
- 発売日: 2015/11/26
- メディア: Kindle版
- この商品を含むブログを見る
ここ半年、家のことについて自分なりに情報収集しているのだが、そもそも「(高望みせずに満足できる)家を手に入れるには元手が足りない」という当たり前の事実に気づき、資産形成を本気で考えるようになった。
他にいくつか買った本もあるが、興味本位だったので初心者お断りの本もあった。
とりあえず最近じわじわと話題になってるTHEOには登録し、運用を始めている。
完全図解 スポーツクライミング教本 すべてのクライマー必読の教科書決定版
- 作者: 東秀磯
- 出版社/メーカー: 山と渓谷社
- 発売日: 2017/05/26
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
1年半くらい前からどっぷりとハマり、ジムによっては3級に手が出せるようになった。
定期的なボルダリングジム通いと妻が作ってくれるバランスのいい食事のおかげで、最近やっと70kgを切ることができた。
外岩にも行ってみたい。せっかくマット買っているので。
あと、6月に妻とハワイに行ったので、事前に歴史なんかを調べておきたいと思って買ったものもあった。
ハワイの歴史と文化 悲劇と誇りのモザイクの中で (中公新書)
- 作者: 矢口祐人
- 出版社/メーカー: 中央公論新社
- 発売日: 2014/07/11
- メディア: Kindle版
- この商品を含むブログを見る
他に、気分を盛り上げるためによしもとばななのハワイ系の書籍( サウスポイント (中公文庫) , まぼろしハワイ )も買ったりしたが、自分達はほぼワイキキ周辺にしかいなかったので、本から滲み出る土着的な空気まで肌で感じることはできなかった。
マンガは「甘々と稲妻」「ダンジョン飯」「聖☆おにいさん」「ワールドトリガー」「東京グール :re」「ゆるキャン」辺りを半分惰性、半分楽しみに発売日に即購入している。
来年はどんな振り返りができるのか楽しみだ。よいお年を。
GraphQLのresolverの登録方法についての一例(Perlの場合)
<2018-01-14追記>
本エントリはライブラリの使用方法について僕が大きな誤解をしています。修正版については以下を参照ください。
taiyoh.hatenablog.com
<2018-01-14追記終わり>
所属プロジェクトでは一部のAPIリクエストにGraphQLを採用していて、最近のAPI実装をGraphQLで行うだけでなく、既存のREST APIの実装の順次置き換えを進めている。GraphQL便利すぎる。
GraphQLの各言語の実装では、定義したObject型のfieldはその実像となる集約だけで解決する必要はなく、 resolver
と呼ばれるコールバック関数を定義することでfieldの所属する集約から切り離すことができる。
そのresolverの登録方法について、プロジェクトでは以下のような方法を採っている。
#!perl use 5.014; use warnings; use GraphQL::Schema; use GraphQL::Execution qw/execute/; use Data::Dumper; package Person { use Moo; # GraphQLがMoo依存なので使わせてもらう has name => ( is => 'ro', required => 1, ); has favorite_fruit_ids => ( is => 'ro', required => 1, ); }; package Fruit { use Moo; has id => ( is => 'ro', required => 1, ); has name => ( is => 'ro', required => 1, ); }; package MyApp::GraphQL::Resolver::Query { sub person { my ($root_value, $args, $context, $info) = @_; my $person = main::get_person(); return { name => $person->name, favorite_fruit_ids => $person->favorite_fruit_ids }; } }; package MyApp::GraphQL::Resolver::Person { sub favoriteFruits { my ($root_value, $args, $context, $info) = @_; my $fruits = main::get_fruits($root_value->{favorite_fruit_ids}); return [ map +{ name => $_->name }, @$fruits ]; } }; my $idx = 1; my @fruits = map { Fruit->new(id => $idx++, name => $_) } qw/apple banana orange grape kiwifruit/; my $person = Person->new(name => 'taiyoh', favorite_fruit_ids => [1, 5]); sub get_person { $person } sub get_fruits { my $ids = shift; my %id_map = map { $_ => 1 } @$ids; return [ grep { $id_map{$_->id} } @fruits ]; } my $schema = GraphQL::Schema->from_doc(<<'EOF'); type Person { name: String! favoriteFruits: [Fruit!]! } type Fruit { name: String! } type Query { person: Person } schema { query: Query } EOF for my $type (grep { ref($_) eq 'GraphQL::Type::Object' } @{ $schema->types }) { my $pkg = sprintf 'MyApp::GraphQL::Resolver::%s', $type->name; for my $field (keys %{ $type->fields }) { if (my $resolver = $pkg->can($field)) { $type->fields->{$field}{resolve} = $resolver; } } } my $query = <<'EOQ'; { person { name favoriteFruits { name } } } EOQ my $res = execute( $schema, $query, {}, ); local $Data::Dumper::Indent = 1; say Dumper($res); __END__ $VAR1 = { 'data' => { 'person' => { 'favoriteFruits' => [ { 'name' => 'apple' }, { 'name' => 'kiwifruit' } ], 'name' => 'taiyoh' } } };
Perl版GraphQLライブラリはバージョン0.16から from_doc
という関数が追加され、GraphQLの定義の形式をそのまま読み込めるようになっている。フロントエンドを担当する人間と認識を擦り合わせたいという都合もあるので、schemaはPerlでゴリゴリ書くことはせず、定義ファイルを作ってそれをフロントエンドの人間にも読んでもらっている。
ただ当然ながら、定義ファイルにはresolverの記述はできないのでどうすればいいのかと試行錯誤している最中。
当初は「DSLっぽく登録できたらいいのかも」と思っていたが、しばらくしてテストしづらさを感じてきたので、「resolverが必要な1typeにつき1パッケージ用意する」「resolverを登録したいfieldと同じ名前の関数を定義する」というルールにしている(それが上記のサンプルの方法)。resolverの置き場所はこれで一旦落ち着けることにしたが、resolverの登録方法がhashrefに直接突っ込むスタイルなのであまり気持ちいいものに見えず、かといってそれを解消する手段を考えるために手を止めるわけにもいかないので、「あとでもっといい方法が見つかったらそれに変更する」というのが現状のステータスとなっている。
Elastic Beanstalkのsqsdの劣化コピーみたいなのを書いてみた
そろそろいい加減golangはちゃんと勉強しないとと思っていたところ、たまたまElastic Beanstalkのsqsdの話を見つけた。
本家のsqsdはちょっと探してみる限りossとして公開されてるものがなさそうだったのと、課題としてそんなに大きすぎない規模だと思ったのでいい練習になると思い、書いてみることにした。
golangについては、大昔にusbドライバー的なものやcgoを使ったものはちょっと書いてみたことがあったが、やっつけみたいな勢いだったので、今回はcontextを使ったりテストをちゃんと書いてみようと思ってそのあたりは気を付けてみた。sqsにただロングポールするだけでは使い勝手が悪そうに思ったので、一緒にHTTP Serverを立てるようにし、稼働中のjob一覧の取得やロングポールの一時停止・再開の操作もできるようにしてみた。
とりあえず「go test -race」や「go vet」では特に何も出てなさそうという状態にしてあるが、当然ながら実戦に持ち込んだことはないので、メモリリークがどこまでおきるかや、実際の使い勝手についてはまだわからない。今後ちゃんと検証していく必要はある。現状では僕の自己満だが、本当にいい勉強になった。