selmertsxの素振り日記

ひたすら日々の素振り内容を書き続けるだけの日記

【PO編】PO&SMをやめるので過去の学びをアレコレ書いてく

背景

  • 2年間くらい PO & Scrum Master とソフトウェアエンジニアを兼務したり色々あった
  • この度、ソフトウェアエンジニアに集中できることになった
  • せっかくなので、忘れる前に ( もうたくさん忘れたけど ) 書き出すことにした
  • この記事は、未来の自分が思い出すための記事である

全般

絶対に兼務しない

  • これだけ兼務まつりしてて言うのもあれだが
  • POに集中する期間は、SMとエンジニアとしての貯金が減ってるのを感じ
  • エンジニアに集中する期間は、POやエンジニアとしての貯金が減ってるのを実感する
  • 兼務状態は、常に何かしらの貯金が減る不安を抱えながら仕事することになる
  • スーパーマンでない限り、1つ1つのクオリティが落ちてしまい、よしんばなんとかなっても「なんとか破綻しない」程度になる
  • うまくいったとしても9割のケースは、誰かが荷物を持ってくれたから
  • なので 成功ケースだけを見て「兼務いけるやん」と思ってはいけない
  • 自分がうまくいった経験があったとしても「誰かのフォロワーシップに助けられただけ」 という意識を忘れてはいけない

Product Management 領域

仕事のほとんどは組織のチェンジマネジメント

  • Product Management の仕事。と考えると、顧客ヒアリングをして、市場調査して、仮説建てて、プロトタイプ作る。そんな感じの面白い仕事を想像してしまう。
  • だけど、それは仕事の中のほんの一部でしかない
  • プロダクトが変えるのは、顧客の業務だけでない。自組織の仕事の仕方も変わる
  • 顧客・自組織を問わず、業務のASIS/TOBEを描き、変化の過程を設計し、信頼を獲得し、プロダクトのために変化させていく
  • 現状を適切に把握する上で、自ら営業として現地に行ったり、CSとして電話を取ったりすることもある
  • いつも慣れない領域に飛び込まねばならないので、ストレスフルなお仕事になる
  • けど、コンフォートゾーンにいるだけではまともな結果は出せないのでやるしかない

新しいソフトウェアじゃなくて新しい業務を作る

ベストプラクティスはWeb系企業で育まれている〜三菱重工業のDXを支える学びの姿勢〜 川口賢太郎、森岡周平(三菱重工業株式会社) | エンジニアの生き様をウォッチするメディア

仕事の大部分でPCを使わないような人達に、ソフトウェアの力で価値を届けていくという難しさがあると感じています。ただ、それこそとても挑戦しがいのある課題だと捉えています。

  • 昔、インタビューの中でこんなことを言った
  • これは今でも重要だと思っている
  • 顧客とソフトウェアのタッチポイントが多ければ多いほど、作る機能が増える
  • コード量、バグの可能性、顧客の負担、不満を言われる可能性も増える
  • ドリルと穴の話で、最高のドリルをつくるばかりに意識を向けず
  • 「穴を最小のコストで開ける」ってことに意識を向けたい
  • 顧客の利益を最大化しつつ、サービスとのタッチポイントを最小化することが重要
    • 例えば画面作らなくても、メールで済むものはそれで終わらせるとか
  • そのために、顧客の既存業務をしっかり理解し、ASIS/TOBEを描き、TOBEに至るまでの過程と、その都度のサービスのあり方を考えることが重要

ニーズが表面化するまで解決しない。でも準備はする

  • 「データが1万件になったら整理が必要なのでこの機能作りたい」
  • みたいな話が出ることがある
  • その時期は半年後だったり1年後だったりする
  • 今必要ない or ビジョン実現にMustでない機能は絶対に作らない を徹底しろ
  • 必要になったときの方が情報が増えてて適切な判断をできるだろうし
  • 今解くべき課題を確実に解くためにチームのキャパシティを割きたいし
  • 今、その課題に直面していないユーザーから納得感を得られないからだ
  • 前もって準備しても、課題に直面していないユーザーからは不満の声しか出てこない
  • 機能は作るよりも削るほうが難しい
  • Nice to Haveな機能を作ることに、なに1つ良いことはない
  • ステークホルダーの一時的な欲求を満たすだけだ
  • その代わり、課題が表面化したときに迅速に対応できる体制はつくっておく

PSFit完了まで人を増やさない

  • 一般的な会社において、人を遊ばせることに罪悪感を覚えない人はいない
  • だが、PSFitまでのフェーズにおいて、ひとはそんなに必要ない
  • PO、営業、デザイナ、場合によってマーケター (or コンサル) がいればなんとかなる
  • それ以上の人がチームにいたとき、POはそれらの人の仕事をつくることが求められる
  • またPOはステークホルダーの不安マネジメントも求められる
  • 結果、なかなかPSFitに集中できずズルズル余計なコストが嵩んでいく
  • ただし、各々が自走できる場合、不安マネジメントが不要な場合は人がいても良い
  • 開発チームは空気を読んで必要そうな機能の実験・検証・学習をしてくれてたりすると最高のスタートを切れたりする

