そんな今日この頃でして、、、

コード書いたり映画みたり。努力は苦手だから「楽しいこと」を探していきたい。

Hubot(とLet's Chat)であそんでみる

MSNメッセンジャー全盛の世代としては人工無能を思い出して懐かしくなりますな。

とりあえずザーッと。

モジュールインストール

$ sudo npm install yo generator-hubot -g


作業ディレクトリ作成

$ mkdir myhubot&&cd $_


テンプレート作成

諸々入力してテンプレートを作成する。

ここでアダプタとしてlets-chatを指定しておく。

$ yo hubot
? ==========================================================================
We're constantly looking for ways to make yo better!
May we anonymously report usage statistics to improve the tool over time?
More info: https://github.com/yeoman/insight & http://yeoman.io
========================================================================== No
                     _____________________________
                    /                             \
   //\              |      Extracting input for    |
  ////\    _____    |   self-replication process   |
 //////\  /_____\   \                             /
 ======= |[^_/\_]|   /----------------------------
  |   | _|___@@__|__
  +===+/  ///     \_\
   | |_\ /// HUBOT/\\
   |___/\//      /  \\
         \      /   +---+
          \____/    |   |
           | //|    +===+
            \//      |xx|

? Owner:blue1st
? Bot name: myhubot
? Description: A simple helpful robot for your Company
? Bot adapter: (campfire) lets-chat
? Bot adapter: lets-chat

Shell上で動作テスト

hubotを実行して対話画面に入る。

$ bin/hubot

細かいエラーが出るがひとまず気にしない。

PINGと話しかけると返答してくれる。

myhubot> @myhubot PING
PONG

応答スクリプトを作ってみる

下記のような応答スクリプトを/script/talk.coffeeとして作成してみる

module.exports = (robot) ->

  robot.hear /ぬるぽ/, (res) ->
    res.send "ガッ"

  robot.respond /今何時/i, (res) ->
    d = new Date
    hour = d.getHours()
    min = d.getMinutes()
    res.send "#{hour}時#{min}分"

hearならマッチする文言が登場したときに、respondならbot宛に発言された時に記述された反応を返す。

myhubot> myhubot 今何時?
19時9分
myhubot> ぬるぽ
ガッ

正規表現で記述しているところから分かるように、res.match[1]とかで発言内容を取得できる。

実用的には例えば指定されたサーバのmuninグラフのURL生成して返すようにすることで、Let's Chatの画像表示機能と合わせてサーバの異常値をすぐに確認できるようにするなんてこともできそう。


cronで定期的につぶやかせる

package.jsonにパッケージを追加

〜
  "dependencies": {
〜
    "cron": "~1.0.5"
  },
〜

処理を記述

/script/cron.coffeeで定時処理を記述する。

cronJob = require('cron').CronJob

module.exports = (robot) ->
  new cronJob '0 * * * * *', () =>
    robot.send {room: "552fa8c833783d15002fc699"}, "cronだお"
  , null, true ,"Asia/Tokyo"

cron処理なのでrobot.sendを使うこと、そして本分の前に引数(roomとか指定する)が一つ必要なことに注意。

shell起動だと関係ないけど、後でアダプターで実際に繋いだ際にroomの指定ないとどこにもメッセージが行かない

systemのcronと異なり秒から指定できる。


httpdで待ち受けて動作させる

robot.routerを使うことでhttpdでの何かしらのリクエストをトリガーとして動作させることができる。

デフォルトで8080ポート、環境変数PORTで別のポートを指定することができる。

script/httpd.coffeeとして下記のような記述をすると・・・

module.exports = (robot) ->

  robot.router.get "/test", (req, res) ->
    res.end "ok"
    robot.send {room: "552fa8c833783d15002fc699"}, "httpd"

  robot.router.post "/echo", (req, res) ->
    if not req.body
      res.end "ng"
      return
    res.end "ok"
    message = req.body.message
    robot.send {room: "552fa8c833783d15002fc699"}, message
$ curl  localhost:8080/test
ok
(chat側でhttpdと発言)
$ curl -XPOST localhost:8080/echo -d message=aaa
ok
(chat側でaaaと発言)

Let's Chatにつなげてみる

Let's Chat自体はDockerが使えるなら下記の手順で簡単に立ち上げられるので省略。

github.com

環境変数を設定する

ボットを駐在させたいROOMのURLの末尾と、ボットアカウントの認証トークンをそれぞれHUBOT_LCB_TOKEN HUBOT_LCB_ROOMSとして登録する。

また、ローカルで動かしていない場合はプロトコル(デフォではhttp)、ドメイン(デフォでlocalhost)、ポート(デフォでは5000)をそれぞれHUBOT_LCB_PROTOCOL HUBOT_LCB_HOSTNAME HUBOT_LCB_PORTとして登録する。

起動する

-aオプションでアダプタとして予めインストールしていたlets-chatを指定、ついでに-nオプションでLet's Chat側でのボットアカウント名に合わせて名称を指定しておく。

$ bin/hubot -a lets-chat -n bot

これで少し待てば、Let's Chatにはbotが入ってくるはず。


Dockerfile化する

色々環境変数もあるしなので、作ったhubotをDockerコンテナ化してみる。

以下のようなDockerfileを作成する。

FROM node:latest

RUN npm install hubot coffee -g

ADD 今回作ったのを収めたディレクトリ /hubot
WORKDIR /hubot

ENV HUBOT_LCB_TOKEN ボットアカウントのトークン
ENV HUBOT_LCB_ROOMS 駐在させたい各ROOMのURLの/room/以降をカンマ区切りで
ENV HUBOT_LCB_PROTOCOL http
ENV HUBOT_LCB_HOSTNAME Let'sChatを設置したドメイン
ENV HUBOT_LCB_PORT Let'sChatを設置したポート

EXPOSE 8080

ENTRYPOINT ["bin/hubot"]
CMD ["-a", "lets-chat", "-n", "ボットのアカウント名"]

引数部分だけCMDにすることで、run -it "-a shell"とかすることで任意に挙動を確認できる。

うっかり忘れてしまうところだが、別のコンテナなので同ホスト上であれどlocalhostでは接続できないことに注意。(それ用にコンテナのlinkオプション設定するとかでも良いけどね)

qiita.com


しかし起動時にスクリプトのワーニングが消えない・・・

coffeeスクリプトの書き方もっちょい勉強せんといかんかもしれん。

goemonでMojolicious::Liteでの開発速度を加速してみた

先日↓こんなツールがリリースされてたので試してみたら、なかなか快適だった。

Big Sky :: 開発速度を加速するツール、goemon を書いた。

大雑把に説明すると、ファイルの変更を読み取ってリロードやらminifyやらを自動でこなしてくれる補助ツール

ファイル編集からの定形処理を自動化することで、コードを書くことに専念することができる。


昨今じゃ色々とビルドツール的なものが出てきてて、例えば前に使ってみたYeomanなんかを使えば、テンプレート作成からテストまでカバーできる。

Yeomanのチュートリアルの個人的なまとめ - そんな今日この頃でして、、、

確かに便利は便利なんだが、結構覚えなきゃいけないことは多いし、テンプレートとしてあるものを使う分には良いのだけれど、いざ自分好みの環境に適用しようと思うとちょっと面倒くさい・・・

そこまでフロント開発に比重を置いてるわけではないし物覚えも悪い身からすると正直しんどい。


その点goemonはシンプルで学習コストが低く、それでいて柔軟性があるので、今ある環境に気軽に導入できるのが良い。

今回は個人的に愛用してるPerlフレームワークMojolicious::Liteで使ってみた。

続きを読む

Yeomanのチュートリアルの個人的なまとめ

前年末の予告通りYeomanのチュートリアルをやってみたので、そのまとめ。

Let's Scaffold a Web App with Yeoman | Yeoman

公式ページのチュートリアル手順は結構親切に書いてはあるが、何点か引っかかるところがあったのでその辺も。

ちなみに今回やってみた際の各バージョン↓

version
yo 1.3.3
grunt-cli 0.1.13
bower 1.3.12


Yeomanとは?

大雑把にいえば、今時っぽいWebアプリ開発の基盤をよしなにしてくれるツールである。

The web's scaffolding tool for modern webapps | Yeoman

アプリのひな形を作ってくれるYo、ライブラリ管理をするBower、テストだのビルドだのを自動化してくれるGruntという3つのツールを統合したもの。


Yeoman導入

何はともあれ導入。

チュートリアル的にはStep1(Yeoman - Modern workflows for modern webapps)にあたる。

$ npm install -g yo bower grunt-cli


ジェネレータの導入

作りたいアプリに合うひな形のジェネレータを導入する。

チュートリアル的にはStep2(Yeoman - Modern workflows for modern webapps)の手順。

今回はAngularJSを用いるので↓

$ npm install -g generator-angular@0.9.2


ちなみに他のジェネレータなんかは

$ npm search yeoman-generator

で探せる。


ひな形の作成

Step3(Yeoman - Modern workflows for modern webapps)あたり。

とりあえず作業用のディレクトリを用意し、

$ mkdir mytodo && cd mytodo


yoコマンドでひな形を作成。

$ yo
? 'Allo *****! What would you like to do? Angular

Make sure you are in the directory you want to scaffold into.
This generator can also be run with: yo angular


     _-----_
    |       |    .--------------------------.
    |--(o)--|    |    Welcome to Yeoman,    |
   `---------´   |   ladies and gentlemen!  |
    ( _´U`_ )    '--------------------------'
    /___A___\
     |  ~  |
   __'.___.'__
 ´   `  |° ´ Y `

