2008年4月17日木曜日

DB2ストアドプロシージャ メモ

Stored Procedure のページが簡潔で良いです。
この通りにやれば出来ますが、一部ハマった点があったのでメモしておきます。

まず、接続は「デフォルトコネクション」を使います。
Connection con = DriverManager.getConnection("jdbc:default:connection");

最初、'jdbc:db2://hostname:port/dbname'でやったところ見事にハマりました。

まず「resultset closed invalid operation」とか何とか出て、気持ち悪いなと思ったもののconnectionをクローズせずにやったところ「java.sql.CallableStatement.executeQuery() was called but no result set was returned.」だのなんだの。

デフォルトコネクションを使ったところ、connectionをcloseしても問題なく使えました。

次に
db2 "call sqlj.refresh_classes ( void )"

です。これを実行すると、SQL0444N rc=4 が出ました。
SQL0444N  ルーチン "*_classes" (特定名 "SQL080417102058370")
が、アクセスできないライブラリーまたはパス "...refresh_classes"、関数
"sqlj.refresh_classes" のコードで実行されています。 理由コード: "4"
SQLSTATE=42724

これも大分ハマったのですが、
以下のように'void'を取ると問題なく実行できました。
db2 "call sqlj.refresh_classes()"

以上です。

2008年4月15日火曜日

コマンドラインからCVSを使う

コマンドラインからCVSを使ってみます。
Eclipse - CVS連携はよく出来ていますが、やはり内部の動きが見えないと不安ですね。(そんなことはないですか?)

情報提供しているページは山ほどありますが、自分のために整理してみました。

■ログイン■

$CVSROOTを確認します。サーバがセットアップされているのが前提となります。
# echo $CVSROOT
:pserver:user@hostname:/cvsroot
【CVSにログイン】
# cvs login
Logging in to :pserver:user@hostname:2401/cvsroot
CVS password: ********[Enter]

■プロジェクト追加■
# ls sample_project
a.c b.java
# cvs import -m "初期登録" sample_project vendor start
N sample_project/a.c
N sample_project/b.java

■バイナリファイルの指定■
# cvs co CVSROOT
# cd CVSROOT
# vi cvswrappers
【ファイルを編集し、以下の行を追加します】
*.gif -k 'b'
*.GIF -k 'b'
*.bmp -k 'b'
*.BMP -k 'b'
*.xls -k 'b'
*.XLS -k 'b'
*.Xls -k 'b'
*.pdf -k 'b'
*.PDF -k 'b'
*.class -k 'b'
# cvs update
cvs update: Updating .
M cvswrappers
# cvs commit
cvs commit: Examining .
【viが開くので"バイナリファイル指定を追加'というコメントを入力し':wq'でviを終了します。】
CVS: ----------------------------------------------------------------------
CVS: Enter Log. Lines beginning with `CVS:' are removed automatically
CVS:
CVS: Committing in .
CVS:
CVS: Modified Files:
CVS: cvswrappers
CVS: ----------------------------------------------------------------------
cvswrappersを編集
~
~
"/tmp/cvsNrkSUb" 9 行、314 文字
Checking in cvswrappers;
/cvsroot/CVSROOT/cvswrappers,v <-- cvswrappers
new revision: 1.3; previous revision: 1.2
done
cvs commit: Rebuilding administrative file database

■CVS関連作業の終了■

cvsからチェックアウトしたファイルをリリースします('-d'オプションでディレクトリも削除されます)。一旦作業を止めるイメージです。
# cd .. # <- 削除対象ディレクトリを指定するため上位に移動
# cvs release -d CVSROOT
You have [0] altered files in this repository.
Are you sure you want to release (and delete) directory `CVSROOT': yes
#

■タグをつける■

タグをつける前に、以下のを確認しましょう。
 バージョンを構成する全てのファイルがコミットされていること
 リリースしないファイルやディレクトリがないこと
  # ls *.log *tmp* *test* *.org *.orig *.bak *.back *.[0-9]* *hoge* *piyo* *foo* *bar* # などなど
 classなどをCVSで管理している場合は、タグをつける前にコンパイルをしましょう
# ls
sample_project
# cvs tag rel20080326 sample_project
cvs tag: Tagging sample_project
(略)

■rdiffの使い方■

タグ=バージョン名をつけると、タグを使ってもバージョン同士/バージョンと現状のdiff/rdiffを見ることができます。(もちろん-r [リビジョン]でもOKです)
# cvs commit -m'rdiffテスト' a.c
# cd ..
# cvs rdiff -s -r rel20080326 sample_project
cvs rdiff: Diffing sample_project
File sample_project/a.c changed from revision 1.2 to 1.3

■cvs statやcvs logコマンドでタグの状況を確認■
# cvs stat -v a.c
# cvs log a.c

■タグを削除する■
# cvs stat -v | grep -p Existing
【削除したいタグを確認する】
# cd ..
# cvs tag -d rel20080326 sample_project

■エクスポートする■

バージョンを指定してエクスポートします。
エクスポートによって"CVS"管理ディレクトリを含めないでソースを抽出することができます。
タイムスタンプも、レポジトリ上の最終更新日に揃えられます。
# mkdir export
# cd export
# cvs export -r rel20080326 sample_project

■コメントを編集する■
# cvs admin -m1.3:'変更後コメント' a.c

■パーミッションを変更する■

やむを得ず(go+xやパg+wなど)パーミッションを変更する場合は、レポジトリのファイルパーミッションを直接変更することになります。
レポジトリのパーミッション+umaskで最終的なパーミッションが決まります。
動かなくならないよう、常識的な範囲で変更して下さい。

■ログインしてモジュールをチェックアウトする■
# cvs login
Logging in to :pserver:cvs@hostname:2401/cvsroot
CVS password: ********
# #【重要】必要に応じてumaskを変更します。
# # 755, 644系のパーミッションを期待するなら、umaskは022とします。
# umask 022
# cvs co sample_project # <- co は checkoutの略

■ファイル追加■

ファイル'addtest.ksh'を追加します。
# cvs add addtest.ksh
# cvs commit -m"新規登録" addtest.ksh

■バイナリファイルの追加■
# cvs add -kb binry.o

■ディレクトリ追加■

ファイルが存在しないディレクトリは存在しないのと同じです。
# mkdir adddir
# echo "test" > adddir/adddir.ksh
# cvs add adddir
# cvs add adddir/*.ksh
# cvs commit -m "dir以下のファイル追加"

他の人が追加したディレクトリを自分の作業ディレクトリに表示させるときは
cvs update -d -P を実行します。

■ファイル編集■

viでも何でも使って適宜編集した後、update, commitします。
'cvs commit ファイル名' とすると指定したファイルのみをcommitします。
# cvs update
# cvs commit -m"コメント" fileName.txt

■ファイル削除■

実際にはファイルは削除されません。レポジトリから見えなくなるだけで、いつでも復活させることができます
# rm filename
# cvs remove filename
# cvs commit -m "Removed unneeded files"

cvs remove -f とすれば、rmコマンドは不要です。
# cvs remove -f filename

# 削除後でもログは参照可能です。
# cvs log filename

■ファイルの削除を中止する■

手順概要(1)remove 実行前
# rm filename
# cvs update

手順概要(2)remove 実行後(commit未済)
$ rm filename
$ cvs remove filename
$ cvs add filename
$ cvs commit

手順概要(3)remove/commit後
$ cvs add filename
$ cvs commit

■ディレクトリ削除■

実際には削除されません。リポジトリには空のディレクトリが残ります。
# rm adddir/*.ksh
# cvs remove adddir/*.ksh
# cvs remove adddir
# cvs commit -m "adddirを削除"
# cvs up -d -P

■ファイルの名前を変更する■■
# mv addtest.ksh renametest.ksh
# cvs remove addtest.ksh
# cvs add renametest.ksh
# cvs commit -m "addtestをrenametestに変更"

■ディレクトリの名前を変更する■
特別な手順はありません。新規のディレクトリを作成し、ディレクトリ中のファイルを作成したディレクトリに移動させます。

■古いファイルとのDIFF■
# cvs diff -r[rev] [ファイル名]

■コメント/履歴確認■
# cvs log [ファイル名]

■バージョン確認■
# cvs stat [-v] [ファイル名]

