こんにちは。わいけいです。
最近エンジニアとしてマネージング寄りの業務をすることが増えてきました。
今回の記事では、その中で自分の考え方がどう変わってきたかをメモしておきます。
私の場合は、まずフリーランスエンジニアとしてこの業界に入ってきました。
それもあって、今までは基本的にあくまで「良いコードを書く」ことが仕事であり目標でした。
以前からいわゆる上流工程にも全く興味関心がなかった訳ではありません。
しかし、これまで私が経験したのは
- システムの要件定義(ビジネス的な視点も含む)は社員が行う
- フリーランスは(やったとしても)技術的な設計のみ担当する
という切り分けの現場が多かったんですよね。
そんな背景もあり、マネージング層以上の上流に携わる機会があまりありませんでした。
そして、そもそもマネージャーという役割に必ずしもいいイメージだけを持っている訳ではありませんでした。
マネージングと聞くと 「業務の中で自分がコード書く時間が削られるのでは?」 という漠然とした不安がありました。
もしかしたら同じ思いを持っているエンジニアも多いのではないでしょうか。
(丁度これを書いている日の前日も、とある交流会で上場企業のCTOと対面で話す機会があったのですが、彼も「マネージングはクソw コーディングが正義!」と言い放っていました。)
私自身が実際にここ最近マネージメントをやってみた感想はやや異なります。
色々と自分にポジティブな影響があったので、その概要をシェアできればと思います。
ここでいうエンジニアリング・マネージャーとは
まず最初に
そもそもエンジニアリング・マネージャーとは何なのか
という点を明確にしておきます。
私自身、実際に経験する前は「エンジニアリング・マネージャー」の業務内容のイメージは漠然としていました。
せいぜい、
「コードも書いてスクラムマスターもやって、って感じでしょ?」
くらいの解像度だったんですよね。
しかし、実際にマネージングをやってみることで、他にもっと色々な仕事があることに気付きます。
一例として、自社開発のスタートアップで新規プロダクトを開発する際のエンジニアのマネージャーをイメージして仕事内容をまとめてみました。
エンジニアリング・マネージャーの仕事内容
要件定義(ビジネス面含む)
あえて、エンジニアリング・マネージャーの仕事として要件定義(ビジネス的観点含む)を最初に挙げておきます。
私は 現場でマネージングする人間が要件定義の段階から関わっておく ことが重要だと思っています。
- マネージャー自身の仕様理解度が開発チームの進捗スピードを左右する
- 仕様策定時からエンジニア観点から助言できると後で悲劇を避けられる
という経験則が理由です。
例えば、ライ○ップをIT化したような健康管理アプリを作るとしましょう。
このアプリでは、ユーザーがその日の食事の画像をアップロードしたり、運動した量をトレーナーに報告できるとします。
さらに、それに対してトレーナーがアドバイスを送れるという機能もあるとしましょう。
そして、このアプリ上でユーザーに対して課金できるようにしたい、とします。
イメージとしては、
- フリープランなら月に貰えるアドバイスは10件まで
- 課金プランに加入すれば無制限にアドバイスが貰える
といった具合です。
この課金機能を実現するまでに、どういう作業が必要になるでしょうか。
取り敢えず、
- プラン情報を管理するマスターテーブルを作らないとなあ
- Userのプラン情報もDBに保存しておく必要があるなあ
- Userがアドバイスを貰おうとする度に今月の受け取ったアドバイス数が限界に達しているか確認し、超過している場合はエラーにしよう
- 決済周りはStripeを使えば迅速に実装できそうだ
とか色々考えが湧いてくると思います。
しかし、いざ実装をはじめてみると
- 実は登録してから2ヶ月間の間は課金してなくても機能をフルに使える
- 実は課金していても過去に迷惑行為を行ったユーザーは機能に制限がかかる
- 実は友達招待機能があり、友達招待経由で登録した/させた場合は課金の有無に関わらず2ヶ月全機能が使える
- 実はアプリ内で使えるクーポンの概念があり、請求金額をチャージする際にはクーポンを考慮しなくてはならない。
など細かい仕様が色々と登場してくるものです。
更に
- 実はこのアプリは法人単位での契約を基本としており、請求はユーザー単位ではなく、そのユーザーが勤務している会社に対して行う
なんて仕様が存在しているかもしれません。
こういった情報は、実装に頭で考えても分かるものではありません。
その人がどんなに腕の良いプログラマーだったとしても、要件検討の会議に参加していなければ知りようがないものです。
そして、悲しいことに実務では、
「コードの書き方が分からずハマる」
というパターンより
「仕様を理解しておらず間違ったものを作ってしまう」
パターンの方が多いものです。
マネージャー自らが仕様を深く理解しチームに浸透させていくのが重要だと考えています。
これにより開発チームのメンバーの手戻りが最小化し、高速に開発を進められるようになります。
そのためには、
・そのアプリは誰がどういう状況で何のために使うのか
・個々の実装はユーザーが快適に利用するためにどういう機能を提供しているのか
といった根幹部分を明確化&常に組織内部で発信していくことが大事だと思っています。
そして、 そもそも要件定義の段階からエンジニアリング・マネージャーが関与しておくことには別のメリットもあります。
早い段階から技術的観点からの提言をしておくことで、後々発生しがちな
・やっぱり出来ないことが判明した
・出来るけどコストが高すぎた
・小規模でなら動くけどスケールが非常に難しい
という事態を防げるのです。
例えば、先程の健康管理アプリの例で、
- ユーザーがアップロードした食事の画像は最低3年は保存したい
- 課金転換率をあげるため、支払いから5ヶ月もの長期間に渡って課金ユーザーに返金できるようにしたい
- データドリブンに事業戦略を立てたいので、日次で各ユーザーのログイン回数やDAUなどのKPIを確認したい
といった要望があったとしましょう。
このアプリの場合、画像アップロードなのでそんなに大きなファイルは扱わないと思われます。
とはいえ、ファイル保存にはS3などを使うと当然コストがかかります。
- 運用予算に対してファイルストレージのコスト比率はどうなるのか
とか
- Stripeを使って請求周りを実装した場合、支払いの5ヶ月後であっても返金できるのか
とか(ちなみに出来ます)
- DBにNoSQLを使うことになっている場合、KPIの集計はうまくできるのか
とか技術者視点から早い段階で相談/提言しておくべきポイントは挙げればキリがありません。
このあたりは、後になって軌道修正するのが非常に難しいケースもあります。
なので、マネージャー的ポジションのエンジニアが早い段階からアドバイザ的に関わっておくのが吉だと思っています。
技術選定
特に新規プロダクトの開発の場合、要件を満たすためにどのような技術を使っていくのかを決定していく必要があります。
この作業をマネージャー的ポジションのエンジニアが担当するという場合も多いでしょう。
例えば
・バックエンドのインフラはどういう構成にするのか
・アプリケーションの言語やフレームワークは何を使うのか
などを決めていきます。
例えば、
・初期投資を抑えながら柔軟にスケールさせたい。なのでインフラはクラウドで運用し、極力AWS上ですべてを完結させよう。
・要件の変化が激しいことが予想され、かつKPI集計などをしっかりやりたい。なので、(論理設計が難しくなりがちな)NoSQLを避けてRDS Auroraを使おう。
・アプリケーションのフレームワークは特段縛りは無い。だが社内メンバーの経験値を考慮してバックエンドはRuby on RailsでフロントエンドはReactにしよう
といったことを決めていきます。
(すでに走っているプロジェクトの場合はこれらは既に決まっていることも多いかと思います。)
この辺りの技術選定は個人的には楽しい作業です。
要件を満たせる範囲で自分好みの技術を選定していけるわけですからね。
なお、この時にビジネス面を含んだ要件をしっかり理解しておくことが重要になります。
例えば先程の健康管理アプリの場合だと、
-
ユーザーが運動した際の心拍数などの情報を独自のウェアラブルな端末から取得したい。だが、その端末のメモリが貧弱でhttpのようなリッチな通信は難しい。なのでサーバーのフレームワークもCoAP通信などに対応可能なものにしよう。
-
今回のアプリの性質上、災害時等の可用性までは担保しなくても良い。なのでマルチリージョンでの冗長化などは一旦無しで良いか。
-
普段は低アクセス数だが、特定のスポーツイベント時などにリクエスト数の急激なスパイクが予想される。なので、サーバー側のスケーリングが高速で行われる必要がある
といった風に設計に関して思考が深まっていきます。
これはあくまでも架空の例なので解像度がかなり粗いです。
実務だともっと細かな要件理解が必要とされるでしょう。
いずれにせよ要件定義と技術選定はセットで現場のマネージャーが関与しておくべき仕事だと思っています。
進捗管理
そして、開発スタート後の進捗管理ももちろんエンジニアリングマネージャーの仕事です。
アジャイルで開発している場合、日々カンバンボードなどを確認してメンバー全員のタスク確認や問題共有を行っているチームが多いかと思います。
日次で、朝晩二回ほど
- 全体のスケジュール感の確認
- 各人のタスク内容や困りごとの確認
をやっていくと良い感じにハマるかなと思います。
ちなみに、私が以前いた現場ではリモートワークのエンジニアが多かったという事情もあり、バーチャルオフィスサービスを活用していました。
具体的には、gatherというサービスを利用して開発定例会を行っていました。
下に引用したものが、公式の画像です。
このようにバーチャルオフィスを使うと、ドラクエなどのゲームをプレイしている感覚で開発ミーティングが行えるのが特徴です。
gatherでなくても良いのですが、こういった感じで その場にいないのに何故か集まってる感を出せる サービスは意外な効果を発揮してくれます。
やっていることはGoogle MeetやZoomと本質的に変わらないはずのに メンバー間のコミュニケーションのハードルが激下がりする んですよね。
中々面白い現象だと思います。
ちなみに私はウォーターフォールでの開発経験はありません。
そのため、ウォーターフォールのカチッとした進捗管理のやり方などはわかっていません。
ここは今後の課題とさせてください。
コードレビュー
コードレビューを行うのもエンジニアリング・マネージャーの仕事になります。
これに関しても、仕様理解が意外と大事です。
そもそも仕様を理解していないとコードレビューができない、もしくはめちゃくちゃ時間がかかるということになります。
ここでも
- マネージャー自身が仕様を解像度高く理解する
- 仕様をチームメンバー全員に浸透させる
努力が必要になります。
そして、 レビュー時の負荷を軽減する仕組みを作る ことも重要になってきます。
典型的には自動テストがしっかり組み込まれたCICDの設計・構築を行うことがまず挙げられます。
自動テストにはメンバー間の作業量の勾配を調整する作用がある 、というのが最近の気付きなのですが、それについては後述します。
ちなみに、我々のチームの場合CodeRabbitというAIコードレビュー補助ツールを活用しています。
これによってレビューを高速化しています。
CodeRabbitは、Github Actionsでpull requestに対して自動でレビューを行うツールです。
(裏側ではOpenAIのAPIを叩きにいっています。)
PRの要約(新規にテストを追加した、リファクタを行った、など)に加え、個別の修正箇所にAIによる監修が入ります。
AIによる指摘は現実的には読み飛ばされていることも多いのですが、たまに
「ここでこの変数を使うのは誤りで、こっちを使うべきでは?」
という有益な指摘をしてくれるので助かっています。
渉外
組織や案件によってまちまちであるとは思いますが、私としては渉外もエンジニアリングマネージャーの仕事の範疇 なのかなと思っています。
なおここでいう渉外とは、発注者などの外部のステークホルダーが存在する場合に彼らとの開発に関する各種折衝を行うことを指します。
私も実際にプロダクトがある程度形になってきた段階で時々お客さんに見せに行っています。
が、正直に言うと、客先にデモに行くときは結構緊張しますね。
プレッシャーがかかるのも事実なので渉外をあまりやりたがらないエンジニアが多い理由は正直分かります。
が、顧客の生の声を聞けるのは開発者としてもプラスであると思っています。
機密保持上の理由で、実際に私が経験した顧客折衝について事例としてここに書くのは難しいです。
なので代替として先ほどの健康管理アプリを例にしてみます。
仮に、アプリの販促のために既存のフィットネスジムを展開しているグループ会社と提携したとします。
- ジムの入会者にアプリの課金プランを無料開放してジム側の会員獲得に協力する
- 代わりに、ジムの運営サイドから一定のフィーを受け取る
といった協業モデルを組んだとしましょう。(いかにもありそうな話だと思います)
今回の事例ではジムの運営会社側も開発に一枚噛む、という流れになったと仮定します。
こういったケースであれば、アプリ開発を担う我々には、ジムのグループ会社側の担当者に開発成果を報告に行く機会が定期的に発生するでしょう。
このときに社内のビジネスサイドのメンバーだけだと細かい質問に答えにくいことが予想されます。
アプリ上のAUなどのKPIは答えられても、
「こういう機能があると嬉しいんだけど、どれくらいで作れそう?」
といった質問には持ち帰りが発生するかもしれませんね。
そこで開発サイドの人間も同行しておくとベター、というわけです。
こういった折衝にはプログラミング能力とはまた別の能力が要求されることになります。
が、個人的にはプロダクトの外部ステークホルダーの生の意見を知ることができる良い機会だと感じています。
採用・育成
最後に、エンジニアの採用や育成もエンジニアリングマネージャーの重要な仕事です。
まず、採用業務は下記のようなものです。
- 正社員や業務委託フリーランスのエンジニアの書類審査を行う
- 書類審査を通過したエンジニアの採用面談に臨む
我々の場合は基本的には 「自分より凄い人を採用する」 という採用方針を掲げています。
これは単純に自分より凄い人を採用していくことで、どんどん仕事を任せられるだろうという目論見からです。
結果的に自分が楽をすることが出来、プロダクトも成長するという好循環が生まれるであろうという展望があります。
(ちなみに今の会社では私が一人目のエンジニアなので、この理論でいくと私が社内最弱エンジニアということが証明されてしまうという点からは目を背けておきましょう)
実際に、これまで能力の高いエンジニアをどんどん採用したことで、チームとしての進捗を生むスピードが加速度的に速くなっていきました。
以上の背景もあり、採用は非常に重要な仕事だと認識しています。
また、採用する側を経験しておくことは一人のエンジニアとしても色々学びがあると感じます。
特に最近候補者について思うのは
- 経歴書やスキルシートを漠然と書いているせいで本来の能力が伝わらず、非常にもったいない人が多い
という点です。
これは、個人的には採用媒体によって経歴書やスキルシートのフォーマットが固定化されている弊害だと感じています。
大体の場合は、エージェントから与えられたテンプレートを埋める形で、
- XX年〜XX年の間、開発者としてXXなアプリを作った
- 言語はXXで、他にXXの技術を使用した
という情報を羅列するケースが多いと思います(私もフリーランス時代そんな感じでした)。
この場合その人が技術的な発信活動などをしていない or していてもこちらから特定できない場合は、他の人との違いが非常にわかり辛いという状況になってしまっています。
ある一定以上の単価の人になると、みんなモダンな技術を使ってます。
経歴書を見た感じだと なんだか全員めちゃくちゃ賢そう に見えるんですよね。
しかし、雰囲気は確かに凄そうなのですが、具体的にその人が我々のチームにマッチするかどうかのイメージを持ち辛いのが現状です。
その人が、チームの中でどういう役割を果たしていて、どのくらい活躍していたのかは実際に話してみるまでは非常に見え辛いと感じています。
この結果、
- 実際には優秀な人を書類選考で落としてしまう
- ミスマッチな人と面談をした結果、自分の時間も相手の時間も無駄にしてしまう
という現象が起きてしまいます。
そういった背景から、自分を売りこみたいエンジニアは
- SNSなどで技術的な発信をする
- ポートフォリオサイトなりなんなりを持っておく
- それらのリンクを経歴書やスキルシートに貼っておく
といったことをすべきだと感じました。
自分の技術レベルやこなした仕事の内容を具体的に伝えられる導線があると、採用する側もされる側もハッピーになれると思います。
(余談ですが、ある意味では私がこうして記事を書いているのも自分や自分の会社がその他大勢に埋もれないようにする、という意図もあります。)
このあたりは採用活動を通じて得られた、一人のエンジニアとしての学びでした。
また、 採用と並んで育成も同様に重要です。
育成業務のポイントは、新規参画者がキャッチアップしやすい仕組み作りにあると思っています。
例えば私の場合だと、
- プロジェクトの目的や要件
- システム全体のインフラアーキテクチャ
- 各ディレクトリ内のファイルの役割
- RDBの各テーブルの役割
- 基本的なコーディングの流れ
などを動画資料にまとめておくことが多いです。
新規参画者にそのファイルを共有することでキャッチアップを支援するという手法を多用しています。
自分経験からこのようなスタイルに落ち着きました。
自分自身、技術的な勉強する際、初めの一歩として動画サイトなどでライブコーディングを観て学ぶと効率が良かったんですよね。
また、他にも教わる側のメリットがあります。
そもそも教わる方としても、毎回同じことを人に聞くのは気が引けます。
私自身、
「あれ、これ分からないけどこないだも質問した気がする。もうちょっと自力で調べてみるか。。。」
という状況になることがよくあります。
人に聞けばすぐ解決することを悩み続けるのはチームとしても損失になります。
こういった場合、何度も再生できる動画などに情報がまとまっていると教わる側も精神的にラクです。
動画ならボタンを押すだけで何時でも何度でも情報を聞きに行けます。
動画資料を多用する方法は、要件の変更などがあったときに資料をアップデートする手間がかかるというデメリットもあります。
が、それでも以下のようなメリットが大きいと感じています。
- 文字より喋って伝えた方が重要な部分とそうでない部分の区別が伝わりやすい
- 動画撮影はPC画面をキャプチャすればOKなので意外と資料作成の初期コストが低い
- (肌感覚ではあるものの)文字の資料よりも動画の方が興味を引きやすく、読み飛ばされたりスルーされる確率が低い
勿論これはあくまでも現在の私のやり方です。
状況に応じて最適な資料作成方法などは異なると思います。
必要に応じて参考にしていただければ幸いです。
マネージャーの仕事をしてみて生じた変化
次に、マネージメントを経験した結果自分自身に起きた変化についてメモしていきたいと思います。
大きく言うと、
- 自分個人よりも全体の進捗スピードが関心事になった
- チームメンバー間の認識ズレを無くす仕組みを作りたいと思うようになった
といった変化が起きたように思います。
後者を実現する目的で、動画によるオンボーディング資料システム構築など色々試行錯誤を重ねているのは先述した通りです。
ここからは、前者の
- 自分個人よりも全体の進捗スピードが関心事になった
というトピックに関して、概要をまとめておこうと思います。
自動テストの重要性をより認識するようになった
まず挙げられるのが、 自動テスト に一層感謝するようになったことです。
以前から
「そりゃテストは大事だよね。バグ出る確率少ない方がいいもん。」
くらいの感想は持っていました。
しかし、最近思うのは自動テストがあることで、
- チームメンバー間の作業量格差が調整されている
- その結果としてチーム全体の開発スピードが上がっている
ということです。
まず前提としてマネージャーポジションの人は、かなり忙しいです。
自身の開発や他人のコードレビューに加え、採用周りなどの一部人事系のタスクも担当することになります。
特にコードレビュー業務はそれが終わらないと他のメンバーが作業を進められない状況にもなりがちです。
要はマネージャーが作業を早くこなせないと、チームの他のメンバーの進捗に悪影響が出てしまうわけです。
そういった理由で、ただでさえ忙しいマネージャーに作業が集中するのはチーム全体にとってマイナスだと言えます。
自動テストがあるとそういった事態をある程度軽減できます。
各メンバーが自分で一定程度コードの動作を保証できるので、マネージャーによる動作チェックの工程の負荷を軽減できるのです。
仮にテストを書かない場合でのチームの作業量分布が
一般メンバー | 20 |
マネージャー | 80 |
だったとすると、
これが
一般メンバー | 20 |
マネージャー | 70 |
くらいになるイメージでしょうか。
この場合、テストを書く工程を挟んだことでチーム全体の作業量は増えています。
しかし、ボトルネックになるマネージャーの作業量が減ったことで全体としてのスピードが増します。
自動テストが単にコードの正確性を保証しているだけでなく、 メンバー間の作業量の配分調整を行う機能を持っている ということは私にとっては新しい視点でした。
静的言語やそれに準じる書き方を好むようになった
また、チーム全体の進捗が関心事になった結果、静的言語を好むようになりました。
具体的に言うと私の場合はGo言語であったり、PythonであってもPydanticなどのライブラリを使って型を縛っておく書き方が快適です。
「スクリプト言語の方がコード量が少なく高速に開発できるだろ!」
という意見の方もいるとは思いますが、如何せん読む方は大変になりがちです。
実際の現場で大量にコードレビューする際を考えてみましょう。
現実のコードレビューでは、(良くも悪くも)
各モジュール内の具体的なロジックについては書いた人を信用しておき、重点的にチェックするのはそのモジュールのインターフェースなど重要な部分だけ
といったスタイルにならざるを得ない場面も多いと思います。
ここで、しっかり型によって定義付けられたコードでないと
そもそもそういったレビュー自体が不可能になる or 可能であっても膨大な時間を浪費する
といった事態になりがちです。
一つ例を挙げてみます。
まず、Pythonで型を意識せずにコーディングした例です。
def get_user_dict(user_id: int) -> dict:
# Simulating fetching user data from a database
user_data = {"id": user_id, "name": "John Doe", "email": "john.doe@example.com"}
return user_data
次にPydanticで型を縛りつつ書いた例です。
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str
email: str
def get_user_pydantic(user_id: int) -> User:
# Simulating fetching user data from a database
user_data = {"id": user_id, "name": "John Doe", "email": "john.doe@example.com"}
return User(**user_data)
最初の例だと、関数の返却値が単なる辞書になっています。
このため他のメンバーが後々この関数を使おうとした際に、その辞書がどういうキーを持っているか知るには大元のソースコードを読む必要があります。
そこで認識の相違が生じて、email
というキーをmail
と間違えて
user = get_user_dict(user_id="sample")
mail = user["mail"]
などと書いてしまい、バグを引き起こすかもしれません。
また、メンバーの注意力が高くてそういう事態が起こらないと仮定しても、コードレビューに手間暇がかかるのは変わりません。
毎回、今扱っている辞書がどういうキーを持っているかを確認しながらコードを読んでいくのはツライものがあります。
一方でPydanticを使っている方だと、この関数を使う開発者はだいぶラクができます。
VSCodeなどのエディタの補完でインスタンスが持ちうるfieldを一瞬で知ることが可能ですし、タイピング数も減らせます。
さらにPydanticはインスタンス化したときにfieldの型が不正だとエラーにしてくれます。
これにより、常に正しい形式のオブジェクトを扱えているという安心感があります。
このように、
- スクリプト言語であっても型バリデーションを行うライブラリを使って型のある開発を行う
- そもそも静的型付け言語を使う
といった施策を行うことで、チームメンバーに読みやすいコードを書くことを「強制」できます。
こういった工夫でマネージャーの作業量を軽減することは、チーム全体の開発速度向上に寄与すると思います。
程よく枯れた技術を好むようになった
また、程よく「枯れた」技術を好むようになったのも変化といえば変化でしょうか。
これも、チーム全体の開発効率を重視したいという理由で生じました。
「最新技術を使いこなしてこそのエンジニアだ!」
という方もいると思いますし、それも素晴らしい考え方だと思います。
ただ、私の場合は
- Google検索が容易
- ChatGPTやCopilotの精度が高い
という理由で実務では安定した技術を使いたいです。
私は自社のエンジニアにコーディングでのGPTやCopilotを活用して開発効率を上げることを強く推奨しています。
そして、それらAIツールの性能は対象のプログラミング言語などによってかなり異なります。
例えばGPTは、Pythonなどネットに情報が多い言語のコードはかなりのクオリティのものを一瞬で生成してくれます。
しかし、(当然ですが)学習された時点以降に出た技術については全く答えることができません。
インフラ等他の部分についても状況は同じです。
ある程度昔からある技術を使った方が全メンバーにとって快適な開発環境になっていくと思っています。
(しかし、新しい技術を全く使わないと停滞を招くので、そこの塩梅は難しいところもであると思っています)
まとめ
今回は、「エンジニアリング・マネージャーを経験したことで自分に生じた変化」をまとめてみました。
割と勢いで書いたので、ここに書けていない部分も多々あるように感じています。
不足部分はどこかで補足できたらと思っています。
今後も技術に関する情報発信を続けていくので、
もし良ければ私のSNSアカウントをフォローしていただけると幸いです。
X: https://twitter.com/yk_llm_gpt
LinkedIn: https://www.linkedin.com/in/ykimura517/
Github: https://github.com/ykimura517