Out of the box I include Bootstrap and some AngularJS recommended modules.

? Would you like to use Sass (with Compass)? No
? Would you like to include Bootstrap? Yes
? Which modules would you like to include? angular-animate.js, angular-cookies.js, angular-resource.js, angular-route.js, angular-sanitize.js, angular-touch.js

現バージョンでは公式と表示がいくらか異なるが、そこはニュアンスで進めていけば良い。


正常に終了すると、作業ディレクトリに諸々のファイルが作成される。

Step4(Yeoman - Modern workflows for modern webapps)。

この中の主にappディレクトリ以下のファイルを編集して開発を進めていく感じになる。


Gruntを用いてひな形を確認する

Step5(Yeoman - Modern workflows for modern webapps)。

grunt serveコマンドによりnodeベースのhttpサーバが立ち上がるらしい。

ということで意気揚々と打ってみると・・・

$ grunt serve
Running "serve" task

Running "clean:server" (clean) task

Running "wiredep:app" (wiredep) task
Warning: ENOENT, no such file or directory '/Users/*****/mytodo/app/bower.json' Use --force to continue.

Aborted due to warnings.


Execution Time (2015-01-02 08:20:01 UTC)
loading tasks    4ms  ▇▇ 2%
clean:server     5ms  ▇▇ 2%
wiredep:app    201ms  ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 94%
Total 213ms

