入社以来未だオフィスに踏み入れていない自分の転職とオンボーディングについて

前回までのあらすじ

転職した: 新しい職場で半年経った

面接を受ける1年前 (2019年初頭) にカジュアル面談に行った時にオフィスを訪れて以来、面接から入社後に至るまで自分は一度も現職のオフィスに踏み入れていない。
転職から入社

転職活動

新しい職場を決めるにあたって重視した点は金沢からの勤務実現に前向きか同僚となるメンバーが刺激的かどうかの2つ。

これは以下に引くようにこれまでに言及してきた:

数年前に観光で訪れた金沢を歩いてから一目惚れしてしまい、自分がここで生活する想像をするうちに単なる夢想から具体的に実現することを考えはじめた。
これを書いている時点で、株式会社はてなの事業拠点は東京と京都のみであり、在宅勤務は育児や介護、その他会社が認めるに足る理由があるケースのみ認められている。
平時は週数日程度スポットでの在宅勤務はマネージャーと合意した上では認められている。またコロナ禍においては在宅勤務推奨となっている。ただし、継続的にフルリモート勤務というのは上記の通り認められる事例は限定的になっている。
このまま在職しつづけても実現が難しそうと判断したのが、転職を決意した最大の動機といえる。

株式会社はてなを退職

転職先を決めるにあたって一緒に働くメンバーから刺激をもらえそうかを一番重視した。
これは抜きん出たタレントを持っているとか輝かしい経歴を持っているかとかではなく:

  • 知的好奇心を持っているか
  • それがよく表出しているか (= アウトプットされているか)

……ということを重視している。

新しい職場で半年経った

転職ドラフト

上述の条件の他、漠然とWeb系で、くらいしか思い付かなかったのでとりあえず世にどんな企業があるのか知ろうと思い転職ドラフトに登録した。
当初は自分にスカウトが来るとしてどれくらいの条件なのか知りたい、くらいの気持ちだったけれど。

転職ドラフトに登録していくつかスカウトをもらってわかったことがいくつかある。

まず、提示される条件は自分の市場価値がどうとかより企業が儲かるかどうかが支配的ということ。
具体的には、スカウト文言の熱量の高さと年俸の高さに相関はあまりなかった (熱烈だけど低いというケースはままあった) し、額面は高いけれど明らかにこちらのレジュメ読んでいないなってわかるケースもあった。
考えてみれば当然ではある。
「リモートワーク希望、で少なくとも首都圏では働きたくないです」ってレジュメに書いてあるのに「当社の(都内の)オフィスにはこんなに福利厚生があって〜」みたいなことをスカウト文言に書いていた企業は申し訳ないけど笑ってしまった。

金沢から勤務したいっていう条件が折り合い付かなかったのでお断りさせていただいたけれども、PLAIDからのスカウトはこちらのレジュメに書いてあることをしっかり読んでもらえたことがわかって嬉しかったし好印象だった。(レジュメに載せた過去の発表内容や就労条件についてちゃんと言及いただいていた)
今回はマッチしなかったけれども記憶には残ったので、こういう細かい取り組みが強みになるんだろうなーと感じる。

企業探し

そんなわけで転職ドラフトに参加してみて、漠然と首都圏や近畿で働いても良いなら便利な仕組みではありそうだが自分の条件ではファジーすぎるので不適と判断して地道に自分で探すことにした。

まずremote-in-japanを眺めてみることにした:
GitHub - remote-jp/remote-in-japan: Tech companies in Japan that hire remote workers

よくまとまっていて便利。転職活動をはじめた2020年前半はCOVID-19の影響下にあり半ば緊急避難的にリモートワークをやっている会社も多かったけれども、やはり以前から運用している組織のほうがいろいろと不都合はなかろうと参考にした。

が、結論からいうとここからはマッチしなかった。事業会社かどうか・メンバーの魅力 (そもそも誰が所属しているかよくわからないとかあった) などを考えるとリモートワーク可以外の点で決め手に欠けた。

面接

けっきょく知人の所属している・していた数社にカジュアル面談を設定していただき、さらにそこから合いそうだと感じたいくつかの面接を受け、最終的に現職の内定をいただき受諾となった。
面接はすべてzoomなどを利用した。

入社後

全社的に半強制的なリモートワークにあった (ある) ので、オフィス勤務時のように黙って座っているだけで新顔だなって覚えてもらう機会はなく、能動的に行動しないとかなり仕事しづらいだろうと考えていたのでとにかく存在感を出して認知してもらうことを考えた。

特に自分は基盤バックエンドというサーバサイドのお困りごと全般をなんとかするというプロダクト横断のチームに配属されたので、考えなしでいると薄く広くという関係構築になることが予想されたのでかなり気にかけた。

Slackで存在感を出す

リモートワーク環境においてはチャットで見かけるかどうかが良くも悪くも存在感に繋がると前職から感じていたので、まずSlackでの認知を高めることにした。

xxx-zassouのようなカテゴリごとの雑談チャンネルがいくつかあるので、とりあえずそこで絵文字のreactionをつけるくらいから始める。
reactionをつけること自体が認知に繋がるとは思えないけれど、とりあえず自分がそのチャンネルの雰囲気に馴染むことを目的として絵文字をつけていった。

慣れてきたら発言したり。分報チャンネルで仕事するのはやめよう高校出身なので、用意されていた *1 分報チャンネルのtopicは「社内Twitterです」と書いて未だに仕事の話はほとんど書いていない。archiveしても良い気はしているけれど、思いがけないコミュニケーションが生じていてこれはこれで惜しいのでそのままにしている。

しかし振り返ってみても「あとはがんばる」以上の取り組みをしていないな。

顔出し

zoomやGoogle MeetなどでのWeb会議ではカメラの映像を映すようにしている。
少しでも情報量が増えたほうが相手に認知してもらうフックは増えるので出したらいいかと思ってそうしている。

実際「そのフリースHaglofsですか?」とかフックが生まれたりしているのでわりと良い取り組みなのだと思っている。

まあこれは自分が必要性を感じているから苦に感じないのであって、結果が同じでも会社に「出しましょう」って言われたらエッとなりそうだなとは思う。
ので、こういう良い変化はありましたよとは書くけれど無理に勧めることはしない。

文化のすりあわせ

よく中途で入った人は「新しい風をもたらすことを期待しています」と言われるし、実際言われたけれど、しかし新しい風がなにもかも良いかというとそうではない。
なにより「前職ではこうやったで」おじさんは、たとえ言っていることが正論であっても量が過剰だったり、現職へのリスペクトがないと鬱陶しがられるだろう。

もたらす情報:受け取る情報 = 3:2くらいの割合を心がけた。根拠は特にない。求められていることに違いはないだろうから、
あと単にまだ知らなくて知っておいたほうが良いこととの比ってこんなものかな? という印象。

いかがでしたか?

開発者ブログの再興とか調整事も必要なプロジェクトを提案して軌道に乗せられていたりと、本来のパフォーマンスを発揮するには3ヶ月くらいはかかるという定説から外れてわりと良い仕事ができているのでうまいことやれていると評価して良いでしょう。

もちろん現職が提供してくれたオンボーディング施策によるところも多分にあるだろうから、ここに書いたことが結果のすべてだとは思わないけれども。

初めての転職がフルリモート下というわりとハードな状況のわりにはよくやっていると思うので自信にはなった。