ホームランを狙うか、アウトを避けるか決めておく

  • プロダクト開始時に、どちらのスタンスを取るか決める
  • ホームランを狙うなら、積極的にリスクを取れ
  • アウトを避けるのであれば、不要なリスクを取るな
  • コントロールしやすいリスクは、極力安全に倒せ
    • 人の採用・異動: 安易に人を増やすな。変えるな。もっと厳しい状態になることが多いぞ
    • 利用技術の選定: 社内で実績ある技術を採用する
    • ステークホルダーからシステムへの期待
      • プロダクト開始当初にちゃんと伝える。合意できなければそもそもやらない
    • 我々からステークホルダーへの期待
      • 極力期待しない。期待するときは何を期待するか。どうすれば実現できるか明示する
  • POとして意思決定する際は、何のリスクを取ってるか常に意識しろ

様々な道具で具体・抽象のアウトプットし続ける

  • 具体と抽象を行き来しなければ、有用な発見は得られない
  • 考えるだけでは意味がない。手を動かせ。手で考えろ
  • 抽象であたりをつけ、具体で検証しろ
  • 具体で違うとなったら、また抽象にもどれ
  • 例として、下記のような成果物が考えられる
  • 煮詰まったらDesign Sprint を頻繁に行っても良いだろう

デザイン

  • 具体的なアウトプットイメージは上記である
  • 1週間で1往復くらいがちょうど良い

資料作りを絶対サボらない

  • 顧客に説明に向かうとき、説明資料を持っていくことがある
  • 社内のステークホルダーに協力を依頼するとき、資料をつくることがある
  • この資料は絶対にサボってはいけない
  • 顧客においては、上司にシステム導入の話をする際に、自分が作った説明資料を使うことがあるし
  • 社内のステークホルダーも、周りに協力を得る際にその資料を使うことがある
  • PO自身が作った資料が、どんどん独り歩きしていく
  • そのため、明確で分かりやすい言葉を使い、多くの人が理解できるように、懇切丁寧な渾身の資料を作ることを常に意識することが大切

意思決定を人に委ねるな

  • プロダクトオーナーはプロダクトの意思決定者
  • 偉い人アドバイスをくれるだろうが、短絡的に飛びついてはいけない
  • アドバイスをくれた人に対して、自分が現状を100%伝えられてない可能がある
  • その場合のアドバイスは、必ずしも正しいとは限らない
  • 自分の中でロジックが説明できないことは、誰が言ったことでも通しちゃいけない
  • ステークホルダーがどんなにイヤと言ってもやらなければいけないこともある
  • 誰かに恨まれても、やるべきと思ったらやるという意志を持つ
  • そのとき、説明だけはちゃんとする。伝わらなくても、全力で伝える努力をする

最後に

  • 他にもいっぱい学びがあった気がするが... 今すぐ思い出せるのはこれくらい...
  • 思い出したら追記する
  • 翌週にスクラムマスター編を書く

チームみんなが参加しやすくなるIaC設計の工夫

モチベーション

私は「インフラ」という言葉は、人によって受け取り方が大き違う言葉だと思ってます。 「よく分からないけど責任が重いので出来れば触りたくない」という人や、「本質的に難しいものなので訓練された人にしか触らせたくない」という人、 「IaaS、PaaSはインフラと認めない!」という人にも会ったことがあります。

「よく分からないなんとなく難しいもの」である「インフラ」は、多くの人に敬遠されがちなので、 中小規模の開発組織では1人のエンジニアがひっそりと孤独に作ってるケースがままあるのではないでしょうか。 私も3年間ほど、やりたがる人がいない...という理由でPMとインフラエンジニアを兼務してきました。

この記事では、一人でひっそりとインフラを作ってた私が、 それでもなんとか触れる人を増やしたいと思って工夫したIaC設計のアイデアを記述しようと思います。

言葉の定義

インフラ

IaCで扱う「インフラ」の定義について。 言葉の定義を探していくつか書籍を漁ってみましたが、なかなかコレといった文書を見つけられませんでした。

OSを作るようなソフトウェアエンジニアからすればマシンそのものがインフラですし、 Webアプリケーションをつくるソフトウェアエンジニアは、AWSGCPなどクラウド上で構築された、サーバー、ネットワーク、 ストレージなどのコンピューティングリソースをインフラと呼びがちです。 より一般向けの記事を読むと、社内のソフトウェアエンジニアが作成した管理画面や社内のCRMなどをITインフラと呼ぶこともあるようです。

ここでは「インフラ」という言葉の定義を、便宜的に「ソフトウェア開発に利用する、IaCで管理できるものすべて」とさせていただこうと思います。 なので、AWS等で構築するネットワークやDBだけでなく、エラー監視用のSentry、パフォーマンス監視に使うNewRelic、CI/CDとして利用するGitHub Actions、 その他様々なサービス群をインフラと呼ばせていただきます。

インフラのスタック

