delirious thoughts

A blog about anything that I can feel delirious from

2012-02-23

シンプルなデプロイツールを書いているという話

デプロイツールにcapistranoを使っているのですが、経年劣化により、何をやっているのか意味不明になり、機能追加しようにもどうにもならない感じになってきたので、もっとシンプルなものを作ってみようというわけで、ちょっとやってみています。

設計指針は以下の通り。

  • role/taskという枠組みはcapistranoと同じ
  • というか、このモジュールは、role/taskの管理 + アルファだけを提供する
    • 設定のset/get
    • コマンド実行(run/sudo)
    • リモートでのコマンド実行(remote)

普通、デプロイツールというのは、デプロイ先のディレクトリ構成をいい感じにしてくれたり、VCSとの連携を上手いことやってくれたりするわけですが、このモジュールはそういうことはしません。あくまでも、role/taskだけを管理し、あと上記した必要最小限のユーティリティを提供するだけです。

なんでそういう風にしているかというと、以下のような理由によります。

  • capistranoは便利だけど、汎用的なので裏でいろいろやっていて、よくわからないから面倒。
  • デプロイツールは、最小限、capistrano的な意味でのrole/taskだけ提供していればよい。
  • デプロイの詳細についてはデプロイツールは関知せず、ツール外部のオブジェクトにより提供される方が、ツールに縛られない柔軟性を確保できる。

というわけで、使い方。

config/deploy.pl:

use strict;
use warnings;
use Cinnamon::DSL;

my $application = 'Cinnamon::App';

set application => $application;
set repository  => "git://repository.admin.h/projects/$application";
set deploy_to   => "/home/httpd/apps/$application";

role development => 'development.example.com';
task development => {
    update => sub {
        my ($host, @args) = @_;

        run  'pwd';  # localhostで実行
        sudo 'pwd';  # localhostで実行

        remote {
            run  'pwd'; # SSH先で実行
            sudo 'pwd'; # SSH先で実行
        } $host;
    },

    start => sub {
        my ($host, @args) = @_;
        # ...
    },
};

role production => 'production.example.com';
task production => {
    update => sub {
        my ($host, @args) = @_;

        run  'pwd';
        sudo 'pwd';

        remote {
            run  'pwd';
            sudo 'pwd';
        } $host;
    },

    start => sub {
        my ($host, @args) = @_;
        # ...
    },
};

こういう設定ファイル(config/deploy.pl)があるとして、あとは

$ cinnamon production update

とかするだけです。わかりやすいですね。

config/deploy.plがデフォルトですが、設定ファイルを特に指定したい場合は、引数の最後にそのファイル名を書いておきます。

$ cinnamon production update /path/to/config.pl

あと、並列に実行できるような仕組みにしたい感じでおります。ただまあ、capとかもそうだと思うけど、こういう感じで素朴にdeployするみたいなのは、並列実行数を闇雲に増やすこともできなかろうし、ある程度のホスト数で許容できる範囲を超えてしまうだろうと思います。もっと大規模になってくると、たとえばTwitterで使われているという、BitTorrentでデプロイするMurderのような仕組みが必要になるだろうなあと思います。

2012-02-22

iOS Programmingを読んでいるという話

会社で、iOS Programming 2nd Edition輪講をしていて、今日は僕の担当で、第7〜9章をやりました。以下、資料。

慣れないことが多いので難しいのですが、いろいろやってるうちに面白くなってきた。この本は、アプリケーションを作る説明と、設計指針や実装の詳細の説明のバランスが非常によくて、自然とどう開発していけばいいのかわかるようになっていて、とてもいい本だと思う。

iOSプログラミング 第2版

iOSプログラミング 第2版

  • 作者: アーロン・ヒレガス,ジョー・コンウェイ,Aaron Hillegass,Joe Conway,木南英夫,上堀幸代,内橋真吾
  • 出版社/メーカー: ピアソン桐原
  • 発売日: 2011/12/21
  • メディア: 単行本(ソフトカバー)
  • 購入: 6人 クリック: 92回
  • この商品を含むブログ (6件) を見る

