>

2010年12月15日水曜日

SyntaxHighlighter覚え書き

ブログにソースコードを書くときはSyntaxHighlighterが綺麗にハイライトして表示してくれそうなのでその使い方の覚え書き。

ブログのテンプレートなどをいじってSyntaxHighlighterのjavascriptを読み込むよう編集する。

ブログの記事を書くときはソースコードを次のように囲む。

###MY_CODE###

brush名はコードの種類に合わせて適切なのを選択する。
利用可能なbrushはこちらを参照のこと。

2010年11月10日水曜日

if 文の中括弧とコメントの書き方

if 文の中括弧は下の例のように条件式と同じ行には書かずに改行してから書く。

if else ブロック全体に対するコメントは最初のif 条件式の前の行に書き、条件文の意味に関するコメントは条件式と同じ行の右となりに書くことで二つの種類のコメントを区別しやすくすると全体的に見やすくなる気がするので。
//if elseブロック全体に対するコメントはここに書く。
if (index == -1)//この条件式の意味に対するコメントはここに書く。
{
    ...;
}
else if (index == fragments.Count)//この条件式の意味に対するコメントはここに書く。
{
    ...;
}
else//この条件式の意味に対するコメントはここに書く。
{

}

2010年10月22日金曜日

CollabNetのsubversion for Win32bitをうまくインストールできない件

CollabNetのsubversionをインストールすると自動的に C:\csvn\launch.html が開かれるのだけどいつまでたってもConsole StatusがNot Readyのままで何も始まらない件で僕のケースでの対応をまとめる。

まず、Serviceが動いてないのかなと思って、登録されたCollabNet Subversion Serverを手動で開始するとエラーで
httpd.exe: Could not open configuration file C:/csvn/data/conf/httpd.conf:
みたいなメッセージが出るのは問題なし。httpd.confは本来subversionの設定UIで設定作業を行うと自動生成されるものらしい。

設定UI(CollabNet Subversion Edge)が動かないのが本質的な問題だが、この理由は環境変数JAVA_HOMEで指し示されているJavaがおかしくて CollabNet Subversion Edge Service のインストールに失敗していたことが原因だった。
設定UIのインストールは %JAVA_HOME%\bin\java.exe を使用して行われるが試しに僕の環境でコマンドプロンプトからこのJavaを実行すると

Error occurred during initialization of VM
java/lang/NoClassDefFoundError: java/lang/Object

というエラーが出てしまい、設定UIの起動に失敗していた。コントロールパネルからJavaを一旦アンインストールしてからSun(Oracle?)のサイトからJRE6の最新版をインストールしてやることで解決した。なお、JAVA_HOMEが示すjavaは1.6以上じゃないと動かないので注意。
こうしてJAVA_HOMEの下のjavaを実行するとちゃんとオプションの説明みたいなのが出るような環境にしてから

C:\csvn\svcwrapper\bat\installService.bat

を実行するとCollabNet Subversion Edgeが正常にインストールされる。手動でインストールしたらServiceの画面からCollabNet Subversion Edgeを手動で開始すると元のC:\csvn\launch.htmlにてConsole StatusがReadyになった。
Readyになるまで結構時間がかかるので注意。

参考
http://subversion.open.collab.net/ds/viewMessage.do?dsForumId=3&dsMessageId=381180

2010年9月28日火曜日

JavaからJDBCを使用してOracleにSQLを投げるときのTimezoneの注意点

有名な話ではあるとは思うがJavaのOracle JDBCドライバはタイムゾーン情報を持てない。
※JDBC全般の話なのかOracle特有の話なのかは未確認だがAPI仕様を見る限りJDBC全般の話かも。

JavaからJDBCを使用してOracleにSQLを投げるときにSQLのWHERE句に日時が入っているときはタイムゾーンに関して注意が必要。

PreparedStatementにsetTimeStampやsetDateしてSQLを実行する際、JDBCは引数で渡すDateのエポック秒でSQLを実行するのではなく、引数で渡したDataをマシンのデフォルトタイムゾーン
で出力した(タイムゾーンを伴わない)日時でSQLを実行する。DBを受け取った日時をDBのタイムゾーン設定に基づいて解釈する。

なので特に対策をしないで実行すると次のような問題が起こる。
  • クライアントマシンのタイムゾーンとDB(Oracle)のタイムゾーンが異なると意図する結果が戻らない。
  • クライアントマシンのタイムゾーンが一致していたとしてもJavaで勝手にサマータイムとかが考慮されて一時間ずれた結果が戻ったりする。