数々存在しているインフラリソースを任意のまとまりを、この記事では参考にした書籍にならって「スタック」と呼ばせていただきます。 この概念はCloudFormationのStackから来ており、スタックで管理されているリソースは一緒にデプロイされます。

設計について

設計の方針

私は「安全性」を最優先、「開発効率の維持」を2番めの優先事項としてIaCを設計します。

「安全性」は下記2点によって実現します

  • 設定の再現性・冪等性を担保するため、多少開発工数が掛かっても、できる限りのクラウドリソースをコード化
  • 障害発生時の影響範囲を限定的にするため、開発効率が多少下がっても初期からスタックを分割し、軽量なスタックを維持

「開発効率の維持」は下記2点によって実現します

  • 役割・技術要素軸でスタックを分割し、スタックを更新する上で必要な学習コストを軽減
  • スタックを小さく保ち、インフラタスクを複数人が並行して着手できる状態を維持

スタックの分割

上図のように、インフラを複数のスタックに分割します。

ここで簡単にいくつかのスタックについて説明します。 Appは、AWSなどクラウド上で構築しているネットワークやDB、バックエンドのサーバーを含む最も巨大なスタックです。 Frontは、フロントエンドのアプリケーションが構築されるスタックになります。最近だとVercelや Next.js をECS上で動かすことが多いです。 Monitoringは、監視に纏わる諸々を管理するスタックです。DatadogやCloudWatch等のインフラを管理します。

スタックは、ソフトウェアにおけるコンポーネントと同様の基準で分割しています。 再利用・リリース等価の原則 に従い、利用される単位とリリースの単位は等価になっており。 閉鎖性共通の原則 に従い、同じ理由、同じタイミングで変更されるものをまとめており。 非循環依存関係の原則 に従い、スタックの依存グラフは循環しない(必ず下の方向にのみ依存させる)ようになっています。

分割による狙い

分割の狙いは3つあります。

1つは 「変更容易性の確保」 です。 長大なスタックは把握しなければならないコード量と、変更による影響範囲が大きくなります。 すると、多くの人は怖がって触らないようになり、一部のエンジニアがお腹を痛めながら必要な修正をし続けることになります。 スタックを小さく保つことで、把握しなければならないコード量と変更による影響範囲を小さくし、高い頻度で継続して更新し続けられる状態を保ちます。

2つめは 「開発効率の維持」 です。 長大な1つのスタックは共同編集することができません。 インフラの変更を要する機能開発の要望が増えたとき、スタックが1つでは1人のエンジニアしか開発に参加できなくなります。 開発のボトルネックとなり、開発効率の低下を招きます。

3つめは 「開発組織の冗長性を高める」 ことです。 1つめの狙いに重なりますが、スタックの目的や影響範囲を限定することで、必然そのスタックに纏わる機能開発をする上で必要な前提知識も限定されます。 そうすることで開発に参加するための敷居を下げ、多くのメンバーがインフラの開発に参加できるような環境を整えます。

スタックの開発に参加する上で必要な知識の学習コストと、スタックを壊してしまったとき復旧にかかる時間をマッピングした図が下記のようになります。

右上にないものは学習コストが低い。 もしくは壊してもダメージ少ないものです。 それらはチームメンバーが開発に参加する上で心理的ハードルも低くなります。 そのため「初めての人は左下にあるものから入って、徐々に領域を広げて貰う」のような成長設計をしやすくなります。

IaCで採用するツールについて

私個人としては、スタックが適切に分割されていること。スタック間の依存が把握できていること。 この2点さえ守れるならば、IaCツールは何でも良いしと思っています。 どれか一つに統一する!と考えすぎず、各々のスタックの管理に適した(道具としての性質だけでなく、開発者の親和性含め) IaCツールを利用すれば良いのではないでしょうか。

私一人で利用する場合は、スタック間の依存関係を把握しやすく、リファクタリングも容易という理由でcdkを好んで使いますが、 下記の記事にも書きましたが terraformと比較すると cdk はそれなりに学習コストはあります。 なので、そこはチーム内で話し合ってチームに適したものを選べると良いかなと思います。

selmertsx.hatenablog.com

新しい技術を検討する際、PdMとして事前に決めておくこと

この資料の目的

自分のキャリアを振り返ってみると、PdMとソフトウェアエンジニア業を兼務することが多くありました。PdMとして業務していくなかで、エンジニアへのお願いの仕方を間違えて、想定よりも多く時間が掛かってしまうこともありました。その問題は、特に新しい技術を使って課題を解決しようとするときによくありました。

この記事では、新しい技術を試す際、現場で良くみるムダな仕事が発生しちゃってるケースを例に、そうならないよう自分が意識しているお願いの仕方を言語化してみようと思います。

よく見る良くない依頼の仕方

ケース1

  • PdM: 最近、XX という技術をよく聞くんだけどさ、あれでうちのサービスも良く出来ない?
  • エンジニア: うーん、とりあえず検証してみるんで、何ができたら嬉しいか教えてください
  • PdM: 何ができるか分からないからなー。とりあえず試してみてよ。良さそうだったらどう使うか考えるからさ。
  • エンジニア: やってみました!こういう結果になりました!
  • PdM: なるほどー、ありがとう!仕事で使いそうなことがあれば何か提案するわー。

