@ledsun blog

無味の味は佳境に入らざればすなわち知れず

reduceでPromiseをつないでタイムライン実行する

Promiseとreduceを組み合わせたトリック。 適当な間を置いてイベント発行するstubを作る時に使いました。

指定時間後に処理を実行するPromiseを作ります。

var DelayPromise = function(delay, action) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      try {
        action();
        resolve();
      } catch (err) {
        reject(err);
      }
    }, delay);
  });
};

map/reduceでつなげて実行します。

[1, 2, 3].map(function(record) {
    // Promiseはnewすると実行します。前のPromise完了後に実行する関数を作ります。
    return function() {
      // 指定秒後に数字を表示します。
      return new DelayPromise(record * 1000, function() {
        console.log(record)
      });
    }
  })
  .reduce(function(prev, action) {
    // 順次実行するために各actionをthenで繋ぎます。
    return prev.then(action);
  }, Promise.resolve())
  .catch(function(err) {
    console.error(err, err.stack);
  });

1秒後に1が、それから2秒後に2が、それから3秒経って3が表示されます。

Mac OS X で Raspberry PiのOSイメージを焼く

Mac OS XMac に刺したSDカードにddコマンドを使ってOSイメージを焼く方法です。

OSイメージの入手

Downloads | Raspberry Piから好きなイメージをダウンロードします。 特にこだわりがなければ、サンプルが多いRASPBIANが良いと思います。

Download Zipをすると数時間掛かるので、面倒でもBitTorrentをインストールして、BitTorrent経由でダウンロードするのをオススメします。

SDカードの確認

SDカードのデバイス名を確認します。 SDカードをMacに刺し、ターミナルから次のコマンドを実行します。

diskutil list

次のような結果が表示されます。

/dev/disk0
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *251.0 GB   disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:                  Apple_HFS Macintosh HD            250.1 GB   disk0s2
   3:                 Apple_Boot Recovery HD             650.0 MB   disk0s3
/dev/disk1
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     Apple_partition_scheme                        *374.6 MB   disk1
   1:        Apple_partition_map                         32.3 KB    disk1s1
   2:                  Apple_HFS Adobe Photoshop CC 2014 374.6 MB   disk1s2
/dev/disk2
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     Apple_partition_scheme                        *46.1 MB    disk2
   1:        Apple_partition_map                         32.3 KB    disk2s1
   2:                  Apple_HFS Bitcasa Installer       46.1 MB    disk2s2
/dev/disk3
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *8.0 GB     disk3
   1:                 DOS_FAT_32 NO NAME                 8.0 GB     disk3s1

Appleで始まるキーワードはOSで使っているデバイスです。 それ以外のデバイスが今回刺したSDカードです。 この例では/dev/disk3/です。

OSイメージを焼く

ddコマンドを使ってOSイメージを焼きます。

アンマウント

ddコマンドはマウントされているデバイスには実行できません。 一度アンマウントします。 指定するデバイス名はさきほど確認した/dev/disk3/です。

diskutil unmountDisk /dev/disk3 

焼く

ddコマンドでOSイメージを焼きます。

sudo dd if=2014-09-09-wheezy-raspbian.img of=/dev/rdisk3 bs=1m

完了まで6分掛かります。注意点がたくさんあります。

  • デバイス名を間違えるとMacのデータを壊せるので気をつけましょう
  • デバイス名にrを付けて/dev/rdisk3/にすると10倍速く焼けます
  • bs=1mオプションを付けると10倍速く焼けます

指定を間違えると、ものすごく時間が掛かるので気をつけましょう。

進捗確認

ddコマンドは実行中にCtrl + Tを押すと現在の進捗を表示します。

load: 1.00  cmd: dd 3056 uninterruptible 0.00u 1.31s
1935+0 records in
1934+0 records out
2027945984 bytes transferred in 258.285589 secs (7851565 bytes/sec)

2014-09-09-wheezy-raspbian.imgのファイルサイズは3276800000バイトです。 おおよその残り時間が推測できます。

動作確認

Raspberry PiをHDMIケーブルでモニタと繋ぎ、SDカードを刺して電源を入れてみましょう。 起動画面が表示されば成功です。

参考リンク

参考書籍

Raspberry Piユーザーガイド 第2版 ラズパイマガジン (日経BPパソコンベストムック)

Raspberry piをMQTT 気温 publisherにするAnsible Playbookを公開しました

