Heroku本を読んだ

『プロフェッショナルのための実践Heroku入門』をざっと読んだ。

コンパクトにまとまっていて良い本だと思う。 私が以前1日がかりで調べて回ったこと+αぐらいが書かれているので、読んでおけばそういう調べ回る時間を節約してくれるし。

インストール手順に結構な紙面を割いたりするあたりはあまり好みの構成ではないが、薄い割に触れているトピックが豊富なのは良い。 Herokuの概要、各言語の開発環境セットアップ、Herokuを用いたアプリケーションの開発サイクル、デプロイの仕組み、Addon, Herokuアーキテクチャの外観などに順に触れている。 web開発者ならこれだけ一冊読めばとりあえずHerokuにアプリケーションを立ち上げられるようになるだろう。 ベストプラクティスやアンチパターンについても折々触れているので、読んでおけば先々楽にもなる。

残念なのは、workerプロセスについては名前ぐらいであまり触れていないことだろうか。workerがあればmicroservicesも可能だ思うのだけれども、web dynoからworker dynoにアクセスするにはどうしたら良いのかわからなかった。これは前にHerokuのhelpを調べたときも良くわからなかった。ambasadorパターンしてくれてたりするのだろうか。

これは愚痴だけれども、冒頭の概説におけるGoogle Cloud Platformの扱いが悲しい。

  • IaaSの例としてはGoogle Compute Engineは無視された。紙面には限りもあるので落とされるものがあるのは仕方がないが、ごく個人的な希望としては入れてくれたら嬉しかった。
  • Google AppEngineではRDBが使えない、ということはない。 Cloud SQL というのがあって、これは普通のMySQLとして使える。

    • AppEngineではBigDataというKVSしか使えないと書いてあるのは Blobstore (もしくは Google Cloud Storage )と Datastore が混ざってないだろうか。BigDataという製品は今のところ無い。
    • Blobstore/Cloud Storageは要するに S3 みたいなものなのでKVSといえばKVSだし、特にBlobstoreのAPIはKVSっぽい。DatastoreはEventually Consistentじゃなくて厳密にtransactionalな HBase みたいなものなのでKVSとはちょっと違うNoSQL DBだ。

libchanを読んだ

libchan を読んだのでまとめてみる。

libchanとは

libchanはdockerに使われているライブラリの1つで、先月の DockerCon で発表された。 非同期かつ一方向の通信チャネルをインプロセスでもネットワーク越しでも扱えるというGoライブラリである。 一方向とはいうものの、チャネル自体をデータに添えて他のチャネル越しに送れる。なので、返信や待ち合わせが必要ならば自分宛のチャネルを送って相手に使ってもらい、自分はそのチャネルの上で待機していれば良い。

早い話がGo言語の機能であるチャネルをネットワーク対応したようなものだ、と書いてある。

DockerはこのDockerConではDocker 1.0に加えてlibcontainer, libchan, libswarm, Docker Hubを発表していて一応キーノートの話題の1つではあったものの、 個人的にはlibswarmやKubernetesに比べるとインパクトは小さいなという感想であった。

実装

何らかのトランスポート機構の上にシリアライズされたメッセージを送る仕組みで、割とシンプルな造りである。

トランスポートとしては下記をサポートするとドキュメントに書いてある。

  • In-memory Go channel
  • Unix socket
  • Raw TCP
  • TLS
  • HTTP2/SPDY
  • Websocket

ただし、現在実装されているのは下記のみに見える。

  • In-memory Go channel
  • Unix socket
  • SPDY

また"In-memory Go channel"とはいうものの、実際にはmutexと変数共有で実装されていてchanは使っていない。

送信可能なメッセージの定義は次のようになっている。

type Message struct {
    Data    []byte
    Fd  *os.File
    Ret  Sender
}

Data は任意のペイロードRet は返信用に相手に送るチャネルである。

Ret には特別な値である libchan.RetPipe を指定できる。これを使うとチャネルの実装が勝手に返信用の逆方向チャネルを作って送ってくれるので、位置透過性を保ったまま「送信元に返信してね」と指定できる。

