SNSで同僚をフォローするのをやめた

SNSというかTwitterで同僚をフォローするのをやめて精神衛生が良くなった。

一緒に仕事をするうえでパーソナリティも知りたいなと思って基本的にフォローしていたのだけれど、最近それによって楽しいとか便利と思うことより、きついと感じる機会のほうが多くなったのでやめた。

『エンジニアのためのマネジメントキャリアパス』を読んだ そもそものきっかけは、チームでテックリードというエンジニアのリーダー的な役割を拝命したからだった。 チームを良くするためにという思いもあって、チームのエンジニアのそれも職能のうちの一部に限定して基礎的なマネジメントに手をつけはじめた。

会社にはシニアエンジニアによるメンタリング制度がありそちらはチーム のエンジニアがメンターを務めることになっている。その制度とは別にテックリードとしてチームメンバーのキャリアプランなどを鑑みて、チームと個人がお互いにハッピーになるにはどうしたらいいか、ということを定期的に話している。

そうすると必然とメンバーの個人的な動向を気にするようになる。有り体に言うと最近仕事うまくいってそうだな・調子悪そうだな、とか、そういうこと。

調子が良い時は良いけれど、悪い時はだいたい何かあまり楽しくないできごとによって調子が上がっていないことが多い。プライベートで何かあったとか、季節の変わり目でフィジカルがついてこないとか、上司含む他のメンバーと折り合いが付かない、とか。

そういう動向を察知したら解決に向けて手伝えることはないかと声をかけたりもする。幸い今まで自分の手に負えないような巨大なできごとはなかったので、それなりの負荷でそれなりの点数で解決できたと思っている。

しかし、そう、少なからず自分にも負荷がかかることも事実なのだった。

少なくとも今のところの自分は、相手の感じているストレスを自分なりに受け止めて、まず相手のストレスを柔らげて緊張をほぐす、というやりかたをとる。

個人的な体験だけれども、エンジニアという課題を解決するということを生業にしていると、自分が感じているストレスを課題に変換できないことは、自分の能力の不足ではないかとか、そもそも課題ではないのだから周りを変えるかたちでの解決ではなく、自分が適応すべきなのではないか、とかそういうことを考え込んでしまう。

もっと言うと自分の感じているモヤモヤを課題というレベルまで昇華できなければ他人と共有できないとさえ思い込んでいる節がある。

こうして冷静な時に書き出してみれば「そんなことないでしょ」と思えるのだけれど、真剣に悩んでいる時あるいは弱っている時は、そういう考えに至ることができない。

こういう体験は学生時代にはあまりしなかったから職業病みたいなものだろうと捉え、そうすると個人的な特質というより普遍的である可能性が高いだろうから、特に同じエンジニアに対してはまずストレスの置かれている状況に共感を示して「モヤモヤしている状態を伝えてもいい・伝わる可能性がある」という安心をしてほしいな、という思いがある。

こういった振る舞いは自分の強みでもあると思っている。ストレングスファインダーを受けたら5つの特質の中に共感性 (sympathy) が挙げられていた。

だからこそ、こういったメンタリングが自然にできているのだと思う。

とはいえかなり消耗するので、得意というのも違うかなと思っている。燃費が悪い。

だから適度に休息が欲しいけれど、そこでSNSでの繋がりがネックになる。

自分の仕事はTwitterを見たりツイートすることではないので、仕事をするというコンテキストから (一時的に) 離れている時だけTwitterを見るが、そこで同僚をフォローしているとそのツイートに一喜一憂してしまう自分がいる。

わかりやすく「仕事がうまくいかない!」とか言っている場合もそうだし、こっちが滅入っている時は「疲れた」という発言にさえ自分の瑕疵を疑いぎくりとする。

ほとんどノイローゼみたいな時は、自分がファシリテータを務めたMTGを終えた10分後くらいに「は〜〜」みたいな溜息めいたツイートを見た時は、責められているのかと思い落ち込んだりもした。けれど普通に考えて無関係な確率のほうが高いと思う。

で、いろいろ考えた結果、同僚をフォローするのをやめた。少なくともチームメンバーはフォローしないことにした。 自分の負荷を減らすためでもあるし、またよりよいマネジメントを目指してのことでもある。

つまり一緒に仕事をするメンバーのことは、仕事というコンテキストから見える姿のみを見て理解しよう、ということ。

たとえば、大袈裟にいえばSNSとかで仕事とは関係のない思想信条を発露していたとして、それが自分の主義と反するものだった場合、いくら仕事と関係のない思想信条であったとしてどこかしらにひっかかりを覚えずにはいられないと思う。

また、実際にあったSNSでの発言に被害妄想めいた不安を抱いたとして、けっきょくそれを確かめるにはプライベートとかまで踏み込む必要があるが、それは泥沼だ。自分がケアしたいのは仕事仲間としての同僚であって、同僚という人間そのものではない。