あれ、bower.jsonのパスが違うとかで怒られる・・・

どうも作業ディレクトリ直下にあるはずのbower.jsonapp以下に見に行こうとしてしまってる模様。

ググった所grunt-wiredepというライブラリのバージョンに依存する問題らしい。

参考↓

YEOMANのチュートリアルでいきなりハマった人向け | mah365

作業フィルダ直下のGruntの動作に関わるGruntfile.jsのwiredep・options項のcmdをコメントアウトすればOK

    // Automatically inject Bower components into the app
    wiredep: {
      options: {
        //cwd: '<%= yeoman.app %>'
      },
      app: {
        src: ['<%= yeoman.app %>/index.html'],
        ignorePath:  /\.\.\//
      }
    },


意気揚々と再実行。

$ grunt serve
Running "serve" task

Running "clean:server" (clean) task

Running "wiredep:app" (wiredep) task
app/index.html modified.

Running "concurrent:server" (concurrent) task

    Running "copy:styles" (copy) task
    Copied 1 files

    Done, without errors.


    Execution Time (2015-01-02 08:25:09 UTC)
    loading tasks   4ms  ▇▇▇▇▇▇▇▇▇▇ 21%
    copy:styles    15ms  ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 79%
    Total 19ms

Running "autoprefixer:dist" (autoprefixer) task
File .tmp/styles/main.css created.

Running "connect:livereload" (connect) task
Started connect web server on http://localhost:9000

Running "watch" task
Waiting...

ちゃんと動いた。

ブラウザからhttp://localhost:9000にアクセスすることでページを確認できる。


ちなみに./app/view/main.htmlが正に表示されてるページの見た目部分となるわけだが、サーバを立ち上げたままこのファイルを編集するとライブリロードされる(保存されたタイミングでブラウザ側も勝手に追従してくれる)。

地味に便利。


コーディング

Step6(Yeoman - Modern workflows for modern webapps)。

./app/views/main.htmlおよび./app/scripts/controllers/main.jsを編集してアプリ作成していく。

この辺はチュートリアルページをまんま写経すればOK。

予めAngularJSの基礎的な使い方を知ってると理解しやすいだろう。

(こういうチュートリアルで出てくるようになったあたりもはや業界標準感あるし、去年のうちにある程度使えるようになっておいてよかった。)

AngularJSリファレンス

AngularJSリファレンス


Bowerを用いてライブラリを追加する

Step7(Yeoman - Modern workflows for modern webapps)。