*1:事前に作られていた

DDD is overratedについて

DDD is Overrated | Stefan Tilkovについて。

DDD is overratedの自分なりの受け取り方

  • DDDだけが設計手法や考えではないんやで
  • 必要なら(DDDにおけるaggregateやvalue objectのような)概念に対する名前を自分たちで付けてもええんやで

自分の考え

筆者が言わんとする「盲目的にDDDを受け入れたり、その他の手法などの探索を諦めるような思考停止はいかがなものか」ということは理解はできる一方で、生半可な労力でもってこうした一般的な設計手法の(再)発明を試みるのは概ね良い結果をもたらすとは言えないのでやめたほうが良いと思っている。

DDDなりPoEAAで紹介されているパターンなりは、数多くのプロジェクトを調査して頭の良い人が心血を注いで一般化したもので、完璧でないにせよ少なくとも見てきた事例の多さという点は評価できそう。

一方、事業(サービス)を持ってその開発をしている組織のデベロッパーが立ち会うプロジェクトの数は知れている。 それはたとえばLINEやYahooのような規模であっても一般化を踏まえるとサンプル数や偏りの是正は不足していると考える。

そも事業ドメインの知識モデリングだけでもかなりタフな仕事なので、ましてやその一般化をしようとするのはコスパが悪い。

餅は餅屋ではないけれど、こういった開発手法や設計・分析については借用に留め、発明を試みないほうが総合的な生産性は高く保てる。これらは最終的に良いソフトウェアを作るためにあるので。

もちろん選ぶのがDDDでなくとも良いし、きちんと批判的に見て合いそうか評価することは大事だけれども、ある程度は型にはまる・型通りにやるということも大事だと考える。

新しい職場で半年経った

from: 株式会社はてな 退職エントリ
to: 株式会社Classi 社の開発者ブログに書いたエントリ

決め手

転職先を決めるにあたって一緒に働くメンバーから刺激をもらえそうかを一番重視した。
これは抜きん出たタレントを持っているとか輝かしい経歴を持っているかとかではなく:

  • 知的好奇心を持っているか
  • それがよく表出しているか (= アウトプットされているか)

……ということを重視している。

転職ドラフトに参加したり、いろいろな企業を見る中でbuildersconなどのカンファレンスで顔を合わせて話すことがあったid:nkgt_chkonkさんやid:lacolacoさんが所属していることを思い出した。

所属がはっきりしているメンバーで事前に認知していたこの2人がいたので、先に述べたような資質を引き出す働きかけは頑張れそうかなと思えたのが決め手になった。

いろいろ考えたけれど初めての転職だし、うまくいかなかったとしてもこの2人と働いた経験が短くとも得られたら元は取れるかなと思えた、という防衛的な見方もある。

やっていること・やりたいこと

基盤バックエンドチームというサーバサイドのソフトウェア技術的な困り事全般をなんとかするチームにいる。
……はずなのだけれど、もはや「サーバサイド」「ソフトウェア技術的」という但し書きすら怪しくなるくらい様々なことに手が出せているのでざっくりソルジャー上がりのなんでも屋って思っている。

この基盤チームやプロダクトチームなどの現在の組織に関する情報の一端はセキュリティインシデントと大規模障害を経てClassiは開発組織をどう変化させたのか - Classi開発者ブログに書いてもらえた。

チーム・機能横断の基盤システムの設計と開発

dron: クラウドネイティブなcron代替の紹介 - Classi開発者ブログ

(自分にとっての) 本業というかんじ。得意かつ求められているかつ好きなこと。

今のところうまくいっているけれどドメイン知識がまだまだ足りていないなーと感じている。ので後述するようにプロダクトチームに出向しはじめた。

開発者ブログの編集長業

決め手でも述べたように好奇心とその表出が強い人間が好きで、そういう人間が集まっていると自然とブログを書いたりといった活動が生まれると信じている。
Classiは2020年4月に高負荷インシデントが起きたりなどの事情があってアウトプットがすっかり止まってしまっており寂しかった。

一方で社内のesaには日々のサービス開発・運用で発見したことが想像以上に活発に投稿されていて、アウトプット自体はあったのは嬉しい誤算だった。
単に対外的に出していないだけでアウトプットに対する感度は決して低くなかった。

とはいってもこのままだと進展しないのも確かなので「復興させたいです」と手をあげていろいろやらせてもらった。

  • 編集部の立ち上げ
  • 公開スケジュールの段取り
  • ブロガーのスカウト

……など。

編集部は自分とVPoEでミニマルに立ち上げて今は3人体制。まず開発者ブログをどう位置付けるのかということを表明し、興味を持っている人やステークホルダーに判断しやすい環境を整えた。
向こう1〜2年のあいだは執筆者が不特定多数の社外の読者に自分たちの取り組みを過不足なく理解してもらうだけのアウトプットをするスキルを養うことを目的としその場として開発者ブログを整えるということにした。
採用や広報のツールとして活用するという視点は、少なくとも現時点では時期尚早かつ高度すぎるのでうまくいかないだろうと思ったのでスコープから外すようステートメントに盛り込んだ。なのでPVやSNSでの反響は主要なKPIとして見ないことにしている。

プロダクトチームに出向しての草の根活動

テックリードの相談相手になったり外様として「この会議の位置付けってどういうかんじでしたっけ」みたいなことを言ったり改善の意見を出したり、もちろん一緒にちょっとしたタスクをやったりといった本当に様々なことをやっている。

これは自分がプロダクト領域の知識を付けるという意味もあるし、いろんな環境・状況での開発経験がちょっとある人間としてチームに新しい視点をもたらすという意味もある。

11月くらいから始まって評価は上々っぽいけれど塩梅がむずかしいな〜と日々悩んでいる。自分がしゃしゃり出て改善できたとしても、きっとそれはチームの糧にならないだろうし、そもそもチームの状況・事情を咀嚼しなければ「正しいだけの正論」になるだろうし。
かといってチームに悪い意味で馴染みすぎたら役割を果たせないし、というかんじでとても難しい!
が、少なくとも自分はプロダクトの知識や事情のキャッチアップが進んでいるので成果は大きいと感じる。

自分の働きが効果を発揮できているかは、おそらく自分が出向をやめたあとでしか評価できないので今はあれこれ模索中。

事前の印象と変わらないところ・異なったところ

相対的に見て前職と比べて所属を明らかにしてオープンな活動をしている人は少なかったので印象らしい印象はそんなに強いものはなかったけれど、面接などを通して文化的背景がさほど遠くないと感じ、それは今も変わらない。なんというか落ち着きがあると思う。

印象的なのは社内外で開発組織のマネージャーやリーダー経験のある人が多いので、自分のようにマネジメント・メンタリングが得意じゃない人間でもそういう仕事をやっていてささいなアドバイスをもらえて孤独感を感じにくいし、リーダー・マネージャーポジション以外にそういう背景・キャリアの人がいるのは層が厚くて良いところ。

ギャップを感じているというほどではないけれど、プロダクトチーム制への変化はけっこうドラスティックで無理が生じているところも見え隠れしている。
まあこういうのはビッグイベントの当事者でなかった自分のようにMPを消耗させた経験のない人間がサポートしていくのが良いんだろうなと思うので、しばらくそこらへんを頑張りたい。