ケース2

  • PdM: 最近、機械学習で不良品を見つける、ってことを他社でやってるらしいじゃん。うちの部署でもやってみたいからちょっと調べてみてよ
  • エンジニア: やってみました!僕たちの生産ラインで試したら、検知精度は75%みたいです
  • PdM: ちょっとうちの仕事では使えなそうだね〜。ありがとう

なんでこうなっちゃうの?

双方、エンジニアがあれこれ調査してくれましたが、成果につながらない、とても残念な結果になってしまいました。ちょっと極端に描いてしまいましたが、程度の差こそあれよく見る光景ではないでしょうか。( 僕は経験があります )

これらの問題は、扱おうとしている技術がどういうものか、そもそも何を解決したいのか、双方の解像度が低いときによく見られます。技術に関する理解が深ければ解くべき課題は定めやすいので混乱は生まれにくいですが、技術の理解が浅く、課題定義の能力も欠けていると現場はものすごいカオスになります。

そんなカオスな状態は下記の図の緑の状態にあります。こんな状況では「課題」というのもおこがましいので「何か」って言います。

これを望ましい状態に持っていくためには、「技術 」と「課題」の双方から確実性を高めていくアプローチが考えられますが、初手は「課題」の解像度を上げるべきです。たいていのケースで「課題」の解像度を上げるほうがコストが低いからです。

対処方法

ケース2で、PdMがもう少し状況を深く掘り下げ、下記の情報が分かっていたとします。

  • 出荷時の不良品は0.08%であり、これを目標値とする
  • 生産時の不良品は0.5%
  • 現在採用している不良品の検知システムは偽陰性が1%ある
  • そのため、最終的には人の目ですべて確認している
  • 確認の際は、月ウン百万の人件費が掛かっている
  • 不良品の見極めはルールベースで定められず
  • 見極めには深い知識と経験を持つ工員が必要になる
  • 現場は高齢化が進んでおり、恒常的に人を確保することが難しい
  • 熟練工の確保や、また業務時間の増加による従業員の不満増加という面で、事業継続リスクを抱えている
  • なので「検査工数の削減」「検査の簡易化」などの対処が求められる

※ 設定は新聞で読んだ事例を参考にしています。ので、現場の人から見ると間違いだらけかもですがご容赦ください

ここまで把握してれば、エンジニアに仕事を依頼する前に、下記のような意思決定をできるはずです。

意思決定を事前に下した場合、PdMからエンジニアへの依頼は下記のようになるでしょう。

  • 機械学習による不良品の検知を試して欲しい
  • 目的は不良品検査の工数削減
  • 精度が十分に高ければ、不良品検知の完全な自動化を検討するし
  • 精度が十分でなくとも偽陰性が基準値未満なら検査の工数を十分に下げられるはず。
  • なので、「精度」「偽陰性」「カットオフ値の調整有無」の3つの観点で調査してみて

そうすればエンジニアから、下記のような回答が得られるかも知れません。

  • 不良品の検知精度は75%程度なので、基準値に対して未達です
  • でも、偽陰性はx%でした
  • カットオフ値を調整すると精度は70%に下がりましたが、偽陰性は基準値を下回りました
  • 不良品と判断した製品をのみを抽出した場合、検査する部品数を大幅に下げられそうです
  • このシステムを導入したら、不良品検査に掛かる工数が30%程度下がる見込みです
  • ということでやっていきましょう!

こんな感じで、仕事を依頼する前に色々ちゃんと考えておくと、良い成果につながりやすいです。

さいごに

多くの人がアイデアを考える際、課題と解決策のセットを1つのアイデアとして捉えている。しかしアイデアは本来、課題と解決策に分離可能である。思いついたアイデアは一見きれいにまとまっているように見え、発想した本人も思い入れが強くなっていることも多いが、アイデア自体を課題と解決策に分離してそれぞれを検討することでさらに発想が広がることがある。 「プロダクトマネジメントのすべて」より引用。

ソフトウェア開発の経験が長いと、「課題と解決策を分けるなんて、当たり前じゃないか」と感じます。でも、意外と、驚くほどに、それらを混同して話し合ってしまっていることがあります。「うちのチームはそんなことないよ!」ってチームの場合は、きっと優秀な誰かが事前に整理してくれてるから。もしくは、チームメンバー全員が高いレベルにあって、議論が混ざらないからだと思います。誰かがそこらへん混同し始めると、意図せずみんなで混同し始めることが多くあります。そんなときに「あれ、なんかおかしいぞ」って気づいて、話を戻そうよって言える人は珍しいでしょう。ということで、PdMは「課題」と「解決策」を分け、「解決策」も複数パターン考慮した上でエンジニアに依頼すると、そこらへん混同せずに議論でき、業務がスムーズに進みます。

そもそもエンジニアにお願いする前にやれることもたくさんあります。

note.com

ということで、人に仕事をお願いする前に、自分で色々考えときましょう!という記事でしたー。