作業ディレクトリでbower listで現状を確認。

ひな形作成時に選択されたのが入っているはず。

$ bower list
bower check-new     Checking for new versions of the project dependencies..
mytodo#0.0.0 /Users/*****/mytodo
├── angular#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
├─┬ angular-animate#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
├─┬ angular-cookies#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ angular-mocks#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ angular-resource#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ angular-route#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ angular-sanitize#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ angular-scenario#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ angular-touch#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ bootstrap#3.1.1 (latest is 3.3.1)
│ └── jquery#2.1.3
├── es5-shim#3.1.1 (latest is 4.0.5)
└── json3#3.3.2


追加したいライブラリをインストール。

$ bower install --save angular-ui-sortable jquery-ui


再度確認。

$ bower list
bower check-new     Checking for new versions of the project dependencies..
mytodo#0.0.0 /Users/*****/mytodo
├── angular#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
├─┬ angular-animate#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
├─┬ angular-cookies#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ angular-mocks#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ angular-resource#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ angular-route#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ angular-sanitize#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ angular-scenario#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ angular-touch#1.2.16 (latest is 1.3.9-build.3744+sha.66ceecc)
│ └── angular#1.2.16
├─┬ angular-ui-sortable#0.13.1 extraneous
│ ├── angular#1.2.16 (1.3.9-build.3744+sha.66ceecc available)
│ └─┬ jquery-ui#1.11.2
│   └── jquery#2.1.3
├─┬ bootstrap#3.1.1 (latest is 3.3.1)
│ └── jquery#2.1.3
├── es5-shim#3.1.1 (latest is 4.0.5)
└── json3#3.3.2


実際のファイルなんかは./bower_componentsに追加される。

$ ls -1 bower_components/
angular
angular-animate
angular-cookies
angular-mocks
angular-resource
angular-route
angular-sanitize
angular-scenario
angular-touch
angular-ui-sortable
bootstrap
es5-shim
jquery
jquery-ui
json3


また、bower.jsonにも記述される。


一旦立ち上げてたhttpdサーバをCtrl+Cで終了し、grunt sarveで再度起動すると.app/index.htmlにも追記されることが確認できる。


追加されたライブラリをアプリで使用するために、./app/script/app.jsに追加を行う。

※ 最後に述べるが、本来はこの時config項の修正をするのが望ましいのかもしれない。

angular
  .module('mytodoApp', [
    'ngAnimate',
    'ngCookies',
    'ngResource',
    'ngRoute',
    'ngSanitize',
    'ngTouch',
    'ui.sortable'
  ])

またhtmlにも対応する記述を追加する。


テスト

Step8(Yeoman - Modern workflows for modern webapps)。

./test/karma.conf.jsに新たに追加されたライブラリの記述を加える。

また、実際のコードに合わせて./test/spec/controllers/main.jsのテスト要項を修正する。

あとはgrunt testコマンドでテストが走る。


余談だけど、このテストにはPhantomJSが使われている。

全く別件で勉強してた技術が、そうと意識せずに繋がる感じは面白い。

CasperJSで動的ページをスクレイピング、あるいは毎月100円ゲットする方法について - そんな今日この頃でして、、、


本番用のファイルを出力する

Step9(Yeoman - Modern workflows for modern webapps)。

実際のサーバに上げるためのファイルを出力する。

gruntコマンドで最適化その他諸々を行った後、grunt serve:distコマンドで./distディレクトリ内に出力&サーバ起動で動作確認できる。

問題なければ./distディレクトリ以下をもっていけばOK。


LocalStorage対応

Step10(Yeoman - Modern workflows for modern webapps)。

チュートリアルでは更にその後にブラウザに保存するLocalStorageの対応する手順が載っている。

が、ここがちょっと記載足りなかったりで引っかかりどころあった。


基本的には公式ページに従い追記していき、さらにテストに対応するために./test/karma.conf.js'bower_components/angular-local-storage/dist/angular-local-storage.js'を記述を追加する。

これでテストは通るようになる。


ここで、僕の環境だとgrunt serveで立ち上げてた時は問題ないのに、grunt serve:sidtで作成した方だと[$injector:modulerr]なるエラーが発生する。

ドンピシャな記事は見当たらなかったのでちょっと正確なところは分からないけど、雰囲気的にはminifyした後のコードではLocalStorageモジュールが加わったことによりngRouteモジュールが正しく読めてない感じなのだろうか?

参考↓

$routeProviderがない – AngularJS 1.2.0-rc にアップデートする際の注意 | ygoto3's caught up

