こちらの記事を訪れていただき、ありがとうございます。
この度、タイトルにもある通りポートフォリオとして 「面倒な献立作りから解放し、レベルを上げて料理を楽しむレコメンド献立アプリ(FunCooApp)」 を開発しました。
こちらの記事では、アプリの制作過程や実際の機能など を紹介していきます。
アプリの使用イメージは『主な機能』で確認することができます。
- (旧)アプリURL:
https://fun-coo-app.com(費用を考慮してHerokuに移行予定です) - (新)アプリURL:
https://fun-coo-app.herokuapp.com/(Herokuの無料プランが廃止されたため現在公開を停止しています) - GitHubリポジトリ: https://github.com/iloveomelette/funcoo_app
- Twitter(学習継続130日[執筆時点]): https://twitter.com/icanenrichlife7
簡単な自己紹介
- 神奈川県在住の24歳、男
- 2月前後にRubyの学習を始め、2月中旬からRailsの学習を開始(総学習継続130日[執筆現在])
- 同時に基本情報技術者試験の学習も並行し4月末に受験し『合格』しました。
- 好きな食べ物は 「オムライス」 です!
開発目的、背景
どうしてポートフォリオ?
大きく 『3つ』 あると考えています。
- 転職活動をする上で、現時点での自分のスキルを証明するため
- 実際の現場に入る前に開発の全体的な流れを大まかに把握するため
- 実践を通して技術力を向上させるため
どうしてレコメンド献立アプリなの?
お恥ずかしい話、私は現在実家に住まわせていただいております。
そんな我が家では、以下のような会話が毎日繰り返されていました。
母 「今日の夕ご飯は何にしようか?」
私 「ん〜、何がいいかな〜。なんでもいいよ!」
心の声: どうしよう...何を食べたい気分なのか、がない!
母 「なんでもいいじゃ分からないでしょ!献立を毎日考えたり料理をするのってすごい面倒だよね。」
私 「うん...」
みなさんもこんな会話があるのではないでしょうか。
聞く側も「なんでもいい」と言われ 自分で考えて作らなければならない面倒な気持ち を抱え、聞かれた側も答えられず、申し訳なさなど を抱える。
そんなマイナスしか生まない会話を解消したい という想いから当アプリが生まれました。
「FunCooApp」という名前も 「Fun Cooking Application(料理を楽しむアプリ)」 の各頭3文字を取ったものです!
ただ献立を提案するだけでは、献立や料理に関するプラスの会話は生まれません。
では、どうしたら料理が楽しくなるのか考えました。それは 「達成感」 だと思います。
「こんだけ頑張ったんだ」という気持ちが湧くと 「もっと頑張ろう!」 と思えますよね?
それを実現するのが当アプリです!
*補足
レシピの質を担保するため、投稿者は食に精通した個人農家、個人飲食店経営の方々を想定しています。
ユーザの属性を「法人」と「一般利用」に分けて「法人」のみが投稿をできるように実装しています。
開発期間は?
最初のコミットが3月下旬だったので、1ヶ月強 [執筆時点]です!
以下は、GitHubのcontributionsです。(ポートフォリオ以外も含まれています)
使用技術
フロントエンド
- HTML / CSS / Sass / Tailwind / Javascript
基本はSassを使ってスタイルは仕上げています。
Tailwindは補助的な立ち位置で使っていましたが、 分かりやすいクラス名を考えるまでもなく自由に実装できる点は助かりました。 もう少し厳格に使用基準を設定してあげるとコードの見栄えも良くなったかなというのが反省点です。
これは、徐々に改善していきます。
バックエンド
- Ruby 3.1.0
- Ruby on Rails 6.1.5
Ruby/Railsを選択した主な理由は、
日本語でのドキュメントが充実している点
実際に触れてみて自分との相性が良くスピード感を持って開発できる点 です。
DB
- MariaDB 10.6.7
MariaDBを選択した主な理由は
実務で普及しているMySQLと高い互換性がある点
学習中はMariaDBを使用しており、スムーズに開発に進められる点 です。
インフラ
- AWS(VPC / EC2 / RDS / ACM / ALB / Route53 / S3 / CloudFront / IAM)
AWSを選択した主な理由は
Herokuでは起動するまでに時間がかかってしまう点
実務では圧倒的に支持されているであろうAWSの大枠に触れたい点
1年間の無料枠をこの機会に活用して勉強できる点 です。
ツール
- Rubocop
- FactoryBot / RSpec
- Visual Studio Code
- Git / GitHub(Git-flow)
- FontAwesome
- Adobe Color
- Draw.io
- Figma
- Notion
主な機能
以下は、パソコン画面での紹介になります。
【レコメンド機能】
「作ってみた!」ボタンを押すと、そのレシピ情報に合わせてログインユーザへレシピをレコメンドします。
【レシピ投稿】
タイトル、内容、調理コストなどの情報、ジャンル、料理イメージを入力して投稿します。
【レシピ検索】
レシピタイトル、レシピ内容、調理時間、ジャンルなどから検索をすることができます。
【アカウント登録】
アカウント登録では、属性を選択して一般利用か法人かを選択します。ユーザ名、メールアドレス、パスワードを入力してアカウント登録します。また、Googleアカウントでもログインができます。
【ユーザページ】
ユーザページでは、プロフィール画像、メールアドレス、現在のレベルなどの情報、「作ってみた!」ボタンを押した投稿、お気に入りの投稿を閲覧することができます。
使用したGem[一部抜粋]は以下の通りです。
開発過程での意識した点
実務(チーム開発)を意識した開発
実際の現場を想定してGit-flow
モデルに沿って開発を行っています。
Commit
メッセージとプルリクエストのタイトルは 誰が見ても概要がわかる ようにし、メッセージは 具体的にどんな実装を行ったのか 、理由を記載すべき時は理由を含めて記述していました。
↓実際に使用したブランチ
ブランチ名 | 目的 | 用途 |
---|---|---|
main/master | 本番用 | 開発作業は行わず、タグでバージョン管理 |
develop | 開発用 | featureブランチを作成して機能開発 |
feature | 機能実装用 | 新規機能を開発してdevelopにマージ |
release | リリース直前用 | リリース直前のバグ修正など小さな変更してmain/developにマージ |
難しいタスクは細分化して開発
詰まってしまったり、処理が複雑な場合は以下のように細分化したり、対象が1人の場合どうなるか、など簡単に実装できるところから徐々に膨らませていきました。
この時にNotionを活用していました。
- ゴールを明確に言語化する
- それに到達するまでの中間ポイントを明確に言語化する
- 一つ一つを実現するための手順や必要な変数などを言語化する
- コードに落とし込んでいく
以下は、実際に細分化している一部です。
ユーザ視点でのUI/UX設計
まず、色がぶつかり合って見づらくならないように
アプリ内で使用するカラーを 3色 ないしは 4色 に限定しました。
優先度 | 色コード | 選定基準 |
---|---|---|
1 | オレンジ | 料理は火のイメージが強く、それに近く元気なイメージを与えられる色 |
2 | グリーン | 近年では健康志向が強いため、健康かつ体に優しいイメージを与えられる色 |
3 | イエロー | オレンジとの相性がよくサブとして活躍できる色 |
4 | スカイブルー | オレンジ、グリーン共に相性が良くアクセントに使用できる色 |
次に、通常時以外 の時に行動を促すメッセージを表示するようにしました。
例えば、レコメンド機能ですが最初の段階では「作ってみた!」を押さない限り、レコメンドすることができません。
そういった場合は、「作ってみた!」を押すように促すメッセージを表示しています。
まだまだスタイルの改善点はあるので、随時更新していきます!
開発過程での苦労した点
苦労した点はかなりあるのですが...大きく3つ 挙げさせていただきます。
RailsデザインであるFormオブジェクトでの実装
特に更新アクションにおいて、パラメータがうまく渡らず苦戦しました。
1つのフォームで複数のテーブルに保存をかける方法の一つとして、Formオブジェクトでの実装を行いました。
理由としては、accepts_nested_attributes_for
の評判があまり良くなく、Rails開発者の方も無くしたいと言っているメソッドであり、現役のエンジニアの方々が会社の方針として使用禁止にしていることを聞いたためです。
こちらの記事でアウトプットさせていただきました。宜しければご覧ください。
Formオブジェクトで実装したことで、パラメータがどのように渡っていたり、どのような流れで渡されていくのかをbinding.pry
を通して学ぶことができました。
また、どのように問題を切り分けるか地力の向上に繋がりました。
まだまだ奥が深いので、引き続き深ぼっていきたいです。
レコメンド機能の実装
レコメンド機能のアルゴリズム設計に苦戦しました。
調査を行なっていくと、「協調フィルタリング」「Matrix Factorization」「SVD(Singular Value Decomposition)」など様々あることに驚きました。
「強調フィルタリング」 がレコメンドを実装する上で基礎となりうると判断し、コサイン類似度を用いて実装しました。
レコメンドの土台となるデータ(Genre
テーブルのenum
型カラム)を定めて、どのように他ユーザとの関連性を求められるかを考え抜きました。
こちらも後に記事にしていきたいと考えております。
「強調フィルタリング」はユーザやレシピの数が増えると、それだけ次元が増え計算が困難になる 「次元の呪い」 があります。これを回避する次元削減という考え方があるみたいなので、こちらも触れていきたいと思っています。
AWSへのデプロイ
エラーを解決して1歩進むたびにエラーと遭遇する、を繰り返してかなりの根気を要しました。
この時に意識したことが、基本ではありますが
- エラー文を隅々までよく読むこと
- それをもとに、どこでエラーが発生しているのか(AWS側なのかアプリケーション側なのかなど)、何が要因なのか仮説を立てる
- 調査、検証を繰り返す
詳細は省きますが、以下の記事でアウトプットさせていただきました。
- AWS - Capistranoを使ってデプロイした際のエラー奮闘記
- AWS/Rails デプロイ後の『502』エラー奮闘記
- 【ACM/ALB】504 Gateway Time-out と向き合って見つけた解消法
ER図
ER図は上記の通りです。
抜粋してテーブル/カラムの説明を記載します。(左から)
-
Genres
テーブル: レシピのジャンル。全てenum
型で管理-
staple_food
: 主食 -
main_dish
: 主菜 -
side_dish
: 副菜 -
country_dish
: 各国料理
-
-
Users
テーブル: ユーザ-
characteristic
: 属性。法人もしくは一般利用。enum
型で管理 -
level
: レベル -
experience-point
: 経験値 -
rest-point
: 次のレベルまでの残り経験値 -
url
: 法人が運営するHPのURL
-
-
LevelSettings
テーブル: レベル参照テーブル-
passing_level
: 合格レベル -
threshold
: 閾値(次のレベルを満たす経験値)
-
インフラ構成図
インフラ構成図は以下の通りです。
今後の展望と課題
課題
-
Users
テーブルのカラムが少々多いため、正規化してクリーンにする - 当たり前ですが、現状コードのリファクタリングを行うこと
- レコメンド機能の比較他ユーザ5人のみの比較となっており、正確な関連性ではないため、こちらの最適化
- レベルアップ機能は現状 Lv.50までしか用意しておらず、それ以上の計算となると膨大な計算量になるため、こちらの最適化
- 1つの食材ずつ登録ができるようにFormオブジェクトでの投稿フォームの改善
- アカウント編集の際、新しいプロフィール画像を選択すると、それに応じてビューの画像も切り替わるように改善
- セキュリティ面の向上
などなど課題は山積みですが、一つ一つ改善していきたいです。
展望/実装したいこと
- レシピに対するコメント機能
- ユーザ同士の褒め合いや相談投稿
- 相互フォロー機能
- チュートリアルページ(ヘルプページ)
- お問い合わせ
- Vue.jsを活用したフロント側の向上
- Docker/Docker-composeを活用したコンテナ化
- 自動テストの導入
開発をしてみての感想
実際に0から開発を行って大まかな全体像を掴むことができたことで、私にとって自信に繋がり開発を行う楽しさを味わえました。
試行錯誤を繰り返しながら実装していったため、少々コミット数が多かったり、効率的に記述できる部分があったり、と今後の伸び代がある点は反省点でもあり、嬉しい収穫でもあります。
開発途中でエラーと遭遇した時 「よしきた!」 と思えるようになったことは、エラーを恐れていた開発前と比べて非常に成長できました。
まだまだ至らない点が数えきれないほどにありますが、1つ1つ身につけていけるよう今後も精進してまいります。
最後までお読みいただきありがとうございます。
LGTM
を押していただけますと、大変励みになります!