説明・説得コストについてアレコレ考えたこと

TL;DR

  • 払うべき説明・説得コストと、払うべきでない説明・説得コストが存在する
  • 払うべき説明・説得コストとは、その行為によって期待する成果
  • (積極的に) 払うべきでない、もしくは説明の方向性を逆転すべき説明・説得コストは、下記の通りだと考えている
    • 説明される側の、本来職種として持つべき知識の明らかな不足によるもの
    • 説明される側の、間違った先入観に基づく一方的な心理的抵抗によるもの
  • マネージャーとして、メンバーから説明を受けるときは下記項目を注意する
    • 今受けている説明コストは、本来メンバーが支払うべきものか
    • メンバーが支払うべきである場合
      • 何故にメンバーが支払うべきで、その説明を受け自分はどのようなアクションをするか、そのためにどこまでの品質を求めるのか
      • 上記項目が確実にメンバーに伝わっているか
  • マネージャーとして、払うべきでない説明・説得コストを支払っているシーンを見たら下記の対策を検討する
    • 説明の方向性を逆にする
      • なぜその変化が必要なのか。ではなく、なぜ変化を必要としないのか。
    • 職種ごとに必要とされる知識の種類と深さについて明文化する
    • 学習の工数を確保し、読書会等での業務時間内での学習を奨励する
    • 予算を確保し、説明コスト支払われる側の人に、外部の研修を受講してもらう
  • 説明・説得コストの削減、方向の変更、偏りの是正は、マネージャーとして最も重要な仕事の1つである
    • 大抵のケースにおいて、説明・説得コストを払う人は特定の個人に偏る
    • 説明・説得コストが特定個人に偏ってしまったチームは成長しなくなる
    • 故に、チームが健全に成長していく上で、説明・説得コストの偏りは是正しなければならない

はじめに

  • 組織、チームで仕事をしている以上、我々は常に変化の中にいる
  • 自分が主体的に変化を促す側になることもあれば、変化を受け入れる側になることもある
  • 変化を促すときは、相手の状況に合わせて適切なアプローチをしたいし
  • 変化を受け入れるときは、自分の現在地を理解して、適切なフォロワーシップを取りたい
  • 変化が起こるとき、そこには説明・説得コストが存在する
  • 「エンジニアリング組織論への招待」の著者である広木大地さんが 「Developer eXperience Day CTO/VPoE Conference 2021」 にて、下記のような話をされている

でも組織の文化としてソフトウェア作りが定着する前に、日本の大きな企業や行政機関は、いろいろなものをユーザー企業が丸投げしてしまったりするので、このノウハウが消失してしまいます。ソフトウェアを作ることが、どういうことなのかを理解する間もなく、徐々に消えていってしまう。 一方で、いい文化資本が蓄積する企業や、ソフトウェアエンジニアリングの文化資本、開発者体験を高めていくさまざまな工夫がどんどん蓄積していく環境の会社には就職したいと思ったり、自分のスキルアップになるんじゃないかと思うエンジニアが多い。そうじゃない会社は不遇な目に合うかもしれないし、嫌な思いをするかもしれないので、就職するのは止めておこうという気持ちになったりします。 こういった差が生まれるのは、文化資本の獲得をする際に、説明・説得に費やされるコストの差が、やはり大きいのではないかなと思っています。当たり前のように自動テストを書くことが習慣になっている会社と、「なんでそれをやらないといけないの? CI のツールはなんでそれを使わないといけないの?」と、いちいち説明・説得に費やされるコストがかかる会社は、なかなか定着していきません。

  • つまり、マネージャーとしては、不当に説明・説得コストが高い状況があれば是正しなければならない

説明/説得コストの分解

構成要素

  • 説明/説得コストについて要素を分解すると、形式知、経験、心理的抵抗の3点と考える。

f:id:selmertsx:20210920202826j:plain

  • 知識も経験もあり、抵抗もない。というケースは説明/説得コストは極小である
  • 知識としてはあるが経験がなく、心理的抵抗もない。というケースは説明・説得コストは少ない
  • 知識も経験もなく、心理的抵抗も大きい。という状況が最も説明・説得コストが高くなる
    • ※ 間違ったやり方の経験だけあり、それによって心理的抵抗が極めて高い状態は除く
  • 説明/説得コストを敢えて計算式で表現するならこんな感じか
Cost=\sqrt{x^2 + y^2 + z^2} \\
x: 知識不足への対応コスト \\
y: 経験不足への対応コスト \\ 
z: 心理的抵抗への対応コスト

説明・説得コストを払っていく

f:id:selmertsx:20210920222211j:plain

  • 心理的抵抗が少ないチームであれば、説明・説得コストの削減は難しくない
  • 知識がないのであれば、下記のような対応が検討できる
    • 職種ごとに必要とされる知識の種類と深さについて明文化し、読書会等での業務時間内での学習を奨励する
    • 予算を取得し、説明コスト支払われる側の人に、外部の研修を受講してもらう
  • 経験がないのであれば、下記項目が検討される
    • モブプログラミング等で、期限を決めて一緒に実験してみる ( 例: TDDとか )
    • 経験者を呼んで、経験談を教えてもらう ( ハンガーフライトみたいなもの )
  • 大変なのは心理的抵抗が高い状態
    • 特に「知識も経験もないが、心理的抵抗が高くチームとしてのINPUTも出来ていない」状態がやっかい

