はじめに
はじめまして、未経験からWeb開発エンジニアへの転職を目指しているひろと申します。
今回、転職活動で使用するポートフォリオとして、Qiitaのクローンアプリを作成しました。
ポートフォリオ「Nput」のURL:https://n-put.com
こちらの記事では、ポートフォリオを開発した過程についてまとめたいと思います。
私自身、ポートフォリオとして何を作成しようかとずいぶん悩んだ経験がありますので、もしポートフォリオのテーマ選定などで悩まれている方がいらっしゃいましたら、少しでも参考になれば幸いです。
ポートフォリオのテーマ選定の経緯
テーマ選定の経緯についてお話しするにあたって、まずは簡単に自己紹介をさせていただきます。
自己紹介
私は地方在住、非IT企業に勤めている30代のサラリーマンです。
28歳になるまで、ITとはほぼ無縁の人生を送ってきました。
とあるきっかけでWebサービスを利用する機会が増え、初めて個人用のパソコンを購入し、それからは様々なことにチャレンジするようになりました。
その中で、Webサービスがこんなにも生活を豊かにする力があるのだと気づき、自分もWebアプリ開発に携わってみたいと考えるようになりました。
とはいっても、なんの知識もない初心者である私がいきなりWebアプリを開発できるわけもないので、以下のサービスを利用してプログラミングの基礎を学習してきました。
学習教材
- Progate
- デイトラ(Webアプリ開発コース)
- りあクト! TypeScriptで始めるつらくないReact開発 第4版(①〜③)
- 【独学ポートフォリオ開発応援】実務未経験から学べる!Rails×Next.js×AWSハンズオン解説
- YouTube(Dockerなどについて)
インプット
- Claude:主に、コードやエラーの内容を理解するために利用しました。また、ポートフォリオ開発の初期段階では、Claudeを活用して最適な技術スタックの選択肢を調査し、アーキテクチャやデータベース設計をイメージしてから開発に着手するように意識しました。
- Notion:教材で学習した「環境構築手順、コードの実装手順など」についてまとめました。ポートフォリオを作成する際には、Notionにまとめたことを再利用することで、効率化することができました。
- Studyplus:学習時間を可視化し、プログラミング学習のモチベーションを維持するために利用しました。
課題の発見
これまで、上記の教材やWebサービスを利用して学習を行ってきましたが、アウトプットについてはほとんどできていませんでした。
転職活動を意識するようになってから、アウトプットをしてこなかったことをものすごく後悔しました。
唯一記録していた学習時間は努力の指標として示すことはできますが、『あなたに何ができるの?本当にできるの?』という問いに対する根拠や説得力に欠けるからです。
そこでこれからはアウトプットを行い、それを継続していこうと決意しました。
しかし、今までアウトプットしてこなかった人が突然アウトプットをしていきます!と宣言しても、それを長く続けていくのは難しいことだと思います。
そこで、自分がなぜ今までアウトプットができていなかったのかの原因と課題を明確にして、まずはそれらを解決する必要があると考えました。
アウトプットができなかった原因
結論から言いますと、次の2点が原因であると考えました。
① 学習記録に使用しているツールではアウトプットができない
② 技術ブログ(Qiitaなど)への投稿に対する心理的なハードル
原因① 学習記録に使用しているツールではアウトプットができない
私は学習時のツールとして、StudyplusやNotionを利用していました。
Studyplusはあくまでも「学習時間を記録する」ことが主な機能であり、学んだ内容を記録してアウトプットするには不向きだと考えました。
また、Notionは学んだ内容の記録と整理には特化していますが、コミュニティプラットフォームと連携していないため、フィードバックを得る機会が限られています。
そのため、学んだ内容を効果的にアウトプットするためには、StudyplusやNotionとは別のツールを使用する必要があると考えました。
原因② 技術ブログ(Qiitaなど)への投稿に対する心理的なハードル
エンジニアの方であれば、アウトプットの場として真っ先に思いつくのはQiitaだと思います。
しかし、プログラミングの勉強を始めたての私は、Qiitaに投稿されている記事のレベルの高さに圧倒され、「自分のような初心者が投稿してもいいのだろうか」と、なかなか最初の一歩を踏み出せずにいました。
また、マークダウン記法自体にも慣れていなかったため、「もうちょっとスキルを磨いてからアウトプットしよう」などと、何かと理由をつけてアウトプットを先送りにしてしまっていました。
課題解決
以上のことから、「プログラミング初学者が、学んだ内容を記録して、気軽にアウトプットできるコミュニティプラットフォーム」があれば、アウトプットを続けられるのではないかと考えました。
既存の様々なサービスを検討してみましたが、満足のいくものを見つけることができなかったため、自分で作ってみようと思い立ち、ポートフォリオのテーマとして決定するに至りました。
ポートフォリオの内容のご紹介
長々と書いてしまいましたが、上記のような背景から、今回のポートフォリオのテーマを選定しました。
ここからは、実際に開発したWebサービスの機能、技術スタック、考えなどをまとめていこうと思います。
また、この記事ではパソコン画面での表示で説明していますが、レスポンシブ対応しているため、スマートフォンでも同じ内容を快適に閲覧・操作していただけます。
機能一覧
Qiitaで実装されている機能を参考にしました。
機能 | 説明 |
---|---|
アカウント関連機能 | 新規登録、ゲストログイン、ソーシャルログイン、メールアドレス/パスワードログイン、パスワードリセット、ログアウト、削除 |
ノート関連機能 | 新規作成、マークダウンテキスト、画像保存、変更内容のバックアップ、下書き保存、公開、一覧表示、詳細表示、検索、編集、削除 |
コメント機能 | コメント投稿、マークダウンテキスト、画像保存、ノートに対するコメント一覧表示、削除 |
フォルダ機能 | 新規作成、フォルダ名編集、ノート整理、削除 |
エール機能 | エール送信、エールポイント消費、エール状態表示、エール回数表示、保有エールポイント表示、エールしたノート一覧表示、削除 |
タグ付け機能 | ノートへのタグ付け、タグ付けされたノート一覧表示、ノートに付けるタグの編集 |
学習時間記録機能 | タイムトラッキング、エールポイント付与、学習時間のグラフ表示、ノート作成時間表示 |
プロフィール関連機能 | プロフィール表示、編集、アバター画像保存 |
フォロー機能 | フォロー、フォロー状態表示、フォロー中ユーザーの一覧表示、フォロワーの一覧表示、アンフォロー |
〜基本機能〜
【新規登録・ログイン】
Amazon Cognitoによる認証機能を利用して、以下の4パターンで実装しました。
① ゲストログイン
② メールアドレスとパスワードで新規登録
③ メールアドレスとパスワードでログイン
④ Googleで新規登録・ログイン
ゲストログイン機能について
ノートやユーザーページの閲覧はログイン不要ですが、ノート編集画面などへアクセスするにはログインが必要となるため、「ゲストログイン」機能を実装することで、気軽に試していただけるようにしました。
また、ゲストユーザーによるデータの保存、フォロー、エール送信などの操作については、バックエンド側で制限しています。
制御方法は、Usersテーブルにroleカラムを設定し、リクエストを送信したユーザーのroleがguestの場合にはエラーメッセージを返すようにしています。
Googleログイン機能について
Googleの認証システムを活用することで、情報セキュリティを高めながら、ログイン手続きも簡素化しています。
当アプリ内でのパスワードの設定が不要となるため、複数サイトで同じパスワードを使い回すリスクを回避でき、簡単にログインすることができます。
【ノートページの閲覧】
ノート一覧・詳細ページでは、以下の操作ができます。(UI/UXはQiitaを参考に設計しています)
- ユーザーが公開したノート一覧をカード形式で閲覧(ページネーション)
- カードをクリックしてノート詳細ページに遷移
- ノートにエールを送信
- ノートにコメントを投稿(マークダウン記法・画像挿入可)
【ユーザーページの閲覧】
ユーザーページでは、以下の情報を閲覧できます。
- プロフィール情報
- 学習記録
- ノート公開・エール・フォローなどの活動履歴
また、ログイン後のマイページでは、学習記録のグラフ内にある「X」のアイコンをクリックすることで、X(旧:Twitter)へ学習記録を簡単にポストすることができます。
【ノート作成・編集】
ノート作成・編集ページでは、以下の操作ができます。(UI/UXはQiitaを参考に設計しています)
- タイトル・本文・タグ・概要の入力(本文はマークダウン記法・画像挿入可)
- エディタ/プレビューの表示切り替え
- 下書き保存・ノート公開・ノート削除
- 学習時間の確認
〜こだわりの機能〜
学習時間記録とグラフ化
Studyplusで学習時間を記録することでインプットのモチベーションを維持してこれたという経験から、学習時間記録とグラフ表示機能を実装しました。
ノートを開くと自動でタイマーが開始され、保存時に学習時間が記録されるようにすることで、タイマーの測り忘れや止め忘れを気にせずに学習できるように工夫しました。
エール(応援)
学習時間に応じて獲得できるポイントを使って、他のユーザーを応援することができます。
ポイント制として応援できる回数を制限することで、通常の「いいね」以上の特別な価値を持たせています。(わかりづらいですが、エールボタンを押すと、右上のメガホンアイコン横の数字が減ります)
フォルダによるノート整理
学習したことを後から見返せるようにするために、ノートをフォルダに保存できる機能を実装しました。
技術スタック
5-1. 使用技術
【開発言語・フレームワーク】
本サービスの開発に使用した技術は、以下の2点を軸に選定しました。
- アプリ開発の基礎を効率的に学べるように、学習リソースが豊富な技術であること
- 実務環境ですぐに活用できるように、業界で広く採用されている技術であること
フロントエンド
◯ TypeScript
- 静的型付けによるコード品質の保証と開発効率の向上
◯ Next.js
- CSR(Client Side Rendering)によるインタラクティブな体験の提供
- ISR(Incremental Static Regeneration)による、コンテンツの初期ロード高速化と動的更新の両立
- 組み込みのMarkdownサポートと画像最適化機能による開発効率の向上とパフォーマンスの改善
バックエンド
◯ Ruby on Rails
- 必要最小限の機能に絞ったAPI modeで使用することで、軽量で効率的なAPIサーバーを実現
一覧
区分 | 名称 | 説明 |
---|---|---|
フロントエンド | Node.js(v20.18.3) | JavaScriptランタイム環境 |
Next.js(v14.2.13) | フロントエンドフレームワーク | |
TypeScript(5.3.3) | フロントエンド開発言語 | |
バックエンド | Ruby(3.1.2) | バックエンド開発言語 |
Ruby on Rails(API mode)(7.0.8.4c) | バックエンドフレームワーク |
【ライブラリ・ツール】
フロントエンド
区分 | 名称 | 説明 |
---|---|---|
UI | React(18.3.1) | UIライブラリ |
MUI(Material UI) | UIコンポーネント | |
Marked | Markdown変換ツール | |
フォーム | React Hook Form | 状態管理ライブラリ |
データフェッチ | Axios | HTTPリクエストライブラリ |
SWR | データフェッチとキャッシュ管理を行うライブラリ | |
リントツール | ESLint(v8.57.1) | コードの静的解析ツール |
Prettier(3.4.2) | コードフォーマッタ |
バックエンド
区分 | 名称 | 説明 |
---|---|---|
リントツール | RuboCop | コードの静的解析ツール |
テスト | RSpec | テストフレームワーク |
FactoryBot | テスト用データを作成するライブラリ | |
Faker | ランダムなデータを生成するライブラリ |
【インフラ】
開発環境
区分 | 名称 | 説明 |
---|---|---|
共通 | Docker(v27.4.0, build bde2b89) | コンテナ管理ツール |
Docker Compose | コンテナのオーケストレーションツール | |
フロントエンド | AWS Amplify Sandbox | ローカル開発環境 |
バックエンド | Puma | バックエンドサーバー |
ActiveStorage | ファイルの保存管理 | |
MySQL(8.0.39)(コンテナ) | リレーショナルデータベース管理システム | |
Redis(コンテナ) | インメモリデータベース |
本番環境
区分 | 名称 | 説明 |
---|---|---|
共通 | Docker | コンテナ管理ツール |
フロントエンド | AWS Amplify | ローカル開発環境 |
バックエンド | ECS Fargate | サーバーレスコンテナ実行サービス |
VPC | AWS上で仮想ネットワークを構築 | |
Public Subnet | フロントエンド(Next.js)、バックエンド(Puma、Nginx)を配置 | |
Private Subnet | RDS(MySQL)、ElastiCache(Redis)を配置 | |
ALB | ドメイン名に基づくトラフィック分散 | |
Route53 | ドメイン名管理とDNS設定 | |
ACM | SSL証明書の管理 | |
ECR | コンテナイメージを保存するリポジトリ | |
S3 | ファイルを保存管理するストレージサービス | |
RDS | データベースサービス(MySQL) | |
ElastiCache | データキャッシュサービス | |
Systems Manager | マスターキーなどの秘密情報管理 | |
CloudWatch | ログ監視 |
【認証】
区分 | 名称 | 説明 |
---|---|---|
ID管理 | AWS Cognito | ユーザー情報の管理 |
認証方法 | メール/パスワード | Cognito組み込み機能 |
Google認証 | ソーシャルログイン連携 | |
トークン | JWT | バックエンドでのトークン検証 |
【Continuous Integration / Continuous Delivery(CI/CD)】
区分 | 名称 | 説明 |
---|---|---|
フロントエンド | GitHub Actions | コード品質チェックの自動化 |
AWS Amplify | ビルド・デプロイ自動化 | |
バックエンド | GitHub Actions | テスト・ビルド・デプロイ自動化 |
5-2. 図解
【インフラ構成図】
全体
- フロントエンドとバックエンドをAWSに統合
- Route53によるDNS管理
- ACMによるSSL/TLS証明書付与
フロントエンド(Amplify)
- 静的ファイルのキャッシュによる初期ロードの高速化
- ユーザー認証ロジックの実装効率化
- GitHub連携による自動デプロイパイプライン
- HTTPからHTTPSへの自動リダイレクト
バックエンド(ECS/Fargate)
- RDSのプライベートサブネットへの配置
- GitHub ActionsとECRを連携した自動デプロイパイプライン
【ER図】
基本エンティティ
- User:ユーザー
- Note:ノート
- Comment:コメント
- Profile:プロフィール
- Folder:ノート整理用のフォルダ
- Tag:ノートコンテンツ分類用のタグ
- Duration:学習時間
- Consent:利用規約・プライバシーポリシーへの同意情報
関連エンティティ
- Cheer:エール管理
- Relationship:フォロー管理
- NoteFolder:フォルダーのノート管理
- NoteTag:ノートのタグ管理
ファイル管理システム
- ActiveStorageAttachment:画像ファイル添付情報管理
- ActiveStorageBlob:アップロードされた画像ファイルデータ
- ActiveStorageVariantRecord:画像のバリエーション管理
開発の振り返り
最後に、今回のアプリ開発を通して感じたことをまとめていきたいと思います。
コードの実装内容などの細かい点については、こちらの記事では割愛させていただきます。
もしご興味を持っていただける方がいらっしゃいましたら、今回開発したNputというアプリ内で、Nputの開発手順について順次アウトプットしていっていますので、ご覧いただけると嬉しいです。
また、GitHubのリンクはこちらです → https://github.com/hirolibe/nput
良かった点
学習リソースの豊富な技術(Next.jsやRailsなど)を選定したこと
Railsの学習を始める前はPythonに興味があり、Djangoでアプリを開発した経験がありますが、当時の私は必要な情報を探すスキルも乏しく、デプロイするだけで非常に苦労したことを覚えています。
それに比べると、今回使用した技術では、検索すれば多くの情報を取得できたため、実装方法が全くわからず手が止まってしまうということは少なかったです。
作りたいものを明確にしていたこと
アプリ開発のすべての工程において、「挑戦してみよう!」「どうすればできるだろう?」と、常に前向きな姿勢を保ち続けることができました。
これにより、よりよいアプリとするために新しい技術を調査したり、実際に実装したりする意欲にも繋がったと思います。
苦労した点
取り組んだこと
最初はアプリ内のすべてのページをCSR(クライアントサイドレンダリング)のみで実装していたのですが、Qiitaと比べて初期表示が遅く、画面のちらつきも気になりました。
そこで、途中からISR(段階的静的再生成)を取り入れ、CDN(コンテンツ配信ネットワーク)からキャッシュしたページを配信する方法に切り替えようと考えました。
詰まったこと
今回、インフラ設計は初めてだったこともあり、学習教材を参考にフロントエンドアプリ(Next.js)をAWS ECSにデプロイしていました。しかし、ECSでCDN配信する方法についての情報がほとんどなく行き詰まってしまいました。
様々な記事で調べた結果、ECSを使用する場合に、CloudFrontをCDNとして使用できることまではわかりましたが、設定方法に関する情報はなかなか見つからず、試行錯誤に多くの時間を費やしてしまいました。
考えたこと
そのとき、「AWSって一般的に使用されているインフラなのに、なんでこんなにも情報が少ないのだろうか?」と疑問に思い、「インフラの選択が間違っているのでは?」と考え、Next.jsでCDN配信する一般的な方法を調べました。
その結果、VercelやAmplifyではCDNが標準搭載されていることがわかりました。
改善したこと
今回は、AWSを中心にインフラを構築していたためAmplifyを選定し、フロントエンドアプリのデプロイ先をECSからAmplifyへ変更しました。
これにより、CDN配信に切り替えることができ、初期ロード時間短縮とサーバー負荷の軽減を実現することができました。
(ページにアクセスした際に、即座にコンテンツが表示されるようになったときの感動は忘れられません!)
学んだこと
この経験から、情報が見つからない場合は、試行錯誤して無理に実装しようとするより、まずは選んだ技術が本当に最適なのか疑ってみることが大切だと学びました。
そのためにも、初期段階で必要な機能の洗い出しと適切な技術選定を十分に行うことが重要だと実感しました。
工夫した点
◯ Durationsテーブルを設けて、日々の学習時間を見える化
問題点
Notesテーブルにdurationカラムを追加するだけでは、日々の学習時間のデータを集計・分析するのが複雑になってしまいます。
解決策
セッションごとの時間だけを記録するためのDurationsテーブルを中間テーブルとして実装することで、「今日」や「今月」などの期間別で学習時間を集計できるようにしました。
◯ NoteFoldersテーブルを設けて、ノート整理を効率化
問題点
FoldersテーブルとNotesテーブルを1対多で関連付けると、1つのノートを複数のフォルダに置きたい場合に複製しなければいけません。さらに、後からノートを修正する際には再度複製し直す必要があります。
解決策
NoteFoldersという中間テーブルを介した設計にすることで、1つのノートを複数のフォルダに複製せずに保存できるようにしました。
◯ Twitterカードで学習記録の発信を効率化
Twitterカードとは
TwitterにURLを投稿すると、左下の画像のようにカード形式で表示される機能です。このカードをクリックすると、右下の画像のようなNputのユーザーページが開きます。
問題点
ユーザーページのURL(例:https://n-put.com/ユーザー名
)をそのまま投稿すると、X側で学習記録の画像データが一定期間キャッシュされてしまいます。
そのため、常に最新の学習記録を反映するために画像を動的に生成しても、Twitterカードに表示される画像は最初に投稿したときの画像が繰り返し表示されてしまいます。
解決策
投稿するたびに異なる文字列を含むURL(例:https://n-put.com/ユーザー名/文字列1
や https://n-put.com/ユーザー名/文字列2
など)を生成する仕組みを実装し、X側で画像がキャッシュされる問題を回避しました。
また、これらのURLからユーザーページへリダイレクトさせる仕組みも実装することにより、どのTwitterカードをクリックしてもユーザーページが表示されるようにしました。
反省点
-
後から機能を追加する際に、テーブル設計やインフラ設計を大幅に修正する手戻りが頻発してしまいました。そのため、要件定義などの開発初期段階で十分に構想を練ることが必要であると痛感しました。
-
今回のアプリ開発はすべて単独で行ってきたので、複数人によるチーム開発で生じる課題への対応などについては、十分に経験を積むことができませんでした。今後は、チーム開発を経験できる開発案件にも携わって行きたいと考えています。
今後の展望
オフライン環境下におけるデータ保存機能の実装
ネット接続が不安定な場所でも学習を継続できるように、オフライン環境でのデータ保存機能を実装したいと考えています。
この課題を解決するため、ローカルデータのキャッシュと、オンライン復帰時の自動同期機能を持つ「AWS Amplify DataStore」の導入を検討しています。
今回開発したアプリ「Nput」の運用
私は「Nput」を通じて、アプリ運用の経験も積みたいと考えています。
Nputを少しでも多くの方に利用していただき、貴重なフィードバックを得るために、自分自身もNputを積極的に使いながらXなどのSNSで情報発信を行っています。
まとめ
今回は、「Nput」というアプリをポートフォリオとして開発してきました。
開発過程では、単に機能を実装するだけではなく、「どうすれば使いやすいか」「学習のモチベーションを維持するにはどうするべきか」というユーザー視点に立ち続けることを常に意識して取り組んできました。
特に、ECSからAmplifyへのインフラ構成の見直しは、大きな学習コストがかかることが想定されましたが、「ユーザーにとって最高のパフォーマンスを提供する」ことを意識してきたからこそ決断できたことだと考えています。
今後も「Nput」の運用を続けながら、ユーザーからのフィードバックを大切にし、実際に使われるWebサービスとして育てていく経験を積んでいきたいと思います。
そして、このポートフォリオがWeb開発エンジニアを目指す他の方々にとっても、少しでも参考になれば幸いです。
最後までお読みいただき、誠にありがとうございました。