感覚的にはそうなのだろうが

素朴な疑問。個人的には減反とか意図的に牛乳の生産量を抑えさせる政策には賛成できないのだが、庄内米のサイトに書かれていたこんな文句について、気になった数字があったのでちょっと調べてみた。

その質問に答える前に、なぜお米があまるようになったのかについて、考えてみましょう。今から50数年前に、日本がアメリカなどの大国に無謀な戦争を挑み、そして負けたことは、みなさんも知っていますね。戦争には兵士としてたくさんの人が農村からもかりだされ、そして多くの人が死んでしまったため、戦後、お米や農産物を作る労働力が極端に減ってしまい、日本人が食べる分のお米を作ることさえ、できない時代があったのです。その時期には、アメリカをはじめとする外国から、小麦や大豆などを輸入し、何とかしのいできたのです。しかしお米の生産技術が進歩し、ベビーブームなどで人口も確実に増えていき、いつしか( 昭和40年代なかばころ)必要な量を上回るお米を生産することができるようになったのです。

独立行政法人統計センターの政府統計によれば、昭和25年(1950年)の農林水産業に従事する人口はおよそ2,500万人(「職業(大分類),男女別15歳以上就業者数」)。しかし、以降その人数はどんどん減っている。上の引用にある昭和40年は西暦1965年だから、確実に減っているのがわかる。

就業者数(男) 就業者数(女)
1950 17292280 8504271
1955 16057926 8062118
1960 14320691 7394336
1965 11777325 6053420
1970 10085070 5348820
1975 7290080 3577805
1980 6049324 2877457
1985 5360005 2456322
1990 4342391 1947884
1995 3807145 1645547
2000 3149337 1350166

つまり、上の引用にある、農村の労働力不足が1940年代から続き1965年に解消されたというのは事実ではない。

もちろん、引用文にあるように、機械化や効率化、品種改良などによる生産力の大幅な向上がこの期間にあったために収穫量が飛躍的に伸びたというのはあり得ることだ。

第二次世界大戦による日本人の死者と行方不明者はWikipediaの資料では軍人、民間人合わせて270万人。1939年時点の人口と比較すればこれは3.78%にあたるとのこと。仮に、あり得ない仮定として亡くなったのが全員15歳以上の農林水産業従事者であったとしても、1950年から1965年までの減少率29%には到底及ばない。そして、人口そのものが増え続けていたことを考えると、戦争による農林水産業従事者の減少率は戦後の方が遥かに急激だったことがわかる。

計測は大事だ。

心理的な数字、という言い方があるのかどうかは知らないが、戦時中に周囲でどんどん人が亡くなって、あれこれ支障が出て困ったという感覚を知っている人には、心理的な数字として戦争の影響を語ってしまう気持ちももちろん理解はできる。

Popularity: 1% [?]

スカウティングメールに返信した

エクストリーム・ヘッドハンターズ株式会社*1 ○○様

はじめまして。八木と申します。LinkedInからのアクセスでしょうか。

ご紹介いただいております案件ですが、正直なところを申し上げれば残念ながら特に技術的な興味を引く内容ではありませんでした。申し訳ございません。

それだけでは何なので、僭越ながら、私が職業について個人的に重視する項目についてざっとご説明申し上げたいと思います。お忙しい中、大変恐縮ではございますが、ご関心があればお読み頂ければ幸いです。*2

■作業環境

開発の効率化をお題目に挙げている開発会社はいくらでもありますが、実際に効力のある手段を実現しているところはそう多くはありません。n個の「K」で始まる問題を抱える職業なりに、多くの企業がこの点を問題として会議の議題にしていることは間違いありません。

しかし、実際には、この問題の答えは非常に明確かつ単純であり、やる気になればそう難しいことではありません。

それが無料の食事や飲料の提供ではないこともいうまでもありません。

私が考えるもっとも効果的な生産効率向上手段は、静かなオフィスです。冗談のように思われるかもしれませんが、これまで経験した中でこれ以上に効果的な手段はありませんでした。もちろん、手旗信号の方がまだましなひどいネットワーク環境や停電続きの建物などは論外ですが、営業の電話がひっきりなしに鳴り続け、コーディング中のプログラマが管理者たちのこれ見よがしな自慢話にイヤホンで抵抗するような作業環境では、どんなプログラミング言語もツールも役に立ちません。

さらに驚くべきことに、ソフトウェア開発の現場について上のようなことが指摘されたのはかれこれ20年以上も前のことです。