Fd はよく分からない。一見するとUnixソケットのFD passingみたいなものを実現するつもりなのかとも思うが、"file attachment not yet implemented in unix transport"とか書いてあるし、"file attachment"というのは何か別のものなのかもしれない。

unix.Receiver の定義が下記のようになっているあたり、やはりFD passingか、とも思うのだが。

type Receiver interface {
    Receive() ([]byte, *os.File, error)
}

感想

デザインは魅力的だ。ただし、位置づけがまだ不安定であるし、実装も開発途上で未実装機能が多い。

チャネル上でチャネルを送れるということの強力さはGoでchanを使っているとよく分かる。 それをネットワーク分散システムで利用できるのはとても楽しみだ。ただしSPDYトランスポートでのチャネル転送が libchan.RetPipe を除いて未実装なので、その魅力は現時点では半減する。

チャネル再転送の困難

実際のところリモートマシン宛の任意のチャネル転送をサポートするとなると厄介な問題に出会うだろう。 転送されてきたチャネルを再転送できるというのがこのパラダイムを強力たらしめるのだが、そのトランスポートレベルでの実装は面倒になり得る。

ノードA, B, Cがあって、Aが生成したA宛のチャネルをBに送り、BはそれをCに再転送し、Cがそのチャネルに書き込んだとしよう。素朴には2通りの実装が考えられる。

  • CはAと直接通信する。Cはチャネルを受け取った時点でAへの通信を確立し、その上に受け取ったチャネルを再現する
  • BがCとAの通信を中継する。

複雑なシステムでチャネルがあちこちでやり取りされると、中継モデルは破綻することが予想される。 チャネルの流通経路を逆に辿ってシステム内のノードをたらい回しされ、無駄に転送コストを支払うメッセージが見えるようだ。

一方で直接通信モデルはではAとCが直接通信可能とは限らない。firewall越えやNAT越えの問題があるし、Raw TCP経由でWebsocketチャネルを送った場合どっちのプロトコルが妥当とも言えない。

結局は直接通信と中継のハイブリッドが妥当であろうと考えられるが、どうハイブリッドするのか、通信パスをどう最適化するのかというルーティング問題が残る。

将来性

Dockerを実装するには便利なんだろうと思う。問題はどこまで汎用化してくれるだろうかというところにある。

一応は任意の言語でライブラリを実装可能と書いてあるので、Docker以外が使うことも想定はしているんだろう。それでも、NAT越えとかルーティングとかをどこまで真剣にサポートしてくれるのか。 その辺のDockerには必要かどうか分からない機能のためにパッチを継続的に受け付けてくれるのか。誰がそういうパッチを書くのか。

競合

多様なトランスポートをサポートした通信ライブラリという点でlibchanはあからさまにZeroMQと競合する。

中の人のコメント では「ZeroMQは機能過剰だし、ローレベル過ぎるし、要らない機能を外すのも大変」だからlibchanを作ったとある。

個人的にはこれに賛同する。チャンネル自体の転送ができるのは圧倒的な魅力だし、これで十分に強力だ。 ZeroMQがサポートするPublisher-Subscriberモデルや同期通信, 双方向通信はlibchanに欠けているが特に問題とも思わない。 バイトストリーム上にチャネル転送を構築することに比べると、PubSubや同期、双方向通信を非同期一方向+チャネル転送で実装するほうが楽だし、抽象化としてまともに思える。

しかし、皆がそう思わなければ使われないだろう。どれだけユーザー層が成熟していくのか未知数である。

結論

流行ったらいいなと思うし、ネットワーク越しのチャネル転送の仕様が固まってきたらRubyC++で実装するのもの面白いかもしれない。 でも今は使うときではないと思う。

Dockerで何が変わるのか

DockerCon 2014 に行ってきた。

この会期中には各社からいくつもの製品が紹介/発表された。そして、それによってクラウドという技術は次のステージに移行したと言っても過言ではないだろう。

