はじめに
こんにちは! ひらぬま(@koocookooc)と申します。
「エンジニアDB」という、『〇〇なエンジニアを検索できるサービス』を開発したので、紹介します。
ターゲットは、エンジニアの皆さんに向けていますので、ご利用いただけると嬉しいです。
無料でご利用頂けます。
自己紹介
大学院(建築学)を卒業後、新卒で大手ハウスメーカーのIT事業部に入社しました。3年ほどITの企画、PM、設計、開発、テストなどを通して、ITのイロハを身につけました。
その後、より良いサービス・プロダクトを作れる人になるためには、開発サイドの経験もしておきたいと思いから、Web受託開発のスタートアップ会社にエンジニアとして転職しました。 今でちょうど2年目になります。
勉強したこと、使ったサービス
下記、1年間の勉強方法、使ったサービスをざっくり紹介しておきます。 結構幅広く手を出していました。
- 実務でフルスタック開発
- メンターのアルバイト
- 業務委託で開発
- Happiness Chainで、フルスタックに勉強
- Cloud Techで、AWS勉強、SAA,DVAを取得
- IT KINGDOMで、最先端のフロントエンドのキャッチアップ
- connpassのオンラインイベントに参加
- XやQiita,Zenn,Udemyなどでインターネットから情報収集
そんな筆者が開発したサービスを紹介します。
ポートフォリオや個人開発の参考になればと思います。
目次
1.「エンジニアDB」の紹介
2.企画〜基本設計について
3.インフラ(全体構成)について
4.フロントエンドについて
5.バックエンドについて
6.さいごに
1.「エンジニアDB」の紹介
サービス概要
エンジニアDBは、エンジニアデータを集約させて、エンジニア間の技術的なつながりをするプラットフォームです。求人検索や求職、開発仲間の発見をスムーズに行えるよう設計されています。
全体像
ご利用手順
▼サービスURL
レスポンシブ対応していますが、PCファーストで実装しています。
開発背景
現在、エンジニアの求人には、SNSや人材サービスを活用することが多いですが、
その求人と求職の体制にはいくつか課題がある考えています。
SNSは検索性に欠け、特定の人材を見つけにくいという問題があります。また、人材サービスはデータを独占する傾向にあり、複数のサービスに登録する必要が生じます。
このような課題を解決するために、「エンジニアDB」を提案します。
エンジニアDBは、登録されたデータを独占せず、共有し、その民主化を目指しています。
このアプローチにより、エンジニアや企業が互いに結びつきやすい状態が生まれ、エンジニアの探索や仕事の探求に役立ちます。
さらに、エンジニアDBに蓄積されたデータを分析することで、より価値ある情報を提供していきます。
最終的なビジョンは、
「本サービスに登録するだけで、企業やエンジニアと繋がる状態を実現すること」 を目指しています!
図解するとこんな感じです。
2.企画〜基本設計について
アイデアを出し
初期段階でのアイデア出しについて、具体的な指針がない状態だと、非常に難しいです。
なので、はじめに、以下の基本方針を設定することにしました。
- 人の役に立つものを作りたい。
- スクール課題レベルの技術(基本的なCRUD・認証など)で、価値あるサービスを作りたい。
- ターゲットは、エンジニアの皆さんにしたい。
- 理由は、Webアプリに慣れている & XやQiitaなどでリーチしやすそう & フィードバックを頂きやすい(かも)といった点です。
この方針でアイデアを考えていると、
エンジニアという特定の属性データを集約し、それをユーザーに共有・還元することで、魅力的なサービスを開発できるのではないかという考えに至りました。
バージョン1として、求人・求職に利用できる機能のみにフォーカスを当てて、実装し、リリースしています。
今後、需要に合わせて、機能を拡張していきます。
要求定義と要件定義
ざっくりですが、説明します。
「〇〇を△△したい」という形でまとめられるのが、要求定義と位置づけています。
つまり、このサービスで実現したいことです。
- エンジニアのデータを集めたい。
- エンジニアを検索できるようにしたい。
- サービス内で連絡を取れるようにしたい。
- イベントや求人・求職をアピールできる場を設けたい。
要求定義を基に、次は要件定義に移ります。
要件定義は、どのようなシステム・機能が必要なのかをまとめます。
- エンジニアのデータを集めたい。
- ユーザー(エンジニア)がアカウントを作成できるようにする。
- プロフィール情報を入力できる機能をつける。
- エンジニアを検索できるようにしたい。
- 検索機能をつける。
- エンジニアと連絡を取れるようにしたい。
- メッセージ機能をつける。1対1のメッセージで十分である。
- イベントや求人・求職をアピールできる場を設けたい。
- 投稿機能をつける。
ここまでの構想をまとめると、
下記のように図解することができます。
ここまでくると、ユーザーの動線がわかってきますので、
必要なページや機能が明確になり、ワイヤーに落とし込めるようになります。
画面(ワイヤー)設計
今回のプロジェクトは一人で全て実装したため、詳細なワイヤーフレームの作成は行っていません。
しかし、ユーザーの動線の確認と画面構成の概要を理解するために、Figmaを用いてモックアップレベルの設計を行いました。
ここまでの設計をフローにまとめると、下記のようなイメージです。
機能一覧
続いて、機能一覧とそれぞれの説明をします。スクショを併せて記述します。
UIUXやURL設計は、ZennやX、食べログなど、有名なtoCサービスを参考にさせていただきました。
(有名なサービスがデファクトになっていると思ってますので)
認証機能
ログインは、GitHubログインのみにしています。
1人あたり1アカウントのみの作成にしたかったのと、ユーザー対象をできるだけエンジニアだけにしたかったためです。
GitHubを使用しないエンジニアにも将来的にはアクセスを拡大する計画ですが、現段階では特定のターゲットに焦点を当てています。
ユーザーのプロフィール設定
基本情報やスキルセットを登録できるようにしています。
これにより、ユーザー検索する際や、そのユーザーについて知ることができます。
スキルセットについて、様々なスキルを細分化して、それぞれにレベルを登録いただけるようなUIにしています。
検索機能
ユーザーのプロフィール情報とスキルセットを検索条件にして、検索できるように設計しています。
この機能がサービスの肝になります。現状は、基本的な検索条件のみを設けています。
今後、ユーザーの声が聞けたら、もっと検索方法を改善していきたいと思っています。
投稿機能
特定の人を探したり、イベントなどをアピールしたりするときに、自分から発信できるようにするために投稿機能を設けています。
ターゲットをエンジニアにしていますので、マークダウンで投稿できるようにしました。
リッチでスタイリッシュな投稿ができます。
メッセージ機能
求めるエンジニアに連絡を取るために、メッセージ機能を設けています。
最近では、SNSでメッセージができる環境があるので、あえて本サービスでメッセージのやり取りはしなくてもいいと思い、軽めに設計・実装しています。
今後、Webプッシュ通知を導入できれば便利になるかなと思っています。
ダッシュボード機能
ユーザーデータをいい感じに集計して表示できる機能があったら面白いな〜っていうので設けることにしました。
データが集まったら、もっと価値のあるダッシュボードを提供していきたいです。
URL設計とページ一覧
下記のようになっています。
URL | ページ |
---|---|
/login | トップページ |
/engineers | エンジニア一覧(ログイン後のトップページ) |
/engineers/dashboard | データダッシュボード |
/engineers/{id} | 特定エンジニアのプロフィール |
/engineers/{id}/skill | 特定エンジニアのスキルレベル |
/engineers/{id}/post | 特定エンジニアの投稿一覧 |
/posts | 投稿一覧 |
/messages | DMグループ一覧 |
/messages/{id} | 特定エンジニアとのDM内容一覧 |
/mypage | 自分のプロフィール |
/mypage/skill | 自分のスキルレベル |
/mypage/post | 自分の投稿一覧 |
/policy | プライバシーポリシー |
3.インフラ(全体構成)について
ここから技術的なことについて話していきます。
まず大前提として、プロジェクトの全体構成は、Happiness Chain の卒業課題の条件に基づいて決めれらていました。これらの条件には以下が含まれます
- Rails APIモード / Reactで完全SPAのポートフォリオを作る。
- 本番環境と開発環境にDockerを使う。
- 本番環境にはECS Fargateを使う。
- GitHub Actionsを使ってAWSに自動デプロイする。
- Terraformでインフラをコード化する。
なので、これに倣って実装しています。
アーキテクチャの全体像
フロントエンドはVercelにデプロイして、バックエンドはAWSのECSにデプロイしています。
ブランチ運用は、GitHub flowを採用しています。
プルリク時にテストが走り、mainブランチにマージされるとデプロイされる感じでCICD設計しています。
AWSリソースは全てTerraformで書いています。
こちらの記事にまとめていますのでご参照ください。
認証の仕組みについて
今回、フロントエンド側でNextAuth.jsを用いてGitHub認証のみでログインできるように実装しました。
FIDO Allianceを中心に推進されている 「パスワードレス」です。 セキュリティやユーザービリティが向上すると思っています。
さらに1ユーザー1アカウント、かつユーザーはエンジニアのみ、という条件にもぴったりです。
APIの認証は、NextAuthで生成されたJWTトークンをheaderに含めたリクエストをRailsに投げて、Rails側でJWTトークンを検証することで実装しています。
下記のようなフローになっています。
JWTトークンは、Next.jsのサーバーサイドのみで扱うようにしています。
サーバーサイドでのみJWTを処理することで、クロスサイトスクリプティング(XSS)などのウェブベースの攻撃からトークンを保護できます
状態管理が簡素化されるので実装がシンプルになり、さらにクライアントサイドの負荷が軽減されるので、よりスムーズなユーザー体験を提供できていると考えています。
以降、フロントエンドとバックエンドの設計、実装内容を説明していきます。
実装したコードはこちらで公開しています。
よくないところは、率直にご指摘いただけますと嬉しいです。
4.フロントエンドについて
使っているフレームワークや主要なライブラリ、テスト手法について記述していきます。
フレームワーク
Next.js13のApp Routerを採用しています。 言語はTypeScriptです。
採用理由
キャッチアップを兼ねて、このサービスは、Next.jsの最新に追従していきたいので、採用しました。
下記の記事を参考にして、リリース段階ではApp Routerの機能へ深入りはせず、
必要になったときに、必要な分だけアップデートしていく感じで、考えています。
良かった点
サーバーサイドデータフェッチが容易になっており、Railsとやりとりする部分は、全てサーバーサイドで処理するように実装しました。 データフェッチの部分では、状態管理が不要となるので、実装がシンプルになりました。
ルーティングとレイアウトの設計がしやすく、ディレクトリ構成から設計の意図が伝わりやすくなったように感じます。
学習教材としては、Next.js が公式で出している、Learn Next.js がわかりやすいのでおすすめです。
CSSやUIコンポーネントのライブラリ
Tailwind CSS で実装しています。
UI コンポーネントとして、Shadcn/UIを採用しています。
Shadcn UIは、Radix UIとTailwind CSSを用いたコンポーネントで、必要なUIのみをプロジェクトにinstallできるようなツールになっています。
採用理由
Tailwind CSSは、クラス名など考える必要がなくスラスラ書けるので、開発速度が圧倒的に速いと思っています。
ネットではコードが見にくくなるようなデメリットの懸念が散見されましたが、一人で開発していたことや小規模なサービスだったので、気になりませんでした。
UI コンポーネントのShadcn/UIについて、
2023 JavaScript Rising Starsで、スターの増加数が高かったJSのOSSのラインキングで1位にもなっててかなり注目を浴びています。
使ってみた感想として、
プロジェクトに応じてスタイルを変更しやすく、ライブラリのような依存関係がないので取り入れやすかったりするので、Tailwind CSSを採用している場合はおすすめです。
Storybook
採用理由
コンポーネントの採用利用率を上げるため、UIテストを実装できるため、今後の保守運用の3点です。
このうち最も魅力に感じているのは、UIのテストを実装できることでした。
Storybook の採用デメリットとして、メンテコストが高い、腐らせてしまうなどが多いようでしたが、下記記事が参考にすると、それらの懸念は解消されると思いました。
つまり、Storybook を採用しても、「プロジェクトの複雑化を避け、ファイル生成のコストを共通化で抑え、スナップショットテストと絡めてリターンを得る。」ことが可能になります。
テストについて
ESLint と Pretiier による静的解析、Storybook による UI の単体テストと結合テスト、Jest によるビジネスロジックや関数の単体テストを実装しています。
Github Actions でプルリク時に、これらのテストが自動で走るように設定しています。
なお、E2E テストはコストがかかりすぎので、導入を諦めました。手動でチェックします。
フロントエンドのテスト手法として、Jest や React-testing による単体テストや結合テストが散見されましたが、〇〇コンポーネントに「〇〇」と書いてあればテスト OK のような例が散見されており、効果が薄そうだなぁ感じていました。
Storybookを使ったテストでは、インタラクションテストやビジュアルテストリグレッションテストが実装できることがわかりました。なので今回、UI に関するテストはStoryBookで実装するように決めました。
参考
ディレクトリ構成
_components というディレクトリを切って、いい感じにコンポーネントを管理しています。
urlに関わるディレクトについて、ディレクトリ名は小文字ハイフンで統一しています。
大まかな構成は下記のような感じです。
.
├── app
│ ├── _components # 全てにコンポーネント
│ │ ├── ui # atom, moduleレベルのコンポーネント
│ │ └── layout # 共通のheaderやfooterなど
│ ├── (authenticated) # 認証後のページ
│ │ ├── _components # 認証後の共通コンポーネント
│ │ ├── engineers # エンジニアページ
│ │ │ ├── _components # エンジニアページの共通コンポーネント
│ │ │ ├── (root) # /engineersページ
│ │ │ │ ├── _components # /engineersページのコンポーネント
│ │ │ │ ├── layout.tsx # /engineersページのレイアウト、メタ情報
│ │ │ │ ├── page.tsx # /engineersページのデータフェッチ、コンポーネント配置
│ │ │ ├── [id] # /engineers/[id]以下のページ
│ │ │ └── layout.tsx # エンジニアページのレイアウト
│ │ ├── messages # DMページ
│ │ ├── mypage # マイページ
│ │ ├── posts # 投稿ページ
│ │ ├── quit # 退会ページ
│ │ └── layout.tsx
│ ├── (unauthenticated) # 認証前のページ
│ ├── api # Api Route
│ ├── globals.css
│ ├── layout.tsx # 前ページ共通のレイアウト
│ ├── not-found.tsx
│ └── page.tsx # 認証前後で、リダイレクトを設定している。
詳細は、こちらを参考にしてください。
App routerでは、このようなディレクトリ構成を採用&おすすめしているケースが多いです。
参考
開発で工夫したところ
- 画像投稿機能について、画像投稿前に、フロントエンド側で画像圧縮するようにし、無駄なサーバーやストレージのリソースを利用しないようにしました。
- レンダリングについて、基本的に SSR として、フォームなど状態管理が必要な部分のみを CSR にするようにしました。 また、ダッシュボードページ等の処理が重いページかつ、最新データでなくてもOKなページは、ISR にし、キャッシュしたデータを扱うようにしました。 (0.5hごと更新)
- url設計やUI, UX は丁寧に設計しました。 トップページなどのクリエイティブが必要な点は、外注すべきと思いました。。
- 無限スクロールとページネーションを使い分けています。使い分けのポイントは、UI・UXとURLが必要かどうか と思っています。 (今回SEOは関係ないので無視する)
- 検索ページは、検索条件やページ数をクエリパラーメータで持たせるようにして、ページネーションを採用しています
- それ以外のページは、UIUXの良い無限スクロールでを採用しています。
- 「Next13NProgress」というライブラリで、画面遷移時のプログレスバーを実装しています。ページ遷移待ちのユーザーの心理状況がかなり向上すると思っています。導入が簡単なので、おすすめです。
5.バックエンドについて
使っているフレームワークや主要なgem、テスト手法について記述していきます。
開発環境
Dockerを使っています。
Appサーバー用とDBサーバー用の2つのコンテナを起動させています。
ローカルPC(macbook air メモリ16GB)で、Docker起動すると、PCが重すぎて作業が捗りませんでした。。
なので、AWS EC2(linux)にremote SSH接続した環境内で、Dockerを起動させるようにしていました。。
フレームワーク
Ruby on Rails7 のAPIモードで実装しています。
前述の通り、スクールから指定があったので採用しています。特に採用理由などは書きません。
gem
特殊なものは採用しておらず、あまり説明することがないです。
下記のような、多くの人から支持されているgemを採用しています。
active_model_serializers
APIのレスポンスボディを構成するために、採用しました。
aws-sdk-s3
Active Storageの保存先を、S3に設定するために採用しました。
テスト
テスト戦略として、RuboCopによる静的解析でコードの品質を保ち、モデルスペックでバリデーションやアソシエーションの正確性を確認しています。さらに、リクエストスペックを用いてAPIの結合テストを行い、システム全体の動作を保証しています。
モックデータの作成
モックデータの作成には『factory_bot_rails』と『faker』を使用しています。これらのgemにより、テスト用のリアルなデータセットを容易に生成でき、テストの正確性と効率を大幅に向上させています。
モデルの単体テスト
shoulda-matchersというgem使っています。 バリデーションテストなどを1行で記述できるようになので楽になります。
モデルスペックでは、バリデーション、アソシエーション、メソッドのテストを実施しています。
APIの結合テスト
ユースケースに基づいて、正常系と異常系の動作を確認しています。
正常系は、レスポンスのステータスとボディの確認をしています。
異常系は、認証エラー、not found、リクエストパラメータのバリデーションなどを確認しています。
参考
DB設計
主要な部分を記述します。
開発で工夫したところ
- 開発面では、Rails Wayに従い、MVCアーキテクチャを厳守し、DRY原則を適用してコードの重複を避けるようにしています。
- パフォーマンス面では、n+1問題、データアクセス回数、メモリ使用量などに注意して実装しています。
- Primary Keyは、UUIDを採用しています。インフラとバックエンドを移行する可能性があるので、移行性を考慮しての対応です。セキュリティ的にもUUIDの方が良いみたいでした。
参考
6.さいごに
ここまで読んでありがとうございます!。
「エンジニアDB」は、エンジニア間のコネクションを深め、求人やプロジェクトへの参加機会を広げることを目指すプラットフォームです。エンジニアの皆様にとって、新たな出会いやチャンスの発見の場となれば幸いです。
今回の開発は、Happiness Chain で学んだ知識と経験が基盤となっています。 ロードマップがしっかりしてるので、効率的にフルスタックな技術が身につきました。 最後まで・ご指導、レビューいただいた皆様に感謝申し上げます。
今後も「エンジニアDB」のさらなる成長と、エンジニアの皆様にとっての価値あるサービスづくりに努めます。ご興味を持っていただいた方は、ぜひ下記のリンクよりサービスをご利用いただければと思います。
また、私の活動やサービスに関する最新情報は、「X」で随時更新していますので、ぜひフォローしていただけると嬉しいです。
改めて、この記事を最後までお読みいただき、ありがとうございました。
以上