Qiita Advent Calendar 2021 個人開発の最終日です。
僭越ながらトリを務めさせていただきます。
私達は、数ヶ月かけて ErrorShare というWebアプリを作成しました。
私は十数年間、会社員としてVBAのみで仕事をしてきました。1年前に「Webアプリを開発したい!」と発起し退職。たくさんの方々にアドバイスや助けをいただきながら、独学1年でアプリをリリースできるまで成長できました。
私の話は少し置いておいて、この記事ではシステム構成を中心にお話をしていきます。
この記事の目的
以下のような方を対象に、この記事を書いています。
- どんな技術で作られてるか興味がある!
- Webアプリ開発未経験だけど、開発するために必要なライブラリやサービスが知りたい!
記事の構成
- ErrorShareとは?
- 開発にいたる経緯
- システムアーキテクチャ
- フロントエンド(NextJS)
- バックエンド(Supabase)
- CI/CD
- 開発時の失敗談
- おわりに
ErrorShareとは
ErrorShareとは、プログラムで発生したエラーを皆で共有する目的で作られたサービスです。
皆さんも開発をしていると、理解不能なエラーに悩まされた事があると思います。Googleで検索してみたけど、海外のサイトばかりでわからない…なんていうことも多くの方が経験があるのではないでしょうか?
『 皆でエラーを共有することで、お互いに助け合えることができる場所を作りたい。 』
そんな思いを込めてサービスを開発しました。
開発チームメンバーと、開発に至るまでの経緯
このプロジェクトは3名(+1名のオブザーバー)のチームで開発をしてます。
詳しくは、22日の個人開発アドベントカレンダーに一緒に開発をしている@SFITBさんが記載しています。是非、読んでみてください!
システム・アーキテクチャ
フロントエンド → Next.JS
Next.jsとは、Javascript開発におけるReactライブラリのフレームワークです。
Reactで開発しようと思うと色々な準備が必要ですが、その準備を省略することができるのでとても効率的に開発ができます。
Next.jsの特徴の一つであるISR/SSGを活用し、ビルド時にあらかじめ表示に必要なデータをデータベースから取得し、静的なHTMLファイルを出力しています。事前にHTMLファイルを出力しておくことで、ユーザーがアクセスしたときの表示スピードも早く、またGoogleにも見つけてもらいやすいというSEO対策のメリットもあります。
他にもメリットはたくさんあります。
- フォルダが自動的にルートパスになるので手間が省ける。
- Webpackやbabel等の細かい設定も不要。
- CI/CDを使わずともVercelを使えば、Githubリポジトリと連携するだけで簡単にデプロイできる。 etc...
TypeScript
JavaScriptを拡張して作られたプログラミング言語です。TypescriptとJavascriptの大きな違いは、型付けです。Javascriptは動的型付け言語なのですが、Typescriptは静的型付け言語です。
javascriptの場合は動的に型付けされるので、数字型を想定した関数に文字列を入れてもエラーが発生しません。
const addition = (a, b) => {
console.log(a + b);
}
addition(1, 2) // 結果 3
addition('1', '2') // 結果 12
Typescriptでは静的型付けなので、型を制限することができ不具合を防げます。
const addition = (a: number, b: number) => {
console.log(a + b);
}
addition(1, 2) // 結果 3
addition('1', '2') // エラー
Typescriptも結果としてはビルドされ、最終的にはJavascriptになりますが、上記のような型での不具合を防げる等のメリットがあります。
アトミックデザイン
デザイン及びコンポーネントのディレクトリ構成は、アトミックデザインを採用しています。
アトミックデザインとは、小さなのパーツを複数作り組み合わせることで、Webページを作成してくUIデザインシステムです。最小単位は原子(Atoms)でパーツを作り、少しづつ組み合わせて一枚のページにします。
- Atoms 原子
- Molecules 分子
- Organisms 有機体
- Templates テンプレート
- Pages ページ
国際化(i18n)の対応
Nextjsの機能を使い、英語の対応を行っています。enを追加したUrlでアクセスすると項目名などがすべて英語に変更されます。
国際化の方法については、以下の私がまとめて記事があるので、方法が気になる方は以下を御覧ください。
ライブラリ
いくつものライブラリを活用し、効率的に開発を行っています。
➡ styled-components
CSS in JSのライブラリの一つである、styled-componentsを 採用しています。CSS in JSを使うことで、コンポーネント内でスタイルの管理が完結できるメリットがあります。
➡ recoil
候補としては、「React Hook useContext」や「Redux」等が上がると思いますが、今回はRecoilを採用しました。useStateのような間隔で使用できるので、とてもシンプルで使いやすいです。
➡ headless UI
UIコンポーネントは要所要所で、headless UIを使用しています。スタイルは自由に指定できるので自由度が高いことがメリットです。基本的にはTailwind CSSを使用するのですが、今回はStyled-componentsでスタイルを当てています。
➡ marked ( highlight.js )
エラー記事投稿をマークダウン記法に対応させるため、markedというライブラリを使用しています。またコードにハイライトをつけるために、highlight.jsも併用しています。
しかし、使い方によってはページのパフォーマンスに影響を及ぼします。対応方法については以下の記事で記載しています。
➡ Formik / Yup
バリデーションにはFormikとYupを使用しています。
使用するライブラリを選別から導入までの方法を、@k-kztkさんが記載していますので、是非ご一読ください!
バックエンド → Supabase
Supabase とは、認証やデータベース、ストレージ等を提供する BaaS です。 類似サービスでは「Google Firebase」が存在します。
BaaSであればFirebaseを選ぶのが今はセオリーかと思います。私もNoSQLでのアプリ開発経験はありますが、長期的に運用していくのはとても難しいと感じたため、今回はRDBが使用できるSupabaseを採用しました。
RDB、NoSQL、それぞれの強み読みがありますが、今回開発したアプリはリレーションを多く使用するため、RDBが向いていると考えました。
認証(Authentication)
認証(サインアップ/インの機能)は、GoogleとGithub認証を使用しています。認証の設定方法は、公式で公開してくれているので、以下のサイトを参考に設定しました。
ストレージ(Storage)
エラー記事内で投稿出来る画像やアバターの画像などの保存先に使用しています。画像形式は、WebPで保存をしています。
関数(Functions)
PostgreSQLのFunctionsを使い、記事内の画像サイズの確認などを行っています。SupabaseのデータベースはPostgreSQLなので、同じ要領でFunctionを追加することができます。
CI/CD(継続的インテグレーション/継続的デリバリー)
CI/CDツール等を活用し、自動化をして開発効率を上げています。
以下は全体像です。
3つのポイントがあります。
① フロントはGithubにpushすることで、自動的にデプロイ。
フロントエンドの置き場所は、Vercelを使用しています。
GithubとVercelを連携しているので、GibhubにコードをPushするだけで自動的にデプロイされます。
② Githubのブランチによって、デプロイ先を変更
Vercelの環境変数でSupabaseのAPIを設定することで、メインブランチはSupabaseの本番プロジェクト、メインブランチ以外は開発プロジェクトに接続されます。
③ データベースはマイグレーションで変更
Supabaseはブラウザ上でテーブル等の修正を行いますが、db-migrationというマイグレーションツールを使いPostgreSQLの編集を行っています。
Github Actionsを使用して、各ブランチにマージするタイミングで開発環境や本番環境に反映されるよう設定をしています。これは早い段階で導入したので、大活躍してくれました。
その他技術要素
画面デザイン → Figma
画面のデザインはFigmaを使用しました。プロジェクトの作成数等に制限はもちろんありますが、数名での個人開発をする上では、無料でも十分に活用ができます。
共有も行えるので、私が画面デザインを行いチームメンバーに色々と指摘をいただきながら今の画面に行き着きました。
失敗談……今後の改善!
ここからは技術から離れますが、個人開発をしてきて「こうしておけばよかった……」という後悔を記載していきます。
🙅 もっと先を考えてしっかりと設計をしておけば良かった…。
最初は一人で開発をしていました。
なので、「まぁ、単純にエラーを項目別に登録できるような機能があればいいかなぁ……」なんて適当に考えて作りはじめました。
でも作れば作るほど、「あれも欲しい!これも欲しい!」という気持ちが沸き上がってきます。気がつけば、チーム開発にまで発展しました。
最初に想像を膨らませて全体像を考え、その中から現実的に開発できる機能を構築していけば、もっと効率的に開発できたのかなと感じています。
【 改善点 】
現実的に出来る出来ないは考えず、まず最初はたくさん想像を膨らませよう!
🙅 ライブラリもっと使えば良かった…。
私がVBAのみで十数年開発していたことが大きな原因なのかもしれませんが、「こんな機能が欲しいな。」という状況に直面したとき、「よし!作ろう!」という思考に移ります。
でも今の時代は何でもあるんです。自分がほしいと思ったもの、体験したいと感じたことは、地球上の誰かが経験してるんですよね。
自分の悩みは誰かの悩みです。
誰かが既に悩み、そして解決しています。
【 改善点 】
「こんな機能がほしい」 → 「よし!探そう!」
🙅 もっと早く相談すれば良かった…。
上のライブラリの話と似ている部分もあるのですが、「こんなふうなものを作りたいな」と思ったときに、「こんな風なもの」の名前が分からないですよね。Googleで検索したいけど、「なんて検索したらいんだろ……」そんなふうに一人で悶々と考え、途方にくれてしまいます。
名前の分からない機能を自作してレビューしてもらったときに、「これライブラリあるよ。◯◯って検索したら色々出てくるよ」と教えてもらいました。
一人では開発している場合、頼れる人がおらず難しいかもれません。
それでもやっぱり、誰かに頼ることはとても大切です。頼るということは弱さを見せることのように感じます。とてもとてもハードルが高いように感じます。
でも意外と自分が思ってるよりもフラットです。わからないときは聞くのが一番です。
【 改善点 】
どうにかイメージを言語化して、誰かに相談してみよう!
おわりに
ErrorShareは、はじまったばかりです。
今から少しづつではありますが機能も追加していきたいと考えています。もし「このアプリいいな!」と感じてもらえたら、使っていただける嬉しいです。
長文の記事、読んでいただき有難うございました。
また、個人開発のアドベントカレンダーを主催いただいた、@yuno_miyakoさんに感謝申し上げます。
記事投稿された皆様、お疲れさまでした!