過去のBlogで手動でやっていたことをAnsible Playbookに書き起こしました。

変更点は?

  • 秘密情報(Sangoへの接続情報)をansible-vaultで隠蔽した
  • cron設定(15分に一回)を追加した

困ったこと

  • 電車の中や外出中はRaspberry Piの実機がなくて動作確認できなかった

次にやりたいこと

  • Raspberry Pi でMQTTで更新トピックを監視、メッセージが飛んで来たらansible-pull
  • Raspberry Pi を増やして、それぞれ別トピックにpublish。ansibleのrollを使ってトピック名を変数で指定する

とてか03にて発表してきました #toteka

咳マニアの集うイベント とてか03 にて発表してきました。 発表は「忍者式テスト」についてです。 忍者式テストは2004年頃に咳さんが発表されてから(咳さんチーム以外の)実施者が一人しか観測されていないテスト(開発?)手法です。

私が忍者式テストに取り組んだ経緯と、やってみてどうだったのかの感想をしゃべってきました。

MVCとかMVPとかしゃべるのはマニアックすぎないか、そしてマサカリが飛んでこないか恐かったです。 特に問題はありませんでした。

最強のIT系かあちゃんからたかしへのアドバイス知っている方が何人か居ました。 おほめいただき光栄です。

質問など

  • 何人で開発して忍者式テストは何人がやっているのですか?
    • 一人プロジェクトです。なので全員がテストしています。
  • テストを一周回すとどれぐらいの時間が掛かりますか?
    • バグが無ければ30分、見つけても1時間ぐらいで終わります。
  • テストを捨てるのに驚きました。
    • 一周が1時間を越えると、毎日できなくなるので頑張って減らしています。
  • なんで忍者式なんですか?
    • 忍者のジャンプ練習法からです。麻の苗を植えて毎日飛び越えるやつです。
    • 本当はタケカワユキヒデさんの英単語の学習法かららしいです。
  • そのTシャツはどこで売っていますか?
    • KUMAYAで買えます。
    • 当日は「つゆだく」ホワイトを着ていました。

感想レポート

とてかの感想

湯本さんの基調講演

「自分の作業手順(プロセス)をしらないと他人の手法をどこに入れていいか分からない」がぐっときた

いかつい

ぐっときた

  • ツイートを「すらっとしている」と形容
  • 人間は数字を追いかけるのが好き。79に行くと80にしたくなっちゃう
  • 漏れは認識の違い。使う人と作る人のズレ
  • テスト対象に詳しくないとフリーダムなテストができない
  • テストケースの上に目的を書いている
  • 開発者はいい加減な仕様から、ちょっと外れたケースを考えて設計している

ぞっとした

  • 一万回テストというものがある。30人で2,3日掛けてやる。再現しなかったらOK。再現できたら、「とりあえず直してみた」からもう一回。

Raspberry piからmqttcliでSangoに送信する

mqttcliのarmバイナリを作ってもらったので使ってみます。

インストール

Raspberry Pi にsshログインして実行します。

wget https://drone.io/github.com/shirou/mqttcli/files/artifacts/bin/linux_arm/mqttcli
chmod +x mqttcli 

実行

Raspberry Pi にsshログインして実行します。

export MQTT_HOST="lite.mqtt.shiguredo.jp"
export MQTT_PORT="1883"
export MQTT_USERNAME="ledsun@github"
export MQTT_PASSWORD="XXXX"
echo hoge | ./mqttcli pub -t "ledsun@github/temper" -s

※ 接続パスワードは伏せてあります。

確認

Mac OS Xから確認します。

export MQTT_HOST="lite.mqtt.shiguredo.jp"
export MQTT_PORT="1883"
export MQTT_USERNAME="ledsun@github"
export MQTT_PASSWORD="XXXX"
mqttcli sub -t "ledsun@github/temper"

Mac OS XでSubscribe中に Raspberry PiからPublishしてMac OS Xで以下が表示されました。

hoge

成功です。パチパチ

Raspberry piで計った温度をMQTTでSangoに送信する

構成

Raspberry Piの設定

2014-09-09-wheezy-raspbian.img を使ってRaspberry Piを起動してください。 Raspberry Piにsshでログインし、以下の作業を行います。

aptの設定

現時点でwolframに接続できません。削除しておきます。