Google Formでお手軽に自分のヘルスチェックをしてみる

気分によってパフォーマンスが左右されるな〜と数年前くらいから自覚するようになり、自分の生産性とどういう相関があるのか・ないのかを知りたいと考えた。

生産性は普段の仕事のアウトプットで評価すれば良いだろうから、あとは気分を記録すれば良いだろう、ということで掲題の通りGoogle Formで手軽に始めていたことを思い出したので書いておく。

収集

f:id:aereal:20210106173225p:plain

Google Formで記録

こういう素朴なGoogle Formを作った。

  • 😀 良い
  • 😎 最高
  • 😑 感情なし
  • 😱 大変だった
  • 😇 大いなる動きの前では何もできないちっぽけな私

みたいなかんじ。

f:id:aereal:20210106173138p:plain

Slackで毎日リマインド

これをSlackで毎日リマインドする。数年前に素朴に作ったけれど、今だとSlack AppにしたらSlack上で完結して良いかもしれない。

収集と可視化

Google Spreadsheetsに送られるのでいろいろグラフを出してみた。

まず曜日によって傾向が変わるのかを出してみる。

f:id:aereal:20180404094950p:plain

曜日ごとのバブルチャート

縦軸が曜日で、1が日曜日、7が土曜日。

どうやら自分は尻上がりタイプらしいということがわかった。

 

またこの画像を保存した当時は水曜日と金曜日に厳しい気分になることが多いようだった。

確か厳しい定例ミーティングがあったのだったような。

f:id:aereal:20180404094955p:plain

期間での感情の割合

 期間全体だとこういうかんじ。こうしてみるとわりとまんべんなく現れており、感情の浮き沈みがはっきりしているといえそう。

 

カレンダーの予定と組み合わせての評価とかやったらおもしろそうだと今思った。

データの集計方法はあまりに素朴すぎるので改善の余地はある気がする。

2020の振り返り

去年

作ったもの

仕事

はてな

退職

株式会社はてなを退職 - Sexually Knowing

8月を最終出社日として退職した。来年から金沢に引っ越す。

退職する時に同僚からフィードバックをもらう - Sexually Knowing

今でもたまにもらったフィードバックを読み返すことがあるのでやってよかった。

新メンバーのメンター

4月に新しく入ったメンバーのメンターをやった。

メンター自体は何度も経験があるけれど、その時に辞意は固めていたこともあり自分の考えとか振る舞いとかを伝えるっていうことを意識してみようと思い、いろいろメンタリングのやりかたを変えてみた。

かなりまめに様子を見たり、正解のないものごとについて「自分はこういう風に考えている」ということを伝えることが多かった。 これまで価値観のインストールはメンタリングの範疇を越えていると考えて意図的にやってこなかったけれど、新メンバーが新卒ということもあり価値基準が確固たるものになっていない内から「あとはあなたの考えに基づいて行動してね」では突き放しすぎかなとも思いやってみることにした。

もちろん染まりきっていない新卒だからこそ、自分の一挙一動に染まりやすいので果たしていかがなものかという思いはあったけれども。

その他

AWS API Gateway HTTP APIを使って認証エンドポイントを生やしたりといった仕事をしていた。

チームメイトをつかまえてLambdaとかの知識を伝授したり、単に作る以上のことはできたと思う。

現職

AWSでちょっとしたシステムを作ったり、他のチームに出向いてDX改善おじさん業などをしている。

来年

最高のアーキテクトになる - Sexually Knowing

これかなあ。転職したので、新しい職場でちゃんと実績と信頼を勝ち取っていきたい。

ポジションを作る動きが1年後にできていたら良いかなあ。

あとは新天地で楽しく生活したい。

たいへんな仕事は仲間を募ると良い

重い仕事・比較的やりたくない仕事・とっかかりが見つからない仕事など、アサインされたけれどどうにもやる気が出ない仕事に出くわすことはしょっちゅうあると思う。

そういう時におすすめしたいのが「誰か一緒にやりませんか」とペアプロ・ペア作業相手を募集すること。

実際に一緒に作業することになれば:

  • 相手の作業時間を確保するので否応なしに向き合うことになる
  • 視野が広がる
    • 単純に他人の目が増える
    • またプレッシャーが減ることで自身の視野も良くなりうる
  • 作業効率が上がる
    • 単純作業がたくさんある場合なんかにはとても助かる

また、チームの状況がそれを許さない場合でも:

  • なんか大変そうだなというアラートが届く
    • だいたいアラートを上げるのが苦手な人は顔色を変えないことが多いので、周りからフォローしにくい
  • アラートをあげる心理的障壁が低い
    • 「つらいのでやりたくないです」と言える人はなかなかいないと思うし、言ったとして何かを失うリスクも高い
    • 「つらいので誰かと一緒にやりたいです」だとやりかたを変える提案なので言う側も受け取る側もそれなりにポジティブに捉えられる

というような話をチームメイトにした。

この考えは自分が独自に辿り着いたわけではなくて id:hitode909 さんが言っていたので影響された。 一緒に仕事していた時にペアプロ・ペア作業の効能について話した時だったと思う。

ブログに書いていなかったかな〜とあれこれ調べたけれど見つからないので書きました。 かわりに見つけたお気に入りツイートを置いておきます (そのエピソードの登場人物が「hakobeさん」だったはずなのでそれで検索した):

Twitterでつぶやいていたらhitodeさんが発掘してくれました:

blog.sushi.money

こちらも併せてご覧ください。また引き続きリリカルなのは大学のエピソードもお楽しみください。

Re: ネットワーク越しリトライ考

moznion.hatenadiary.com

  • サーバが脆弱という意味では弱者だけれども、一方でreadinessとかの豊かな情報が欠けているという意味ではクライアントもか弱い存在で、このミスマッチが根本的に問題を難しくしていると思う
    • 素朴なモデルだとクライアントは自身で完結して得られる情報からのみリクエストを制御しなければいけないけれど、サーバが許容できるかは個々のクライアントだけでは判断できないというのも難しい
    • クライアントにリトライを任せるというのもけっこう難しい話だと思っていて、クライアントはサーバに言わば計算機資源の外注をしたいことが多いはずで、リトライを重ねるとクライアントの資源も消費されていくっていうのも難しい
  • 利用者が、Web APIで言うSSKDsLSUDsなのかにもよりそうだけれど、メッセージを介してやりとりするアクターモデルにするっていうのが最もサーバが防御的に振る舞えると思う
    • メッセージブローカーにいわゆるサーキットブレイカー的な役割を負わせるかんじ
    • あるいはUDP的な、サーバが応答をしなくても良い = メッセージの到達不可能性を折り込んで、クライアントが常に悲観的に振る舞うっていうモデルもありそう。サーバではstrong consistencyは狙わない

ひどい目に遭いそうなところからテストを書く

blog.sushi.money

僕も最近は正常系から書くことが多いです。こうすると悪い設計に早く気付きやすいという利点があると感じています。 ここでは単体テストのような開発者向けのテストを想定していて、E2Eテストのようなテストでは必ずしも当てはまらないでしょう。

最初にテストを書く時には何も準備がない状態から始まりますが、その時にとても素朴な異常系から始まると整える事前条件が少なく済んで簡単に書けた、という体験になると思います。