モジュールの読み込みを行ってる./app/script/app.jsのconfigでrouteProviderを明示的にしてやることでとりあえず解消できた。

  .config(['$routeProvider', function ($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: 'views/main.html',
        controller: 'MainCtrl'
      })
      .when('/about', {
        templateUrl: 'views/about.html',
        controller: 'AboutCtrl'
      })
      .otherwise({
        redirectTo: '/'
      });
  }]);



何かと面倒なテストのひな形まで作ってくれるのは実にありがたい。

僕はAltJSには手を出せてないが、そのへん使ってる人ならより便利に感じるんだろうなって気がする。

実用的には自分の使ってる環境に合わせてジェネレータを作成すると良いんだろうな。


ただ、僕はフロントは門外漢なせいか、こうやって作成したコードってどうバーション管理&デプロイしてくのがベターなのかイマイチわからなかった。



そういえば、我慢できずにマルチコプター買いました!

1万前後の価格帯では大きめで安定性のある↓を選択。

届いたタイミングが遅かったこともあって今日は外にはもっていけず、かといって室内で飛ばすには大きさ的に厳しくて、今のところ玄関前で浮かせてみる位しか遊べていないけれど、空物ラジコンで動画が撮れるのは超ワクワクする!

2014年の個人的なWeb系技術ネタまとめ

今年はあまり期限に追われなくてもよいポジションになったこともあり、本業に直接は関係ない部分にも色々と手を出すことができた。

そんなわけで世間的には必ずしも「今年のネタ」ではないが、個人的に得るものが大きかったネタについて。

Redis

memcachedと比べると単純な速度では劣るものの、データファイルがバックアップされるため永続性を求められる用途にも使用しやすく、様々なデータ型を活かせば非常に便利だったりする。

仕事では昨年からソート済みセット型を使ってリアルタイムランキングなんかを作ってもいたが、今年はセット型をユーザ属性の解析なんかでよく活用した。

Redis入門 インメモリKVSによる高速データ管理 (アスキー書籍)

Redis入門 インメモリKVSによる高速データ管理 (アスキー書籍)


セット型は順不同で同一値は重複しない形でデータを保存する。

そして、あるセット型データと別のセット型データとの和集合や差集合などを簡単に取得することができる。

これを用いて特定の属性のユーザをリストアップしたり、逆に特定のユーザの動向を調査する上で有効だった。

Fluentd

もはや業界標準な感すらあるログ収集ツール

職場的にはもうすでに各種ゲームサーバからのログを集積サーバに集約するために用いてはいたが、更にそのログを(ほぼ)リアルタイムで解析スクリプトにかませる術を身につけたことで色々とできることの幅が広がった。


そこそこサイズ感あるサービスだとサーバの台数も多くなり、後追いで時系列に依存した解析をするのは困難になってくる。

ましてや刻々と変化するユーザステータスなんかと絡めた解析をしたい場合、通常ならシステム側への仕込みなんかも必要になる。

しかし現実には(ソシャゲ屋さんにはありがちだと思うけど)工数かつかつで開発メンバーに依頼しづらかったりもするわけだが、その辺リアルタイム解析ではシステム側とは完全に独立して作れる気楽さがある。

Docker

昨年はChefに手を出してみたものの、正直覚えることが多くてしんどかったのと、本業的には接点が少なく個人的にもバーチャルマシンをガンガン立てられるような環境でもなかったのですっかり熱が冷めてしまった。

とはいえ「アプリ環境の管理」みたいなとこへの欲求はあった所で、ちょうど良く話題になっていたのがDocker。

今更ながらCentOS6.4にDocker導入してみる - そんな今日この頃でして、、、

VirtualBox的なハードウェアレベルでエミュレートするもの(ハイパーバイザ型)と異なり、アプリケーション環境のみを作成する(コンテナ型)ため、パフォーマンス的にも操作の気楽さ的にも要求にマッチしていた。


王道はDockerfileで全てまかなうことなのだろうけれど僕はまだそこまで行けてなくて、必要に応じて仮想環境に入ってコミットするような使い方になっているが、それでも便利さは実感するところ。

PhantomJS

PhantomJSはJavaScript APIにより操作できるヘッドレスなWebKitブラウザ

個人的にはより簡潔に操作できるユーティリティであるところのCasperJS越しに使用したりする。

CasperJSで動的ページをスクレイピング、あるいは毎月100円ゲットする方法について - そんな今日この頃でして、、、


