みんなの「作ってみた」

学習期間4ヶ月、3週間でReact+Node.js+Express+MongoDB+GraphQLで初心者がポートフォリオを作ったお話【2019/6/29更新】

2019/06/20

mbdkaleido
mbdkaleido

初めまして。今回が初投稿になるのでお手柔らかにお願いします。

就活が終わって来年4月入社までに実践で使えるプログラミングスキルを身に着けたいと考えるようになりました。
とりあえず現段階の目標としては夏までにインターンに入ることを目標にしてきました。
【6/22日に達成】
そこで2月から約4ヶ月間勉強を重ねて5月の終わりから現在まで約3週間で動くWebアプリが出来たので

今後勉強をしようと思っている方の参考になればと思って内容をまとめさせてください。

注意

一部未完成の部分もありますが、一先ず動かせるので見逃させてください。3日間悩んでもできなかった部分なのでどなたかご教授頂けると助かります。
一応未完成部分はなくなりました!

目的

前置きでも話したことと被りますが、会社に依存した働き方をしないことを目標に自分で稼ぐ力を身に着けることが真の目的です。

加えて会社に入って即戦力になることも目的の一つです。

なので、フロントだけではなくバックエンドまでこなせる万能マンになることが一つの条件でした。

理由は先輩の社員さんに聞いたところ結局裏のアプリを動かすのにバックエンドの知識は必要だけれど
提案面で行くとフロントの知識となぜこのデザインなのかの説明力も必要とのことで、やはり両方できるに越したことはないという結論にいたりました。

勉強前の筆者のプログラミングスキル

中学時代にUWSCを少し触った程度

大学4年の授業でC言語を少し、夏休みにJavaをPaizaB問題が解けるぐらいまで
大学の研究でデータをいじるのにPythonをわずかに。

その他の知識一切なし。(HTML/CSS,SPA,API,JavaScriptも触ったことなし)

プログラミングへの抵抗は一切なかったです。

4ヶ月間の勉強内容

学習する言語選び

私の場合は入社する会社に併せて選びました。一通り話を聞いたところrubyやphpはあまり使っておらず、Webアプリ系ならnodeやflaskを使ったアプリなら少人数で動かしているとのことだったのでバックエンドはNode.jsに決めました。

フロントエンドは私がお世話になっている社員さんがReactを使っているとのことだったので当時は何もわからないかったけれどReactを選びました。なのでSPAって何?状態からスタートです。

これは後付けですが、約1ヶ月間ほどはいろんな言語見たりしていました。Ruby,Python,etc..
でも、海外の講座で勉強していると一番熱いのはJavaScriptであるという結論漬けになったのでそこから本格的にJS系で行こうと決めました。

データベースはNode.jsとの組み合わせならMongoDBらしかったのでなんとなく決めました。GraphQLは当初は学ぶ予定はなかったのですが、個人的にすごいいいデータの取り出し方だなと感銘を受けたので、割と最新の技術学んでるからこれも行こう!

と思い切りで学びました。

勉強法

教材としてはProgateとUdemy(どの言語が自分に合っているかも含めて大体5万ほど)だけです。

最初二週間はHTML/CSSをProgateで道場の上級編までクリア
https://prog-8.com/

それからUdemyのサイトを使ってNode.jsの講座40時間分でexpressを使ったバックエンドの構築とRestAPIについて簡単なecサイトを作りながら勉強

この時はReactの中身については学ばず、SPAとNode.jsのやり取りを学んだり、GraphQLについても学びました。

バックエンドが一通り終わった段階で1ヶ月半程度、

その後React単体についての講義を取りました。内容はReact-Redux,Firebaseを使った簡単なWebアプリを作りな
がらReactについて学ぶものでした。

これに加えてReact-ReduxをHooksを使った書き換えまで学びました。

これで二か月半くらいです。

これでReactとNode.js単体の動きについては一通り学んだのでMERNスタックの講座を取って勉強。今までの知識の組み合わせだったのでここまでくると足りない部分を補うみたいな感じでした。

他にもReact+FirebaseやMERN+GraphQLの講座を全部で5~6こなして一通りのパターンを学びました。
実際一つ二つやれば十分にWebアプリは作れると思います。