特に二つ目の問題は、プログラムをリリースした時期が冬で正常に動作していたのにサマータイムの季節に突然発症したりして厄介。

以上を踏まえるとクライアントのJavaプログラムでSQLを呼び出すときには次の処理を忘れずに行う必要がある。
  1. Javaプログラム中でDBのタイムゾーンをGMT-HH形式で保持する。
    Timezone oracleTZ = TimeZone.getTimeZone("GMT-5");
  2. そのタイムゾーンをデフォルトタイムゾーンとして指定する。
    TimeZone.setDefault(oracleTZ);

デフォルトにすると不都合な場合はPreparedStatementで時刻を扱う都度設定。
PreparedStatement ps = ..... ;
ps.setTimestamp( 1, t, Calendar.getInstance(oracleTZ) );


まとめると
  • OracleJDBC(OracleのみならずJDBC全般の可能性あり)はタイムゾーン情報を持たないためJavaプログラム中にデータベースのタイムゾーン設定する必要がある。
  • Javaプログラムでタイムゾーンを設定する場合は"EST"みたいな三文字略称を使うと勝手にサマータイムとかが考慮されることがあるので"GMT-5"のような形式で設定するのがよい。

捕捉
もっとも大抵の場合はWHERE句でバインド変数の日時を使うのを避けてOracleのSYSDATEなどDB内で完結した表現で日時を設定するのが無難と言えば無難。

2010年9月14日火曜日

CloudFrontによる一回目ダウンロードの速度調査

CloudFrontは基本的にはキャッシュサーバなので一回目のDLでは速度向上は期待できないのではないかという疑問があったので実験してみた。

実験は1.5MBのデータファイルをAmazonS3のBucketから直接DL(RESTのGET API )するのに要する時間と同じファイルをCloudFrontを使用してDLするのに要する時間を比較した。
実験では各イテレーションで実験用ファイルをその都度新規ULしてから時間を計測しているのでCloudFrontからのDLは常に一回目である。実験結果を以下に示す。

【実験条件】
実験日時:2010年4月26日
AmazonS3のBucket置き場所:US
アクセス元:日本
ファイルサイズ;1,722,874バイト
イテレーション数:100回

【結果】
Bucket直接アクセスの平均DL時間:11.7秒
CloudFront経由アクセスの平均DL時間:4.3秒


結果を見てのとおり、CloudFrontはたとえそのコンテンツへの初めてのアクセスであってもDLに要する時間を半分以下に短縮していることが分かった。単なるキャッシュサーバ以上の役割を果たしているようである。

2010年4月2日金曜日

エラーコードは振るべきか否か

エラーログを人間が読むときはエラーコードはなくてもよい。エラーメッセージの内容のほうが人間にとってよりわかりやすいから。

ただし、ログ解析をするときはエラーコードがあった方が望ましい。
ログ解析では個々のエラーの件数を数えることをほとんどの場合で行うと予想されるがその時のログ抽出条件として一意のエラーコードで抽出するのが合理的。
エラーメッセージそのもので抽出する場合はエラーメッセージがユニークであることを保証しなくてはならないが実装者間でそれをやり取りするのは困難である。その他の一意な文字列で抽出することは可能かもしれないがグラフ化したときに凡例には短いエラーコード文字列で記載された方が便利であるためエラーコードを使用する。

つまりエラーコードは人間の理解のためではなく解析的メリットのために存在するのではないだろうか。

※ORA-ERRORを見るとエラーコードは上記のためではなく人間がそれをキーに検索をして内容を知るような設計になっているがこれはキーを元に多言語化されたエラーメッセージを引く要望があるからだと思われる。エラーメッセージを多言語化したいならException発生時にはメッセージキーのみを決定されることになりこのメッセージキーは簡潔で一意の文字列になるべきである。

よく同じような内容のエラーではソースコードの異なる場所でも同じエラーコードを使いまわす例があったがこれは使いまわす条件を定義するのが困難であるためやるべきではない。

必要に応じて解析ツール側でグルーピングを行った方が安全であるように思う。

エラーコードは基本的にMyExceptionのコンストラクタで定義する。
Javaコードを編集してエラーコードを埋め込むエラーコード管理ツールを作成し、それは以下の機能を持つ。
  • MyExceptionのコンストラクタの引数に一意にエラーコードを振る。
  • 採番したエラーコードとエラーメッセージの組みをCSVに出力する。

