あんパン

こしあん派

筋の良い解決方法に辿りつくためには

ということを以前考えていたので、やや加筆しつつここにメモ。

筋の良い解決方法に辿りつくためには

  • 仕様を十分に理解できている
  • 選択肢が十分に洗い出されている
  • それぞれの選択肢について、実現する上での制約が洗い出されている
  • それぞれの選択肢について、メリット/デメリットが十分に洗い出されている

の4状態を辿ればよくて、これができるとあとは決めれば良い状態になる。このフェーズは上から順に辿る必要がある。なぜなら上の状況が変わると下の判断に影響が及ぶため。それぞれが十分に行われていないと大きな手戻りが発生してしまう。

これはタスクの大小問わず、日々の暮らしのうちおおよその課題には適用できると思う。

仕様を十分に理解できている

仕様が与えられたらすぐさまその実現方法を考えようとなってしまいがちだが、まずは立ち止まって仕様を理解することに注力する。以下のようなことを気にかけておくと良い。

  • そもそも仕様に不備はないか?
  • 仕様で実現したいことは別の形で実現できるのではないか?
  • 仕様に書かれている中で曖昧な点(書いた人と認識がズレそうな点)はないか?

次のフェーズで選択肢を列挙するにあたって、全く無意味なものを出すのを防ぐことができる。また、全く無の状態から列挙するのは大変なので、とっかかりを見付けるためにも役立つ。 3つめのフェーズとやることは微妙に被っているけど、おおざっぱに枝刈りする意味でまず最初にやっておけるとよい。

選択肢が十分に洗い出されている

課題の解決方法はひとつとは限らない。いろんなパターンを洗い出して一番良いものを選び取ることで、筋の良い解決方法に辿りつくことができる。ここでパターンを洗い出せていないと次以降のフェーズの検討を進める際に選択肢が増えてしまい、十分な検討がなされていないのでまたこのフェーズに戻ってくることになる。4フェーズの中で一番重要なフェーズといえる。

選択肢といっても亜種を何パターンも出しているのでは、結局どれを取っても変わらないことになりあまり意味がない。できるだけ違う経路で同じ場所に辿りつけないだろうか? を考えたいところ。

十分な選択肢を洗い出す決定的な方法はない。本当に他に実現方法はないか? を常に考えておく癖をつけておくとだんだん身についていく。松竹梅で案を出すのが典型的なやりかただと思う。つまりスコープと工数にグラデーション(松から順に小さくなっていく)をつけた3パターンを出すということ。

自信がなければ、次のフェーズに行く前に誰かにレビューしてもらうのも有効そう。

それぞれの選択肢について、実現する上での制約が洗い出されている

これは1つめのフェーズに似ている。選択肢を挙げたけど実は実現不可能な項目が存在しないか? をいまいちど立ち止まって検討したい。最初は見えてこなかったけどここにきて見えた結果実現不可能と判断できることはよくある。具体的にはこのフェーズで以下のような制約が見えたりする。

  • 工数
  • 予算
  • ステークホルダーの利害
  • 他チームとの兼ね合い
  • 関連会社との兼ね合い

これらは典型的な例として挙げているだけで、実際には他にもいろいろあろう。

それぞれの選択肢について、メリット/デメリットが十分に洗い出されている

選択肢を挙げるフェーズの次に重要なのがこのフェーズ。メリットとデメリットを洗い出せていないと、どれを選べばよいのか判断することができない。大抵の場合トレードオフになることが多いので、基本的には以下のような軸で考えて、必要に応じて軸を増やしたり減らしたりする。

  • 技術的な難易度
  • 影響範囲
  • 既存機能との整合性
  • 横展開可能性
  • 負荷
  • 直近何らかの開発で触ることが分かっている場合、その工数を増大させないか
  • 予算

慣れていないと十分にメリット/デメリットを列挙することもできないので、ここでも誰かにレビューしてもらうと良い。

決めるには