sudo mv /etc/apt/sources.list.d/wolfram.list /etc/apt/sources.list.d/wolfram.disabled
sude apt-get update

temperのインストール

を参考にします。

sudo apt-get install gcc libusb-dev
git clone git://github.com/bitplane/temper.git
cd temper
make

実行

sudo temper/temper 
26-Sep-2014 14:58,44.412800

GMT時刻と現在の温度が表示されます。当然ですが、USB温度計を刺していないと表示されません。

※ Raspberry PiのUSBポートに直接刺すと、Raspberry Piに温められ40度を超えることがあります。

MQTT clientのインストール

Mosquitto Debian repository | Mosquitto の通りですが、クライアントだけをインストールします。

wget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key
sudo apt-key add mosquitto-repo.gpg.key
cd /etc/apt/sources.list.d/
sudo wget http://repo.mosquitto.org/debian/mosquitto-wheezy.list
cd ~
sudo apt-get update
sudo apt-get install mosquitto-clients

publish

を参考にしてpublishします。次のようなコマンドになります。

sudo temper/temper | mosquitto_pub -h lite.mqtt.shiguredo.jp -u "ledsun@github" -t "ledsun@github/temper" -P XXXX -s

※ 接続パスワードは伏せてあります。

subscribe

Mac OS Xから確認します。

を参考にしてmqttcliを使います。

export MQTT_HOST="lite.mqtt.shiguredo.jp"
export MQTT_PORT="1883"
export MQTT_USERNAME="ledsun@github"
export MQTT_PASSWORD="XXXX"
mqttcli sub -t "ledsun@github/temper"

実行

Mac OS XでSubscribe中に Raspberry PiからPublishしてMac OS Xで以下のような表示がされれば成功です。

26-Sep-2014 15:26,29.368061

Ansibleを使ってRaspberry PiにNode.jsをインストールする

前提

2014-06-20-wheezy-raspbian.imgを使ってRaspberry Piが起動できていること。

ansibleをインストール

Mac ではHomebrewが使えます。

brew install ansible

設定ファイルを準備

hosts

[raspberry-pi]
192.168.0.54

IPアドレスを適切に設定します。

ansible.cfg

[defaults]
hostfile = hosts
remote_user = pi
ask_pass=True
transport = paramiko

ログインユーザーを適切に設定します。 ここでは初期値のpiを指定しています。

node.yml

---
- hosts: raspberry-pi
  tasks:
    - name: download dpkg
      get_url: url=http://node-arm.herokuapp.com/node_latest_armhf.deb dest=node_latest_armhf.deb

    - name: install dpkg
      apt: deb=./node_latest_armhf.deb
      sudo: true

実行

ansible-playbook node.yml

参考

crestとバグとpacage.json

MongoDBを外部プログラムから更新するのにREST APIがあると便利です。 Cordazar/crest · GitHubというアプリケーションを試してみました。 バグを踏みましたが、原因がわかりました。そういう話です。

npm installできない

npm install crest

エラーが起こります。

npm ERR! Error: ENOENT, chmod '/Users/shigerunakajima/node_modules/crest/bin/server'

この時点でよく考えればわかったのですが・・・

親切な罠

同じ問題がISSUEに上がっていました。

npm install exits with Error: ENOENT, chmod ... · Issue #1 · Cordazar/crest · GitHub しかもPullReqestまで!

これでインストールできる♪

npm install git+https://github.com/jasonnathan/crest.git

しかし・・・通らない!!! 同じエラーが起こります。

npm ERR! Error: ENOENT, chmod '/Users/shigerunakajima/node_modules/crest/bin/server'

バグは

冷静にエラーメッセージを見ます。 見つからずにエラーになっているファイルはserverです。 私が使いたいコマンドはcrestでした。

package.jsonを見てみましょう。

  "bin": {
    "server": "./bin/server"
  }

実行ファイルとして./bin/serverが指定されています。 binディレクトリに入っているのはcrestです。

確認

forkして、package.jsonを直します。

  "bin":  "./bin/crest"

インストールしてみましょう。

npm uninstall git+ssh://git@github.com:ledsun/crest.git

無事にインストールできました。

node_modules/crest/bin/crest
crest listening at http://0.0.0.0:3500

起動もできました!

参考

package.jsonの書き方はこちら。 npm package.json 日本語版 取扱説明書

永和さんの「価値創造契約」に思うこと

刺激を受けました。 個人的な思いを書きます 後出しじゃんけんです。 寝言です。