そこからインクリメンタルに事前条件を積み重ねて、複雑なメソッドの動作を確かめていきますが、その場合の開発体験はコピペしつつちょっとずつ整えていくという風になり、都度の負担はそれほど高くならないでしょう。

一方、最初に正常系から書く場合、あらゆる事前条件を把握し、それを整えるコードを書く必要があります。

理想的に実装されたメソッドは、どちらの進め方であっても体験は大きく変わらないでしょう。 でも最初からうまくいくことは稀だしインクリメンタルに良くしていくためのハーネスとしてテストがあるので、ひどい時のことを考えます。 たとえば現在時刻に基づく計算をしているとか、ファイルシステムや外部のAPIに依存していてモックが必要だったりとか。

僕の感覚としては、素朴なケースから始めて徐々に重ねていくボトムアップのやりかたでテストを書いていくと、こういったテスタビリティの低い実装に対する感度が鈍るのではないかという仮説を持っています。

テストを書いていって大変だった度が同じ100のメソッドのテストを書くことを考えて、最初にあらゆる事前条件を把握して書く場合は100の大変だった度を感じることになる一方、ボトムアップだと10の大変だった度が10回繰り返されますが、総合的な大変だった度は異なるのではないか、ということです。

なので、最初にひどい目に遭う蓋然性の高いところから書くことで、これはまずい! という感覚を鋭敏に向けられるのでよりよい実装を得やすいのではないか、という意見です。

AWS CDKやGo関連で最近作ったものたち

cdk-dynamodb-expression

aereal/cdk-dynamodb-expression: DynamoDB expression builder for AWS CDK

AWS CDKでDynamoDBの式を書く時に便利なグッズ。

usageより:

import { DynamoAttributeValue } from "@aws-cdk/aws-stepfunctions-tasks";

    const builder = new ExpressionBuilder();
    builder.update`SET Executing = ${DynamoAttributeValue.fromBoolean(true)}`;
    const {
      updateExpression,
      conditionExpression,
      expressionAttributeValues,
      expressionAttributeNames,
    } = builder.aggregate();
    expect(conditionExpression).toBeUndefined();
    expect(updateExpression).toBe("SET Executing = :v0");
    expect(expressionAttributeNames).toBeUndefined();
    expect(expressionAttributeValues).toStrictEqual({
      ":v0": DynamoAttributeValue.fromBoolean(true),
    });

DynamoDBの式に属性の値をリテラルとして書くことはできず、プレースホルダを書き、プレースホルダと実際の値の辞書をそれぞれ与えるようになっている。

式に現れるプレースホルダは当然ユニークでなくてはならないけれど、シンボルテーブルの管理を自前でやるのもめんどうなのでtagged template literalを使うことで、式にそのまま値を埋め込んでいるような書き味なのがオシャレだと思う。

また、色気を出してプレースホルダの生成に使うカウンタをgeneratorで実装した。

go-dynamodb-attribute-conversions

aereal/go-dynamodb-attribute-conversions

AWS SDK for GoAWS Lambda for Goの間でDynamoDB関連の型に互換性がないので変換するライブラリを書いた。

AWS SDK for Goにはdynamodbattributeという便利パッケージがあることに最近気がついて、たとえば UnmarshalMapmap[string]*dynamodb.AttributeValue をstructにUnmarshalしてくれる。 DynamoDBのO/Rマッパを意識したライブラリは世にいくつかあるけれど、個人的な用途ではこれとdynamodb/expressionというDynamoDBの式を組み立てる便利パッケージがあれば十分だと感じた。

ところでAWS Lambda for GoはLambdaのハンドラを書く時に便利な型も提供している。 eventsパッケージ以下にあるのがそれで、CodeBuildやKinesisから呼び出されるペイロードの型が定義されているので、それらを購読するLambdaハンドラを書く時はこの定義を使うと便利。

その中にもちろんDynamoDB Streamsを購読する時の型も定義されているけれど、これと前述のAWS SDK for Goの型に互換性がない。 なので、Streamsを購読して何かするLambdaハンドラを書く時に、ペイロードにやってきたアイテムを構造体にUnmarshalする時にAWS SDK for Goの型に直さないといけない。

一対一対応しているので実装は大変ではないがちまちましているし、けっこうありがちなパターンっぽく、かつAWS Lambda for Goの型をSDKに寄せるP-Rは2年以上動きがなく、コメントのやりとりを見てもwon't fix感が漂っているので書いた。

go-httpretryafter

aereal/go-httpretryafter: Provides functions to parse Retry-After header.

Retry-Afterヘッダをパースして再試行して良い time.Time を返す関数を提供するライブラリ。

GoでHTTPリクエストを良いかんじに再送するライブラリはいくつかあるけれど、どれも一長一短で用途に合わなかったのでリトライ処理は自前で書くことにした。

そのためにRetry-Afterの仕様を調べたところ、実は絶対時刻と相対時刻の両方が指定できるので、これはアプリケーションの中で実装するにはちょっとめんどうだなと思い外に出した。

aws-cdk-apigw-documentation

aereal/aws-cdk-apigw-documentation: Collection of constructs for API Gateway Documentation parts.

AWS API Gateway v1のREST APIにはDocumentation PartというOpenAPIに準拠した追加のドキュメンテーション情報を与えることができるのだけれど、これのAWS CDK Constructsがないので書いた。

Documentation Partについてはちょっと前のメモもどうぞ: AWS API Gatewayのdocumentation partに関するメモ - Sexually Knowing

関係ないけれど命名規則がけっこうぶれている。aws-cdk-なのかcdk-なのか。

やたらと短いエイリアスは使わない

Gitもシェル (zsh) もよく使うコマンドをエイリアスとして設定して任意の入力で呼び出すことができる。

このエイリアスについていくつか派閥があると感じていて、おおまかには:

  • エイリアスをまったく使わない
  • 入力の手間を減らすため極限まで短いエイリアスを使う
  • よく使うコマンド・オプションの組み合わせに説明的な名前をつける

……という派閥に分類できると思う。

自分は3つめの「よく使うコマンド・オプションの組み合わせに説明的な名前をつける」に属する。

短いエイリアスへの苦手意識

衝突しないようエイリアスを管理するのがだるい

エイリアス名前空間を通常のコマンドと共有しているので、それらと衝突しないよう管理しなければいけない。

短い名前を設定しても思い出せない

よく使うコマンドなら手癖で打てるだろうけれど、ごくたまにしか使わないコマンドのごく短いエイリアスを思い出せる気がしない。

これはエイリアスではない通常のコマンドでも起きるけれど、コマンドは検索なりすれば出てきて辿れるのでリーチできるが、エイリアスの場合は検索しても出てこないので死にエイリアスになったままになりがちという問題があると思う。

これはシェルやGitの設定でコメントを書くとか

誤爆のリスクが高まる

たとえば grgit reset --hard HEADエイリアスしているとして、 grep と打とうしたが誤って gr でエンターを押してしまって誤爆すると悲惨なことになる。

危険な操作にエイリアスをつけるなとか、いろいろ突っ込みどころはあるが、操作者に責任と自由が委ねられているシェルにおいてわざわざ危険な操作を実行する敷居を下げることもないなと感じている。

検索性が低い

シェルのヒストリ検索は文字列の部分一致で行うのが常なので、ごく短い文字列にしていると発見しづらい。

