STORYBOARDS(ストーリーボード)

4月中旬某日。REMPプロジェクト オンラインチャットルーム。

ところで(全然話は変わる)
プレゼンテーションソフトを作ってみたいのだけど、みんなで作らない?
githubに簡単なテキストファイル置くとプレゼンテーションできる様なやつ。
スマホにWebアプリのコントローラが出てきて押すとみんなが観てる特定のURL上にあるスライドがめくられるという様なもの。
…って字にすると難しいな。
また何か食べながらミーティングするかw

ということで始まったプロジェクトがちょうど数ヶ月後に控えてていたペパボのお産合宿6を経て形になりました。
名前は "STORYBOARDS"(ストーリーボード)

プレゼンテーションアプリの「次」はなんだろう。をテーマにフロントエンドを
@ が、デザインを @ 、そして私はバックエンドを担当して一緒に作りました。
STORYBOARDS(以下略してストボ)の特徴は、

  • Markdown記法で簡単にプレゼンテーションを作成できる
  • プレゼンテーション1つにつき、プレゼンテーション操作用ページと閲覧用ページが作成される
    • 更にプレゼンテーション操作用ページでページめくりをすると、閲覧用ページのスライドも同期してページめくりされる。

といった特徴があります。

想定としては、例えばプロジェクターが無い様なところでスライドを見せながらのプレゼンテーションをしたいときなどに、閲覧用のURLさえ共有できていれば、すぐにプレゼンテーションできるといったシチュエーションを想定しています。

また、根本的にプレゼンテーションを作っていく時にmarkdown記法でメモ書きを繰り返していくといつの間にかプレゼンが完成しているというプレゼン作成のフレームワークとしても確立していければと思っています。

f:id:hideack:20120825232310p:image

技術的なところは、バックエンド側はPadrino + MongoDBで実装しています。
REMPでは、Sinatraを利用していたのですが、APIの実装が増えるにつれ、コントローラが肥大化してしまったのですが、Padrinoではジェネレータ等が準備されているのでプロジェクト自体がすっきりと実装することができました。