価値観

「初期費用が無料だから私たちは本気です」という価値観はあまり好きではありません。 「斉藤浩司@帯をギュっとね」メソッドや「苦しければ報われる欺瞞」に近いものを感じます。 お客にリスクを負ってもらって、それに報いる方がより本気のように感じます。

商売として

お金は商売の血液

1000万円の資金を全額、保証金としてロックするのは商売として考えると微妙です。 商売お金をお客様とそのお客様と自分たちと協力会社と・・・の間を血液のように流す活動のことです。 バッファとして30%ほどをプールするのは良いですが、100%プールするのはいけません。 脾臓に血液を貯めても全身に巡らなければ死んでしまいます。

*1

気が長い

2,3年続かないとペイしない契約で、 成り立つのはファンドや保険などの数百〜万契約を束ねられる商売だけです。 新規ビジネスとして始めるにはリスクがすこし大きいです。 資金ショートがこわいです。 多額の保証金が必要な理由でもあります。

チケット制

チケット制は契約はシンプルですが運用が面倒くさいです。

特にシステム担当者には辛いシステムです。 毎日チケット消化のネタを考える時間はないので、余らせがちです。 余らせると怒られると思います。

担当者がつく案件の場合は、 事前に数ヶ月程度の消化計画を立てる必要があります。 実施しながら消化計画を修正しながらすすめて行くと、アジャイルっぽくなります。

大きなマイルストーンは必要です。

経営者からの直接発注であれば細かい計画を立てなくてもマッチすると思います。 毎日チケット消化のネタを考える仕事なので。

このまま進むならお客さんを選ぶのがいいと思います

永和さんにはファンがいっぱい居ると思います。 そのうち一社か二社を、木下さんが「なにかあったら俺がケツ拭くから」と口説きましょう。 売上を立てて、オブジェクト倶楽部で事例発表してもらいましょう。 ここまで1年。 2年目に5社まで増やせれば、3年目ぐらいでギリギリ赤字ぐらいになると思います。

複数案件掛け持ちで、お客さんのチケット消化スケジュールを考慮しながら、 開発を進めていくのはめちゃくちゃしんどいです。 開発者がやめたくなるかもしれません*2

トントンが見えれば仕事として取り組めるので、 もう少し「仕組み化」できるかもしれません。 というか、そういうのを期待しています。

Try もし私がやるとしたら

今は業務委託でも受注できるので「アジャイルな受託開発のため」だけなら不要と思います。

「1/3人月しかお金が無いけど、作りながら考えたい」という需要はありそうに思います。 実装を伴う要件定義です。 そろそろ自社サービス開発以外の受託開発でもやってもいいかもしれません。 というわけでプランはSとSSに絞ります。 要件決定のインセンティブとして最大3ヶ月間など期間の制約がある方がいいかもしれません。

開発案件として立ち上がって1人/月以上の開発になれば普通の受託開発にします。 仕様をよく理解できているので開発者としてはやりやすいと思います。 会社としても得意な受託開発のリソースが生きるので良さそうです。

全てのステークホルダーが参加してインセプションデッキを作って、 夢のようなアジャイル受託開発ができるかもしれません。

*1:インカムゲイン原理主義者からすると株主をなめすぎと思います。 資本を預かって、商売して利益出して配当出すのが(インカムゲイン原理主義者的な)株式会社の本分です。 使わない資本を減らせば一株辺りの配当増えるじゃん。 余った資金を他の会社に出資したいです。 永和さんは非上場会社ですので余計なお世話ですね。 それでも資本金6000万円の15%と考えると大きなチャレンジです。 すごい会社です。

*2:私はチケット制は一社でこりました。

mowsのtestlingの動かし方

mowsのテスト方法が判明しました。

mowsのtestlingの実行方法

npm install -g testling

でインストール

testling -u

を実行、表示されたurlをFirefoxSafariで開くと通ります。 そしてPull Reqesutを修正しました。

npm testも実行し、テストが通ることも確認しています。

Google Chromeではエラーが出る

testling -uGoogle Chromeで開くとエラーが出ます。 これはどうしたらいいのだろう?Issueをあげればいいのかな?

mowsにPull Requestするなど

PullRequestを送る

mowsというWebSocketに対応したJavaScriptのMQTTクライアントがあります。