というようなことを考えてフォローするのをやめた。そもそもけっこう前から同僚はフォローせずに非公開リストに入れて見ていたのだけれども、それも消した。

まあ、これは近年のTwitterがリスト機能をぞんざいにしているので、そもそも機能が使えなくなるのでは、といった不安もきっかけだった。

ちなみに結果からすると自分は同僚のSNS上の発言や振る舞いを見て落ち込んだりもしたけれど、あくまで自分が一方的な解釈をしただけのことなので、自分含めた人々は好きにSNSをやるのがいいと思う。

『みんなではじめるデザイン批評』から学んだコードレビューのやりかた

同僚が社内グループに『みんなではじめるデザイン批評』を読んだ感想を書いていて、それが良かったのとそういえばこんなことあったなと思い出したので読んだ感想がてら書きます。

みんなではじめるデザイン批評―目的達成のためのコラボレーション&コミュニケーション改善ガイド

みんなではじめるデザイン批評―目的達成のためのコラボレーション&コミュニケーション改善ガイド

命ずるな、尋ねよ

『みんなではじめるデザイン批評』を読んでからデザイナーとの会話だけではなくエンジニア同士でコードレビューをする時にも「まず、意図を尋ねる」ことに気をつけるようになった。

「自分だったらこうするのにな (だから、こうすべき)」と思ってもそのまま脳直で出すのではなく、なにか事情があるのかもしれないと思い「こうなっているのはなぜですか?」と聞く。 そうすると「時間がないけど急いでいるので、今は妥協したい」「イケていると思っていないけれど他に思いつかなかった」などの返事がもらえるので「時間がないのは仕方がないので落ち着いて考えなおすというissueを入れましょう」とか「こういうやり方だとしっくり来ませんか?」という返事へ進める。

この質問形式のコードレビューなら、チームに入り立てだったり経験の浅いエンジニア (以下、一般的な語法に則り「ジュニアエンジニア」とする) でも真似しやすいのではないか、と思っている。

コードレビューは構造上どうしてもレビュアーに対して権威付けが起きやすいが、質問形式でレビュアーが常に下手に出るよう振る舞う儀式的な関係を強いるとバランスが是正されるのではないかと思う。 加えて、この「レビュアーは常にまず自分の未知を想像して尋ねる」という姿勢をいつでも誰にでも強いて、レビュアーとレビュイーというロールで振る舞う時には対等であると意識付けることが肝。

コードレビューのやり方として「ここはこうだからこうすべきです」という言い方にしましょうというルールだと、そこまで断定できるドメイン知識や経験のない人はすぐに実践できず、かくあるべきレビュアーとしての振る舞いと現在の自分のあいだに断絶が生まれてしまう。 コードレビューでレビュアーを務めることはドメイン知識やエンジニア一般としての経験を積むチャンスなのに、レビュアーを務めるにはドメイン知識や経験が必要、というデッドロックが起きてしまって、これはまずい。

模倣

しかし「尋ねるレビュー」は誰でも真似できるのが一番の利点だと思う。そのシステムに詳しいエンジニアも、そうでない人も、変更に対して「どういった理由があってこういった変更になったのですか?」と尋ねる。 レビュイーはその疑問に明快に答える。言い淀むところがあればそれはより良くするチャンスかもしれない。それはエキスパートであってもそうでなくとも、そうする。

世の中いろいろな仕事があるがコードレビューは誰でもできたほうが良いし、そうできる可能性の高い仕事のひとつだと思う *1。 それは対象のソフトウェアの知識を効率良く培う方法であるからでもあるし、チームによるソフトウェア開発を効率的に進めるためだからでもある。

こういった仕事は担当できる人を効率的に増やすために模倣しやすく設計するのが大切だと常々感じる。 また、とても専門性の高い仕事もある一方、大抵の仕事はまず模倣するところから始まるはずで、裏を返せばそっくり真似のできないやり方はもっと改善の余地が潜んでいそう、とも言えそう。


また、普段のレビューをこういう形式にしておくと、絶対にやってはいけないこと (例: XSSCSRFなど脆弱性を作り込む) に対するフィードバックとして「〜してはいけないです」という表現が活きてくる。つまり何らかの指標に基づいて明らかにやってはいけないと誰でも断定できるときは断定してよい、という「例外」を設けられる。

さらに考えを深めると、普段コードレビューで指摘することの大半は、その是非がほとんど決定的じゃないということも考えられる。 つまりN+1クエリはバッドパターンだけれど、いついかなる時も致命的かというとそうではない、とか。アクセス数がほとんどないとか、Nが高々10くらいなら、大したことにはならない、みたいなそういう話。

もちろん今まで書いたことだけやっていれば万事良しかといえばそうではなくて、細かな言い回しに気を付けるといったことは依然として必要だろうと思う。 今回はコードレビューにおけるプロセスのうちいくつかを形式的にしようという話でしかないから、そういったウェットな話題は残っている。が今回は言及しなかった。

