2008年10月28日火曜日

優秀なプログラマは空気を読んで空気を描く

まず、3つのポイントをおさらい。
  1. 変数のスコープは小さく抑える
  2. Do Not Repeat Yourself (DRYの原則) 同じコードは2度書くな
  3. 言語を極めよ

この1と2は、まったく違うようで、とても似た問題を扱っていることにお気づきでしょうか。それは「依存関係」を減らすか増やすか。


矛盾を抱えるプログラマ 変数のスコープを短くすると、コードで必要なデータを近くにまとめて依存関係を減らすことができます。要するに、コードを

inputから、output(+副作用)を作る

というメソッドと同じparadigm(パラダイム: 枠組み)にまとめたいわけです。この形にすると、コードをメソッドの形に書き直して、再利用することが簡単になります。グローバル変数を多く使っているコードは、依存関係を即座に判断するのが難しく、メソッドに纏め上げるのが大変なので忌み嫌われています。

一方、DRYの原則に従ってメソッドやクラスとして一箇所にまとめられたロジックは、使うユーザーや使われる場所が増えるため、依存関係を増やします。使う場所が増えないなら、メソッドやクラスにまとめる理由は、コードにわかりやすい名前(alias)をつけるくらいの意味しかありません。例えば、あちこちで頻繁に使われる文字列型(string)の最初の文字のindexが0ではなく1に変更されたら、大惨事になるでしょう。

プログラマって、依存関係を減らそうと努力しているかと思えば、一方で依存関係を増やそうと一生懸命になる、とても不思議な生き物です。入力から出力を作る枠組みでしか物事を考えられない、可哀想な生き物でもあります。

変数のスコープを最小に抑えると、リソースを解放するタイミングを明確にできる利点がありますが、GC(garbage collection) を搭載した現代的な言語実装では、不要になったらメモリを即解放というわけにはいかないので、スコープが多少ずれていても、さほど深刻ではありません。

プログラマは空気を読む 学生向けにプログラミングの講義をしていたときに学んだのは、ソースコードを追う能力の乏しい段階の学生さんは、抽象化されたコードの「意味」ではなく、「動作」を追ってしまう、ということ。

例えば、SQLなどは高度に抽象化されたコードの典型例でしょう。(これを宣言型という人も多いですが、抽象化の度合いの違いにすぎません)。以下のSQL文、

SELECT * FROM t1, t2 WHERE t1.id = t2.id

を見て、「2つのテーブルt1とt2でidが同じ値の行を結合する」、と読み取れたなら、おめでとう! もうあなたは立派に優秀なプログラマです。

例え内部で、lexer, parserからなるSQLコンパイラが動いていて、テーブルとクエリの静的型チェックをし、問い合わせスケジュールを組み立て、テーブルのデータ分布に基づいてスケジュールを最適化し、B+-treeとsequentialレコードを、ページロックを取得しながらserializabilityが保証されるようなプロトコルに従って検索して、必要ならライトウェイトロックで管理されたキャッシュにディスクページを保存しつつ、テーブルの結合にディスクを介したhash joinやexternal merge sortを実行していたとしても、そんなことは気にしてはいけません。SQLという入力から得られる結果の意味、つまり空気を読むことが大事です。

プログラミング言語は空気を描くもの どのプログラム言語を極めたらいいかって? 空気を読みやすくて、自分の空気を描けるもの。できなければ拡張するか、作る。これが言語を極めるということでしょう。作るのは割に合わない? 使いやすいプログラミング言語とその実装・ライブラリが出来上がるのを待つリスクが割に合うなら、のほほんと偶然の産物を待つのも一興でしょう。

(追記 10月29日)

考えることを減らせるように書く

長くなったのですが、同じラボにいた川中君がきれいにまとめてくれました。


メソッド(関数)によるコードの整理や、オブジェクト指向による実装の隠蔽、プログラミング言語のなりたちなど、プログラミングのすべてはこの動機から始まります。すばらしい。

2008年10月21日火曜日

[SQLite JDBC] Javaで始めるSQLiteデータベース入門

SQLiteデータベースは、Cで書かれた軽量データベースです。「軽量」というのは2つの意味があって、全体のコード数が10万行程度という点(PostgreSQLは100万行に近づいています)と、データベースを保存するファイルが1つに納まっているのがSQLiteの特徴です。他のシステムだと、複数のデータベース用のファイルがあって管理が面倒なのですが、SQLiteのデータベースはファイル1つで、しかもOS互換フォーマットで保存されているので、簡単にOSをまたがったデータベースのコピーを作成することができます。