ログに出力したいエラーはすべてMyExceptionでラッピングすることをルールとする。SQLExceptionであろうとなんであろうとログに出力したい場合はすべてMyExceptionのコンストラクタに食わせることを
ルールとする。

このツールはbuild.xmlなどから呼び出して本番用バイナリをビルドするときにエラーコード管理票を出力し、ビルドバージョンとともに管理する。その時に毎回全部やっていると大変なので、引数に
パッケージ名を指定できるような仕様にしておくと良さそう。

と言ってみたもののまだまだ問題がありそうですね。
この辺はみなさんどう対応してますか。

2010年2月18日木曜日

Windows上のFlex SDK(Flex Builder)でASDocがうまく作成されない件

WindowsでASDocを作成しようとすると

Error: could not find a JVM.

と怒られる場合は
C:\Program Files\Adobe\Flex Builder 3 Plug-in\sdks\3.2.0\bin\jvm.config
にあるjava.homeの項目を次のように編集する。

java.home=/Program Files/Java/jre1.6.0_07

上記は僕のJVMのインストールフォルダだが要するにC:\...のような形式ではなく/から始まる形式にする。通常はC:\が/に対応する。

2010年2月17日水曜日

ActionScriptのメンバ変数の命名では頭に_をつけるべきか

メンバ変数の名前の先頭にはアンダーバーをつけるべきかどうか。

FlexBuider 3を使用した場合、Javaエディタと異なり、ActionScriptではメンバ変数のフォント色を自動的に変えてくれないため一目で見分けがつかない。
この解決方法として命名規則とかでプレフィックスとしてアンダーバーをつけてこれを解決することは妥当なのか考える。

一目で見分けがつかない不便さの解消方法としては_とかをつける他には全ての参照箇所でthis.をつける方法があるがこの方法と比較してみる。

1)this.は参照箇所すべてに付ける必要があり、コーディング規約としては抜けなく守るのが難しい
2)次のようなコードではthis.はHogeインスタンスを示さないので逆にthis.をつけてはならない。こうなるとthis.がついたりつかなかったりで混乱を招く

public class Hoge
{
 var private myMemberStr:String = null;

 public function AlbumManager(albumUrl:String)
 {
  var proc:MyProcedure = new MyProcedure();
  proc.execute();

  proc.addEventListener(Event.COMPLETE, function(event:ResultEvent):void{
   //ここでthis.を入力するとFlexBuilder3のオートコンプリートではmyMemberStrが
   //候補として表示されるがこれはバグ。
   //この行が終わってもHogeインスタンスのmyMemberStrはnullのまま。this.をつけなければ
   //意図したとおりにHogeインスタンスのmyMemberStrにevent.resultが代入される。
   this.myMemberStr = event.result as String;
  });
 }
}


以上より全ての参照箇所でthis.をつける方法は危険。よって_をつけるのは妥当である。
なお、基本的には_をつけたメンバ変数は基本的にはprivateにし、アクセスにはgetter, setterを使う。getter, setterでアクセスする際は_はつけない方がかっこいいのではないかと思う。(というか普通そうなのかもしれないが。)

//例
//メンバ変数名には頭に_をつける
private var _myMemberStr:String;

//関数名には_はつけない
public function myMemberStr ():String{
 return _myMemberStr;
}


結論として
ActionScriptのメンバ変数の命名では頭に_をつける。メンバ変数はprivateとしてそれにアクセスする際にはgetter, setterを用いる。getter, setterの関数名には_はつけない。

2010年1月31日日曜日

Hello World extensionをビルドしてみる

次はBuilding an Extensionに従いHello World extensionをビルドしてみる。

まずすることは上記サイトのリンク先からHello World extensionをダウンロードして解凍する。次にこの内容に対する説明がmozillaZineのGetting started with extension developmentに詳しく説明されているのでなんとか読んで理解する。

上記サイトによるとChromeとXULの概念の理解が前提条件になっている。
ChromeとXULについてはここで丁寧に紹介してくれている。

とりあえず、概念の詳細な勉強は後回しにしてダウンロードしたHello World extensnionを開発用プロファイルで開いているFirefoxにインストールしてみる。