タイトルに反して「制作物に対しより効果的でヘルシーなフィードバックをしたい」と思う人にとって『みんなではじめるデザイン批評』は示唆と発見に富んでいることと思います。おすすめです。

みんなではじめるデザイン批評―目的達成のためのコラボレーション&コミュニケーション改善ガイド

みんなではじめるデザイン批評―目的達成のためのコラボレーション&コミュニケーション改善ガイド

*1: もちろん卓越したコードレビューのスキルとそれを持つ人がいることも知っている

『エンジニアのためのマネジメントキャリアパス』はなりたてのテックリードが読んで安心できる良い本

エンジニアのためのマネジメントキャリアパス ―テックリードからCTOまでマネジメントスキル向上ガイド

エンジニアのためのマネジメントキャリアパス ―テックリードからCTOまでマネジメントスキル向上ガイド

各所で良いという評判を聞いており、ちょうど先々週くらいに京都に台風が来るので自宅に引っ込み続けられるように急いで買った。Amazonでは売り切れていたのでリアル書店で買った。

読もうと思ったきっかけ

テックリードというロールを拝命して1年と数ヶ月が経つ。なんとなく今までの仕事と違うので知識の地図を広げたほうがいい気がするな、と思っていた。
現在所属する組織であるはてなとしてはテックリードはマネージャーではなくアプリケーションエンジニアの専門性を高めていく方向性の先にあるロールとされているけれど、マネジメント、とりわけプロジェクトマネジメントについては必要とされるなという感触をおぼえた。

見積もりとか計画作りとか、そういう分野は別途学んではいるが、しっくりこないというか要素技術だけ学んでおり有機的に繋がらず身に付いたかどうか怪しいので、シナプスを繋げたいなーとかねがね思っていた。
ソフトウェア技術では、最高のソフトウェアを作るためには、たとえばいつでも素早くリリースできる技術 (Continuous Delivery) があることで平均障害回復時間の改善に繋がったりリリースフローが滅びるリスクを下げられるとか、たとえば関心を分離する方法論 (layered architecture, clean architecture, etc.) があるとか、そういう咀嚼ができているからこそ「こういった分野の学習は、こういう時に役立つ (ので今やったほうがいい)」とか知っているけれど、マネジメントに関してはそうではない。
一言でいうと「テックリードはなぜプロジェクトマネジメントをやったほうがいいのか」「どれくらいできるといいのか」みたいなのが知りたい、というかんじかも。

そこでこの本が登場し、目次を読むとよさそうだった。で、実際に読んだところ良かった。

学び

最近テックリードないしマネジメントを学びはじめたけれど何をしたらいいかわからないや、という人はこれを読むととっかかりが見つかりそう。少なくとも自分は見つけられた。

まずこの本は「エンジニア (技術職) のために」というコンセプトなので、マネジメントについて本格的に書いてあるというより、エンジニアの視点・価値観に近いところからアプローチしてあるのがよい。
最初はマネジメントされる側の視点から始まって、メンター、テックリード、チームマネージャー……という風にマネジメントする対象がより大きくなっていくという構成が丁寧。

抽象的な精神論ばかりではなく、たとえば「提案を断る時にはいきなり『いいえ』『できません』と言うのではなく『なるほど、そのためにはこういうものが必要ですね』といった風に実現のために必要な対価を求める」といった具体的なテクニックが書いてあって、ほどよいバランス感だと思う。
実際に使える・使うかよりも、こういう今の自分でも実践できそうな情報が盛り込まれているかどうかで未知の分野について書かれた記述を信用していいか・地に足が付いているかを判断できるのが良い。

さらに自分が所属している組織にはチーフエンジニアやシニアエンジニアといった職位があるが、そういった同僚を他者評価する時にも「期待」が設定しやすくていいと思う。
つまり、まだ自分が経験していないポジションに求められるスキルや役割への理解が進みやすいということ。各章の冒頭に筆者が書いたとても丁寧なジョブディスクリプションがあり、通り一辺倒じゃない様々な働きについて述べられている。
(もちろんこれはあくまで一例であって、自分たちの組織において求めることを自分たちの言葉で書くのが良いし、そうすべきだと思う)

ジョブディスクリプションを書くのはこれからテックリードないしそういったポジションを目指すエンジニアにとっても意義がありそうなので、早速やろうという

後半のCTOや経営メンバーの章はだいぶ高度で「へー」というかんじでわりと流した。こういうことを考えているのだな、という知識がついたのはよい。

一方、マネジメントの各技術については別途専門の本を読むのがよさそうに思う。

シグマのSAマウント終了告知が丁寧かつ真摯で素晴らしかった

SAマウントカメラ・レンズをご愛用の皆さまへ | レンズ | SIGMA|株式会社シグマ

レンズ交換式カメラを開発・製造しているシグマがカメラシステムを終了させる告知を出して、告知をすること判断自体とその告知内容がとても丁寧で心証が良かったです。

前提

