Bug Pattern というか今日のミス

– 事前に気づいたけど相当焦ったもの。

SELECT * FROM foo WHERE …;

な、ただレコードの有無を調べる(要素は取り出さない)クエリのパフォーマンスを意識して SQL クエリのみ書き換えたときに、うっかり次のようにしまった。

SELECT COUNT(*) FROM foo WHERE …;

常に 1 レコード返るようになり、レコード数 0 のときも毎回処理が行われることに… リリース前に自分で気づいたけれど反省。

委譲とコンポジション(Effective Java の間違い)

Effective Java には、自身を参照にして渡さないと委譲とは呼べない、とあるが、これは間違い。Effective Java にも挙げられている [GoF P32] には次のようにある。

委譲では、1 つの要求を 2 つのオブジェクトが扱う。要求を受け取ったオブジェクトは委譲者へオペレーションを委譲する。これは、サブクラスが親クラスに要求を渡すことと同様である。

Effective Java にある自身の参照渡しはどこからでてきたのかというと、多分次の文の誤解から。

しかし継承の場合は、継承されたオペレーションは、C++ ならば this メンバ関数、Smalltalk ならば self を用いて、要求を受け取ったオブジェクトを参照できる。委譲でこれと同じ効果を実現するには、要求を受け取ったオブジェクトが自身を委譲者に渡す。そうすれば、委譲したオペレーションが受け手のオブジェクトを参照できるようになる。

その他参考:
<http://www.ogis-ri.co.jp/otc/otc2/oosquare-ml/Archive/200005.month/767.html>
– オージス総研 ML

MySQL で ENUM を使うべきではない

– ENUM 型のカラムには、リストにない任意の文字列をエラーなしで指定できてしまうため、不具合の温床になりうる。例えば次のテーブルを考える。

CREATE TABLE `foo` ( `number` ENUM(‘zero’,’one’,’two’) NOT NULL DEFAULT ‘zero’);

これに zero, one, two 以外の値が入ることは望ましくないが、リストにない文字列をいれることで空文字が入ってしまう。

mysql> INSERT INTO `foo` VALUES (‘six’);
Query OK, 1 row affected, 1 warning (0.03 sec)
 
mysql> select * from foo;
 +——–+
 | number
 +——–+
 |
 +——–+
1 row in set (0.02 sec)

これは typo でも発生してしまうため、TINYINT などを使って、マジックナンバーは各言語の const 変数でラップしたほうがエラーを捕捉できていいかなと。

Servlet の基本

– 基本は通常のクラスと同じだが、条件として javax.servlet.http.HttpServletを親クラスとする必要がある。
– protected void do*(HttpServletRequest, HttpServletResponse)
doGet, doPost, doDelete, doHead, doOptions, doPut, doTrace があり、それぞれ対応するリクエストのときに呼び出される。
– protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException
別のオーバーロードされた service メソッドから処理を受け、配分するのが役目なので protected。
parent.service(req,res) を呼び出した時点で do*(req,res) の処理が行われるので、その前後の共通動作を定義するのに便利。
– 日本語(マルチバイト文字)を引数にとる
— getParametervalues,getParameterを使い、化けた状態の文字を取得したあと

new String(string.getBytes(“ISO_8859_1”), “Shift_JIS”);

のようにする。(HTTPプロトコルの文字コードが ISO-8859-1 のため)
— HttpServletRequestクラスのsetCharacterEncodingで、パラメータを取得する前にエンコードを指定しておく。
— HttpServletRequest#setCharacterEncoding(String enc) の挙動の違いの問題に注意!
Tomcat 4.1.29 以降の 4.1.*/5.0.16以降の 5.0.*、では、Getメソッドではエンコードされなくなった。GETの引数はURIに含まれるので、URIはエンコードされるべきではないという見解による仕様変更とのこと。
– スレッドセーフということ。
サーバサイドでは1つのインスタンスを使いまわしてマルチスレッドで動作するので、スレッド同士の不要な干渉をなくさなければならない。
“staticではない”フィールド(インスタンス変数)もスレッド間では共有されている事に注意!
–> ページ閲覧者固有の変数を持ちたい場合、メソッド内で定義した変数を使わなければならない。
データアクセスなど同期を取らないといけない場合は、(デッドロックにくれぐれも注意しつつ)適宜 synchronized にする。

メールのContent-Header, Content-Body の仕様(RFCのピックアップまとめ)

世界中で標準となっているeメール仕様(SMTPプロトコル仕様)はRFC822などのRFCドキュメントです。
原本を読めばすべて書かれているのですが、全部読むのは大変なのでピックアップしてまとめてみました。

続きを読む メールのContent-Header, Content-Body の仕様(RFCのピックアップまとめ)

Outlook Express で Multipart/Related したときの望ましくない挙動