DLしたhelloworldフォルダを適当な開発に使っているフォルダ(僕はD:\dev\FirefoxExtensions\の下)にコピーする。

次にPROFILE_FOLDERを開く。PROFILE_FOLDERはOSと先ほど作成したFirefoxの開発用プロファイルの名前によって異なる。各OSでのパスはここで説明されている。ここではWindows2000より上に限っていうとWindowsキー+Rで「ファイル名を指定して実行」を開き、"%APPDATA%\Mozilla\Firefox\Profiles"と入力してEnterするとExploreで開かれるフォルダがPROFILE_FOLDERとなる。

PROFILE_FOLDERの下には0v2q6gns.devみたいな名前のフォルダがある。この.より後のdevが開発用プロファイ名と一致しているフォルダが開発用プロファイルの設定を記述する場所である。

さらにその下のextensionsフォルダを開き、そこにhelloworld@mozilla.doslash.orgという名前のファイルを作成する。このhelloworld@mozilla.doslash.orgという名称は今回インストールしようとしているextensionのIDであり、DLしたhelloworldフォルダの中にあるinstall.rdf内で記述されているem:id要素の文字列と一致している必要がある。

で、そのhelloworld@mozilla.doslash.orgファイルの中にはHello World extensionの実体の所在地を示す次の一行を記述する。

D:\dev\FirefoxExtensions\helloworld


これで大方の作業は終わったのだがしかしこのままでは正常にインストールできない。DLしたhelloworldフォルダの中にあるinstall.rdfをエディタで開いてem:maxVersion要素の値を確認する。デフォルトだと1.5.*とかだと思うのでこの値を今使っているFirefoxのバージョンをサポートするように変更する。このエントリを書いているときは3.6だったので3.6.*と書いてみた。

さてこれで本当に設定が完了。Firefoxを再起動するとアドオンダイアログが開きインストールされましたというメッセージが表示される。メニューのツールを選択すると一番下にHello World!というメニューが増えていてこれを押すとHello Worldというウィンドウが開くことを確認できる。

開発環境の構築

Setting up an extension development environment
にはFirefoxを開発用にチューニングする設定や開発に欠かせないアドオンが書かれている。ここに書いてある内容を設定することでプロファイルをFirefox実行時の引数で分離し開発用Firefoxを起動できるようになる。ちなみにここにもほぼ同等のことが日本語で分かりやすく説明されている。設定したらFirefoxのショートカットのプロパティのリンク先を"C:\Program Files\Mozilla Firefox\firefox.exe" -no-remote -P devとかにしておいてそれをデスクトップとかクイック起動とかに置いておくと便利と思われる。
僕は通常のFirefoxにはGoogleツールバーは入れていないが開発用のFirefoxにはGoogleツールバーをインストールして常にログインした状態にしている。マウスオーバー辞書とかBlogger投稿が楽なので。

2010年1月30日土曜日

MyExceptionクラスを作成する必要があるケース

Exceptionを継承したMyExceptionクラスを自分で作る場合は多分次のときだと思う。
  • 自分のプログラムでExceptionに独自の機能を持たせたいとき。どのような機能を持たせるべきかはそのプログラムで採用する例外処理の規則によって異なる。例えばフィールドにログレベルを持たせたRuntimeException継承クラスを作成して全ての例外はベースとなるクラスでログに出力するとか。検査例外(例えばSQLExceptionとか)は全てMyExceptionのコンストラクタに食わせて、同時にメッセージとログレベルを設定してやるとかにしておけば複数のプログラマで開発しているときでも比較的全員に例外処理のルールを周知しやすい。
  • catch節で発生した例外の種別によって条件分岐をさせたいとき。発生した例外の種別によって後処理を切り替えたいときで、Javaで用意されているException(NumberFormatExceptionとか)で意味合い的にちょうどいいのがなかったときも適切な概念を持つMyExceptionクラスを自分で作っても良いかもしれない。ただし、プログラム的に正常系で単にif文とかの代替として例外種別による切り替えをするのはよくないとEffective Javaに書いてあった気がする。あくまで例外系での後処理の切り替えに使用するべきだと思う。例えばログイン時にユーザIDとパスワードの組み合わせが間違っていたのか個人情報を管理しているDBへのアクセスが出来なかったのかを分岐させて適切な表示をユーザに提示するときとかは例外種別による切り替えが適切な状況だと思う。

2010年1月25日月曜日

定数の管理場所