これは技術的に挽回する余地はあると思うけれども、後述するように長いが説明的な名前をつけて、それを検索しやすくするというほうが技術のテコをきかせやすく総合的に生産性が高まると感じている。

説明的な名前をつける

特にGitの操作はやたらと難しいので自分でいろいろエイリアスを作っている。たとえば:

  • git cp: git cherry-pick
    • ファイル操作のメタファーになぞらえて
  • git interactive-rebase, git continue-rebase, git abort-rebase: それぞれ git rebase --interactive, git rebase --continue, git rebase --abort
    • git-rebaseはinteractiveとそれ以外でかなり性質の異なるサブコマンドだが1つに押し込められておりかなりヤバい設計になっている
    • 区別しやすくなるだけではなく、先頭一致で検索する際にサブコマンドの先頭を分けることで誤ったrebaseのオプションを選ぶことを防ぐ意味がある
      • git rebase まででC-pすると git rebase --continuegit rebase --abort も候補に含まれるが、 git cont を入力してC-pすると git abort-rebase が候補に出てこない

など。

そもそもGUIを使えばっていうのはごもっともだと思うけれど、なんだかんだ複雑であまり整然としていないと批判されることの多いGitのCLIも覚えておけばリポジトリの統合とか凝った操作をする時に役立つことがあるので、そこは妥協している。

組織をプロダクトと捉えてみる

  • ※組織の話は詳しくないので自信はないけれど、こう思ったという話を書きます
  • ※現在の所属組織の社内ブログに書いた内容を一部修正して転載しています

プラットフォームのプロダクトマネジメント

メルカリのSREであるdeeeetさん (eは4つ) のこの記事が良かった: 社内PlatformチームのProduct Management | SOTA

直接エンドユーザーに面しないプラットフォームであってもプロダクトマネジメントの基本的な考えや方法論を適用し「ちゃんと」やっていく話と、エンドユーザー向けのプロダクトマネジメントと異なるビジネスとのバランスの話が挙げられている。 参考となる書籍やページがたくさん挙げられているので、おすすめ。

特にどのような優先度がやるかについて紹介されていた方法が自分にとっては初見で有益だったので紹介:

大きなタスクの分類としては左から「User asks」「Platform quality」「Long term key initiatives 」が挙げられる.それぞれの意味は以下.

  • User asks: 開発者の問題を解決するタスク
  • Platform quality: Securityや技術的負債などPlatformの質を担保するタスク
  • Long term key initiative: 長期的な投資のためのタスク

Will Larsonはこれらを40:30:30でバランスをとるのが良いとしている.自分たちは完全にこの比率に沿っているわけではないが分類を含めて参考にしている.

40:30:30の根拠は原文を読んでいないのでよくわかっていない。あとで読む。

他の指標としてBusiness, ROI, SLOが挙げられている。これはまあ普通なかんじ。

組織をプロダクトとして捉えてみる

Developer Experienceがバズワードしていった流れは、作るものが複雑になってきて成果の精度や価値を左右する要素として過程の改善が占める割合が小さくない・投資効率がそれなりに高いと認知されてきたからだと思う。

古くはアジャイル開発を始めとして、最近ではソフトウェアエンジニアリングと組織開発の両方に立脚して意義や効果を説いたという点では広木さんの『エンジニアリング組織論への招待』も挙げられる: エンジニアリング組織論への招待 ~不確実性に向き合う思考と組織のリファクタリング

これらの背景から組織をプロダクトとして捉えると、改善の進め方やうまい機能のさせかたは実は身近なところから応用できるのかもしれないと考えた。

たとえばプロダクトを開発する部署の顧客は誰だろうと考えると:

  • 経営者:競争力のあるプロダクトを速く正しく作る実行力を提供する
    • 主要な結果の例: 設定した稼動率目標の達成、競争力の獲得
  • プロダクトを開発する部署の各メンバー: 知的好奇心を満たすに足る場や業界で生き残る知識・スキル獲得の機会を提供する
    • 主要な結果の例: 昇給

……など。

同様にプロダクト開発の考え方を適用すると、自分の所属の開発部署をどう変えていくかというロードマップを敷くのは未だできていないことで効果が見込めることかもしれない。

Roadmapを作る意義は大きく2つある.まず開発チームからするとどのような機能がいつ頃利用可能になるのかが明確になる.(略) 次にPlatformチームのメンバーからすると今後何を作るかが分かるため,実装時の意思決定の助けになる.「3カ月後にこういうことをやります」と分かって書くコードと、知らないで書くのとでは全然違う.「次にこうするから今はこういう実装をしておけばOK」といった意思決定ができるになる.

以下の優先度の話にもつながることだがRoadmapを作るといかに「やれることが少ないか」が分かる.(略)

https://deeeet.com/writing/2020/10/07/internal-platform-product-management/ より。

組織とプラットフォーム (基盤) は、提供者と受益者の関係性が二面的であったり曖昧であったりする点に共通点を見出すことができる。

上記例では各メンバーを顧客としたが、同時に開発部署を作るのも各メンバーであって、どちらかのペルソナだけを持つわけではない。 これは社内プラットフォームにも言えて、開発者と利用者が完全に分断されているケースのほうが珍しいだろう。

個人のキャリア形成という文脈では受益者という立場が強く出るだろうし、マネージャーに近い役割を負う人は提供者という立場の割合が大きくなることが想像できる。

ロードマップがあれば、近い内に解決が難しい問題に直面した時に実は3ヶ月後なら変わる芽がありそうだとか、しばらく解決は難しそうだが積み上がっている課題を見れば納得感はあるのでバックログを片付けることに協力しようとう気持ちになるなど、そういったコミュニケーションをとれる人が増えないだろうか。

また人事評価 (MBO) とは独立して、かつ人事評価の単位より長い時点までのロードマップを立てられると、人事評価のようなモノリシックなシステムを変えることなくメンバーにより遠い未来について思いを馳せる機会が与えられるかもしれない。 それは視座の上昇の機会となり、自己組織化を促すきっかけにならないだろうか。 リーダーであるための視野・視座・視点 - Tech Inside Drecom

正しく作る

という話に還元されそうなので未読の以下を読みたいと思います:

正しいものを正しくつくる プロダクトをつくるとはどういうことなのか、あるいはアジャイルのその先についてn

まとめ

  • 冒頭に挙げたdeeeetさんのエントリは良いことが書いてある
  • 組織運営も同様にプロダクトマネジメントの手法やベストプラクティスが応用できないだろうかと考えた
  • その考えに則ると、ロードマップの策定は効果が見込めるのではないか

AWS API Gatewayのdocumentation partに関するメモ

Documentation part

AWS API GatewayREST APIはOpenAPIに準拠したドキュメントの生成もサポートされている *1

API GatewayREST APIはリソースやメソッドなどの部品から成る。特別な定義なしでも、これらAWS上のリソースが持つ各種プロパティからデフォルトでまあまあ良い感じのドキュメントは出力される。
しかしデフォルトではOpenAPI 3が必須とするいくつかのプロパティ *2 が出力されなかったり、実用的なAPIドキュメントに含めたい内容が欠けていたりする。

API GatewayREST APIの各構成部品に対して追加のドキュメンテーション情報を持つことができ、それらはdocumentation partと呼ばれる。
refs. Documenting REST APIs - Amazon API Gateway

location