そもそもリレーショナルデータベース(日本語では関係データベースと訳すことが多いです)って何?という方は、初心者向けに用意した以下の講義資料を参考にしてください。
Javaでデータベースアプリケーションを作成するには、JDBC (Java Database Connection)というAPIを使います。ただし、データベースを使うには、まずシステム側にデータベースシステムをインストールする必要があり、ここが慣れた人でもデータベースシステム(英語では、Database Management System: DBMSと言います)の設定でつまづいたり、面倒なことが多いのが難点でした。

このような問題を解決するために、SQLiteの軽量さを生かしたJava用のライブラリ(jarファイル)を作成しました。
このSQLite JDBC Driverでは、Mac OS X, Windows, Linux (i386, amd64)などよく使われるOSでSQLiteをインストールなしで動作させるために、それぞれのOSでコンパイルしたSQLiteのバイナリをjarファイルの中に埋め込んであります。これは、SQLiteが軽量だからなせる技です。プログラムの実行時に、自動的にjarファイルの中から、OSに応じたSQLiteのバイナリを取り出し、Java側でロードして使えるようにしています。

もし、少々特殊なOSや、CPUを使っていても安心です。SQLiteのCのコードを完全にJavaで動作するように置き換えたpure java版のSQLiteもライブラリに含めているので、上記以外のOSでもきちんと動作します(CをJavaコードに書き換えるのに少々無理があるので、動作は遅くなりますが)

JavaでSQLiteデータベースを使うには次の手順で行います:
  1. sqlite-jdbc-(version).jar をここからダウンロードします。2008年10月現在の最新版は3.6.4です。(Maven central repoのミラーからもダウンロードできます。)
  2. 下にあるサンプルプログラム(Sample.java)は、JDBCを通してデータベースの作成、検索をする例です。これをコンパイルします。
  3. Javaを実行するときに、上記のJARファイルを以下のようにクラスパスに含めます。
    java -classpath ".:sqlite-jdbc-(VERSION).jar" Sample
  4. これだけでJavaでDBMSが使えるようになります。お手軽!
Sample.java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


public class Sample
{
public static void main(String[] args) throws ClassNotFoundException
{
// load the sqlite-JDBC driver using the current class loader
Class.forName("org.sqlite.JDBC");

Connection connection = null;
try
{
// create a database connection
connection = DriverManager.getConnection("jdbc:sqlite:sample.db");
Statement statement = connection.createStatement();
statement.setQueryTimeout(30); // set timeout to 30 sec.

statement.executeUpdate("drop table if exists person");
statement.executeUpdate("create table person (id integer, name string)");
statement.executeUpdate("insert into person values(1, 'leo')");
statement.executeUpdate("insert into person values(2, 'yui')");
ResultSet rs = statement.executeQuery("select * from person");
while(rs.next())
{
// read the result set
System.out.println("name = " + rs.getString("name"));
System.out.println("id = " + rs.getInt("id"));
}
}
catch(SQLException e)
{
// if the error message is "out of memory",
// it probably means no database file is found
System.err.println(e.getMessage());
}
finally
{
try
{
if(connection != null)
connection.close();
}
catch(SQLException e)
{
// connection close failed.
System.err.println(e);
}
}
}
}

やや高度な内容ですが、MavenをJavaの開発に使っている人は、mavenのcentral repositoryにsyncされているこのSQLite JDBCライブラリを使うことができます。pom.xmlファイルに以下のような記述をするだけで自動的にダウンロードされます。
<dependencies>
<dependency>
<groupid>org.xerial</groupid>
<artifactid>sqlite-jdbc</artifactid>
<version>3.6.4</version>
</dependency>
</dependencies>

SQLiteではファイルにデータベースを保存せずにメモリーの上でデータベースを構築することもできるので、データベースのテスト用にも最適です。

僕のパソコンで動いたよ!証明書

開発者にとって、作ったプログラムがちゃんと動くことを証明するのは、悩みの種。なぜなら、人によってOSの設定も、インストールされているソフトウェアも違うから、作ったコードはそのままじゃ動かないかもしれない。でも安心して! そんな時はこのバッジを張ればいいんだ。

Works on My Machine Certificate 
僕のパソコンで動いたよ!証明書