URLと認証情報を同時に設定してconnectすると、認証情報が無視されます。 修正するPullRequestを送っている話。 現在進行中です。

testlingへの対応

mcolinaさんはnodeconf.euに参加していたようで、しばらく反応がありませんでした。 関係ないけど、日本に来たら握手しに行く!

Fix connect URL with authentication. by ledsun · Pull Request #15 · mcollina/mows · GitHub

To check, you can run testling

と、コメントをいただきました。 対応しようとtestlingを設定するも上手く動かせない・・・

作業ログ

testlingと必要なツールをインストール。

npm install -g testling phantomjs browserify
node /usr/local/lib/node_modules/testling/node_modules/browser-launcher/example/detect.js

browserify test.js | testlingで実行してもtestlingで実行しても、テストが通らない。 もちろん修正前のコミットです。

そもそもtestlingの使い方がよくわかない。 質問を投げて今日の作業は終了にします。

MQTTのリアルタイムWebビューの実装など

活動記録の続き。完成していません。

sangoでconnectionが残る問題

  • WebSocket上だとkeepalive指定があってもsangoにconnectionが残ることがある
  • 次回deployで修正予定らしい
  • connect中にPCをスリープにしてネットワークを切断するか切り替えるかで発生した
  • 具体的には、電車の中でつないでて、電車降りて(スリープ)、家帰って(ネットワーク切り替え)Dashboard見たら起きてた
  • 一応beforeunloadイベントでdisconnectする実装を入れたけど、 ブラウザ閉じなくても起きるので、この問題には無意味だった。
  • 世のWebSocket対応MQTT Brokerは対応しているのだろうか?

疎通確認

  • PC上のmqttcliからsangoを通してブラウザでsubscribeしたメッセージを見るところまできた
  • -d付けるとBroker URI: %stcp://free.mqtt.shiguredo.jp:1883%sが余計に表示される
  • mqttcli/mqtt.go at master · shirou/mqttcli · GitHub のぱっと見では起きそうにないんだけどな・・・
  • 次はRaspberry Piからpublishしたい
  • goの環境を作らなくては

追記

  • mqttcli は修正済みでした
go get -u github.com/shirou/mqttcli
mqttcli pub -t "ledsun@github/test" -d -m "yoyo"

INFO[0000] Broker URI: tcp://free.mqtt.shiguredo.jp:1883 
INFO[0000] Connecting...                                
INFO[0000] Connected                                    
INFO[0000] Topic: ledsun@github/test                    
INFO[0000] Published
  • sangoも対応版をdeploy済み出そうです。
  • この対応の早さたるや!mowsはいつPull Requestに反応してくれるのだろう・・・

sangoを使ってセンサー監視システムを作ろう

MQTT as a Service sangoを使ってMQTTな何かを作ってみる活動記録。 まだ完成していない。

作りたいのは

みたいなやつ。違うのはセンサーが照度でなく温度になる予定です。

システムアーキテクチャ

f:id:ledsun:20140910001201p:plain

こんな感じ。 本職はWebアプリケーション屋さんなのに アプリケーションサーバが要らなくなってしまった。

名前はtemper-monster

温度のtemperatureをちょっと縮めてテンパーにしたら @take3000 サンが思い浮かんだのでモンスターを付けました。 ああ、ledsun/temper-monster · GitHub 全然更新してないや

主な活動履歴

  • clientのテンプレを用意
    • VagrantDebian環境作ればRasberryPiへの移植が楽だろうと作る
    • 時代はprovisionigだぜ!と調子こいてansibleに手を出す
    • あんまり似てなかった・・・
  • RasberryPiの用意
    • Debianだろ?とか余裕こいてたらパッケージが大分違った
    • こっちもansibleのスクリプトを用意
    • SDカードコピーすればいいだけなのに!
  • リアルタイムビューの用意
    • mowsでsangoに繋がらない
    • sangoでMQTT3.1を許容してもらう
    • mowsがURL指定&認証ありで動かないのでパッチを当てる
    • Pull Requestするも放置
    • gulpの環境を作るのに嵌る。
      • 主にlivereload
      • 何回も試しているうちにsangoにコネクションが残ってしまったので、解放してもらう

ちょっとした振り返り

  • broker
    • 当初はbroker込みのNodeアプリケーションを考えていた
    • moscaがサーバー組み込みで上手く動かなかった
    • herokuにTCPが通るか検証するのがめんどくさかった
    • 上手いタイミングでsangoがサービスイン!

