node.jsの関数型プログラミング

  • 投稿日:
  • by
  • カテゴリ:

Kmoneyを開発する過程でJavascriptについてあれこれ調べていて、node.jsに辿りついた。

サーバーサイドJavascriptの環境で、ファイル入出力やTCP/IP通信などもできるようになっている。つまりRubyやPerlと同様に使える。今までPerlで書いてきたプログラムの大半はこれで書きなおすことができそうだ。

プログラムはシングルスレッドで動き、ネットワーク通信やファイル入出力などは非同期で実行される。プログラミングのモデルはオブジェクト指向ではなく、関数型になる。

var fs = require('fs');

function readdirCallback(err, files) {
	function readFileCallback(err, data) {
		console.log(data);
	}

	for (var i = 0; i < files.length; i++) {
		if (files[i].indexOf('.js') !== -1) {
			fs.readFile(files[i], 'utf8', readFileCallback);
		}
	}
}
fs.readdir('.', readdirCallback);

カレントディレクトリにある'.js'の付いたファイルを読み込む処理はこんな感じ。ディレクトリを読み込むreaddir()、ファイルを読み込むreadFile()にコールバック関数を渡して、読み込んだデータに対する処理はコールバック関数の中で行う。非同期の処理なので独立のスレッドにする必要はない。

このモデルはJavascriptの特性によく合っているように思える。プロトタイプベースのオブジェクト指向モデルに対する違和感はやっぱり正しかったようだ。この点はNodeビギナーズブックというチュートリアルで指摘されていて、Javaが「名詞王国」であるのに対してJavascriptは「動詞王国」とのこと。

Javascriptのオブジェクト指向は分かりにくい

  • 投稿日:
  • by
  • カテゴリ:

HTML5の時代になると、アプリケーションロジックはJavascriptで書かれることになる。現在はC++やJavaで書かれているアプリケーションがJavascriptで書かれる。データベースは長年支配的だったSQLからJavaScriptと親和的なIndexedDBに代わる。

しかし、本当にそんな時代が来るのだろうか?

C++とJavaは文法が比較的近いので、どちらか一方が分かればもう一方を習得するのは難しくない。しかしJavascriptはC++やJavaとは基本的な枠組みが違う。C++やJavaはクラスベースのオブジェクト指向で、クラスをインスタンス化してオブジェクトを作るのに対し、JavaScriptはプロトタイプベースのオブジェクト指向で、既存のオブジェクトをプロトタイプとして新しいオブジェクトを作る。C++やJavaに慣れ親しんできた私にとって、これはなかなか理解しにくい。

Javascriptにはオブジェクトを作成する方法が大きく分けて二つある。オブジェクトリテラルを使う方法と、関数オブジェクトに対してnew演算子を使う方法だ。

オブジェクトリテラルを使う方法は以下のようになる。

var testObj = {
	strValue: "Hello",
	testFunc: function() {
		this.strValue = "Bye";
	},
	showValue: function() {
		alert(this.strValue);
	}
};
testObj.testFunc();
testObj.showValue();

私がKmoneyの元ネタにしているSQL Managerではこの方法が使われている。しかし、オブジェクトリテラルは元々はデータ構造を表現するためにあるはずなので、そこに関数の定義を含めるのは違和感がある。各メンバーがセミコロンではなくカンマで区切られるのも単純ミスの原因になる。

関数オブジェクトに対してnew演算子を使う方法は、クラスベースのオブジェクト指向に慣れた人間にとって一見親しみやすい。

function TestObject() {
	this.strValue = "Hello";
};
TestObject.prototype.testFunc = function() {
	this.strValue = "Bye";
};
TestObject.prototype.showValue = function() {
	alert(this.strValue);
};
var testObj = new TestObject();
testObj.testFunc();
testObj.showValue();

関数の定義が実質的にコンストラクタとなり、そのあとにprototypeをつけたメンバ関数の定義が続く。メンバ変数の定義はコンストラクタの中に書かれる。しかし、オブジェクトをプロトタイプとしてオブジェクトを作るはずのJavascriptで、クラスをインスタンス化するかのように書いてしまうことには疑問が残る。Javascriptの特性を無視しているように感じる。

継承に関しても、Object.create()を使って実現する方法とprototypeで継承元を設定する方法がある。前者はオブジェクトリテラルを使う方法の延長線上にあり、後者はnew演算子を使う方法の延長線上にある、と考えてよさそうだ。

var secondObj = Object.create(testObj);
secondObj.testFunc = function() {
	this.strValue = "How are you?";
};
secondObj.testFunc();
secondObj.showValue();

function ThirdObject() {
};
ThirdObject.prototype = new TestObject();
ThirdObject.prototype.testFunc = function() {
    this.strValue = "May I help you?";
};

var thirdObj = new ThirdObject();
thirdObj.testFunc();
thirdObj.showValue();