しかし、現実には、何人もの管理者が寄り集まって(私も時折その中の一人であるわけですが)、開発ツールをEclipseにするべきか、言語をJavaにするべきか、などなど愚にもつかない議論を繰り返すばかりで、プログラマはせめてオフィスが静かになる夜にようやく落ち着いて作業に取りかかっているといった具合の開発会社は枚挙に暇がありません。

私が転職するとすれば、そこが静かで集中できる職場であることが必須条件です。

■組織

日常生活においては人間同士のつながり、付き合いは引き起こされるストレスと密接な関係にあり、非常に重要なものですが、キャリアとしての仕事を考えれば、やはり企業は人よりもまず組織が重要です。

社内である程度の技術力を発揮して認められたプログラマが、よき友人たちに囲まれて、給与も上がり(残業代はなくなり)、そしてひどい作業環境で悪戦苦闘する哀れな若いプログラマたちの管理を任され、そんな状況なので不具合は浜の真砂の如く尽きることはなく、メールの返信の手を休めることなく障害報告書をクライアントに送り続けるようになるだけのキャリアパスしか用意されていない企業で失われた若さを嘆くのも人生ですが、ソフトウェア開発者の未来としてみればそれが魅力的な人生であるかどうかは意見の分かれるところです。

ある職が用意されているとして、それはキャリアにどのような意味を持つものなのか、組織がどのようにそれを定義しているのかが重要なことだと私は思っています。

■その他

さて、上段に構えてえらそうなことを書き連ねましたが、ウェブ開発におけるキャリアとして面白そうな職場があれば興味があるのは確かです。面白い仕事があれば是非お話をお伺いすることができればと思います。

では、よい週末を。

*1 もちろん、実在の会社名ではない。

*2 もちろん、実際にこの内容で返事を書いたが、その後の返信はなかった。

Popularity: 1% [?]

PostgreSQL8.1以降の透過的なパーティショニング

PostgreSQLのConstraint Exclusionの使い方がよくわからなかったのでまとめた。

基本的にはマスタテーブルを作成して、そこで型の指定をする。で、Constraint Exclusionを利用することで透過的に選択、更新処理のSQLを扱うことができる。

たとえば、購入履歴だとかダウンロード履歴、閲覧履歴など、何らかのログを残したい場合、データ量が膨大になることが予想されるので期間やユーザでデータを分割しておきたくなる。でも、アプリケーション側から分割されたテーブルにアクセスするのは何かと面倒だ。

そんな場合、継承元と継承先を透過的に扱うにはこんな風にする手がある。期間別テーブルの例は以下の通り:

まずはマスタとなるテーブルで方を指定して、そいつを継承した子テーブルを作成する。

--マスタテーブル(SERIALにはあまり意味はない)
CREATE TABLE master_table (
    id SERIAL, name VARCHAR(20),
    created_at TIMESTAMP WITHOUT TIME ZONE,
    updated_at TIMESTAMP WITHOUT TIME ZONE
);

--子テーブル(2009年1月のデータ用)
CREATE TABLE child_table_2009_01
    (CHECK(created_at >= '2009-01-01 00:00:00'
     AND created_at < '2009-02-01 00:00:00'))
 INHERITS (master_table);

--子テーブル(2009年2月のデータ用)
CREATE TABLE child_table_2009_02
    (CHECK(created_at >= '2009-02-01 00:00:00'
    AND created_at < '2009-03-01 00:00:00'))
 INHERITS (master_table);

で、子テーブルに入るデータの制約を決める。

--2009年1月のデータしか入らない
CREATE RULE insert_child_table_2009_01
    AS ON INSERT TO master_table
    WHERE created_at >= '2009-01-01 00:00:00'
    AND created_at < '2009-02-01 00:00:00'
DO INSTEAD INSERT INTO child_table_2009_01
    (name, created_at, updated_at)
    VALUES
    (NEW.name, NEW.created_at, NEW.updated_at);

--2009年2月のデータしか入らない
CREATE RULE insert_child_table_2009_02
    AS ON INSERT TO master_table
    WHERE created_at >= '2009-02-01 00:00:00'
    AND created_at < '2009-03-01 00:00:00'
 DO INSTEAD INSERT INTO child_table_2009_02
    (name, created_at, updated_at)
    VALUES
    (NEW.name, NEW.created_at, NEW.updated_at);

とりあえず1月と2月のデータがあればいいので、こんな感じのテストデータを用意。

$ cat insert.sh
#!/bin/sh

COUNT=0
INTERVAL=1000
MAX=3000000
BASETIME=`date --date "2009-01-01 09:00:00" "+%s"`