カメラシステムはカメラボディ自体と交換レンズおよびフラッシュなどのアクセサリからなります。
カメラシステムの導入にはカメラボディ + レンズで最低数万、熱心なユーザーは数十万・数百万という単位でお金をつぎ込みます。

カメラシステムは複数社が展開していますが、基本的に互換はないので熱心なカメラユーザーはこれから数年・十数年に渡って数十万〜数百万のお金を使う先を吟味して選び、決定しています。

またシグマという会社は撮像センサー (フィルムカメラでいうフィルム、カメラの根幹をなすパーツ) にFOVEONという他社とは一線を画す革新的なセンサーを採用しており、そのセンサーから得られるイメージはとても熱心なファンをひきつけています。
詳しくはメーカーのテクノロジー説明を読んでもらいたいのですが、一言で表すならば技術的な独創性ゆえに「XXXと比べて画質が良い・悪い」といった他のメーカーと同じ次元には立たずに、根本的に出てくるイメージそのものが違う、といったレベルの違いがあります。

終了告知自体の潔さ

カメラシステムに限った話ではないですが、莫大な資産を投じてきた既存ユーザーを刺激しないよう明示的に開発終了はアナウンスせずに、単に既存製品をディスコン (discontinued; 生産終了) させてフェイドアウトさせるに任せる、といった方針をとる会社が多いです。

実際、ユーザーは製品のリリースサイクルなどをもとに早いうちから「緩やかな死」を感じとって他システムへ移行しますし、すべてのユーザーに納得してもらえるようなアナウンスは難しい (なにせ大金を注ぎ込んできたものがほぼ泡になる) ですから、下手に行動を打つよりはひっそりと、というのは良し悪しはともかく合理的であるといえそうです。

そういった慣行・背景がありながらもきっぱりと終了をアナウンスする姿勢からは、システムそれ自体よりもシステムを作ってきたシグマという会社を信頼してくれているという自信が見えますし、ひいてはカメラシステムという息の長いプロダクトに対するビジョンの強さが伺え、ポジティブな印象です。

しかし単にアナウンスがあったからだけではなく、その内容が実に丁寧で真摯だったからだと思います。

告知の真摯さ

SAマウントカメラ・レンズをご愛用の皆さまへ | レンズ | SIGMA|株式会社シグマ

要旨としては:

  • SAマウントは終了します
  • Lマウントという新しいシステムを開発します
    • Lマウントはこれまで要望を受けてきた製品 (フルサイズセンサー搭載のカメラ) を実現するために最適な仕様です
    • 他社とのアライアンスを通じて最高のシステムにします
  • SAマウントのレンズ生産は続けます
    • Lマウントシステムのリリースまでに空白期間は設けません
    • 既存のSAマウントをLマウントで使えるよう移行手段を用意します

……といった内容です。

この告知は、事実を端的に説明し表現を濁した点が無く、ユーザーが最も知りたい点、すなわち現行システムの将来 (いつまでに、どうなる)、新システムへの移行がどうなるか、に絞って書かれています。

簡潔でわかりやすいだけではなく、実はこの告知には「申し訳ありません」などの謝罪表現が一切使われていません。
これから作る新しいものは絶対に良い自信があるし、それに向けた滑らかな移行手段も用意するから安心して、という強いビジョンが伺えますし、それを根拠付けるシグマからのアクションが提示されているからこそ説得力のあるものになっているのでしょう。

また、新マウントへ変更してより素晴しいシステムを作っていく必要があるというシグマ側の事情も匂わせつつも言い訳がましく見えないのは、けっきょくこの判断は最高のカメラシステムをユーザーに提供したいからです、という視点に立っているからという点も見逃せないです。

感想

これだけ丁寧にアナウンスしても少なからず反発はあるでしょうし、かなりハイカロリーな決断だと思いますが、シグマのプロダクトに対するビジョンの強さを感じさせ、シグマ製品を愛用している自分のシグマに対する信頼感は増しました。

アナウンスからはユーザーに対するケアだけでなく、これから作ろうとするシステムに対する強い自信を感じられます。
ユーザーに寄り添う姿勢も、新しいものに対する自信も、どちらか一方だけでは片手落ちで、両方を兼ね備えているからこそ納得感のあるアナウンスになったのでしょう。

カメラ業界的には決して大きなパイではないシグマですが、確かな地位を築いており今回のアナウンスはさらにそれを磐石にするものと思います。

いち開発者としても感じるところがたくさんあり、業界は違えど、見習いたいところばかりです。

MySQL: テーブルのデータサイズを見るときはinformation_schema.tables

こういうかんじ:

mysql> select table_name, table_rows, avg_row_length, (data_length + index_length) / 1024 / 1024 as total_mb, data_length / 1024 / 1024 as data_mb, 
index_length / 1024 / 1024 as index_mb from information_schema.tables where table_schema = '...';
+---------------------------------+------------+----------------+----------+---------+----------+
| table_name                      | table_rows | avg_row_length | total_mb | data_mb | index_mb |
+---------------------------------+------------+----------------+----------+---------+----------+
| foo                             |      10224 |            350 |        6 |       3 |        3 |
| bar                             |     391760 |            274 |      102 |     102 |        0 |
+---------------------------------+------------+----------------+----------+---------+----------+
2 rows in set (0.01 sec)