ここまできたらあとは決めるだけ。決めるにはどのメリット/デメリットを重く捉えるべきかの認識が重要になる。評価軸が多い場合は表にして点数をつけると判断をつけやすい。

意思決定者が自分ではない場合はここまでのサマリーをまとめて意思決定者に持っていくことになる。持っていく前に、自分の中でどのメリット/デメリットが重要なのかと、その理由を持っておくと意思決定者の判断に役立つので、何も考えずに持っていくよりはある程度考えてから持っていく方が望ましい。


これらのステップは必ずしも一人でやりきる必要はない。最後に意思決定者に持っていく段になって実は前提が違っていて別の案の方が良いですねとなることも往々にして発生しがちだと思う。タスクの性質に応じて相談のタイミングを調整すると良い。

QNAPのNAS上のデータをAmazon S3 Glacierに同期する

masawada.hatenablog.jp

この記事でも書いた通りQNAPのNASにファイルを置くと定時バッチでAmazon S3にアップロードされ、翌日にはAmazon S3 Glacierに移動されるようになっている。なぜ直接Glacierに投入しないかというと、直接Amazon S3 Glacierを扱うのはやや煩雑で、Amazon S3を通して操作できる状態にする方が楽なため。Amazon S3のbucketにライフサイクルを設定することで自動的にGlacierに移動される状態にできる。

以前は手でぽちぽち設定していたのだけど、最近はAWSアカウントを作り直したりIaCでリソース管理するように整備するなどしていて、この設定もCDK化した。具体的には以下のようなStackを書いた。

gist.github.com

NASに設定する用のIAM userとpolicy(とgroup)はIaCで管理しているがkeyなどは管理しない。CDKで発行することもできるが、まさかCloudFormationのコンソールに表示したくはないし、SecretsManagerに保存するとお金(といっても月数十円くらいだろうけど)がかかるのでケチくさく手動で発行している……

あとはQNAPのNASに入っているHBS 3 Hybrid Backup SyncでS3へのアップロードを設定しておけばOK。特に難しいことはない。

iOS 16のSafariではJoy-Conの情報をGamepad APIで取れる

iOS 16 Release Notesにもあるように、いくつかのBluetooth接続のゲーム用コントローラが新しくサポートされた。具体的にはJoy-Conなど。

Many additional Bluetooth and USB game controllers are supported by the Game Controller framework on macOS 13, iOS 16, and tvOS 16 and later. (82409809)

https://developer.apple.com/documentation/ios-ipados-release-notes/ios-16-release-notes#Game-Controller

ということはiOSのSafariでもGamepad APIから値を取れるのでは?? と思ってやってみたところ、やはり取ることができた。

iOSをiOS 16にアップグレードしてからJoy-Conを接続してこのURLにアクセスして、何らかのボタンを押すと値を取れるようになる。Joy-Conの接続は、Joy-Con側のシンクロボタン*1を押して、iOS側で 設定 > Bluetooth から接続できる。接続後は 設定 > 一般 > ゲームコントローラ で接続状態の確認ができる。

Bluetoothで接続してキーの状態を確認

Gamepad APIはkeydownイベント等が送られてくるわけではなく、接続時と切断時にイベントがやってくるだけ。状態は requestAnimationFrame 等でフレームごとに監視してあげる必要がある。

developer.mozilla.org

書いたコードは以下のrepoに置いてある。

github.com

昔はWiiのコントローラをキーボードとして認識させるアプリとかを入れてスライドのページめくりなどをやっていたけど、いまやブラウザのAPIで値が取れるようになって便利な時代だなあと思う。

デスクトップ環境をdisposableに保つ

もう5年以上続けている取り組みのひとつにデスクトップ環境をdisposableに保つというのがある。いつでも何があっても即座に環境を捨てて作り直せるようにするということ。EC2やVPSのインスタンスに対してAnsibleでプロビジョニングできる状態にしておけば即座に新しいホストを立てて古いホストを捨てられる、そんな状態を目指すということ。具体的には以下のようなことを心がけている。

