テックリードになって気をつけていること

[フューチャーアドベントカレンダー2020](https://qiita.com/advent-calendar/2020/future)の24日目です。

# はじめに

フューチャーに入ってテックリード（社内だとアーキリーダーと呼ぶことも多い）のような役割をし始めて4,5年ほど経過しました。

いくつかの案件を回して自分なりに汎化・パターン化してきた部分も増えてきたので、気を付けていることをまとめました。

# テックリードとは

[エンジニアのためのマネジメントキャリアパス――テックリードからCTOまでマネジメントスキル向上ガイド](https://www.oreilly.co.jp/books/9784873118482/) によると、以下のように説明されています。

* テックリードはエンジニアの階層におけるランクのひとつではなく、シニアのレベルに達したエンジニアが担うことのできる職責群である
* 技術的なプロジェクトの管理者
* 部下に効率良く仕事を割り振って自身の負担を適宜軽減するよ
う心がける
* チーム全体の生産性に照準を定め、しかるべき成果を上げるよう全力を尽くさなければならない
* 管理やリーダーシップに関わる難局を打開する方法と、製品、分析など社内の他部門と効率良く協働する方法とを習得することが求められる

大体はエンジニアチームの取りまとめ役で、リードエンジニア的な存在だと思います。目立つ部分ではアーキテクチャ選定、テスト計画、コードレビューなど非機能や品質の砦としての存在。あとはメンバーの技術的育成、不効率な開発フローなどの整備。開発スケジューリングやタスクの優先順位付けなども領域に入ってくると思います。入ってくる前提で気をつけてくることを書いていきます。

# 気をつけていること

## ①アーキテクチャ設計で気をつけていること

一般的には、一番の制約条件を見つける部分に一番力を入れます。前提条件を整理した上で、設計をすすめる流れです。


### 1-1. 採用技術選定

AWSであればアイコンを並べるようなインフラレベル・サービスレベルの技術選定です。主に以下を気をつけています。案件の文脈にかなり依存しますがざっと気にしているポイントです

* 運用負荷を下げるため、なるべくフルマネージドに寄せる
* 同期・非同期のポイントを意識する
    * できる限り同期処理で密結合させたほうが、開発生産性や品質は上がる
        * 非同期は疎結合になるがテストもしにくいし、安易に採用すると不具合の温床になりがちなので、戦略的に同期にするのも良い
    * アーキテクチャ机上設計上はKinesis,S3 Trigger, DynamoDB Streamなどなどで非同期ピタゴラスイッチすると格好いいので寄せたくなりますが、品質保証上難しくなることが多いので、容量用法を正しく確認します
* バッチ処理
    * リラン可能な仕組みになっているか
        * リカバリポイントはどこか
    * システムI/F周りは、初期データ移行でプログラムが相乗りさせることも多い。そうでなくてもデータリカバリで部分的に洗替に用いたり。そういったデータ量でも対応できる仕組みなっているか
    * 分散実行可能な仕組みになっているか
        * パーティションキーなどで入力データを分割可能になっているか、同時書き込み可能か、できるサービスか
* 各種ハードリミットに引っかからないか
    * データ量が増えた時、接続量が増えた時、処理種別が増えたとき、..などいくつかのシナリオを想定してみて、それが成り立つかはかなり机上で検討します
        * サイジングが大事。だいたい5年後換算で。5年の意味は状況によって様々ですが、一つは減価償却の耐用年数から仮止めすることが自分は多いです
        * 海外展開があるかはかなり考慮ポイントです
            * その時点でノックダウンになることも多いです
    * 構築するリージョンでそのサービスが利用できるか
    * バージョンがGAかβかαか
        * カットオーバーの時期次第では、βくらいなら採用するのもありかと（既存案件のポリシーと合わせることが通常ですので、選定時の制約は前もって調べましょう）
    * サービスのSLAやポリシーを確認。特に非同期であればAt Least OnceかExactly Onceか
* クラウド利用料金
    * コストドライバーがどこにあるかポイントを掴みます
        * 代替が従量課金なので、メッセージ数増加で破産しないか（ビジネスとしてペイできそうか）
            * 利用量の概算をユーザ数で割ってみると妥当そうかそうで無さそうか感覚がつかめると思います
* 非機能
    * 多すぎて語れないですが、IPAの非機能要求グレードから引っ張ることも多いです
    * 可用性（サービスレベル）はかなり気をつけます
        * 必要に応じて、マルチリージョン構成をとるべきか、ダウンタイムの許容度に応じてデータのみバックアップを取ってリカバリできるか
  

### 1-2. 機能配置

実際は技術選定の前に行うことが多いですが、サービス同士や、コンポーネント同士での機能配置（何をやって、何をしないのか）はかなり注意して設計します。

* それぞれのサービスで意識することとしないこと（知らなくても良いこと）はかなり厳格にポリシー付けます
    * アプリケーションのパッケージと同じく、そのサービスが依存して良いサービスかどうかレイヤー的に切ることが多いです
* 機能配置や機能分解は、サービスレベルや、そのサービスが別のサービスから依存されるかといった拡張シナリオを理由に行うことが多いです
* それぞれのサービスで、重複したデータを持つ場合は、どのサービスが正となるデータ（ゴールデンレコード）なのかは設計ポイントです
* もっとも依存するサービスが、一番の障害点なので可用性を上げれるか（冗長構成が取れるか）確認します
* サービスに状態（ステート）を持つと複雑化することが多いので、なるべくステートレスで冪等な処理ができるように設計します


### 1-3. 連携方式

同期・非同期やAPIコールにするのかファイル連携にするのかといった連携方式を決めていきます。概ねAPIコール（REST）が多そうですが、gRPCでもなんでも好みで決めて良いかなと思います。

その上で注意すべき点です。

* エラー時のハンドリング
    * 非同期でストリーミング処理をする場合は、処理が失敗した場合にDLQで救済できるかどうか
* 処理速度がボトルネックにならないか
    * バッチ取り込みが必要では。その場合のエラーハンドリングも検討
* ファイルの場合は静止点が楽なので、データコンペアがしやすい
    * 一方で、ストリーミングとファイルが混ざるとリアルタイム性が落ちるのと、データ整合性でも不安
* データの鮮度はどこまで求められるか
    * 数秒なのか、数時間でよいのかでかなり影響度が大きい
        * 要件を決めきれないなら将来要件が出たときにリアルタイム化するといった方策を練った上で、容易なファイルに要件を落とすといった調整を入れる



### 1-4. 開発言語、フレームワーク

その都度その都度、一番よいと思うツールを選定します。重視しているポイントです。

* 開発上整合性が取りやすい開発フローを描けるものか
    * 例えば、ERDとコード
    * 例えば、API仕様書とコード
* 基本的にはコードか外部定義なのかを駆動に、どちらかを生成したりするのが定石です。ダブルメンテはNG
    * これが守れていれば、その他は大体好みの差といっても良いくらいな気がしています
* 残りは単体テストがしやすい仕組みになっているか、モック化が必要かくらいでしょうか（テストがサポートしていないフレームワークはあまり見たことが無いですが）


### 1-5. データについて

* データの保持期限、アクセス頻度は気になるところです
    * 頻繁にアクセスされるデータはキャッシュ層にあげて、最悪性能向上ができる逃げ道があるかは気にします
* データの改廃
    * データの作成、利用、更新は意識が向くことが多いですが、削除タイミングについては見落とすことが多いです
    * 作成されるものに関しては、削除タイミングがいつなのか（そもそも削除しないこともある）、削除しない場合に性能劣化の起因にならないか、データ品質でアプリケーションの価値を毀損してしまわないかは気にします
    * 年次くらいで改廃を入れる場合は、動くかどうか怖いので、自動化せずに運用で削除するフローに落とすことが多いです。それはそれで怖いですが、データ削除はかなりセンシティブな操作であるため、品質を高めきる自信がない場合はあえて自動化（コード化）まで至らせない判断もありえます


## ②開発生産性で気をつけていること

### 2-1. コードレビュー

* 基本的には最優先でレビューします。自分の開発より大事です
    * コードレビュー待ちはレビュイーからすると緊張するし、作業がブロッキングしやすいので成果を出しにくい時間です
    * なるべく待ち時間を減らすのがテックリードの仕事かなと思います
* 問題なければドンドンマージする
    * これもレビュイーの気持ちなんですが、問題ないコードであればドンドンマージしたほうが良いです
        * 同時に、修正しなければならない内容はキッチリとレビューコメントを付けてあげる
        * コンフリクトは萎えるので、その面でも早くマージしたほうが良い場面が多いです
    * マージした後、指摘したコメントをスルーする人は、次からは修正するまで直さない作戦です
        * まずは信じてみる。駄目だったら別の対応を考える、が良いです
    * マージされることは良いこと、の文化
    * マージしないのは、テストが壊れているとかビルドできないとか、根幹となる機能に影響があるとかそういうものです
        * 周辺の影響度が低い機能は特に早く取り込んで見るのが良いと思っています
* ちょっと不具合を見つけた時
    * typoくらいであれば自分でGitHubのブラウザ上から修正します
        * なるべくやり取りは減らした方がスピードアップになるからです
* 非機能観点を見る
    * リトライはExponential Backoff and Jitterってのは最近よく言われますがこのあたりはよく見ます
        * そもそもリトライをしていないっていうのはよく見られるので注意します
    * ログ出力がループの内部で行っていないか
        * trace/debugレベルであればよいですが、ログ出力位置はよくチェックします
            * 開発アーキテクチャドキュメントにも記載すべき内容ですね
* 機能横断的な実装が入っている場合はAOP（Aspect Oriented Programming）ができないか検討する
    * 個別機能ではなく、機能横断的な実装は、Middleware PatternやAOPなどで対応できないか検討します
    * 何かしらの不具合対応で、コード横断的に3行くらいの変更が入ったとすると、多分何かを疑ったほうが良いです
* キューイングを挟む場合のエラーハンドリング
    * キューイングだけではなく、エラーハンドリングはよく見落としがちなので対応が考慮されているか確認します
    * DLQに入る設定・設計になっているか
    * その場合にはどういうシステム運用・業務運用になるか確認する
    * この辺は開発が軌道に乗るとほぼパターン化されるので気にすること自体減ってきます
        * 逆に言うと、開発立ち上げ時に固めることが大事なので、レールに乗せるまでは気合入れましょう


### 2-2. 開発規約の整備

* 開発アーキドキュメントは整理すべきだと思っています
    * いわゆるコーディング規約だけではなく、何をテストすべきか、どこに処理を書くべきか、ログを出す内容とそのレベルは？といった内容です
        * 詳細は[自走プログラマー](https://gihyo.jp/book/2020/978-4-297-11197-7) にp85 に書いてあります、この章だけでも読む価値アリです

### 2-2. チケットの起票

* 背景が何で、何をしたらクローズなのかは絶対書くようにしましょう
    * 書いていないチケットは別途、起票者に終了条件のものは確認しましょう
        * もし、起票者に聞いて終了条件を明確にできなくても即クローズは、起票してくれた人の気持を無為にする行為なのでやめましょう
            * なんとなく、隔週くらいでチケット状況を更新するタイミングで、閉じれそうなら閉じるといった非同期GCが良い気がします
            * 熱が冷めたらクローズするといった具合で、お互いヒートアップしないくらいの運用が吉
* 横断的なリファクタリングタスク
    * 影響度が大きいので、あまりメンバーに振らずテックリードが自分で担当したほうが良いです
        * よくコンフリクトする
        * リファクタリングの途中でもっと良いアイデアが出てくる
            * メンバーに任せると、レビューでもっと良いアイデアを思いついたので修正させたくなる


### 2-3. Issueのメンテナンスは人任せにしない

* テックリードは大体忙しいので、Issueを整理しておいてって委譲したくなりますが、大体良いことはないです
    * タスクの優先順位付けや、Issueの状況分析はおそらく一番重要な職務なので、一番わかっている人がやりましょう
    * 顧客要望や不具合など、部分的に委譲するのはありだなと思っています
    * テックリードは、おそらく最もBacklogやGitHub Issueを見るくらいが一番正しいかなと思います

### 2-4. 優先度付け

* 開発メンバーのスキルを見てタスクを依頼します
    * 似たタスクをこなしたメンバーに類似タスクをアサインするともちろん効率的。なるべく戦術的に成果が上がるようにします
    * 育成用途では特定のメンバーにナレッジが偏るので、定期的に入れ替えることも忘れずに
* 重大な機能は信頼できる人に任せる
    * 一番、意欲があり技術が高まって来たメンバーに難しい仕事を振ります
    * タスクの難易度と、メンバーのスキルセットはかなり注意を払います


### 2-5. 同時に複数のIssueをアサインしない

* できれば1つまで。どうせ着手しないため
    * 最大で2つまでが限界
    * WIP中の機能開発は何も価値を産まないため、理想は1つタスクアサインです
        * レビュー待ちや気分転換のため2つくらいまでが良いです
        * 4,5はやりすぎです

### 2-6. あったら良いな機能は作らない

* 管理者機能や開発者向けのレポーティング通知は、利用用途が明確な場合にのみ開発します
    * 利用イメージが付いていない場合は、便利スクリプト化までにしておくなど、濃淡つけて対応しましょう

### 2-6. クローズさせる

* 中途半端に仕上げて別の仕事をやる人は一定数いる
    * 気分屋だが仕方ないのでリマインドして、クローズさせるように導きます
* 80%くらいまで仕上げて残り20%、ずっと進捗が上がらない人もいます（よく見ます）
    * 最後のネックになっているものを可視化し、それが他者なのか何かブロッキング要素がないかはあぶり出して対策を打ちましょう
        * 案外、チーム内外のアナウンスに心理的影響があって言い出せない、みたいな人も多いです


### 2-7. チケットのクローズに至るロジックを信じない

* 信頼しても良いけど、無防備はダメ
    * 重要な機能は自分でも確認すること
    * 個人に依存するのではなく、品質チェックゲートはいくつか組織的に用意しよう

### 2-8. ワンショットのドキュメントにしない

* なにかしら設計のインプットとなった資料は、できればそのまま正式版のドキュメントとして使えるように汎化させます
    * 作って説明して終わりではなく、資産として使えるように二度美味しを狙っていきます


### 2-9. ポカヨケ

* 開発者は人間なので必ずミスをします
    * 仕組みで防ぐことができるものは仕組みで防ぐようにします
        * 例えば、git pushでmainブランチを直接プッシュできない仕組みとか
    * CIにLinterを仕込むとかも含めます
* 開発者が勘違いしやすい名称はやめる
    * 不整合な名称はできる限り正します
        * ちょっとした齟齬で時間を奪われるのがもったいないので、気がついたら修正します
    * 例えば、環境変数は一般的な名称に寄せるなどです
        * PROXY_URLよりHTTP_PROXYにするなど
* なるべく一般的な名称・概念に寄せる
    * 勘違いが減らす取り組みです
    * 例えば、make servertest より make testでテストができる仕組みを整えるなどです


### 2-10. 環境構築

* `docker-compose up -d` と `make test` で単体テストが起動するよう、環境構築を整えます
    * その他の手順はなるべくREADMEにまとめるようにします
    * 同じハマリを別のメンバーが行わないようにします
* その他、単体テストの実行方法は make test だけではなく、例えば go test コマンドでも動かせるようにします
    * 個別の関数テストに関しても、大量の環境変数をexportする必要があるのはスピード感を落とすので、テストコードでは環境変数設定を無くして動かせるようにします
* `.editorconfig`、`.gitignore`, `.dockerignore`, `.env`, `.vscode` など設定ファイルは開発立ち上げ時になるべく揃えておきましょう
    * このあたりのメタファイルは漸進的にでもキレイにできるので、間に合わなければ優先度を下げても大丈夫かなと思います
* 便利系ツールも環境構築手順書に追記する
    * 例えばChromeExtensionです
        * [JSON Formatter](https://chrome.google.com/webstore/detail/json-formatter/bcjindcccaagfpapjjmafapmmgkkhgoa)
        * [Swagger Viewer](https://chrome.google.com/webstore/detail/swagger-viewer/nfmkaonpdmaglhjjlggfhlndofdldfag)
    * 「○○で困っている～」っていうメンバーに、コレ便利だよって差し出すのではなく、最初から提示することが大事です
        * とにかく情報を前だしするコストは低いので、情報量で非対称性を作らないように意識します


### 2-11. 口だけではなく正解を提示するのも大事

* メンバーに最後までやり遂げて欲しいという意識もありますが、初志貫徹するとお互い疲労度が蓄積しますし、人生これから先は長いし、例示は大事だって数学ガールのミルカ先輩も言っていました
    * テックリードがそれ以上のマネジメントロールと異なるのは、自分も手を動かす事ができるということだと思ってます（まぁPdMでもEMでも動かす人が動かしていそうですが）
    * 特に設計時に考慮事項の抜け漏れが多い時、最後までそのメンバーに担当させるのは生産性が悪いと感じることが多い
    * メンバーには1日ごとに成果を出してもらえるように、50点以下の状態なら巻き取って、部分的に依頼するか叩きを作ってそこから仕上げてもらいます
    * 口だけ指示にならないよう、時には自分で手を動かします。動かしすぎて自分の首を締めないようには注意ですが、基本的にメンバーに設計開発を委譲するスタンスであればそこまで留意すべきことになったことは今のところ無しです
* 設計タスクをテックリードの考えを当てるクイズゲームにしない
    * 正解までの筋道が詳細レベルまでテックリードが思い描けるなら、テックリードが設計すべきです
        * メンバーに委譲させて（放り投げて）、自分の考えと違うから設計し直しを命じるのは、ヘルシーじゃないと思います
    * パットやれるなら自分でやり、できない部分をメンバーに委譲して助け合うのが自然な形だと思います
    * そうするとテックリードの作業時間が奪われるので、コアな部分だけ方針を10分でも良いのでまとめ、そこをベースにメンバーに設計を依頼すると良いと思います
    * たたき台は大事って話でした


## ③品質

* システムレベルのI/F品質
    * システムレベルのInput/Output部分はかなり厳密に確認します
        * このあたりは、ジュニアレベルだと見逃しがちなポイントが多いのと、調整先や問い合わせ先が外部になることが多いので、比較的シニアな人に担当してもらうことが多いです（というか、自分自身がやることが多いです）
* 一番、サービス（システムを叩く）ロールになる
    * システムI/Fを担当すると、一番そのサービスを利用するロールに繋がります
        * そのサービスのフィードバックを一番行えるので、ここを握っておくと最終的な品質に好影響を与えることができます
* テストデータ
    * なるべく本番相当のデータ品質を準備すると、クオリティの高いテストにできます
        * そのため、本番データを引っ張れる仕組みを作れると、勝負は半分決まったようなものです
* 単体テスト
    * C0で85%くらいを目処にします
    * あくまで目安なので、それ自体をゴールにしないようにします
* バグ密度、テスト密度
    * イテレーションを小さく回すプロジェクトだとバグ密度は難しいなと思っています。テスト密度は目安になるので、重要機能な割にテストケースが少ないと、機能追加のタイミングでケースを追加したり、してもらったりします
* テストケースレビュー
    * コードレビューより実は大事です
    * テストケースの観点出しはテックリードの腕が問われる一つですが、まずはメンバーに出してもらってそこからブラッシュアップすることが多いです
        * あまりテックリード自身がやり過ぎると、ワーカー感が強まる仕事なのであくまで指摘しつつ最後に枠組みをブラッシュアップしてあげると良いかなと思います
* データ品質
    * IN/OUTのデータがトレースできるような仕組みをアーキテクチャレベルで仕込んでおくと楽です
        * トレースIDなど
    * 他にも、受信テーブル、送信テーブル、それらの管理テーブルなどです
    * I/F周りは責任分界点で、障害調査が多い箇所ですので、運用が楽になる仕組みはかなりこだわると後々自分を救います


## ④会議運営、情報伝達、コミュニケーション

* ドラッカーも言っていました
    * 第一のルールは、目的の明らかでない会議は開かない。
    * 第二のルールは、出席者の数を減らす。
    * 第三のルールは、会議の時間を短くする。
* 成長の機会を与えるため、とりあえずメンバーになるべく会議に出るように進める人もいますが、基本的には反対です
    * 1,2回、どういった会議の雰囲気か教えるために参加させるのは意味がありますが、それ以降は議事録などで代替可能な気がします
    * 発言しないであったり、ステークホルダーとしてリーダーが代替可能であればメンバーの参加は極力スキップするようにします
        * 会議の時間が真水の作業時間に充てられるので、正直一番生産的な施策です
* Daily Standup Meeting
    * 朝会です。社内での運用は[ここ](https://future-architect.github.io/articles/20200129/)で紹介されています
    * 見るべきポイントがいくつかあります
        * ずっと進捗が悪いタスクが無いか
            * 技術的にハマっているか、作業時間が取れないか、別の理由か（家庭の事情など）です
                * 技術的ハマリはフォローが必要なので、チャット＋Webミーテイングでフォロー
                * 作業時間が取れないのは、会議参加や事務手続きなどで時間が取られている例が多いです
                    * 会議時間を抑えるようにと依頼することが経験上は多いです
        * 本日やると宣言しているタスクを欲張りすぎていないか
            * 4つも5つもやると言う人がいますが、やれないので減らします
                * 作業見積もりが甘いということなので、フィードバックしたり、一緒に見積もりを手伝います
        * 昨日やったタスクとの予実管理
            * 前日の宣言したタスクと、当日のタスクの差分を見て、振り返りを促進します
* 出席する会議で発言する機会を設ける
    * あまり会議に出さないようにといっても、週1くらいだと逆に出席したほうが良いと思います
        * せっかく会議に出るのであれば、何か発言する機会を作るのも重要です
        * 技術的なトピックや、工夫点、仕様の不明点などは折角なので資料を作ってもらうことが多いです
* 1 on 1
    * 費用対効果があるの？とはよく思いますが、リーダーが時間をとるという行動そのものが重要です
        * メンバーの心理的安全に繋がります
    * 月次からでもやらないよりは、やったほうが遥かに期待とのギャップを埋めることができます
        * 細かなフィードバックオススメです
* 情報アクセス
    * 設計ドキュメントは全員がアクセス可能な状態にします
        * Google Drive、Backlog、etc.
        * 個人的にはgit管理に寄せると幸せになれました
            * 別リポジトリにすると環境構築が面倒になるので、リポジトリルートにdocsフォルダを作ってそちらに集約させています
            * 重いファイル（テストデータ）とかがある場合は、別ブランチ（docs-dataみたいな名前）を作って、そちらにバイナリファイルを置いて、mainブランチからはリンクを参照しています。本当に大きい場合はGoogleDrive、svn、git-lfsを使うべきでしょうが、そこまでスゴイのに出会ったことは無いです（ゲーム業界だとこんなもんじゃないよ！ってのは教えてもらいましたが、システム開発界隈だとそんなに肥大化しないかな？って思います）
    * なにか不明点があると、そのリンクを行単位でシェアできるのがよいところです
        * Driveだと行単位のリンクが不可（多分）なので、優位点だと思います
* Slackに分報
    * 特に求めていません。ただ、新規参画者で立ち上がりの生産性が悪い場合は、適時フォローを入れたい（主に自分の精神衛生上）のため、15分ハマったらハマっているよって投稿してもらったりは良くします。正直、PullRequestが頻繁に飛び始めたら見なくなるので過渡期対応みたいな感じです


# まとめ

実際にテックリードをやっている人のプラクティスがそういえば少ないなと思い筆をとりました。

書いてみると、アーキテクチャ設計以外は、ほぼ開発生産性を上げることを気をつけていました。開発生産性を上げると、メンバーが成長するというサイクルが周り、さらに自分が楽になるということにも繋がるので、良いことです。みなさんも良いナレッジがあれば教えて下さい。