2021/11/30ごろに、みんなの共感を集めるアプリ「SORENA」をβリリースしました。
SESでのお仕事をしながらアプリのβリリースまで行うことができました。
この記事では『SORENA』のサービス内容や使い方、技術とのご紹介をさせていただきます。
また、βリリースにあたってフィードバックも頂いたので、これからのアプリの課題も書こうと思います。
目次
サービスの紹介
-何をするアプリなのか?
-メインページ
-結果画面
技術の紹介
-フロントエンド
-バックエンド
-ホストサービス
-使用データベース
-テーブル設計
-主な使用技術
悩んだポイント
-カードスワイプ
-node.jsのノンブロッキング処理
-MySQLの自動的切断問題
アプリの課題、将来的な実装
-なぜ、βの状態でリリースしたのか?
-これからのアプリの課題(フロント)
-これからのアプリの課題(サーバー)
サービスの紹介
何をするアプリなのか?
サイトURL:https://sorena-aruaru.com/
実際に「これあるよねー」という事柄を「あるある」「ないない」を答えてもらい、その結果を収集するアプリです。
今はエンジニアのみですが、後々デザイナー等のカテゴリを増やしていく予定です。
メインページ
カードに書かれている事柄に対して共感するならば右へスワイプ、しないならば左へスワイプというように直感的に「YES」「NO」を判断できるようなUIとなっています。
結果画面
メインページで判断した結果を最後に表示しています。
また、一番右には「今までどのくらい共感されたのか?」という共感された数をパーセントで表しています。
以下GitHubのコードです。
フロントエンド
バックエンド
技術の紹介
ここからは技術のご紹介をいたします。
フロントエンド
"nuxt": "^2.15.3"
"@nuxtjs/axios": "^5.13.1"
"swing": "^3.1.4"
"vue-swing": "^0.0.10"
"vuex": "^3.6.2"
"@nuxtjs/vuetify": "^1.11.3"
バックエンド
node.js -v v14.18.1
"cors": "^2.8.5"
"cross-env": "^7.0.3"
"dotenv": "^10.0.0"
"express": "^4.17.1"
"mysql2": "^2.3.2"
"nodemon": "^2.0.14"
ホストサービス
Netlify(フロントエンド)
Heroku(バックエンド)
データベース
ClearDB
※Herokuのアドオンとして使用
テーブル設計
status_count
今までの問題IDに紐づいて「はい」「いいえ」の情報を貯めるテーブルです。
こちらはトランザクションテーブルの扱いにしています。
question_table
事柄の問題を貯めておくテーブルです。
今現在はマスターテーブルの扱いにしていますが後述するアップデートでトランザクションテーブルの扱いにする予定です。
将来的には以下のテーブルでスケールアップしていきたいと考えています。
count_logs
status_countを膨大にため込まないためのテーブルです。
1日ごとに集計をして1日単位での結果レコードを生成します。
処理はバッチ処理として起動させます。
categories_table
「エンジニアあるある」や「デザイナーあるある」などのカテゴリ分けを行うテーブルです。category_idとquestion_tableをつなげて問題ごとのカテゴリ分けを行っています。
appled_questions
Twitterから応募された問題をAPIを通してため込むテーブルです。
以下の画像のように、つぶやきから投稿された問題をTwitterAPIを通してタグで判断、カテゴリ分けをしてため込む形になります。
(DBスケール時に実装)
また、クラッシュログなどサービス運用に必要なログも作成していく予定です。
・主な使用技術
Nuxt.jsはnode.js+expressでサーバーAPIを構築しています。
悩んだポイント
カードスワイプ
カードスワイプはvue-swingいうライブラリを使用して実装していきました。
「はい」か「いいえ」を判断する座標、カードを消すなどのイベントを書くときにオブジェクトプロパティが必要なのでconsole.logを使用してオブジェクトの中身を確認しながら実装していきました。
node.jsのノンブロッキングコーディング
node.jsはノンブロッキングを前提としたコーディングが必要です。
node.jsを触られた方は分かると思いますが、手続き型の形で書いていくと、A=>B=>Cという関数の順番に実行させたいのにA=>C=>Bの順番で実行してしまう場合があります。
今現在は非同期で行う処理はありませんが、今後検索機能などを実装していくうえで必要となる処理となるのでPromissなどのノンブロッキングメソッドを意識したコードを書いていく必要があります。
MySQLの自動的切断問題
mysqlは仕様上、接続したまま自動的に接続が切られる仕組みとなっています。
これは、問題内容をリクエストする場合、何らかの原因でレスポンス応答が遅くなった場合、自動的に接続を切断され
レスポンスエラーが起こる恐れがあります。
最初はコネクトエラーが起こった場合再度接続を行うというポーリングを書いていましたが、MySQLの接続プールは持続的に接続されると聞いて以下のようなモジュールを作成しました
const mysql = require("mysql2");
const pool = mysql.createPool({
host: process.env.DB_HOSTNAME,
user: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
});
module.exports = pool;
このモジュールを使用し以下のように問題を呼び出していく処理を書いていきました
const res = require("../app")
const mysql = require("mysql2");
const pool = require("../dbController/pool");
function getData(res){
pool.getConnection(function(err,connection){
pool.query(
"SELECT * FROM question_table;",
(error, results) => {
if (error) {
console.log("error connecting: " + error.stack);
return;
}
//makeQuestionsは問題を抽出する関数
const data = makeQuestions(results);
res.header({'Content-Type': 'application/json'});
connection.release();
return res.json(data);
}
);
})
}
接続プールを使用するとトランザクション処理はできなくなるのですが、その処理をする場合は
接続=>処理=>リリース=>処理
というコードにしていく形になります。
コード、DB等の規則を作成してないリスクを考えてなかった
作成前に命名規則やCSSの構造規則を規定してなかったため、少し作成から離れたら「この変数って何?」という余計な時間を使うことになってしまいました。
また、DB名も「question_table」ではなく「questions_table」などの細かい部分での命名も決めてませんでした。
こちらはチーム開発を経験してないために雑になってしまったことが原因ですね、、、
リーダブルコード読んで出直してきます、、、
アプリの課題、将来的な実装
なぜ、βの状態でリリースしたのか?
メイン機能を動かせる範囲で、
どの部分を改善するべきかの指標を明確化したいので、β版を公開した後はユーザーにアプリを使ってみて実際に感じたことを聞いていきました。
結果、
・ファーストビューで何をするアプリなのかわからない
・スワイプ時にカードをリリースする距離が長くスマホだとやりにくかった
・はい、いいえが表示される画像のレスポンスが遅く、どちらの
などのご意見を頂けました。
気づいたこと、こうしたほうがいいよねというご意見を色々いただけたのでよかったです。
これからのアプリの将来(2022/09//07更新)
Vue.jsからReactに移行しようと考えています。なぜなら
・もし、機能追加などの実装が出てきた場合Vue.jsだと煩雑になりやすい。Reactだと機能ごとにオブジェクトとして切り分けができるので都合がよさそう。
・もし、ほかのエンジニアさんと共同作成をするならば上記理由で分担しやすいと考えたから。
また、サービスの形として、Webアプリよりもスマホアプリとして作成するのが都合が良いとも感じています。
なので、React NativeかFlutterでの作成もしていきたいと考えています。