次はRaspberry Piからリアルタイムビューまでの疎通確認の予定。

XP祭りに行きました #xpjug

http://xpjug.com/xp2014/

アジャイルが好きな理由

アジャイルソフトウエア開発が好きな人が集まっている会なので、いろんな人にアジャイルが好きな理由を聞いて回ればよかった。

自分が(受託開発で)アジャイルが好きなのは「動くものを見せながらお客さんと話すと話しやすい」からです。 仕様から動きを想像して話を噛み合わせるのはすごく難しい。 ペーパープロトタイプをやると画面上のパーツの配置は決められるけど、動きはやっぱり認識を合わせづらいです。

動くものを見せればすぐに伝わる。今作るものに集中できて開発側のスピードがあがる。 そのぶんビジネス側へのフィードバック量(数も頻度も)増えるので、ビジネスで判断する回数は格段に増える。 これについて来れない(今までの「最初にお願いして半年後に検収」みたいな発注方法を続けたい)発注者もいるので、発注者を選ばないといけないといけない。 この辺の話はみんなしないね(開発側で発注者の良し悪しの話をするとダークサイドに落ちるから避けてるんだろうけど)。

XPが好きな理由

上のは実利上の話で、XPの思想的な話では「人が学ぶことを是としている」ところが好き。 LTで勝手に

が成長するってしゃべって、ここはみんな特に感じるものがなかったみたい。 後ろ2つのプラクティスとプログラマが成長する部分はすごく好き。 プラクティスが成長するのは咳さんのずっと守だった話に通じると思う。 プログラマが成長するのはパーフェクトじゃない僕がやるには合ってるなあと感じる。 感じ過ぎて

と、スライドに入れそうになったけど、テストエンジニアとして勉強したことないに偉そうなことを言うのは恐いので自重した。

感想など

咳さん

  • ぐっと来るポイントがたくさんあった
  • TestingとCheckingの話が好き
    • 楽しいTDDとクソみたいなTDDの理由が説明できる
    • 三角測量とかAPIの洗練とか新しいことが分かるTDDはTestingだから楽しい
    • 「C0カバレッジを100%にするためにデータオブジェクトのプロパティのテストコードを書く」 みたいな発見のないChekingなTDDはつまんない
  • チームの話になると自己組織化しすぎてて参考にならないw

岩切さん

  • やばいやつ
  • ちょーかっこいい
  • 10年かけて真似する案件

木下さん

  • いろいろ思うことがありすぎる
  • お客さんにリスクを負わせないのは、それはそれで本気じゃないと思う・・・
  • アジャイルだとお客さんが大量のフィードバックをさばけないといけないのでお客さんは選ぶべき
    • 担当者個人の話じゃない
    • あるユーザー部門に仕様を確認して回答がおそかったら開発が止まってしまう
    • 担当者が仕様変更に納得してても現場を知らないえらい人が納得しないことがある

くらぬきさん

  • 5年ぶりぐらいに講演を聞いた
  • めっちゃ情熱的な講演になっててびびった
    • これが営業力の差かと思い知った
  • TIS時代の専務の話にぐっと来た
    • 「社外で活動したいなら指名されるぐらい有名になれ」
    • 「仲間を見つけろ。一人ではじめ(起業し)たらずっと一人だぞ」
  • 「人は変えられないけど、会社の仕組みは変えられる」もぐっと来た

伊藤浩一さん

受託開発でここまでやっているのはすごい。 Web系自社サービスの会社はもう一周先に行ってたりする。 辛いものがあるなと思った。

米澤さん

ゆっくりしゃべってるのに情報量が多くて不思議。

LT

やってきました。

3/4ぐらい話すつもりで1/2ぐらいまでしかしゃべれなかった。 結果的に「とてか03の予告」感が増した。

忍者式のプラクティスは木ではなく麻だというフィードバックを手に入れました。

しかも伊賀の忍者博物館公認らしい。

アドリブで受けた点はちゃんと取り込もうとおもう。

没項目

千葉☆滋と芸風違い過ぎというフィードバックがあった。

実際はしゃべる内容に迷っていたのでネタを入れてブラッシュアップする時間がなかっただけです。

ネタ1

ニンジャスレイヤーとか入れようと思ったが、テンションが違い過ぎてしゃべれなかったので割愛。 単に練習不足なんだけど、やってもウケる気がしない。 今思うと客層的に忍者タートルズの方が良いと思う。