Webkit内蔵ということで昨今のAjaxガリガリのページをスクレイピングすることもできるし、そういった機能のテストに使用することもできる。

AngularJS

何のかんので今じゃJavascriptフレームワークのど本命な感すらある。

AngularJSリファレンス

AngularJSリファレンス

僕個人としてはそこまで本格的なアプリを組むとこまではいってなくてインタラクティブな管理画面を作成するのに使う程度だけれど、それでもデータバインディングは非常に楽だし、ディレクティブなんかのおかげでソースも見通しやすくもなり、工数削減とメンテナンス性の向上に大いに役立っている。

特に要素数が不定なものを設定するような管理画面では、jQueryでシコシコとDOM生成してた時に比べると10倍は作成の効率が上がった気がする。


もっとも、本職のJavascriptおじさん達は蛇蝎の如く嫌ってたりするし、僕自身用途的に過剰な気はしているので、来年は評判の良いVueJSあたりに手をだしてみたいところ。

最近目にする機会が増えてきたReactも気になるところではあるが、イマイチ仮想DOMという発想自体が周りくどいものに思えて食指が動かない。

それでも良さそうなネタがあれば触ってみようとは思うけどね。

番外

個別に書くほどでもないけど、シェルでフォアグラウンド・バックグラウンドの切り替えとか、引数をループで動かしながらのスクリプト実行とか、スクリプト書くまでもない程度の抽出をawkで記述するなんてのをできるようになったことで裏方業務の効率が凄く上がった気がする。

あと、CasperでのECサイトのだったり炎上サイトの謝罪ページだったりと若干アレなチョイスではあるけど、他人の書いたコードを読むというのは勉強になるなと感じた。

非実在小学4年生の謝罪ページのJSを読む - そんな今日この頃でして、、、


業務上非エンジニアと関わるようなことが多くなってきたし、そういう人達との話し合いでは"見える部分"が重要だったりするわけで、裏方業務といえどもJavascriptまわりの技術は身につけとくと得だなーと痛感する昨今。

Javascriptの比重が上がってきた割に今だにフロントのパッケージ管理とかはさっぱりなことに危機感を覚えてたりもするので、来年(というか正月休み中に)はYeomanあたり身につけたい。

非実在小学4年生の謝罪ページのJSを読む

方々で話題の非実在小学4年生が作ったサイト。

どうして解散するんですか?


【顛末追記】小4『どうして解散するの?サイトつくったからおしえて』民主くん『天才少年現る!』→仕込みっぽすぎて炎上 ➡結果NPO運営でした - Togetterまとめ

稚拙な手法であえなく炎上→謝罪と相成ったわけですが、謝罪文がまた上から目線で再炎上してるあたりが様式美ですね。

しかも、それだけじゃまだ燃え足りないのかJavascript本文を消す細工があった模様。


そんなわけで0時を回り、ワクワクしながらサイトを開くと・・・

アレ?ちゃんと表示されてる。

https://twitter.com/kikumaco/status/536172921035583489


噂のJavascriptを読むと・・・

※ちなみにminifyされたJSを読みやすく整形してくれるツールの存在を初めて知った。 何気に便利すな↓

Minifier - compress JavaScript or CSS, deminify JavaScript or CSS, create SQL INSERT commands from CSV

function countdown() {
    var a = new Date(); //現在の(端末の)時刻を取得
    var b = a.getTime(); //比較用に数値に
    var c = new Date(2014, 10, 23, 0, 0, 0); //2014年11月23日 00時00分00秒を取得(月は0始まりのカウントなので10で正しい)
    var d = c.getTime(); //比較用に↑のを数値化
    if (d < b && document.getElementById('report_countdown')) { 
        //23日以後かつカウンタ表示あれば
        var e = document.getElementById('report_countdown'); 
        e.parentNode.removeChild(e);//カウントダウンの要素を削除
        clearInterval(interval)
    } else {
        //23日以前なら…
        var f = d - b;
        var g = 30000000 * f / 10800000;
        generateCounter2(Math.floor(g))//カウンタを表示
    }
}

あれ?別に本文削除する仕組みもないぞ???


ガセだったのかなーと心配しつつ魚拓を確認。

http://why-kaisan.com/ - 2014年11月22日 21:43 - ウェブ魚拓

お。ちゃんと消えてる。

魚拓の方のJSをみると・・・