builderscon tokyo 2018で『ブログサービスのHTTPS化を支えたAWSで作るピタゴラスイッチ』という話をした

builderscon tokyo 2018で話しました。

2017に続いてスピーカーとしての登壇で光栄です。こういうイベントで何も話さないとどことなく居心地が悪くなる性分なので、スピーカー or die (不参加) となるところだったのでよかったです。

トークについて

speakerdeck.com

資料はすでに公開しています。

Hatena Engineer Seminar #10という社の名前を冠したイベントでもこのシステムについて話したのですが、けっこうおもしろいシステムができたという自負もあったしお待たせしてしまった感は拭えないのでせめて裏側を紹介して「知らなかった、を聞」いてもらえたらな、という思いもありました。
実際にbuildersconで話を聞いてもらえる機会をいただけて本当に嬉しいです。

実は後半の「ぼくのかんがえたさいきょうのピタゴラスイッチ」以降のスライドは直前に追加したものです。
今回初開催となるスピーカーディナーの会でid:devorgachemさん (今回はじめてお会いしました) とid:nkgt_chkonkさんと「設計について話そうとすると実践から離れた表層の話か、逆に応用の利きづらいドメイン特化の話になりがちでむずかしい (けどなんとかやっていきたい)」というような話をして刺激を受けて「もっと一般化された・普遍的な話ができるはずだ、したい」と思い捻り出しました。
実際できあがった話は、普段から考えていたことを咀嚼したものでかなり納得感がありました。ちょっと背伸びするきっかけができてよかったです。

あと「ぼくのかんがえたさいきょうのピタゴラスイッチ」は「ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく」をリスペクトしました。
スピーカーディナーでid:cho45さんとお話しできたのもすごく嬉しくて *1 、これだけでも参加した甲斐がありました。

Q&A

すっかり頭から抜けてしまったので、ツイート検索しました。ありがとうございます。
これまでのキャリアで最も質疑をたくさんいただけたトークで、とても励みになりました。やっぱり反応もらえるとうれしいです。

Q.「StepFunctionsのJSON手書きつらくならないんですか?」A.「つらいです。schemaがないので全体を把握するのがむずかしい。Goのコードを解析してschemaを作るグッズを作ろうとしている」

あともうちょっと質問いただいた気がします。録画見て思い出そうと思います……。

聞いたトーク

正直いうと他のトークほとんど聞けていないのが心残りです。ただでさえ発表前でナイーブになっているところへ関西にものすごい台風が来たり、地元の北海道で大きな地震が起きたりして、けっこう堪えました。
特に北海道の地震は仕事でもプライベートでも大きな打撃があって冷や冷やしました。

また、会場へ出向いても満員御礼だったということが多かったのもやや残念です。SmartHR社のマルチテナンシーの話はおもしろそうだったので生で聞きたかった……!

事前知識なしで理解する、静的検査のいろは - builderscon tokyo 2018

昨年のビルコンで僕も「Goで実装する軽量マークアップ言語パーサー」というトークをして興味のある分野だったので聞きました。
というのと、iOSDC 2018でベストスピーカー賞2位とのことで、プレゼンテーションが上手な方の話を聞いてみたいという興味もありました。

実際、幅広いトピックを密度高く紹介するというプレゼンテーターとしては難易度の高い話だったと思いますが、細かい粒度でまとめを挟んだり、構文木など難しい概念はグラフィカルに説明することを徹底されており、唸りました。

内容自体だけでなくプレゼンテーションそのものが勉強になりました。

JavaCardの世界 - builderscon tokyo 2018

興味の範囲がWebを中心としている限りおよそ出会うこともなかろうトピックだったので聞きました。

AIDなどの払出しがISOだったり、中央集権っぽいのが組み込みっぽいというかWebっぽくなくて新鮮ですね。

運営スタッフのみなさまへフィードバック

  • スピーカーディナーよかったです
    • お酒入ってたこともあり1分間ピッチの反応が思ったより良くて発表前にちょっと自信がつきました
    • 規模感がちょうどよく、いろんな人と話しやすかったです
  • 満員御礼で見れないトークが多く残念でした><
    • 街頭ディスプレイみたいな、コンサートホールのホワイエで見れるやつみたいな、立ち見席みたいなのもあると嬉しいかも、とおもいました

とはいえ部屋に入れなかったらHUBへ行くことができて、そこはそこでおもしろい話ができました。
僕のトークの裏番組になってしまい聞けなかった遠いようで身近なサウンドエンジニアリング - builderscon tokyo 2018もスピーカーである id:karupanerura さんとイベント後のHUBでゆっくり話ができたのもいい思い出です。