作成したアプリ(Manehabi)の概要

作った目的

勉強するって決めた時からTwitter頑張ってたんですが,積み上げしてる人がたくさんいるなーって思っていました。でもそれは1日分しか見えないので積み重ねなんだから可視化出来る習慣アプリならこの問題を解決できそうって思いました。

また新しい視点として習慣ってみんなに認知、共有した方が続きそうだなってことで共有することも新しさとして取り入れました。

それが通称Manehabi

Management Habitを略してManehabiです

習慣管理アプリになります。

https://manehabi.herokuapp.com/

メイン機能は習慣の共有、積み上げの可視化(グラフ)この二つになります。

残りはあったら便利だなと思うものを補助的に付け加えていってます。

できること一覧

会員登録&ログイン

基本中の基本ですが、会員登録とログイン機能。かなり苦労しましたがTwitterログインもつけました。
Googleログインも同じ要領でつけられるとは思います。
同一メールアドレスや、エラーはきちんとバックで処理して表示されるようになっています。

習慣登録(単位は複数個の指定が可能)
それぞれの単位について積み上げることが出来ます。例えばブログだったら時間と文字数など。

習慣の更新、削除、日数リセット
習慣の削除はもちろん更新、毎日更新や更新が出来なかった場合にはリセットボタンが備わっており合計時間はそのままに、挫折回数をカウント+1増やします。

全て可視化により挫折回数ですら積み上げ出来るようになっています。


コメント登録&閲覧と並び替え
その日やった内容の簡単な記録をまとめることが出来ます。また他人から応援コメントをもらうこともできます。
コメントは自分だけか他人だけなどでソートできるので見やすくなるようにしています。

お気に入り登録
気に入ったユーザーの習慣をお気に入りとして登録することでいつでも閲覧することが出来ます。
全員の習慣一覧&検索機能
作った日付、お気に入りの数、挫折した回数、更新日、継続日数、タイトルと説明の内容で検索をかけられるようになっています。
似たような習慣の人を探してもいいですし、新しい習慣を探すこともできます。
詳細一覧とグラフ機能
習慣を始めた日や、登録した日、挫折回数などすべての記録が閲覧できるようになっています。
また、これまでの積み上げ分とその日の積み上げも表示できるようになっています。
7日間14日間28日間で今のところ表示の切り替えが出来ます。

プロフィール欄
簡単な一言と説明。ユーザー名とメールアドレスの変更が出来ます。

モバイル対応

今回は携帯からでも手軽に出来るようにモバイルも
初期動作では右上のハンバーガーメニューによる実装でしたが、前々から遠いと思っていたのでしたに固定しています。


ザックリとはこんな感じになります。興味持った人は登録して一つでも習慣作ってくれると作者が喜びます。
https://manehabi.herokuapp.com/

アプリの言語選択

私が4ヶ月で学んだスキルだと以下のパターンが考えられました。

React+Firebase,

MERNスタック

MERNスタック+GraphQL

正直どれでも良かったのですが一番ポートフォリオとして苦労するものを選択しました。

それも理由なのですが、個人的にはGraphQLがすごいスマートだったので使ってみたいということもあって入れました。

Firebaseは確かに魅力的ですがポートフォリオってところでブラックボックスすぎてしまったので止めました。

簡単にアプリ作るならFirebaseはめちゃくちゃいい選択肢だと思います。

開発環境

フロントエンド

React.js+React Hooks

バックエンド

Node.js

データーベース

MongoDB

GraphQL(データーの取り出しに利用)

エンドポイント

/graphql

全てのデータ作成、取り出しはここのみです。

/auth/twitter

