1.投稿趣旨
この記事は、個人開発 Advent Calendar 2021 の22日目の記事です。
本投稿で題材にした個人開発は、経験者が趣味で開発するというものではありません。Web開発未経験者が、個人開発プロジェクトをチーム開発に移行させ、現場のWeb開発をロールプレイしていくという体験を題材にしました。そして、この投稿の視点は、開発者当人ではなく、開発の支援側からになります。
また、投稿の論点は、プログラム・製造ではなく、以下になります。
○ 個人開発をチーム開発へ移行させた過程
○ 少数チームによるプロジェクト運営
○ 未経験者が「とりあえず動くものをつくる」から次のステップへいく指針
Webサービスの技術面については、2021年アドベントカレンダーの12/24に、@AkiUnleash さんが記事を書いています。簡単に予告すると 「Vercel + React + Next.js + Supabase + Typescript 」 という最近採用される事が多いライブラリとサーバレスを基盤としたWebアプリの内容になります。
ちなみに、このプロジェクトは現在、3名のチームで開発を進めています。2人以上で開発していれば「個人開発」ではないとも言われそうですが、このプロジェクトは、1人の未経験者が始めました。
そのうち、開発を支援してくれるメンバーが増え、プライベートプロジェクトだけどチーム開発している状態になりました。いわば、「個人開発」から次のステージに移る過程を題材にしたといってもいいのかなと思っています。
今、個人開発をしている人、これから個人開発をしようとしている人、また、実際の現場で小さいチームで開発をしている人のヒントになれば幸いです。
2.開発しているWebサービス:ErrorShare
現在、プログラムのエラー対応記録を共有するWebサービス、「ErrorShare」を開発しています。
サービスは至ってシンプルです。プログラムをしていて遭遇したエラー内容や対応策をフォーマットに記録し、Web上で公開するサービスです。
このサービスの目的は、プログラムエラーで困っている人が少しでも早く問題解決できることを支援するものです。
3.プロジェクト誕生からチーム形成の過程
(1)チーム開発のメリット
本プロジェクトは、完全に1人の個人開発ではなく、3名体制で開発しています。途中4名でしたが、仕事が多忙ということで1名はオブザーバーになっています。
このプロジェクトは、仕事ではなくプライベートでの学習目的で行っています。1人で開発しても色々勉強にはなりますが、現在のWeb開発を仕事で行うにはチーム開発が一般的です。勿論、サーバレスやLCNC(LowCode-NoCode)などを使えば一人で開発できるものもあります。それでもやることが増えれば、当然、チーム開発になっていきます。私個人、7-8年前からWeb開発は一人でやるべきではないと感じたことがあります。それについては、記事を書いたことがあります。
いずれにしろ、複数人で作ることは以下のようなメリットが考えられます。
○ 機能実装が早くなる。
○ 自分の知らない知識を得られる。
○ 読みやすい、メンテナンスしやすいコードを意識する。
○ チーム開発の技法を学びやすい。
○ モチベーションを維持しやすい。
私がこのプロジェクトが始まったとき、開発未経験者にこそ、できるだけチーム開発をしてもらいたいと思い、仲間を集めようと思いました。
まずは、どうやって開発チームが形成されたかを記載します。チームメンバーを集めるときの参考になれば幸いです。
(2)プロジェクト誕生の経緯
このサービスを作るきっかけは、@AkiUnleash さん(以下、Akiさん)がWebプログラマーに転職したいのだけど、学習や就職などの相談にのってほしいと言われたことに遡ります。
私は、Web開発には15年携わっています。ベンチャー企業や大企業のWebシステム開発において、要件定義・設計・製造・テスト・運用など一通りの工程を経験しました。現在は、クライアントサイドで、業務Webシステムの内製化支援を行っています。
ちなみに今年は、以下のような記事をQiitaに投稿していました。
Akiさんとは、プログラマーで構成されるSlackのWorkspaceで知り合いました。このWorkspaceは、Twitterで知り合ったり、リアルで知っているエンジニアやコーダーを呼び集めて構成されています。
ここでは、日々、技術に関する情報交換をしたり、プライベートなことについて意見交換をしています。サロンとも言えますが、営利目的ではなく、本当に遊び感覚で参加しているWorkspaceです。
このWorkspace内で、AkiさんからWebプログラマーに転職したいという相談を受けて、どういうプログラム言語、ライブラリ、サービスが良いかの情報提供をしていました。
そして、Akiさん自身、約一年半、Web開発の学習をしてプロダクトが作れるレベルに来ました。その頃、私からErrorShareのアイデアを伝えました。
Akiさんからはスキルをアピールする場として、作ってみたいと言われたので、私がPO(プロダクトオーナー)のような立ち位置で側面支援し、プロジェクトが始まりました。
(3)プロダクト技術の選定
AkiさんはWebプログラマーになりたいということでしたので、学習の段階から、ここ数年最も利用され、仕事が取りやすい言語、ライブラリ、サービスを提案していました。
ただ、私はあくまでも提案だけであって、Akiさんの
方も独自でいろいろ調べており、二人のアイデアを突き合わせて、冒頭に書いたサーバレス(Vercel + Supabase)とTypeScriptとReactを使ったWebアプリにしようとなりました。
仕事をするという意味では、AWSを使うのもありだと思いました。ただ、個人開発なのでできるだけ省力化したいという考えがあり、サーバレスのインフラを選定することにしました。結果的に、思ったよりは早く形ができたので、やっぱりサーバレス構成はいいなと改めて思いました。
(4)プロジェクトチームの増員
最初は、Akiさんと私の2人、といっても、もっぱらAKiさんが製造されていて、私は思いついたことをいう程度でした。なのでチームらしい動きはほとんどなく、字義通りの個人開発という感じだったと思います。
そんな折、私がTwitterで知り合った @k-kztk さんと仕事の打ち合わせをしているとき、Reactを使った開発を経験したいというのを聞き、「じゃあ、ErrorShareをいっしょに作らない?」と誘いました。
k-kztkさんは快く参加してくれて、プログラマー2人での開発体制ができました。ちなみに、彼も今年のアドベントカレンダー投稿しているので、みてあげて下さい。!
そして、SlackのWorkspaceでErrorShareのチャンネルをつくってプロジェクトを進めていくことになりました。チャンネルを作ったところAkiさんとk-kztkさん以外にもチャンネルに参加してくれる人がいました。そのうちの一人が設計やプロジェクト運営にいろいろアイデアをだしてくれました。とりあえず、この方はXさんとしておきます。Xさんは現場・開発経験もあり、頼りになる人です。
プロジェクトチームに人数が増えたこともあり、キックオフをする事になりました。このとき、Xさんがスクラムマスターみたいな立ち位置でいろいろとプロジェクトを引っ張っていってくれました。
こうして最初2名で始めたプロジェクトに、追加で2名参加してくれて4名体制で進めることになりました。その後、Xさんはお仕事が多忙になり、メインからは外れてオブザーバーになり、現在は3名体制で開発を続けています。
(5)チーム形成のヒント
これが本プロジェクトの誕生からチーム形成の経緯です。Twitterをきっかけに作られたSlackの技術者Workspaceが本プロジェクトのスタート地点です。
今、こうしたコミュニティはいろいろありますので、気が向けば参加してみるのもいいと思います。ドラクエのルイーダ酒場みたいに、開発パートナーがみつかるかもしれません。
ただ、いつもうまくいくとは限らず、頓挫することも多々あります。僕もそうした経験は何度かあります。今回はたまたまうまくいっているように思います。でも、失敗も物事にはつきものですから、恐れずに仲間を探して、チャレンジすることは意味があると思っています。
4.プロジェクト運営
複数人でプロジェクトを進めるにあたり、ツールや進め方を整備しました。そこにはXさんの現場での知見が大いに役立ちました。
勿論、本プロジェクトは、仕事ではなくあくまでもプライベートなので、互いが負担にならないようにしようという合意がありました。一方で、負担は避けつつも、やるべきことを明確にして着実に進めていこうという認識も持っていました。
現在、どのようにプロジェクト運営をしているのか概要を書いてみます。ここは、一般的な内容だし、そこまで高度なことはしてないので、本当に知識がなくてゼロの状態の人だと参考になるかもしれません。
(1)リモート開発と利用ツール
メンバーは日本各地に点在しており、オンラインツールを使ってリモート開発をしています。オフラインで打ち合わすことはないです。利用しているツールは以下のとおりです。
a. ソースコード・タスク管理
これはオーソドックスに、Githubです。ソースコードだけでなく、チケットもissueを使って管理しています。あと議事録もGithubに記載していっています。
チケットはissueで作成し、それをプロジェクトボードを使ってカンバン方式で管理しています。1スプリントごとにプロジェクトボードをつくり、進捗を管理しています。
issueも属性ごとにラベルをつけて、タスクの優先順位や作業者の振り分けがしやすいように分類しています。
質問などタスクではないけど共有し、リマンドのために残すものは、discussionを活用しています。
Githubは単なるソースコードのバージョン管理だけでなく、タスク・プロジェクト管理ツールとしても日々発展しているので、機能追加をみつつ、上手に使いこなすといいと思います。ツールを分けて使うより、少ない方が使うストレスが少ないです。
今だと、Notionを使って情報共有、プロジェクトマネジメントするというのも一つの方法ですね。
b. チャット
これはSlackです。前述した技術者Workspaceにチャンネルをつくって、そこでやり取りしています。やはりチャットツールは、リモート開発では必須だなとつくづく思います。
簡単なタスク依頼や質問、情報共有はSlackで行っています。Teamsもありますが、スレッドの機能やもろもろ考えると使いにくいので、やっぱりSlackが一番ですね。その他のツールを学習目的で使うのもありですね。
c. オンラインミーティング
NeWorkを使っています。これはXさんの提案で採用されました。今なら、Teams、Zoom、Wherebyとかいろいろありますね。NeWorkを使った理由は、Xさんによると「無料、4人以上で時間無制限に使えること」という条件に合致したからとのことでした。
個人開発は費用を抑えるため、無料ツールがいいですよね。でも、多くのツールは人数と利用時間に制限があります。Zoomは3人以上は40分、Teamsは100人行けるけど60分とか。他にもいろいろツールがあるので、試してみるのもいいですね。
NeWorkをつかってみてZoomやTeamsと違ってよいなと思った点は、共有画面が一つに強制されないことですね。これはデメリットになるときもありますが、それぞれのユーザーが共有画面を提供できるので、共有の切り替えで待ち時間がないのがいいなと思いました。
NeWorkは、オンラインでずっと繋いでおき、会議したいときにミーティングするという「オンライン≠ミーティング」という点も良いと思いました。
d. チャットとオンラインミーティングの使い分け
個人開発に限りませんが、リモートで開発するとき、それぞれのツールの使い分けはプロジェクト運営の指針として決めておいてもいい気がします。
個人的には、オンラインミーティングは必要最低限にすべきだと思っています。会議は、ついつい話が長くなったりしますし、参加人数が増えると関係ない人の時間もとりかねません。NeWorkだと聞き耳で聞いておくだけもできるのでいいですが、それにしても、集中してタスクをこなす方がメインにしたいなと思っています。
まず、チャットで済ませられることはチャットですませて、そこできまったことをタスク管理ツールでチケットをあげていく。どうしても、広範囲な情報でチャットでは書くのがめんどくさいとか、みんなの意見を聞きたいとなったとき、オンラインミーティングをすべきだと思っています。
ただ、定期的なオンラインミーティングは、「心情的なつながり」を持つ上で大切かなと思っています。まったく顔を見なくて作業はできますが、たまには顔をみて、雑談でもいいので話をすることはチームの一体感を感じる上でも大切かと思っています。
(2)プロジェクトの推進方法
チームとしてどのように開発を進めているか、評価の意味合いを込めて記載します。プライベートで負担なくやりつつも、チームでの情報共有はしっかりやっていこうという考えのもと以下のような感じでプロジェクトを進めています。
a. チケット駆動
本プロジェクトでは、原則、タスクはGithubのissueに記載し、それに対処するようにしています。いわゆるチケット駆動開発です。一人で開発していれば、わざわざチケットを作る必要はなく、いきあたりばったり、気ままにつくってもいいと思います。
一方、本プロジェクトでは、仕様を決めるのは一人の開発者ではなく、チーム全体で行っています。また、製造自体も2名で行います。つまり、タスクは明文化し、チーム全体で共有していく必要があります。共同作業をするとき、タスクを形にして共有するのは当然のことと言えます。
また、前述したとおり、issueはスプリントごとに作られたカンバンボードで進捗が分かるようにしています。表計算ソフトでタスクリストをつくるよりも、画面を開くと一瞥ですべての状況が分かるのはいいなと思います。
ちなみに、チケットは、大きな計画とは異なり、細かい実行タスクを記載したものであり、機能設計や中期的な計画は、別にGithub内にマークダウン形式でテキストとして保存し、共有しています。
チケット駆動開発のメリットとデメリットについては、いろいろな記事があるので一度読んでみるのもいいと思います。
b. 非ウォーターフォール・ゆるいアジャイル
このプロジェクトはスタートが1名での個人開発ということもあり、「要件定義、外部設計、内部設計、製造、テスト、リリース」の工程を順番に踏むウォーターフォールでは進んでいません。個人開発でウォーターフォールする人もいるかもしれないですが、大体、非ウォーターフォールかなと思います。
では、「アジャイル開発」なのかというと、それも微妙なところがあります。敢えていうと、「ゆるいアジャイル」。一応、アプリの目的や全体計画を元にプロダクトバックログをつくり、優先順位やマイルストーンをつくり、それに合わせてスプリントバックログは作っています。それは前述のとおりです。
ただ実務の現場とは違い、プライベートなので、デイリースクラムなど短い期間でのコミュニケーション、スプリントレトロスペクティブ(振り返り)などは行っていません。1~2ヶ月に1度ぐらいのペースで対面ミーティングをして、その際に振り返りやスプリントの確認等行っています。
とはいえ、タスクの進捗は、カンバンみれば一目瞭然で、各々が自発的にタスクをこなし、適宜Slackでコミュニケーションをとっているので、オンラインのミーティングが頻繁になくてもそれほど問題を感じていません。
XPプログラミングについても、そこまで実践ができているとは言いにくいですが、だんだん技術的な知見もえられ、ファーストリリースを迎えたので、これらの内容も実践していきたいなと思います。
そもそもが実務とは違い、プライベートでやっているので、負担を少くタスクも比較的長めにこなしています。
このような背景から、アジャイル開発の様々な手法も徐々に、できる範囲で取り入れていこうと思っています。
一応、みんなも「ゆるいアジャイル」なのは認識しています。
でも、言葉の上だけになりますが、時折、現場では本当はこうしてるとか話したりします。
c. コードレビュー
開発者は2名ですが、Githubのプルリクとレビュー機能をつかって互いにレビューした後、マージをするようにしています。絶えず、誰かに見られているというコーディングは現場では必要になるので、小さくてもこのようにレビューをいれるようにしています。
また、開発者同士でもくもく会もしてるようで、一人ではできない経験ができているようで、チーム開発のメリットが享受できてていいなと思っています。
ペアプロというスタイルではないですが、それでも他人を意識したコーディングをするのはよいと思います。
5. アプリが作れるようになったら学習・意識した方がよいと思うこと
プロジェクト運営は上記のとおりで、プライベートでゆるいとはいえ、それなりにWebアプリも形になってきました。まだまだ不備も多々ありますが、最初の頃に比べればかなり形になってきました。そして、Webアプリの形成と共に、Akiさん含め開発チームの知見も増えてきました。
Akiさんについて言えば、Web開発を学習し始めてから1年ぐらいの間に、プログラムの文法やWeb特有の技術、Web開発の流れについてはある程度理解し、とりあえず動くものが作れるレベルには達していたと思います。それが今回のWebアプリ開発によって、より板についた感じがします。
このプロジェクト、そして、Akiさんの成長を通じて、Web開発の未経験者が勉強した方がいいのではと感じたことがあります。この内容を次に記載していきます。ただし、「こうしなければならない!」というものではなく、私個人が「こうしたほうがいいな」と感じたことであり、ある程度、プログラムの文法が分かり、とりあえず動くものが作れるようになった人の次のステップの指針になればと思います。
(1)上流工程(要件定義や設計)の進め方:作業分担と優先順位
a. 上流工程の必要性
このプロジェクトはスタートが個人開発であり、機能も多くないので上流工程をきっちりする必要はなかったと思います(できるならしてもいいと思いますが)。
ただ、複数人で開発し、プロジェクトを外部に向けてリリースすると決めたあたりから、「機能実現の可否」を決定し、「タスクの優先順位」をつける必要がでてきました。つまり、「協業」、「期限」、「公開」が「上流工程の必要性」をもたらしたように感じます。
上流工程は、一般的に「企画・要求定義、要件定義、外部設計(基本設計)、内部設計(詳細設計)」をさして言うことが多いと思います。端的にいえば、「何をするのか」(要件定義)、「どのように実現するのか」(設計)を決め、それを明文化し他者と共有できるようにする工程だと思います。
この工程は、ウォーターフォール、アジャイルを問わず、その範囲や頻度の差こそあれ、必要な工程だと思います。ウォーターフォールの場合、各工程にて全体を明文化してから次の工程へ行き、それぞれの工程の期間は長く、ドキュメントも多くなります。
一方、アジャイルは、上流工程、製造、リリースを小さい機能単位で繰り返して行います。それゆえ、各工程の期間は短く、ドキュメントも少なくなります(少なくなったり、無駄な形式はないかもしれませんが、作らないということではありません)。
上流工程は、意識的にしていなくてもその片鱗をなんとなくは行っています。ですが、現場で行われる手法を意識的に行うことで、「実現機能の明確化」によりタスクが決めやすくなり、「関心の細分化」ができ、ステークホルダーを分けやすく、タスクの配分がしやすくなります。
b. 機能の明確化、タスクの優先順位の決定
「要件定義」では、制限のある予算、人員、時間などでどこまでの機能を実装するかを決めます。ただ漠然と、「あれもやりたい、これもやりたい」では、収拾がつかなくなります。なので、制約を意識しつつ、何を優先すべきなのかを考慮して、やることを決めます。
より具体的には、ユーザーがアプリを使ったときの行動(業務フロー)を整理し、その行動において、データをどのように扱い、どのようにアプリが関わるのか(アプリの機能)を定義します。
c. 関心の細分化と作業分担
また、要件定義では、「機能要件(業務要件)」と「非機能要件(システム要件)」の2つがあります。
「機能要件」は、ユーザーの行動に直接関わり、ユーザーがもつ情報を元にアプリの機能を定義します。例えば、このプロジェクトでいえば、「ユーザーがエラーの情報を投稿する」というのは機能要件になります。
一方、「非機能要件」は、アプリの機能を実現するためのインフラや、ユーザーが意識しない技術者視点の要件に該当します。例えば、「投稿完了までの時間は3秒以内」とか「バックアップは毎日、Amazon Driveに保存すること」などです。
このように「ユーザー視点」と「技術者視点」を分けて要件定義することで、役割分担をしやすくなります。たとえば、「ユーザー視点」は非エンジニアが担当し、「技術者視点」はプログラマーやインフラエンジニアが担当するなど、作業分担しやすくなります。
d. アプリを具体的に形にする方法の整理
要件定義では何をするのかを明示しました。ちなみに、要件定義時に各機能については、おおよその機能を整理する「概要設計」を行っておきます。その「概要設計」を元に、詳細な機能実現方法を整理していきます。これが「外部設計(ユーザー視点の詳細設計)」、「内部設計(技術者視点の詳細設計)」にあたります。
「外部設計」は、ユーザー視点でアプリの機能を設計していきます。画面レイアウト、ボタンを押した場合などの機能、ユーザが扱うデータなど、ユーザーが見えて、分かる範囲の内容を整理していきます。
「内部設計」は、技術者視点でアプリの機能を設計します。DBテーブルを定義したり、モジュールをどうするのかなど、コーディングを意識した実現方法や手順を整理していきます。
このように「外部設計」と「内部設計」を分けることで、議論のステークホルダーや論点を分けやすく情報が整理しやすいと思います。
外部設計、内部設計は製造するときの指示書ともいえます。要件定義や概要設計はこれらの為の準備段階ともいえます。この指示を共有してこそ、ユーザーやチームとの認識の共有がある程度はできるのだと思います。
e. できるだけ全体を広く、深く見通す設計思考を意識する
ここまで見てきたように「上流工程」を意識的に行うことで、チーム開発はやりやすくなると思います。実際の現場では、工程の呼び方や期間、進め方、ドキュメント・テキストの体裁は変われど、似たようなことを行っていると思います(行っていない現場もありますが、そういう現場がどうなるかは想像のとおりです)。
上流工程においてはできるだけ幅広い視点をもって全体の機能を可能な限り列挙し、アプリや作業イメージをもつ必要があると思います。これは、ウォーターフォールだと一般的だと思いますが、アジャイルではこのようなことは必要ではないと思う人がいるかもしれません。
ウォーターフォールとアジャイルの違いは、全行程を1回ずつ長期間に行うのか(ウォーターフォール)と、全行程を細かく短期間で複数回行うのかの違いであり、各工程のタスクの実行期間と範囲が違うだけであると思います。そして、「全体の設計を考えない」ことではないと思います。当然、いずれの開発手法においても、早い段階で、全体を見通し、ドキュメントにして全員と共有しておくことは大切だと思います。
実際、アジャイルの前提にあるように、プロジェクトの初期の段階で、「完全、かつ、詳細に」全体を把握することは難しいと思います。変更も当然ありえます。だからといって、全く全体も先も見通さず、行き当たりばったりで進めて物事がうまくいくでしょうか?
経験しなくても分かりますが、経験すれば尚、それが無駄や問題を引き起こすことが理解できると思います。殆どの場合、なんらかの問題が発生します。行きあたりばったりに開発を続けると、製造(コーディング)において、以下のようなことが起きたりします。
○ クラスやテーブルの名前が短く曖昧になり、機能が増えると、最初につけた名前の役割が不明瞭になる。
○ 先に仕様を洗い出しておけばまとめられた処理が重複して存在する。
○ 全体の処理に関わるキーの設定をデータ設計で見落とし、全体の修正か応急処置コードで不安定な修正を強いられる。
○ 逐次的に仕様が分かり、関数やクラスの修正が突貫になり、使い勝手が悪くなっていく。
それぞれ事前の対策はあると思いますが、YAGNIの法則にある通り、どうなるかわからないのに予備的な対策コードは逆に使い勝手を悪いモジュールを作ったり、無駄な工数を発生させかねません。
上記のような製造上の問題は、品質の低下、テスト工数の増加、スケジュールの遅延を発生させることになります。アジャイルであれば、リファクタしながら、スケジュールを伸ばしていけばよいと考える人もいるかもしれませんが、「時間」と「予算」は往々にして有限です。そもそも、アジャイルはウォーターフォールよりも結果的には無駄を減らしてこそ、その意味があります。
ウォーターフォールよりもひどい状況で失敗する「なんちゃってアジャイル」の多くは、こうした行きあたりばったりなものが多いように思います。繰り返しになりますが、アジャイルだからといって全体について設計を行わないということではありません。
「過ぎたるは及ばざるが如し」で、「できないから曖昧で中途半端にする」、「完全、かつ、詳細に把握しなければならない」など極端な考えは禁物だと思います。
理想をいえば、「完全、かつ、詳細に把握できる」に越したことはありません。しかし、現実には難しい。けれど、少し落ち着いて、意識的に全体を考えるだけで、そうしないよりも遥かに多くのことが見えてくると思います。
そして、日頃からいろいろな設計について学習し、経験をして失敗を放置せず、改善策を考える癖をつけていけば、プロジェクトの最初の段階でも、より広く、深く見えてきます。それが完全ではないにしても、ゼロよりは遥かに見通しがつくようになります。
ところで、「アジャイルソフト開発」をする際の指針として、『アジャイルソフトウェア開発宣言』や『アジャイルソフトウェアの12の原則』があります。
この中にはアジャイルでソフトウェア開発をする原則が記載されています。そして、次のような原則があります。
技術的卓越性と優れた設計に対する不断の注意が機敏さを高めます
(Continuous attention to technical excellence and good design enhances agility)
よい技術や設計への耐えざる意識が、「機敏さ(agility)」を強くするという原則があります。「機敏さ(agility)」は、別の言い方をすれば臨機応変さと言えるかもしれません。色々な技術や設計の知識、経験、日頃からの思考があれば、様々な課題に対応しやすくなるということだと思います。
一見、行きあたりばったりにしていても、技術知見や経験があれば、臨機応変にこなせると思う人もいるかもしれません。実際、そのようなことはなく、技術知見や経験により、初期の段階からプロジェクトの全体がある程度見通せており、問題が起こりにくいアーキテクチャやモジュールの設計をしたり、サービスやライブラリの選択をしています。
つまり、問題を起こす前に予防線を張っておくことです。そして、その予防線を張っているからこそ、問題の発生を減少させていると思います。これでもなお、予見しない仕様変更やバグは起きます。ですが、何も予防線を張っていないよりは遥かに少なくなります。
先程のアジャイルの原則はこうした観点から看過できない点だと思っています。アジャイルは短い期間で全行程を行い、小さく機能実装を行いますが、その基盤には、全体を見通した設計がないと問題発生の頻度が高くなったり進捗が遅れていくということです。
アジャイル開発だとしても、できるだけリファクタなしに、やることが少なくなるに越したことはありませんし、早く全体の機能実装が行われる方がよいに決まっています。
e. 思考した設計を形にする手軽なドキュメント作成
ウォーターフォールの批判(※1)として、全体の機能をプロジェクトの初期の段階ですべて整理し、ドキュメントに整理することが無駄な作業として指摘されたりします。確かに、時間をかけて、手間のかかるフォーマット作成しても、製造に入って修正をすると無駄な気もします。
ただ、前述したとおり、設計の「思考」はすべきであると思います。問題は、ドキュメントをどうするかということであり、手間のない方法で形にして、チームメンバーと共有すればいいのではないかと思います。
たとえば、Markdownを使ってテキストベース形にするのもいいと思います。テキストベースでフロー図やシーケンス図を書くこともできます。
また、最近であれば、Notionやdiagrams.net(draw.io)などのクラウドツールを使って手軽に情報を整理、共有することができます。私達のプロジェクトチームでは、Markdown形式のテキストファイルをGithubにあげて共有しています。
アジャイルにしても、できるだけ全体を見渡した設計をしつつ、その内容は手軽に作成して共有する。これをベースにプロダクトバックログを作成してもよいと思います。
f. Low-Code/No-Code(LCNC)やSaaSでシステムを作る場合も上流工程は必要
コーディングを教えてくれる教材、スクール、書籍はたくさんあります。上流工程については、書籍やネットの情報はそこそこありますが、コーディングより少ないと思います。
実際、現場にいくと大規模な会社だとしっかりしとした進め方を持っているところが多いですが、小規模、ベンチャーとなるとこの辺りの方法論が確立しておらず、炎上案件を抱えているところもよく見かけます。
特に、これからはLCNC、SaaSをつかって、コーディング自体はあまりせずに、システムが作れる分野も増えてくると思います。この場合でも、上流工程は必ず必要になってきます。ですので、上流工程を学んでいれば幅広くスキルを活かせるように思います。
##(2)他人が読みやすい、使いやすいコーディングを心掛ける
a. 変数や関数の命名方法(一般的な単語を使いシンプルに命名)
チーム開発を始めたときにメンバーから命名について色々指摘がありました。まずは、命名された英語に違和感がある。確かに、英語が苦手だと最適な英単語を選ぶことは難しいかもしれません。このプロジェクトでは、チームメンバーからのアドバイスを元に命名を修正していきました。
違和感のない命名は、他人とコードを書きながら学んだり、Githubにある有名なライブラリのソースをみて真似をしていくことが必要だと思います。また、ネットには命名の参考になる情報がたくさんありますので、それらを参考にするのもありだと思います。
単語の選定の他に心掛けることは、できるだけ短い単語を採用し、冗長な命名を避けることだと思います。言葉を省略することではなく、元々短い単語を採用し、重複なく使うことです。
たとえば、現場にいくと以下のような命名を見かけることが。そのものズバリの例ではないですが、要点を明確にするため単純なコードにしています。
//メソッド内の処理は省略
public class Product {
public String getProductName() {}
public String getProductPrice() {}
}
クラス名、メソッド名でそれぞれ「Product」が重複しています。このコードはまだ冗長さを感じませんが、現場ではもっと長いクラス名やメソッド名を見かけることがあります。特に、Javaの現場にいくとよく見ます。
名前空間、パッケージ、クラスなどはグループを作る容れ物といっても過言ではありません。別の言い方をすれば、文脈(コンテキスト)です。普通の会話や文章でも、ある文脈がわかれば、それを繰り返したり、提示する必要はないと思います。読み手側は自ずと全体の文脈から部分が何を指しているかは類推できます。
なので、上のコードにおいては、重複した「Product」をメソッド名から削除しても、十分意味が通ると思います。
public class Product {
public String getName() {}
public String getPrice() {}
}
このようにクラス名、メソッド名、変数名は、それらを内包する上位のグループ名によって文脈を与えら得るので、わざわざ重複した命名は不要であると思います。これにより、命名はシンプルにスッキリします。コードを読むときも読みやすいと思います。たとえば、上のクラスを実際に呼び出すコードをみても、特に違和感なく読めると思います。
//Java10以降の変数宣言構文で記載してます
var product = new Product();
var name = product.getName();
このプロジェクトに限らないのですが、いろんな現場にいくと他人の命名をよく見ます。中でも、経験が浅い人の命名ほど、ブレ、冗長さ、意図したことが伝わらないなどを感じることがあります。チーム開発であればこそ、他人が読みやすい命名は大切なことだと思います。
b. 関数やメソッドの引数を少なくする
今回のプロジェクトのコードをみていて、気になったのはReactで作られたコンポーネントのpropsが多すぎることです。propsは関数で言えば引数に当たります。引数が多いことは一般的にはよくないとされています。
例えば、引数が多い場合の問題点として以下が思いつきます。
○ 必ずしも使われない引数(オプション引数)が多い傾向があり、どの引数を設定するのか呼び出し時に悩む。
○ 名前付き引数(※2)の構文がない場合、引数の設定を間違いやすい。
○ 呼び出し時の設定が煩雑で、コードが読みにくい。
○ 引数仕様の変更時、Parameterオブジェクト(後述)と比較すると、修正する箇所が多くなる(呼び出し箇所すべてになる為)。
○ 引数の数だけ色々な処理との関係性をもつことで、他の処理の変更の影響を受けやすい。
ぱっと思いつくところはこれぐらいですが、他にも色々問題がある気もします。いずれにしろ引数が長くしろという推奨はないと思ってます。仮に良さがあってもデメリットの影響は大きいと思います。止むを得ず多くの引数が必要な場合、以下のような対策があります。
- クラスや構造体を使い処理を独立させて定義する。(クラスや・構造体全体が一つの関数のように定義する)
- クラスや構造体で値のグループをつくり、そのオブジェクトを引数にする。(このオブジェクトをParameterオブジェクトと呼ぶ)
このようにすることで関数やメソッドの引数は少なくなり、引数に設定した値に仕様変更があった場合も、関数の定義は変えず、値のSetterやParameterオブジェクト(※3)の仕様を変更するだけでよくなります。
ちなみに、項番1と項番2の使い分けは次のとおりです。基本的に項番1のクラス・構造体で処理を定義することを考えます。ただし、その引数となった値の集合が、他の処理と共有するのであれば、項番2のようにParameterオブジェクトを設定するのがよいと思います。要は、パラメーターのグループを他の処理と共有するか否かが項番1と2の使い分けの基準だと思います。
以上のように引数が多い場合でも、対処方法はあります。ただ、基本的には引数を増やさないように、「引数の数が4~5個以上になった場合、関数を分割するかクラス・構造体で定義することを検討する」という癖をつければいいように思います。
引数が多い場合、関数の役割や処理が増えている可能性があります。関数の処理は少ないほうがテストもしやすく、コードも読みやすく、修正しやすくなります。この観点からも、引数を少なく抑えるべきだと思います。
つまり、引数の数が多いことは、関数・メソッドを分割したり、クラス・構造体で定義し、独立化させるサインだとも言えます。
冒頭で触れたReactのprops(※4)については、JavaScript特有の文法での回避もありますね。以下の記事で紹介されています。
関数、メソッド、コンポーネントの役割を小さく、設定を少なくすることはいろいろなメリットがあります。その指標となるのが、引数、Porpsなどであるように思います。
引数が多くても、取り敢えず動きはしますが、チーム開発での協業、長期的な仕様変更への対応を考えると、引数を少なくすることこそベストプラクティスな気がします。
こうしたコーディングのベストプラクティスについては、「リーダブルコード」などの書籍を始め、ネット上に「コーディング ベストプラクティス」などで検索すれば色々でてきますので、問題を感じた時に少しずつ実践するのがよいと思います。
ちなみに私は、「SOLID DRY KISS」 というコーディングに関する法則を意識してコーディングするようにしています。こうした法則はいろいろあるので、一読しておくのもよいと思います。
(3)ビジュアルデザイン(UI/UX)への配慮
今回、私はコーディングはしていないのですが、唯一作業らしいことをしたのはロゴの作成です。それに関連して、デザインに対してのアドバイスもしました。
本サービスの最初の段階のデザインは素人が作った感は否めなかったです。ロゴ、レイアウト、配色、フォント、文字の大きさなどがよくみるサイトからすると見劣りするものでした。ちなみに、少し前に、前掲のSlackのWorkspaceで、以下の記事が投稿されていました。頷きながら読んでいました。
コンシューマー向けのWebアプリ開発をしていると、UIデザイナーさんが作成したUIを元に実装することが多いです。また、Webサイトを作る時、当然、できるだけカッコいいデザインにしようと思い、カッコいいデザインを集めたサイト集を見たりします。
こうした経験から、日頃からいろんなWebアプリやサイトをみたとき、「これはかっこいいなあ」とか「これは素人くさいな」とか思いながら、デザインを評価したりすることがあります。今回のプロジェクトにおいても、当然、デザインがすごく気になりました。
まず、ロゴがあまり良くなかったので、自分も下手ではありますが、少しマシなものをつくってみようと思い、ロゴ作成を買って出ました。それから、以下の点がデザインとして良くなかったので、ZennやQiitaなど良いデザインのサイトをみて修正してほしいと開発メンバーに依頼しました。
○ コンテンツ間、BOX内の文章と枠線の間の余白が狭い。
○ 必要以上にコンテンツ間の余白が広い。(意図的ではない空白が広い)
○ 配色にメリハリがない。同系色ばかりでアクセントがない。
○ 文字のフォントが読みにくい。
○ 必要以上に文字のサイズが大きい。
○ 必要以上に説明文や説明タイトルが多い。(言わなくても分かるのに説明・タイトルが配置されている)
○ コンテンツの変化が乏しい。
○ よく見るサイトコンテンツがないので素っ気なく感じる。
これらの問題点は、良いデザインのサイトを見ていると自然と身につく気もしますが、デザインに関するWebサイトを読んでも気づくかと思います。
こうしたデザインへの配慮は、個人開発やポートフォリオで他人に見てもらうときにも大切なことだと思います。プログラムの動き、コーディングは一瞥してもわからないし、判別しにくいです。
一方で、どんなに技術的に素っ気なくても、デザインがよければインパクトがあります。デザインは他人に何かをアピールするときはとても重要になります。アメリカでソフトウェア開発の営業をしている人もプレゼンの際には、腕の良いデザイナーさんに資料作成を依頼すると言われていました。
時々、大手企業のシステム受注のコンペに参加したり、その結果を見たりすることがあります。やはり、UIデザイナーさんが作ったイメージがプレゼン資料内にある企業は、受注率が高い気がします。ダサいところは、経営層からのウケが悪いように思います。
あるコンペをしたとき、アプリのデザインがダサかった大手SIer企業は失注し、デザインが良かったベンチャー企業が受注したのを見たことがあります。確かに、私がみたときも、同じような機能ならデザインが良い方をとるなあと思いました。ちなみに、価格はベンチャー企業もそこまで安くしてなかったように思います。
では、デザインをよくする手法はどうやって学ぶのか?
たまにデザイナーさんと話す機会があるのですが、皆さん言われるのは、「良いデザインの真似をする」ということです。パッと見た時に、良いなと思ったら、その良さを分析して、それを自分のプロダクトに活かしていくとよい気がします。すごいデザインとかは無理でも、それなりに見えるものは練習すれば作れるようになると思います。
6. さいごに
(1)個人開発とチーム開発の補完関係
本投稿の前半は、個人開発をチーム開発へと移行した過程を整理してみました。個人開発にもいろいろあって、経験者が終始個人で開発していくものもあると思います。一方で、未経験者が学習目的で行うものもあります。今回は後者のケースです。なので、どうせ学習するなら現場でもっと必要とされていて、一人ではできないことを学んでもらおうと思いチーム開発へと移行させました。
単価の高い仕事をすればするほどチーム開発は当たり前になっています。そして、個人開発のアプリが儲かるようになり機能が増えてくれば、チーム開発が必要になる局面も来るかと思います。
プログラム自体を学ぶのは、書籍、オンライン講座、スクールなどいくらでも学ぶリソースが溢れています。ただ、チーム開発を学ぶとなると、ある程度の経験者と仲間が必要になります。一方で、チーム開発をするにしても、「何をつくるか」というテーマが必要であり、個人開発でつくっていたアプリは、チーム開発のテーマとしても良かった と思っています。つまり、「個人開発」と「チーム開発を学ぶ」ということが互いに補完していたように思います。
(2)実務をする上で必要なこと
後半の「5. アプリが作れるようになったら学習・意識した方がよいと思うこと」は、「上流工程」、「コーディング」、「デザイン」について実際にメンバーに伝えたこと、そして、その補足を整理してみました。この内容は、今回の開発メンバーだけでなく、これまで色んな現場であってきた若手のプログラマーを見ていても同じことを思ってました。
実際、チーム開発の現場に入ったり、フリーランスとして仕事を受注したりなど考えた場合、ここで触れた内容は重要だと思います。上流工程やコーディングの内容はチーム開発にも必要ですし、デザインは営業面で必要となるものです。
開発メンバーがいずれもフリーランスということもあり、常駐、受託いずれもすることを念頭に、上記の内容を伝えました。少しでも実務に活きることを願っています。
(3)2021年個人開発アドベントカレンダーの作成者、投稿者の皆さんへ
個人開発のアドベントカレンダーの投稿者の皆さん、お疲れさまでした。そして、残りは3日となりました。担当の投稿者の方、頑張ってください!投稿記事を楽しみにしています。
また、このカレンダーを作成してくださった、@yuno_miyako さん、ありがとうございました。
※1 :個人的には、ウォーターフォールだから失敗するとも思っておらず、本文で述べたように、経験・知見があれば、結局は大幅なブレを抑えた設計が最初の時点できます。また、こまめにメンバー間での意思疎通をして、状況を把握していれば大きな問題になりにくいと思っています。
活発な意思疎通、細かい情報共有という意味では、アジャイルと同じ方針だと思います。要は、ウォーターフォールとアジャイルは、工程の対象範囲、期間、進め方が違うだけで、人の動きを管理する方法はアジャイルと同じだと思います。
逆に、アジャイルとは名ばかりで、全体をみず行きあたりばったりだったり、意思疎通もなく、状況把握ができていなければ当然、大炎上します。つまり、ウォーターフォールかアジャイルかというよりも、もっとプロジェクト運営のベースの部分にマネージメントの大切さがあると思っています。
結局は、ウォーターフォールもアジャイルも銀の弾丸でもなく、人的な素養の高さを求めるものな気もしています。アジャイルで小さくすれば成功するけど、全体の整合性がとれていなければ、結局、振り出しに戻ることもありますので、やはりアジャイルとはいえ全体を見渡すことは大切なのだと思います。
※2: 名前付き引数については、以下にメリットが書いています。
※3:パラメーターオブジェクトについての補足。
※4:個人的には、チーム開発するならコンポーネントにスタイルのパラメーターを設定させなくてもいいのではないかと思っています。スタイルはCSSで設定し、そのためのセレクターだけパラーメーターとして持っていればいいように思います。
こうすることで、「見た目・スタイル」という関心事をコンポーネントから切り離すこともでき、スタイルが変更になった場合も、Js/Ts/HTMLの変更はあまりないと思います。コンポーネントからスタイルを独立させてしまえば、HTML/CSSコーダーさんとの協業もしやすくなります。
Reactは、個人や少ない人数での開発をする際は、コンポーネントに何でもかんでも定義している方が、短期的にはコーディングが楽かもしれません。一方、チーム開発をしてくるとなんでも詰め込んでしまうと協業がしにくくなります。
特に、Js/Ts/HTMLは、「データの構造・操作」のみを関心事としておくほうが役割はスッキリし、見た目が異なるいろいろなプロジェクトで使い回すこともしやすいと思います。
本来、コンポーネントは小さく、独立化させ、ポータブル(どこでも使える)にしておくものだと思います。コンポーネントの役割や設定が多い場合、それを使う箇所がが増えると、仕様変更の際に修正箇所が増えることになります。特に、スタイルについては、セレクターだけをもち、別途独立したCSSで定義しておくほうが一括変更しやすくて効率的だと思います。
ただ、あるプロジェクトでしかそのコンポーネントは使わず、スタイルと構造を一緒に管理しておきたいというのであれば、Styled-componentのようにスタイルをコンポーネントで定義するのもありだと思います。