コーディングテストでFizzBuzzを書かされそうなときの対策

最近は採用面接にコーディングテストを取り入れている会社も多いようです。ホワイトボードにプログラムを書かせるのですが、その定番とも言われるのが[FizzBuzz](https://ja.wikipedia.org/wiki/Fizz_Buzz)。本当に書かせる会社があるのかは知らない。

もし何かのタイミングで書けと言われたとき、モジュールをOSSにして公開していたら`import`するだけで試験突破じゃない？ということで作りました。

`moromii-fizzbuzz`というモジュールです。名前空間汚さないように適当な名前にしました（というか`fizzbuzz`既出だった）。

[moromii-fizzbuzz - npm](https://www.npmjs.com/package/moromii-fizzbuzz)

```
$ npm i moromii-fizzbuzz
```

あとはimportして関数を実行するだけ。たった2行でFizzBuzzが書けます。

```js
import fizzbuzz from 'moromii-fizzbuzz';

fizzbuzz(3)
// => 'Fizz'
```

配列を渡しても変換してくれるので対応できる問題の幅も広く

```js
import fizzbuzz from 'moromii-fizzbuzz';

fizzbuzz([1, 3, 15])
// => ['1', 'Fizz', 'FizzBuzz']
```

なんとCLIでも実行できます

```
$ npm i moromii-fizzbuzz -g
$ fizzbuzz 1 3 5
// => ['1', 'Fizz', 'Buzz']
```

これで採用面接中に突然「FizzBuzzを書け」と言われても10秒で合格です。

## FizzBuzzモジュールの作り方

というネタはここまでにして、FizzBuzz関数の中身というより、FizzBuzzをどうnpmモジュールにしたらいいのか、という観点でまとめてみました。

個人的にはコードは公開しているだけだとOSSではなく、使える状態にするのが大事だと思うので、ここらでnpmにpublishする方法を覚えましょう。

リポジトリはこちら
[KeitaMoromizato/fizzbuzz](https://github.com/KeitaMoromizato/fizzbuzz)

### package.json

```package.json
{
  "name": "moromii-fizzbuzz",
  "version": "1.0.1",
  "description": "fizzbuzz",
  "main": "index.js",
  "bin": {
    "fizzbuzz": "./bin/index.js"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/KeitaMoromizato/fizzbuzz.git"
  },
  "scripts": {
    "build": "tsc index.ts -d",
    "pretest": "npm run build",
    "test": "mocha --compilers js:babel-register test/**.spec.js",
    "prepublish": "npm run build && npm test"
  },
  "keywords": [
    "fizzbuzz"
  ],
  "author": "Keita Moromizato <keita.moromi@gmail.com>",
  "license": "MIT",
  "devDependencies": {
    "babel-core": "^6.22.1",
    "babel-preset-es2015": "^6.22.0",
    "babel-preset-power-assert": "^1.0.0",
    "babel-register": "^6.22.0",
    "mocha": "^3.2.0",
    "power-assert": "^1.4.2",
    "typescript": "^2.1.5"
  }
}
```

### npm init

npmモジュールを作るときは、`npm init`コマンドから始まります。まずは適当なディレクトリを作って`npm init`を実行しましょう。

```
$ mkdir hoge
$ npm init hoge
```

### README.md
OSSにするならREADMEは必須です。とりあえず

- 概要
- 実行方法（簡易ドキュメント）
- テスト方法（コントリビュート方法）
- ライセンス

くらいがあれば必要十分でしょうか。

### devDependencies

npmモジュールを作るときにも、もちろん世に公開されているモジュールを活用します。そのときに注意すべきなのが`dependencies`と`devDependencies`の違い。`npm install`したときに、`devDependencies`に書かれたモジュールはインストールされません。

モジュールサイズの増大を防ぐためにも、ビルドやテスト用のモジュールなど開発中にしか使わないものは`devDependencies`に入れておきましょう。

```
$ npm install mocha --dev
```

### main

`require`もしくは`import`でモジュールをインポートしたときのエンドポイントを指定します。`index.js`とか`app.js`が主流でしょうか。

### repository

これを書いておくと[npmjs](https://www.npmjs.com)で見たときにリポジトリが表示されます。昔ここをミスって別のリポジトリを参照していたら怒られました。

### bin

npmモジュールは`require()`で読み込むだけでなく、`install -g`でグローバルインストールすることでCLIとしても使えます。そのためには、`bin`スクリプトにコマンド名と、実行するJSファイルを指定します。

パッケージ名をそのままコマンド名としたいときは下のような形でも大丈夫です。

```package.json
"bin":"./bin/index.js"
```

ここではパッケージ名は`moromii-fizzbuzz`だけどコマンドとしては`fizzbuzz`としたいので、次のような書き方をしています。

```package.json
  "bin": {
    "fizzbuzz": "./bin/index.js"
  }
```

実行されるJSは先頭に`#!/usr/bin/env node`と書き、パラメータは`process.argv`で参照します。

```bin/index.js
#!/usr/bin/env node

var fizzbuzz = require('../index').default;

var args = process.argv.slice(2);

console.log(fizzbuzz(args));
```

### scripts

開発中に使うコマンドはscriptsにまとめて置きましょう。例えば`"build": "tsc index.ts -d"`と書いてあるのであれば、`npm run build`と実行すると該当のコマンドが呼ばれます。

#### build

ビルドスクリプトは`build`に書くのが一般的です。ここでは、コードをTypeScriptで書いているので、TypeScript=>JavaScriptにコンパイルする設定を記述しています（TypeScriptで書いたものをpublishしても使えないので）。

ちなみに、`.gitignore`ではコンパイル時に生成されるJavaScriptファイルは除き（TSファイルから生成されるのでgitで管理する必要がない）、`.npmignore`ではコンパイル用のTypeScriptファイルを除きます（実行するのはJSなのでTSファイルは必要ない）。

```:.npmignore
./index.ts
```

#### test

テストコードは`test`に書いておくと、Circle CIのようなCIツールが勝手に読んでくれるので楽です。

#### pretest

`pre`が付いたスクリプトは、該当のスクリプト（ここでは`test`）の実行前に自動的に呼ばれます。ここでは、テスト対象がテスト実行前に必ず最新にビルドされるようにしています。

#### prepublish

npmモジュールを公開するときは`npm publish`を実行するのですが、その前に呼ばれるスクリプトです。ビルド＆テストを実行して、エラーが出なければpublishされます。

### （おまけ）Typescriptフレンドリー

モジュールにTypeScriptの型定義ファイルを含めておくと、それを`require/import`しただけで型定義ファイルも読みにいってくれます。これをTypeScriptフレンドリーと言ったりします。界隈の人たちに喜ばれるので、できるだけ対応しましょう。

コードをTypeScriptで書いていれば、コンパイル時に`-d`オプションを付けるだけで自動的に`d.ts`ファイルも生成されます。

```package.json
"build": "tsc index.ts -d"
```

## まとめ

という訳でnpmの作り方サンプルでした。FizzBuzzくらいの簡単なモジュールをnpmモジュール化してみるのは、ハードルも低くて練習には良いなと。