documentation partのインスタンスは自身がAPI, オーソライザー、リソース、メソッド、などどの部品に対するドキュメントなのかを指す情報としてlocationを持つ。
refs. Location of a documentation part - Representation of API documentation in API Gateway - Amazon API Gateway

locationは各部品ごとに必須・利用可能なフィールドが異なっておりValid location fields of DocumentationPart - Representation of API documentation in API Gateway - Amazon API Gatewayにまとめられている。

properties

documentation partはpropertiesという任意のオブジェクトを持つことができ、これがOpenAPI spec.に現れる。

このpropertiesはOpenAPI spec.に準拠していないといけないとドキュメントでも言及されている。
refs. Content of a documentation part - Representation of API documentation in API Gateway - Amazon API Gateway

即ち仕様で定められたプロパティか、あるいは x- で始まる任意の拡張プロパティのみが使える。

invalidなプロパティはAPI Gatewayによって無視され出力に含まれない。

実体への対応

どうもdocumentation partは対応する部品の実体なしにエクスポート結果には現れないようだった。
これは公式ドキュメントの記述を引いたわけではなく、挙動からの推測になる。

HTTPメソッド定義がなければそれをlocationに持つdocumentation partが現れないというのは想像しやすいけれど、自分はパスパラメータのdocumentation partが出てこなくてしばらくハマった。

現時点ではパスパラメータのdocumentation partはrequestParametersに含めないと現れないようだった。
これは恐らくクエリパラメータやヘッダについてもそう言えると思う。

documentation version

ここまでで定義してきたdocumentation partを反映するには新しいdocumentation versionを発行しなければならない。
APIドキュメントの版を指し、新しい版が最新のdocumentation partを含む。

documentation partだけCloudFormationなどで定義してもdocumention versionを新しく作成しなければ参照できない。

*1:公式ドキュメント中ではエクスポート, exportと表現される

*2:たとえばリソース定義中のパスパラメータ

ISUCON 10の予選に参加しました

id:masawadaid:side_tanaと一緒にはやいTシャツ屋さんで参加しました。初期スコアが最高スコアでした。察してください。

チームでやった主なこと:

  • New Relicの導入
    • Web Transactions
    • SQL
    • Logs
  • デプロイ自動化
    • デプロイするたびにNew Relicのdeploymentsを打つ *1
  • MySQL 8化n
  • estateのlongitude/latitudeをgeometry型にする
  • ☆searchEstates/searchChairsをやっつける
  • もろもろインデックス貼る
  • アプリ複数台構成へ

コミュニケーション

Slackで事務連絡、Scrapboxにメモ、Hangoutで会話という体制にした。Hangoutは繋ぎっぱ。

Scrapboxに予選ページを作ってそこで30分ごとのイテレーションで進捗確認と次のタスクを確認した。

f:id:aereal:20200914112003p:plain

1時間だとおよそ8回しか回せないけれど30分だと16回あるので「これ前回も共有してからハマっているな」って自覚できるタイミングが理論値では30分はやくなる。 実際、「これ前も共有しているからヘルプしますか? まきとりますか?」みたいな会話は何度かできた。

New Relic

ISUCON 9の問題を事前に解く練習をしてその時にNew Relicを試して良かったので今回も使った。

なので我々はalpを使わなかった。pt-query-digestは詳細な分析に使うくらい。複数台構成も睨まれていたので、ログもNew RelicのLogsに集約させた。

alpとかを使うのに比べてレイテンシはまああるし、X-RayGoogle Cloud Traceと比べても遅い。これは集計にかかっているらしい。

それでもタイムアタック競技のISUCONでなぜ選んだかというと、パーマリンクを共有できることと差分の比較が楽という点が魅力だったから。

今回はリモート参加で3人全員別の拠点におり、ぱっと画面を見せたりということが難しいのでパーマリンクができてSlackやScrapboxにスッと貼れるのは便利。

あと時系列で変化を見られると、この変更が効いて速くなったねとか一目でわかる。

特に便利だったのはLogsで、これは仕事でもよくあることだけれど「こういうログが出ていました」「タイムスタンプが見たいな (削らないで!)」「スタックトレース出ていない? (削らないで!)」「どのホスト? (書いて!)」みたいなやりとりはけっこうしたことがあって、複数台で動かすとなるとこれが面倒そうだなと思っていた。 LogsはWebのコンソールに集約されるのでリンクを貼ればメンバーに過不足なく共有できるのが良い。

別途デーモンを立てないといけなくはあるけれど、まあさして大変ではなかったし最後に止めてしまえばパフォーマンス影響はないしでよかろうと思った。

ちなみにファイルに書き出すようにしたのでlogrotateどうしようか一瞬悩んだけれどデプロイごとに : > /var/log/app/isuumo.log して空にすればいいかと思った。妥当な判断だったと思う。

blog.sushi.money

MySQL 8

geometry型にできるとか最新は正義でしょっていうことで選んだ。ただ、最初にコード読んだ時はGISか?!ってびっくりしたけれど、声に出して自分たちはMySQLでいくよねって確認をした。

MySQL 8へのアップグレードやgeometry型への書き換えはid:masawadaがやってくれてめちゃくちゃ頼もしかった。 感想部屋ではbind-addressとかユーザーの接続元情報とかでハマって外から繋げられなかった人もいたっぽいけれど、裏番組で本人に聞いていたら「ハマると思ったので初手でやりましたね」って言っていてかっこよかった。

反省点としては事前の練習時にはMySQLが使われたなら8に上げようって話をしていたので変更点についてちゃんと勉強しておくべきだった。 descending indexとかパラメータとかについて調べておくべきだった。

DB2台構成に至らなかった

のがこのスコアの根本的な原因だねーって話をチームメイトとした。

searchとか改善しても焼け石に水のようなスコア上昇しか見られなかったけれど、後から振り返ると順番が逆だったんだろう。しかし間違えてしまった結果「ここは意味がないのか?」「きっと複数台構成にすれば早くなるはず」と間違った推論をしてしまい深みにはまってしまった。 間違った前提からは間違った帰結しか得られないとはこのこと。

なんというかサービスを改善するっていう意識が低くてISUCONをやるっていう意識に支配されていたなあ。

各ホストのメトリック中止がおろそかになった

New Relic傾倒の余波なのかもしれないけれど、アプリケーションメトリクスはつぶさに見れたと思うが、各ホストのメトリクスはきちんと見れていなかった。

象徴的なのがinnodb_buffer_poolを贅沢にしすぎて終盤にDBがOOMで死んだこと。あとからインフラメトリクスを見ると枯渇気味だったことは一目でわかった。

これは普段ではできていることなので、良くも悪くも道具に使わされたということなんだろう。New Relic, 便利ではあったのでちゃんと手にしたい。

感想

コードを見た時に「短い! 把握できる!」「テーブルが2つしかない!」「外部へのHTTP通信ない! ほんとに?」「なぞって検索、スコアリングに影響しないのにちゃんと作られていてすごい」と今まで見てきた問題のどれよりもコンパクトでありながら歯応えがあって取り組んでいて楽しかった。 それだけにこの結果はすごく悔しい。

特にDB2台構成に舵を切る判断ができなかったのは決断力の甘さと場数の少なさを痛感させられる。

問い合わせの仕組みとかリアルタイムにスコアが増えるベンチマーカーとか予選ポータルのもてなしが充実していたりと、最大級の規模でありながらすばらしい競技体験が得られたのは一重に運営のみなさまの尽力あってのことだと思います。ありがとうございます。

