JavaScript
FizzBuzz
npm

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

More than 1 year has passed since last update.

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

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

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

moromii-fizzbuzz - npm

$ npm i moromii-fizzbuzz

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

import fizzbuzz from 'moromii-fizzbuzz';

fizzbuzz(3)
// => 'Fizz'

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

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

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

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

$ npm install mocha --dev

main

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

repository

これを書いておくとnpmjsで見たときにリポジトリが表示されます。昔ここをミスって別のリポジトリを参照していたら怒られました。

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モジュール化してみるのは、ハードルも低くて練習には良いなと。