Technical Certification Requirement
このバッジ(証明書)を発行するための技術的な要件は以下の通り:
  • コードをコンパイルします(他の開発者が修正した最新版のコードを使うかどうかはあなた次第であり、この証明書の要件ではありません)
  • コンパイルしたアプリケーション/ウェブサイトを立ち上げます
  • 変更箇所に該当するコードを実行します(推奨する方法は、自分の手でad-hocにコードの動作を確認すること。もし変更箇所が5行に満たない場合や、開発のプロフェッショナルとしてエラーが起こりようもないと判断できるときは、このステップを省略してもよいでしょう)
  • 修正したコードをヴァージョン管理システムにチェックインします
Notification Requirement
この証明書を使用するときの通知義務:
  • テスターや顧客に、この証明書を開示する義務はありませんが、きっと人に見せたいと思うはずです。そして、あなた自身はきっとこの証明書を相当誇りに思うでしょうが、「僕のパソコンで動いたよ!」証明書を使うときには、むやみやたらに大喜びするのではなく、さりげなくこれは自己満足なんだよ、という雰囲気を醸し出すと良いでしょう。
使用例:



2008年10月20日月曜日

Bloggerにはてなブックマークボタンを追加する

Bloggerの記事に、はてなブックマーク、delicious、livedoorクリップ、Buzzurlなどへのリンクボタンを追加する方法。

テンプレートの編集画面から、
<div class="post-header-line-1">
の箇所を探し、以下のコードを挿入します。
<div class='post-header-line-1'>
<b:if cond='data:post.url'>
<a expr:href='&quot;http://b.hatena.ne.jp/entry/&quot; + data:post.url'><img alt='このエントリーを含むはてなブックマーク' height='12' src='http://d.hatena.ne.jp/images/b_entry.gif' style='border: none;' title='このエントリーを含むはてなブックマーク' width='16'/></a>

<a expr:href='&quot;http://del.icio.us/post?url=&quot; + data:post.url + &quot;&amp;title=&quot; + data:post.title'><img alt='Add to Delicious Bookmark' height='10' src='http://static.delicious.com/img/delicious.small.gif' style='border:none;' width='10'/></a>

<a class='ldclip-redirect' expr:href='&quot;http://clip.livedoor.com/redirect?link=&quot; + data:post.url + &quot;&amp;title=&quot; + data:post.title + &quot;&amp;ie=euc&quot;' title='この記事をクリップ!'><img alt='この記事をクリップ!' height='16' src='http://parts.blog.livedoor.jp/img/cmn/clip_16_16_b.gif' style='border: none;' width='16'/></a>

<a expr:href='&quot;http://buzzurl.jp/entry/&quot; + data:post.url'><img src='http://buzzurl.jp/static/image/api/icon/add_icon_mini_08.gif' style='border:none;' title='Bookmark to Buzzurl'/></a>
</b:if>
</div>

2008年10月16日木曜日

優秀なウェブ開発者の見極め方

「Webアプリケーション技術者の見極め方(Java)」 こんな記事を見かけましたが、使えるツールやフレームワークの種類云々を聞くより、単刀直入に欲しい人材を見抜く質問はこれ。


「JavaでWebアプリケーションを開発する利害得失を述べよ」


2008年10月7日火曜日

Macのキーリピートを加速

[Mac] キーリピートを速くする方法の記事で、システムで設定できる限界値を突破する方法を書いていたのですが、効果がいまひとつ実感できないものでした。

今日発見したのが、KeyRemap4MacBookというソフトウェア。MacMiniでも使えました。インストールして、再起動後、System Preferences(環境設定)- KeyRemap4MacBookのアイコンから、キーリピート値を変更できます。

画面は、key repeatの開始までを150ms (default: 500ms)、repeat間隔を15ms(default: 30ms)に設定してみた例。おお~、速い速い。これでMacでも快適にコーディングできそうです。

どうやってこんなことを実現しているのか気になって、ソースコードを眺めたところ、kernelプログラミングで、キーボードのフィルタドライバのようなものを作っているのでしょうか、自前でキーリピートの動作を実装しています。いい仕事ですね。


このソフトは、キーボードレイアウトを変えるのが本来の用途だと思いますが、キーリピートの設定ができるだけでも十分。感謝。

License

Creative Commons LicenseLeo's Chronicle by Taro L. Saito is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 2.1 Japan License.