より自由にユーザーがクラウドベンダーを選べる時代へ。どうやってクラウドにうまくデプロイするかではなく、アプリケーションそのものに注力できる時代へ。

Dockerとは

Docker とはいわゆるコンテナ技術の1つで、Linuxホスト環境の中に隔離された別のLinux環境を作ってくれる技術だ。

軽量仮想マシンと呼ばれたりもする。 Solaris Container とも似ている。

新しくないDocker

1つ述べておくとDockerは技術的には新しくない。Dockerの価値は技術以外にある(とDockerのCEOもDockerConで言ってた)。

技術的にはSolarisにはSolaris 10の頃からあるし(ruby-lang.orgも使ってた)、LinuxにだってLXCがKernel 2.6の頃からある。そもそもの話Dockerの初期のバージョンはLXCのラッパーみたいなもんだった。

仮想マシンに似ているという観点から述べるなら、コンテナ技術というのはマシンやOSそのものを仮想的に実現してその上でアプリケーションを動かす代わりにマシンとカーネルはホストのものをそのまま使って、ユーザーランド+αだけを仮想化する、みたいなもんだ。

別の視点から述べると、これって要するにchroot+αだ。「ちょっとすごいJail」と言ってもいいだろう。Chrootだとファイルシステムだけが隔離されるけど、その他にDockerではプロセスIDのネームスペースや、ユーザーIDやネットワークポートの空間も隔離される。Dockerの中のrootはホスト環境のrootとは違うユーザーだし、プロセス番号は同じでも違うプロセスだし、TCP portも同様。要は、これぐらい一通りホスト環境から隔離してやればユーザーランドから見ると仮想マシンに隔離されてるも同然だよね、という話。実際にはカーネルはホスト環境のやつを使ってるけど、ユーザーランドからそれを知るすべはほとんどない筈。

新しいDocker

Dockerが新しいのは、コンテナ環境で走らせるアプリケーションを簡単にパッケージする標準的な方法を確立したことにある。

Dockerは、ユーザーランドで使われるGNU/Linuxディストリビューションファイルシステムひと揃いをメタデータと一緒に固めた形式を定義している。要するに仮想ディスクイメージなんだけど。

また、イメージはしばしば他のイメージから派生する。その場合は元のイメージからの差分だけが保存されるので軽量である。

更に、イメージはgitのコミットと同じ要領で内容のハッシュで識別されることになっている。

これらが合わさると、こういうことになる。アプリケーションを含まないOSだけのbaseイメージ(例えばUbuntu preciseイメージ)はみんなが大抵手元に持っているし、必要であれば公式のリポジトリから簡単にダウンロードできる。

そのベースイメージから派生した自分のアプリケーションインスール済み環境を配布したいとする。

受け取る相手は、今自分が受け取ろうとしているイメージの派生元を辿って行く。既に持っている分は改めて取得する必要はなくて、そこからの差分だけを転送すればよい。つまり、ディスクイメージの転送が軽量にできる。

同じ内容のイメージは必ず同じハッシュを持つので、既に持っているかどうかは簡単に判別できる。この辺もgitと同じだ。

更に、こうして作成された差分ディスクイメージを走らせるときもホスト環境のディスクを無駄に使わず、起動時にマージなんてアホなことをすることもなく、効率的にインスタンス化できるようになっている。

こういう便利なパッケージの仕組みをオープンソースで作った。そしてこの仕組みをみんなが使い始めた。みんなというのはGoogle, Amazon, IBM, Microsoft, Rackspace, ...を含む。

新しいクラウドの話

Dockerはそれ単体で使っても便利なものだ。プロセスを隔離したいときのchrootの不便を解消できる。

Chrootだと、chroot環境のファイルシステムを作るのが結構面倒でみんな自作のスクリプトで頑張ったりしたものだった。Dockerなら簡単にUbuntuでもCentOSでも好きな環境のイメージを作れる。 *1