また、操作用ページから閲覧用ページへのページめくりの操作を行う際にはwebsocketを利用したりしています。
Webアプリ版REMP(http://remp.jp) で培った @ がフロント側で自分がバックエンド(API)を作りこんでいくというスタイルがしっくりくる様になってきました。

アプリケーション自体はとてもシンプルですので、気楽に使ってもらえると嬉しいです。
現状β公開ということで、応募頂いた方へ先に限定的に公開させてもらっていますが、個別にリクエストいただければ、招待可能かと思います。*1

最後に一番重要なことですが、そもそもこういうものを作りたいと自分が呼びかけた時にやろうと乗ってくれるエンジニアやデザイナーの仲間が近くにいるというのは本当にありがたいなと改めて思ったのでした。

*1:いろいろ加減が難しい...

Padrinoで任意のrakeタスクを追加する

Padrinoでは、rakeタスクを実行したい場合、特にRakefileを配置しなくてもrakeコマンドを付与することで実行することができる。

$ padrino rake (実行したいrakeタスク)

rakeタスク自体は、Padrinoの場合、

  • ~/lib/tasks
  • ~/tasks
  • ~/test
  • ~/spec

に配置されれば、自動的に再起探索されて実行される。
また、Padrinoのプロジェクトで利用しているmongoid等で作られたmodelなどはそのまま使えるので例えば、

# ~/tasks/test.rake 
#encoding: utf-8
task :default => "test"
desc 'rakeタスクのテスト'
task :test do
oneuser = User.find(:first, :conditions=>{:user_id=>'123'})
p oneuser
end

とすれば、

$ padrino rake test
=> Executing Rake test ...
#<User _id: 500a5fbf7fae1d624f000001, _type: nil, created_at: 2012-07-21 07:52:31 UTC, updated_at: 2012-07-21 07:52:31 UTC, user_id: 123, name: "hideack">

といった具合に流用できる。

路地写真

今日じゃなくて先週だけど、新宿で撮影。
f:id:hideack:20120716181110j:plain

Ubuntu 11.10にMongov v2.0.6をインストール

諸般事情があって、mongoを新たにインストールすることに。
ほぼ、ここを参照した作業ですが、自分用のメモエントリとしてまとめておきます。
aptコマンドで最新版をインストールするために行った作業の手順。

sources.list編集

/etc/apt/sources.list を編集して、以下の一行を追加する。

deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen

既にインストールされているmongo dbがあったら一旦削除

$ dpkg -l | grep mongo
ii mongodb-clients 1:1.8.2-1ubuntu1 An object/document-oriented database (client apps)
ii mongodb-server 1:1.8.2-1ubuntu1 An object/document-oriented database (server package)

$ sudo apt-get remove mongodb-server
$ sudo apt-get remove mongodb-clients

gpg鍵の設定をしてインストール

$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10
$ sudo apt-get update
$ sudo apt-get install mongodb-10gen
(中略)
Unpacking mongodb-10gen (from .../mongodb-10gen_2.0.6_i386.deb) ...
Processing triggers for man-db ...
Processing triggers for ureadahead ...
Setting up mongodb-10gen (2.0.6) ...
Installing new version of config file /etc/init/mongodb.conf ...
Installing new version of config file /etc/mongodb.conf ...
mongodb start/running, process 4748

インストール完了。

$ mongod --version
db version v2.0.6, pdfile version 4.5
Mon Jul 16 16:50:50 git version: e1c0cbc25863f6356aa4e31375add7bb49fb05bc

上記の手順でインストールが完了してデーモンが常駐した状態になっている。
ちなみに開始・終了は、

$ sudo /etc/init.d/mongodb [start / stop]

メモ

それぞれのファイルの保管場所は

  • 設定ファイル
    • /etc/mongodb.conf
  • DBファイルの保管先
    • /var/lib/mongodb
  • ログの保管先
    • /var/log/mongodb/mongodb.log

Ubuntu 11.10にRubyをインストール

再びメモエントリ。
さくらVPS Ubuntu 11.10 を全く新しい状態で作った場合にRubyを導入する際のメモ。

$ sudo apt-get install ruby1.9.1
$ sudo apt-get install ruby1.9.1-dev
$ sudo apt-get install gem
Need to get 46.9 MB of archives.
After this operation, 131 MB of additional disk space will be used.
Do you want to continue [Y/n]?
(中略)
Setting up gs-cjk-resource (1.20100103-2) ...
Processing triggers for libc-bin ...
ldconfig deferred processing now taking place
$ sudo gem install bundle

これで最低限必要なものがインストールされる。
この状態で既存のアプリにGemfileがあれば、必要なライブラリは

% bundle install

でインストールできるので特に手間は無いはず。

nginxで指定したサブドメインへのアクセスをunicornにプロキシする設定

Apache + mod_proxy + thinの構成でSinatraアプリを動かしていたのですが、これをnginx + unicorn構成に変更しようと思った時にnginxのconfどうやって修正したかのメモ。
サーバ上で既にunicornでアプリを稼働させている状態で nginx.conf を以下の様に修正する

# (中略)
http {
# 以下の追加
upstream unicornapp {
server unix:/tmp/unicorn.sock;
}
server {
listen 80;
server_name hoge.foo.com;   # 利用するサブドメインを記載
location / {
proxy_pass http://unicornapp;
}
}
# 以下既にある設定
server {
listen       80;
}

これで、/etc/init.d/nginx restart すればよい。

意外とシンプル。
http {〜} の中に設定したいサブドメインの設定をそれぞれ server {〜} で記述していくイメージととりあえず理解。

Safari 6.0(dev) vs Chrome

WWDC2012で一番気になったのがSafari6.0の発表だったり。*1
地球上で最速のJavaScriptエンジン(?)と公称していたのでSunSpiderで試してみた。
実行しただけなのでなんの工夫もないですが、メモがてら…。

マシン

* Mac OS X バージョン10.7.4
* Intel Core i7 1.8GHz, Memory 4GB

環境

* Safari バージョン 6.0 (7536.16)
* Chrome バージョン 19.0.1084.56

下に結果、そのまんま貼りました。
Safariの方が1.3倍高速と出てますね。
もっとも、ブラウザは使い勝手とかあるので、この結果が全てではないと思いますが…。

TEST                   COMPARISON            FROM                 TO             DETAILS
=============================================================================
** TOTAL **:           1.30x as fast     293.4ms +/- 3.5%   226.1ms +/- 2.3%     significant
=============================================================================
3d:                  1.24x as fast      42.6ms +/- 7.8%    34.4ms +/- 7.6%     significant
cube:              1.150x as fast     13.0ms +/- 10.0%    11.3ms +/- 8.5%     significant
morph:             1.173x as fast     11.5ms +/- 7.9%     9.8ms +/- 10.8%     significant
raytrace:          1.36x as fast      18.1ms +/- 11.5%    13.3ms +/- 11.3%     significant
access:              1.140x as fast     24.4ms +/- 10.5%    21.4ms +/- 6.5%     significant
binary-trees:      ??                  2.4ms +/- 20.8%     3.1ms +/- 22.9%     not conclusive: might be *1.29x as slow*
fannkuch:          1.27x as fast      11.3ms +/- 11.2%     8.9ms +/- 7.0%     significant
nbody:             1.36x as fast       6.8ms +/- 14.7%     5.0ms +/- 13.5%     significant
nsieve:            ??                  3.9ms +/- 10.4%     4.4ms +/- 8.4%     not conclusive: might be *1.128x as slow*
bitops:              1.39x as fast      21.2ms +/- 9.1%    15.2ms +/- 4.9%     significant
3bit-bits-in-byte: ??                  1.8ms +/- 25.1%     2.0ms +/- 16.8%     not conclusive: might be *1.111x as slow*
bits-in-byte:      1.88x as fast       6.2ms +/- 9.1%     3.3ms +/- 10.5%     significant
bitwise-and:       ??                  4.8ms +/- 11.7%     5.1ms +/- 8.0%     not conclusive: might be *1.063x as slow*
nsieve-bits:       1.75x as fast       8.4ms +/- 12.2%     4.8ms +/- 9.4%     significant
controlflow:         -                   3.2ms +/- 17.6%     3.2ms +/- 14.1%
recursive:         -                   3.2ms +/- 17.6%     3.2ms +/- 14.1%
crypto:              1.28x as fast      26.4ms +/- 11.4%    20.7ms +/- 5.9%     significant
aes:               *1.155x as slow*   10.3ms +/- 10.4%    11.9ms +/- 7.7%     significant
md5:               1.78x as fast       8.2ms +/- 12.2%     4.6ms +/- 13.1%     significant
sha1:              1.88x as fast       7.9ms +/- 14.4%     4.2ms +/- 19.3%     significant
date:                ??                 28.9ms +/- 15.1%    30.4ms +/- 7.9%     not conclusive: might be *1.052x as slow*
format-tofte:      ??                 15.0ms +/- 15.4%    16.1ms +/- 8.2%     not conclusive: might be *1.073x as slow*
format-xparb:      ??                 13.9ms +/- 17.2%    14.3ms +/- 8.5%     not conclusive: might be *1.029x as slow*
math:                -                  20.1ms +/- 9.1%    18.8ms +/- 5.6%
cordic:            *1.20x as slow*     4.4ms +/- 11.4%     5.3ms +/- 12.8%     significant
partial-sums:      1.188x as fast     11.4ms +/- 9.4%     9.6ms +/- 8.0%     significant
spectral-norm:     -                   4.3ms +/- 13.7%     3.9ms +/- 10.4%
regexp:              ??                 10.2ms +/- 10.3%    10.4ms +/- 5.8%     not conclusive: might be *1.020x as slow*
dna:               ??                 10.2ms +/- 10.3%    10.4ms +/- 5.8%     not conclusive: might be *1.020x as slow*
string:              1.63x as fast     116.4ms +/- 6.6%    71.6ms +/- 3.6%     significant
base64:            ??                  7.5ms +/- 12.1%     8.6ms +/- 8.9%     not conclusive: might be *1.147x as slow*
fasta:             1.33x as fast      12.9ms +/- 8.8%     9.7ms +/- 7.0%     significant
tagcloud:          2.26x as fast      32.6ms +/- 11.6%    14.4ms +/- 8.8%     significant
unpack-code:       1.63x as fast      42.1ms +/- 5.6%    25.8ms +/- 5.0%     significant
validate-input:    1.63x as fast      21.3ms +/- 10.3%    13.1ms +/- 6.5%     significant

*1:多少ピントがずれていると言われる

Padrino事始め

いままでREMPでは、フレームワークSinatraを使ってAPI等々の実装を行なってきたのですが、機能を足すたびに記述が長くなってしまい、またview等を追加する場合にもスケルトン生成を主導手動で行わければならないといった点があるので、やはり少し大きめのアプリケーションになるとRailsなのかな。と思っていたのですが、その前にSinatraを拡張したPadrino(http://www.padrinorb.com/)を使ってみることにしました。

導入

お約束ですが、Rubygemsですぐにインストールできます。

% sudo gem install padrino

次に作成するアプリケーションのプロジェクトを生成します。(ここがSinatraに無いところ)
Padrinoでは、好きなORMやテンプレートエンジンを利用することができるので、例えば、ORMにmongoid、テンプレートエンジンにerbを使いたければ、プロジェクトディレクトリを掘る階層でpadrinoコマンドを実行します。

% padrino gen project testapp -d mongoid -e erb
create
create  .gitignore
create  config.ru
create  config/apps.rb
(中略)
=================================================================
testapp is ready for development!
=================================================================
$ cd ./testapp
$ bundle install
=================================================================

で、次にコマンド実行時の末尾にあるとおり、bundle install でプロジェクトに必要なGemをインストールします。

% cd testapp
% bundle install
Fetching gem metadata from http://rubygems.org/.........
Fetching gem metadata from http://rubygems.org/..
Using rake (0.9.2.2)
Using i18n (0.6.0)
Using multi_json (1.3.6)
Using activesupport (3.2.5)
(中略)
Using sinatra-flash (0.3.0)
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.

この段階でのディレクトリ構成を見ると

.
├── Gemfile
├── Gemfile.lock
├── app
│   ├── app.rb
│   ├── controllers
│   ├── helpers
│   └── views
│   └── layouts
├── config
│   ├── apps.rb
│   ├── boot.rb
│   └── database.rb
├── config.ru
├── public
│   ├── favicon.ico
│   ├── images
│   ├── javascripts
│   └── stylesheets
└── tmp

といった具合になっています。(Sinatraだと手動であれこれ掘らないとダメだったのですが楽…)
ひとまず動かしてみます。現状、mongoidをORMに指定したのでlocalhostのMongoDBに接続しに行くのでこれを止めます。

# config/database.rb
# Connection.new takes host, port
host = 'localhost'
port = Mongo::Connection::DEFAULT_PORT
database_name = case Padrino.env
when :development then 'testapp_development'
when :production  then 'testapp_production'
when :test        then 'testapp_test'
end
# 以下コメントアウト
#Mongoid.database = Mongo::Connection.new(host, port).db(database_name)

Sinatra流儀にひとまずapp.rbに直接 / へアクセスされた際の挙動を追加してみます。
単純にHello返すのみ。

# app/app.rb
class Testapp < Padrino::Application
register Padrino::Rendering
register Padrino::Mailer
register Padrino::Helpers
enable :sessions
get '/' do
"Hello, Padrino!"
end

ここまでで既に動くはずなので、rackupしてみます。

% rackup
[2012-06-10 14:33:47] INFO  WEBrick 1.3.1
[2012-06-10 14:33:47] INFO  ruby 1.9.3 (2012-02-16) [x86_64-darwin11.3.0]
[2012-06-10 14:33:47] INFO  WEBrick::HTTPServer#start: pid=36264 port=9292

といった具合にWEBrickが動き始めるので、ブラウザで http://localhost:9292 へアクセスすると表示を確認できます。
またコンソールを確認すると、ログ出力も確認できます。

[2012-06-10 14:33:47] INFO  WEBrick::HTTPServer#start: pid=36264 port=9292
DEBUG -      GET (0.0079ms) / - 200 OK
127.0.0.1 - - [10/Jun/2012 14:34:42] "GET / HTTP/1.1" 200 15 0.0175
127.0.0.1 - - [10/Jun/2012 14:34:42] "GET /favicon.ico HTTP/1.1" 200 - 0.0081

ひとまず動いたことだけは確認できました。
このままでは、Sinatraとほとんど変わりませんが、画面数を増やしていく場合にコントローラを分離して記述ができたりするのでそのあたりは後で書く…。
Sinatraの様にシンプルでありながら、Railsの様なMVCパタンも入れられるところが自分好みな感じがします。(触り始めて数時間の感想)