次は予選突破するぞ。

*1:実際にはアプリIDを間違えていて今回は使えていなかった

AWS CDKとは何か、IaCの変遷を踏まえての紹介

概要

これまで業務・プライベートの双方でAWS CDK (Cloud Development Kit)というInfrastructure as a CodeツールをDeveloper Previewのころから着目し利用してきたので、その特徴を競合と比較しながら説明します。

概観を掴んでもらうことを目的とするので詳細は外部の公式・非公式のドキュメントへ適宜リンクするかたちをとります。

想定読者

  • AWS CDKが何かよくわかっていない人
    • CloudFormationとの違いがわかっていない人
  • IaCに興味がある人

前提・背景

AWS CDKの特徴を説明するためにIaCの変遷について簡単に言及したく、そのためにはWeb開発におけるインフラの変遷に触れる必要があります。

結論から言うと 現代においてインフラとアプリケーションの境界は非常に曖昧 で、比較的はっきり別れていた時代に定義・設計された IaCの概念や実装から進化した存在が必要 であるという考えに応えて登場したのがAWS CDKです。

以下に書く話はデプロイ今昔 - Hatena Developer Blogがよくまとまっているのでそちらを読むのが早いかもしれません。 もう少しインフラにフォーカスして書きます。

ペットと家畜

インフラとアプリケーションがはっきり別れていた時代では、インフラのライフサイクルとアプリケーションのライフサイクルが異なっており、インフラリソースの制御がほとんどすべてユーザーの手にありました。

アプリケーションの生まれ変わり = デプロイよりインフラの方が大抵長生きするので、インフラが必然と状態を持つ、そんな時代です。 サーバーがペットや家畜として扱われていた時代という比喩もあります。

また、インフラの制御がユーザーの手にほぼあるということは、プロバイダーは何もしてくれずユーザーが管理しなければ壊れたり動かないといった管理コストの裏返しでもあります。 まず仮想マシンの調達と在庫管理からユーザーを開放したのがAWS EC2のようなIaaSサービスです。

マネージド化

長じて、コンテナオーケストレーションサービスやサーバレスサービスが登場します。これらをまとめてクラウドプロバイダーによる進んだ資源管理が行われることをうけてマネージドサービスと称することにします。

これらのサービスはコンテナ技術や進化した仮想化技術を利用しアプリケーションに設計上の制約を与える一方で意欲的なインフラの隠蔽を行うことで、クラウドプロバイダー側が最適化を行う余地を広げました。 ここでいう最適化とは、アプリケーションが利用されていないあいだは計算機資源を開放してコストを抑えることであったり、突発的な利用の増加に複雑な事前準備なしに対応できるよう計算機資源を用意することであったり、あるいはクラウドプロバイダーがより簡素・柔軟なデプロイメントを設計しDX (Developer Experience) を向上させることであったりします。

コンテナオーケストレーションサービスの代表例はAWS ECS (Elastic Container Service) やGKE (Google Kubernetes Engine) などが、サーバレスサービスの代表例にはAWS LambdaGoogle App Engine (GAE)などが挙げられるでしょう。

アプリケーションとインフラの漸近

マネージドサービスがアプリケーションに与えられる制約は様々で、コンテナ技術のようにシステムコールや計算機資源へのアクセスがスーパーバイザに隠蔽・管理されることであったり、AWS Lambdaのように利用できるランタイムに限りがあることであったり、様々です。

インフラがユーザーの管理下にあるケースでは、たとえばCPUやメモリをよりヘビーに使いたければサーバーを増強したり、たとえばアプリケーションのランタイムにPythonを使いたければサーバーにインストールしたりすることで、インフラがアプリケーション側に寄り添わせる柔軟性がありました。 設計の主導権はアプリケーションに多くあったといえそうです。

一方で、インフラ = 計算機資源にはいくつかのハードリミットがあり制約条件たりえました。 用意できるCPUやメモリのスペックに現実的な上限があったり、単位時間あたりに用意できる数が限られていたり、様々です。

また、必要なライブラリを揃えるプロビジョングやアプリケーションを実行可能な配置を行うデプロイメントは、インフラ (OS, ミドルウェア, etc.) による制約や要求が生じますが、アプリケーションと異なるレイヤと規定され分断されがちでもありました。

あるインフラ上で動かすのが非常に手間であったり非効率なアプリケーションを生むケースもありえたでしょう。

サーバレスサービスなどマネージドサービスではアプリケーションに制約をいくつか与える代わりにそれら分断を埋め開発からデプロイメントまで包括的なツールや体験が整備されていることが期待できます。

ここまでのまとめ

  • EC2などIaaS時代までは、インフラとアプリケーションは分断され、ツールもそれぞれの世界で独自に設計されていた
  • マネージドサービスではインフラとアプリケーション双方に制約を与えるかわりにスケーラビリティなど包括的な体験が提供されるようになった

AWS CDKとは

AWS CDKはAWSが開発しているツールセットでCloud Development Kitの略です。 便宜上IaCと呼びますが、インフラに限らない開発キットを志向していることは明らかなので、以下に示す競合との比較も厳密には同じレイヤとはいえず比較として不十分・不適切とも捉えられますが、わかりやすさのためにあえて比較します。

AWS CDKは:

  • L1 layer: CloudFormationのリソース定義に一対一で対応するクラス群
  • L2 layer: CloudFormationのリソース定義を包みユーザーフレンドリーなAPI (intent-based API) を提供するクラス群
  • patterns: 1つのクラスが複数のサービスのリソースを包括的にプロビジョニングするクラス群

……の、3つの層から成り立っています。 refs. Constructs - AWS Cloud Development Kit (AWS CDK)

L1 layer

L1 layerはCloudFormationのリソース定義からコードが自動生成されます。 L2より上位の階層のクラス群はより下位のクラス群を利用しています。言い換えるとCDKが提供するCloudFormationに関わるクラス群は最終的にL1 layerを利用し、CloudFormationの変更適用に還元されます。 基本的にCloudFormationでできることはCDKでも実現できると捉えてよいです。一方でCloudFormationに存在するハードな制約を越えることはできません。

L2 layer

CloudFormationはAWSのリソース設計に強く根ざしリソースのあるべき状態を宣言すれば差分の適用を任せられるサービスですが、宣言的な設計のために生じる様々な要求・制約が絡み、ひとつのリソースをプロビジョニングするのにも慣れが必要な癖の強いサービスでもあります。

たとえばあるIAMユーザーにだけS3バケットへのアップロードを許可したいという目的を達成するために必要なCloudFormationのリソース定義は AWS::IAM::User, AWS::IAM::Policy, AWS::S3::Bucket などに渡るなど人間の思考から離れたリソース設計を見つけ適切な設定を与える必要があります。

また、各リソースの意味論レベルで実現が難しい制約は実行時に検証されることも多いです。 たとえばある設定Aはある設定Bがtrueであることを求めるが、それは実行してみるまでわからない、など。

こうしたCloudFormationの難点に対してまず設計されたのがL2 layerです。 たとえば上記で例にあげた「あるIAMユーザーにだけS3バケットへのアップロードを許可する」ケースでは以下のようなコードで済みます。