しかし、Dockerが本当に便利なのはクラウド環境との組み合わせで、イメージを他のマシンに転送するときだ。手元のマシンでDockerイメージを作り込んでプロダクション環境に転送、実行してやる。すると、手元で設定したアプケーションがそのままプロダクションで動く。ファイルを配備して、ユーザーを作成して、設定ファイルを弄って、みたいな成果物をそのままの状態で転送できる。もう苦労してプロダクション環境を適切にセットアップしてやる必要はない。つまり、ProvisioningやDeploymentの手順が劇的に簡略化される。

Dockerさえ設定しておけば、あとはイメージをポイッと配布するとそれがそのまま動くのだ。

最初にDockerを軽量仮想マシンぽいものだと言ったけれど、ここに至っては仮想化であるということは手段の1つでしかなくてあまり重要なことではない。重要なのは設定済みのアプケーション動作環境をユーザーランドまるごとパッケージして軽量に移動できるということのほうだ。

そして、これがクラウドの主要ベンダーたちによってサポートされた。

  • GoogleはManaged VMを発表した。ユーザーがアップロードしたDockerイメージがAppEngine相当のmanaged環境で実行される。AppEngine同様の「Googleが運用の面倒を見てくれる」手軽さがありながら、Dockerイメージには任意の言語で任意のアプケーションを入れられる。
  • AmazonはElastic BeanstalkでDockerをサポートした。話としてはManaged VMと同じだ。
  • ...

こうして各社がDockerをサポートした。つまり、クラウド環境で動かすためにアプケーションをパッケージングし転送する標準的な方法が生まれた。もうベンダーロックインを心配しなくていい。他社のサービスへ移りたくなったらそのDockerイメージを移動先に改めてアップロードすれば良い。

libswarm

今回のDockerConでは、もう1つベンダーロックインをなくすための製品が発表された。

なるほど、一個のサービスはDockerで簡単に配備できるし移動もできるかもしれない。しかし、今どきのクラウド上のアプケーションというのは1つのサービスだけで動く訳ではない。データベースに、キャッシュに、バックエンドサーバー、フロントエンドwebアプケーションサーバーなどなど沢山のroleを為すそれぞれの種類のサーバーインスタンスがあって、それぞれを適切に繋げてやらねばならない。しかもクラウド上の話だからしばしばサーバーのIPはクラウドベンダーに割り振られる。IP決めうちであらかじめ設定してからイメージを作るという訳にもいかない。つまり、依存する各サーバーが他のサービスを発見して繋ぎにいくというサービスディスカバリとオーケストレーションの問題が発生する。

この問題に対しては既にいくつものソリューションがある。fleet+etcdだとか、gearだとか。うまく使えばDNSも解になり得るだろう。クラウドベンダーも思い思いに解決法を提供している。

真の問題は、解決法が多すぎることだ。未だに標準的な方法はないし、どこかのベンダーの機能を使えば、サービスのオーケストレーションという要の部分を握られてロックインされる。

そこでDockerはこの度libswarmを発表した。libswarmはこの様々な実装を抽象化したAPIを提供するライブラリだ。

個人的にはlibvirtオーケストレーション版、という理解をしている。

libswarmによっていよいよクラウドベンダー間の移動は楽になる。もっと安いところ、もっとスケールするところ、などなど必要に応じて他のベンダーに自由に移動できる時代がやってくる。

Kubernetes

そしてKubernetesは更にその一歩先の話、だと思うけどその話は後で書く

Disclaimer このブログはYuguiの個人的なものです。ここで述べられていることはDockerConで聞いた話の個人的理解、および個人的な意見に基づくものであり、私の雇用者には一切の関係はありません。

上で間違ってdocker imageのidがcontent hashかのように書いたが、それは次期イメージフォーマットの話で現在はイメージ作成時にランダムに決まる256bitだった。イメージ生成時にはキャッシュが効くので続けざまに二回同じイメージをビルドすると同じIDが帰ってくるが、別のホストで独立に同じイメージをビルドしても別のIDになる。

*1:隔離されていて予測可能な状態にある環境というのはビルドやなんかにはとても便利だ。だからDockerのビルドスクリプトはDocker環境の中でDockerをビルドする

fluentdを勉強中