Javascriptの場合、継承といってもC++やJavaとは意味が異なる。C++やJavaで派生クラスをインスタンス化した場合にはオブジェクトは一つしかないのに対し、Javascritでは二つのオブジェクトをprototypeという鎖でつないでいるだけだ。is-a関係は存在せず、特殊なhas-a関係によって継承らしきものを実現している、と考えればよいか。

分かりにくいなあ、というのが正直な印象だ。私の頭がついていけないだけで、HTML5の時代にはみんながこれをスッキリ理解するようになるのだろうか。せめて上記の点については標準的なベストプラクティスが確立して、みんな同じ書き方を採用するようになってほしいものだ。

XULは引退間近?

  • 投稿日:
  • by
  • カテゴリ:

Android版Firefoxは、14になって劇的に速くなったという。

私のスマートフォンでは、Googleで検索してから検索先のページへ行こうとするとクラッシュするという状況。どれくらい速くなったのかは確認できない。

しかしそれはいずれ解決するだろうからいいとしても、もっと問題なのは速くなった理由のほうだ。UIがXULではなくAndroidのネイティブUIを使って作られることになった。エクステンションもXULではなく新しいAPIで作ることになる。

以前のAndroid版Firefoxはまともに動かなかったので、XULを捨てるという決断も仕方がないところだと思う。

一方デスクトップでも、XULは少しずつ引退への道を歩んでいるように見える。もうすぐ一般公開されるMozilla MarketplaceにはHTML5で書かれたアプリケーションが並ぶ。搭載端末が来年発売されるFirefox OS(Boot to Gecko)でもアプリケーションはHTML5で書かれる。XULの居場所はなさそうだ。

現在開発中のKmoneyは、デスクトップ向けにXULアプリ、スマートフォン向けにAndroidアプリという2バージョンに分けるというプランで進めている。しかし、まずはXULアプリの開発を進め、もし可能ならAndroid版Firefoxでもコードを共有したいと思っていた。見当違いの願望だったようだ。

今すぐKmoneyをHTML5で書き直すわけにはいかない。HTML5を使う場合、データベースはIndexedDBで作ることになる。これはまだW3Cの仕様が確定していないので導入しにくい。しかもスマートフォンに関してはFirefox OSが日本市場に登場するかどうかもまだ分からない。

XULアプリはJavaScriptでアプリケーションロジックを書くので、それでJavaScriptに慣れておけばHTML5への対応もやりやすくなる。とりあえずはそう考えてXULを使い続けることにしたい。

Kmoney: XULアプリでのグラフの描画

  • 投稿日:
  • by
  • カテゴリ:

XUL版Kmoneyの開発は少しずつ進んでいる。最低限度の入力機能を実装し、開発開始時からたまっていたレシートを片づけることができた。

Kmoney20120423.pngのサムネイル画像難関だと思っていたグラフは、icoというJavaScriptのライブラリを使って描画できることが分かった。Webアプリ向けのライブラリだが、XULアプリでも問題なく使える。アドオンマネージャで検索してもSVGやcanvasを直接使っているエクステンションしか見つからなかったので、できあいのライブラリで簡単に片づけることができたのは嬉しい。

次の大きなヤマは銀行やクレジットカードの明細のインポート。

OCN家計簿/zaim

  • 投稿日:
  • by
  • カテゴリ:

OCN家計簿」が、銀行口座やクレジットカードの明細をインポートする機能と、スマートフォンのアプリと連携する機能を実装していることに気がついた。私がつくろうとしている「Kmoney」と完全にかぶっている。私が思いつく程度のことは、やっぱり誰かが先に思いついているものだ。

しかし、ちょっと試してみた限りではいろいろ問題もありそうだ。

第一の問題は、銀行口座やクレジットカードの明細をインポートするためにはそれぞれのIDとパスワードを入力しなければならないことだ。新生銀行の場合、ログインするためには口座番号、暗証番号、パスワードを入力し、さらにセキュリティー・カードという乱数表から3つの英数字を入力する必要がある。そのため、OCN家計簿は乱数表のデータをすべて入力させるようになっている。これは怖い。入力画面が現れたときに恐怖を感じ、新生銀行の明細をインポートするのは諦めた。ちょっと調べてみたら新生銀行のサイトで「セキュリティ・カードの番号を電子的に登録することは決して行わないでください」と注意されていた。そもそも全ての金融機関のパスワードを一つのサイトに預けるなんて危険すぎる。

第二の問題は二重計上。クレジットカードの明細に出てくる買い物のデータと、銀行口座の明細に出てくるクレジットカードの支払いが、OCN家計簿ではカレンダー上でどちらも出費とされてしまう。クレジットカードや電子マネーを使うと買い物と支払いが分離するので、それぞれ別のカレンダーで表示できなければならない。

連携するスマートフォンのアプリ「zaim」は、ソーシャル家計簿サービスと称している。年齢や家族構成などをプロフィールとして登録しておくと、出費を同様のプロフィールの人たちと比較できる、という仕組みだ。面白いとは思うが、そのため入力ごとに通信が発生し、数秒待たされる。地下鉄の車内など、電波状況が悪いところで入力したらいったいどうなるのか。