2012-02-22

2012-02-21 (Tue) - Lean Startupを読んでいるという話

Lean Starupを、暇をみて読んでいるので、その途中経過の話。fbに書いたのを転載。

The Lean Startup: How Today's Entrepreneurs Use Continuous Innovation to Create Radically Successful Businesses

The Lean Startup: How Today's Entrepreneurs Use Continuous Innovation to Create Radically Successful Businesses

今日は、放課後にiOS Programming勉強会をして、その後、数人で食事しつつあれこれおしゃべり。iOS開発まわりの話や、開発手法、Lean Startupの話など。Lean Startupの話は、僕が先行して読んでいる感じなので、面白いと思った話を口頭でざっくばらんに説明を行った。

実際、取り入れるべき考えはたくさんあるし、みんな読むといいと思う。というか、企画、エンジニア、デザイナのような制作はもちろん、営業やマーケも読んだらいいと思うし、マネージメントクラスのひとは是非読むべきだろうと思う。近々邦訳が出るという話をきいているので、それを待ってもいいのだけど、できるだけ早いうちに読んだほうがいいだろう。

読書会みたいなのをしてもいいけど、まあ基本的には読み物なので、がっつりやるというよりはエッセンス、というか、フレームワークを知れればいい話だと思うので、全部読んだら「5分でわかるLean Startup」みたいなスライドを作って、共有できたらいいなと思っているところである。

KPIのような粒度ではなく、機能ごとのcohort-basedなmetricsを取るのが重要という話があって、それを裏返すと、cohort-basedなmetricsを設計できない機能というのは、ただ闇雲な、机上の空論と大差ないという話になるわけで、そういうのはなかなかできてないとろが多いと思うので、普通に重要だろうと思う。

ただ、それを原理主義的に適用して、metrics設計がなければ機能開発しないというのは、それはそれでよくないと思うので、ケースバイケースで、モチベーションベースの機能開発というはもちろんあるべきだし、実際その方が効率がいいという場面は大いにあるのだから、その方がよければそうしたらいい。

ただ、エンジニアリングにおけるデザインパタンと同じで、マネジメントやサービス開発においても、Lean Startupでもなんでもいいんだけど、共通言語をみなが持っている方が話が早いし、そこから外れるにせよ沿うにせよ、筋の通った議論ができるだろうという話。

2012-02-20

"Hello, Android!" by Scala

Install Dev Tools

Install scala, sbt, android-sdk by homebrew:

$ brew install scala sbt android-sdk

Set $ANDROID_HOME and $PATH:

export ANDROID_HOME=/usr/local/Cellar/android-sdk/r16
export PATH=$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$PATH

Install SDK:

$ android

f:id:antipop:20120220233312p:plain

Create AVD: Tools -> Manage AVDs:

f:id:antipop:20120220233526p:plain

Install android-plugin:

$ git clone git://github.com/jberkel/android-plugin.git
$ cd android-plugin
$ sbt publish-local

Install giter8:

$ curl https://raw.github.com/n8han/conscript/master/setup.sh | sh
$ ~/bin/cs n8han/giter8

Hello, World App

Create template:

$ g8 jberkel/android-app

Template for Android apps in Scala

package [my.android.project]: org.kentarok.myapp
name [My Android Project]: MyApp
main_activity [MainActivity]:
scala_version [2.9.1]: 2.9.1
api_level [10]: 15
useProguard [true]: true

Applied jberkel/android-app.g8 in myapp

Launch sbt:

$ cd myapp
$ sbt
> android:package-debug
> android:emulator-start <my_avd> # Your own AVD name
> android:install-emulator

f:id:antipop:20120220233324p:plain

2012-02-14

Data::Mapper Updated to 0.04

Data::Mapper has been updated to version 0.04. I'm trying to use it in my new project and improving it along with the real development progress.

Adapter object now takes a coderef as a driver factory. It's especially for the use with DBIx::Handler:

my $handler = DBIx::Handler->new(...);
my $adapter = Data::Mapper::Adapter::DBI->new({
    driver => sub { $handler->dbh }
});

