[中文版](./README-zh.md) | [ENGLISH](./README.md) | [한국어](./README-ko.md) | [РУССКИЙ](./README-ru.md) | [Português](./README-pt-BR.md) | [Persian/فارسی](./README-ir.md) [](https://www.elsewhen.com/) # プロジェクトガイドライン[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) > 開発中の新たなプロジェクトは草原のようですが、メンテナンスは誰にとっても悪夢になります。 > ここには私たちが見つけ記載し、集め考えたガイドラインがあります。 このガイドラインはほとんどの[elsewhen](https://www.elsewhen.com)の JavaScript のプロジェクトで機能しています。 > もしもベストプラクティスを我々と共有したかったり、このガイドラインの項目は削除した方が良いと思ったら[気軽に私たちに報告してください](http://makeapullrequest.com)。 - [Git](#git) - [Git のルール](#some-git-rules) - [Git workflow](#git-workflow) - [良いコミットメッセージの書き方](#writing-good-commit-messages) - [ドキュメント](#documentation) - [開発環境](#environments) - [統一された開発環境](#consistent-dev-environments) - [一貫した依存性](#consistent-dependencies) - [依存関係](#dependencies) - [テスト](#testing) - [プロジェクトの構造と名前付け](#structure-and-naming) - [コードスタイル](#code-style) - [コードスタイルガイドライン](#code-style-check) - [標準的なコードスタイルの強制](#enforcing-code-style-standards) - [ログ](#logging) - [API](#api) - [API デザイン](#api-design) - [API セキュリティ](#api-security) - [API ドキュメント](#api-documentation) - [ライセンス](#licensing) ## 1. Git ![Git](/images/branching.png) ### 1.1 Git のルール いくつかの Git のルールを覚えておきましょう。 - feature ブランチで作業しましょう。 _Why:_ > 全作業がメインブランチではなくて独立した作業専用のブランチで完結するからです。そうすることによって混乱をきたすことなく複数のプルリクエストを作成することができます。作業途中のコードや不安定なコードを master ブランチを気にすることなく繰り返し作れます。[もっと読む...](https://www.atlassian.com/git/tutorials/comparing-workflows#feature-branch-workflow) - `develop`ブランチからブランチを切りましょう _Why:_ > こうすることで master のコードを問題なくビルドできることができ、master はリリース用にほとんどそのまま利用できます。(プロジェクトによってはやりすぎかもしれません。) - `develop`と`master`ブランチに直接 Push するのはやめましょう。プルリクエストを作成しましょう。 _Why:_ > `develop`と`master`ブランチが更新されるということはチームメンバーにその機能を実装し終わったと伝えることと同義です。直接 Push さえしなければ、コードレビューや新たな機能の議論がしやすくなります。 - feature ブランチを Push してプルリクエストを作成する前にローカルの`develop` ブランチを最新にして、feature ブランチをインタラクティブリベースしましょう。 _Why:_ > リベースはブランチ(`master`か`develop`か)をマージします。また local に作ったコミットをマージコミットを作成せずに Git のヒストリーのトップに並べ替えます。コンフリクトがなければ。そうすることで綺麗で素晴らしいヒストリーが残ります。[もっと読む...](https://www.atlassian.com/git/tutorials/merging-vs-rebasing) - リベースする間やプルリクエストを作る前にコンフリクトを解消しましょう。 - マージした後のブランチは local、remote 共に削除しましょう。 _Why:_ > 不要になったブランチをが含まれることで自身 local のブランチのリストが乱雑になるでしょう。またマージする時にのみ一回だけブランチ(`master`か`develop`)に戻ることを保証します。feature ブランチは作業中だけ存在すべきです。 - プルリクエストを前に、feature ブランチのビルドの成功を確認して全てのテストを通しましょう。(コードのスタイルも含めて確認しましょう。) _Why:_ > 安定的なコードを追加しようとする時、もし feature ブランチのテストが失敗したとすると、最終的なマージ後のテストも失敗する可能性が高いです。加えてプルリクエストを作成する前に、スタイルチェックを行う必要があります。スタイルチェックを行うことで可読性が上がり、実際のコードと一緒にフォーマットによる修正を減らすことに繋がります。 - [こちらの](./.gitignore)`.gitignore`ファイルを使いましょう。 _Why:_ > この.gitignore ファイルには remote のリポジトリに含めたくないシステムファイルのリストを列挙しています。またユーザーが多くの人が使うエディタ用のフォルダやファイル(依存フォルダも同じように)も含めてます。 - `develop`と`master`ブランチを保護しましょう。 _Why:_ > プロダクションに備えているブランチに予期しない破壊的なコミットが Push されることを防ぎます。 ### 1.2 Git workflow 上記の理由のために、私達は[Feature-branch-workflow](https://www.atlassian.com/git/tutorials/comparing-workflows#feature-branch-workflow)と[Interactive Rebasing](https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing)、[Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows#gitflow-workflow) の要素のいくつか(名前付と develop ブランチを持つこと)を使います。主なステップは以下の通りです。 - 新しいプロジェクトにとっては初期の git の設定。**features/changes ブランチの作成は の次のステップなので無視しましょう。** ```sh cd git init ``` - feature/bug-fix ブランチを作成する。 ```sh git checkout -b ``` - コードを変更する。 ```sh git add git commit -a ``` _Why:_ > `git commit -a`を使うと本文から主題を切り離して始めることができます。詳しくは*section 1.3*を読みましょう。 - 取り込まれていない変更を取得する為にリモートのリボジトリと同期しましょう。 ```sh git checkout develop git pull ``` _Why:_ > こうすることでコンフリクトを含めながらプルリクエストを作成するのではなくてリベース(のちに)しつつ、コンフリクトに対処できる可能性が高まります。 - feature ブランチにインタラクティブリベースをすることで常に develop の変更を取り込みましょう。 ```sh git checkout git rebase -i --autosquash develop ``` _Why:_ > --autosquash は全てのコミットを一つにまとめることができます。一つの feature に対して複数のコミットがある状態は望ましくありません。[もっと読む...](https://robots.thoughtbot.com/autosquashing-git-commits) - もしコンフリクトしてなかったらこの章は飛ばして大丈夫です。ただしもしコンフリクトが起きてたら[解決しましょう](https://help.github.com/articles/resolving-a-merge-conflict-using-the-command-line/)。そしてリベースを続けましょう。 ```sh git add ... git rebase --continue ``` - 自分のブランチを Push しましょう。リベースはヒストリーを改変しますので、リモートに Push する際は`-f` のオプションをつけて Push する必要があります。もし他の人が同じブランチで作業をしていたらより破壊的でない`--force-with-lease`を使いましょう。 ```sh git push -f ``` _Why:_ > リベースをすると、作業ブランチのコミットヒストリーを変えることになります。結果として Git に普通の`git push`は拒否されるので代わりに -f や--force フラグを使えば大丈夫です。[もっと読む...](https://help.github.com/articles/resolving-a-merge-conflict-using-the-command-line/) - プルリクエストを作りましょう。 - プルリクエストが受け入れられたら、レビュワーによってマージされて課題が閉じられます。 - マージが完了したらローカルのブランチを消しましょう。 ```sh git branch -d ``` 必要のないリモートブランチを全て削除するコマンド。 ```sh git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done ``` ### 1.3 良いコミットメッセージの書き方 コミットを作成して維持するための良い指針を持つと、Git をうまく使うことができ他の開発者との共同作業をとても簡単にします。ここにいくつかの経験則があります。([ソース](https://chris.beams.io/posts/git-commit/#seven-rules)) - 本文を改行することで主題と切り離しましょう。 _Why:_ > Git は最初の行をそのコミットのサマリとして区別します。実際`git log`の代わりに`git shortlog`を使うと、コミット ID とサマリーのみで構成される長いコミットメッセージのリストを見ることができます。 - 主題は 50 文字以内、本文を含めても 72 文字以内に制限しましょう。 _why_ > コミットはできる限りきめ細やかで完結あるべきで、コミットメッセージを冗長にすることは避けましょう。[詳しく読む](https://medium.com/@preslavrachev/what-s-with-the-50-72-rule-8a906f61f09c) - 主題の先頭は大文字にしましょう。 - ピリオドで終わるのをやめましょう。 - 主題部分では[命令法](https://en.wikipedia.org/wiki/Imperative_mood) を使いましょう。 _Why:_ > コミッタが何を行ったかわかりやすいメッセージを書きましょう。コミットがマージされた後にそのコミットが何をしたのかをうまく説明できるように考えるといいでしょう。[もっと読む...](https://news.ycombinator.com/item?id=2079612) - 本文は **How** ではなくて **What** と **Why**を説明しましょう。 ## 2. ドキュメント ![ドキュメント](/images/documentation.png) - こちらの[テンプレート](./README.sample.md)を使って`README.md`を作成しましょう。空白のセクションがあっても気にしなくても大丈夫です。 - 一つ以上の Git リポジトリがあるようなプロジェクトでは、各々の`README.md`ファイルをリンクさせてあげましょう。 - プロジェクトの成長に合わせて`README.md`の情報を最新に保ちましょう。 - コードにはコメントを書きましょう。その際には自分の意図をできる限り簡潔に書くように心がけましょう。 - もしコードや試みているアプローチについて github や stackoverllow でオープンな議論があれば、そのリンクもコメントに含めましょう。 - ダメなコードに対する言い訳を書くのはやめましょう。コードを綺麗に保ちましょう。 - 綺麗なコードを全くコメントがないことに対する言い訳にするのはやめましょう。 - コードの成長に合わせてコメントを最新に保ちましょう。 ## 3. 開発環境 ![開発環境](/images/laptop.png) - 必要なら`development`, `test` と`production`の環境を分けて定義しましょう。 _Why:_ > データやトークンや API、ポートなど環境によって必要とされるものは様々です。。。テストの自動化と手動のテストを簡単にさせるために、`development`モードは予測可能なデータを返すフェイクの API が欲しいかもしれません。もしくは Google Analytics は`production`でだけ有効にしたかったり様々でしょう。[もっと読む...](https://stackoverflow.com/questions/8332333/node-js-setting-up-environment-specific-configs-to-be-used-with-everyauth) - 環境別の Config ファイルを環境毎に適用するようにして、コードベースに定数として決して書き込まないでください。[サンプル](./config.sample.js) _Why:_ > トークン、パスワードなど様々な重要な個人情報を持っています。 その情報はコードベースがいつ公開されてもいいように、コードベースとは切り離さないといけません。 _How:_ > `.env`ファイルを情報を保持するために使いましょう。そのファイルは`.gitignore`に加えて、Git リポジトリからは除外されるようにします。その代わりに`.env.example`のようなサンプルを他の開発者向けのガイドとしてコミットしておきましょう。production 環境用に、環境設定は標準的なやり方で設定するようにしましょう。 > [もっと読む...](https://medium.com/@rafaelvidaurre/managing-environment-variables-in-node-js-2cb45a55195f) - アプリケーションを開始する前に環境変数を validate することをオススメします。[サンプルを参照](./configWithTest.sample.js) 変数を Validate するために`joi`を使っています。 _Why:_ > トラブルシューティングに費やす時間を節約することに繋がります。 ### 3.1 統一された開発環境 - node のバージョンを`package.json`の中の`engines`に設定しましょう。 _Why:_ > どのバージョンの node をそのプロジェクトで使うべきかを示すことができます。[もっと読む...](https://docs.npmjs.com/files/package.json#engines) - さらに`nvm` を使って`.nvmrc`をプロジェクトルートに作成しましょう。ドキュメント内に記述を残すことを忘れないようにしましょう。 _Why:_ > `nvm`を使う人は誰でも誰でも`nvm use`を使うことで node のバージョンを切り替えることができます。[もっと読む...](https://github.com/creationix/nvm) - `preinstall`スクリプトを使って node と npm のバージョンを確かめるのがいいでしょう。 _Why:_ > npm の新たなバージョンでインストールすると依存関係のライブラリが失敗することがあります。 - できるならば Docker イメージを使いましょう。 _Why:_ > Docker イメージは全てのワークフローを跨いで同じ環境を提供してくれます。依存関係やコンフィグファイルに悩む必要があまりないようになります。[もっと読む...](https://hackernoon.com/how-to-dockerize-a-node-js-application-4fbab45a0c19) - グローバルのモジュールを使うのではなくローカルのモジュールを使いましょう。 _Why:_ > 同僚が特定のモジュールを彼らのマシンにすでにインストールしていることを期待するのではなく、使うライブラリは共有できるようにしておきましょう。 ### 3.2 一貫した依存関係 - チームメンバーが同じ依存関係を取得できることを確認しましょう。 _Why:_    > コードにはどんな開発マシンでも同じ挙動をしてほしいからです。[もっと読む...](https://medium.com/@kentcdodds/why-semver-ranges-are-literally-the-worst-817cdcb09277) _how:_ > `npm@5`以上で`package-lock.json`を使いましょう。 _npm@5 は使ってない:_ > `Yarn`を使い`README.md`を確かめることで代替手段とすることができます。各ライブラリをアップデートした後にロックファイルと`package.json` は同じバージョンを保持しているでしょう。 _`Yarn`という名前が気にくわない:_ > それは残念です。 古いバージョンの`npm`用に、パブリッシュする前に新しいライブラリをインストールしたり`npm-shrinkwrap.json`を作るときには、`—save --save-exact`を使いましょう。[もっと読む...](https://docs.npmjs.com/files/package-locks) ## 4. 依存関係 ![Github](/images/modules.png) - 使用可能な最新のパッケージを保ちましょう。 e.g.,`npm ls --depth=0`. [もっと読む...](https://docs.npmjs.com/cli/ls) - 無関係であったり使っていないパッケージを確認しましょう: `depcheck`. [もっと読む...](https://www.npmjs.com/package/depcheck) _Why:_ > もしかしたら使っていないライブラリが production のサイズを増加させているかもしれません。使っていない依存関係を見つけてそれを消すようにしましょう。 - ライブラリをインストールする前に、そのライブラリがコミュニティでよく使われているかどうかを確認しましょう。`npm-stat`。[もっと読む...](https://npm-stat.com/) _Why:_ > 多く使われているということは多くのコントリビューターがいるということで、それは良いメンテナンスが行われているということになります。そのことはバグが開発者によっていち早く発見され、修正されることに繋がります - ライブラリをインストールする前に、それがいい機能を持っているか、多くのメンテナーがいて成熟したバージョンを頻繁にリリースしているライブラリかを確認しましょう。: e.g., `npm view async`. [もっと読む...](https://docs.npmjs.com/cli/view) _Why:_ > もしメンテナーが修正をマージしなかったりパッチを素早く当てないと、コントリビュータが効率的な開発を行えなくなるでしょう。 - それほど知られてないライブラリが必要な場合には、使用する前にチームメンバーと議論しましょう。 - ライブラリはビルドを破壊しない限りは常に最新で動くかを確かめましょう: `npm outdated` [もっと読む...](https://docs.npmjs.com/cli/outdated) _Why:_ > 依存パッケージの更新はたまに破壊的変更が含まれていることがあります。アップデートが出たときには常にリリースノートを確認しましょう。何かあったときにトラブルシューティングを簡単にするために、依存ライブラリを一つ一つ更新しましょう。[npm-check-updates](https://github.com/tjunnone/npm-check-updates)のように素晴らしいツールを使いましょう。 - 依存パッケージに公開されている脆弱性が含まれている場合があるのでチェックしましょう。 e.g.,[Snyk](https://snyk.io/test?utm_source=risingstack_blog) ## 5. テスト ![テスト](/images/testing.png) - 必要であれば`test`の環境を用意しましょう。 _Why:_ > 通常は end to end のテストを`production`に行うだけで十分なですが、例外がいくつかあります。統計データを`production`環境で有効にしたくなく、テストデータでダッシュボードを汚したくない場合です。あとは`production`の API に制限があって、テストをする際のリクエスト数が制限に達してブロックされてしまう場合です。 - 単体テストコードはテストされるファイルの隣におきましょう。 `moduleName.spec.js`のように`*.test.js` や `*.spec.js` のようなファイル名が慣例となっています。 _Why:_ > ユニットテストを探すためにフォルダ構造を掘り進めたくないでしょう。[もっと読む...](https://hackernoon.com/structure-your-javascript-code-for-testability-9bc93d9c72dc) - 追加のテストファイルがどこにあるか混乱を避けるために隔離されたフォルダに入れましょう _Why:_ > いくつかのテストコードは実装コードと関連してないことがあります。他の開発者が見つけやすいフォルダ(`__test__`フォルダのような)にテストコードをおきましょう。`__test__`フォルダはスタンダートであり、様々な JavaScript フレームワークのテストで使用されています。 - テストの書きやすいコードを書きましょう。副作用を避けましょう。副作用を抽出しましょう。純粋な関数を書きましょう。 _Why:_ > 結合を分けてロジックのテストをしたい場合。ランダムで非決定性のプロセスがコードの信頼性に与える影響を最小にする必要があります。[もっと読む...](https://medium.com/javascript-scene/tdd-the-rite-way-53c9b46f45e3) > 純粋関数は同じ入力に対して常に同じ結果を出力します。逆に言えば純粋でない関数は副作用をもっているか結果を出力する際に外部の状況に左右されます。そのような関数は予想通りの結果が返ってきにくくなります。[もっと読む...](https://hackernoon.com/structure-your-javascript-code-for-testability-9bc93d9c72dc) - 静的解析ツールを使いましょう。 _Why:_ > 静的解析ツールが必要な場面があるかもしれません。コードが信頼できる基準をもたらしてくれます。 - `develop`ブランチにするリクエストを投げる前にローカルでテストを実行しましょう。 _Why:_ > 誰しもプロダクション準備中のビルドを失敗される犯人になりたくたいでしょう。`rebase`した後、リモートの feature ブランチにリポジトリに Push する前にテストを実行するようにしましょう。 - テストの実行方法などの情報を含めて、ドキュメントとして`README.md`ファイルに記述しましょう。 _Why:_ > ドキュメントを残すことで他の開発者、DevOps の担当者もしくは QA にプロジェクトを引き継いだ時に、彼らがあなたのコードで仕事をしやすくなります。 ## 6. プロジェクトの構造と名前付け ![Structure and Naming](/images/folder-tree.png) - ファイルを役割ではなく商品、ページ、コンポーネントのように集約しましょう。テストファイルも実装の隣に配置しましょう。 **Bad** ``` . ├── controllers | ├── product.js | └── user.js ├── models | ├── product.js | └── user.js ``` **Good** ``` . ├── product | ├── index.js | ├── product.js | └── product.test.js ├── user | ├── index.js | ├── user.js | └── user.test.js ``` _Why:_ > 長いファイルのリストの代わりに、テストコードを含めたカプセル化された単一責任の小さいモジュールが出来上がります。そうすることでコードのガイドがしやすくなり、一目で見つけることができるようになります。 - 追加のテストファイルは混乱を避けるために test フォルダに置きましょう。 _Why:_ > 他の開発者やチームの DevOps の担当者の時間を節約することにつながります。 - `./config`フォルダを作成しましょう。違う環境のための違う config ファイルを作らないようにしましょう。 _Why:_ > 異なる目的(例えばデータベースや API 等々)のために複数の config ファイルに分割する時は、同じフォルダに`config`のようなわかりやすい名前でまとめておきましょう。ただし、異なる環境ごとに異なる config ファイルを作成しないように気をつけてください。新たなデプロイ先が増えた時に新たな環境の名前が必要となり、綺麗にスケールすることができないからです。 > config ファイル内の変数は環境変数から与えるのが良い方法です。[もっと読む...](https://medium.com/@fedorHK/no-config-b3f1171eecd5) - スクリプトは`./scripts`フォルダに置きましょう。ここには node や bash のスクリプトが含まれます。 _Why:_ > プロダクション、デベロップのビルド、データベースの構築と同期等々を行う際に少なくとも一つ以上のスクリプトがプロジェクトで必要とされる可能性が高いでしょう。 - ビルドの成果物は`./build`に出力するようにしましょう。`build/`を`.gitignore`に加えましょう。 _Why:_    > 名前はなんでもよくて、dist という名前でもかっこいいです。なんでもいいとはいえ、チームのメンバーが矛盾なく理解できる名前でなければなりません。例えば何がそのフォルダで取得できるのか、作成されたものなのかバンドルされたものなのか、コンパイルされたものなのか、もしくはただ移動されてきたものなのか。なにを出力するのか、チームメートがそこになにを出力できるのかもそうです。だからそのフォルダは特殊な事情がない限りですがリモートリポジトリにコミットする必要がありません。 - `PascalCase`と`camelCase`をファイルとディレクトリの名前に使用しましょう。`PascalCase`はコンポーネントのみに使用しましょう。 - `CheckBox/index.js`は`CheckBox`のコンポーネントを持っているべきです。`CheckBox.js`もそうでしょう。しかし`CheckBox/CheckBox.js`や`checkbox/CheckBox.js`のような名前は冗長なので避けるべきです。 - 理想的にはフォルダの名前は`index.js`のデフォルト export の名前と一致させるべきです。 _Why:_ > そうすることで親フォルダをシンプルに import するだけでモジュールやコンポーネントを想像できます。 ## 7. コードスタイル ![Code style](/images/code-style.png) ### 7.1 コードスタイルガイドライン - 新しいプロジェクトでは stage-2 かそれよりバージョンの新しいモダンな JavaScript を使用するようにしましょう。古いプロジェクトについては、モダンな JavaScript が動くプロジェクトにさせたい場合は別として既存のバージョンと互換性のあるバージョンにとどめておきましょう。 _Why:_ > チーム次第ではありますが、私たちはトランスパイラを使用することで、新しいシンタックスの利点を活用しています。stage-2 は残りわずかな改訂で仕様の一部になる可能性が徐々に高くなっています。 - コードスタイルチェックをビルドプロセスに含めましょう。 _Why:_ > ビルドを壊すことはコードスタイルを矯正する一つの方法になります。あなたがだんだんコードスタイルを真剣に捉えなくなるということを防いでくれます。クライアントとサーバーサイドのコード両方に導入しましょう。[もっと読む...](https://www.robinwieruch.de/react-eslint-webpack-babel/) - コードスタイルを強制するために[ESLint - Pluggable JavaScript linter](http://eslint.org/)を使いましょう。 _Why:_ > 私たちはシンプルな `eslint` が好きなだけなので、あなたがそうである必要はないです。`eslint` 自体たくさんのルールをサポートしています。ルールを設定でき、カスタムルールを追加することができます。 - 私たちは[Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript)を JavaScript に使っています。[もっと読む...](https://www.gitbook.com/book/duk/airbnb-javascript-guidelines/details)。あなたのチームに求められた JavaScript のスタイルガイドを使用しましょう。 - 私たちは[FlowType](https://flow.org/)を使用する時には[Flow type style check rules for ESLint](https://github.com/gajus/eslint-plugin-flowtype)を使っています。 _Why:_ > Flow には、特定のコードスタイルに従ってチェックする必要がある構文がほとんどありません - 特定のフォルダやファイルをコードスタイルチェックから除外するために`.eslintignore`を使いましょう。 _Why:_ > 複数のファイルをスタイルチェックから除外する時に、`eslint-disable`のコメントでコードを汚す必要がありません。 - プルリクエストを作成する前には`eslint`のコメントアウトを削除しましょう。 _Why:_ > ロジックの実装に注力している時はスタイルチェックを無効にするのは一般的ですが、`eslint-disable` のコメントを削除してルールに従うことを忘れないようにしましょう。 - タスクのサイズによって、`//TODO:` コメント使うか、チケットを起票するかを選択しましょう。 _Why:_ > チームメートには小さなタスクの事(関数のリファクタリング、コメントのアップデートなど)を定義しておきましょう。大きめのタスクにはリントルール通りに`//TODO(#3456)`と書き、チケットの番号を記載しましょう。 - コメントは常にコードの変更に関連させるようにしましょう。コメントアウトされたコードは取り除きましょう。 _Why:_ > コードは可能な限り読みやすくする必要があると同時に、余分な部分は除去しておくべきです。リファクタリングする時は既存コードをコメントアウトするのではなく、削除しましょう。 - 無関係であったりおかしなコードやログや名前付けは避けましょう。 _Why:_ > ビルドプロセスでそれらを除去できるかも(すべき)です。あなたのコードは別会社や別クライアントの渡される可能性がありますし、あなたのコードがどこかの誰かに見られて笑われないようにしましょう。 - 短い名前を避けて、意味として区別しやすい検索しやすい名前をつけましょう。関数には長くて記述的な名前を使いましょう。関数の名前は動詞もしくは動詞のフレーズにしましょう。その関数の意図を伝える必要があります。 _Why:_ > ソースコードをより自然により読みやすくさせるためです。 - ファイル内の関数を降順によってまとめておきましょう。高いレベルの関数は上部へ、低いレベルの関数は下部へ位置させましょう。 _Why:_ > 読むのに適したソースコードになるようにするためです。 ### 7.2 標準的なコードスタイルの強制 - .editorconfig ファイルを使って開発者が異なるエディタや IDE のプロジェクト間で一貫したコーディングスタイルを定義し維持することができるようにしましょう。 _Why:_ > EditorConfig プロジェクトはコーディングスタイル定義とエディタがファイルフォーマット読み込んでスタイル定義を有効にするエディタプラグインからなります。EditorConfig ファイルは可読性が高くバージョンコントロールシステムともうまく機能します。 - コードスタイルのエラーを伝えてくれるエディタを使いましょう。既存の ESLint の設定と一緒に[eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier)と[eslint-config-prettier](https://github.com/prettier/eslint-config-prettier)を使いましょう。[もっと読む...](https://github.com/prettier/eslint-config-prettier#installation) - Git hook の使用を考えましょう。 _Why:_ > Git hook は開発者の生産性を大きく高めてくれます。ビルドの破壊を怖がることなく、ステージングやプロダクション環境に変更を作成、コミット、Push できます。[もっと読む...](http://githooks.com/) - Prettier を`precommit hook`とともに使いましょう。 _Why:_ > `prettier`自体はとても力強いものではありますが、毎回のコードフォーマットに対して個別の npm task としてシンプルに実行することはあまり生産的ではありません。ここでは`lint-staged`(と`husky`)が活躍します。`lint-staged` [here](https://github.com/okonet/lint-staged#configuration)の`husky` [here](https://github.com/typicode/husky)の設定をよく読みましょう。 ## 8. ログ ![Logging](/images/logging.png) - クライアントサイドの console ログをプロダクション環境で出力するのは避けましょう。 _Why:_ > ビルドプロセスを通して Console ログを取り除くことができます(すべきです)が、コードスタイルチェックが吐き出す console log についての warning の情報を確認しましょう。 - プロダクションのログは読みやすいように出力しましょう。理想的にはプロダクションモードで使われているロギングライブラリを使いましょう([winston](https://github.com/winstonjs/winston) もしくは [node-bunyan](https://github.com/trentm/node-bunyan)のようなものがあります。) _Why:_ > ログのカラー化やタイムスタンプ、ログファイルの出力や日々のログファイルのローテートが、トラブルシューティングの不快感を少なくしてくれます。 ## 9. API ![API](/images/api.png) ### 9.1 API デザイン _Why:_ > 私たちは明快に構築された RESTful のインターフェースでの開発を強制することで、チームメンバーやクライアントがシンプルに矛盾なくそれを使えることができます。 _Why:_ > 一貫性やシンプルさがない API はシステムの結合やメンテナンスのコストを増加させます。だから`API design`をこのドキュメントに含めて説明しています。 - 私たちは多くの場面でリソース志向アーキテクチャに従っています。リソース志向アーキテクチャとは主にリソース、集合、URL の要素で構成されます。 - リソースはデータを持っていて、ネストを取得でき、それらのリソースを操作できるメソッドがあります。 - リソースの集合はコレクションと呼ばれます。 - URL はオンラインのリソースの場所はリソースかコレクションで表します。 _Why:_ > 上記のことは開発者(あなたの API を使う人たち)に周知されていることです。可読性や使いやすさを別としても、REST API ではその API の詳細を知らずとも汎用なライブラリやコネクタを書くができます。 - URL には kebab-case を使いましょう。 - リクエスト内のパラメータやリソース内のパラメータには camelCase を使いましょう。 - URL 内のリソース名は複数形の kebab-case にしましょう - コレクションを表す url には常に複数形の名詞を使いましょう。`/users` _Why:_ > 基本的にはそうすることで読みやすさの向上 URL の一貫性を維持することになるでしょう。[もっと読む...](https://apigee.com/about/blog/technology/restful-api-design-plural-nouns-and-concrete-names) - ソースコード内での変数やプロパティ名の複数形はリストのサフィックスにしましょう。 _Why:_ > 複数形は URL においては良いものですが、ソースコード内では分かりにくくエラーの原因になり得ます。 - コレクションで始まり識別子に終わる単一のパスを常に使用しましょう。 ``` /students/245743 /airports/kjfk ``` - 以下のような URL は避けましょう。 ``` GET /blogs/:blogId/posts/:postId/summary ``` _Why:_ > この URL はリソースではなく、プロパティをさしています。プロパティはレスポンスを整えるようにパラメータに渡しましょう。 - リソースを示す URL からは動詞を含めないようにしましょう。 _Why:_ > 各リソースの操作に動詞を含めると、各々のリソースの操作について大量の URL が出来てしまい、開発者にとって理解するのが難しい一貫性のないパターンになってしまうからです。私たちは他の箇所に動詞を使っています。 - リソースではない部分に動詞を使用しましょう。このケースではこの API はリソースを返さずに、操作を実行して結果を受け取るのみです。CRUD(Create Retrieve Update Delete)の操作ではないことに注意しましょう。 ``` /translate?text=Hallo ``` _Why:_ > CRUD についてはリソースやコレクションの URL に対して HTTP メソッドを使用するからです。説明している動詞はおおよそ`Controller`となります。通常これらの URL をたくさん作成することはないでしょう。[もっと読む...](https://byrondover.github.io/post/restful-api-guidelines/#controller) - リクエストボディやレスポンスタイプは`JSON`にしましょう。そして一貫性あるメンテナンスをしやすくするために、プロパティ名は`camelCase`を使用するようにしましょう。 _Why:_ > このドキュメントは JavaScript プロジェクトのガイドラインであるため、JSON の読み書きには JavaScript が使用されてることを想定しています。 - リソースオブジェクトインスタンスや DB のレコードと同じような単一なものであったとしても、`table_name`や`column_name`はリソース名やプロパティ名にしないようにしましょう。 _Why:_ > あくまでリソースを公開するのであって DB のスキーマの詳細を公開するためのものではないからです。 - 念のためにもう一度、URL には名詞のみを使い、機能を説明するような名前付けは避けましょう。 _Why:_ > 名詞のみをリソースの URL には使用しましょう。`/addNewUser`や`/updateUse`のようなエンドポイントを用意するのはやめましょう。同様にリソース操作をパラメータを送るのも避けましょう。 - CRUD の機能的説明には HTTP のメソッドを使いましょう。 _How:_ > `GET`: 存在するリソースの取得。 > `POST`: 新しいリソースとサブリソースの作成。 > `PUT`: 既存のリソースの更新。 > `PATCH`: 既存のリソースの更新。提供されたフィールドのみを更新し、他のフィールドはそのままにしておきます。 > `DELETE`: 存在するリソースの削除。 - ネストしているリソースのために関連する URL 間にリレーションを使用しましょう。例えば会社の従業員を関連されるために、id を使用します。 _Why:_ > 各リソースを探索しやすくするための自然なやり方です。 _How:_ > `GET /schools/2/students `。2 の学校のすべての生徒を取得できるはずです。 > `GET /schools/2/students/31` 。2 の学校に所属する、31 の生徒の詳細を取得できるはずです。 > `DELETE /schools/2/students/31` 。2 の学校に所属する 31 の生徒を削除できるはずです。 > `PUT /schools/2/students/31` 。31 の生徒の情報を更新するはずです。また PUT はコレクションには使用せずにリソース URL のみに使用するようにしましょう。 > `POST /schools`。新たな学校を作成して、その作成された学校の情報を返却するはずです。POST はコレクションの URL に使用しましょう。 - バージョンには`v`をプレフィックスとした単純な整数を使用しましょう(v1,v2)。全ての URL を残したまま移動するために、バージョンは一番上のスコープに使用しましょう。 ``` http://api.domain.com/v1/schools/3/students ``` _Why:_ > API がサードパーティのために公開される時には、API の破壊的変更を伴うバージョンアップは既存のプロダクトや API を使うサービスに多大な影響を与えます。バージョンを URL に含めることで、これらの問題が起きることを防いでくれます。[もっと読む...](https://apigee.com/about/blog/technology/restful-api-design-tips-versioning) - レスポンスメッセージは自己記述的でなければなりません。良いエラーレスポンスは以下のようなものになります。 ```json { "code": 1234, "message": "Something bad happened", "description": "More details" } ``` またバリデーションエラーならこうです。 ```json { "code": 2314, "message": "Validation Failed", "errors": [ { "code": 1233, "field": "email", "message": "Invalid email" }, { "code": 1234, "field": "password", "message": "No password provided" } ] } ``` _Why:_ > API を使用したアプリケーションがそのユーザーの手元に届けられたあと、問題解決やトラブルシューティングをする重要な時に、開発者は良いデザインのエラーメッセージに頼ることになります。 _Note: セキュリティの例外のメッセージは極力一般化しましょう。例えば"パスワードが間違っています"と言う代わりに、"ユーザー名もしくはパスワードが間違っています"と言いましょう。私たちの場合はユーザー名が正しくて、パスワードだけ間違っていると伝えることはしないようにしています。_ - **全てがうまく動いていた**、**クライアントアプリがうまく動いてなかった** 、**API がうまく動いてなかった** 等 レスポンスの説明には 8 個のステータスのみを送るようにしましょう。 _一覧:_ > `200 OK` `GET`、`PUT` 、`POST`リクエストが成功したことを表します。 > `201 Created` 新しいインスタンスが作成された時に返却されます。新しいインスタンスの作成、`POST`メソッドの使用は`201`のステータスコードを返します。 > `304 Not Modified` ユーザーがすでにレスポンスのキャッシュを持っている場合に返却されます、最小の転送に抑えることになります。 > `400 Bad Request` リクエストが処理されなかった場合に返却されます。サーバーがクライアントの要求するリクエストを理解できなかったような時です。 > `401 Unauthorized` リクエストの認証情報が不足している時に返却されます。要求された認証情報で再リクエストを行うことになるでしょう。 > `403 Forbidden` サーバーはリクエストを解釈できていますが、認証を拒否したという意味です。 > `404 Not Found` リクエストしたリソースが見つからなかったことを示します。 > `500 Internal Server Error` リクエストは正しいが、サーバーが予期せぬ事態により動作しなかったことを示します。 _Why:_ > 多くのAPIの提供者は少数のHTTPのステータスコードを使用します。例えばGoogleのGdata APIは10個のステータスコードしか使っていません。Netflixは9つです。Diggは8つだけです。もちろんながらこれらのレスポンスは追加の情報をbodyに含めています。70を超えるHTTPのステータスが存在しますが。あまり一般的でないステータスコードを選択すると、アプリケーションの開発者は開発を離れて、ステータスコードが何を示しているのかを理解しようとwikipedia等で調べざるを得なくなります。[もっと読む...](https://apigee.com/about/blog/technology/restful-api-design-what-about-errors) - レスポンスにはリソースの数の合計を提供しましょう。 - `limit`と`offset`のパラメータを受けつけましょう。 - リソースの公開するデータ量はよく考える必要があります。API の利用者は常にリソースの全ての表現が必要というわけではありません。フィールドのカンマ区切りリストを含むフィールドクエリパラメータを使用します。 ``` GET /student?fields=id,name,age,class ``` - ページネーション、フィルタリング、ソートは初めから全てのリソースをサポートする必要はありません。フィルタリングやソートのあとにこれらのリソースを記述しましょう。 ### 9.2 API セキュリティ いくつかのセキュリティのベストプラクティスをご紹介します。 - セキュアな通信(HTTPS)以外ではベーシック認証を使わないようにしましょう。認証トークンを URL に含めてはいけません。`GET /users/123?token=asdf....` _Why:_ > トークンやユーザー ID やパスワードが平文としてネットワークを超えてくるので(base64 にエンコードされているでしょうが、base64 は可逆なエンコード方法です。)、ベーシック認証機構はセキュアではないです。[もっと読む...](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication) - トークンは毎回のリクエストの認証ヘッダーに乗せて送信されなければなりません。`Authorization: Bearer xxxxxx, Extra yyyyy` - 認証コードの生存期間は短く設定されるべきです。 - 安全ではないデータの受け渡しを避けるために HTTP リクエストに応答しないことで TLS ではないリクエストを拒否するようにしましょう。その際には`403 Forbidden`で応答しましょう。 - リクエスト制限を使うことを考えましょう。 _Why:_ > 一時間あたり何千ものリクエストを送りつけてくるボットから身を守るために、リクエスト制限を早いうちから考えておくべきでしょう。 - HTTP ヘッダを適切に設定することは Web アプリケーションをより強固に、より安全にするのに役立ちます。[もっと読む...](https://github.com/helmetjs/helmet) - API は標準的なフォームのデータを受け取ってデータを加工しましょう。できなければリクエストを拒否するようにしましょう。400 Bad Request とともにデータの不足やエラーについての詳細を返却しましょう。 - REST な API で交換される全てのデータは API 上で Validate するようにしましょう。 - JSON をシリアライズしましょう。 _Why:_ > JSON エンコーダの悩みの種は、ブラウザ内でリモートからの任意の JavaScript の実行を防ぐことです。もしくは node.js を使用しているのであれば、サーバーサイドも同様です。ユーザーから与えられた入力がブラウザ内で実行されないように、ユーザーからの情報をエンコードできる適切な JSON シリアライザーを使用することが重要です。 - Content-Type を Validate するようにしましょう。多くの場合で `application/*json` (Content-Type ヘッダ)を使いましょう。 _Why:_ > 例えば、`application/x-www-form-urlencoded`の mime-type を受け入れることは、攻撃者にフォームを作成させ、シンプルな POST リクエストを誘引させることを許すことになります。サーバは受け入れる Content-Type を決して推定させないべきです。Content-Type ヘッダもしくは予期しない Content-Type ヘッダに対しては`4XX`のレスポンスでリクエストを拒否する結果を返却しましょう。 - API のセキュリティをチェックリストを見て確認しましょう。[もっと読む...](https://github.com/shieldfy/API-Security-Checklist) ### 9.3 API ドキュメント - [README.md template](./README.sample.md)の`API Reference`のセクションを埋めましょう。 - コードのサンプルとともに API の認証方法について記述しましょう。 - URL の構造(path についてのみでいいです。root の URL については必要ありません。)をリクエストのメソッドとともに説明しましょう。 各エンドポイントについて - URL パラメータはもし存在する場合は、URL セクションに記載されている名前に従って指定しましょう。 ``` Required: id=[integer] Optional: photo_id=[alphanumeric] ``` - リクエストタイプが POST なら、ちゃんと動く例も用意しましょう。URL パラメータのルールはここにも適用します。Optional と Required に分けましょう。 - レスポンスの成功の場合ステータスコードは何でしょうか?どんなデータを返されるでしょうか?ドキュメントは API の返答を開発者が知りたいときに役立ちます。 ``` Code: 200 Content: { id : 12 } ``` - レスポンスの失敗の時は、ほとんどのエンドポイントの失敗は複数通りあります。認証されていないアクセスからの不正な値等。それら全てをここでは列挙しましょう。繰り返しになりますが、こうすることで憶測のみで開発せざるを得ない状況を防ぎます。例 ```json { "code": 403, "message": "Authentication failed", "description": "Invalid username or password" } ``` - API デザインツールを使用しましょう。[API Blueprint](https://apiblueprint.org/)、[Swagger](https://swagger.io/)のようなオープンソースの良いドキュメンテーションツールがたくさんあります。 ## 10. ライセンス ![Licensing](/images/licensing.png) 使用できる権利のあるリソースを使用していることを確認してください。ライブラリを使っているのであれば、MIT、Apache、BSD のライセンスを見つけることを心がけましょう。ライブラリを修正したいのであれば、ライセンスの詳細を少し見て見ましょう。著作権で保護されている画像や動画が法的問題を引き起こすかもしれません。 --- Sources: [RisingStack Engineering](https://blog.risingstack.com/), [Mozilla Developer Network](https://developer.mozilla.org/), [Heroku Dev Center](https://devcenter.heroku.com), [Airbnb/javascript](https://github.com/airbnb/javascript), [Atlassian Git tutorials](https://www.atlassian.com/git/tutorials), [Apigee](https://apigee.com/about/blog), [Wishtack](https://blog.wishtack.com) Icons by [icons8](https://icons8.com/)