最近はlog collectionというと fluentd が話題らしいというので、少し触り始めている。 多少は分かってきたように思うので理解したことと、理解できていないところをまとめてみようと思う。

fluentdとは何か

オフィシャルサイトには"tool to collect events and log"と書いてある。 要するに、サーバー群から継続的に情報を吸い上げるための仕組みを提供するdaemonである。

この「情報をかき集める」という枠組みは今時のサーバーサイドでは頻出パターンだ。 データベースサーバ、アプリケーションサーバー、フロントエンドキャッシュサーバー, ...と役割分担をするのが普通だし、 アプリケーションサーバーだって負荷分散のために複数インスタンスを持つのが当たり前だ。 そしてこれらサーバー群をきちんと管理するためには様々な情報をかき集めてきて一カ所に保存したり集約したりする必要がある。 たとえば、

  • アプリケーションサーバーのログを全インスタンスから集めて一覧可能にする
  • キャッシュサーバーのヒット情報を集めて解析する
  • 各マシンのディスク空き容量を定期的に集めて不足しそうなら警告を出す

これらはいずれも一見するとそれほど難しい処理には思えない。scpとcronでもできそうだ。 しかしデータ転送の際の失敗をどうやって扱うのかを考えだすと、自明ではなくなる。 定時バッチ処理ではなくリアルタイムに処理し続けるようにしたいと考えると問題はさらに難しくなる。 失敗時は適切な時間を置いて再試行するように。通信エラーで情報が失われたりしないように。

fluentdはこの頻出パターンを司り、上記のような困難を処理してくれる。 そして、パターンの個々のバリエーションに対応できるようにデータ入力、加工、出力のそれぞれをプラグインなどで拡張可能になっている。

また、異なるデータソースからの情報をバラバラにあつめるのではなくfluentdという1つのシステムにつなぐことそのものにも意味がある。 データソースをまたいだリアルタイムの解析も容易になる。

よく分かってないこと1: システム監視

fluentdだけでモニタリングシステムを構築できるだろうか。すべきだろうか。

情報をかき集めて変換するという点でシステム監視はfluentdのカバーする範囲に思える。 一方でシステム監視の世界では nagiosZABBIX)が長く使われている。 仮にこうした「fluentd以前」からのソリューションを置くとしても最近出た((<Sensu|URL:sensuapp.org) ももた話題になっているようだ。 こういうのとfluentdは棲み分けるべきなんだろうか。それともfluentdに集約してしまうべきなんだろうか。

可能ならシステムの中に似たようなモジュールは2つ置きたくない。fluentdを中心としたモニタリングは可能そうだし、 実際に構想している人もいる 。 でも、もし餅は餅屋としてシステム監視専門のモジュールならではのfluentdでカバーできない利点があるならそれは知りたい。

よく分かってないこと2: アーキテクチャ

Sensuやなんかだと、データ転送をreliableにするためにRabbitMQを使っている。 一方fluentdのforwardingは特にそういうミドルウェアは使ってない。fluentd自身ががんばってエラー対応している。

こういうのは別途ミドルウェアでqueueを使うものだと言う思い込みがあったのでfluentdのやり方は見慣れない感じがする。 この違いはどういう設計判断によるものなんだろう。

お返事

疑問を書いてみたら偉い人から お返事 来た。

MQ使わないのはやっぱりそういうことか。モニタリングは、うん、もうちょっと考えてみよう。

環境に優しい難読コード

ぼちぼち忘年会やクリスマス会のシーズンとなってきた。

そんなパーティーの1つに出欠の連絡をしなければならない場面があったのだけど、どうやらネタ回答を期待されているらしかったので次のように回答した。

puts [[->(&f){->(n){f[f[f[f[f[f[f[f[f[f[f[f[f[f[n]]]]]]]]]]]]]]}},->(&f){->(n){f[f[f[f[f[n]]]]]}},
->(&f){->(n){f[f[f[f[f[f[f[f[n]]]]]]]]}},->(&f){->(n){f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[n]]]]]]]]]]]]]]]}},
->(&f){->(n){f[f[f[f[f[f[f[f[n]]]]]]]]}},->(&f){->(n){f[f[n]]}},->(&f){->(n){f[f[f[f[f[f[f[f[f[f[f[f[f[f[n]]]]]]]]]]]]]]}},
->(&f){->(n){f[f[f[f[f[n]]]]]}},->(&f){->(n){f[f[f[f[f[f[f[f[n]]]]]]]]}},->(&f){->(n){f[f[f[f[f[f[f[f[f[f[n]]]]]]]]]]}},
->(&f){->(n){f[f[f[f[f[f[f[f[f[f[n]]]]]]]]]]}},->(&f){->(n){n}}].map{|x|x[&:succ][0]}.map(&("%x".method("%"))).join].
pack("H*").unpack("U*").pack("U*").encode(Encoding.default_external)

