はじめに
こんにちは。サーバーサイドエンジニアの池垣です。
2024年4月に新卒エンジニアとして入社し、先日新卒研修を終えた身になりました。
研修期間中にぶち当たった3つのチームエンジニアリングの難しさと、それにどう向き合ったのかについて3つの記事に分けて書いていきたいと思います。
本記事では、「タスク見積もり」についての試行錯誤を書いていきます。
新卒研修について
3週間でSNSサービスを開発する、というチーム研修です。
1チーム8人で構成されており、自分のチームの職種はフロントエンド3人、サーバー3人、ML/DS2人でした。
以下の必須条件を実装すればどんなSNSサービスにしてもオケとのことでした。
- ユーザ登録
- 投稿
- 投稿の参照
- いいね・リポスト・フォロー
- 画像の投稿
- アプリ内通知
- なんらかの形でAIを活用する
自分たちは「社員がランチに迷わず行けるように推薦AIを活用したレビュー投稿SNSサービス」を開発しました。
サーバーエンジニアとして開発していた僕視点で、このサービスが出来上がるまでにぶつかった難しさとそこから得た学びについてお話ししていきます。
あくまで僕個人の感想なので悪しからず。
ぶち当たった問題3つ
主にぶち当たった問題を整理すると綺麗に
- 個人の問題
- サーバーサイド内の問題
- チーム全体の問題
になっていました。
今回の記事では最初の「個人の問題」についてお話ししていきたいと思います。
【個人】見積もりと現実の作業時間のズレがえげつない
僕が直面した最初の問題は、僕自身のタスク見積もりでした。
僕たちのチームは、毎朝15分と夕方30分を使って、その日のタスクを確認し、進捗を共有する日課を設けていました。
朝のミーティングでその日の目標を設定し、夕方には達成度を振り返り、翌日の計画を立てます。
しかし、プロジェクトが進行する中で、ある日気づいたのです。僕がその日に計画したタスクを完遂できた日が、一度もないことに。
大抵はその日に宣言したタスクの半分ないしは1/3の量しか完了できていなかったのです。
PMは僕が見積もった時間を元にガントチャートを組んでスケジュール管理していくので、当然サーバー側のTODOがどんどん後に積もっていくわけです。
そもそもこのプロジェクト自体、3週間後に成果発表をして終了という時間境界型プロジェクトなので、完成できずに納期が来たらそこで終了です。
徐々にチーム全体にスケジュール不安が押し寄せます。
この状況をまずいと考えた僕は事態を改善するための対応策を次々と試していくことになります。
このセクションでは僕が試行錯誤した一部始終をお話ししていきたいと思います。
1. もっと一生懸命頑張る
はい。最初の打開策は「もっと頑張る」でした。
自分が見積もった時間内にタスクを終わらせるために、もっと頑張るようにしました。これには全国のムキムキ脳筋協会から拍手喝采を浴びれることでしょう。
冷静に考えると、今まで精一杯頑張って、できていなかったことを、もっと頑張るようにしたからといって解決する問題ではありません。
この時の自分は「なぜ見積りの精度が悪いのか」というよりかは「なぜ自分は見積り通りに作業を終わらせれないのか」というところに着目してしまっていました。
そうなると変えていくのは見積もりのやり方ではなく、見積もりに間に合わせるための自分の行動となります。
具体的に変えたこととしては、
- 単純に作業時間を増やす(8時~21時稼働にする)
- 品質より速度を優先したコードを書き進める
- 時間がかかりそうな複雑なタスクはTODOにしていく
です。
これをした結果、一体どうなったか。
その日に計画したTODOは何とか完了報告ができるようになりました。
なのですが、作業時間を増やしたので徐々に体は満身創痍となり、速度を優先し品質を意識しない実装をしたので全体的にぐちゃぐちゃなコードが散りばめられることになりました。
さらに時間がかかりそうなタスクを「一旦TODO!」という魔法の言葉で片付けていただけなので、一見作業が進んでいるように見えるが実は後回しにしているだけ、という状況になりました。
ここでやっと問題は違うところにあると気づきました。
原因を分析したところ、「この作業はスムーズにいったらこれくらいで終われるな」というふうに希望的観測を含めた短い見積もりを設定し、それを 努力目標としてしまっていたこと に気づきました。
つまり、このズレの根本的な原因は「 見積もり時間を努力目標と捉えている 」ことにありました。
「間に合うか、間に合わないか」ではなく、「スケジュール予測が収束していくかどうか」に焦点を合わせるべきである
(エンジニアリング組織論への招待/第4章)
なので次は、見積もりに対してどう間に合わせるのかではなく、どうしたら見積もった時間に作業が収束していくか、について考えるようにしました。
2. 「いけるぜ」と思った見積もり時間を単純に3倍してPMに言う
不確実性を考慮した上で見積もりをする、と一言でいえど、その時点でどれくらい不確実性が潜んでるかを推測するのは至難の業でした。
そこでまずはこれまでの見積もりと自分の作業時間の平均的なズレを計算しました。
すると大体がおよそ3倍ズレていることが分かりました。
走り出してすぐのプロジェクトの不確実性と、自分の技術力を鑑みると確かに想定の3倍ズレることは納得できました。
それからはこれまでと同じく楽観的見積もりをしてから、その時間に3倍かけた時間を見積もり時間として提出することにしました。
まだまだ脳筋の名残があるのはさておき、これは意外と効果的でした。
これまでの間に合うかどうかの見積もりよりかは精度が高くなりました。
とはいえ、じゃあ見積もりは自分が考えた時間に3倍すれば完璧なのかと言われればそんなことはないです。
PMも、「この作業は40分で終わる想定ですが、これに3倍をかけた時間が120分なので、120分で終わります」と言われても困るはずです。
なので次は より精度の高い見積もりにする にはどうしたら良いかを考えていきました。
3. 詳細までタスクを分解して、それぞれ楽観的、悲観的見積もりをする
これまで 見積もっていた対象が粗く大きいこと に気づきました。
当然大きなタスクを見積もるとその分ズレは大きくなります。
例えば「レビューを投稿するAPIを実装する」という粒度で見積もりをするのと、「ドメイン層にReviewオブジェクトを追加/ユースケース層のinteractorで・・・」というように粒度を細かくした上でそれぞれに見積もりをする方が精度は上がります。
(今これを書いていて、いや当たり前のことだろと思うのですが、当初プロジェクトの要件を実装しきれるかどうかに必死になっている時の自分はこれが見えていませんでした)
なのでタスクを細分化した上でそれぞれ 楽観的見積もり と 悲観的見積もり を行いました。
最後にそれぞれを足し合わせて、「このAPI実装の見積もりは60分~90分です」と伝えるようにしました。
これなら以前よりもだいぶ現実的で説得力がある見積もりになります。
ただ、これで完璧ではありませんでした。
当初作業をしていく順番は特に決めていなかったので簡単な作業は予定通りに進むが、不確実性の大きい複雑な作業に対しては沼ったり詰まったりで見積もり時間を大きく超えてしまうこと がありました。
最後の最後で沼ると、それまで予定通りにいっていたはずのタスクも今日中に終わらない、という状況になりました。
4. 不確実性が高いタスクから取り組んでいく
ここで僕は広木大地さんの言葉を思い出しました。
「 不確実性が高いタスクから取り組んでいきなさい 」
人間は不安なことから目を背けたい習性があるので、簡単な作業から手をつけてしまう。それだといつまで経っても不確実性は削減されないので先に不安量が大きい順にタスクを終わらせていこう。ということです。
僕は何も考えずランダムな順でタスクに取りかかっていっていたので最後まで不確実性が削減できていない状態でした。
次のような不安量が大きい要素を含むタスクから順に終わらせていくことにしました。
- 過去にやったことがない機能実装
- 初めて使用するライブラリを扱う処理
- 要件が曖昧な部分の処理
- バグの要因が多数考えられるような部分の処理
そして、 不安量の大きいタスクが終わるたびに再見積もり して、より精度の高い時間を伝えるようにしました。
上図はプロダクト全体の不確実性コーンですが、同じようにミクロな視点でタスクの不確実性を見るとこのようなイメージになっていました。
ここまででようやく自分が出来得る最善の見積もりが固まってきたように思えました。
ただ、実際にはまだ見積もりを大きく外れることが多々ありました。
この原因について分析するためにslackのログなどを見ながら、1日の中で自分がやっていることを客観的数字と共に書き出すことにしました。
その結果分かったこととしては、「 自分の作業をしている時間が30%ほどしかない 」という事実でした。
他の時間は何をしているのかというと、サーバーのメンバーが詰まっていたらハドルを開いてペアプロしたり、フロントのメンバーとAPIのすり合わせをしたり、です。
なので、次はこの 自分の作業の割合をいかに上げていくか に焦点を移していきました。
5. 自分の作業だけに集中できる時間を作る
当初、自分に用があるときはメンションしてもらい、すぐにハドルを開いて対応するという方法をとっていました。
常に開かれている状態だったので当然作業の途中で雑多なタスクが入り込む形となります。
そこでやったこととしては、「朝7時から始業までの10時の間に、その日の1番不確実性が大きいタスクを片付ける」です。
業務が始まる前だとメンションも飛んでこないので自分1人の作業に集中できます。
浅い集中だと3時間かかるものも、深い集中力でもって一気に取り掛かると40分で終わったりすることはよくあります。
この朝作業の効果は絶大でした。
タスクを最後まで終わらせられないとしても、 午後の浅い集中力の時間帯に、脳死に近い状態で作業できるようにタスクをさらに細分化してほぐしておく だけでも生産性は全く違います。
これで1日の自分のタスクに対しての作業時間割合を多少増やすことはできました。
とはいえ、午後の6時間という長い時間はやはり雑多なタスクが入り込み半分以上は違うことをしているという状態でした。
6. すること、しないことをはっきり決めてチームに共有
雑多なタスクについて細かく分析したところ以下のことが分かりました。
- メンバーが責任をうっすら全体的に持ってしまっているため、対応しなければいけない幅が大きい
- 自分が対応するには非効率な雑務(よく知らない部分に対する質問等)も含まれていた
- リアルタイムで解決しなくてもいい雑務も含まれていた
このことから次は、 サーバーのメンバーが持つ責任範囲をハッキリさせ ました。
「AくんはOpenAPIの定義周りに責任を、BくんはML/DSとの接続回りに責任を、Cくんはインフラ周りの責任を」というように。
そうすると自分がやるべきこと、やらないべきことがハッキリして、 自分が割かなくてもよかった時間が丸ごと浮き出て きました。
7. ちょこちょこハドルするのではなくスポット対応
そして、リアルタイムで解決しなくてもいいような緊急性の低い雑務をなんとかしたいと考えました。
その結果チームに以下のように伝えました。
- 自分に対して相談がある場合はメンション付きの文章でやり取りする
- 自分は作業がひと段落してからまとめてそれらの対応をする
- 緊急性が高いときは声かけてもらうが、それ以外の雑務に対しては、出来るだけ自分のペースで空き時間対応するようにする
- 全体的に進捗や方針を見ながら薄い集中力で進めるのではなく、自分の作業時間を捻出するのを第一にする
要は、開かれた状態でちょこちょこハドルするのではなく、 スポットで対応して作業時間をギュッと集める ようにしました。
そうしたことで1日の間で自分の持っているタスクに対して一括で集中できる時間を最大4時間とれるようになりました。
朝7時から10時までの3時間。14時から18時までの4時間。その他の時間は違うことをする。
結果自分の生産性がみるみる向上し、見積もり通りに作業を完了できる確率が格段に高くなりました。
まばらに時間を過ごすのではなく、 集中の濃度をコントロールすることの大切さ を思い知った瞬間でもありました。
8. ベストを諦めてベターな方法に切り替える締切をあらかじめ決めておく
それでも沼るときは沼ります。
大きな沼にハマると大きく見積もりからズレます。
プロジェクト終盤、ORMであるGormのバージョンの違いで沼ったときのことです。
外部キー制約を設定しようとしてオブジェクトにタグを付与しても、一向に制約が効かない状況が続きました。
当初スムーズに完了できる見込みの作業に思わず手間取ってしまったことに、焦りを感じてしまい我ながら冷静さを欠いてしまっていました。
gormのv1とv2のドキュメントを読み漁り、その原因を探求するのに躍起になってしまいました。
気づくと「ここまで時間を消費したのだから最後までやるしかない」と損切りできない状態に陥っていたのです。
ハッとした時には1日が終わっていました。
本当に後悔しました。
この経験から得られた教訓は「 タスクに取り組む前にあらかじめ締切を設けて第2の方向を決めておくこと 」でした。
この時間までやって解決しなかったらベストのやり方ではなくベターのやり方に切り替えるということを事前に決めておくのです。
そうしておくことで、沼ってしまった時の損切りするか否かという苦しみもなく スムーズに方向転換 できます。
見積もりの精度を高めること と、 見積もりがズレた時に怪我をしないように尻を決めておくこと 。その2つを意識することが大切だということを身を持って学びました。
あわせて読みたい
今回は色々と自分の頭で試行錯誤しましたが、スケジュール不確実性に対処する手法はこれだけではありません。
- ストーリーポイントとベロシティによる見積もり
- 不安量を集めて管理するCCPMアプローチ
- 多点見積もり
- 相見積もり
- 小さいスプリントを繰り返し実績から予測する
と、世の中にはスケジュール不安を可視化し、削減していくのに有効と言われている方法が数多く存在します。
これらを理解しながら丁寧に導入していくことでより精度の高い、かつスケジュール不確実性に対処した見積もりが可能になっていくのだと思います。
以前は以下の記事を読んでも「ほおー確かに。まあでもそらそうか」と頭の中をすり抜けていた内容ですが、試行錯誤をし終えた今読み直すと 身体の芯まで染み渡る濃い内容 ばかりでした。
やはり机の上で知識として読むのではなく、ちゃんと手を動かして汗をかいたあとに読むことが大事ということなんでしょうか。
まとめ
これまでの試行錯誤から分かった大切なことをまとめたいと思います。
- 見積もりは 努力目標ではない
- 「間に合うか否か」ではなく「 スケジュール予測が収束していくかどうか 」を管理すべき
- タスクを 細分化 して 楽観的、悲観的見積もりをして幅を持たせた見積もりをする のが大事
- 不確実性の 高いタスクから 潰していく
- 自分が持つ タスクに取りかかる時間を確保できる環境 にする
- 早朝、業務が始まるまでに重いタスクをほぐす
- すること、しないことの 責任範囲 をハッキリ決める
- 雑務は スポット で対応する
- 見積もりは 常に修正 していく
- 事前に ベストの方法を諦める期限と切り替えた際の方法 を定めておく
最後に
経験のあるベテランエンジニアが肌感覚で見積もりをして終始オンスケで進む、というのを見て、ものすごく憧れてしまう節があります。
ですが、経験が浅いうちは 色々と試行錯誤して精度の高い見積もりを出せることが大切 になってくるのだと思います。
工数見積もりはエンジニアリングタスクの中でも特に難しいと言われております。
ある方法を真似たからと言って一長一短で身に付くものではありませんが、開発作業やプロジェクト全体に及ぼす影響が大きいため、慎重に取り組む必要がありそうです。
技術を深めていきつつ、信頼できるエンジニアになるためにも日々精度の高い見積もりを出せるように精進していきたい所存です。
ここまで記事を読んでくださった皆さま、誠にありがとうございました。
次回はサーバーサイドチーム内での難しかったことと試行錯誤について書いていきたいと思います。