マネージャーとして説明・説得コストに関して気を払うこと

チームの学習機会の観点から

  • 説明・説得コストについて、説明の方向、頻度、分量については、注意が必要である
  • マネージャーは、下記のようなケースを見かけたら、特に意識して観察する必要がある
    • 例1: 自動テストを導入する上で、導入を推進する側が説明/説得コストを大量に払おうとしている
    • 例2: フロントエンドエンジニアとテックリードのどちらが決めても良い内容を、毎回テックリードが決めて、周りに説明している。
    • 例3: プロダクトオーナーとカスタマーサクセスのどちらが決めても良い内容を、毎回プロダクトオーナーが決めて、周りに説明している。
    • 例4: Scrumについて知らないが、導入する必要がないと考えており、学習する気もない
    • 例5: マイクロサービスについて知らないが、導入する必要がないと考えており、学習する気もない
      • ※ 別にマイクロサービスを推奨する訳ではないが、自分で学び、経験してもいないのに、判断を下すのは時期尚早である
  • それは説明・説得する側に回る人間のストレスを減らすためであり
  • 説明・説得される側の人間の、学習機会の損失や主体性の欠如を避けるためでもある

期待値の観点から

  • 誰が払うべき説明コストなのかを明確にする
  • 何が理由で、誰が、何を、どこまで説明する必要があるのか明確にする
  • とくに「どこまで」の部分が難しいが、ここをやりきることが大切だと感じてる

蛇足

やってみせ、言って聞かせて、させてみせ、ほめてやらねば、人は動かじ。
話し合い、耳を傾け、承認し、任せてやらねば、人は育たず。
やっている、姿を感謝で見守って、信頼せねば、人は実らず。
山本五十六
  • やってみせ、言って聞かせて が知識のINPUT
  • させてみせ が経験のINPUT
  • ほめてやらねば心理的抵抗の除外に結びつく

ドメイン乗っ取りを防ぐためにAWSで .com ドメインを使っている

TL;DR

  • JPドメインの管理をしている株式会社日本レジストリサービスには、下記の規則がある
    • ざっくり言うと、「誰かがあなたのドメインを欲しいと言って、あなたが10日以内に返事をしなければ、ほしいと言った人にあげちゃうよ」という規約である
// https://jprs.jp/doc/rule/toritsugi-rule-wideusejp.html
2 当社が、指定事業者に対して登録者の意思確認等を依頼した場合、指定事
業者がその依頼のときから10日以内に登録者がその意思を有しない旨の回答を
しない場合には、指定事業者において登録者の意思確認等を行い、登録者がそ
の意思を有する旨の回答を得たものとみなす。

用語の確認: レジストリ/レジストラ

// https://jprs.jp/doc/rule/toritsugi-rule-wideusejp.html
2 当社が、指定事業者に対して登録者の意思確認等を依頼した場合、指定事
業者がその依頼のときから10日以内に登録者がその意思を有しない旨の回答を
しない場合には、指定事業者において登録者の意思確認等を行い、登録者がそ
の意思を有する旨の回答を得たものとみなす。
  • つまり、「誰かがあなたのドメインを欲しいと言って、あなたが10日以内に返事をしなければ、ほしいと言った人にあげちゃうよ」という規約である

ドメインに関連する事件

ラブライブドメイン乗っ取り事件とドメイン移管ロック

  • 2019年4月5日、上述した仕組みを悪用した事件が起きた。
  • ラブライブというアニメのドメインがイタズラで乗っ取られて、上記のように書き換えられてしまった事件である
    • 詳細はこちら
    • きっと誰も 10日以内に返事をしなかったんだろう
  • この事件により、 ドメイン移管ロック という言葉が一躍有名になった

お名前.com 不正アクセス事件

  • .jpドメインドメイン移管ロックに 対応している お名前.com だが、2020年6月に重大なインシデントを起こした
  • coincheckとbitbankの2社が、お名前.com 側の管理ツールにおける不具合によってドメインの乗っ取りを受けてしまった
    • どのような不具合だったか詳細は不明
    • 2018年に お名前.com が提供を始めた 「ドメインプロテクション」という機能で対処できたかも不明
  • 全体的なまとめはこちら
  • Coincheck側の説明はこちら
  • 以上の問題により、一概にドメイン移管ロックに対応しているから問題なし、とも言えない