システムで定数を定義する場合はどこで定義するかをちゃんと考える必要がある。
定義する場所はちょっと思いついただけでも次のようなところがある。
ちなみにこの文章で定数と呼んでいるのは結構あいまいで、ローカル変数以外の値のことを指している。

  1. 環境変数
  2. propertiesファイル
  3. J2EEコンテナなどのプラットフォームが読み込む定数ファイル
  4. Constant.javaなどのjavaファイル
  5. JVM引数
  6. Java引数
  7. DB

それぞれの管理場所は変更のしやすさや一覧のしやすさが異なる。またその値を参照できるスコープも異なる。それぞれの管理場所ならではの特性をちゃんと考えて定数を管理すべき場所を考える。

とはいえこれで決まりと言う完璧なルールは存在せずプログラムの性質(ただのJavaアプリであるとかサーバアプリであるとか)や運用スタイル次第なところがあるので自分でそれぞれの特性を考えた上で、運用を想像して最終的な結論を出す。ただ忘れてはならないのがそれぞれの管理場所には必ず差があり、その差に応じた管理場所を真剣に考えなくてはならないということ。

環境変数はそのマシン固有の値であり、1回決めてしまえばその後はほとんど気にする必要がない。システムを構成するマシンのスペックにバラつきがある場合は、そのスペックの影響を受けるであろうjavaのヒープサイズとかはここで決めると便利なことがある。

DBはシステムを構成するアプリサーバが複数台であるとき、どのサーバからも一貫性を保って参照でき、またデータの変更は永続的に残るといった特徴がある。参照の負荷は他のところで定義される値に比べると高い。ユーザの操作によって刻一刻と変化するシステムのステートをあらわす値(主な)やシステムに対して一斉に制御したいトリガ値とかはDBに保存すると良い。基本的にはDBに保存しないとどうしても成り立たない値のみが保存されると考えてよいと思う。

その他propertiesファイルは一覧性と変更のしやすさが比較的高いだとかConstantクラスの値はまず変更は出来ないなど各自で特性を考慮した上で決めるのが大事。

2010年1月24日日曜日

Firefox add-onの種類

extension(拡張機能)とpluginとsearch pluginがあるらしい。

search pluginはデフォルト右上にある検索窓で検索できるサービスを追加するものと思われる。xmlで設定されているようだ。

pluginは外部のexeとかのプログラムと連携する際の橋渡しをするプログラムのことらしい。

extensionはFirefox上で動作して機能を拡張するものらしい。今回の目的であるハイライトを同じように行っているGoogleツールバーやTrendmicroのツールバーもextensionらしく、表示するhtmlの元ソースの中に何かタグを埋め込んで表示することが出来るものと思われるので僕が作りたいのもextensionの作成方法を理解すればよいようだ。

以降
https://developer.mozilla.org/en/Extensions
のドキュメントに従って作って行きたい。

Firefox add-on開発を始めました。

外部ファイルの情報を元に、表示しているhtmlの一部をハイライトするをブラウザ上で表示できるFirefox add-onを作成したいと思い、開発を始めることにしました。

Firefox add-onの知識は全くないので、まずは検索してみたがあんまり噛み砕いて説明してくれている日本語サイトはなさそうでした。先は長そうですが分かったことをなるべく書いていきたいと思います。

2010年1月20日水曜日

DBにアクセスする時のJavaコード

DBに接続するときは最終的に欲しい値(下の例の場合はsysdate)の変数宣言をconn, st, rsの変数宣言の手前で行う。conn, st, rsはDB接続のためのtry/catch/finally節が生み出すスコープのみで有効なのに対してsysdateはそのスコープよりも外で使用されることになるので。

closeのときにcatchした例外はその場で適当にログ出力してthrowしない。ここで例外が発生した場合は既に一つ前のcatch節にも入っている可能性が極めて高く、そちらでcatchした例外の方が有用な情報を持っている可能性が微かに高そうなので。まあこれはケースバイケースかも。

Date sysdate = null;

Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn = DriverManager.getConnection (url, user, pass);
st = con.createStatement();
rt = smt.executeQuery("select SYSDATE from DUAL");

sysdate = rs.getDate("SYSDATE");
}catch(SQLException e){
throw new MyException(e);
}finally{
try{
if(rs != null) rs.close();
if(st != null) st.close();
if(conn != null) conn.close();
}catch(SQLException e){
logger.error(e);
}
}