'-v'を追加するとタグ(リリースバージョン)情報を出力します。

■最新バージョンに書き戻す■
$ rm ファイル
$ cvs update ファイル
U ファイル

【あるいは】

$ cvs update -C ファイル

■古いバージョンに書き戻す■
# cvs log ファイル
# cvs diff -r[rev] ファイル # 戻したいファイルとのDIFFを確認する
# cvs update -p -r [rev] ファイル > ファイル
# cvs update
M ファイル
# cvs commit ファイル

■追加を途中でやめる■
# cvs remove -f ファイル

commitは不要です。

■作業ディレクトリがいつチェックアウトしたものか分からなくなった■
作業ディレクトリで'cvs update'するか、一旦作業ディレクトリを削除してcheck outします。
(当たり前か)

■終了する(release)■

cvs releaseコマンドを使います。
'-d'オプションを使うとディレクトリまで削除してくれます。
# cvs release -d sample_project


【参考】
CVS--Concurrent Versions System (in Japanese) - CVS のコマンド便覧 必要十分なリファレンス
CVS使用法メモ(Hishidama's CVS usage Memo) 実践的なコマンドメモ
リリースブランチ(cvs) ちょっと毛色は違いますがブランチの意義について

2008年4月4日金曜日

DIFF出力結果の見方

申し訳ないほど基本的なことですみません。
普段ぼおっと見ているもので、今回意識的に整理してみました。
【凡例】
$ diff File1 File2

Lines Affected in File1 Action Lines Affected in File2

1. Number1 a Number2[,Number3]
2. Number1[,Number2] d Number3
3. Number1[,Number2] c Number3[,Number4]

読み方
1. 'File1'の'Number1'行に、'File2'の'Number2'(から'Number3')の行を追加
2. 'File1'の'Number1'(からNumber2')を('File2'の'Number3'から)削除
3. 'File1'の'Number1'(からNumber2')を'File2'の'Number3'(から'Number4')の記載へと変更

[tmp/] $ cat a.txt
aaa
bbb

ccc

ddd

[tmp/] $ cat b.txt
xxx
yyy

iii
jjj


[tmp/] $ diff a.txt b.txt
1,2c1,2 (1)
< aaa .
< bbb .
--- .
> xxx .
> yyy .
4c4,5 (2)
< ccc .
--- .
> iii .
> jjj .
6d6 (3)
< ddd .


(1) a.txtの1~2行目の(aaa, bbb)を、b.txtの1~2行目(xxx,yyy)に変更し、
かつ
(2) a.txtの4行目(ccc)を、b.txtの4~5行目(iii,jjj)に変更し、
かつ
(3) a.txtの6行目(ddd)を削除すれば、
a.txtとb.txtは同じファイル

といった読み方になりましょうか。

2008年3月18日火曜日

EclipseからCVSを使う

ソースコードが増えてきたのでCVSを使ってバージョン管理をしたいと思います。

■手順あらまし
(1)AIX環境にCVSサーバを立てる
(2)Eclipse(Lomboz)からCVSを利用する

■手順詳細
(1)AIX環境にCVSサーバを立てる

a. 下記URLからcvsとzlib(CVSの前提)をダウンロードします
AIX Toolbox for Linux Applications
3/18時点では、下記のrpmが最新でした。
cvs-1.11.17-3.aix5.1.ppc.rpm
zlib-1.2.3-4.aix5.2.ppc.rpm

b. インストールします
# rpm -i zlib-1.2.3-4.aix5.2.ppc.rpm
# rpm -i cvs-1.11.17-3.aix5.1.ppc.rpm
#

c. 各種設定
1:ユーザの作成
smitty mkuser

などでCVSユーザ(ここではcvsuser)を作成します。
パスワードも忘れずに付けておきましょう。(rootで"passwd cvuser")
(手順は割愛)

2:CVSレポジトリの作成とinit
ディレクトリを作成し、cvs initを実行します。
# su - cvsuser
$ mkdir cvsroot
$ export CVSROOT=/full/path/to/cvsroot # .profileなどにいれてしまいましょう
$ cvs init
$

3:/etc/servicesに以下のエントリーを追加
/etc/servicesに以下のエントリーが存在しない場合(存在しないと思いますが)追加します。
cvspserver      2401/tcp # CVS client/server
cvspserver 2401/udp # CVS client/server

4:/etc/inetd.confに以下のエントリーを追加
cvspserver stream tcp nowait root /usr/bin/cvs cvs -f --allow-root=/full/path/to/cvsroot pserver

5:inetdを再起動
# stopsrc -s inetd
0513-044 /usr/sbin/inetd サブシステムは停止を要求されました。
# startsrc -s inetd
0513-059 inetd サブシステムは始動しました。サブシステム PID は 1536230 です。

この状態で'cvsuser'でEclipseから接続し、使うことができます。

6:(オプション)cvsのpasswdを作成
/full/path/to/cvsroot/CVSROOT
以下にpasswdファイルを使います。書式は
userid:encrypt_password:valid_userid
です。パスワードが空で、cvsuserと同じ権限でアクセスできる'cvs'ユーザを作成する場合は、
cvs::cvsuser

というエントリーを追加すれば良いです。
ファイルのエンクリプトにはApacheなどに付属する'htpasswd'ユーティリティを使えばよいようですが、個人的な環境なのでそこまではしません。

(2)Eclipse(Lomboz)からCVSを利用

Eclipse(Lomboz)を起動し、'Window' → 'Open Perspective' → 'Other' から、'CVS Repository Exploring'を選択します。

'CVS Repository'ビューを右クリックし、'New' → 'Repository Location'を選択します。

'Add CVS Repository'で以下の項目を入力し、'Finish'をクリックします。
Host: CVSサーバのホスト名
Repository Path: /full/path/tocvsroot
User: cvsuser
Password: ******* (cvsuserのOSパスワード)

これでCVS Repositoryが表示され、使えるようになります。

2008年3月13日木曜日

awkメモ(シングルクォーテーションを出力する)

awkでシングルクォーテーションを出力する方法です。
# echo a | awk '{print "\047"$1"\047"}'
'a'

例えばこんな利用方法です。
db2 -x "select itemid from icmstcheckedout with ur" | awk '{
print "select sourceitemid,targetitemid from icmstri001001 where sourceitemid=\047"$1"\047 with ur"
}' > $TMP_SQL
db2 -vf $TMP_SQL >> $LOG

2008年2月27日水曜日

罪悪感との戦い(1)

顧客に迷惑を掛けてしまった時の罪悪感に、どう対処するか。システム構築の仕事をする時に、大事な課題です。
罪悪感を強く感じてしまうタイプの人は、その感情にドライブされてハードワークにのめり込み、体か精神を壊してしまうという結果にハマりやすいといえるでしょう。
そこまでいかないまでも、何となく「何でオレがこんな目に・・・」「知るかよ!」的な感情に囚われ、モチベーションが下がったり、訳もなく顧客に悪い感情を持ってしまうこともあるかと思います(顧客だって同じことを言いたいんですが、そこまで気が回らなくなるんですね)。
罪悪感をあまり感じずに、モチベーションを維持できる人は非常にお得です。私も常日頃そうなりたいものだ、と思っているのですが・・・

以上の説明では、分かる人には分かるかも知れませんが、分からない人には何のことだかさっぱり分かりませんね。もう少し具体的に書いてみましょう。まず、迷惑を掛ける原因の方です。

【ケース1】「自分の書いたソースにバグがあってシステムが止まってしまった」時の罪悪感。

→ まあ、私に関して言えば、この場合に割とまっとうで適切な罪悪感が得られますね。なんと言ったって自分が書いたものが問題を引き起こして周りに迷惑を掛けた訳ですから、自分で責任を取りたい。
体調を崩さない限り、出来るだけ努力して修正して、必要であれば徹夜も辞さない、ということを、モチベーション維持しながら遂行できるような気がします。
当然、懲罰的な徹夜待機とか、出来るだけ無意味な作業は勘弁して欲しいということはありますが、それでもまあ仕方がないか、と納得できます。

【ケース2】「自分の部下(指導する後輩)の書いたソースにバグがあってシステムが止まってしまった」時の罪悪感。

→ 他人(隣接プロジェクト|他社|他チーム)のバグならば極端なとばっちりはないので、ケースからは除外します。こちらで再テストが発生したとしても「お互い様」というのが大人の対応でしょう。
そうではなく、直接自分が手を下したわけではないが、強めの連帯責任が発生するパターンです。
この場合は「後輩のミスの後始末を助けてやるいい上司(リーダー|先輩)」というイメージを無理矢理自分に重ねつつ、心の中では部下に「このやろー」と思いつつ、何とかモチベーションを維持する、といったところでしょうか。部下から一言「ありがとうございました」あるいは「ご迷惑をお掛けしました」と言って貰えれば「俺も昔は失敗したもんだ」などと余裕の対応できると思います。

【ケース3】「第三者が開発したが、それを引き継いでしまい責任を追うことになったプログラムに(略)」時の罪悪感

→ 前任者のソースコードを引き継いで管理しているようなケースです。
前任者が自分と同じ会社の人間かそうではないかによって微妙に異なりますが、前任者の顔が見えている分【ケース2】よりも気が楽ではないでしょうか。「やらなきゃならないことはやるけど、俺の書いたソースじゃねーし」みたいな感覚です。罪悪感がない分「なんで俺が」というのはあるかもしれませんが、周りも事情は理解しているでしょうから、そう無体なことは言われないような気がします。やらなければならないことを淡々と進める感じですね。

【ケース4】「第三者から提供されたが、こちらで責任を負わなければならないプログラムに(略)」時の罪悪感

→ ケース3と違い、第三者の顔が見えないパターンです。具体的にはプロダクトの障害や、多くの開発メンバーを束ねるゼネコンのリーダーやマネージャにとってのプログラム障害がこれに該当します。
プロダクトと一口に言っても、OS、Oracle、WebSphere、DB2、WebLogic などいろいろなものがあります。これらを扱っている、いわゆるインフラ構築SE、基盤SEが時折直面する障害です。障害が発生したけれども、それは自分やプロジェクトチームで作成した個所ではない。じゃあ誰の書いたコードで障害を出しているんだ、と言えばどこにいるかも分からない見知らぬ他人です。開発拠点はアメリカか。はたまたインドか中国か・・・。しかし、その障害の責任は現場で取ることになるのです。その責任の取り方(取らせられ方)も、誰が、という具体的な個人名ではなく、法人名になってくるのが普通です。法人名で個人が責任を取らされるわけです。
リーダーやマネージャーにとってのプログラム障害も同様です。一応自分のチームで作っていることになってはいるが、実際のソースなんか見たこともない(スキルを問題にしているのではありません。数千本のソースを全て見て理解できるわけがない)。せいぜい特徴的な設計とテストケースの概要と、これまで起きた障害を把握している程度、上等なプロジェクトマネージャと言えましょう。それでもプロジェクトで障害が発生して、大問題になる。「知らねーよ」とは口が裂けても言えない。これも、プロダクトの障害と似ていて、個人ではなく、法人名で責任を追及されてしまうパターンです。

【まとめ】
やはり一番きついのが4のケースでしょう。自分がコントロールできたわけでもない障害について、法人名で責任を問われるのですから。
障害が発生してがっかりしている顧客に申し訳ないと思いつつ(中には張り切っている顧客もいるかもしれませんが)、自身の罪悪感を何とかマネジメントしなければなりません。
恐らくは適度な罪悪感が必要なのでしょう。過度に思いつめると、行き着く先は肉体的/精神的ダウンです。あまりに罪悪感がなさすぎると、顧客からは信頼されなくなります。
顧客の立場は理解した上で、障害対応に必要なモチベーションは保持しつつ、不安に駆られた顧客からの、理不尽な対応は適宜断るなり、有効なものを逆に提案するなりできる、そんな適度な精神状態になりたいものです。

(続く・・のか?)

2008年2月25日月曜日

技術の変遷とその弊害(2)

技術の変遷がセールスパーソンというフィルタを通ると、ある滑稽な状況を生み出します。

それは、技術があたかも魔法のソリューションのように語られるようになることです。もちろん顧客の誰もそんな売り文句を全て信じているわけではないでしょう。しかし、それを生み出す方は必死です。世の中を見回せば、ある技術が「とても素晴らしい」ものであり「顧客の抱える問題を見事に解決する」ものであるキャッチフレーズに溢れているようです。曰く、複雑怪奇な環境で行る非効率なビジネスプロセスを革新して、目覚しい生産性をもたらす。あるいは、そこかしこに散ったビジネスロジックを統合して業務の効率化だけではなく運用体力の軽減を実現する。あるいは企業の意思決定を迅速に行えるようにし、国際競争力を強くする、などなど。

しかし、そのセールストークが指すのがEJBであったり、SOAPであったり、Web Servicesであったりすると、エンジニアとしては苦笑せざるを得ません。一体この技術の何が/どこがお客様のプロセスを革新するのか、と。
恐らく、このような新しい技術を利用して、業務を革新することは可能ではあるでしょう。しかし、それは多分EJBやSOAPを使わずともできるはずです。それにEJBを利用して業務革新が出来たということは、必ずしもEJBを利用すれば業務革新ができる、ということを意味しません。技術は手段に過ぎないのです。

このようなことを言うと、技術なんてどうでもいいのか、と批判されてしまうかもしれませんが、そうではありません。
技術が変ることによって、人が活性化します。ITシステムを作るのは結局のところ人ですから、人(特に若い人)が楽しめる、夢中になれる技術は必要です。そのためには技術は常に変って行く必要があると思います。
そういう意味では、ピントが外れたようなよく分からないセールストークも、新しい技術をお客さんに売り込むためには必要です。買ってもらえなければ、その技術も使われることがありませんから。

問題は、大風呂敷を広げる営業が技術を理解していないことではなく、現場を左右する意思決定を行う人が技術に疎い、という状況が広がることです。

技術を理解していなくてもマネジメントは出来る。システムの運用が出来る。そういう言葉が大手を振っているのが現状です。それは決して間違いではない。Javaのシステムを理解し、意思決定するために、必ずしもJavaのコーディングが出来る必要はありません。C言語でもCOBOLでも、何らかの開発経験があればアナロジーによって理解はできるし、意思決定もできるでしょう。

しかし、その「技術を理解していなくてもマネジメントができる」「システムの運用ができる」というスローガンの下には、実は暗黙的な過去の技術の蓄積があるのではないでしょうか。Javaは知らない。知らないけれどシステムの上流設計は出来る。だからJavaの知識は不要だ。本当でしょうか。COBOLやC言語の知識があるから、Javaで実装するシステムの設計ができるのではないでしょうか。

Javaやそこから派生した新しい技術が進化する度に、暗黙的な過去のノウハウに依存した「新しい技術を理解しなくてもよい」という思い込みが、どんどん時代遅れになってくるような気がしてなりません。さすがに今さらJavaを勉強して欲しい、などと言うつもりはありません。昔の技術でも何でもよいのです。とにかく現在のシステムを理解しようと努力すること。現在のシステムが人によって作られていることを理解すること。その努力がなければ、これからもどんどん現場とマネジメント層が乖離して行くことになるのではないでしょうか。現場とマネジメントが無理解によって乖離して行けば、理不尽な意思決定が行われることも増えますし、それにつれて現場のモチベーションも下がって行きます。

技術が変って行くその背景を見つめ、適切に理解し、セールストークに踊らされず、現場をきちんと理解すること。これらのことが重要になってくるだろう、と私は思います。

技術の変遷とその弊害(1)

IT業界ではどんどん技術が移り変わって行きます。
昔のホスト中心の構成、一昔前のクライアント・サーバー構成、そして現在のJavaアプリケーションサーバが中心になった三層Webアーキテクチャ構成。
この遷移が、何を背景として進んできたのか。それには例えば以下のような理由があるでしょう。

■ ハードウェアの進歩
安価なハードウェアが普及したことによって、リッチなクライアントを展開しやすくなったこと。
→ ホストからクラサバへ。
コストと比較して、相対的にサーバの処理能力が向上したため、サーバでロジックを実行できるようになったこと。
→ クラサバから三層アーキテクチャへ。

■ インターネットの普及
インフラとしてのインターネットが一般化し、その上で稼働させるアプリケーションの実行環境が整ってきたこと。(Java Webアプリケーションサーバ、PHP、Ruby)
それによってイントラネットでもWebアプリケーション実行環境が利用されるようになった。
→ クラサバから三層アーキテクチャへ。

上記の他にも理由はいろいろありそうですが、ここで少し根本的な問いを立てて見ましょう。
それは「なぜ、ソフトウェアが変らなければならなかったのか」という問いです。

ソフトウェアの技術の変遷と軌を一にして、環境が変ってきたことが分かりました。どちらかと言えば環境が先に変化し、それに伴ってソフトウェアの状況が変ってきたように見えます。この流れは不自然ではありません。ハードウェアの変化は('ハード'らしく)硬直的です。つまり、ソフトウェアに合わせてハードウェアが変るよりもハードウェアの変化に合わせてソフトウェアが変る方がよほど自然だからです(一部の例外はありますが)。

しかし、ここでもう一度問いを立ててみましょう。「ハードウェアが進歩したからといってソフトウェアは本当に変らなければならなかったのか」。

実はここには必然的なつながりはないのです。ホストの処理能力が向上したのなら、ホストで稼働させるアプリケーションもそのまま早くなります。ハードウェアを置き換えて、アプリケーションをそのまま稼働させればよい。
クラサバも同様です。クライアントが早くなれば、そのままクライアントアプリケーションの処理が早くなる訳ですから、単にリプレースすればよい。

ソフトウェアが変化しなければならないのは、主に二つの理由からです。

一つは技術を活性化すること。技術を新しくすることによって、新しい人材をひきつけることができます。また、若い技術者は昔の技術に早晩慣れてしまい、それを改善したがります。彼らは学習意欲が活発で、また吸収も早い。この場合ソフトウェアの変化は、ソフトウェアの改善に結びつきます。
もう一つはビジネス上の理由です。新しいビジネスを作り出すために、ソフトウェアを変化させるのです。これをさらに二つに分けてみます。
一つは、いわゆるプロダクトのバージョンアップです。プロダクトに新しい機能を付け、バグを修正してリリースします。このサイクルを進めることで、昔のバージョンのサポートを切ることができます。サポートを切れば、サポートに必要な人体力を別の仕事に振り分けることができますし、顧客にはバージョンアップ費用を要求することができます。
使いもしない機能を売りつけるのか、とか、バグを直しただけの製品に新たに金を取るのか、という意見もあるかもしれませんが、ソフトウェアビジネスとしてはやむを得ない流れでしょう。
もう一つのタイプは、セールスのための新技術開発です。これは実体としてはプロダクトのバージョンアップと一体になっています。新しい技術はこんなに素晴らしく、お客様の問題を解決するものだからぜひ買ったらいいよ、という提案に結びつきます。

(続く)

2008年2月15日金曜日

プロジェクトと、そうでないもの

プロジェクトとは何でしょうか。
普段プロジェクトに関わっている人にとっては、十分過ぎる程の実在感を伴っているこの言葉ですが、悲惨なプロジェクトを経験したり、理不尽な顧客の要望を聞いていると、改めて「プロジェクトとは?」と考えさせられることは少なくありません。

ざっとWebや辞書で調べたところ、プロジェクトとは「一定の期間で何かを作り出すこと」と定義できるようです。これをベースとして、例えば「複数人で遂行するものである」とか「コストが決まっている」とか「新しい物を作る」とか付随的な定義もあります。

しかしまあ、はっきり言ってこのような定義に意味はないですね。なぜなら、かなり高いレベルまで抽象化されてしまっているからです。ここまで抽象化してしまうとシステム開発だろうがビルの建設だろうが、商品の開発だろうが、何にでも適用されます。無難ではありますが、空虚な定義です。

ここではもう少し具体的に踏み込んで考えて見ましょう。具体的に、とはどういうことでしょうか。それはもうこの上なく具体的に「いや、こんなのプロジェクトじゃねーよ」と心から叫びたくなるような、そんな無体なプロジェクトについて考えてみたいと思います。

さて、ここから本題に入りましょう。

いきなり本質に飛びますが、何のかんの言ってプロジェクトそれ自体が存在するわけではありません。存在するのはあくまで人です。人が集まっては喧々諤々と、あるいはしんねりむっつりと、何事かやっているわけです。要するに、プロジェクトはそれ自体が実体として存在するのではなく、人がやるものです。つまり、プロジェクトは人次第、ということになります。

プロジェクトの中でもシステム開発のそれには特徴があります。それは「成果物がなかなか見えない」ということです。とにかく文書は大量に出来上がる。コードのサイズも増えて行く。でも、最終的な成果物=システムがちゃんと動くかどうかはなかなか見えてきません。確かにテストをすれば分かります。でも、そのテストがちゃんとシステムの必要十分条件を満たしているかどうかは、非常に分かりづらい。

分かりづらいから人は何とかしようとします。何とかしようとするわけですが、そのやり方がまずいと「こんなのプロジェクトじゃないよー」という状況になります。

話が拡散してきました。要するにマズいプロジェクトは結局の所人の問題だ、というのが結論なのですが、一旦要件定義作業にフォーカスを当てましょう。

上手く行かないプロジェクトの特徴の一つに「要件がなかなか決まらない」というものがあります。あれもしたい。これもしたい。それも必要だ。いろいろ要件がでてきます。積極的な(=ポジティブな)要件を決めることは比較的簡単です。あれができます。これができます。出来ることを言っているだけなら誰にも文句はありません。
難しいのは消極的(=ネガティブ)な要件の決定です。このシステムではこれができません。このシステムを使うと、このデータは切り捨てる必要があります。この意思決定の方がよほど難しく、重要なのです。
何かを決定すれば、必ずどこかにリスクなり制約が発生します。意思決定とはそういうものです。ある選択をするということは、別の選択肢を捨てることなのです。それによってリスクや制約が発生する。しかし、そのリスクを取りたがらないお客さんがいる。そうなるとなかなか話が進まないことになります。あるいは進んだとしてもあれもこれも機能を盛り込むことによって納期、コスト、品質に悪影響が出てくる。悲惨なプロジェクトの始まりです。

このようなプロジェクトが始まると(そしてマネージャーがきちんと顧客の要求をマネージできないと)ひたすらTODOが定義されて、納期だけが決められ、品質が悪くなるかあるいはTODOがいつになってもこなせない、皆が不幸になるプロジェクトとなってしまいます。

こういう顧客をマネージすることでまず大事なのは、顧客と対立するのではなく、顧客をこちらの立場に引きこむ、ということです。リソースと時間が有限であるという課題を共有し、限られた中で一緒に何とかしてゆく、というスキームに持ち込むことです。コラボレーションして行く中で「できないものはできない」という当たり前のことを理解してもらうのです。
それから「未定義の領域がある」ことを理解してもらうことも大事でしょう。例えば「システムはこう動く」と定義して、お互いに同意して、その通り作ったとします。当然定義されていない個所については、顧客の思った通りにはならないこともあります。それはベンダーだけではなく顧客の責任でもあるのです。それを理解して貰えないと、いつまでたっても改善要望が尽きることはありません。顧客も「聞いてなかった」「知らなかった」では済まされないという意識を持ってもらう必要があります。
出来上がった後で気に入らない点が出たとしても、それはお互いの責任だ、ということです。システム開発プロジェクトでは、お客様は神様ではないのです。限られたリソースの中で一緒にモノを作って行くチームの中で、とりわけ責任が重いメンバー(リーダー)の一人なのです。

システム化するとは、あるプロセスを単なるデータの流れへと抽象化する、という側面があります。つまり、システム化によって何かが切り捨てられるのです。切り捨てられることによって、効率的になるのです。
ですからシステム化することによって何か出来ないことが出てくるのを恐れる必要はありません。それもまた、システム化の目的の一つなのですから。

2008年2月13日水曜日

システム開発原理主義に注意

原理主義とは、何らかの教義を絶対視してそこからの逸脱を許さないような態度を意味します。ここではもう少しやわらかく「ある課題が、100%、完ぺきに遂行されることを求める態度」を指すことにしましょう。

厄介な態度ですね。しかし、普通の緊張感を持ってプロジェクトを運営していると、しばしば出くわす精神状態に違いありません。「徹底的に調査しろ!」「バグは許さない!」などなど。

プロジェクトを運営しているとそう言いたくなることはよくあります。しかし、実際のところこのような原理主義的スローガンは「百害あって一理なし」と言えるでしょう。

「なんだと?バグは徹底的に潰すべきだ!」「セキュリティホールは許されない!」「ミスなんかありえない。再チェック、再々チェック、再々々チェックだ!!!」というプロジェクトマネージャー(あるいは体育会系のリーダー)からの声が聞こえてきそうです。

ちょっと待ってください。冷静になって考えてみましょう。私も別にミスを許容している訳ではありません。明らかなミスやセキュリティホールは潰すべきでしょう。しかし、その手のタスクを「スローガン化」してしまうことの弊害は、今一度考えた方がよいと思うのです。

「徹底的にやります」「全てチェックします」という宣言は一見頼もしいものです。真面目な部下が青ざめた顔でこう報告した時「うむ。そうか。頑張れ!」と言いたくなることもあるでしょう。しかし、部下を信頼して後押しするとしたら、残念ながらあなたはマネージャー失格です。

なぜでしょうか。それは具体性が欠けているからです。「徹底的」とは、「全て」とは具体的には何を指しているのでしょうか。実際の所あなたの部下はどのように作業をするつもりなのでしょうか。それはひょっとしたらムダな作業ではないでしょうか。

「セキュリティホールをなくす作業が、ムダなはずはない!」あるいは「バグを潰す作業がムダであるはずがない!」とおっしゃるでしょうか。残念ながらそれもまた原理主義的スローガンから派生する無思考に過ぎません。

具体的に考えましょう。例えば今構築しているのがイントラネットを対象としたWebアプリケーションだとしましょう。するとセキュリティホールの重要性は急激に下がります。バグにしたって業務に関係あるものだけを探せばいいわけです。では、どうやって探すか。業務に関係ある操作は、テストケースで網羅されているのではありませんか?だとすれば、テストが実施されていれば、業務に関係のないバグは、既に潰れているはずですよね。そうでないとすれば、やるべきはテストケースの漏れをチェックすることであってバグの洗い出しではないでしょう(テストケースの見直しが手遅れでなければよいのですが・・・)。

そもそも見てすぐに分かるようなバグなら、既に直っているはずです。これまでの切り口では見えないものが潜在バグなのです。とすれば、潜在バグを顕在化させるためには、顕在化させるような切り口が必要となります。具体的にそのような切り口が定義できるなら、そしてその切り口が現実的ならば実際に調査してもよいでしょう。しかしいたずらに「潜在バグ」という言葉のおどろおどろしさに不安になって「徹底的に潜在バグを潰す」というスローガンが生まれたとすれば、それは単なる無思考に過ぎません。

このようなバグをゴキブリに例えてみましょう。ゴキブリがいるかどうかは分かります。ゴキブリを実際に見つければいいのです。死骸でも写真でもいい。とにかくいることは分かります。目の前にゴキブリを見つけながら、いない、というのは要するにウソです。
しかし、ゴキブリがいないことはいつまでたっても分からない。確かに目の前にはいない、でも背後にいるかもしれない。物陰に潜んでいるかもしれない。気が付いていないだけかもしれない。いないことはいつまでたっても証明はできません。だとすれば「バグを0にする」などは不可能なのです。せいぜい「これまでのところゴキブリは見つかっていない」としか言うことはできない。明日ゴキブリが見つかるかもしれないのです。

人間の認識は本来有限なものです。真実はなかなか分からない。それを忘れて簡単に原理主義的な発想に陥るのは、思い上がりに過ぎません。そしてその思い上がりは大抵はよく考えられていない不安から生じるものです。そのような原理主義がプロジェクトを破壊してしまうことは、容易に想像できるのではないでしょうか。

2008年2月12日火曜日

DB2 v8.2 表スペースをDMSに変更する(4)

まだ手順が足りないようです。
select count(*) from RMOBJECTS

1
-----------
SQL0668N 操作は、理由コード "1" のため、表 "RMADMIN.RMOBJECTS
に対して許可されません。 SQLSTATE=57016

というエラーが発生しています。
DB2のInfocenterによると

表がチェック・ペンディング状態にある。 表の保全性が強制されておらず、表の内容が無効である可能性があります。 従属表がチェック・ペンディング状態である場合は、チェック・ペンディング状態でない親表または基本表に対する操作も、このエラーを受け取る可能性があります。

とのことなので、チェックペンディングを解除します。
db2inst1@ホスト名 [20080207_DMS/] $ grep -v ^-- setIntegrity.sql
set integrity for rmadmin.rmobjects immediate checked
db2inst1@ホスト名 [20080207_DMS/] $ db2 -f setIntegrity.sql
DB20000I SQL コマンドが正常に終了しました。

これで、SQL0668Nが出なくなりました。(それにしても自分のやっていることが分かってないのがバレバレですな)

DB2はリストアしたら'何とかペンディング'状態になるので要チェックです。(ほとんどFAQですが)

(2/13追記)
今はアーカイブロギングモードのDBでロードすると、デフォルトではバックアップペンディング状態になってバックアップが強制されるようです。
大量のデータが存在するときは要注意のようです。
参考)DB2逆引きWiki データをロードするには

2008年2月1日金曜日

DB2 v8.2 メモリをチューニングする

貧弱な開発環境向けに、CMのDB2のメモリ使用率を下げます。
@IT DB2チューニング・ベストプラクティス(2)を参考にすると、DB2のグローバルメモリ使用率は以下の計算式で概算がでるようです。
バッファ・プール+dbheap+util_heap_sz+pckcachesz+aslheapsz+locklist+約10%のオーバーヘッド
※太字部分は@ITのサイトに誤植(pkgcachsz)がありました。

当方の環境(icmnlsdb)で調べて見ると、以下の通りでした。
(icmnlsdbに接続します)
db2inst1@ホスト名 [sql/] $ grep -v ^-- sys.sql
select substr(bpname,1,20),npages,pagesize from syscat.bufferpools
db2inst1@ホスト名 [sql/] $ db2 -f sys.sql

1 NPAGES PAGESIZE
-------------------- ----------- -----------
IBMDEFAULTBP 1000 4096
ICMLSFREQBP4 1000 4096
ICMLSVOLATILEBP4 8000 4096
ICMLSMAINBP32 8000 32768
CMBMAIN4 1000 4096

5 レコードが選択されました。

db2inst1@ホスト名 [sql/] $ db2 get db cfg | egrep -i '(util_heap|dbheap|pckcache|aslheapsz|locklist)'
データベース・ヒープ (4KB) (DBHEAP) = 2400
ユーティリティー・ヒープ・サイズ (4KB) (UTIL_HEAP_SZ) = 5000
ロック・リスト用最大ストレージ (4KB) (LOCKLIST) = 1000
パッケージ・キャッシュ・サイズ (4KB) (PCKCACHESZ) = (MAXAPPLS*8)
db2inst1@ホスト名 [sql/] $ db2 get dbm cfg | egrep -i '(util_heap|dbheap|pckcache|aslheapsz|locklist)'
アプリケーション・サポート層ヒープ・サイズ (4KB) (ASLHEAPSZ) = 15

ざっくり計算すると、以下のような感じです。
a. バッファプール:(上から)4MB + 4MB + 32MB + 250MB + 4MB = 約300MB
b. DBヒープ:8MB
c. UTILヒープ:20MB
d. ロックリスト:4MB
e. アプリヒープ:60K
効きそうなのは、順に「250MBのバッファプール」>「32MBのバッファプール」>「20MBのUTILヒープ」のようです。他は無視しましょう。
では、各サイズを変更します。ALTER BUFFERPOOLコマンドとUPDATE DB CFGコマンドを使います。
db2inst1@ホスト名 [sql/] $ grep -v ^-- sys.sql
alter bufferpool ICMLSVOLATILEBP4 size 2000 -- 8000
alter bufferpool ICMLSMAINBP32 size 2000 -- 8000
update db cfg using UTIL_HEAP_SZ 2000
db2inst1@ホスト名 [sql/] $ db2 -f sys.sql
DB20000I SQL コマンドが正常に終了しました。

DB20000I SQL コマンドが正常に終了しました。

DB20000I UPDATE DATABASE CONFIGURATION コマンドが正常に終了しました。

db2inst1@ホスト名 [sql/] $ db2 -f sys.sql

1 NPAGES PAGESIZE
-------------------- ----------- -----------
IBMDEFAULTBP 1000 4096
ICMLSFREQBP4 1000 4096
ICMLSVOLATILEBP4 2000 4096
ICMLSMAINBP32 2000 32768
CMBMAIN4 1000 4096

5 レコードが選択されました。
db2inst1@ホスト名 [sql/] $ db2 get db cfg | egrep -i '(util_heap|dbheap|pckcache|aslheapsz|locklist)'
データベース・ヒープ (4KB) (DBHEAP) = 2400
ユーティリティー・ヒープ・サイズ (4KB) (UTIL_HEAP_SZ) = 2000
ロック・リスト用最大ストレージ (4KB) (LOCKLIST) = 1000
パッケージ・キャッシュ・サイズ (4KB) (PCKCACHESZ) = (MAXAPPLS*8)
(念のためDBを再起動します)

以上です。

DB2 v8.2 循環ロギングを設定する

定義

ここでは、データベースへの変更が記録されたファイルをログと呼びます。
(情報やイベントやエラー情報を書き出すログではありません。)
ログには複数種類(後述)があり、ラッシュリカバリー、ロールフォワードやロールバックに使われるものです。

DB2では、ログの状態によって用語を区別しています。

a. アクティブログ 
今まさに使っているログです。commit前の情報が含まれます。DBがクラッシュしたときに直前の状態に戻すために使われます。これがないとDBは復帰できません。このタスクで扱う対象ではありません。

b. オンライン・アーカイブログ
commit済みのログです。DBの起動/稼働には不要で、ロールフォワードやロールバックに使います。

c. オフライン・アーカイブログ
[b.]のログを管理のため別の場所に移したもの。あくまで運用の観点からの差異であり、ログの観点で言えば[b.]と同じです。DB2は、[b.]が一杯になったときに、ログを退避する機能を持っています。退避されたログを便宜的に「オフライン・アーカイブ」と呼びます。(異なる切り口での用語を混在させることは、話をややこしくするだけですね。)

b.-1 一次ログ、二次ログ
オンライン・アーカイブログに一次ログと二次ログというパラメータを指定することができます。一次ログに割り当てた分が溢れると、二次ログに移る、という仕組みのようです。(これも話をややこしくしているだけのような気がします。)今のタスクでは意識する必要はありません。

放置されることが多い開発環境では、アーカイブログ(b. c. d.)を設定しておくと、ログが満タンになってしまうことがままあります。循環ログを指定してログが増えつづけないように設定することで、ログ溢れによるアプリケーションの停止を回避できます。

ちなみにDB2のデフォルトは循環ログです。

手順概要

a. DBに接続します。

b. 以下のパラメータを変更します。
LOGRETAIN=NO  (デフォルト)
USEREXIT=NO (デフォルト)
LOGARCHMETH1=OFF (デフォルト)
LOGARCHMETH2=OFF (デフォルト)

c. DB2を再起動します。

手順例
db2inst1@ホスト名 [sql/] $ db2 connect to icmnlsdb

データベース接続情報

データベース・サーバー = DB2/6000 8.2.7
SQL 許可 ID = DB2INST1
ローカル・データベース別名 = ICMNLSDB

db2inst1@ホスト名 [sql/] $ db2 -f sys.sql | egrep -i '(logretain|userexit|logarchmeth)'
リカバリー用ログの保持使用可能 (LOGRETAIN) = RECOVERY
ロギング用ユーザー出口使用可能 (USEREXIT) = OFF
第 1 ログ・アーカイブ・メソッド (LOGARCHMETH1) = DISK:/cm/lsdb/archive_log/
logarchmeth1 のオプション (LOGARCHOPT1) =
第 2 ログ・アーカイブ・メソッド (LOGARCHMETH2) = OFF
logarchmeth2 のオプション (LOGARCHOPT2) =

db2inst1@ホスト名 [sql/] $ grep -v ^-- sys.sql
update db cfg using logretain NO
update db cfg using userexit NO
update db cfg using logarchmeth1 OFF
update db cfg using logarchmeth2 OFF
db2inst1@ホスト名 [sql/] $ db2 -f sys.sql
DB20000I UPDATE DATABASE CONFIGURATION コマンドが正常に終了しました。
SQL1363W 即時変更のためにサブミットされた 1
つ以上のパラメーターが動的に変更されませんでした。
これらの構成パラメーターでは、変更を有効にする前にすべてのアプリケーションをこの
データベースから切断する必要があります。

DB20000I UPDATE DATABASE CONFIGURATION コマンドが正常に終了しました。
SQL1363W 即時変更のためにサブミットされた 1
つ以上のパラメーターが動的に変更されませんでした。
これらの構成パラメーターでは、変更を有効にする前にすべてのアプリケーションをこの
データベースから切断する必要があります。

DB20000I UPDATE DATABASE CONFIGURATION コマンドが正常に終了しました。
SQL1363W 即時変更のためにサブミットされた 1
つ以上のパラメーターが動的に変更されませんでした。
これらの構成パラメーターでは、変更を有効にする前にすべてのアプリケーションをこの
データベースから切断する必要があります。

DB20000I UPDATE DATABASE CONFIGURATION コマンドが正常に終了しました。

db2inst1@ホスト名 [sql/] $ db2stop
2008-02-01 10:27:12 0 0 SQL1025N データベースがまだアクティブになっているために、データベース・マネー
ジャーが停止されませんでした。
SQL1025N データベースがまだアクティブになっているために、データベース・マネージャーが停止されませんでした。
db2inst1@ホスト名 [sql/] $ db2 force application all
DB20000I FORCE APPLICATION コマンドが正常に終了しました。
DB21024I このコマンドは非同期であり、即時に有効にならない場合もあります。

db2inst1@ホスト名 [sql/] $ db2stop
db2inst1@ホスト名 [sql/] $ db2start
2008-02-01 10:28:01 0 0 SQL1063N DB2START の処理が正常に終了しました。
SQL1063N DB2START の処理が正常に終了しました。
db2inst1@ホスト名 [sql/] $ db2 connect to icmnlsdb
db2inst1@ホスト名 [sql/] $ db2 -f sys.sql | egrep -i '(logretain|userexit|logarchmeth)'
リカバリー用ログの保持使用可能 (LOGRETAIN) = OFF
ロギング用ユーザー出口使用可能 (USEREXIT) = OFF
第 1 ログ・アーカイブ・メソッド (LOGARCHMETH1) = OFF
logarchmeth1 のオプション (LOGARCHOPT1) =
第 2 ログ・アーカイブ・メソッド (LOGARCHMETH2) = OFF
logarchmeth2 のオプション (LOGARCHOPT2) =

2008年1月31日木曜日

文字列置換ツール(無保証)

文字列置換ツールを作成しました。
時折必要性を感じるのですが、その場でさっさと作るには難しいシェルです。
かといって胸を張って公開できるようなツールでもありませんが。

当ツールは完全無保証です。ファイルが壊れるかもしれません。脅しではありません。バイナリファイルは、例え検索結果にマッチしなくても、無条件に破壊します。注意して使ってください。

私的なメモとして貼っておきます。
#!/bin/ksh
trgt_dir=$1
trgt_ext=$2
str_search=$3
str_replace=$4
self=`basename $0`
USED=0
use_parcent=0
use_slash=0

w_list_file=/tmp/tmp.$$.dirlist
w_tmp_file=/tmp/tmp.$$.aft

usage() {
echo "$self [PATH] [対象拡張子] [検索文字列] [置換文字列]"
echo "注意:バイナリファイルは破壊されます。"
echo "注意:'/'と'%'を同時に使うことはできません。"
}

# 引数チェック
if (( $# <= 2 )); then
usage;
return 0
fi

if [[ ! -d $trgt_dir ]]; then
echo "第一引数が有効なディレクトリではありません";
usage
return 1
fi

# sedで使う'/'あるいは'%'が含まれないことを確認。
echo $str_search $str_replace | grep '/' > /dev/null 2>&1
use_slash=$?
echo $str_search $str_replace | grep '%' > /dev/null 2>&1
use_percent=$?

if (( $use_slash == $USED && $use_percent == $USED )); then
echo "'/'と'%'を同時に使うことはできません。"
return 1
fi
echo "警告> ファイルのタイムスタンプは全て現在の時間に更新されます。"
if (( $# == 3 )); then
echo "警告> 置換文字列が指定されていません。"
echo "警告> 文字列[$str_search]をファイルから削除しますがよろしいですか?[Y/y] : "
read input
if [[ $input != "Y" && $input != "y" ]]; then
echo "終了します"
return 0
fi
fi

echo "警告> ${trgt_dir}/ にある *.${trgt_ext} がバイナリファイルであれば、"
echo "警告> *.${trgt_ext} は問答無用で破壊されます。よろしいですか?[Y/y]"
read input
if [[ $input != "Y" && $input != "y" ]]; then
echo "終了します"
return 0
fi
echo "警告> 本当に?[Y/y]"
read input
if [[ $input != "Y" && $input != "y" ]]; then
echo "終了します"
return 0
fi

ls -l $trgt_dir | grep -v $self | grep ^- | grep \.${trgt_ext}$ |
awk -vDIR=${trgt_dir} '{print DIR"/"$NF}' > $w_list_file

while read trgt_file
do
if (( $use_slash == $USED )); then
cat $trgt_file | sed "s%${str_search}%${str_replace}%g" > $w_tmp_file
else
cat $trgt_file | sed "s/${str_search}/${str_replace}/g" > $w_tmp_file
fi
mv $w_tmp_file $trgt_file
echo "$trgt_file を処理しました。"
done < $w_list_file

rm $w_list_file

2008年1月30日水曜日

awkに外から変数を渡す

これも基本だと思いますが、よく忘れるので・・・
awk -vVAR=VALUE '{print VAR}'

です。# 方言はあるのでしょうか?AIX5.2とcygwinのGNU Awk 3.1.5で動きました。
root:/tmp # echo a | awk -vhoge=${PWD} '{print $1,hoge}'
a /tmp

2008年1月28日月曜日

DB2 EVENT MONITOR FOR STATEMENTS を使ってみる

イベントモニター開始
create event monitor sql_evmon1 for statements write to file \
'/home/db2inst1/sql_evmon1' maxfiles 3 maxfilesize 1000
set event monitor sql_evmon1 state=1

※ディレクトリのパス名が間違っていると、2つ目のコマンド(3行目)でエラーが出ます。

SQLを実行します。

イベントモニター終了
flush event monitor sql_evmon1 buffer
set event monitor sql_evmon1 state=0


イベントモニターの結果確認
db2evmon -path ./sql_evmon1


※CMで実行してみましたが、コンテンツを一つ登録するのに相当SQL/ストアドプロシージャを発行しているようです。
CMの背後で実行されるSQLはほとんどブラックボックスとして捉えたほうがよさそうです。

2008年1月27日日曜日

今更ながらSSL(3.セキュリティについて考えてみた)

今回SSLの検証用に導入したIHSのhttpd.confを編集して、以前に導入した別の純正Apacheを起動して動作確認をする、という信じられないようなミスをしながらも、何とかSSLで稼働させることが出来ました。
(別のプロダクト起動しておいて設定が反映されるわけない・・・しかも↑のチョンボで1時間ほどロスしました。気が付くの遅い)

で、考えたこと。

a. SSLの仕組みはよく考えられている
b. でも、はっきりいって万全なセキュリティではない

SSLはネット通販サイトでは必須の機能です。SSLをサポートしていないサイトで、絶対にクレジットカード番号などを入力してはいけません。まあ、常識ですね。
しかし、逆に「鍵マークが出ていればまず安全」と思い込んでいる人が多いと思います。でもそれは完全に間違っています。まさに「逆は必ずしも真ならず」です。
証明書自体は誰にだって取得できます。だから、証明書があるからそのサイトは正しいとか、そのサイトに悪意がない、と判断するのは無謀なことです。

普通の人は、Yahoo!や楽天などの超メジャーサイトで、鍵マークを確認して、安心してクレジットカード番号などを入力していることでしょう。それは結果的にはおおむね健全な判断と言えます。

しかしその判断を成り立たせている、以下の要素を一つ一つ見てみましょう。

a. 定評のあるサイトだという思い込み
b. 正規のURLを参照しているという思い込み
c. 鍵が出ていることから来る安心感

a. 極端な話、信じられるサイトだと思って、正規のURLにアクセスして、鍵マークを確認していても、最後にその裏にいる人に騙されることがあるわけです。まあこのパターンではSSLがどうしたとか、そのレベルの議論にはなりませんが。

b. はしばらく前から流行っているフィッシング詐欺などに騙される可能性のことです。
騙りメールにウソのURLが載っていて「パスワード変更のお願い」というお知らせが来るわけです。アクセスしてみるとデザインはどう見ても正規のページ。URLもまあまあ不信なところはない。SSLにも対応している(何かポップアップウィンドウが出たけどよく分からないので無視した)。で、パスワード変更したらアカウントを乗っ取られてしまった、というパターンですね。
これに対応するには、メールを信用しない、サイトにはいつも使っているブックマークから飛ぶ、などの実践が必要です。もちろん、SSLの証明書をよく見れば分かる人は分かるのでしょうが、そんな面倒臭いことはできないですよね。多少SSLに詳しかったとしても。

c. 鍵が出ているからといって、そのサイトが信用できるとは限りません。確かにそのサーバまでの通信は暗号化されています。でもその先の人やサーバがどうなっているかは分かりません。
有名なサイトに行って、ブラウザで何の警告も出ずにSSL通信できたのなら、まず信じてよいとは思います。でも何らかの警告が出たら、まずさっさとそのサイトからは逃げたほうがよいと思います。例えどう見ても正規のページに見えたとしても。

まあ、結局はリスクをどう評価し、どう責任を取るかですね。それこそ、近所のスーパーに買い物に行っても、車にぶつかる可能性があるわけですから。

セキュリティも考えて見るといろいろ面白いものです。

今更ながらSSL(2.IBM HTTP Serverに設定してみる)-2

IBM HTTP Server(以下IHS) Infocenterの通信の保護を参考にしてIHSのSSL構成を行います。

2.2 手順概要
 a. SSLモジュールのロードを定義します。
 b. 仮想ホストとそのポート(443)を定義します。
 c. その他SSL関係のディレクティブを指定します。
Limiting IBM HTTP Server to encrypt at only 128 bits or higherを参考にしました。

2.2.1 SSLモジュールのロード定義
%IHS_ROOT%\conf\httpd.confの最後に、以下の行を追加します。
LoadModule ibm_ssl_module modules/mod_ibm_ssl.so


2.2.2 仮想ホスト定義、その他SSLディレクティブの追加
さらに以下の行を追加します。
Listen 0.0.0.0:443
<VirtualHost HOST名:443>
ServerName HOST名
DocumentRoot "F:/IBMHTTPServer/htdocs/en_US"
ErrorLog "logs/error.log"
TransferLog "logs/error.log"
ServerSignature Off
SSLEnable
Keyfile "F:/IBMHTTPServer/bin/key.kdb"
SSLClientAuth none
SSLServerCert key_test
SSLCipherSpec 27
SSLCipherSpec 21
SSLCipherSpec 23
SSLCipherSpec 3A
SSLCipherSpec 34
SSLCipherSpec 35
</VirtualHost>


2.2.3 確認
https://ホスト名/ にアクセスします。
証明書の警告が表示されます。

勝手証明書なので警告マークがついていますね。
外部サイトでこの表示を見たら逃げるが勝ちです。でも今回は自分が作った証明書なので「はい(Y)」をクリックします。ページが表示されれば完了です。

今更ながらSSL(2.IBM HTTP Serverに設定してみる)-1

IBMHTTPServerにSSLを設定してみましょう。
※このソフトウェアはApacheにIBMが独自に拡張を加えたものです。
※上記リンク先からダウンロードが出来ます。無料でダウンロードできますが、ユーザIDや個人情報が要求されます。

2 IBM HTTP ServerをSSL構成する

2.1 手順概要
i. %IHS_ROOT%\bin\ikeyman を使って証明書と公開/暗号鍵を作成します。
ii. %IHS_ROOT%\conf\httpd.conf にSSL関連の設定を行います。

2.2 ikeymanを使って証明書を作成する
ikeymanユーティリティを使って、自署名入りの証明書を作成します。
証明書と公開/暗号鍵のセットのことを、鍵データベースと記載しているようです。
以下で「鍵データベース」という用語を使います。

2.2.1 鍵データベースの作成(1)
%IBM_HTTP_SERVER_ROOT%\bin\ikeyman.bat を実行、あるいは スタート>プログラム>IBM HTTP Server V6.X とたどり、ikeymanユーティリティを起動します。




2.2.2 鍵データベースの作成(2)
新規作成します。



2.2.3 鍵データベースの作成(3)
鍵データベース・タイプはCMSとします。
その他はデフォルトにしています。


2.2.4 鍵データベースの作成(4)
パスワードは"Password1!"としました。
有効期限を設定しますか→チェック入れないまま
パスワードをファイルに隠しますか?→チェック入れる



2.2.5 鍵データベースの作成(5)
プルダウンで 個人用証明書 を選択します。
右下の 新規自己署名 をクリックします。



2.2.6 鍵データベースの作成(6)
鍵ラベル→key_test
共通名→ホスト名が入っている筈です
組織→org_test
とし、
有効期間は10年としました。



2.2.7 鍵データベースの作成(7)
以上でkey_test 鍵データベースが作成されました。

今更ながらSSL(1.概要)

今更ですがSSLについて勉強します。
外向けECサイトを構築するエンジニアにとっては当たり前の知識かもしれませんが、イントラ向けシステムを構築する人にとってはあまり縁がない機能です。かく言う私もあまりSSLを理解しているとは言えません。
CMでSSLを利用しているということもあり、今回はSSLについて、学んでみます。

※勉強に際しては、主にWikipediaの公開鍵暗号を参考にしました。非常に優れた説明です。

1 SSLとは?
通信を暗号化し、当事者以外には通信内容を分からなくする仕組みです。

1.1 暗号化って具体的にはどんな感じ?
双方で内容を暗号化/復号化する鍵を持ちます。
(i) データを送るときは暗号化して送ります。
(ii)受け取った内容は暗号化されているので、鍵で復号化して読みます。
(i)と(ii)の繰り返しです。

1.2 なあんだ。簡単じゃないか。
限られた友人やチーム内でやり取りするのならば、暗号化も簡単な話でしょう。例えばZIPファイルの暗号化を使えば、普段使いレベルの秘密は保てます。
しかしインターネットは違います。不特定多数の人とやり取りすることになりますから、最初に鍵をいかにして安全に配るかが課題となります。

1.3 どういうこと?
不特定多数のユーザーと、共通鍵暗号(お互いに共通の鍵を持ってやり取りする方法)で通信する実装を考えてみましょう。仮にサーバをXとして、ブラウザをAとします。
最初にAからリクエストが飛んできます。サーバXはランダムに鍵を生成して、Aに送付します。以降、Xは生成された鍵をA用の共通鍵として使い、AはXから貰った鍵をX用の共通鍵として使います。

1.3.1 問題なさそうだけど?
インターネットは基本的には平文が飛び交う世界です。そしてお互いのもとにたどり着くまでは、さまざまな見知らぬサーバ/ネットワーク機器を経由します。要するに全ての通信は途中のサーバ管理者から丸見えです。当然Xが生成した最初の鍵も簡単に見られてしまいます。

1.3.2 本当?
本当です。サーバ上でネットワークトラフィックをダンプすれば、全部見えます。

1.3.2.1 杞憂じゃないの?
杞憂ではありません。

1.3.2.2 そんなの割り切っちゃえば?
あなたのパスワードやらクレジットカード番号が丸見えでもいいんですか?

1.3.2.3 それはいやだな。
でしょう。

1.3.3 じゃあどうやって最初の鍵を配るの?
公開鍵というものを使います。

1.4 公開鍵って?
暗号化する手順を公開します。復号化出来るのは、その暗号化手順を作った人だけです。
Aさんは公開されている暗号化手順で通信を暗号化します。それを復号化できるのはその暗号化手順を作った人だけです。つまり、公開鍵を使って最初の通信メッセージを暗号化すれば、そのメッセージは、Xにしか復号化できません。だから最初のメッセージから安全にやりとりできるわけです。

1.5 暗号化する手順が分かれば、復号できるんじゃないの?
それが非常に難しいんだそうです。

1.5.1 どうなってるの?
詳しい話は私にも分かりません。素因数分解とか、そういう話のようです。詳しくはWikipediaなどを調べてください。

1.5.2 よく分からない。面倒くさい。
同感です。まあ、その辺は隠蔽されているので、知らなくてもSSLは設定できます。

1.5.3 それはよかった。
はい。

1.6 じゃあ秘密鍵と公開鍵を持てばSSL通信できるわけね。
いえ。まだ足りません。公開鍵が本当に通信したい相手のものかどうかを、知るすべが必要です。

1.6.1 どうして。
Aさんがインターネット書店サイト'ほんもの書店.com'から本を買うとします。'ほんもの書店.com'はネット通販のためにSSLに対応しています。Aさんはある日通販リンク集サイトの'あやしいリンク集'(実はイカサマサイト)を辿って'ほんもの書店.com'へのリンクをクリックしました。
実は、この'あやしいリンク集'経由で訪れたページは、すべてこの'リンク集'が設置されたサーバ(Yとしましょう)経由で通信されるように仕組まれていたのです。するとYはAさんに対して偽の公開鍵を発行することが可能になってしまいます。
Aさんは暗号化が行われていると信じて、クレジットカード番号と住所を打ち込むのですが、その情報は全てYに筒抜けとなるのです。
その流れを表すと、以下の流れになります。
i.   'ほんもの書店.com' → 公開鍵X →  'Y' (公開鍵XをYと差替え) → 公開鍵Y → 'Aさん'
ii. 'Aさん'(公開鍵Yで情報[共通鍵Z]を暗号化) → Y暗号 → 
   → 'Y'(Y暗号を解読。公開鍵Xで再度暗号化) → X暗号 → 'ほんもの書店.com'
iii. 'ほんもの書店.com'(クライアントから送られた共通鍵Zで暗号化) → Z暗号 →
   → 'Y'(Z暗号は既に知っているので読み取り可能) → Z暗号 → 'Aさん'

1.6.1.1 何となく分かった。でもこんな面倒くさいこと誰がするの?
面倒臭くありません。優れたプログラマなら下手をすれば数日で作っちゃいますよ。

1.6.1.2 ハッカーってやつね。
クラッカーです。ハッカーは意味が違います。(という主張も最近は聞かなくなったな)

1.6.1.3 何を言ってる?
もういいです。

1.7 どうやってある公開鍵が目的のサイトのものだと分かる?
Verisign Inc.などの第三者機関が公開鍵の証明書を発行します。
ある公開鍵がどのサイトに対して有効なものか、信頼できる第三者機関が保証してくれるわけです。

1.8 証明書?
公開鍵とあわせて証明書をクライアント(ブラウザ)に提示します。証明書には第三者機関による電子署名が入っていて、証明書の偽造を防ぎます。
ブラウザは証明書とサイトのアドレスをチェックして、目的のサイトの公開鍵かどうかをチェックすることができます。

1.8.1 SSLを使えば絶対安全なの?
そうとも言えません。
SSLで暗号化できても、その向こうにいるのはやはり人間だ、ということです。
技術的な安全性については、詳しくはWikipediaのSecure Sockets Layerを見て下さい。

1.8.2 ネットショッピングが怖くなってきた
普通に有名なサイトを利用している分には大丈夫でしょう。多分・・・

1.8.3 何かつかれてきた
私もです。

1.8.4 もう終わりにしたい
私もです。

1.8.5 まとめて
結論です。SSLを構成するのに必要なのは以下の2つです。
-公開鍵/暗号鍵
-公開鍵証明書
※外部に公開したサーバであれば、証明書は第三者機関に依頼することになります。
以上がまとめです。

1.9 (1/31追記)ちょっと待った。1.6.1の例では第三者の証明書は役に立たないじゃないか
どうしてですか。

1.9.1 中間サーバのYが正規の証明書を取ってしまえばいい
あ。

1.9.2 どうだ
くやしい。

1.9.3 ということは、証明書があるからと言って安心してはだめだ、というのが結論だな
ま、そういうことですね。