import { Stack, App } from '@aws-cdk/core'
import { Bucket } from '@aws-cdk/aws-s3'
import { User } from '@aws-cdk/aws-iam'

const app = new App()
const stack = new Stack(app, 'buckets')
const uploader = new User(stack, 'Uploader')
const bucket = new Bucket(stack, 'FilesBucket')
bucket.grantRead(uploader)

Bucket#grantRead を呼べばいい、非常に人間がやりたいと望んだことにほぼ対応するAPI設計ではないでしょうか。

patterns

最後にpatternsです。これはL1/L2 layerのクラス群を1つ以上包みAWSのサービスでよくあるパターンをカプセル化したクラス群です。

たとえばApplicationLoadBalancedFargateServiceというECS FargateのサービスがALBの後ろにいるというのは典型的なパターンですが、 ApplicationLoadBalancedFargateServiceインスタンス化するだけでALBやターゲットグループ、リスナー、クラスターやタスク定義、サービスなどなどにプロビジョニング・動作に必要十分なデフォルト設定を備えたリソース定義が与えられます。

慣れれば楽ですが、慣れるまでに数え切れないトライアンドエラーを要するCloudFormation. 特に複数サービスにまたがるベストプラクティスは情報ソースを見つけるのにも一苦労だったりします。 上記例だと情報がECSのドキュメントにあったり、ALBのドキュメントにあったり、などなど。

patternsレイヤはよくあるパターンに名前が付けられパッケージ化されているので、たとえばECSに関するよくあるパターンを手軽に使いたいと考えたらaws-ecs-patternsを見に行けば望むものが見つかるかもしれないというアフォーダンスを与えてくれます。

もちろん複数のリソースに良いかんじのデフォルトを与えてくれるということは、デフォルト設定が自分たちのユースケースにフィットするかきちんと読み解くことが求められます。 手放しにこれを使うべきというより、ベストプラクティスがコード化されていること・それを読んで必要な知識への参照を得られることが本質的に重要でしょう。

モジュール化と再配布

AWS CDKはコアがTypeScriptで書かれNPMパッケージとして配布されています。TypeScriptが第一級のサポート対象言語ですが、PythonJavaへも移植されています。 refs. Translating TypeScript AWS CDK code to other languages - AWS Cloud Development Kit (AWS CDK)

いずれにせよ既にパッケージシステムが確立したエコシステム上で提供されていますし、AWS CDK自体がそうであるように自分たちがCDKを利用して作ったクラスや関数をNPMやその他のパッケージとして配布するのに特別な労力は要りません。 NPMパッケージならTypeScriptで書いて、型定義とトランスパイルされたJavaScriptのコードを成果物に含めるだけです。

きちんと動くパッケージシステムを作るのは存外に難しく、無闇にパッケージシステムを独自開発しても成熟したものに比べてうまく動かず利用者に負担を強いたりdependabotやrenovateのようなSaaSのサポートが受けられず不便であったりします。 過去のバージョンのアーカイブを参照できたり、脆弱なバージョンを非公開にしたり、改竄されていないか整合性を確認する手段を提供したり、などなど、パッケージシステムに求められる要件は多岐に渡ります。

その点でCDKは独自開発せずに既存の成熟したシステムにうまく乗っており、この点でCDK固有のフラストレーションを抱えることはほとんどないでしょう。

実例

たとえば前職ではステージング環境や開発用途のアプリケーションなどを社内の人間のみに公開する用途にG Suiteのメンバー一覧から作られたCognitoのユーザープールとそれを使って認可するリスナールール類を社内モジュールとしてメンテナンス・提供しました。 用途によって社員のみ・アルバイトを含むユーザープールなどを選ぶオプションを提供しました。

これを実現するためには認可されたユーザーが特定のグループに所属しているかG SuiteのAPIに問い合わせる必要があり、このモジュールはそれを実現するLambdaのコードも含みます。

単にCloudFormationのテンプレートを配布するだけではなく付随するリソースも含められる点が、競合と比べてCDKが傑出している点であり、それをうまく活かしている例に挙げられるでしょう。

競合との比較

AWS CloudFormation

基本的にCDKはCloudFormationの上位互換と捉えてよいです。即ちCloudFormationでできることはすべてCDKで実現できると捉えて問題ありません。

CDKはchangesetを作成→実行というCloudFormationのベストプラクティスが cdk deploy というコマンドひとつで実現されているほか、 cdk diff でスタックとテンプレートの差分を表示できるだけではなく、 cdk synth でCloudFormationのテンプレートを出力できるなど、ワークフローにおいてもCloudFormationを包括しより使いやすくしてくれます。

CloudFormationがフィットするケースにおいては、CDKの検討を強く勧めます。

SAM (Serverless Application Model)

ベストプラクティスや典型的なケースをより使いやすくするという思想は似通っています。

SAMはCloudFormationのテンプレート変換として実装されており、SAMに精通しているメンバーがいない場合はCDKを勧めます。 CDKはL2 layerのコードを見たり cdk synth コマンドでどんなCloudFormationテンプレートが適用されようとしているか静的に確認できます。

SAM localなど周辺ツール群はCDKのスコープにないのでそれらは別途利用しても良いでしょう。

Terraform

Terraformはレイヤや設計としてはCloudFormationの直接的な競合ですが、IaCという括りで比較してみます。

抽象度の点ではTerraformよりCDKの方が高いです。一方でTerraformはAWSに限らずGCPなどのクラウドプロバイダーではなくGitHubなどのWebサービスのリソースも管理できます。

特定のクラウドプロバイダーと結びついていないことは柔軟な機能にも繋がっており、コード上で管理していないリソースをインポートしてさも最初からコードで管理されていたかのように扱える terraform import は早いうちから実装されており便利です。 ちなみにCloudFormationでは2019年11月に既存リソースのインポートがリリースされました: 新機能 – CloudFormation スタックへの既存リソースのインポート | Amazon Web Services ブログ

GCPなどAWS以外のリソースも扱う場合はTerraformを使うのがベストです。

一方でCDK for TerraformというバックエンドをTerraformとしたCDKも開発・リリースされています: CDK for Terraform: Enabling Python & TypeScript Support 日本語記事: AWS CDKでプロバイダーとしてTerraformが使える!!CDK for Terraformが発表されました!! #awscdk | Developers.IO

また同様にKubernetesのリソースを管理できるCDK for Kubernetesもリリースされています: Introducing CDK for Kubernetes | Containers

このようにCDKの基本的な概念は他のIaCプラットフォームにも拡張可能ということがDeveloper Previewとして示されており、比較的安定しつつあるCDKでこれらの体験に触れることは今後を見据えればポジティブではないでしょうか。

まとめ

  • CDKは、インフラとアプリの関係性の変遷に応じて生まれた新しいツールキットです
  • 単にインフラリソースを管理するだけではなく、クラウドプロバイダのサービスをあたかも外部モジュールのように扱う設計が特徴です
  • しかもTerraformやKubernetesへの展開も進みつつあり、既存のIaCから拡張された普遍的な概念にもなりえそう

付録: 筆者とAWS CDK

speakerdeck.com

AWS Cloud Development Kit -CDK- Meetupというイベントで新サービス開発にAWS CDKを採用した事例とその特徴について発表しました。上記スライドはその時の資料です。

またaws-cdk · GitHub Topicsにこれまで公開してきたAWS CDK関連のライブラリやリポジトリがあります。