ネタ2

尺が足りないのと、早口に切り替えるのが辛いのでやめた。

ネタ3

も入れたかったけど、あまりにもハイコンテキストなので自重しました。 忍者式テストの10年後のフォロワーって意味を掛けたいのだけど、 比喩の方が分かりにくい。 これを読んでくれているすべての人に伝わらない自信があります。

感想リンク

追記

忍者式テストの真の由来

MQTTとJavaScript

MQTTってなに?

PUB/SUBプロトコルです。 HTTPと同じレイヤーです、主にTCP上で動きます。 WebSocket上でも使えます。 温度計などのセンサーの計測値を集めるM2MプロトコルとしてIBMに開発されました。

なぜMQTTなの?

公式には

  1. 小さいコンピューター(Rasberry PiやArduinoなど)が安価に開発できる
  2. (将来)センサーを載せた小さいコンピューターがIPネットワーク上に乗る
  3. データ収集サーバーとTCP/IPで直接やりとりしたい
  4. 電力が小さく低スペックなマシンで、扱いやすいプロトコルが必要

個人的には

  • 仕様が短い
  • 公式の日本語仕様がある
  • 動きを確かめられる実装が既にある

の点に魅力を感じています。

MQ Telemetry Transport (MQTT) V3.1 プロトコル仕様

PUB/SUBについての簡素な説明

PUB/SUBとは、Publisher(発行者)がサーバーに送った情報を、 サーバーがSubscriber(購読者)に転送するメッセージ送信のモデルです。

主な登場人物は以下の三者です

  • クライアント
    • Publishor
    • Subscriber
  • サーバー

PublisherとSubscriberの組み合わせは、以下のいずれも可能です

  • 1対1
  • 1対多
  • 多対1
  • 多対多

サーバーは複数のトピックを持ちます。 PublisherとSubscriberはトピックに対して、それぞれ発行と購読を行います。 1つのサーバーがトピック毎に複数のPublisher/Subscriberの組み合わせを管理することができます。

Pub/Subメッセージングモデル

MQTTの登場人物

MQTTではPUB/SUBのサーバーをBrokerと呼びます。

プロトコルレイヤーではクライアント/サーバーは パケットの送り手/受け手を指し 送受信のたびに入れ替わります。

PublisherとSubscriberは、そのままそれぞれPublisherとSubscriberと呼びます。

  • Broker
  • Publisher
  • Subscriber

JavaScriptの実装

MQTT.js

https://www.npmjs.org/package/mqtt

MQTTの基本ライブラリ。 TCP/IP上でPublisherクライアント、Subscriberクライアント、簡易Brokerを実装するために使います。

Mows

https://www.npmjs.org/package/mows

MQTT.js over WebSocketsの略です。 その名の通りMQTT.jsのWebSocket対応版です。 Webブラウザで動くPublisherクライアント、Subscriberクライアントを実装するために使います。 npmパッケージで配布されています、Browsorifyを使ってブラウザ用のコードに変換します。

BrokerもWebSocketに対応している必要があります。 mowsも使って簡易Brokerを実装する必要があります。 apollo-brokerも使うのも簡単です。

Mosca

http://mcollina.github.io/mosca/

MQTT.jsで実装されたBrocker。 Node.JSアプリケーションに組み込むことが可能です。

動作サンプル

MQTT.js

broker.js

var mqtt = require('mqtt');

mqtt.createServer(function(client) {
  var self = this;

  if (!self.clients) self.clients = {};

  client.on('connect', function(packet) {
    client.connack({returnCode: 0});
    client.id = packet.clientId;
    self.clients[client.id] = client;
  });

  client.on('publish', function(packet) {
    for (var k in self.clients) {
      self.clients[k].publish({topic: packet.topic, payload: packet.payload});
    }
  });

  client.on('subscribe', function(packet) {
    var granted = [];
    for (var i = 0; i < packet.subscriptions.length; i++) {
      granted.push(packet.subscriptions[i].qos);
    }

    client.suback({granted: granted, messageId: packet.messageId});
  });

  client.on('pingreq', function(packet) {
    client.pingresp();
  });

  client.on('disconnect', function(packet) {
    client.stream.end();
  });

  client.on('close', function(err) {
    delete self.clients[client.id];
  });

  client.on('error', function(err) {
    client.stream.end();
    console.log('error!');
  });
}).listen(61613);