ビルコンも3度目ですが、毎度、これだけの規模のイベント運営されるみなさまには頭が下がります。ありがとうございます……!

*1: ここだけの話、自分がエンジニアを目指すきっかけになったのでたいへん尊敬しているのです

aws-cdk探訪: AppsとStacksの関係

最近、TypeScriptで癒されたさ重視でaws-cdkを見ています。

aws-cdkはCloudFormation (以下CFn) をよりプログラマブルに扱う高級な・抽象的なライブラリと見てよく、概念もほぼ対応しているのですが、Appsという概念はaws-cdkに固有のもので特色たりえるものに見えるので、これについてメモします。

基本的に公式ドキュメントに書いてあることの咀嚼しなおしなので、既に読んで理解している人には新しい情報は無いです。

ざっくりとした捉え方

  • aws-cdk Stacks = CFn stacks
  • aws-cdk Apps = 複数のaws-cdk stacksをまとめたもの
  • 変更のデプロイはappに含まれる特定のstackを指定するとよい

aws-cdk Appsとは

公式ドキュメントによると:

The main artifact of an AWS CDK program is called a CDK App. This is an executable program that can be used to synthesize deployment artifacts that can be deployed by supporting tools like the AWS CDK Toolkit, which are described in AWS CDK Tools.

Apps — AWS Cloud Development Kit

……とのこと。

この説明はランタイムとしてのaws-cdkに寄った説明でどういった概念なのか掴みづらいです。

実はStacksの説明のほうがわかりやすくて、以下のように書いてあります:

Most production apps consist of multiple stacks of resources that are deployed as a single transaction using a resource provisioning service like AWS CloudFormation.

Stacks — AWS Cloud Development Kit

ここでいう Most production appsaws-cdk Appsを指します (恐らく)。
大抵のAppsは複数スタックからなるでしょう、ということです。

さらにAppsのドキュメントにあるコード例がわかりやすいです:

import { App } from '@aws-cdk/cdk'
import { MyStack } from './my-stack'

const app = new App(process.argv);

const dev = new MyStack(app, { name: 'Dev', region: 'us-west-2', dev: true })
const preProd = new MyStack(app, { name: 'PreProd', region: 'us-west-2', preProd: true })
const prod = [
    new MyStack(app, { name: 'NAEast', region: 'us-east-1' }),
    new MyStack(app, { name: 'NAWest', region: 'us-west-2' }),
    new MyStack(app, { name: 'EU', region: 'eu-west-1', encryptedStorage: true })
]

new DeploymentPipeline(app, {
    region: 'us-east-1',
    strategy: DeploymentStrategy.Waved,
    preProdStages: [ preProd ],
    prodStages: prod
});

process.stdout.write(app.run());
Apps — AWS Cloud Development Kit

上記コードは1つのappにdev, preProdといった開発環境用のstackを追加しています。
これらステージごとのstackなどの集合がappであるという捉え方です。

デプロイはどうするか

これもCLIのヘルプを読めばわかりますが、各コマンドは対象となるstackを指定することができます。

cdk deploy Dev
...
Apps — AWS Cloud Development Kit

指定しなければ紐付くすべてのstackが更新されます。

aws-cdkの基礎にCFnが存在し、CFnの基本デプロイ単位はstackであることを思い出すと理解しやすい挙動だと思います。

私の環境ではdev, staging, productionといった環境ごとにデプロイは分けていたので cdk deploy dev-app のように実行するのがよさそうということがわかりました。

aereal.orgをGoogle Cloud Platformに移した w/Cloud DNS, Cloud Storage, Deployment Manager

aereal.org

長らくさくらのVPSホスティングしていたのだけれども運用がめんどうになったのでこれを機にGCPへ移行した。

登場人物は:

……の4つ。

Google Cloud Storage

GCP版S3みたいなオブジェクトストレージ。使い勝手はかなり似ていて、S3同様にウェブサイトとして公開する設定もある。

ここにindex.htmlとか画像を置いて後述するGoogle Cloud CDNのoriginにする。

Google Cloud Load Balancing

AWSでいうALB/NLBにあたるもの。ALB相当がHTTP(S) Load Balancingになる。
余談だけど日本語ドキュメントでは「HTTP負荷分散」と訳されていて、動名詞なのかプロダクト名なのかわかりにくい。

パスやホストに対してルールベースでbackendへリクエストを送ることができる。
使い込んでいないけれどALB/NLBと機能の差異はそんなにないようにみえる。

Google Cloud CDN

GCPが提供するCDNサービス。AWSでいうCloudFront.

invalidation APIがあったり、普通なかんじ。

Cloud CDNに限らないけれど全体的にGCPは安めな気がする。

Google Cloud Deployment Manager

AWSでいうCloud Formationみたいな構成管理するグッズ。

YAMLを使うのはCFnと同じだけれども、変数展開などはJinja2というAnsibleでも使われているテンプレートエンジンを採用している。
既存のよくできた技術を再利用する筋のよさは後発のGCPならではってかんじ。