ドメイン乗っ取りの何が危険なのか?

  • ここまで長々とドメイン乗っ取りの事件について話してきた
  • ドメイン乗っ取りの何が危険なのか。ということであるが、ラブライブのときのようにサービスにイタズラされるのであれば怖くない
  • 一番怖いのは、フィッシングに使われてしまうことだ
    • 例えば、企業が利用しているドメインが奪われた場合、そのドメインを利用してお客様にメールを送られてしまうと機密情報が容易に取れてしまう可能性がある
  • 他にも、乗っ取ったドメインで、完全に同じ見た目のサービスを作ってしまえば、パスワードを盗むことも容易にできる
  • ということで、ドメインというものは守らなければならない資産であると言える
  • 故にドメインの捨て方は強く注意しなければならない
    • 企業が過去利用していたドメインが破棄されるのを見計らってそのドメインを購入し、フィッシングに利用する事件がよくある

個人的な決定内容

  • 以上の経緯より、自分は AWS.com ドメインを購入することにしている
  • そして、購入したドメインでは、ドメイン移管ロックを掛けている
  • これは、AWSが安全だと判断したから取った方針である

AWSにおける踏み台(Bastion)サーバーの作り方

モチベーション

Bastionサーバーは、会社のサーバーの入り口であり、アクセス管理は厳重に行う必要があります。Bastion(要塞)という名前の通り、各社強力なセキュリティの対策を行っていました。最も一般的なものだと、個人ごとにアカウントとSSHアクセス用のKey Pairを発行したり、LDAPを利用した全社共通のBastion認証基盤の用意などがあります。しかし、その設定コストはそれなりにあって、インフラエンジニアの負担となることがありました。 これらの問題に対処するため、AWSは 2018年にSSM(Session Manager) という機能をリリースしました。本記事では、SSMを用いた Bastion サーバーの構築について説明をします。

前提知識

従来のBastionサーバー管理方法

f:id:selmertsx:20210811105923p:plain

従来、Bastionサーバーは上の図に示す形で運用されてきました。Public SubnetにEC2 instanceを配置し、そこから Private Subnetの中にあるEC2 Instanceや、RDS、Redshiftにアクセスする方式です。2016年時点のAWS公式ブログにおいてユーザーごとのkey pairを発行する方法が説明されているため、2016年時点においてはこの方法が主流だったと言って良いでしょう。

しかし、この方法は冒頭にて説明したように、安全な運用を継続するには膨大なコストが掛かるという問題がありました。

Session Manager

f:id:selmertsx:20210811110004p:plain

2018年9月11日、Session Managerという機能が公式よりアナウンスされました。この機能は、SSHではなく aws-cli を用いてBastionへアクセスする方法を提供します。これにより、Bastionサーバの管理は大幅にセキュアになります。

  • aws-cliAWSのIAMを用いてアクセス制御をすることができます。
    • Terraform等を用いて、アクセス管理のIaC化が可能
    • IAMのPolicyを用いた柔軟なアクセスコントロールや、MFAの強制が可能
    • SSHの鍵管理のコストが不要になる
    • IDaaSによる ID Federation を利用すれば、リスクベース認証などIDaaSの保有している、よりセキュアな方法で認証できる
  • EC2 instanceを Private Subnetに配置することが可能
    • 従来のBastionサーバーはPublic Subnetにあったため、攻撃されうる可能性があった
    • IP制限を掛けることで一定の対処は可能だが、同時に利便性も損なわれていた
  • 操作履歴はCloud Watch Logsに自動的に残される

という訳で、2021年現在において、新たにBastionサーバーを建てる必要があれば SSMの利用を想定した構築をすべしと言えるでしょう。

SSMベースのBastionサーバーの作り方

SSM ベースでBastionサーバーを建てる場合、必要なリソースは前の図に示したとおりです。 ざっくり書き出すと、下記のリソースになります。

  • VPC
  • Public Subnet
  • NAT Gateway ( Public Subnet 内に配置 )
  • Private Subnet
  • EC2 Instance (SSM Agentをinstall済みのもの)

踏み台を立てようとしているので、VPCやPublic/Private Subnetはすでにある前提で説明します。 Terraform を利用している場合、terraform-aws-ec2-bastionというモジュールを利用するのが一番楽でしょう。 下記のような設定をすればすぐに動きます。

module "bastion" {
  source            = "hazelops/ec2-bastion/aws"
  version           = "~> 2.0"
  aws_profile       = "xxx"
  env               = local.env
  ec2_key_pair_name = local.ec2_key_pair_name
  vpc_id            = module.vpc.id
  private_subnets   = module.bastion_private_subnet.ids
}

aws-cdk を使っている場合、公式が提供しているモジュールがあるためそちらを利用すると良いでしょう。

動作確認とPort Forwardingを利用したRDSへのアクセス

まず、踏み台が正常に動作していることを、下記のコマンドで確認します。

$ aws ssm start-session --target ${EC2のID} --region ap-northeast-1 --profile ${任意のprofile設定}
# MFAの確認
Enter MFA code for arn:aws:iam::xxxx:mfa/${ユーザーアカウント名}:

Starting session with SessionId: botocore-session-xxxx
# EC2 instanceにアクセスしていることを確認
$ pwd
/var/snap/amazon-ssm-agent/2996
$ hostname
ip-xxx

次に、よく利用するBastion経由でのRDS接続方法について記載します。まず、.ssh/configに下記のような設定を記載します。ProxyCommandの中では StartSSHSessionというドキュメントを読み込んでいます。これは、ssh tonnelを構築する際に必要な設定です。

