tag:crieit.net,2005:https://crieit.net/tags/%E9%81%8B%E7%94%A8/feed
「運用」の記事 - Crieit
Crieitでタグ「運用」に投稿された最近の記事
2019-10-26T09:06:51+09:00
https://crieit.net/tags/%E9%81%8B%E7%94%A8/feed
tag:crieit.net,2005:PublicArticle/15506
2019-10-26T09:06:51+09:00
2019-10-26T09:06:51+09:00
https://crieit.net/posts/Nuxt-js-SPA-Firebase-Web-5db38e1b32bf6
Nuxt.js(SPA)+FirebaseのWebアプリで初マイグレーションをしてけど、いろいろ失敗した話。。
<p>これはただの失敗談です。。役に立つかわからないけど、誰かの参考になるといいな。。</p>
<p>Nuxt.js+Firebaseで開発した<a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">Webサービス</a>をリリースして2ヶ月目くらい。<br />
サービス止めて、初マイグレーションしてときの失敗談です。</p>
<h2 id="サービスを止めてやりたかったこと"><a href="#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E6%AD%A2%E3%82%81%E3%81%A6%E3%82%84%E3%82%8A%E3%81%9F%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8">サービスを止めてやりたかったこと</a></h2>
<p>いままではちょこっとした変更が多かったため、<br />
サービスを止める必要なく、Nuxtアプリの更新だけで十分でしたが、<br />
新しい機能を追加する際に、Firestoreのスキーマを変える必要が出てきました。</p>
<p>やりたいことは、<br />
「 <strong>今までのデータを読み取って、別の形式に再構成する</strong> 」<br />
という感じのことで、止めないとダメかなと。</p>
<h2 id="メンテンナンスのときの手順"><a href="#%E3%83%A1%E3%83%B3%E3%83%86%E3%83%B3%E3%83%8A%E3%83%B3%E3%82%B9%E3%81%AE%E3%81%A8%E3%81%8D%E3%81%AE%E6%89%8B%E9%A0%86">メンテンナンスのときの手順</a></h2>
<p>手順はこんな感じ。</p>
<ol>
<li>メンテナンス画面に遷移するようにmiddlewareを変更</li>
<li>firestoreのルールを全部ブロックするように変更</li>
<li>スキーマ変更処理を実行</li>
<li>メンテナンス画面を解除し、hostingに最新版をアップロード</li>
<li>firestoreのルールをもとに戻す</li>
</ol>
<p>ポイントとしては、</p>
<ul>
<li>ページを移動したら、<strong>middlewareでメンテナンス画面に遷移</strong>する</li>
<li>クライアントから変更されないように、<strong>全部ブロックするルールに変更</strong>する</li>
</ul>
<p>の2点くらい。</p>
<p>結果、かなりの失敗をしました。。</p>
<h1 id="やらかした失敗と反省点"><a href="#%E3%82%84%E3%82%89%E3%81%8B%E3%81%97%E3%81%9F%E5%A4%B1%E6%95%97%E3%81%A8%E5%8F%8D%E7%9C%81%E7%82%B9">やらかした失敗と反省点</a></h1>
<p>ダメだったのは以下の2点。</p>
<ol>
<li><strong>時間がかかりすぎ</strong>(予想5h以内→実際11h)</li>
<li><strong>メンテナンス画面がちゃんと出ていなかった</strong></li>
</ol>
<h2 id="1. 時間がかかりすぎ問題"><a href="#1.+%E6%99%82%E9%96%93%E3%81%8C%E3%81%8B%E3%81%8B%E3%82%8A%E3%81%99%E3%81%8E%E5%95%8F%E9%A1%8C">1. 時間がかかりすぎ問題</a></h2>
<p>一番の失敗は時間かかりすぎです。。<br />
予想以上に時間が。。予想5h以内→実際11h</p>
<p>対象のスキーマが、</p>
<pre><code>本 - 履歴 - ユーザ
</code></pre>
<p>多対多の関係を持つ構造を持っていて、<br />
本を起点に履歴データの構造を変更するような処理だった。</p>
<p>規模としては、本の件数が47670ドキュメントで、履歴が58144ドキュメント。</p>
<p>実際に実行してみたところ、速度が上がったり下がったりで、<br />
1時間に5000冊位な感じ。。これだけで10時間近く。。</p>
<h3 id="振り返ってみて"><a href="#%E6%8C%AF%E3%82%8A%E8%BF%94%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%A6">振り返ってみて</a></h3>
<p>やってみていくつか良くない感じだったなと。。<br />
振り返ってみて、改善できそうなのは以下の2点な感じ。。</p>
<h4 id="a. メンテナンスでは差分部分のみ反映する"><a href="#a.+%E3%83%A1%E3%83%B3%E3%83%86%E3%83%8A%E3%83%B3%E3%82%B9%E3%81%A7%E3%81%AF%E5%B7%AE%E5%88%86%E9%83%A8%E5%88%86%E3%81%AE%E3%81%BF%E5%8F%8D%E6%98%A0%E3%81%99%E3%82%8B">a. メンテナンスでは差分部分のみ反映する</a></h4>
<p>全量を読み込んで、反映していたので、かなりの時間が。。</p>
<p>とはいえ、1日の変更であれば、そこまで多くないので、<br />
<strong>事前に全量の変更を用意して</strong>おき、メンテナンスにしてから、<br />
<strong>差分があるところだけを更新</strong>をするなどのほうが良かった気がしてる。。</p>
<p>次はそうしよう。。</p>
<h4 id="b. 処理の並列実行"><a href="#b.+%E5%87%A6%E7%90%86%E3%81%AE%E4%B8%A6%E5%88%97%E5%AE%9F%E8%A1%8C">b. 処理の並列実行</a></h4>
<p>内部の処理も<code>Promise.all</code>を使ってない部分がいくつか。。</p>
<p><code>foreach</code>で実行している部分を置き換えて、<br />
<strong>並列実行にするだけでも改善されそうな感じ</strong>。。</p>
<p>この記事がわかりやすい感じだった。<br />
- <a target="_blank" rel="nofollow noopener" href="https://qiita.com/euxn23/items/b9bd8bf28fe3ca707fe3#%E4%B8%A6%E5%88%97%E3%81%A8%E7%9B%B4%E5%88%97%E3%81%AE%E4%BD%BF%E3%81%84%E5%88%86%E3%81%91%E3%81%A8%E6%B3%A8%E6%84%8F%E7%82%B9">Node.js で Promise の直列実行と並列実行、同時実行数の制御 - Qiita</a></p>
<h3 id="2. メンテナンス画面が出てない"><a href="#2.+%E3%83%A1%E3%83%B3%E3%83%86%E3%83%8A%E3%83%B3%E3%82%B9%E7%94%BB%E9%9D%A2%E3%81%8C%E5%87%BA%E3%81%A6%E3%81%AA%E3%81%84">2. メンテナンス画面が出てない</a></h3>
<p>メンテナンスをはじめてから、GoogleAnalyticsを見てると、リアルタイムユーザがちらほら。<br />
終わってからも、メンテナンス画面じゃないとの報告もちらほら。。</p>
<p>Firebase Hostingにアップロードしてもキャッシュが残っているとだめだったもよう。。</p>
<h3 id="振り返ってみて"><a href="#%E6%8C%AF%E3%82%8A%E8%BF%94%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%A6">振り返ってみて</a></h3>
<p>振り返ってみて、改善できそうなのは以下の2点な感じ。。</p>
<h4 id="a. PWAモジュールを使ってnetworkファーストで取得する"><a href="#a.+PWA%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6network%E3%83%95%E3%82%A1%E3%83%BC%E3%82%B9%E3%83%88%E3%81%A7%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B">a. PWAモジュールを使ってnetworkファーストで取得する</a></h4>
<p>以下の記事の前半で書かれている通り、<strong>キャッシュ戦略を設定することで解決</strong>できそう。<br />
・<a target="_blank" rel="nofollow noopener" href="https://qiita.com/hecateball/items/29f726430d204c964f04">Nuxt.js(SPA)とFirebaseで強制リビジョン(バージョン)アップするならPWAモジュールを使おう - Qiita</a></p>
<h4 id="b. Remote Configを使って切り替える"><a href="#b.+Remote+Config%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E5%88%87%E3%82%8A%E6%9B%BF%E3%81%88%E3%82%8B">b. Remote Configを使って切り替える</a></h4>
<p>同じく上記の記事で書かれている通り、<strong>Remote Configを使う</strong>のが良さそう。<br />
・<a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/remote-config">Firebase Remote Config | Firebase</a></p>
<p><strong>Remote Configの値によって、メンテナンス画面の表示を切り替えれるようにしておけば</strong>、<br />
Firebaseのコンソール上での変更で、切り替えれるようにできる感じ。</p>
<h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2>
<p>やってみてわかることも多いですが、なかなかつらい感じ。。</p>
<p>Firebase/Firestore関連の運用系の話はあまり見ないので、<br />
とりあえず書いてみましたが、誰かの役に立てば。。</p>
<p>こんな方法もあるよ!こっちのほうがいいよ!などあれば、<br />
コメントもらえるとうれしいです(<em>´ω`</em>)</p>
<h2 id="ほかの失敗談"><a href="#%E3%81%BB%E3%81%8B%E3%81%AE%E5%A4%B1%E6%95%97%E8%AB%87">ほかの失敗談</a></h2>
<p>以前にもこんなのを書きました。<br />
初級向けの話が多いですが、実際にやってみての体験談的な話。<br />
- <a target="_blank" rel="nofollow noopener" href="https://qiita.com/kira_puka/items/8c1d1240c3aa200cbec0">Nuxt.js(SPA)+Firebaseで積読用の読書管理サービスを作ってみたときにハマったこと... - Qiita</a><br />
- <a target="_blank" rel="nofollow noopener" href="https://qiita.com/kira_puka/items/ef7dd47519403cd9bcf2">Firebaseで作ったWebサービスを3ヶ月運用してみて、ハマったこと・知っておきたかったこと - Qiita</a></p>
<h2 id="こんなのつくってます!!"><a href="#%E3%81%93%E3%82%93%E3%81%AA%E3%81%AE%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BE%E3%81%99%21%21">こんなのつくってます!!</a></h2>
<p>やらかしたWebサービスはこちら。。<br />
積読用の読書管理アプリ 『積読ハウマッチ』<br />
<a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">積読ハウマッチ</a>は、Nuxt.js+Firebaseで開発してます!</p>
<p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/572d4947-f40b-e4dc-1c9c-bc584cd2a66c.png" width="200"/></p>
<p>もしよかったら、遊んでみてください〜</p>
<p>要望・感想・アドバイスなどあれば、<br />
公式アカウント(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/MemoryLoverz">@MemoryLoverz</a>)や開発者(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/kira_puka">@kira_puka</a>)まで♪</p>
きらぷか@積読ハウマッチ/SSSAPIなど
tag:crieit.net,2005:PublicArticle/15426
2019-09-26T19:11:16+09:00
2019-09-26T20:05:46+09:00
https://crieit.net/posts/firebase-admin
複数のプロジェクトのfirebase-adminを起動して、開発用に本番データの一部を移行する
<p>開発している<a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">Webサービス</a>で、本番データの一部を開発用に使いたいと思ったときの備忘録。<br />
firebase-adminは複数のプロジェクトで使えるらしい。</p>
<p>開発用だけじゃなく、UIDを変更しながらのデータ移行などにも使えそう。</p>
<h2 id="ローカル環境でfirebase-adminを使うための準備"><a href="#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E7%92%B0%E5%A2%83%E3%81%A7firebase-admin%E3%82%92%E4%BD%BF%E3%81%86%E3%81%9F%E3%82%81%E3%81%AE%E6%BA%96%E5%82%99">ローカル環境でfirebase-adminを使うための準備</a></h2>
<p>準備の部分は、以前まとめたこちらを参照ください〜<br />
- <a target="_blank" rel="nofollow noopener" href="https://www.memory-lovers.blog/entry/2019/07/25/073000">ローカルPCからfirebase-adminを使ってFirestoreを操作する(管理ツール) - くらげになりたい。</a></p>
<h3 id="ソースはこんな感じ。"><a href="#%E3%82%BD%E3%83%BC%E3%82%B9%E3%81%AF%E3%81%93%E3%82%93%E3%81%AA%E6%84%9F%E3%81%98%E3%80%82">ソースはこんな感じ。</a></h3>
<pre><code class="javascript">const admin = require("firebase-admin");
// *** 移行元のプロジェクトの設定
const srcSA = require("./key/XXXXX.json"); // サービスアカウントの秘密鍵を取得
// firebase-adminの初期化
admin.initializeApp({ credential: admin.credential.cert(srcSA) });
const srcDB = admin.firestore(); // firestoreのインスタンスを取得
// ** 移行先のプロジェクトの設定
const destSA = require("./key/XXXXX.json"); // サービスアカウントの秘密鍵を取得
// ※同じadminを使って、別のAppを作成しないといけない※
// ※2つ目を初期化する場合は、"dest"など名前をつけないといけない※
const destAdmin = admin.initializeApp( { credential: admin.credential.cert(destSA) }, "dest");
const destDB = destAdmin.firestore(); // firestoreのインスタンスを取得
// ****************************
// * MAIN
// ****************************
async function main() {
console.log(`***** START MAIN`);
// 移行元からデータを取得
const snaps = await srcDB.collection("data").get()
const srcData = snaps.docs;
for (let v of data) {
try {
// 移行先からデータを保存
const destDataRef = destDB.collection("data").doc(v.id);
await destDataRef.set(v.data());
} catch (error) {
console.errror(`Error: ${error}`, error);
}
}
console.log(`***** END MAIN`);
process.exit(0);
}
main().then();
</code></pre>
<p>雛形はこんな感じ。</p>
<p>以前書いた以下の記事だと丸々移行するので、UIDが変わるとめんどくさいことになる。。</p>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/kira_puka/items/ef80b07347cfdd37f116">Firestoreのデータをgcloudを使ってバックアップ&別のプロジェクトへインポートしてみる - Qiita</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/kira_puka/items/98283e837f30209f23c8">Firestoreのデータを分析するための3つの方法とその注意点 - Qiita</a></li>
</ul>
<p>この方法であれば、</p>
<ul>
<li>whereで一部のだけに絞り込んだり、</li>
<li><code>set()</code>するときに、UIDを差し替えたり</li>
</ul>
<p>できるので、開発用に使うにはよいかんじ。</p>
<h5 id="注意1: 2つ目を初期化する場合は別の名前に"><a href="#%E6%B3%A8%E6%84%8F1%3A+2%E3%81%A4%E7%9B%AE%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AF%E5%88%A5%E3%81%AE%E5%90%8D%E5%89%8D%E3%81%AB">注意1: 2つ目を初期化する場合は別の名前に</a></h5>
<p>そのまんまコピペで2つのfirebase-adminを作るとエラーに。。<br />
2つ目を初期化する場合は、"dest"など名前をつけないといけないいけないらしい。。</p>
<p>公式ドキュメントの「<a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/admin/setup#initialize_multiple_apps">複数のアプリを初期化する</a>」に書いてあった。</p>
<p>これで、2つのfirebase-adminが起動できるので、データ移行などもできそう(<em>´ω`</em>)</p>
<h5 id="注意2: メモリを大量に使いそうな場合はオプションを指定"><a href="#%E6%B3%A8%E6%84%8F2%3A+%E3%83%A1%E3%83%A2%E3%83%AA%E3%82%92%E5%A4%A7%E9%87%8F%E3%81%AB%E4%BD%BF%E3%81%84%E3%81%9D%E3%81%86%E3%81%AA%E5%A0%B4%E5%90%88%E3%81%AF%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E6%8C%87%E5%AE%9A">注意2: メモリを大量に使いそうな場合はオプションを指定</a></h5>
<p>データが多く、メモリを大量に使いそうな場合は、<br />
<code>--max_old_space_size</code>オプションを指定しないといけない。。</p>
<p>途中で失敗すると(読み込み/書き込み件数的に)悲しいことになるので、<br />
大きめのサイズを指定しておくと良さそう。</p>
<pre><code class="console">node --max_old_space_size=8192 index.js
</code></pre>
<h5 id="注意3: 件数が多い場合は、limitを指定して再帰処理"><a href="#%E6%B3%A8%E6%84%8F3%3A+%E4%BB%B6%E6%95%B0%E3%81%8C%E5%A4%9A%E3%81%84%E5%A0%B4%E5%90%88%E3%81%AF%E3%80%81limit%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%A6%E5%86%8D%E5%B8%B0%E5%87%A6%E7%90%86">注意3: 件数が多い場合は、limitを指定して再帰処理</a></h5>
<p>大量のデータを一度に取得しようとすると、</p>
<blockquote>
<p>Deadline Exceeded error</p>
</blockquote>
<p>が出て怒られるので、少しずつ実行するのがよいかんじ。</p>
<pre><code class="javascript">const BATCH_SIZE = 300
async function moveData(lastItem) {
// 移行元からデータを取得
const colRef = srcDB.collection("data");
let query = colRef.orderBy("createAt", "asc");
if (lastItem != null) query = query.startAfter(lastItem.createAt);
const snap = await query.limit(BATCH_SIZE).get();
if (snap.docs.length === 0) return; // 0件なら終了する
const srcData = snaps.docs;
for (let v of data) {
try {
// 移行先からデータを保存
const destDataRef = destDB.collection("data").doc(v.id);
await destDataRef.set(v.data());
} catch (error) {
console.errror(`Error: ${error}`, error);
}
}
// 最後の要素を渡して、そこから継続する
await moveData(data[data.length - 1]);
}
// ****************************
// * MAIN
// ****************************
async function main() {
console.log(`***** START MAIN`);
await moveData(null);
console.log(`***** END MAIN`);
process.exit(0);
}
</code></pre>
<h5 id="注意4: 複数の場所に反映する場合は、batchやtransactionを使う"><a href="#%E6%B3%A8%E6%84%8F4%3A+%E8%A4%87%E6%95%B0%E3%81%AE%E5%A0%B4%E6%89%80%E3%81%AB%E5%8F%8D%E6%98%A0%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AF%E3%80%81batch%E3%82%84transaction%E3%82%92%E4%BD%BF%E3%81%86">注意4: 複数の場所に反映する場合は、batchやtransactionを使う</a></h5>
<p>途中でエラーになる場合もあるので、batchやtransactionを使うとよさそう。</p>
<p>公式ドキュメントだと、このあたり<br />
- <a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/firestore/manage-data/transactions">トランザクションと一括書き込み | Firebase</a></p>
<pre><code class="javascript"> for (let v of data) {
try {
const batch = destDB.batch();
// 移行先からデータを保存
const destDataRef = destDB.collection("data").doc(v.id);
batch.set(destDataRef, v.data());
// 移行先からデータを保存: その2
const destData2Ref = destDB.collection("data2").doc(v.id);
batch.set(destData2Ref, v.data());
// コミット
await batch.commit();
} catch (error) {
console.errror(`Error: ${error}`, error);
}
}
</code></pre>
<p>ループ外で使うほうのもいい感じ。</p>
<p>ただ、一括で書き込めるドキュメント数は500までと制限があるので、<br />
一度に書き込む範囲は適宜調整が必要。</p>
<blockquote>
<p>1 回のトランザクションまたは一括書き込みでは、<br />
最大500のドキュメントに書き込みを行うことができます。<br />
<a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/firestore/manage-data/transactions?hl=ja#security_rules_limits">トランザクションと一括書き込み | Firebase</a></p>
</blockquote>
<h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2>
<p>firebase-adminは複数のプロジェクトでも扱える。<br />
部分的なデータ移行や一部を書き換えながらの移行もできる(<em>´ω`</em>)</p>
<p>ただ、件数が多かったり、複数の書き込みがある場合は、いろいろ必要。。</p>
<h2 id="こんなのつくってます!!"><a href="#%E3%81%93%E3%82%93%E3%81%AA%E3%81%AE%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BE%E3%81%99%21%21">こんなのつくってます!!</a></h2>
<p>積読用の読書管理アプリ 『積読ハウマッチ』をリリースしました!<br />
<a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">積読ハウマッチ</a>は、Nuxt.js+Firebaseで開発してます!</p>
<p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/572d4947-f40b-e4dc-1c9c-bc584cd2a66c.png" width="200"/></p>
<p>もしよかったら、遊んでみてくださいヽ(=´▽`=)ノ</p>
<p>要望・感想・アドバイスなどあれば、<br />
公式アカウント(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/MemoryLoverz">@MemoryLoverz</a>)や開発者(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/kira_puka">@kira_puka</a>)まで♪</p>
きらぷか@積読ハウマッチ/SSSAPIなど
tag:crieit.net,2005:PublicArticle/14621
2018-12-03T08:00:40+09:00
2018-12-05T04:43:56+09:00
https://crieit.net/posts/Crieit-5c046418731fe
Crieitの普段の運用方法について色々
<p>個人開発のWebサービスの技術紹介となると「こういうふうに作りました!」というのが多くQiitaのAdvent Calendarも含めると色々かぶる気がするため、運用周りについての色々を書いてみることにしました。(実際に作った系は自分が今まで書いた記事にもう既に書いてしまっているものも多く、そもそもそことほとんどかぶってしまうと思いますし)</p>
<h2 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h2>
<p><a href="https://crieit.net/advent-calendars/2018/technology">個人開発サービスに用いられている技術 Advent Calendar 2018</a> の3日目です。昨日は <a target="_blank" rel="nofollow noopener" href="https://twitter.com/morix1500">@morix1500</a> さんの <a href="https://crieit.net/posts/Nyaaan">Nyaaanを支える技術</a> でした。</p>
<h2 id="ローカルでの開発"><a href="#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%A7%E3%81%AE%E9%96%8B%E7%99%BA">ローカルでの開発</a></h2>
<p>docker-composeを使っているのでとりあえずコンテナを起動し、ローカルのURLで開発を行います。<a href="#docker-compose">1</a></p>
<p>フロント側も開発する場合、Node関連は全部WSLに入れているのでとりあえず<code>wsl</code>を実行してあとはLaravel標準で入っているコマンドの<code>yarn run hot</code>によるホットリローディング状態で開発していきます。</p>
<h2 id="フロント側のビルド"><a href="#%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88%E5%81%B4%E3%81%AE%E3%83%93%E3%83%AB%E3%83%89">フロント側のビルド</a></h2>
<p>フロント側で何かしらを対応した時は、ビルドしておく必要があります。ビルドするとmix-manifest.json、js、cssファイルが更新されます。</p>
<p>Crieitの場合は現在これらをcommitしています。こうすることで本番ではpullするだけで全て完了しますし、なにか本番で問題が見つかった場合はpullする前の状態に戻せばすぐ復旧できます(バージョニングをしているため)。業務などでCIでデプロイまでしっかり作るのであればそれでいいと思いますが、個人開発であればこれがフットワークが軽くて一番良いと思います。</p>
<h2 id="デプロイ"><a href="#%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4">デプロイ</a></h2>
<p>開発した内容をサーバーにデプロイする場合はssh接続します。今使っているのはGoogle Compute Engineなのですが、gcloudというシェルで色々操作することができます(予めインストールしてシェル上にログインする形です)</p>
<p>ログインのコマンドはGCPのコンソールのGCEインスタンス一覧のところでコピーしてこれるので、何も考えなくても簡単にログインできます。コマンドは下記のような感じです。</p>
<pre><code class="shell">gcloud compute --project "プロジェクトID" ssh --zone "ゾーン" "インスタンス名"
</code></pre>
<p>あとは普通にユーザーを切り替えてフォルダ移動して<code>git pull</code>や必要であればマイグレーションを実行するだけです。</p>
<h2 id="CI"><a href="#CI">CI</a></h2>
<p>デプロイは前述の通り手動ですが、テストだけCIしています。Werckerという無料のものを使っていて、リポジトリはBitBucketを使っているのですが簡単に連携ができます。</p>
<p>とはいえ、個人開発ですしあまりテストにまでガッツリ時間を書けている余裕はないため、基本的には他のアプリケーションを作る時も含め、テストはほとんど書きません。一応CI成功して嬉しい~というところまでは味わいたいので最小限だけ書いており、例えばCrieitでは下記を書いています。</p>
<ul>
<li>トップページのレスポンスが200か</li>
<li>記事詳細ページのレスポンスが200か</li>
<li>匿名コメントでユーザーの名前が表示されてしまったりしないか、というプライバシー面</li>
</ul>
<p>等。それ以外は、今後何かしら修正や機能拡張が必要だった時に、</p>
<ol>
<li>修正前に正常系のテストを書く</li>
<li>開発</li>
<li>開発完了したらテストがちゃんと動くか確認及び調整</li>
</ol>
<p>という感じでテストを増やしていけばいいと思っています。</p>
<p>デプロイもすれば良いのですが、設定するのが面倒なのでやっていないだけだったりします。</p>
<h2 id="データの閲覧や操作"><a href="#%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E9%96%B2%E8%A6%A7%E3%82%84%E6%93%8D%E4%BD%9C">データの閲覧や操作</a></h2>
<p>データはMySQLで、元々は本番に適当にphpMyAdminを入れていました。むちゃくちゃ長いフォルダ名にしていたので問題はないと思うのですが、仕事でも何度かいつの間にか非公開URLがGoogleにインデックスされる現象を見てきたので一応今は削除してあります。</p>
<p>前述のsshとほぼ同じ方法でポートフォワーディングができるので、手動でそれを実行してPC上のクライアントで見ています。(下記を実行したあと接続)</p>
<pre><code class="shell">gcloud compute --project "プロジェクトID" ssh --zone "ゾーン" "インスタンス名" -- -L 13306:localhost:3306
</code></pre>
<p>Windowsでよく使われるクライアントといえばWorkbenchだと思うのですが、見た目があまり好きではなくデータのセルも変なふうに見えるのであまり使っていません。(今回は関係ないのですが)sshトンネルができれば何でも良いので、適当に最近流行ってそうなクライアントを使っています。</p>
<p>今はHeidiSQLというやつで、Linux Mintの時はたしかTeamSQLとかだったと思います。</p>
<h2 id="アクセス解析"><a href="#%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E8%A7%A3%E6%9E%90">アクセス解析</a></h2>
<p>深夜0時まで起きてたら前日の参照元を見たりしてます。Search Consoleは更新が1時くらいで大体起きてないので翌日の朝に最新の日の流入キーワードとかを見てます。あまり変わり映えしないので飽きてきましたが。</p>
<p>ヒートマップも一応入れているのですが、サービスの特性上読まれるところが読まれて、クリックされるところがされて、という感じでたいして驚きのある結果にはならないのであまり見ていません。</p>
<h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2>
<p>個人開発なので超適当です!</p>
<p>時間もないですし適当に手を抜けるところはガンガン抜いてサービスの改善に努めましょう!!!</p>
<p>明日は <a target="_blank" rel="nofollow noopener" href="https://twitter.com/kame_f_no7">@kame_f_no7</a> さんです!</p>
<h2 id="注釈"><a href="#%E6%B3%A8%E9%87%88">注釈</a></h2>
<p><span id="docker-compose">1</span>: 以前こちらに書いています。 <a target="_blank" rel="nofollow noopener" href="https://qiita.com/dala00/items/963a8f65a7730ede8f3b#docker">Qiitaの様なサービス作成中 ローカル環境構築 連載(1)</a></p>
だら@Crieit開発者