while test $COUNT -lt $MAX
do
        TIME=`expr $BASETIME + $COUNT`
        DATE=`date --date "1970-01-01 $TIME sec" "+%Y-%m-%d %T"`
        SQL="INSERT INTO master_table (name, created_at, updated_at)
          VALUES ('"$COUNT"', '"$DATE"', '"$DATE"');";
        echo $SQL
        COUNT=`expr $COUNT + $INTERVAL`
done

で、テスト用データベース(p_testにした)に流し込む。

$ ./insert.sh > $HOME/pgsql/test/insert.sql

$ head -1 $HOME/pgsql/test/insert.sql
INSERT INTO master_table (name, created_at, updated_at)
VALUES ('0', '2009-01-01 00:00:00', '2009-01-01 00:00:00');
$ tail -1 $HOME/pgsql/test/insert.sql
INSERT INTO master_table (name, created_at, updated_at)
VALUES ('2990000', '2009-02-04 14:33:20', '2009-02-04 14:33:
##テストだからまあいい。
$ psql -Upostgres -d p_test -f $HOME/pgsql/test/insert.sql

インデックスはそれぞれの子テーブルに作成しておく。

p_test=# CREATE INDEX idx_2009_01 ON child_table_2009_01(created_at);
p_test=# CREATE INDEX idx_2009_02 ON child_table_2009_02(created_at);
p_test=# CREATE INDEX idx_master_table ON master_table(created_at);

で、準備は完了。しかし、これだけだと透過的に扱えるといってもあまり効率はよくない。

p_test=# EXPLAIN ANALYZE
SELECT * FROM master_table
WHERE created_at BETWEEN '2009-01-01 00:00:00'
AND '2009-01-15 00:00:00';

こんなクエリを実行すると、なぜかchild_table_2009_02まで検索されてしまう。

そこで

p_test=# SET constraint_exclusion TO on;
SET
p_test=# EXPLAIN ANALYZE
SELECT * FROM master_table
WHERE created_at BETWEEN '2009-01-01 00:00:00'
AND '2009-01-15 00:00:00';

constraint_exclusionをセットすることでWHERE句から子テーブルの制約にひっかかるテーブルの検索がなくなる。

SELECTを発行するたびにconstraint_exclusionを設定するのはバカらしいので、postgresql.confを開き、

#constraint_exclusion = off

デフォルトでoffになっているconstraint_exclusionをonに変更する。

constraint_exclusion = on

これで本当にマスタテーブルと子テーブルを透過的に扱うことが出来るようになる。どれくらい透過的かというと、上のINSERTやSELECT文に加えて

p_test=# UPDATE master_table SET name = 'hoge'
WHERE created_at >= '2009-01-01 00:00:00'
AND created_at < '2009-02-01 00:00:00';

みたいなUPDATE文もみんなmaster_tableに向けて発行できる。

でも、まだまだ問題はある。たとえば、透過的に扱えるようになることでオーバーヘッドは増す。マニュアルによれば、

A rule has significantly more overhead than a trigger, but the overhead is paid once per query rather than once per row, so this method might be advantageous for bulk-insert situations. In most cases, however, the trigger method will offer better performance.

RULEによる処理ではクエリ毎に適用されるので一気に更新する場合はいいが、行毎の実行であれば都度トリガーを実行する方がオーバーヘッドは少ない。また、COPYによるデータ挿入はこのRULEを無視してしまう。また、RULEの記述ミスがあった場合、エラーにはならず、そのままマスターとなるテーブルにデータが追加されてしまう。

それから、CURRENT_DATEなどをWHERE句に使用するとクエリプランナはどのパーティションを使えばいいのか事前にわからないので避ける必要がある。またパーティションが多すぎる場合もクエリプランナによる最適化に時間がかかるためオーバーヘッドが大きくなるので、せいぜい100個程度にしておくべき、とのこと。

あと、ちょっと不思議なことに、relpagesからサイズを求めようとしてもmaster_tableのサイズが出ない。


$ vacuumdb -f -z -d p_test -U postgres
$ psql -p 5433 -Upostgres -d p_test
Welcome to psql 8.3.1, the PostgreSQL interactive terminal.

Type:  \copyright for distribution terms
       \h for help with SQL commands
       \? for help with psql commands
       \g or terminate with semicolon to execute query
       \q to quit

p_test=# select sum(relpages) * 8 * 1024 from pg_class
where relname = 'master_table';
 ?column?
----------
        0
(1 row)

でも子テーブルにはちゃんとデータがある。

p_test=# select sum(relpages) * 8 * 1024 from pg_class
where relname = 'child_table_2009_01';
 ?column?
----------
   155648
(1 row)

p_test=# select sum(relpages) * 8 * 1024 from pg_class
where relname = 'child_table_2009_02';
 ?column?
----------
    40960
(1 row)

このあたりはまだよくわかっていない…

Popularity: 2% [?]

Lux Interior享年62歳

The CrampsのLux Interior亡くなっていた

画像を追加。

Popularity: 1% [?]

携帯電話向けサイトのセキュリティ

以前、こんなことを書いたわけだが、最近ちょっと毛色の違う携帯サイトへの攻撃が増えているのでメモ。

携帯電話の強みとして、マイクロペイメントの仕組みが充実しているという点がある。ようするに、従量課金で100円のコンテンツを売る場合、PC向けサイトだとクレジット決済で手数料がコンテンツの価格の半分近くになったりしてなんとも不合理だが、携帯電話の料金として徴収してしまうシステムだと100円のものは(ほぼ)100円で買えるわけで、その点で携帯電話は非常に強力なプラットフォームだ。しかも、契約情報と関連した端末固有のIDがサーバに送信され蓄積されるシステムのため、それが犯罪に対して一定の抑止力となっている。

それをふまえて、先のエントリではたかだか月額315円のサイトをだまくらかしても得られる利益はたかが知れているというようなことを書いていた。しかし、昨今では例えばアフィリエイトと組み合わせて、大量の契約済端末で月額課金サービルスに登録してアフィリエイトサイトから大量の見返りを得ておいて、支払い前に振り込め詐欺用の使い捨て電話として端末を売却し、アフィリエイトの見返りのみを手にしてドロンというケースが相当な件数で発生しているようだ。アフィリエイト会社に成果発生して料金を支払うコンテンツ提供会社は、キャリアからの支払い情報に大量の「支払い不能」契約を発見するが、支払い情報を手にすることができるのがそもそも何ヶ月か後だったりするので、成果発生して得られるはずの料金を手にすることが出来ず、かといってアフィリエイト会社にその分を請求することもままならない状況に陥ってしまう。

確かにこの不景気で支払い不能による料金未回収が増えたとはいえ、上のようなパターンの詐欺も見過ごせない程度の規模になりつつあるようだ。

Popularity: 1% [?]

ヅラの新スタイル

新しいヅラへの転向のスタイル

Popularity: 1% [?]

iPhone用プラグインWPTouch

iPhoneを見せびらかしに来た人物がWordPress用プラグインの出来がいいというので試してみたのだが。

一覧ページ:
photo2

抜粋だけ見る:
photo1

エントリの詳細:
photo

出来がいいので腹が立つ。iPhoneを横にすると画像がリサイズされる。

しかも、テンプレートに埋め込んだJavascriptで強制的に回転させる技が通じない。

Popularity: 1% [?]

PostgreSQLメモ

PostgreSQLのデータベース毎の容量調査方法を忘れていたのでメモ。統計情報が更新されていないと意味ないが。

psql -Upostgres -l -t -q | while read line
do
    DBNAME=`awk <<< $line '{print $1}'`
    if test -n "$DBNAME"&& test "$DBNAME" != "template0"
    then
        echo -n $DBNAME ":"
        psql -Upostgres -d $DBNAME -t -q -c "SELECT sum(relpages) * 8 * 1024 from pg_class"
    fi
done

Popularity: 1% [?]

memcached(repcached)のデータをバックアップ

memcachedの評価中に、対障害性を高める方法についてあれこれ考えていたのだが、あまりいい案が浮かばなった。

とりあえずストレージの冗長化であればrepcachedでなんとかなる。でも、memcachedのストレージがいっぱいになったらアクセスの古いデータから順に捨てられるので、予想を超える事態になったときにそれを検知してなんとかDBにでも保存しておく方法はないものかと考えたのだが、なかなかスマートな解決方法がない。

たとえば、セッション情報をmemcachedに保存しているとする。期限が設定されていたら、少なくともその間はデータを保持したい。でも、データ量が予想を上回ると上記のロジックで古いセッションが破棄されてしまう。よほどケチった予想をしていない限りは実害はほとんどないのかもしれないが、保障されているセッションの期限が守れない可能性があるのは変わりない。

そこで、現在memcachedのストレージ上に保存されているデータを定期的にDBにバックアップできないかと考えた。でも、よく考えたら、セッションのユニークIDをキーにしてデータを保存している場合、現在どんなIDが保存されているのかを知る方法がどこにもない。RDBMSだと取得先テーブル名はたいていわかるので、条件を書けばいくらでもデータを取得できるが、そもそも前提となる条件がユニークIDであるセッションのような情報だと難しい。

RDBMS風にいえばこんな感じ。
  table      |  data                                        |
----------+----------------------------------+
  yagi       | I still consider myself rather likable |
----------+----------------------------------+
  soey      | Size don't matter                     |
----------+----------------------------------+
  chobee   | Baseball games are like snowflakes |
----------+----------------------------------+

そこで、memcached上にシーケンステーブルのようなものを用意してみた。セッションの期限は24時間だから


$myname = 'yagi';
$mydata = 'I still consider myself rather likable.';

$today = date("Y-m-d", time());
$new_id = $today . '_' . $memcached->increment($today);

$memcache->set($new_id, $myname);
$memcache->set($myname, $mydata);

これで、RDBMS風にいえば

sequence_name | last_value | increment_by |
----------------+-----------+--------------+
2009-02-06       |            1  |                 1 |

id                  | myname |
--------------+---------+
2009-02-06_1 |       yagi |

myname | mydata                                      |
---------+----------------------------------+
   yagi    | I still consider myself rather likable |

みたいなテーブルが出来たことになる。そこで、


$yesterday = date("Y-m-d", mktime(0, 0, 0, date("m"), date("d") - 1, date("Y")));
$max = $memcache->get($yesterday);
$i = 0;
$data = array();
while($max >= $i){
    $save = $memcache->get($yesterday . '_' . $i);
    if($save){//件数が多すぎたら配列に入れられないけどまあいい
        $data[$save] = $memcache->get($save);
    }
    $i++;
}

という感じでバックアップは取れる。特にセッション情報があまり変わらないアフィリエイトのID保存のような目的に使われる場合は、成果発生時のチェックにmemcachedから読み込んだデータとDBのデータを使えばまあ確実になる。

でも、動くことは動くが1件につき2つのデータが必要になり、効率は悪い。

もっとうまい方法があれば教えてほしいと思うのであった。

Popularity: 3% [?]

『君のためなら千回でも』

楽天レンタルでDVDを借りてみた。でも一か月無料のお試し期間を見込んで申し込んでも届くまでに一か月近くかかってしまって意味がなかった。困ったものだ。品揃えもまだまだ。

借りたのはこれ。

原作が非常によかったので期待半分、上下巻組の長い作品を1時間半程度の尺にどうやって押し込むのかは、本人も作家であるという脚本のデヴィッド・ベニオフの腕の見せ所だったのだが、ううむ、ニューヨーク育ちの脚本家にはいまいちどう扱っていいかわからない作品だったようだ。というと意地が悪い気もするが、それもひとえに原作が面白かったせいであり、思い入れのある箇所がどう料理されているのか楽しみにしていた分だけ文句が出てしまうのも仕方がないところ。ドリームワークス作品とは知らなかったが、良くも悪くもそのせいでかっちりしたつくりになっている。やっぱり家族向けにあんまりひどいシーンは出さない方針だったのだろう。

割と淡々と省略気味のストーリーが原作に忠実に続くので、ちょっとした感動作にはちゃんとなっている。でもタリバンに銃撃されるシーンなどは、アクションシーンの少ない映画なのでちょっと原作を変えて入れてみましたとでもいいたげな感じで、一気に現実感が薄れてしまい残念だった。

とはいえ、ハッサン役の子供(アフマド・ハーン・マフムードザダ)が非常にかわいらしく、彼を見ているだけで泣ける。あと、原書を読んでいないので、ああここはこういうセリフだったのか、という楽しみはある。

原作はとにかくよかったのでおすすめだ。繰り返します。原作は非常によかったです。ここ試験に出ます。拷問されるか読むか選べといわれたら、遠い故郷のこととかいろいろ考えてから覚悟を決めて、読む方を選びましょう。

お前みたいな甘やかされた中流育ちにこの厳しい現実に生きる人たちに共感なんか出来るかよ、という意見もあるかもしれないが、出来るに決まっている。俺たちは虫けらだろうが外宇宙人だろうが、理解可能と思えたものになら何でも共感する。それが不満なら、共感の意味についてよーく考えてから、素振り100回してこればいいと思う。

著者は移民二世の内科医とのこと。やっぱり移民二世は親の期待を背負って猛勉強して医者か弁護士になる、というのは単なるステレオタイプじゃなくて現実みたいだ。作品の中では主人公がすんなり作家になってしまうあたり、著者のちょっとした主張が垣間見える。

Popularity: 1% [?]