One of DBIx::Handler's useful features is to keep DB connection active. This change was added for that by supporting a coderef for the driver parameter of the Adapter class.

By the way, I have some intention to use Data::Mapper not only for kind of ORM-ish way, but also a wrapper around data from anywhere, for instance, external Web API. I'm also trying to deal with API's with the module. When it becomes stable, I'll introduce it here.

2012-02-10

ぼくがかんがえたさいきょうのAmon2のつかいかた

新プロジェクトで、それなりに自由にいろいろやれる感じの状況になったので、好きにやろうと思って、いままで実務では使っていなかったツールをあれこれ試しています。


2012-02-17追記: エントリを書いた後、状況がだいぶ変わったので、実際にはずいぶん違う感じになりました。

WAFをどうしようかなーと思った時に、ドメインスペシフィックなぼくがかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーくを作成するということも考えたのですが、そんなにスペシフィックな用途でもないし、WAF自体はPlackを薄くラップしたぐらいのものでよいと思うので、自分でがんばって作る必要もないと考え、信頼と実績のAmon2を試用してみることにしました。

いくつか、こうだったらいいのになという点を反映して、こんな感じでやってみています。試しながらやってるとこなので、全然「さいきょう」でもないし、不十分なところはいろいろあるけど、まあここからスタートということで。

Amon2は、通常WAFに求められるであろうあれこれを、必要最小限にわかりやすく実装していて、とてもよいです。ただ、大きくわけて、以下のふたつについてこうであったらいいなと思っているので、そのようにしてみました。

  • 設定の取り扱い
  • ルーティング

個人的には、環境変数によって設定をきりかえるような機能は、WAFが提供してくれなくてもよいと思っています。なぜなら、WAFは、あくまでもcontroller + viewを担うものであって、そのような立場のものが、たとえばmodelの設定にまで口出ししてくるのは、越権行為であると思うからです。そこで、上記の例ではConfig::ENVを使うことで、設定をWAFから独立して定義できるようにしています。

ルーティングに関しては、Amon2添付のAmon2::Web::Dispatcher::RouterSimpleだと、ディスパッチされるコントローラのクラスが、::C::*というような名前で、僕はクラス名などを省略するのが個人的に嫌いなので、Router::Simpleを使いつつも、自分的に許容できる名前でcontrollerを書けるようにしてみました。controllerがMyApp::Web::Baseを継承して云々というのは、もうちょっといい感じになるような気もしますが、とりあえずこれで。

ともあれ、Amon2はわかりやすく、かつ、カスタマイザブルなWAFなので、とても使い易いものだと思います。これでちょっといろいろ試してみたいところです。

2012-02-09

[diary] 2012-02-08 (Wed) - Scala

I've been interested in Scala, while not started studying yet. Today, I found Effective Scala by Twitter and I thought it was time for me to start it. I almost didn't know the language, so I read a tutorial as the beginning:

I remember I couldn't understand the concept "pattern matching" when I learned it a bit before. I got it this time by the example below:

abstract class Tree
case class Sum(l: Tree, r: Tree) extends Tree
case class Var(n: String) extends Tree
case class Con(v: Int) extends Tree

object Foo {
  type Environment = String => Int

  def eval(t: Tree, env: Environment): Int = t match {
    case Sum(l, r) => eval(l, env) + eval(r, env)
    case Var(n)    => env(n)
    case Con(v)    => v
  }

  def main(args: Array[String]) {
    val exp: Tree = Sum(Sum(Var("x"), Var("x")), Sum(Con(7), Var("y")))
    val env: Environment = { case "x" => 5 case "y" => 7 }

    println("Expression: " + exp)
    println("Evaluation with x=5, y=7: " + eval(exp, env))
  }
}

Hmm, it looks smart. So, I wonder what to do next. To read the official documents seems better. id:motemen, scala master, taught me to read Scala by Example next. Yeah, I'll try it!!1

By the way, I want/need to learn many technical things. There can't be too much tome to spend. I have to spend time much more effectively.