書類のマスターデータを端末上に置かない

デスクトップ環境をdisposableに保つ第一歩は、とにかく手元になんらかのデータのマスターを置かないことにつきる。端末上にマスターデータを置いていると当然新しい環境を用意する際にデータ移行が必要になる。移行をしないためにはこれらを手元に置かないようにする。書類はGoogle DriveやNASに入れる、ソースコードは全てGitHubに上げておく、などなど。現代では機密情報はブラウザやら1Passwordやらに入れておけばだいたいなんとかなるということもあり手元に置きたいデータは少なかろう。もちろん即座に読みたいデータは手元にあっても良いけどマスターは別の場所に置いておく。これを徹底する。

また、複数の場所に置いておくことで耐障害性を高めることもできる。自分はデータをQNAPのNASに入れておくと定時バッチでAmazon S3に上がり、翌日にはGlacierに入るようにしている。

アプリケーションのインストールや設定をコードで管理する

冒頭で出したように、何らかの方法でプロビジョニングできる状態を目指す。自分は全ての設定をdotfilesに置いていて、2,3コマンド走らせて1,2時間くらい放置するだけで慣れたデスクトップ環境が仕上がるようにしている。

github.com

これを利用すればArch Linuxのインストールはいくつか環境変数を設定して1コマンドで終わるし、ツール類のインストールも1コマンドで終わる。日本語環境もウィンドウマネージャもなにもかもが自分の好みの状態で立ち上がる。このあたりは以前も書いた。このころからあんまり変わっていないけど、3年くらい経ってどうなったかはそのうち書きたい。

masawada.hatenablog.jp

なおLinuxデスクトップを使い始める以前はmacOSを利用していて、brewやbrew caskで対応していた。brewのインストールからシェルスクリプトで書いておいて、一発実行すればOKという要領。設定はdefaultsで対応。しかしやや大変ではある。Linuxの場合は全てがファイルなので、大抵の場合ファイルを適当に配置して回ればOKなのがありがたい。

一定期間おきにクリーンインストールする

つまり全ての設定を吹っ飛ばしてOSからインストールしなおすということ。disposableに保っておけば定期的にこれができるし、これができるということはdisposableといえる。なぜこれをやるかというと

  • 構成管理のコードを一切変えてなかったとしても長期間適用しないと動かない可能性があるため
    • コードを変えなくても周辺のツールのバージョンは上がっていくわけで、いざ必要になったときに動かないということがある
      • 手元環境のバージョン固定とか極力やりたくないと思う
    • これを防ぐために定期的に実行して壊れる箇所がないかを確認する
  • 長期間リセットしないまま使うと、どうしても手元にマスターデータが溜まりやすいため
    • 消すリズムを持っておかないと、まああとでGoogle Driveに上げるから……みたいな怠惰な気持ちになりマスターデータが手元環境に溜まりやすい(人による)
    • マジで消えてはいけないものを消してしまってもダメージが少なくなるということもある
      • 消えたら勉強代ということで…
  • リセットする手順を記憶しておくため
    • ある程度は自動化するしドキュメントも書くけれど、放置しているとリセットの方法が記憶から抜けていってだんだんと手順に自信がなくなっていく
    • 手順を覚えておくことで一連の動作を躊躇なく素早く行うことができる
    • つまりは避難訓練

などなどいろんな理由がある。

昔は1ヶ月おきに私物のMacBook ProのOSを飛ばして設定しなおしていたのだけど、中身を消して売却するときにSSDに異常が発見されて買い取り価格がめちゃくちゃ下がるという事件があり、それ以来同じことがあったら嫌だなと思ってペースを落としている。だいたい半年に1回程度でやっている。いまは昔と違って消すときにディスクに異常に書き込みまくるみたいなことがないのでこのリスクは少ないかもしれない。


インスタンスを建てたり捨てたりする際もこれらと同じようなことをやっているはずで、気をつけるポイントは同じといえる。