リソースのプロパティ定義は既存のREST APIのリクエストパラメータと同じ名前・同じスキーマなのでそちらを参照せよというドキュメントになっており親切。
(例: REST Resource: targetHttpsProxies  |  Compute Engine  |  Google Cloud

gcloud deployment-manager types list で使えるリソース定義の一覧が得られるので、これでDeployment Managerで対応しているか確認できる。
前述の通りプロパティ定義はREST APIと一致しているので、このリソース定義名からREST APIのドキュメントを引けばよくて便利。

aereal.orgのデプロイ設定は GitHub - aereal/gcp-deployment-aereal.org に置いたのでご覧ください。

感想

GCPはぼちぼち触っていたけれどDeployment Managerはよく出来ているし筋がいい印象を持った。

会社ではAWSを使っているのでおもしろさ重視でGCPでもっと遊んでいきたい。

aws-cdkを見ている: policyの変換がすごい

aws-cdkを見ている。TypeScriptもしくはJavaAWSの構成管理ができる。CloudFormationのプログラマブルなやつと考えるとよい。

TypeScriptは癒しなので癒されました。今日は感動ポイントをご紹介。

policyの変換がすごい

CFnのなかでもS3のbucket policyを書くのは最もダルい作業のうちのひとつに数えられると思いますが、aws-cdkだとこう書ける:

    const bucket = new Bucket(...);
    const policy = new PolicyStatement(PolicyStatementEffect.Allow);
    policy.addAction("s3:GetObject");
    policy.addResource(this.arnForObjects("*"));
    policy.addPrincipal(new Anyone());
    bucket.addToResourcePolicy(policy);

これが cdk synth でこうなる:

    XxxBucketPolicy81AF88BF:
        Type: 'AWS::S3::BucketPolicy'
        Properties:
            Bucket:
                Ref: XxxBucketEDCC903C
            PolicyDocument:
                Statement:
                    -
                        Action: 's3:GetObject'
                        Effect: Allow
                        Principal: '*'
                        Resource:
                            'Fn::Join':
                                - ""
                                -
                                    -
                                        'Fn::GetAtt':
                                            - XxxBucketEDCC903C
                                            - Arn
                                    - /
                                    - '*'
                Version: '2012-10-17'

すごい!

JavaScriptのtemplate literalでよいかんじに変換されていそう。

よくあるワンソースで適当に変換エンジン作りましたというかんじではなく、ちゃんとTypeScript (ECMAScript) でネイティブにいいかんじに実装していこうという気概が感じられて、今後に期待が持てますね。

その他

cdk synth で出力するYAMLが、既存のCFnのYAMLと完全に互換を保てたら脱出も楽になるからいいな〜とおもっているのだけれど、そういうオプションはざっと見たかんじなさそう。

migration pathみたいなissueはあるのでなにも計画がないわけではなさそうだけど、あれだったらP-Rを送っていきたい。

tslintで有効になっているruleをpreset由来も含めて一覧する

const { resolve } = require('path');
const { Linter, Configuration: { findConfiguration } } = require('tslint');

const tslintJsonPath = resolve(__dirname, '../tslint.json');
const { results: config } = findConfiguration(tslintJsonPath);

const formatRule = (rule) => `${rule.ruleName}:${rule.ruleSeverity}`;

const linter = new Linter({ fix: false });
const rules = linter.getEnabledRules(config, false);
rules.map(r => formatRule(r)).sort().forEach(r => console.log(r));

presetをextendsするのが主流だけど、このpresetってデフォルトでどういう設定を提供するんだっけ? と調べはじめたりしてまあまあ不毛だし、そういうのとってくるAPIあるでしょと思い調べたらやはりあった。

内部向けっぽいAPIを無理矢理使っているわけでもないので、まあまあ安定しそう。

BPMと音価を入れるとディレイタイムを計算してくれるやつをReactで作った

Reactでちょっとした計算機を作ろうと思い、せっかくなのでStorybookを試してみることにした。

できたもの

GitHub - aereal/delay-time-calc

f:id:aereal:20180521112626p:plain

BPMとフィードバックさせたい音の音価を入れるとディレイタイムがミリ秒で出力される。

BPM 120で8分ディレイをかけたかったら250msec.にすればいい、みたいなことが手軽に計算できる。

いま触って気付いたけど付点8分のときの計算まちがっている気がする……。

使ったもの

create-react-appで雛形を作り、Storybookのドキュメントを読んでセットアップをした。
TypeScriptでstoryを書くのに一手間必要だったが、ものはできた。

変更内容は以下の通り。自動生成するコマンドの実行結果と手作業で加えた変更はコミットを分けているので、わりとわかりやすいのではないかと思う:
https://github.com/aereal/delay-time-calc/compare/94b844e12a73fd91b52d21a542b3566e19ab9151...eb106a6dda7e606a40de1453a56d4e642554ae14

TypeScriptでstoryを書くためのあれこれは typescriptでReact Storybookを試す。 - Qiita が参考になった。

感想

  • storybookは便利
    • コンポーネントがたくさんある・たくさん作っていくプロジェクトではカタログとして十分便利そう
    • storybookがあることで、ここで触るのに過不足ない
    • addonを入れるとMaterial-UIのスタイリイングをstorybook上でプレビューできるのめちゃくちゃ便利
  • とりあえずはじめるときはcreate-react-appを使うとよさそう
    • `npm run eject` できるしWebpackの設定をだいたいいいかんじにしてくれるし
    • まあこの先メンテしていけるかっていう話はあると思うが、少なくとも初速は出る・差分アップデートで習得できる、というところをよしとできるなら
    • scripts/test.jsとか、テスト実行をいじりたいと思ったときにメンテできるのかは既に不安ではあるが……

HTTP::Message#content($bytes)を呼んでもcontent-lengthは計算されない

HTTP::Request#content($bytes) もしくは HTTP::Request#add_content($bytes) を呼んでもcontent-lengthは自動で計算されず、0になる。

なのでそのままリクエストを送ると、ちゃんとcontent-lengthだけbodyを読む実装はボディが空だとみなすのでちゃんとcontent-lengthを計算しなければいけない。

Plackの実装に慣れていたのでびっくりした。

    my $req = HTTP::Request::Common::POST($url);
    my $json = JSON::XS::encode_json($payload);
    $req->content($json);
    $req->as_string;

HTTP::Request#as_string した結果:

POST http://example.com/api/issuance
Content-Length: 0
Content-Type: application/json

{"status":"success","expires_at":"2018-04-09T12:19:26+09:00"}

Content-Length: 0 になっていることが確認できる。

AWS CloudFormationメモ

  • aws cloudformation package はS3にfunctionとかいいかんじにアップロードして、そのARNが埋められてそのまま aws cloudformation deploy 実行可能なテンプレートを出力してくれる
    • そのパスを指定する引数が --output-template-path
  • cloudformation自体はS3になにをアップロードするのは不可欠ではない、lambda functionとか追加のファイル (local artifacts) が必要なときはpackageするとよい
  • lambdaとかつかわない場合はいきなりdeployできる

id:dekokun ++

参考:

Go: 外部ライブラリを使ったコードをいいかんじにDIしてテストする話

結論

  • 実装ではなくインターフェースに依存させる
  • Goのinterfaceは実装の明示が必要ないので便利

aws-sdk-goのスタブ

外部ライブラリの例としてaws-sdk-goを使ったこういったコード例を考える:

type CertificateFetcher struct {
  client *dynamodb.Client
}

func New(client *dynamodb.Client) *CertificateFetcher {
  return &CertificateFetcher{client: client}
}

func (f *CertificateFetcher) GetCertificate(domain string) (string, error) {
  resp, err := f.client.GetItem(...)
  if err != nil {
    return "", fmt.Errorf("...")
  }
  key := resp.Item["key"]
  if key == nli {
    return "", fmt.Errof("...")
  }
}

DynamoDBと通信させずにエラーのハンドリングや *dynamodb.GetItemOutput から値を取り出す処理などについてテストしたいが、そのためには *dynamodb.Client を差し替える必要がある。

実装を差し替える範囲が広すぎると実際に実行されるコードに対するカバレッジが低くなりテストの意味がなくなるので、適切な境界を見つけてそこで差し替えられるとよさそう。

実際にどうやるか、結論としては CertificateFetcher*dynamodb.Client ではなく必要なメソッドが定義されたinterfaceに依存させるとよい。

例:

type DynamoDBClient interface {
  GetItem(item *dynamodb.GetItemInput) (*dynamodb.GetItemOutput, error)
}

type CertificateFetcher struct {
  client DynamoDBClient
}

func New(client DynamoDBClient) *CertificateFetcher {
  return &CertificateFetcher{client: client}
}

func (f *CertificateFetcher) GetCertificate(domain string) (string, error) {
  resp, err := f.client.GetItem(...)
  if err != nil {
    return "", fmt.Errorf("...")
  }
  key := resp.Item["key"]
  if key == nli {
    return "", fmt.Errof("...")
  }
}

テストコード例:

func TestGetCertificate(t *testing.T) {
  stubClient := &StubDynamoDBClient{}
  fetcher := New(stubClient)
  // ...
}

type StubDynamoDBClient struct {}

func (c *StubDynamoDBClient) GetItem(item *dynamodb.GetItemInput) (*dynamodb.GetItemOuput, error) {
  // ...
}

Goのinterfaceは所与のメソッドを実装していれば特別なアノテーションをつけずとも構造体がinterfaceを実装しているとみなされるので、実装を変更できない外部ライブラリに対してアドホックにinterfaceを定義できるので便利。

このようにインターフェースに依存させてDIしやすくするというのは、たとえばScalaにおけるcake patternなど他にも例があります。