ツイッターログイン(

/signin

ログイン

/signup

会員登録

/signout

ログアウト

/habits

全習慣

/habit/:id

各習慣の詳細

/user/:id

各ユーザーの詳細

/favorites

お気に入り一覧

/newhabit

習慣作成

/profile

プロフ編集画面

デプロイ

Heroku

開発手順(最初のデプロイまで2週間+現在までの機能追加+1週間)

主にフロントはReact Hooksを使用しています。Reduxでも全然同じ内容で作れると思います。
むしろ後になってからReduxに変えようかと悩んでます。(中途半端にHooks学んだせい)

最初二週間ではお気に入りの表示とプロフィール画面とコメント作成はまだできませんでした。

トップページ作り

Manehabi訪問ユーザーが最初に訪れるページ簡単な紹介ページを作りました。

各画面への遷移ルート作成

全習慣表示、会員登録、ログイン、自分の習慣表示

計4ページのルートを作成

ユーザー認証

フロントで会員登録画面作成後にMongoDBでユーザーモデルの作成

基本的にデータのやり取りはGraphqlを使っているので/graphqlと呼ばれる単一のAPIにデータをポストする形になります。

フレームワーク的なものにMongoはMongoose GraphQLはApolloを使っています。

認証方式はJWT、パスワードはハッシュ化して保存してあります。

同様にログインも設計。

贈られてきたEメールとPWをハッシュ化したものと比較してJWTTokenを返却します。

習慣作成

ミス一つ目

もともとの習慣のモデル設計は習慣の単位には時間+何かを予定していました。

ところが後になってそもそも習慣の単位は任意個数登録のほうがいいなってなってしまった大幅変更を余儀なくされました。

この部分は課題でお話しします。

とりあえずユーザー登録と同じように必要事項のフォーム作成⇒graphQLのクエリ作成⇒control部分の作成の手順で行いました。

習慣の表示(全部or自分のみ)

GraphQLでクエリ作成⇒controlでデータベースからすべての習慣orその習慣を作った作成者のIdでフェッチしてフロントで表示

少し苦労した点はページ遷移がクリックではなくて無限ローダーのような形になっているのでたくさんあった場合は

よくいろんなサイトで見かけるような形になるように工夫しました!

習慣のお気に入り登録

私のお気に入りポイントでもあります。やることはラベルをクリックしたらお気に入りに追加されるだけです笑

ただUIが見栄えよくてお気に入りポイントになってます。

実装方法はクリック時にクエリーを送信して、データベースのユーザーのお気に入り配列からIDを出し入れするだけです。

習慣の更新と削除、継続日数リセット

MongoDBには普通のmySQLに設定できるDelete on cascadeがなかったので実装にちょっと苦労しました。

削除時にはユーザーにお気に入り登録されている場合はそこから削除と、ユーザーの習慣からも削除されるように設定してあります。

更新は1日1回のみ出来るように設定してあります。(ゆくゆくは変更できるようにするつもりです)

作成方法は同様に

フロントで各ボタンを実装⇒モーダル形式で表示。

GraphQLでクエリーを送信してそれに対応する処理をcontrollerで書くってのをひたすら繰り返していました。

習慣のグラフ表示

難しかったです

グラフにはhighcharts-react-officialというものを使っています。

表示方法はその日までの合計+今日の分という形をとっているのですが、

データベースにはユーザーが登録した日付のデータしかないので間3日分とかしかないと4日分を補完して表示するという形になります。

なのでまずはデータベースから指定された日付よりも大きいものを全て取得⇒フロント側でデータを埋め合わせてから表示。

という形にしました。一番難しいアルゴリズムだった気がします。

こういう時って全部バックで処理してフロントに持ってきた方がいいんですかね?

その辺の実装がまだあいまいでこれから勉強しなければいけません。

ちなみに詳しい解説はブログで話してます
https://kaleido01.com/how-to-solve-logic/

ローダーの作成

各部分で読み込みが発生するのでユーザーに知らせるためにサイトからcss引っ張ってきたりReactのパッケージ使ったり

色んなもの試してます。

デプロイ(Heroku)

ここも一苦労しました。

まず、gitの管理で最初小文字のファイルで保存してたみたいでいろいろ設定を変えないと小文字ファイルのみの変更は反映されず差分を反映できませんでした。

あとはapollo-serverの設定がexpressの設定とうまくかみ合っておらず、開発環境では何も問題なく動いていたのに

本番環境で動かなくなりました。

結果的にはドキュメントと記事を漁ってうまく組み込めるようになりました。

ここまでで2週間です。

お気に入りの表示

まだお気に入り登録しただけで表示ページがなかったので作成。

容量は習慣の表示と全く同じです。

コメント登録と表示

一言コメントの実装。ここら辺までくると大体の機能が同じことの繰り返しに見えてくるのでいかにスマートに実装できるか考え始めるようになってきました。

一点、気を付けたのは習慣の削除時に紐づいているコメントを全て消すことを忘れないようにしました。

習慣を時間ともう一つのモデルから任意の個数へのモデルの変更

今回はまだ使っている人もほとんどいなかったので手動でデータ移したんですけど、既に大規模で稼働しているような場合、

どのような処理を挟んでいるのか、対応しているのかものすごい気になりました。

どなたかご教授頂けると助かります。

そして学んだことは新しい機能を追加するより既存の機能を修正する方が大変ってことですね。

何処でそのクエリー使ってたっけとかここデータの取り出し方違くなるとか

もともとの変更をいじらなくてはならなかったのでかなり大変でした。

Server側のvalidation

フロント側だけだといくらでもいじくれてしまうと講座で勉強したので、こちら側をメインで実装しています。

graphQLのエラー設定に一苦労しましたが、サーバー側で正しくないデータを送られてきたらそれをカスタムエラーとして自分でエラー作成。フロント側に送って表示という形をとっています。

例えばユーザー認証でのvaidation,

コメントやお気に入り登録時にログインしていないとエラーが発生するようにしています。

またvaridationで結構controller圧迫するので別フォルダに移して軽くしています。

Twitter ログインの実装

~~Node.jsの有名なパッケージpassportを使っての実装を試みましたが、

開発環境では無事に実装成功したのですが

本番環境でなぜか動きません、丸三日考えても調べてもどうにも動かず現在未完成の機能になっています。

私なりの考えとしては開発環境ではフロントとバックでURLの遷移が異なるので正しく反応しているが

本番環境だと同じURLなのでうまく反応していないとかなんですかね。

ただ、MongoDB onlyで実装したときも同じようにエンドポイントを設定してやっているはずなのでそんなことは

ないはずなのですが....

まずgraphQLと組み合わせているものが見つからなかったので今手詰まりになっています。

現在もいろいろな手法試していますが、ご教授頂けたら幸いです。~~

【2019/06/29】追記

解決しました。原因はReact側にServiceWorkerというオフラインでもアプリが動くようにしておくものがあるのですがそいつがずっと/auth/twitterへのPOSTを強奪していました。

unregister()で起動しないようにして解決しました。これによってスクロールバーがうまく機能しない問題も解決。

今後の予定

Twitterでのログイン機能頑張って実装します。実装済み

習慣の詳細画面からユーザーページへ飛べるようにします。(現状はボタンだけ)実装済み

モバイル表示のハンバーガーを消してフッターですぐにタッチできるように改良しようと思っています。実装済み

全体を通しての感想とこれからについて

まずは初めてのWebアプリを作成できたことに感謝です。ツイッターで報告したところ大きな反響を頂けたので
もっと技術者の集まるQiitaで報告して技術者目線からのアドバイス頂けたらいいなと思っています。どんなコメントでも受け止めますので思ったこと一言書いてくれたら喜びます。

また、最初はしどろもどろになりながら実装していましたがあるラインを超えるとどれも同じCRUD構成+少しのアルゴリズムだと思えるようになりました。
終盤はいかにスマートに後でいじれるような実装にするにはどうしたらいいか少し考えられるようになりました。

来年就職してしまうのですが、夏までにはどこかのインターンのような形で就職まで実務経験したいなと思っています。

あともう一つ頭に思い描いているのは初学者が作ったポートフォリオまとめるサイトとかいいなって思ってます。

そういうサイト探してもなかったので気軽に登録して初学者の人に全体像や何かイメージを浮かべてもらってそこから

プログラミング始めてもらったらもっとスムーズに学習がうまくいくかなと。

最後になりますがここまで読んでくださりありがとうございました!

PS.使った講座知りたい方はこちらから解説しています。
マネハビから学んだ初心者向けのことも書いてあります

https://kaleido01.com/manehabi-part3/