さてdisposableに保っておくことでどういうメリットがあるかというと、自分は以下かなと考えている。

  • 新規にPCを購入して素早く慣れた環境で開発できる状態を整えられる
  • 端末の突然死やデータのロストに耐える状態を作れる
  • 不具合がハードウェアの問題かソフトウェアの問題か分からないときに気軽に切り分けることができる
    • なぜかファンが爆音で回るのだが… というときに気軽にOSを入れ直して様子を見ることができる

逆にデメリットとしては

  • この状態を作るのに手間がかかる
  • ミスってデータが消えると痛い

といったことがある。しかし前者は一度整えたらあとは楽だし、後者はバックアップしましょうという感じ。

半ば趣味の領域ではありそうだけれど、個人的にはオススメできるスタンスかなと考えている。

ロールに求められることと名前は一致させたい

いま所属しているチームには相談役というロールがあって、タスクを進めている人とペアにすることで孤立しないような仕組みになっている。もちろんデイリースタンドアップなどで複数人で相互に見ているのだけど、プライマリな相談相手を決めているという状態。相談役がいることで相談する側が誰に相談するか悩む時間だったり相談される側がタスクのコンテキストを把握する時間だったりが減るのが良いところ。相談役も自分のタスクを持っていたりいなかったりする。

もともとジュニアメンバーにメンターがついて相談を受けていたけど、ジュニアメンバーに限らずどんなタスクでもプライマリな相談相手が決まっているといいよね、という話が元になった。これがだいたい4年くらい前の話。

ところがだんだんチームの規模が大きくなって、うまく回りづらくなっていた。具体的には以下のような状態になっていた。

  • メンバーが増えた結果、相対的に相談役になれるエンジニアの割合が減った
    • 複数の相談役を掛け持つケースが出てきた
      • 把握すべきコンテキストが増えたが、相談役という名前だったためかかる工数の見込みを甘くしてしまった
  • 新しく入ってきたメンバーと既存メンバーの相談役として同じような振る舞いをしてしまった
    • 相談が来るまで待ちの姿勢で居続けてしまった
      • 実際は相手によってもうすこし踏み込んで引っ張ることが期待されていた
      • 例えば進め方や考えに漏れがないかのレビューだったり、間に合わなそうだったらヘルプに入ったり

そうしているうちに、これは相談役という名前ではないよねという話がチームメンバーから持ち上がった。どちらかというとリードしてほしいのでは? という話があったものの、リードともちょっと違う気がしていて、伴走とかコーチとかいろいろな名前を考えてみている。


特定の人を何らかのロールに任命する際は、その名が実態に即しているかは気にしておきたい。気にするタイミングは誰かを何かに任命するとき、とりまく状況が変わるときであろう。

普段エンジニアとしての自分は実態に即した変数名をつけているはずで、ロール名をつけるときに深く考えられていないのは一貫性がないなと思う。いまは紅茶キノコにコンブチャと名付けてしまっている状態といえる。

ついでに書いておくと、ロール名だけでなくて会議の名前もその役割によって変更すべきだと思う。デイリースタンドアップでちょっとおもしろい名前がついているのはいいとして、例えばテクノロジーマネジメント会と称しているのに別にテクノロジーをマネジメントしていない、みたいなことがあると困る。会のメンバーは一緒だけど求められることが変わったり、会のメンバーが入れ替わって方向性が変わると容易に発生してしまう。期やメンバーが変わって会の受け持つ管掌範囲が変わるなら名前も変更すべきか気を払うとよさそう。

逆に、期待する役割があるならその名付けをしておくと沿った働きがしやすくなりそう。

ここまで通して読み返すと、つまるところ期待のコントロールをうまくやれという話なので、それはそうということしか書いていない。けれど細かい期待の変化は意外と見落としがちなので気をつけたい。気をつけるだけではなくて、期の変わり目にリマインダーを仕込んでおくとか、ドキュメントに書いておくとかの対策は取れそう。