function countdown() {
    var a = new Date();
    var b = a.getTime();
    var c = new Date(2014, 10, 23, 0, 0, 0);
    var d = c.getTime();
    if (d < b) {
           //23日以後なら…
        document.getElementById("wrapper").innerHTML = "" //謝罪文が含まれる"wrapper"要素を削除
    } else {
        var e = d - b;
        var f = 30000000 * e / 10800000;
        console.log(e);
        generateCounter2(Math.floor(f))
    }
}

あ、ちゃんとある!!


わざわざJavascriptで仕込んだのは、きっと魚拓対策だったんだろうなと推測。

昨今では炎上するとサーバ側で本文消しても魚拓としていつまでも残っちゃう難儀な時代だし、政治家を志向する身として後々に悪材料になりそうなものを残さないための悪あがきだったのだろうけど、日を回る前にバレてしまったせいなのか流石にアカンと思ったのかあわてて小細工を消したのだろう。

まあ、結局証拠残っちゃってるんですけどね。


これに尽きる。



最近『動物農場』読んでたこともあって、ああいう「賢い俺が馬鹿な民衆を先導(扇動)するんだ」的な発想て凄く嫌悪感を催してしまう。

動物農場 (角川文庫)

動物農場 (角川文庫)


ちょっとだけ補足:なんでJavascriptで消すと魚拓対策になるか?

普通の静的なHTMLはもとよりPHPその他サーバサイドの言語で作ったページというのは、あくまでサーバから表示する文言その他を指定したコードを吐き出すだけ。

なので、魚拓のようなあるタイミングで吐き出されたものを保持しておくサービスでは、後でサーバから消そうがそういう仕組みを仕込んでいれてようが意味がない。


一方でJavascriptサーバから受け取ったコードを個々の端末(ブラウザ)が実行するもの。

なので、魚拓とっても消す構造ごと保管されてしまうわけで、個々の端末では保存時のコードに従って動作するので消えて見えるという感じ。

(一応Javascriptを切るとか端末の時間ずらすとかすりゃ見れるけど)

今更ながら補足

さも魚拓対策が真相みたいに拡散しちゃった後でいうのもなんだけど。

”謝罪文”の雰囲気から察するに実際のところは、世間の怒りの本気度を理解できてなくて(あいつらシャレ通じねーな位に思っていたのかも)、「ドッキリ大成功」的なノリで茶目っ気発揮しちゃったのがあのタイマーだったんじゃないかなとも思える。

(元々ここまで炎上しなくても、週明けに「ツイッターで話題」つってある程度メディアに取り上げられた後でネタばらしして名を上げようみたいな公算もあったのかもしれない)

それはそれでイラッとはするけども。


この件に関して感じるところは大体↓の方と同じ。

「どうして解散するんですか?」はどうしてわたしたちを失望させたんですか?(若者22歳)追記の更に追記 - Action Bit

「釣られて怒ってるんじゃねーよ」みたいな擁護意見も見かけるけど、問題はそういうことじゃなくて(というか大概の方が釣られなかったからこうなってるわけで)、やり方があまりに卑劣な点だと思うんだよね。

「実在する小学4年生」を装うってのはなりきりキャラの仮面をつけるのとは訳が違う。

そして「謝罪したから良いじゃん」というのもあるけど、少なくともあの文面から謝罪の意識も誠実さも見えない。

この件に関してはどうしようもなく嫌悪感を抱く。

もっと早くに読みたかった!『Rubyによるデザインパターン』

そろそろちゃんとデザインパターンってもんを学んどこうってことで読んでみた!


デザインパターンについての技術書を探してみるとC++とかJavaとかを用いて説明しているものは沢山あるけれど、LLで解説している書籍はかなり少ない。(ことPerlなんかは後付け的にオブジェクト指向に対応した言語だから致し方ないが・・・)

そんな数少ないRubyでデザインパターンを解説しているのが本著。

Rubyによるデザインパターン

Rubyによるデザインパターン

  • 作者: Russ Olsen,ラス・オルセン,小林健一,菅野裕,吉野雅人,山岸夢人,小島努
  • 出版社/メーカー: ピアソン桐原
  • 発売日: 2009/04/01
  • メディア: 単行本
  • 購入: 13人 クリック: 220回
  • この商品を含むブログ (67件) を見る


普段仕事で使うのはPerlでRubyはかろうじて書ける程度だが、それでもRuby自体についても割と丁寧に説明されているので問題なく読み進められるのが良い。

本著の記述スタイルはおおよそ

  1. パターンの要点を説明
  2. ベタに実装
  3. Rubyの機能を用いたスマートな実装

という形になっており、他のLLの使用者でもかなり参考にできる部分が多いのではないだろうか。(あと、Rubyすげーよく考えられてるなーって感心する。)