「Kmoney」の開発を中止するほどのものではない、というのがとりあえずの結論。

家計簿アプリ「Kmoney」その2

  • 投稿日:
  • by
  • カテゴリ:

家計簿ソフト「Kmoney」のデータベース設計はだいたい終わった。銀行口座やクレジットカードの明細をインポートする機能をPerlで書いた。

この第一段階では、モダンPerlを習得するのを一つの目的にしていた。Perlは10年以上使っているが、せいぜい100行程度の簡単なスクリプトしか書いたことがなかった。今回はMooseを使ってクラスを作成し、データベースの操作にはSQL::Abstract、ファイルの入出力にはIO::File、HTMLファイルの解析にHTML::TreeBuilderを使ってみた。OFXファイルを取り込むFinance::OFX::Parse::Simpleまであったのはありがたかった。Perl-users.jpのドキュメントや「モダンPerlの世界へようこそ」が参考になった。

第二段階はPCで動作するアプリケーションの開発。Firefoxのエクステンションとして作る。(ブラウザとはまったく関係ないのでXULRunnerアプリケーションと言うのが正しいかもしれない。) さしあたってはSQLite Managerのソースコードを読むところから。

家計簿アプリ「Kmoney」

  • 投稿日:
  • by
  • カテゴリ:

ふと思いたち、家計簿のソフトを作りはじめた。

銀行口座、クレジットカード、電子マネーなどは、たいてい収支のデータをネット上で取得できる。しかしそのデータをインポートできる家計簿ソフトは私が知るかぎり存在しない。アメリカには金融機関のデータを自動的に集めてくれるMintというサイトがあるが、日本で人気があるココマネはひたすらユーザーが入力するしかない。

一方、家計簿をつけていると一番困るのが現金の収支だ。レシートがない入出金は家計簿につけるのを忘れがちになる。レシートがあっても溜め込みがちになる。最近、この問題はスマートフォンを使えば解決することに気がついた。つねに持ち歩いているので、電車に乗っている時や信号待ちの時間などに入力できる。

第一の問題は、Firefoxのエクステンションを作って解決するのが一番よさそうだ。SQLite Managerというエクステンションを流用すればSQLiteデータベースを読み書きできる。あとは現金の収支をマニュアル入力するGUIと、金融機関のサイトからデータをインポートする機能を作ればよい。

第二の問題はandroidのアプリで対応する。すでにかんたん家計簿という使い勝手のよいアプリもあるが、私にとって必要な機能がすべて備わっているわけではないので新規に作っていくことにしたい。

現在はデータベース設計の段階。これまでLibreOffice Calcで入力していた家計簿データをPerlスクリプトでSQLiteデータベースに移行させるところから始めている。アプリの名前はKmoneyとし、githubにリポジトリを作った

Textalk

  • 投稿日:
  • by
  • カテゴリ:

「声書き」として開発を続けていたアプリケーションを「Textalk」としてAndroid Marketに公開した。「声書き」はテープおこしのサービスとかぶっていたためだ。

音声認識機能のほか、Tutorial For Androidを参考にして手書き機能もつけた。音声認識だと話す→複数の認識結果から一つを選択というステップになるので、手書きのほうが簡単な気もする。

androidの最新のバージョンは4.0なのに、開発機は2.3。既にdeprecatedとされているAPIも使っている。4.0が一般的になれば大幅な変更を強いられることになりそうだ。

Androidアプリ「声書き」

  • 投稿日:
  • by
  • カテゴリ:

2年ぶりにAndroidアプリを書いてみた。

音声認識機能がいつのまにか実用レベルに達しているのに気づいたため、聴覚障害者向けのアプリとして作成した「声書き」。聴覚障害者と会話するとき、筆談の代わりに使うことを想定している。

2日で最低限度の機能だけ実装した。これからアイコンなどを作り、Android Marketに出したい。

レース作戦計画ツール

  • 投稿日:
  • by
  • カテゴリ:

マラソンを走るときはペース配分を事前にしっかり考えておく必要がある。自分の走力を正確に把握し、42.195kmを走り通せるペースで走らなければならない。

参加者が多すぎて序盤は自分のペースで走れないことも多い。終盤は疲れてきてペースダウンしてしまうのが普通だ。そんなことを考慮に入れながら目標タイムで走るためのペース配分を考える。

ペース配分を考えるツールとして、ネット上には既にマラソンレースシミュレーターペース計算ツールがある。マラソンレースシミュレーターはよくできているが、目標タイムからペース配分を計算する方式なので今ひとつ使いにくい。私は「5kmなら4分20秒/kmで走れる」「5分/kmペースなら30kmまで持続可能」などと自分の走力を把握しているので、そこからフルマラソンの目標タイムを設定したい。ペース計算ツールは距離とペースからタイムを計算できるが、イーブンペースが前提なのが物足りない。

そこで作ってみたのが「レース作戦計画ツール」。数年ぶりにJavascriptを使って書いた。