難解コードとかゴルフとかは苦手なんだけど、相手のためを思って知恵を絞ればできるもんだね。

難読コーディングとしては割と定番の素材を使っていて読解難度はそう高くない。ただ、呼び出し可能オブジェクト技法の数々や、表示側のエンコーディングに依存しない環境(env(1)的な意味で)に優しい設計でありつつ"Encoding::UTF_8"と書くのはあくまでも避けたあたりについては我ながら満足している。

Ubuntu 12.04 preciseをaufs rootにした

表題のようにaufsをroot filesystemとしてマウントしてみたので、手順をメモする。

経緯

最近 DNA940 という面白い機器を手に入れた。なんでも本来は産業用機器のベースとして使用することを想定した機体で、中身はx86ベースの基板にGbE×4やらコンソールポートやらいろいろついている。 Debianが動いたという話も耳にする。

これにソフトウェアルーターを組み合わせて自宅ネットワークのルーターを好きなように組む、という野望を抱いたのがそもそもの動機である。

ところで、DNA940は2.5in HDDを組み込めるのでそれをメインディスクにしても良いのだけど、可動部品は可能な限りなくしたいのでCFのほうが嬉しい。しかしながら、普通にDebianUbuntuのシステムをCFで動かすとすぐに書き込み上限に引っかかるのは目に見えている。 そこでaufsでext4の上にtmpfsをオーバーレイしたものをroot fsにしたい、というのが今回の話だ。

いきなり実機は怖いので、まずはVMWare Fusion上の仮想マシンでやってみる。

手順

同じような需要は各所に有ると見えて、手順は Ubuntuのヘルプサイト にまとまっている。意外と簡単だった。

  1. 仮想マシンを作成する。メモリを1GB、ディスクを2GB割り振って、 ディスクは丸ごとext4のルートファイルシステムとした。Swap領域は作成しない。

  2. Ubuntu Precise (x86-64 Server Edition)をインストールする。 前述のヘルプページではLive CDからインストールするように書いてあるが、 これだとデスクトップ版がインストールされるような気がした。 そこで、普通にサーバー版のインストールディスクを用いた。

  3. 以下はヘルプページの手順に従った。

    • % sudo aptitude install aufs-tools
    • % sudo bash -c "echo aufs >> /etc/initramfs-tools/modules"

    ここでヘルプページに書いてあるrootaufs Scriptを /etc/initramfs-tools/scripts/init-bottom/__rootaufs に保存した上で、

    • % sudo chown root:root /etc/initramfs-tools/scripts/init-bottom/__rootaufs
    • % sudo chmod 0755 /etc/initramfs-tools/scripts/init-bottom/__rootaufs
    • % sudo update-grub
    • % sudo-initramfs -u

    とする。

    initrdまわりはあまり詳しくなかったのだけど、要はこの scripts ディレクトリ以下にあるスクリプト群はinitrd.imgの中にコピーされて、起動時にinitrdで動いている段階で実行されるということらしい。 スクリプトを見る感じ、実行時の ${rootmnt} 変数とかが見慣れないものの大体やってることは予想通りだ。tmpfsをマウントして、元のrootを他のマウントポイントにどかしてreadonlyでremountして、それからaufsで両者を重ねる。

  4. 再起動する。 さっきのスクリプトカーネルの引数にaufs=tmpfsを渡したときのみ発動するように書かれているので、起動時に引数を手入力した。

  5. 起動後 mount が期待通りであることを確認する。

    なお、ヘルプページにも書かれているように、rootaufsだとdhclient3がapparmorに引っかかって動かないようだ。おまけにDHCPを何度か再試行する間、起動を待たされる。私の用途ではDHCPは必要ないのでIPはstaticに割り振ることにした。 ログを見る限り、この問題って起動タイミングの関係上rootfsの移動によってdhclient3のリンクされるライブラリのパスがapparmorが思ってるやつとずれてしまうのが原因みたいね。dhclient3をprelinkとかすれば解決するんだろうか。まー今回は関係ない。

  6. 次は、常にaufs=tmpが渡るようにGrubを設定する。

    ヘルプページに書いてあるのはたぶんGrub1の設定だ。今回の環境の場合はGrub2なので少し手順が異なる。 といっても、やることは簡単で /boot/grub/menu.lst の代わりに /etc/default/grubGRUB_CMDLINE_LINUX_DEFAULT に"aufs-tmpfs"を設定するだけだ。 設定した後は sudo update-grub/boot/grub/grub.cfg を再生成する。

    以上により、起動時に自動的にaufs-tmpfsが引数に渡るように /boot/grub/grub.cfg が設定され、かつカーネルを入れ替えたりして grub.cfg が再生成されても設定が保たれるようになった。