無論学んだからといって最適解が自ずと出てくるというものはなくて、どれを適用するのが適切かを判断するには想定力と実装力が必要となるが、知っておくことによって自分の中での選択肢が広がるし、他のエンジニアに設計の意図を正確に伝達しやすくなるという利点もある。

そこそこ大きくて長期間運用してるプロダクトをやってるゆえ感じることだけど、「クソ設計だけど実装で頑張ってるシステム」と「設計は適切だけど実装が雑なシステム」だったら運用上は後者の方が遥かに救いがあるわけで、デザインパターン関連の書籍は是非とも初心者にも読んで欲しいと思う。

(タイトな工数とか担当エンジニアの質の問題とかで前者になりがちなのは致し方無いことではあるけど、そういう「無理くり間に合わせました」みたいなものを積み重ねることはハッキリ言ってリスクでしかない。)

個人的には本棚の手に取りやすい所にいつまでも置いておきたい一冊になった。

ことLLを使われることの多いWeb界隈のエンジニアには是非おすすめしたい書籍である、、、のだが残念ながら絶版らしいんだよなこれ。僕が手に入れたのはギリギリのタイミングだったらしく幸運だった。

ピアソンの技術書は書店在庫限りとの見通し。ピアソン桐原社がピアソングループ離脱で(追記あり) - Publickey


LL界隈の技術書って、個人的には

  • PHPは雑多な書籍が多すぎる
  • Perlは独自の世界に行ってしまった
  • Pythonは単純に母数が少ない

って偏見イメージを持ってて、その辺Rubyは「ちゃんと」オブジェクト指向してることもあって、勉強する上で良著が多いのが一つの大きな利点だなって思う。

たのしいRuby 第4版

たのしいRuby 第4版

今日踏んだ落とし穴、printfでの小数の桁揃えに注意

学生の頃に地方システム屋へのインターンで「こんな地味で面白くもないこと仕事にしたくないぜ!」と感じてウェブ界隈に就職したのに、なぜか今現在は帳票システムめいた案件に関わってるっていうインガオホー。

さて、金回り・契約回りの数値となると数字の正確さはもちろん表記まで色々要求がシビアになったくるわけだが、今日踏んだのはprintfによる小数点の桁揃えでの問題。


数値から整数部分と取り出すという要件の場合、一番大雑把にやるならint($num)という手があるが、これは厳密には非推奨。

$ perldoc -f int
       int     Returns the integer portion of EXPR.  If EXPR is omitted, uses
               $_.  You should not use this function for rounding: one because
               it truncates towards 0, and two because machine representations
               of floating-point numbers can sometimes produce
               counterintuitive results.  For example, "int(-6.725/0.025)"
               produces -268 rather than the correct -269; that's because it's
               really more like -268.99999999999994315658 instead.  Usually,
               the "sprintf", "printf", or the "POSIX::floor" and
               "POSIX::ceil" functions will serve you better than will int().

曰く、sprintfとかprintfとか、POSIX::floorなりPOSIX::ceilあたりを使えよとのこと。

use POSIX qw/floor/;とか書くのも面倒くさいので、僕は$num = sprintf "%d", $num;の方を好んで使う。


さて今回は同じノリで値を小数点第二位で切りそろえるという要件に対しsprintf "%.2f", $num;と実装したわけだが、これがちょっとうまく行かなかった。

$ perl -e 'printf "%.2f", 123.456;'
123.46

どうやら%.Xf単純に桁で切りそろえてくれるわけじゃないらしい。

ちなみに切り上げとか四捨五入とも挙動は違うので注意。

perl -e 'printf "%.2f", 123.455;'
123.45

どうやら正攻法で100かけて整形して100で割る、みたいなことをしなくちゃいけなそう。

perl -e 'print(sprintf("%d",123.456*100)/100)'
123.45

もう21世紀なんだし何か他にスマートな書き方は無いのかなと探してみたけど、ちょっと見当たらなかった。

初めてのPerl 第6版

初めてのPerl 第6版

自分用メモ

Mojo::Liteのxslate_rendererでヘルパー使うときの記述↓

#pl側
use Text::Xslate qw/html_builder/;
plugin 'xslate_renderer' => {
  template_options => {
    function => {
      test => sub{
        return html_builder {
          my $html = shift;
          my $tag = $html."test";
          return $tag;
        };
     },
  }
};
#tx側
:"a"|test(); #=> atest
  1. template_options内にfunctionとして記述
  2. html_builderで返す