はじめに
これはQiitaで開催されている「新人プログラマ応援 - みんなで新人を育てよう!」イベントの投稿記事です。
前回は「学習用のプログラムと仕事で書くプログラムは何が違うか」というタイトルで、お勉強用に作るプログラムと仕事で書くプログラムはこんなところが違うんだよ〜、というお話を書いてみました。
今回の記事ではみなさんが無事にプログラマとして就職できたと仮定して、「○○さん、このタスクお願いね」と開発タスクをアサインされたときの対応手順を説明してみます。
この記事を書いている人
- 仕事で20年近くプログラムを書いているプログラマ
- 現在は株式会社ソニックガーデンでRubyプログラマをやっている
- Rubyの入門書「プロを目指す人のためのRuby入門」を出版している
- プログラミングスクール「フィヨルドブートキャンプ」のメンターでもある
対象読者
- 新卒、または業界未経験の中途入社で最近プログラマになった人
- その上で、開発タスクをアサインされたものの、「全然成果が出せなくて辛い・・・😭」と落ち込んでいる人
僕が普段Railsを使っているため、この記事ではRailsを使う開発の現場を想定していますが、大半の内容はWeb系企業であれば言語やフレームワークを問わず参考になるはずです。
想定する開発タスク
ここでは以下のような開発タスクがアサインされたと仮定します。
- 対象となるアプリケーションは運用されてすでに数年が経っている既存のRailsアプリケーション
- 商品一覧画面に「CSVダウンロードボタンを付けてほしい」というのがアサインされたタスクの内容
- ローカルの開発環境はすでにセットアップが完了している
TL;DR(長いので最初に結論)
タスクは食べられるサイズに小さく切ってから口に運べ!
アサインされたタスクをそのままほおばると喉に詰まって死ぬぞ!!
・・・と言われても何の話かわからないと思うので、さっそく本編に進みます。
なお、この手順は新人プログラマ専用の手順ではなく、僕自身も普段から実践している手順です。
手順1. 現行の仕様(システムの挙動)を確認する
まずはローカル環境でRailsアプリケーションを動かしてみて、現行のアプリケーションがどういう仕様で動いているのかを確認します。
たとえば、今回の開発タスクであれば「CSVダウンロードボタン」を追加する画面にどうやってアクセスすればいいのか確認します。
「変更するのはこの画面だから」と伝えられても、いざローカル環境で開発しようとしたらどういうリンクをたどればその画面にたどり着けるのかわからなかったり、データや権限が不足していて画面を表示できなかったりすることは結構あります。
手順2. 機能追加の要件や具体的な変更内容を確認する
次に、機能追加の要件や具体的な変更内容を確認します。
「CSVダウンロードボタンを付けてCSVをダウンロードできるようにすればいいんでしょ?」と考えるだけでは甘いです。
- 画面のどの位置にどんなボタンを付ければいいのか?
- ボタンをクリックしたときの挙動はどうなるのか?
- 確認ダイアログを表示する必要はないか?
- ボタンをクリックしたあとにボタンをdisableにしなくてよいか?
- CSVファイルにはどんなデータを出力するのか?
- どのカラムにどんなデータを出力するのか?
- データの出力順はどうなるのか?
- 日付のフォーマットはどうするのか?"yyyy/mm/dd"か、"yyyy-mm-dd"か、それともまた別のフォーマットか?
- CSVファイルのエンコーディングは何にするのか?UTF-8でいいのか、それともShift_JISでないとダメなのか?
などなど、単なるCSVダウンロード機能でも考慮すべきポイントはたくさんあります。
また、すでに他の画面にCSVダウンロードボタンが付いているのであれば、その挙動もチェックしましょう。
システムの挙動には一貫性があった方がいいので、既存のCSVダウンロード機能があるのであればその挙動にあわせる方がベターです。
正常系だけでなく異常系やセキュリティ面の仕様も検討しよう
新人プログラマのうちはついつい正常系の仕様ばかり考えてしまい、異常系の考慮が不十分なことがよくあります。
異常系というのは「場合によっては起こりうる、あまり嬉しくない動作パターン」のことです。
CSVダウンロードで言えば、次のような異常系が想定できます。
- 出力するデータがゼロ件だったらどうするのか?ヘッダ行だけをダウンロードさせるのか、それとも何か特別な方法でユーザーに知らせるのか?
- ダウンロードしようとしていたデータにカンマや改行が含まれていた場合(つまりCSVファイルのフォーマットを壊すようなデータが含まれていた場合)、どういう形式で出力するのか?
他にもログインしていないユーザーや権限がないユーザーが間違って(もしくは悪意をもって)直接ダウンロード用URLにアクセスしてきた場合など、セキュリティ面の考慮もきちんと検討しておく必要があります。
タスクの背景やユースケースも確認しよう
「何を作ればいいのか」だけではなく、「なぜそのタスクが必要になったのか」という背景までもしっかり確認しましょう。
また、それに加えて、追加する新機能がどういうユースケースで使われるのかも確認しておきましょう。すなわち、
- どういう立場のユーザーが
- いつ、どんな頻度でその機能を使い
- その機能を使ってどんな業務をするのか(例:ダウンロードしたCSVファイルを何に使うのか)
といった点も確認しておいた方がよい、ということです。
背景やユースケースを知っておけば、「そういう目的なのであれば、こういうふうに動いた方がいいだろうな」とか、「そもそもユーザーが必要な機能はCSVダウンロード機能ではなくて、画面に表示されているデータのソート順を変更できる機能なのでは?」といった観点でタスクの内容を見直すことができます。
いわゆる「顧客が本当に必要だったもの」ってやつですね。
Image: 顧客が本当に必要だったものとは (コキャクガホントウニヒツヨウダッタモノとは) [単語記事] - ニコニコ大百科
要件や仕様で不明な点が出てきたり、提示された仕様の見直しを相談したくなったりした場合はタスクをアサインしてきた開発リーダーに質問しましょう。
手順3. 現行のロジックがどのように実装されているのかを確認する
次にソースコードを覗いて現行のロジックがどのように実装されているのかを確認します。
商品一覧画面はいったいどのように実装されているのでしょうか?
サーバーサイドでRailsがHTMLをレンダリングしてレスポンスとして返しているだけ?
それともReactやVue.jsといったフロントエンドフレームワークを使って描画している?
その場合、APIはどこでどうやってどんなデータを返している?
CSVに出力する項目はどのテーブルのどのカラムから出力する?
モデルとモデルの関連はどのようになっている?
既存のCSVダウンロード機能があるのであれば、それはどのような実装になっている?
共通部品や共通ロジックがすでにあって、差分だけ実装すればいいような作りになってたりしないか?
アサインされたタスクの内容や画面の動きだけ見るとすごくシンプルなのに、ロジックを覗いて見ると「げげっ、なんでこんなややこしいことやってるの!?」って思うことは結構あります。(僕は「ふたを開けたらビックリ☆パターン」と呼んでいます)
思った以上に現行ロジックが複雑でどこで何がどう動いてるのかさっぱりわからん、という場合は先輩プログラマに声をかけてそのカラクリを説明してもらってください。
本番環境のデータ量やパフォーマンス目標も確認する
今回例で挙げたCSVダウンロード機能であれば、本番環境のデータベースにはどれくらいデータがあって、一回あたり最大何件ぐらいのデータをダウンロードするのか?といった確認も必要です。
でないと、開発環境では数秒でダウンロードできたのに(=5件しかデータがなかったから)、本番環境では10分以上待ってもダウンロードが終わらない(=100万件データがあったから)、みたいな問題が起きたりします。
時間がかかりそうな場合は、
- ストリーミング形式でダウンロードする
- 非同期でCSVファイルを生成する(あとからダウンロード用のリンクをメールで通知する等)
- バッチ処理で決められた時刻にCSVファイル用のデータを生成する
- SQLをチューニングする or 特定のカラムにindexを貼る
- 検索条件を厳しくして一回あたりの取得件数を抑える
といった対策が考えられます。
テストコードの有無も確認する
実装コードだけでなく、テストコードの有無も確認しておきましょう。
- 商品一覧画面にはすでにテストが用意されているか?用意されているならそこにCSVダウンロードのテストを簡単に追加できそうか?
- CSVダウンロードのテストは他の画面で書かれているか?
既存のテストコードがあればそのテストコードを流用して今回実装するCSVダウンロード機能のテストが書けますが、そうでない場合はゼロからテストコードを書く必要があります。
テストコードの書き方に慣れていない場合は、テストコードを書く時間も開発工数に含める必要があるでしょう。
手順4. 機能追加するにはどこをどう変更すればよいのかリストアップする(=タスクばらし)
ここまでで開発に必要なインプットはそろったはずなので、具体的に何をどうやるのかをリストアップします。
「CSVダウンロードをボタンを追加してCSVをダウンロードできるようにする」みたいな粒度ではダメです。
タスクが大きすぎるので新人プログラマはタスクを喉に詰まらせて死にます。
そうではなく、もっともっと小さい単位にタスクを分解しましょう。
1つ1つのタスクは大きくても30分から1時間程度で終わる内容にしてください。
この作業を「タスクばらし」と言います。
たとえばCSVダウンロード機能であれば以下のようなタスクに分解できそうです。
- CSVダウンロード用のルーティングを
routes.rb
に追加する - 画面上にCSVダウンロードボタンを配置してCSVダウンロード用のパス(URL)にリクエストを送れるようにする
- コントローラにCSVダウンロード用のアクションを追加する
- CSVの生成ロジックを実装する。CSVダウンロード機能はすでに共通ロジックがあるので、今回はデータの取得とファイル名作成のロジックだけを実装し、それ以外の処理は共通ロジックに任せる
- CSSを使ってボタンの見た目を整える
- CSVダウンロード機能のテストを書く
タスクが小さければ小さいほど「食べやすいタスク」になります。
タスクを喉に詰まらせないよう、タスクをできるだけ小さく分解してください。
また、ここでリストアップした小さなタスクはTODOリストであり、自分自身への作業指示書でもあります。
NotionやEvernoteのようなツールでTODOリスト化して、作業が終わったらチェックを付ける、というような使い方もオススメです。
各タスクの作業時間も見積もってみよう
ひととおりタスクを分解したら、それぞれのタスクにどれくらいの時間がかかりそうかざっくりと時間を見積もってみましょう。
これまでに使ったことのあるライブラリを利用する場合や、すでにお手本となるコードがある場合は比較的簡単に終わると思いますが、反対に「今まで使ったことがないライブラリを使うコード」や「お手本がなく自分がゼロから書かなければならないコード」は思った以上に時間がかかるリスクがあります。
タスクが大きいままだと不明な点も多いので見積もりの誤差も大きくなりますが、タスクを細かく分解すれば各タスクの見積もりの精度が上がり、その結果タスク全体の見積もりの精度も向上します。
手順5. タスクばらしの結果を先輩プログラマにレビューしてもらう
タスクばらしが終わったら、その結果を先輩プログラマや開発リーダーにレビューしてもらいましょう。
「今回はこんな手順で、こんなふうに実装しようと思っています」という内容を先輩プログラマに伝え、認識の齟齬はないか、難しく考えすぎてないか等々、大きな手戻りが発生しそうなポイントがないことを確認してもらってください。
また、だいたいの見積もり時間も一緒に伝えてください。
明らかに手間がかかりそうなタスクや、リスクが高いタスク(例:実務でVue.jsのコードを書くのは今回が初めてですんなり実装できるか不安、等)は予め正直に伝えておくことが大事です。
もしかすると「そんなに時間がかかるならその部分だけ別タスクで対応しよう」とか、「もしハマったら手伝うから声をかけて」というように先輩プログラマからのアドバイスやサポートが受けられるかもしれません。
【重要】ここまでまだコードはひとつも書いていません!
さて、現時点で手順5まで説明しましたが、実はここまでコードは一切書いていない点にお気づきでしょうか?
ここまでやったのはひたすら前準備です。
「タスクをアサインされたから早くコードを書かなきゃ!」と焦ってコードを書き始めるのは間違いです。
まずは仕様や実装方法の疑問点を全部潰して、「あとは手を動かすだけ」という状態にすることが大事です。
ゴールまでの道筋がハッキリと見えていないのに慌てて出発すると、すぐに迷子になって右往左往することになります。
ただし、コードを書くなと言っても、スパイク(技術検証のためだけに使う小さなプログラム)を作るのは問題ありません。
スパイクを作る場合は、
- 今取り組んでいるプロジェクトとは別に、技術検証用のRailsアプリを新たに"rails new"する
- 技術検証用のブランチを作ってそこで好きなようにコードを書いたあと、技術検証が済んだらまたmainブランチに戻る
といったアプローチが考えられます。
手順6. 実装を開始する
お待たせしました。ここからようやく楽しいコーディングの時間です。
先ほどのタスクばらしで作ったTODOリストに従って実装を進めていきましょう。
仕様と実装方針が事前に明確になっていれば、そこまで苦しむことなくコードを書き進められるはずです!
実装を開始したらWIP(work in progress=作業途中)のプルリクエストを作って、開発中のコードの差分を他の人が確認できるようにしておきましょう。
ハマったら制限時間を決めて、それを超えたら助けを求める
そうは言ってもいざ実装を始めると思い通りに動かない部分が出てきてハマってしまうことがあるかもしれません。
そういうときは必ず時間を区切って対応するようにしてください。
目安としては30分です。
「ヤバい、これはハマってるぞ……」とイヤな汗をかき始めたら時計を見て、30分後にスマホのアラームをセットしましょう。
もしアラームが鳴ってもまだ問題が解決しないようであればタイムオーバーです。
先輩プログラマをつかまえて「すいません、ハマったんでちょっと助けてください」と声をかけてください。
先輩の時間を奪ってしまうかも、というような遠慮は不要です。
なぜならあなたが1人で悩みに悩んで3日かけてタスクを完了させるよりも、先輩に相談して2時間で完了させる方がチーム全体として見たときに効率がいいからです。
それでも「嫌な顔をされたらどうしよう」と不安になる人は、先ほど書いたタスクばらしのレビューのタイミングで先輩プログラマに「もしハマったら声をかけるんでよろしくお願いします」とひとこと伝えておけば大丈夫なはずです。
正常系の実装が終わったら途中経過を見てもらって手戻りを防ぐ
大きなタスクの場合は最後まで一気に完成させようとせずに、ある程度動くようになった段階でタスクをアサインしてきた開発リーダーに実際の動きを軽くレビューしてもらってください。
これは何のためかというと、手戻りを防ぐためです。
せっかく最後まで作りこんだのに仕様を勘違いしてて作りなおしになってしまうと、時間的ロスがめちゃくちゃ大きくなります。
加えて、時間的ロスだけでなく精神的な落ち込みも半端ないものになるで、手戻りはできる限り避けたいところです。
そのためにも最初は細かい点の作り込みは後回しにします。
細かい点とはたとえば入力値のバリデーションやデザインの調整、イレギュラーパターンの実装等です。
正常系の最もシンプルな処理フローが一通り動くようになったあたりで途中経過を報告するのが一番良いと思います。
手順7. 実装が終わったらプルリクエストのWIPを外して完了!
タスクばらしで作ったTODOリストが全部完了済みになれば、タスクそのものの実装も完了します。
つまり、TODOリストがこの状態になればOKですね。
実装が全部終わったらプルリクエストのWIPを外して、コードレビューを依頼しましょう。
場合によっては一部コードの修正や画面の動きの修正を求められるかもしれませんが、致命的な問題はおそらくないはずです。
プルリクエストが承認され、mainブランチにマージされたらアサインされたらタスクは完了です。
どうもお疲れ様でした!
まとめ
というわけでこの記事では実務に入って間もない新人プログラマを想定して、「開発タスクをアサインされたらどういう手順で進めるべきか」という話を書いてみました。
この記事で述べたようにCSVダウンロード機能の実装をアサインされたからといって、「なるほどCSVダウンロード機能を作ったらいいんだな。よし!」でいきなりコードを書き始めるのはNGです!🙅♂️
そうではなく、コードを書き始めるのはしっかり事前調査をして、大きなタスクを小さく分解して、「これならもう迷うことはない。あとは手を動かすだけ!」と言えるようになってからです。
僕はかれこれ20年近くプログラマとして働いてきていますが、僕自身もこのスタイルで開発を進めています。
こうやって手順を文章化するとすごく時間がかかるように見えるかもしれませんが、「急がば回れ」で結局こういうやり方が一番早く終わります。
つまるところ、「最短経路を見つけるために時間をかけましょう。最短経路を見つけたら、その経路に沿って一気にゴールに向かいましょう。最短経路を確認しないまま歩き始めても、迷子になって余計に時間がかかるだけですよ」ということです。
特に業務で扱う大きくて複雑なプログラムになればなおさらです。
なんの準備も無く真っ暗な樹海に足を踏み込んだら二度と帰ってこれません……👻
新人プログラマとして就職したけどなかなか成果が出せずに困っている人は、ぜひこの手順を実践してみてください!😃
おまけ
プログラミングの理想と現実はこんな感じですよね〜。