Host xxx-bastion
  HostName ${EC2 internal IP}.ap-northeast-1.compute.internal
  User ubuntu
  Port 22
  ProxyCommand aws ssm start-session --target ${EC2 ID} --document-name AWS-StartSSHSession --region ap-northeast-1 --parameters "portNumber=22" --profile ${aws profile}
  IdentityFile ~/.ssh/${bastionのkey pair}

その後、1つめのconsoleで下記コマンドを実施します。これによって、Bastionを経由してRDSに接続するためのトンネルが構築されます。

ssh -N -L 15432:${RDSのURL}:5432  xxx-bastion

先程のconsoleを閉じないまま、別のconsoleで下記のようなコマンドを実行してください。すると、RDSに接続することができるようになります。

$ psql -h localhost -p 15432 -U {username} -d ${database_name}
Password for user {username}:
psql (13.0, server 11.9)
SSL connection (protocol: TLSv1.2, cipher: xxx, bits: 256, compression: off)
Type "help" for help.
database_name=>

将来の話

CloudShell

2020年12月18日、AWS CloudShellという機能がリリースされました。この機能はAWSのマネジメントコンソールから、Shellを実行できる機能です。そのリリース記事の中に下記の文面が存在しました。

ネットワークアクセス – セッションはインターネットへのアウトバウンド接続を確率できますが、インバウンド接続はどの種類でも許可しません。現在、セッションはプライベート VPC サブネット内のリソースに接続できませんが、近日中に接続できるようになる予定です。

つまり、CloudShellで実質 Bastionと同等の作業ができるようになります。そのため、この記事を読んでいる方がBastionサーバーを建てることになったら、まずはCloudShellの最新のアップデートを確認することをオススメします。 ただし、CloudShellでどの程度証跡が残すことができるかをよく検討して、導入の可否判断をする必要があります。

EC2 instance Connect

現在、手元のPCからBastionを経由してRDSにアクセスするには、どうしても鍵の設定が必要になります。そのため、どうしてもkey pairの共有が必要となってしまいます。認証自体にはAWS IAMを利用しているので形骸化された手順ではあるものの、手間といえば手間でしょう。EC2 instance connectを利用すれば、必要に応じて一時的に公開鍵をuploadすることができるため、この手間を削減することができそうです。

現在、踏み台に触る人数が少ないときはさほど問題はないですが、関係者が増えたタイミングではEC2 instance connectの導入を検討すると良いでしょう。

TypeScriptのnode-fetchをテストの際にmockする

モチベーション

  • TypeScript で node-fetch のライブラリを使ってテストするのに少し手間取った
  • 他にもハマる人がいるかも知れないので、ここに記事として残しておく

テストしたい内容

  • Soracom Arcを利用して unified endpointにテストデータを送信したい
  • テストデータの送信では node-fetch というライブラリを利用する
  • node-fetch を利用して所望のパラメータが送信されていることを確認したい

結論: 実装内容

実装は下記の通り。 重要な部分は ts-jest のtest-helpersを利用しているところ。 ts-jestが必要な理由は後述する

// src/publisher.ts
import fetch from "node-fetch";
export const UNIFIED_ENDPOINT_URL = "http://unified.soracom.io";

export const main = async () => {
  const body = { /* なんらかのデータ*/ };
  await fetch(UNIFIED_ENDPOINT_URL, {
    method: "POST",
    body: JSON.stringify(body),
  });
};

(async () => await main())();
// tests/publisher.test.ts
import fetch, { Response } from "node-fetch";

// SEE: https://kulshekhar.github.io/ts-jest/docs/guides/test-helpers
import { mocked } from "ts-jest/utils";
import { main, UNIFIED_ENDPOINT_URL } from "../src/publisher";
jest.mock("node-fetch");

describe("Publisher", () => {
  test("main", async () => {
    mocked(fetch).mockReturnValue(
      Promise.resolve(new Response("ok", { status: 200 }))
    );
    const expectResponse = { /* 何らかのデータ */ };
    await main();
    expect(fetch).toBeCalledWith(UNIFIED_ENDPOINT_URL, {
      body: JSON.stringify(expectResponse),
      method: "POST",
    });
  });
});

Jest公式ドキュメントの手法

Jest公式では node-fetch のようなライブラリのテスト方法は下記のように指示されている。 だが、これは TypeScript ではコンパイルエラーとなりテストができない。 そのため、ts-jestを導入して対処する必要があった。

jest.mock('node-fetch');

import fetch, {Response} from 'node-fetch';
import {createUser} from './createUser';

test('createUser calls fetch with the right args and returns the user id', async () => {
  fetch.mockReturnValue(Promise.resolve(new Response('4')));

  const userId = await createUser();

  expect(fetch).toHaveBeenCalledTimes(1);
  expect(fetch).toHaveBeenCalledWith('http://website.com/users', {
    method: 'POST',
  });
  expect(userId).toBe('4');
});

f:id:selmertsx:20210811105327p:plain