– ドキュメント整理(2004-06)
– Multipart/Related でも、直接の呼び出しが実行中のメールに存在しない場合には添付ファイル扱いになる(A HREF=”CID:〜”ではだめ)。
– HTML同士の Related で<A>や<Iframe>を使おうとしても無理。やはり添付ファイル扱いに。

PHP でメールするときの注意等

– 過去に書いたドキュメントを整理するため、整形してコピペ。内容は多分 2004-06 くらいのもの。
– mail関数と、そのラッパーであるmb_send_mail関数があるが、後者はオプションのヘッダ指定に無関係に、自動的に

MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-2022-JP
Content-Transfer-Encoding: 7bit

という3つのヘッダを挿入する(Content-Typeを明示的に指定していてもなお)。
– mail関数のデフォルトのヘッダーは
mail(‘[email protected]’,’title’,’message’);
として送信した場合、

Return-Path: <[email protected]>
Delivered-To: [email protected]
Received: (qmail xxxxx invoked from network); 2 Apr 2004 15:13:40 +0900
Received: from unknown (HELO local.host) (xxx.xxx.xxx.xxx)
  by pcxxx.xxx.xxx.xxx.in-addr.foo with SMTP; 2 Apr 2004 15:13:40 +0900
Received: (qmail xxxxx invoked by uid 80); 2 Apr 2004 15:13:40 +0900
Date: 2 Apr 2004 15:13:40 +0900
Message-ID: <[email protected]>
From: [email protected]
To: [email protected]
Subject: title
 
message
 

のようになる。(Received:はもちろんmail関数がつけたものではない)
– MIME-Versionフィールドを指定する場合、第四引数でヘッダ指定する場合に改行は\r\nや直接の改行(SJISの場合CRLFになる)ではなく\nでなければならない。(MIME-Version:1.0を宣言した行以降は\rも\nも1つの行として認識されるため。
– PHPでHTMLメールを送るごく簡単な例)

sAddHeader = “MIME-Version: 1.0\n”
.”Content-Type: multipart/alternative;\n”
.”boundary=\”—-=_NextPart_000_0024_01C418A2.AA46C5F0\”\n”;
$sMessage = “This is a multi-part message in MIME format.”
.”\n\n——=_NextPart_000_0024_01C418A2.AA46C5F0\n”
.”Content-Type: text/plain; charset=ISO-2022-JP\n”
.”Content-Transfer-Encoding: 7bit\n\n”
.”プレーンテキストメールです\n”
.”\n\n——=_NextPart_000_0024_01C418A2.AA46C5F0\n”
.”Content-Type: text/html; charset=ISO-2022-JP\n”
.”Content-Transfer-Encoding: 7bit\n\n”
.”<font color=’red’>HTMLメールです。あ</font>いう<b>えお</b>\n”
.”\n\n——=_NextPart_000_0024_01C418A2.AA46C5F0–\n”;
//送信先メールアドレス等。
$sMailAddress = ‘[email protected]’;
$sTitle = ‘タイトル’;
if(mail($sMailAddress,$sTitle,$sMessage,$sAddHeader))
echo “sent successfully!\n”;
else
echo “sent failure”;

プラグインや国際化で動作がおかしいときに状態をクリーンにする

eclipse.exe -clean

みたく -clean オプションを付けて Eclipse IDE を起動すると、クリーンアップされて状態が直ったりする。何かあったときに一度だけやればいい。
3.0.x の日本語化周りで、一部しか日本語化されなかった場合などに有効。

Java Applet で JavaScript コードを実行する

import java.applet.Applet;
import netscape.javascript.JSObject;
 
public class jstest extends Applet{
public void start(){
JSObject js = JSObject.getWindow(this);
js.eval(“alert(‘Hello, world!!’)”);
}
}

JavaScript を Java Applet にしてサイズ圧縮をうたい文句にしているソフトより。これなら JavaScript 上で Zip 圧縮/解凍して eval したほうがいい(jar って zip だし、肝心の JavaScript は Java コードのリテラルなので *.class に生で書かれているし)。

ブラウザの JavaScript バージョンチェック

<http://members.at.infoseek.co.jp/sig1/jscript/js-vercheck.html>
– JavaScript バージョンチェック

<SCRIPT LANGUAGE=”JavaScript1.0″><!–
j=”1.0″;
–></SCRIPT>
 .. snip ..
<SCRIPT LANGUAGE=”JavaScript2.0″><!–
j=”2.0″;
//–></SCRIPT>
.. snip ..
<SCRIPT LANGUAGE=”JavaScript1.0″><!–
document.write(“Javascript “+j+” に対応しています。”);
//–></SCRIPT>

というように, <script> の language 属性を使って判別してる。このサイトでは LiveScript, VBScript もチェック対象としているが、VBScript のチェックを JavaScript の文で行おうとしてエラーになっている。IE6 は JavaScript 1.3, Firefox1.0(Gecko/20050318) は JavaScript 1.5 までに対応していた。