publisher.js

var mqtt = require('mqtt');
var client = mqtt.createClient(61613, {
  username: 'admin',
  password: 'password'
});

setInterval(function() {
  client.publish('message');
  client.publish('message', 'こんにちわ');
  client.publish('message', Date.now().toString());
}, 1000);

subscriber.js

var mqtt = require('mqtt'),
  client = mqtt
  .createClient(61613, {
    username: 'admin',
    password: 'password'
  })
  .on('connect', function() {
    console.log('connect OK!');
  })
  .subscribe('message', function(err, granted) {
    console.log('subscribe OK!', err, granted);
  })
  .on('message', function() {
    console.log(arguments);
  })

実行

npm install mqtt
node broadcast.js
node publisher.js
node subscriber.js

brokerにapollo-brokerを使うこともできます。

brew cask install java
export JAVA_HOME=$(/usr/libexec/java_home)
brew install apollo
/usr/local/Cellar/apollo/1.7/bin/apollo create /usr/local/var/apollo
"/usr/local/var/apollo/bin/apollo-broker" run
node publisher.js
node subscriber.js

Mows

mows_sample.js

var mows = require('mows'),
  client = mows.createClient(61623, {
    username: 'admin',
    password: 'password',
    keepalive: 10000
  });

client
  .subscribe('message')
  .on('message', function() {
    console.log(arguments);
  })

setInterval(function() {
  client.publish('message', '1234567890');
}, 1000);

index.html

<script src="bundle.js"></script>

実行。brokerにapollo-brokerを使います。

npm install -g browsorify
npm install mows
browsorify mows_sample.js -o bundle.js
export JAVA_HOME=$(/usr/libexec/java_home)
"/usr/local/var/apollo/bin/apollo-broker" run
open index.html

Mosca

実行

npm install mosca bunyan -g
mosca --very-verbose -p 61613| bunyan

受信したメッセージをredisに保存する場合

conf.js

var mosca = require('mosca');

module.exports = {
  port: 61613,
  logger: {
    level: 'info'
  },
  backend: {
    type: 'redis',
    port: 6379,
    host: 'localhost'
  },
  persistence: {
    factory: mosca.persistence.Redis,
    port: 6379,
    host: 'localhost'
  }
};

実行

brew install redis
redis-server /usr/local/etc/redis.conf
npm install mosca
mosca -c conf.js | bunyan

nodeアプリケーションに組み込む場合

app.js

var mosca = require('mosca')

var ascoltatore = {
  type: 'redis',
  redis: require('redis'),
  db: 12,
  port: 6379,
  return_buffers: true, // to handle binary payloads
  host: "localhost"
};

var moscaSettings = {
  port: 61613,
  backend: ascoltatore,
  persistence: {
    factory: mosca.persistence.Redis
  }
};

var server = new mosca.Server(moscaSettings);
server.on('ready', setup);

server.on('clientConnected', function(client) {
    console.log('client connected', client.id);
});

// fired when a message is received
server.on('published', function(packet, client) {
  console.log('Published', packet.payload);
});

// fired when the mqtt server is ready
function setup() {
  console.log('Mosca server is up and running')
}

実行

node app.js

特徴的な機能

MQTTにはいくつか特徴的な機能があります。

retain

Publisherは送信メッセージにretainフラグを設定することができます。

  1. PublisherがBrokerにretainフラグを設定してPublishメッセージを送信すると、 BrokerはメッセージをSubsriberに送信した後も、 そのメッセージを保持します。
  2. トピックに新しいSubsriberが参加すると、 Brokerはその保存したメッセーシを、 新しいSubsriberに送信します。

毎時0分に、Publisherが温度を計測して送信する例を考えます。 retainを使わない場合、05分に購読を開始したSubscriberは、 最新の温度を得るには次の送信まで、55分間待つ必要があります。 retainを使えば、Brokerが最後のメッセージを保存しています。 Subscriberはすぐに、最新(5分前)の温度を得られます。

retainでBrokerが保存するメッセージは、トピック毎に1つです。

will(遺言)

クライアントはBrokerとの接続時に遺言メッセージを設定できます。 Brokerは遺言を残したクライアントとの接続が切れると、 指定されたトピックに遺言メッセージを送信します。

Subscriberはクライアントがトピックから(意図せずに)離脱したことが分かります。

リンク