とにかく早くプロダクトのプロトタイプを作るための技術についてまとめます。
この技術は運用しやすく作る技術とはまた別の技術です。
(綺麗に作るのは後でやる)
かなり偏った考え方もあると思いますがご容赦ください。
プロトタイプを作る上でやらないことを決めます。
実はやることよりもやらないことを決めることの方が難しいです。
UXに基づいて後回しにするという意思決定が必要です。
プロトタイプでやるべきこと
-
コンセプトの決定/チャネルの調査:
なぜ作るのか、誰をターゲットとして作るのか、競合プロダクトの調査 -
コア機能の実装:
ユーザの苦痛を解消させるプロダクトのコア機能の実装をします。
ここで想定しているコア機能とは一画面に収まるアプリケーションのメイン機能の事を指します。
デザインはモックレベルではなく、ユーザが使う想定のデザインテーマ、レイアウト、アフォーダンス、メンタルモデル、UI、アニメーションを考慮する。 -
ターゲットユーザにリーチする仕組み作り:
お金をかけないのであればSNSシェアが手っ取り早いです。(長期的にはSEO、お金をかけるのであれば広告)
プロダクトの性質にもよりますが、定期的にコンテンツを配信する仕組み、プロダクトのアップデートをターゲットユーザに伝える仕組みが必要です。
プロダクトに需要があるとわかっていない場合は上に書いてあること以外はやってはいけません。(時間とお金を浪費するので)
卵が先か鶏が先か問題(囚人のジレンマ問題):
UGC(ユーザ投稿型コンテンツ)はプロダクトに関して初期段階ではコンテンツが集まらない問題があります。集まったとしてもコンテンツのクォリティを担保するのは難しく、最初からやると失敗する場合が多いです。
(ユーザ側としては基本的に投稿する理由がなく、やるとしてもプロダクトがある程度の規模になったタイミングでしょう)
プロダクトとして差別化が難しいものに関して:
すでに競合がいる場合、某Pay同士の争いのように資本力の殴り合いか、ブランド力(知名度・信頼度)がある方が勝つのでやはり厳しいでしょう
プロトタイプでやらないこと(後回しで良いこと)
プロダクトのコア機能に影響しないのであれば後回しにしたほうが良いでしょう。
-
データの長期保存(本格的なDBの導入):
プロトタイプには不要です。せいぜいJSONデータを端末の保存領域に直接保存したりする程度十分です。
(検索がコア機能でなければ) -
認証:
コア機能でデータをユーザ間同士で共有する必要がある場合以外はプロトタイプには不要です。
少なくとも本格的な認証は後回しで、idパラメータでユーザ別のデータ取得できる程度で問題ありません。 -
セキュリティ:
決済系の処理を実装しない限り、そのタイミングまで後回しです。EC系など購入がコア機能のサービスだとしたら別ですが。 -
LP(ランディングページの作成):
コア機能の需要がなければ作るだけ無駄ですし、コア機能ができなければ絵に描いた餅になります。コア機能の実装が完了してSEOが必要になったら作れば良いと思います。LPの作り方は以前書きました。ノンデザイナーでもイケてるLPを作成する方法
ちなみに、明らかコストが高い本実装の前に需要があるかどうか確認(計測)するほうが手戻りが少なくて済みます。
参考:ボタンだけおいて、需要があるか計測する
技術選定
作ろうとしているものが特定のプラットフォームに依存しないのであれば
現状、プロトタイプを作る上で次の組み合わせがやはり早いです。(コア部分は枯れた技術ばかりですので、知ってる人はスルーしてください)
・nodejs:npmライブラリが豊富、探せば大抵ある
・parcel:フロントエンドのビルド設定をしなくて良いので楽(ES6、async/await)
・eslint+prettier+snippet:文法チェック+フォーマット自動補正→エラーに注力する負担が減り、ズンドコかける
・heroku:バックエンドも含めたデプロイ先としてはやはりいちばん楽、プラットフォーム固有の処理や設定もほとんどないので後でAWSとか別のホスティングサーバに移行しやすい(無料or課金で独自ドメイン設定&スケールできるのもよし)
・CloudFlare:無料のCDN、herokuの立ち上がりが遅い場合とかに使う
車輪の再発明をしない、複雑なビルド設定に頭を使わない(ハマりどころを減らす)、フォーマットを自動補正(エラーやlintの自動抽出)して細かいコーディングに注力しない。
TypeScriptまで入れていないのはコードの記述量が単純に増えるのでプロトタイプにはまだ不要という判断。
最低限のモックです
https://github.com/teradonburi/mock
プロジェクト構成は次のようになっています。
├── Procfile
├── README.md
├── client
│ ├── index.html
│ └── main.js
├── dist
│ ├── index.html
│ ├── main.1f19ae8e.js
│ └── main.1f19ae8e.js.map
├── nodemon.json
├── node_modules
├── package.json
├── server.js
├── uploads
└── yarn.lock
ぶっちゃけいちいちgitからcloneしてnpm install
するのもyarn
するのも遅いので
自分はローカルでnode_modulesインストール済みのものをプロジェクトごとコピペして使ってます。
eslint+prettier+snippet
.eslintrc.jsに文法チェックを書きます。
module.exports = {
'parser': 'babel-eslint',
'env': {
'browser': true, // ブラウザ
'es6': true, // ES6
'node': true // NodeJS
},
// reactプラグイン
'extends': [
'eslint:recommended',
],
'parserOptions': {
'ecmaFeatures': {
'experimentalObjectRestSpread': true,
},
'sourceType': 'module'
},
'settings': {
},
'plugins': [
],
'globals': {
},
'rules': {
// 略
}
}
エディタはVSCodeの場合は
エディタ左下の歯車アイコンから設定を開き
右上にある左から2番目の矢印と紙のアイコンでsettings.jsonを開きます。
prettierの設定はsettings.jsonにてautoFixOnSave
を有効
validateで対象言語を指定します。
{
"eslint.autoFixOnSave": true,
"eslint.validate": [
{"language": "javascript", "autoFix": true },
]
}
snippetの設定の方はVSCodeで爆速コーディング環境を構築する(主にReactJS向け設定)
の記事を参考にしてください
また、よく使うコマンドのショートカットを.bashrcなどにaliasで作成しておくと、
コマンドの入力が爆速になります。
# 途中で環境変数を使う場合は関数を使う
function gc() {
command git clone $1 --depth 1
}
alias gch='git checkout'
使い方例
$ gc (リポジトリ名)
$ gch (ブランチ名)
ビルド設定(Hot Module Replacement、デバッグ設定、デプロイ設定)
ローカルサーバのnodejs起動はnodemonを使っています。(package.json)
nodemonでサーバを起動するとサーバファイル編集時に自動的にサーバを再起動します。
さらに--inspect
フラグをつけることでnodejsサーバのdebugを行うことができます。(node-inspector)
{
"scripts": {
"dev": "NODE_ENV=dev nodemon --inspect server.js",
}
}
npm run dev
もしくはyarn dev
でローカルサーバの起動ができます。
Chrome Dev Toolsを開き、緑の六角形アイコンをクリック
Ctrl + Pでファイル検索、ここではserver.jsを検索
行の番号をクリックするとブレークポイントが設定できます。
この例ではhttp://localhost:3000/api
にアクセスして処理を止めてみます。
watch式のところに変数名を指定(ここではreq)すると、変数の状態が確認できます。
nodemon.jsonには自動生成されるファイルで再起動してほしくないのでファイルが自動生成される対象のフォルダを除外します。
{
"ignore": ["client", "dist", ".cache", "uploads", "node_modules"]
}
クライアント側の再ビルドはparcel-bundlerのbundler.middlewareで行います。
クライアントのindex.htmlが依存しているファイル(main.jsなど)を編集時にクライアントの再ビルドが行われます。(server.js)
if (process.env.NODE_ENV === 'dev') {
const Bundler = require('parcel-bundler')
const bundler = new Bundler('client/index.html', {})
app.use(bundler.middleware())
}
クライアント側の実装はmain.jsで書いていきます。
regenerator-runtimeでasync/awaitを使えるようにしています。
(Parcelは現状別途入れないとasync/awaitが使えないぽい)
import 'regenerator-runtime/runtime'
async function main() {
}
main()
ちなみにParcelのパスの関係上、クライアント側でimageファイルやcssファイルを参照する際はrequireで参照しなければならないことに注意してください
const imagePath = require('./test.jpg')
リリース設定です。
npm run build
もしくはyarn build
でリリースビルドを行います。
Parcelがうまいこと良い感じにminifyしてくれます。また、デバッグ用の.mapファイルを出力しないように--no-source-maps
オプションをつけます。
{
"scripts": {
"build": "rm -rf dist/* && parcel build client/index.html -d dist --no-source-maps",
"prod": "NODE_ENV=production node server.js"
}
}
Procfileにherokuのリリース後のサーバ起動スクリプトにbuildと同じものを記述します。(実際デプロイ後実行されるのはこちら)
web: NODE_ENV=production node server.js
herokuにデプロイするためにはherokuにアプリをまず作成する必要があります。
【herokuコマンド】createからdestroyまで
などを参考にしてください
アプリ名は全世界で固有の名前でないといけないことに注意が必要です。(誰かがすでに使っている可能性がある)
$ heroku login
$ heroku create アプリ名
herokuの画面上のDeploy項目からGitHubリポジトリにブランチを指定して連携します。(この例だとcartoonnewsというアプリ)
Automatically deploysを設定しておくとgithubにpush時にherokuにもdeployしてくれます。
デプロイが成功してサーバが起動すれば以下のURLでホスティングされます
https://(アプリ名).herokuapp.com/
うまく行かない場合は次のコマンドでherokuのエラーログを確認します。
$ heroku logs --tail
プロトタイプを作る
色々異論はあるかもしれませんが以下私がプロトタイプを作るときの実装の流れです。
- CSSフレームワーク、JSフレームワークは極力使わない(ただしライブラリは使ってOK):
絶対これしか使わないというのであれば別ですが、フレームワークは使ってしまった時点でロックオンされてしまうので、極力使わないでVanillaJSで実装したほうが後で移植しやすいです。HTMLElement、addEventListener、Image、Audio、WebAudio、WebSocket、WebRTC、WebBluetooth、File(Blob)、Form、fetch、LocalStorage、Canvas、WebGL
を組み合わせれば大体実現できます(よく使うものはsnippetを用意しておくと便利)。
ライブラリも使うならメジャーどころ(スター数が多くメンテされているもの)を使いましょう。 - 外部提供APIのコールはサーバサイドで行う(クロスオリジンの制限に引っかかるのが普通なので)、バックエンドはAPI、ファイル操作、WebSocketの実装に注力します。
- CSSでレイアウト・デザインを整える。レイアウトは基本flexbox、display、position、margin、padding、width系、height系、overflow、white-space、z-indexでなんとかなる(GridLayoutとobject-fitはIEがあるのでできれば使わない)、DOMの装飾はcolor、font-size、font-weight、line-height、background、border、border-radius、opactity、box-shadow、gradation、filter、transform、hoverを使う。アニメーションはtransition、animation
- レスポンシブ対応、
@media
クエリでモバイル対応をする(最近はモバイルレイアウトから作り始めたほうが良いかも・・・) - リソースの最適化をする。画像はImageOptimでサイズを減らす。ウェブフォントはサブセットフォントメーカーで使う文字だけに削ってファイルサイズダウンする
- トラッキングコードを仕込む
- インフラの構築(ドメイン取得、CDN設定など)
最近の自分の傾向はクライアントサイドに実装を寄せることが多いです。
(バックエンドでやるとサーバの負荷が増えるし、端末のスペックも上がってきているので大体クライアントサイドでできてしまう)
フロントエンドの簡易な実装であれば、ライブラリを使わずともはMDNに大体実装が書いてあります。
フロントエンドエンジニア御用達の MDN web docs を網羅した
グロースハックに関して
2019/10/05 グロースハックの記事を書きました
スタートアップ界隈4年目エンジニアが苦労したグロースハック手法について語る