さよならピアソン

ピアソン桐原のピアソングループ離脱にともない、 ピアソンの技術書和書は書店在庫限り だそうだ。

聞いたとき、これは日本のソフトウェア開発にとってとんでもないことだと思った。それ以前に私にとっても困ったことだ。だから、在庫限りであるならばそれを押さえなければならないということで急ぎ書店へと向かった。 しかし、見渡しても買うべき本をそれほど見つけられない。これは何故だろう。

なるほど、古典的名著は数多くある。『達人プログラマ』『アナリシスパターン』『リファクタリング』『計算機プログラムの構造と解釈』『Effective C++』『Effective Java』『人月の神話』『テスト駆動開発』『詳解UNIXプログラミング』『プログラミング言語の概念と構造』『モダン オペレーティング システム』『分散システム―原理とパラダイム』『Java仮想マシン仕様』。どれもその技術分野を触る人なら最低限読んでおく必要のある本ばかりだ。そして、『Modern C++ Design』。

Modern C++ Design―ジェネリック・プログラミングおよびデザイン・パターンを利用するための究極のテンプレート活用術 (C++ In‐Depth Series)

Modern C++ Design―ジェネリック・プログラミングおよびデザイン・パターンを利用するための究極のテンプレート活用術 (C++ In‐Depth Series)

これはC++の歴史をかえた本だ。それに個人的にも、この本をたまたまふらりと入った六本木の青山ブックセンターの新刊棚で手に取らなかったら私はソフトウェア開発を職業にしてない。 そうだとも、あの華々しいC++翻訳書の数々を覚えているだろうか。だからこそ私だって、この度のニュースを「とんでもないことだ」と戦慄したのだった。

だが、買うべき本がない。私に関して言えば上のような基本中の基本の本はもう買ってある、というのもあるけど、それだけではない。

  • C++とかCORBAがそこら中で使われてる時代でもないし
  • Effective Javaとか、開発文化じゃなくて純粋技術の話は読みやすいから原書でもいいし
  • SICPとか原書の方が読みやすいとすら言われるし
  • タネンバウム先生の本は分厚いから、まー売れなそうだし、それを仕事で触るのでなければ必須でもないし
  • そして、Javaオブジェクト指向デザインもコンピュータサイエンスも、ピアソンのラインナップの後続にあたる最近の「must have」な本はみんな翔泳社オライリージャパンが翻訳している

これは売れなかろう。技術書から撤退という判断はやむなしなのかもしれぬ。

英語が苦手な人でも読んでほしくて惜しまれるのは

ぐらいか。