『トランヴェール - Train Vert』という無料雑誌があります。JR東日本の新幹線の座席ポケットに、通販雑誌と共に配られています。こぢんまりとまとまっていて広告臭も薄く、ぼーっと目を通すには悪くない雑誌です。
このGW、子供を連れて新幹線に乗る機会がありました。新幹線に乗ってしばらくして、子供たちがおもちゃやお菓子に目を奪われておとなしくなっている隙に、缶ビールの栓を空けてこの雑誌の5月号を手に取りました。何気なく読み始めたのですが、冒頭に掲載されていた内館牧子氏のエッセイにいきなりいやな気分にさせられました。
内容は、コンビニのサンドイッチとおにぎりを泣きながら拒否する未就学児と、それをなだめる親についてのエッセイです。
この未就学児は内館氏の足元に「ゴミ」などと言ってサンドイッチを投げつけ、親は彼(彼女)を叱りもせず海苔巻を与えて一緒に食べたそうです。エッセイは、日本の歴史上の少年兵士と目の前の親子を比較して親子を醜いと断罪するものでした。曰く昔の少年は屋外ではモノを食べてはならないと教えられてきた、飢えを我慢して戦いに臨んだ少年に比べ、この親子の醜さはなんだ、云々
言わんとすることは分かるのですが、一言でいえば「大人気ないなあ」という感想です。その場で「食べ物を粗末にさせてはならない」と親を注意するのならともかく、当の本人たちには何も言わずに言わば公共の場であるところの雑誌で糾弾するというのはどうも卑怯ではないかな、という気がしました。
子供を持つ親の立場からすれば、内館氏に断罪された彼らの気持ちも分からないではありません。
・不機嫌な子供は実に、実に、実に扱いづらい
・子供を怒る親を不愉快に思う人は多い(泣く子供よりも子供を真剣に怒る親の方が醜い)
⇒ 子供はさっさとなだめたい(内館氏のような人がいるから!)
(もう一つ言えば)
・コンビニのサンドイッチはかなりいまいちである
だから、私にとってすれば、彼らが公共の場で貶められるのは残念な気がしてなりません。一歩間違えば、つまり家族の気分や疲れ次第では、容易に起こり得る状況だからです。(ついでに言えば仮に私が断罪された親の立場だったとして、面と向かって文句を言われたら素直に謝りますし、別にしかられたことにクヨクヨしません。)
いやはや。
モットーは「健全な精神は健全な胃腸に宿る」「生きてるあいだは上機嫌」
主張として「原発は営利企業に任せるべきでなく、もんじゅは絶対に廃炉!」「税金には気をつけろ!」
もう一つ、福島原発作業員の方々ならびに早野先生に国民栄誉賞を。
サブ・ブログという位置づけで、細々更新しています。
2008年4月28日月曜日
ドラえもん 緑の巨人なんとか
期待せずに見に行ったのですが、にもかかわらず、残念ながらかなりの駄作でした。
安直な「自然との共生万歳」的なサクサクストーリーであることは覚悟していました。しかし物語以前に展開やセリフ回し、人物描写がお話にならないくらい乱暴で脈絡がないです。ラピュタのパクリもイタい。シャレにもパロディにもなってないし、何で??と違和感のみが残る感じでした。
途中から「こりゃひどい」と思って目と耳をシャットダウンして耐えていましたが、辛かった・・・
子供も「いつまで経っても宇宙船から出られなくてつまらない」と言ったので、途中で出てきました。
映画版プリキュアの方がよほど面白かったです。
安直な「自然との共生万歳」的なサクサクストーリーであることは覚悟していました。しかし物語以前に展開やセリフ回し、人物描写がお話にならないくらい乱暴で脈絡がないです。ラピュタのパクリもイタい。シャレにもパロディにもなってないし、何で??と違和感のみが残る感じでした。
途中から「こりゃひどい」と思って目と耳をシャットダウンして耐えていましたが、辛かった・・・
子供も「いつまで経っても宇宙船から出られなくてつまらない」と言ったので、途中で出てきました。
映画版プリキュアの方がよほど面白かったです。
2008年4月24日木曜日
これは強力!XDoclet
非常に便利そうに見えるのですが、EJBやStrutsと共に使われるため、この人単体で何ができるのかが見えづらいXDocletです。
実際に試してみましたが、かなりマニアックですが、相当使えるツールとみました。
(そもそも目的が違うかもしれませんが、JJTreeとかjavaccとかで苦労したことがサクっとできる感じです)
かなりシンプルに試してみました。
【概要】
XDocletはAntと連携して動きます。
今回、Ant1.7、XDoclet1.23を使いました。
(1)ant buildファイルにXDocletタスクを定義します。
タスクにはejbとかStrugsとかSpring用にすでにカスタマイズされたものがあるようですが、今回はシンプルに実行するため「xdoclet.DocletTask」を使います。
antを実行すると、ソースディレクトリに含まれるJavaソースを解析してくれます。クラス名や、JavaDocコメント形式のコメントそれぞれにアクセスできるようになります。
(2)次に.xdtファイルを準備します。
特にXMLフォーマットにこだわる必要はなさそうです。CSVなどにも出力できますし、当然JavaソースをジェネるのもOK(なんと素晴らしい)
<XDtClass:forAllClasses>タグなどを使って、クラス名やコメントにアクセスします。
(3)Javaを準備します。
JavaDocコメント形式
/**
* @mytest.tag3
* name="foo"
*/
で書いておくと、XDocletが解析してくれます(ただのコメントでは駄目です。)
(4)Antタスクを実行すると、xdtに解析結果を埋め込んだ形でアウトプットが作成されます。
EJBやStruts、SpringのXML定義ファイルや、Setter, Getterしか持たない単純なBeanクラスなどをジェネるのに最適!素晴らしいツールです。
【詳細】
ディレクトリ構造はこんな感じ。

まずはAnt build fileです。
次に'*.xdt'です。二通り準備しました。
■test_print.xdt
■test_xml.xdt
次にJavaソース(1本/2本)
(2本/2本)
実行すると、以下の二つのファイルが作成されます。
う~ん。強力。(って不親切過ぎかな)
余裕が出たら、もう少し細かく解説します。
参考)
春のXDoclet中心生活
実際に試してみましたが、かなりマニアックですが、相当使えるツールとみました。
(そもそも目的が違うかもしれませんが、JJTreeとかjavaccとかで苦労したことがサクっとできる感じです)
かなりシンプルに試してみました。
【概要】
XDocletはAntと連携して動きます。
今回、Ant1.7、XDoclet1.23を使いました。
(1)ant buildファイルにXDocletタスクを定義します。
タスクにはejbとかStrugsとかSpring用にすでにカスタマイズされたものがあるようですが、今回はシンプルに実行するため「xdoclet.DocletTask」を使います。
antを実行すると、ソースディレクトリに含まれるJavaソースを解析してくれます。クラス名や、JavaDocコメント形式のコメントそれぞれにアクセスできるようになります。
(2)次に.xdtファイルを準備します。
特にXMLフォーマットにこだわる必要はなさそうです。CSVなどにも出力できますし、当然JavaソースをジェネるのもOK(なんと素晴らしい)
<XDtClass:forAllClasses>タグなどを使って、クラス名やコメントにアクセスします。
(3)Javaを準備します。
JavaDocコメント形式
/**
* @mytest.tag3
* name="foo"
*/
で書いておくと、XDocletが解析してくれます(ただのコメントでは駄目です。)
(4)Antタスクを実行すると、xdtに解析結果を埋め込んだ形でアウトプットが作成されます。
EJBやStruts、SpringのXML定義ファイルや、Setter, Getterしか持たない単純なBeanクラスなどをジェネるのに最適!素晴らしいツールです。
【詳細】
ディレクトリ構造はこんな感じ。

まずはAnt build fileです。
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="./" default="build" name="xdoclet-test">
<!-- Properties -->
<property name="xdoclet.home" value="F:/libraries/xdoclet-1.23"/>
<property name="src.dir" value="src"/>
<property name="xdoclet.template.dir" value="xdt"/>
<property name="build.xml.dir" value="xml"/>
<property name="build.dir" value="bin"/>
<!-- Path definitions -->
<path id="xdoclet.classpath">
<fileset dir="${xdoclet.home}/lib">
<include name="*.jar"/>
</fileset>
</path>
<!-- Targets -->
<target name="compile">
<mkdir dir="${build.dir}"/>
<javac destdir="${build.dir}" source="1.5" target="1.5" debug="true"
deprecation="false" optimize="false" failonerror="true">
<src path="${src.dir}"/>
<classpath refid="xdoclet.classpath"/>
</javac>
</target>
<target name="build" depends="compile">
<taskdef classname="xdoclet.DocletTask" name="doclet"
classpathref="xdoclet.classpath" />
<doclet destdir="${src.dir}"
excludedtags="@version, @author, @todo" force="true"
verbose="false">
<fileset dir="${src.dir}">
<include name="**/*.java" />
</fileset>
<template destDir="${build.xml.dir}"
destinationFile="test.xml"
templateFile="${xdoclet.template.dir}/test_xml.xdt"
subTaskName="Generate XML file" />
<template destDir="${build.xml.dir}"
destinationFile="test.txt"
templateFile="${xdoclet.template.dir}/test_print.xdt"
subTaskName="Generate Class info" />
</doclet>
</target>
</project>
次に'*.xdt'です。二通り準備しました。
■test_print.xdt
<XDtClass:forAllClasses>==================================================
Class name :
<XDtClass:fullClassName/>
Class tag values :
<XDtClass:forAllClassTags tagName="mytest.tag1">
<XDtClass:classTagValue
tagName="mytest.tag1" paramName="value"/>
Field tag values :
<XDtField:forAllFields>
<XDtField:fieldTagValue
tagName="mytest.tag3" paramName="name"/>
</XDtField:forAllFields>
Method tag values :
<XDtMethod:forAllMethods>
<XDtMethod:ifHasMethodTag tagName="mytest.tag2">
<XDtMethod:methodTagValue
tagName="mytest.tag2" paramName="name"/>
</XDtMethod:ifHasMethodTag></XDtMethod:forAllMethods>
</XDtClass:forAllClassTags>
</XDtClass:forAllClasses>
■test_xml.xdt
<?XML version="1.0" encoding="UTF-8"?>
<XDtClass:forAllClasses>
<class name="<XDtClass:className/>">
<variables>
<XDtClass:forAllClassTags tagName="mytest.tag1">
<tag value="<XDtClass:classTagValue
tagName="mytest.tag1" paramName="value"/>"/>
</XDtClass:forAllClassTags>
</variables>
<fields>
<XDtField:forAllFields>
<tag value="<XDtField:fieldTagValue
tagName="mytest.tag3" paramName="name"/>"/>
</XDtField:forAllFields>
</fields>
<methods>
<XDtMethod:forAllMethods>
<XDtMethod:ifHasMethodTag tagName="mytest.tag2">
<tag value="<XDtMethod:methodTagValue
tagName="mytest.tag2" paramName="name"/>"/>
</XDtMethod:ifHasMethodTag>
</XDtMethod:forAllMethods>
</methods>
</class>
</XDtClass:forAllClasses>
次にJavaソース(1本/2本)
package testpack;
/**
* @mytest.tag1
* value="hoge1"
*/
public class XDocletTest0 {
/**
* @mytest.tag3
* name="foo"
*/
public static String STATIC_VAR = "hoge";
int i = 0;
/**
* @mytest.tag2
* name="piyo2"
*/
public static void method1() {
return;
}
private String method2(String arg) {
return arg;
}
}
(2本/2本)
package testpack;
/**
* @mytest.tag1
* value="hoge1-2"
*/
public class XDocletTest1 {
/**
* @mytest.tag3
* name="foo-2"
*/
public static String STATIC_VAR = "hoge";
int i = 0;
/**
* @mytest.tag2
* name="piyo2-2"
*/
public static void method1() {
return;
}
private String method2(String arg) {
return arg;
}
}
実行すると、以下の二つのファイルが作成されます。
う~ん。強力。(って不親切過ぎかな)
==================================================
Class name :
testpack.XDocletTest1
Class tag values :
hoge1-2
Field tag values :
foo-2
Method tag values :
piyo2-2
==================================================
Class name :
testpack.XDocletTest0
Class tag values :
hoge1
Field tag values :
foo
Method tag values :
piyo2
<?XML version="1.0" encoding="UTF-8"?>
<class name="XDocletTest1">
<variables>
<tag value="hoge1-2"/>
</variables>
<fields>
<tag value="foo-2"/>
<tag value=""/>
</fields>
<methods>
<tag value="piyo2-2"/>
</methods>
</class>
<class name="XDocletTest0">
<variables>
<tag value="hoge1"/>
</variables>
<fields>
<tag value="foo"/>
<tag value=""/>
</fields>
<methods>
<tag value="piyo2"/>
</methods>
</class>
余裕が出たら、もう少し細かく解説します。
参考)
春のXDoclet中心生活
2008年4月17日木曜日
プロジェクトにおける不安について
プロジェクトに参画した人は、普通さまざまな不安を抱きます。
「このコードをリリースして大丈夫だろうか」(開発者)
「無事リリースできるのだろうか」「明日はどんな障害が発生するだろうか」(マネージャー)
「障害が発生して業務を止めたりしないだろうか」(顧客)
人は不安からは逃げられません。プライベートであろうが仕事であろうが、あらゆることが不安の対象となります。
むしろ不安を抱かない方が却って問題です。何も不安に思わなければ、問題意識も生まれません。漠然とした不安をきっかけとして、具体的で有効なアクションを取れることもあるのです。
不安には冷静に対処する必要があります。なぜ自分が不安に思うのか。まずはその対象を明確にしなければなりません。また、不安は対象が明確になればほとんど消えてしまうものなのです。
いろいろ考えてみると不安の原因が単に自分の無知だった、ということも少なくありません。その場合も不安はさっぱりと消えてしまいます。
例えば、あるプログラムが本当に動くかどうか不安に思って調べたところ、開発環境でずっと問題なく動いていることを知ったために一切の不安がなくなった、などということは開発者ならば珍しくないでしょう。
もちろん、対処しようがない不安もあります。そういう場合は覚悟を決める他はありません。ですが、プロジェクトに参画することで生じる不安は、ほとんど全てが具体化すれば消えてしまうものです。ですから、具体化の努力を怠ってはなりません。
まずは漠然とした不安を感じたとして、その不安の原因をできるだけ具体化するのです。例えばある機能がちゃんと定義されているかどうか。具体的にはどのような定義が、どこに設定してあればよいのか。期待通りに定義されていることを確認すれば、不安は消えます。
あるいは無知から生じる不安については、自分が何を知らないから不安なのかをはっきりさせ、その具体的な事実なり知識なりを仕入れさえすれば、同じく不安は解消します。
それを怠り、いたずらに不安の対象を広げるのは好ましくありません。特に下手に不安を抽象化するとその対象は際限なく広がることになります。
例えば、先ほどの「設定漏れ」が不安の原因ではなく、「人によるチェックミス」が原因だと考えてしまったとしましょう。ところが人為的なミスはどこでも常に発生しうるものです。ですから、そのように不安の原因を定義してしまうと、不安はいつまで立っても解消しないことになります。人によるチェックミスは「あってはならないもの」ではなく「当然ありうべき」言わば制約なのです。不安の原因がチェックミスであると考えてしまうと「チェックミスが発生する(し得る)」限り不安は解消しません。すると「今後チェックミスは許さない」という無茶なスローガンが生じたり、「他にチェックミスはないのか」という愚問が生まれたりします。
もちろん今後同じようなミスが発生しないように、「設定漏れ」というリスクに対して「設定項目が正しいか」チェックする運用を作る、という対処は正しいと言えます。そうではなく、顧客やマネージャーの漠然とした不安を「全部チェックする」「あらゆる設定の妥当性を確認する」ことによって解消しようとすると、行きつく先はプロジェクトの破綻です。
顧客やマネージャの不安を上手にハンドリングできるSE、つまり「信頼感」を与えるSEこそが、優れたSEではないか、と私は思います。
「このコードをリリースして大丈夫だろうか」(開発者)
「無事リリースできるのだろうか」「明日はどんな障害が発生するだろうか」(マネージャー)
「障害が発生して業務を止めたりしないだろうか」(顧客)
人は不安からは逃げられません。プライベートであろうが仕事であろうが、あらゆることが不安の対象となります。
むしろ不安を抱かない方が却って問題です。何も不安に思わなければ、問題意識も生まれません。漠然とした不安をきっかけとして、具体的で有効なアクションを取れることもあるのです。
不安には冷静に対処する必要があります。なぜ自分が不安に思うのか。まずはその対象を明確にしなければなりません。また、不安は対象が明確になればほとんど消えてしまうものなのです。
いろいろ考えてみると不安の原因が単に自分の無知だった、ということも少なくありません。その場合も不安はさっぱりと消えてしまいます。
例えば、あるプログラムが本当に動くかどうか不安に思って調べたところ、開発環境でずっと問題なく動いていることを知ったために一切の不安がなくなった、などということは開発者ならば珍しくないでしょう。
もちろん、対処しようがない不安もあります。そういう場合は覚悟を決める他はありません。ですが、プロジェクトに参画することで生じる不安は、ほとんど全てが具体化すれば消えてしまうものです。ですから、具体化の努力を怠ってはなりません。
まずは漠然とした不安を感じたとして、その不安の原因をできるだけ具体化するのです。例えばある機能がちゃんと定義されているかどうか。具体的にはどのような定義が、どこに設定してあればよいのか。期待通りに定義されていることを確認すれば、不安は消えます。
あるいは無知から生じる不安については、自分が何を知らないから不安なのかをはっきりさせ、その具体的な事実なり知識なりを仕入れさえすれば、同じく不安は解消します。
それを怠り、いたずらに不安の対象を広げるのは好ましくありません。特に下手に不安を抽象化するとその対象は際限なく広がることになります。
例えば、先ほどの「設定漏れ」が不安の原因ではなく、「人によるチェックミス」が原因だと考えてしまったとしましょう。ところが人為的なミスはどこでも常に発生しうるものです。ですから、そのように不安の原因を定義してしまうと、不安はいつまで立っても解消しないことになります。人によるチェックミスは「あってはならないもの」ではなく「当然ありうべき」言わば制約なのです。不安の原因がチェックミスであると考えてしまうと「チェックミスが発生する(し得る)」限り不安は解消しません。すると「今後チェックミスは許さない」という無茶なスローガンが生じたり、「他にチェックミスはないのか」という愚問が生まれたりします。
もちろん今後同じようなミスが発生しないように、「設定漏れ」というリスクに対して「設定項目が正しいか」チェックする運用を作る、という対処は正しいと言えます。そうではなく、顧客やマネージャーの漠然とした不安を「全部チェックする」「あらゆる設定の妥当性を確認する」ことによって解消しようとすると、行きつく先はプロジェクトの破綻です。
顧客やマネージャの不安を上手にハンドリングできるSE、つまり「信頼感」を与えるSEこそが、優れたSEではないか、と私は思います。
DB2ストアドプロシージャ メモ
Stored Procedure のページが簡潔で良いです。
この通りにやれば出来ますが、一部ハマった点があったのでメモしておきます。
まず、接続は「デフォルトコネクション」を使います。
最初、'jdbc:db2://hostname:port/dbname'でやったところ見事にハマりました。
まず「resultset closed invalid operation」とか何とか出て、気持ち悪いなと思ったもののconnectionをクローズせずにやったところ「java.sql.CallableStatement.executeQuery() was called but no result set was returned.」だのなんだの。
デフォルトコネクションを使ったところ、connectionをcloseしても問題なく使えました。
次に
です。これを実行すると、SQL0444N rc=4 が出ました。
これも大分ハマったのですが、
以下のように'void'を取ると問題なく実行できました。
以上です。
この通りにやれば出来ますが、一部ハマった点があったのでメモしておきます。
まず、接続は「デフォルトコネクション」を使います。
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を確認します。サーバがセットアップされているのが前提となります。
■プロジェクト追加■
■バイナリファイルの指定■
■CVS関連作業の終了■
cvsからチェックアウトしたファイルをリリースします('-d'オプションでディレクトリも削除されます)。一旦作業を止めるイメージです。
■タグをつける■
タグをつける前に、以下のを確認しましょう。
バージョンを構成する全てのファイルがコミットされていること
リリースしないファイルやディレクトリがないこと
# ls *.log *tmp* *test* *.org *.orig *.bak *.back *.[0-9]* *hoge* *piyo* *foo* *bar* # などなど
classなどをCVSで管理している場合は、タグをつける前にコンパイルをしましょう
■rdiffの使い方■
タグ=バージョン名をつけると、タグを使ってもバージョン同士/バージョンと現状のdiff/rdiffを見ることができます。(もちろん-r [リビジョン]でもOKです)
■cvs statやcvs logコマンドでタグの状況を確認■
■タグを削除する■
■エクスポートする■
バージョンを指定してエクスポートします。
エクスポートによって"CVS"管理ディレクトリを含めないでソースを抽出することができます。
タイムスタンプも、レポジトリ上の最終更新日に揃えられます。
■コメントを編集する■
■パーミッションを変更する■
やむを得ず(go+xやパg+wなど)パーミッションを変更する場合は、レポジトリのファイルパーミッションを直接変更することになります。
レポジトリのパーミッション+umaskで最終的なパーミッションが決まります。
動かなくならないよう、常識的な範囲で変更して下さい。
■ログインしてモジュールをチェックアウトする■
■ファイル追加■
ファイル'addtest.ksh'を追加します。
■バイナリファイルの追加■
■ディレクトリ追加■
ファイルが存在しないディレクトリは存在しないのと同じです。
他の人が追加したディレクトリを自分の作業ディレクトリに表示させるときは
cvs update -d -P を実行します。
■ファイル編集■
viでも何でも使って適宜編集した後、update, commitします。
'cvs commit ファイル名' とすると指定したファイルのみをcommitします。
■ファイル削除■
実際にはファイルは削除されません。レポジトリから見えなくなるだけで、いつでも復活させることができます
cvs remove -f とすれば、rmコマンドは不要です。
# 削除後でもログは参照可能です。
# cvs log filename
■ファイルの削除を中止する■
手順概要(1)remove 実行前
手順概要(2)remove 実行後(commit未済)
手順概要(3)remove/commit後
■ディレクトリ削除■
実際には削除されません。リポジトリには空のディレクトリが残ります。
■ファイルの名前を変更する■■
■ディレクトリの名前を変更する■
特別な手順はありません。新規のディレクトリを作成し、ディレクトリ中のファイルを作成したディレクトリに移動させます。
■古いファイルとのDIFF■
■コメント/履歴確認■
■バージョン確認■
'-v'を追加するとタグ(リリースバージョン)情報を出力します。
■最新バージョンに書き戻す■
■古いバージョンに書き戻す■
■追加を途中でやめる■
commitは不要です。
■作業ディレクトリがいつチェックアウトしたものか分からなくなった■
作業ディレクトリで'cvs update'するか、一旦作業ディレクトリを削除してcheck outします。
(当たり前か)
■終了する(release)■
cvs releaseコマンドを使います。
'-d'オプションを使うとディレクトリまで削除してくれます。
【参考】
CVS--Concurrent Versions System (in Japanese) - CVS のコマンド便覧 必要十分なリファレンス
CVS使用法メモ(Hishidama's CVS usage Memo) 実践的なコマンドメモ
リリースブランチ(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出力結果の見方
申し訳ないほど基本的なことですみません。
普段ぼおっと見ているもので、今回意識的に整理してみました。
読み方
1. 'File1'の'Number1'行に、'File2'の'Number2'(から'Number3')の行を追加
2. 'File1'の'Number1'(からNumber2')を('File2'の'Number3'から)削除
3. 'File1'の'Number1'(からNumber2')を'File2'の'Number3'(から'Number4')の記載へと変更
(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は同じファイル
といった読み方になりましょうか。
普段ぼおっと見ているもので、今回意識的に整理してみました。
【凡例】
$ 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が最新でした。
b. インストールします
c. 各種設定
1:ユーザの作成
などでCVSユーザ(ここではcvsuser)を作成します。
パスワードも忘れずに付けておきましょう。(rootで"passwd cvuser")
(手順は割愛)
2:CVSレポジトリの作成とinit
ディレクトリを作成し、cvs initを実行します。
3:/etc/servicesに以下のエントリーを追加
/etc/servicesに以下のエントリーが存在しない場合(存在しないと思いますが)追加します。
4:/etc/inetd.confに以下のエントリーを追加
5:inetdを再起動
この状態で'cvsuser'でEclipseから接続し、使うことができます。
6:(オプション)cvsのpasswdを作成
/full/path/to/cvsroot/CVSROOT
以下にpasswdファイルを使います。書式は
userid:encrypt_password:valid_userid
です。パスワードが空で、cvsuserと同じ権限でアクセスできる'cvs'ユーザを作成する場合は、
というエントリーを追加すれば良いです。
ファイルのエンクリプトには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が表示され、使えるようになります。
■手順あらまし
(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のケースでしょう。自分がコントロールできたわけでもない障害について、法人名で責任を問われるのですから。
障害が発生してがっかりしている顧客に申し訳ないと思いつつ(中には張り切っている顧客もいるかもしれませんが)、自身の罪悪感を何とかマネジメントしなければなりません。
恐らくは適度な罪悪感が必要なのでしょう。過度に思いつめると、行き着く先は肉体的/精神的ダウンです。あまりに罪悪感がなさすぎると、顧客からは信頼されなくなります。
顧客の立場は理解した上で、障害対応に必要なモチベーションは保持しつつ、不安に駆られた顧客からの、理不尽な対応は適宜断るなり、有効なものを逆に提案するなりできる、そんな適度な精神状態になりたいものです。
(続く・・のか?)
罪悪感を強く感じてしまうタイプの人は、その感情にドライブされてハードワークにのめり込み、体か精神を壊してしまうという結果にハマりやすいといえるでしょう。
そこまでいかないまでも、何となく「何でオレがこんな目に・・・」「知るかよ!」的な感情に囚われ、モチベーションが下がったり、訳もなく顧客に悪い感情を持ってしまうこともあるかと思います(顧客だって同じことを言いたいんですが、そこまで気が回らなくなるんですね)。
罪悪感をあまり感じずに、モチベーションを維持できる人は非常にお得です。私も常日頃そうなりたいものだ、と思っているのですが・・・
以上の説明では、分かる人には分かるかも知れませんが、分からない人には何のことだかさっぱり分かりませんね。もう少し具体的に書いてみましょう。まず、迷惑を掛ける原因の方です。
【ケース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を勉強して欲しい、などと言うつもりはありません。昔の技術でも何でもよいのです。とにかく現在のシステムを理解しようと努力すること。現在のシステムが人によって作られていることを理解すること。その努力がなければ、これからもどんどん現場とマネジメント層が乖離して行くことになるのではないでしょうか。現場とマネジメントが無理解によって乖離して行けば、理不尽な意思決定が行われることも増えますし、それにつれて現場のモチベーションも下がって行きます。
技術が変って行くその背景を見つめ、適切に理解し、セールストークに踊らされず、現場をきちんと理解すること。これらのことが重要になってくるだろう、と私は思います。
それは、技術があたかも魔法のソリューションのように語られるようになることです。もちろん顧客の誰もそんな売り文句を全て信じているわけではないでしょう。しかし、それを生み出す方は必死です。世の中を見回せば、ある技術が「とても素晴らしい」ものであり「顧客の抱える問題を見事に解決する」ものであるキャッチフレーズに溢れているようです。曰く、複雑怪奇な環境で行る非効率なビジネスプロセスを革新して、目覚しい生産性をもたらす。あるいは、そこかしこに散ったビジネスロジックを統合して業務の効率化だけではなく運用体力の軽減を実現する。あるいは企業の意思決定を迅速に行えるようにし、国際競争力を強くする、などなど。
しかし、そのセールストークが指すのが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アプリケーション実行環境が利用されるようになった。
→ クラサバから三層アーキテクチャへ。
上記の他にも理由はいろいろありそうですが、ここで少し根本的な問いを立てて見ましょう。
それは「なぜ、ソフトウェアが変らなければならなかったのか」という問いです。
ソフトウェアの技術の変遷と軌を一にして、環境が変ってきたことが分かりました。どちらかと言えば環境が先に変化し、それに伴ってソフトウェアの状況が変ってきたように見えます。この流れは不自然ではありません。ハードウェアの変化は('ハード'らしく)硬直的です。つまり、ソフトウェアに合わせてハードウェアが変るよりもハードウェアの変化に合わせてソフトウェアが変る方がよほど自然だからです(一部の例外はありますが)。
しかし、ここでもう一度問いを立ててみましょう。「ハードウェアが進歩したからといってソフトウェアは本当に変らなければならなかったのか」。
実はここには必然的なつながりはないのです。ホストの処理能力が向上したのなら、ホストで稼働させるアプリケーションもそのまま早くなります。ハードウェアを置き換えて、アプリケーションをそのまま稼働させればよい。
クラサバも同様です。クライアントが早くなれば、そのままクライアントアプリケーションの処理が早くなる訳ですから、単にリプレースすればよい。
ソフトウェアが変化しなければならないのは、主に二つの理由からです。
一つは技術を活性化すること。技術を新しくすることによって、新しい人材をひきつけることができます。また、若い技術者は昔の技術に早晩慣れてしまい、それを改善したがります。彼らは学習意欲が活発で、また吸収も早い。この場合ソフトウェアの変化は、ソフトウェアの改善に結びつきます。
もう一つはビジネス上の理由です。新しいビジネスを作り出すために、ソフトウェアを変化させるのです。これをさらに二つに分けてみます。
一つは、いわゆるプロダクトのバージョンアップです。プロダクトに新しい機能を付け、バグを修正してリリースします。このサイクルを進めることで、昔のバージョンのサポートを切ることができます。サポートを切れば、サポートに必要な人体力を別の仕事に振り分けることができますし、顧客にはバージョンアップ費用を要求することができます。
使いもしない機能を売りつけるのか、とか、バグを直しただけの製品に新たに金を取るのか、という意見もあるかもしれませんが、ソフトウェアビジネスとしてはやむを得ない流れでしょう。
もう一つのタイプは、セールスのための新技術開発です。これは実体としてはプロダクトのバージョンアップと一体になっています。新しい技術はこんなに素晴らしく、お客様の問題を解決するものだからぜひ買ったらいいよ、という提案に結びつきます。
(続く)
昔のホスト中心の構成、一昔前のクライアント・サーバー構成、そして現在のJavaアプリケーションサーバが中心になった三層Webアーキテクチャ構成。
この遷移が、何を背景として進んできたのか。それには例えば以下のような理由があるでしょう。
■ ハードウェアの進歩
安価なハードウェアが普及したことによって、リッチなクライアントを展開しやすくなったこと。
→ ホストからクラサバへ。
コストと比較して、相対的にサーバの処理能力が向上したため、サーバでロジックを実行できるようになったこと。
→ クラサバから三層アーキテクチャへ。
■ インターネットの普及
インフラとしてのインターネットが一般化し、その上で稼働させるアプリケーションの実行環境が整ってきたこと。(Java Webアプリケーションサーバ、PHP、Ruby)
それによってイントラネットでもWebアプリケーション実行環境が利用されるようになった。
→ クラサバから三層アーキテクチャへ。
上記の他にも理由はいろいろありそうですが、ここで少し根本的な問いを立てて見ましょう。
それは「なぜ、ソフトウェアが変らなければならなかったのか」という問いです。
ソフトウェアの技術の変遷と軌を一にして、環境が変ってきたことが分かりました。どちらかと言えば環境が先に変化し、それに伴ってソフトウェアの状況が変ってきたように見えます。この流れは不自然ではありません。ハードウェアの変化は('ハード'らしく)硬直的です。つまり、ソフトウェアに合わせてハードウェアが変るよりもハードウェアの変化に合わせてソフトウェアが変る方がよほど自然だからです(一部の例外はありますが)。
しかし、ここでもう一度問いを立ててみましょう。「ハードウェアが進歩したからといってソフトウェアは本当に変らなければならなかったのか」。
実はここには必然的なつながりはないのです。ホストの処理能力が向上したのなら、ホストで稼働させるアプリケーションもそのまま早くなります。ハードウェアを置き換えて、アプリケーションをそのまま稼働させればよい。
クラサバも同様です。クライアントが早くなれば、そのままクライアントアプリケーションの処理が早くなる訳ですから、単にリプレースすればよい。
ソフトウェアが変化しなければならないのは、主に二つの理由からです。
一つは技術を活性化すること。技術を新しくすることによって、新しい人材をひきつけることができます。また、若い技術者は昔の技術に早晩慣れてしまい、それを改善したがります。彼らは学習意欲が活発で、また吸収も早い。この場合ソフトウェアの変化は、ソフトウェアの改善に結びつきます。
もう一つはビジネス上の理由です。新しいビジネスを作り出すために、ソフトウェアを変化させるのです。これをさらに二つに分けてみます。
一つは、いわゆるプロダクトのバージョンアップです。プロダクトに新しい機能を付け、バグを修正してリリースします。このサイクルを進めることで、昔のバージョンのサポートを切ることができます。サポートを切れば、サポートに必要な人体力を別の仕事に振り分けることができますし、顧客にはバージョンアップ費用を要求することができます。
使いもしない機能を売りつけるのか、とか、バグを直しただけの製品に新たに金を取るのか、という意見もあるかもしれませんが、ソフトウェアビジネスとしてはやむを得ない流れでしょう。
もう一つのタイプは、セールスのための新技術開発です。これは実体としてはプロダクトのバージョンアップと一体になっています。新しい技術はこんなに素晴らしく、お客様の問題を解決するものだからぜひ買ったらいいよ、という提案に結びつきます。
(続く)
2008年2月15日金曜日
プロジェクトと、そうでないもの
プロジェクトとは何でしょうか。
普段プロジェクトに関わっている人にとっては、十分過ぎる程の実在感を伴っているこの言葉ですが、悲惨なプロジェクトを経験したり、理不尽な顧客の要望を聞いていると、改めて「プロジェクトとは?」と考えさせられることは少なくありません。
ざっとWebや辞書で調べたところ、プロジェクトとは「一定の期間で何かを作り出すこと」と定義できるようです。これをベースとして、例えば「複数人で遂行するものである」とか「コストが決まっている」とか「新しい物を作る」とか付随的な定義もあります。
しかしまあ、はっきり言ってこのような定義に意味はないですね。なぜなら、かなり高いレベルまで抽象化されてしまっているからです。ここまで抽象化してしまうとシステム開発だろうがビルの建設だろうが、商品の開発だろうが、何にでも適用されます。無難ではありますが、空虚な定義です。
ここではもう少し具体的に踏み込んで考えて見ましょう。具体的に、とはどういうことでしょうか。それはもうこの上なく具体的に「いや、こんなのプロジェクトじゃねーよ」と心から叫びたくなるような、そんな無体なプロジェクトについて考えてみたいと思います。
さて、ここから本題に入りましょう。
いきなり本質に飛びますが、何のかんの言ってプロジェクトそれ自体が存在するわけではありません。存在するのはあくまで人です。人が集まっては喧々諤々と、あるいはしんねりむっつりと、何事かやっているわけです。要するに、プロジェクトはそれ自体が実体として存在するのではなく、人がやるものです。つまり、プロジェクトは人次第、ということになります。
プロジェクトの中でもシステム開発のそれには特徴があります。それは「成果物がなかなか見えない」ということです。とにかく文書は大量に出来上がる。コードのサイズも増えて行く。でも、最終的な成果物=システムがちゃんと動くかどうかはなかなか見えてきません。確かにテストをすれば分かります。でも、そのテストがちゃんとシステムの必要十分条件を満たしているかどうかは、非常に分かりづらい。
分かりづらいから人は何とかしようとします。何とかしようとするわけですが、そのやり方がまずいと「こんなのプロジェクトじゃないよー」という状況になります。
話が拡散してきました。要するにマズいプロジェクトは結局の所人の問題だ、というのが結論なのですが、一旦要件定義作業にフォーカスを当てましょう。
上手く行かないプロジェクトの特徴の一つに「要件がなかなか決まらない」というものがあります。あれもしたい。これもしたい。それも必要だ。いろいろ要件がでてきます。積極的な(=ポジティブな)要件を決めることは比較的簡単です。あれができます。これができます。出来ることを言っているだけなら誰にも文句はありません。
難しいのは消極的(=ネガティブ)な要件の決定です。このシステムではこれができません。このシステムを使うと、このデータは切り捨てる必要があります。この意思決定の方がよほど難しく、重要なのです。
何かを決定すれば、必ずどこかにリスクなり制約が発生します。意思決定とはそういうものです。ある選択をするということは、別の選択肢を捨てることなのです。それによってリスクや制約が発生する。しかし、そのリスクを取りたがらないお客さんがいる。そうなるとなかなか話が進まないことになります。あるいは進んだとしてもあれもこれも機能を盛り込むことによって納期、コスト、品質に悪影響が出てくる。悲惨なプロジェクトの始まりです。
このようなプロジェクトが始まると(そしてマネージャーがきちんと顧客の要求をマネージできないと)ひたすらTODOが定義されて、納期だけが決められ、品質が悪くなるかあるいはTODOがいつになってもこなせない、皆が不幸になるプロジェクトとなってしまいます。
こういう顧客をマネージすることでまず大事なのは、顧客と対立するのではなく、顧客をこちらの立場に引きこむ、ということです。リソースと時間が有限であるという課題を共有し、限られた中で一緒に何とかしてゆく、というスキームに持ち込むことです。コラボレーションして行く中で「できないものはできない」という当たり前のことを理解してもらうのです。
それから「未定義の領域がある」ことを理解してもらうことも大事でしょう。例えば「システムはこう動く」と定義して、お互いに同意して、その通り作ったとします。当然定義されていない個所については、顧客の思った通りにはならないこともあります。それはベンダーだけではなく顧客の責任でもあるのです。それを理解して貰えないと、いつまでたっても改善要望が尽きることはありません。顧客も「聞いてなかった」「知らなかった」では済まされないという意識を持ってもらう必要があります。
出来上がった後で気に入らない点が出たとしても、それはお互いの責任だ、ということです。システム開発プロジェクトでは、お客様は神様ではないのです。限られたリソースの中で一緒にモノを作って行くチームの中で、とりわけ責任が重いメンバー(リーダー)の一人なのです。
システム化するとは、あるプロセスを単なるデータの流れへと抽象化する、という側面があります。つまり、システム化によって何かが切り捨てられるのです。切り捨てられることによって、効率的になるのです。
ですからシステム化することによって何か出来ないことが出てくるのを恐れる必要はありません。それもまた、システム化の目的の一つなのですから。
普段プロジェクトに関わっている人にとっては、十分過ぎる程の実在感を伴っているこの言葉ですが、悲惨なプロジェクトを経験したり、理不尽な顧客の要望を聞いていると、改めて「プロジェクトとは?」と考えさせられることは少なくありません。
ざっとWebや辞書で調べたところ、プロジェクトとは「一定の期間で何かを作り出すこと」と定義できるようです。これをベースとして、例えば「複数人で遂行するものである」とか「コストが決まっている」とか「新しい物を作る」とか付随的な定義もあります。
しかしまあ、はっきり言ってこのような定義に意味はないですね。なぜなら、かなり高いレベルまで抽象化されてしまっているからです。ここまで抽象化してしまうとシステム開発だろうがビルの建設だろうが、商品の開発だろうが、何にでも適用されます。無難ではありますが、空虚な定義です。
ここではもう少し具体的に踏み込んで考えて見ましょう。具体的に、とはどういうことでしょうか。それはもうこの上なく具体的に「いや、こんなのプロジェクトじゃねーよ」と心から叫びたくなるような、そんな無体なプロジェクトについて考えてみたいと思います。
さて、ここから本題に入りましょう。
いきなり本質に飛びますが、何のかんの言ってプロジェクトそれ自体が存在するわけではありません。存在するのはあくまで人です。人が集まっては喧々諤々と、あるいはしんねりむっつりと、何事かやっているわけです。要するに、プロジェクトはそれ自体が実体として存在するのではなく、人がやるものです。つまり、プロジェクトは人次第、ということになります。
プロジェクトの中でもシステム開発のそれには特徴があります。それは「成果物がなかなか見えない」ということです。とにかく文書は大量に出来上がる。コードのサイズも増えて行く。でも、最終的な成果物=システムがちゃんと動くかどうかはなかなか見えてきません。確かにテストをすれば分かります。でも、そのテストがちゃんとシステムの必要十分条件を満たしているかどうかは、非常に分かりづらい。
分かりづらいから人は何とかしようとします。何とかしようとするわけですが、そのやり方がまずいと「こんなのプロジェクトじゃないよー」という状況になります。
話が拡散してきました。要するにマズいプロジェクトは結局の所人の問題だ、というのが結論なのですが、一旦要件定義作業にフォーカスを当てましょう。
上手く行かないプロジェクトの特徴の一つに「要件がなかなか決まらない」というものがあります。あれもしたい。これもしたい。それも必要だ。いろいろ要件がでてきます。積極的な(=ポジティブな)要件を決めることは比較的簡単です。あれができます。これができます。出来ることを言っているだけなら誰にも文句はありません。
難しいのは消極的(=ネガティブ)な要件の決定です。このシステムではこれができません。このシステムを使うと、このデータは切り捨てる必要があります。この意思決定の方がよほど難しく、重要なのです。
何かを決定すれば、必ずどこかにリスクなり制約が発生します。意思決定とはそういうものです。ある選択をするということは、別の選択肢を捨てることなのです。それによってリスクや制約が発生する。しかし、そのリスクを取りたがらないお客さんがいる。そうなるとなかなか話が進まないことになります。あるいは進んだとしてもあれもこれも機能を盛り込むことによって納期、コスト、品質に悪影響が出てくる。悲惨なプロジェクトの始まりです。
このようなプロジェクトが始まると(そしてマネージャーがきちんと顧客の要求をマネージできないと)ひたすらTODOが定義されて、納期だけが決められ、品質が悪くなるかあるいはTODOがいつになってもこなせない、皆が不幸になるプロジェクトとなってしまいます。
こういう顧客をマネージすることでまず大事なのは、顧客と対立するのではなく、顧客をこちらの立場に引きこむ、ということです。リソースと時間が有限であるという課題を共有し、限られた中で一緒に何とかしてゆく、というスキームに持ち込むことです。コラボレーションして行く中で「できないものはできない」という当たり前のことを理解してもらうのです。
それから「未定義の領域がある」ことを理解してもらうことも大事でしょう。例えば「システムはこう動く」と定義して、お互いに同意して、その通り作ったとします。当然定義されていない個所については、顧客の思った通りにはならないこともあります。それはベンダーだけではなく顧客の責任でもあるのです。それを理解して貰えないと、いつまでたっても改善要望が尽きることはありません。顧客も「聞いてなかった」「知らなかった」では済まされないという意識を持ってもらう必要があります。
出来上がった後で気に入らない点が出たとしても、それはお互いの責任だ、ということです。システム開発プロジェクトでは、お客様は神様ではないのです。限られたリソースの中で一緒にモノを作って行くチームの中で、とりわけ責任が重いメンバー(リーダー)の一人なのです。
システム化するとは、あるプロセスを単なるデータの流れへと抽象化する、という側面があります。つまり、システム化によって何かが切り捨てられるのです。切り捨てられることによって、効率的になるのです。
ですからシステム化することによって何か出来ないことが出てくるのを恐れる必要はありません。それもまた、システム化の目的の一つなのですから。
2008年2月13日水曜日
システム開発原理主義に注意
原理主義とは、何らかの教義を絶対視してそこからの逸脱を許さないような態度を意味します。ここではもう少しやわらかく「ある課題が、100%、完ぺきに遂行されることを求める態度」を指すことにしましょう。
厄介な態度ですね。しかし、普通の緊張感を持ってプロジェクトを運営していると、しばしば出くわす精神状態に違いありません。「徹底的に調査しろ!」「バグは許さない!」などなど。
プロジェクトを運営しているとそう言いたくなることはよくあります。しかし、実際のところこのような原理主義的スローガンは「百害あって一理なし」と言えるでしょう。
「なんだと?バグは徹底的に潰すべきだ!」「セキュリティホールは許されない!」「ミスなんかありえない。再チェック、再々チェック、再々々チェックだ!!!」というプロジェクトマネージャー(あるいは体育会系のリーダー)からの声が聞こえてきそうです。
ちょっと待ってください。冷静になって考えてみましょう。私も別にミスを許容している訳ではありません。明らかなミスやセキュリティホールは潰すべきでしょう。しかし、その手のタスクを「スローガン化」してしまうことの弊害は、今一度考えた方がよいと思うのです。
「徹底的にやります」「全てチェックします」という宣言は一見頼もしいものです。真面目な部下が青ざめた顔でこう報告した時「うむ。そうか。頑張れ!」と言いたくなることもあるでしょう。しかし、部下を信頼して後押しするとしたら、残念ながらあなたはマネージャー失格です。
なぜでしょうか。それは具体性が欠けているからです。「徹底的」とは、「全て」とは具体的には何を指しているのでしょうか。実際の所あなたの部下はどのように作業をするつもりなのでしょうか。それはひょっとしたらムダな作業ではないでしょうか。
「セキュリティホールをなくす作業が、ムダなはずはない!」あるいは「バグを潰す作業がムダであるはずがない!」とおっしゃるでしょうか。残念ながらそれもまた原理主義的スローガンから派生する無思考に過ぎません。
具体的に考えましょう。例えば今構築しているのがイントラネットを対象としたWebアプリケーションだとしましょう。するとセキュリティホールの重要性は急激に下がります。バグにしたって業務に関係あるものだけを探せばいいわけです。では、どうやって探すか。業務に関係ある操作は、テストケースで網羅されているのではありませんか?だとすれば、テストが実施されていれば、業務に関係のないバグは、既に潰れているはずですよね。そうでないとすれば、やるべきはテストケースの漏れをチェックすることであってバグの洗い出しではないでしょう(テストケースの見直しが手遅れでなければよいのですが・・・)。
そもそも見てすぐに分かるようなバグなら、既に直っているはずです。これまでの切り口では見えないものが潜在バグなのです。とすれば、潜在バグを顕在化させるためには、顕在化させるような切り口が必要となります。具体的にそのような切り口が定義できるなら、そしてその切り口が現実的ならば実際に調査してもよいでしょう。しかしいたずらに「潜在バグ」という言葉のおどろおどろしさに不安になって「徹底的に潜在バグを潰す」というスローガンが生まれたとすれば、それは単なる無思考に過ぎません。
このようなバグをゴキブリに例えてみましょう。ゴキブリがいるかどうかは分かります。ゴキブリを実際に見つければいいのです。死骸でも写真でもいい。とにかくいることは分かります。目の前にゴキブリを見つけながら、いない、というのは要するにウソです。
しかし、ゴキブリがいないことはいつまでたっても分からない。確かに目の前にはいない、でも背後にいるかもしれない。物陰に潜んでいるかもしれない。気が付いていないだけかもしれない。いないことはいつまでたっても証明はできません。だとすれば「バグを0にする」などは不可能なのです。せいぜい「これまでのところゴキブリは見つかっていない」としか言うことはできない。明日ゴキブリが見つかるかもしれないのです。
人間の認識は本来有限なものです。真実はなかなか分からない。それを忘れて簡単に原理主義的な発想に陥るのは、思い上がりに過ぎません。そしてその思い上がりは大抵はよく考えられていない不安から生じるものです。そのような原理主義がプロジェクトを破壊してしまうことは、容易に想像できるのではないでしょうか。
厄介な態度ですね。しかし、普通の緊張感を持ってプロジェクトを運営していると、しばしば出くわす精神状態に違いありません。「徹底的に調査しろ!」「バグは許さない!」などなど。
プロジェクトを運営しているとそう言いたくなることはよくあります。しかし、実際のところこのような原理主義的スローガンは「百害あって一理なし」と言えるでしょう。
「なんだと?バグは徹底的に潰すべきだ!」「セキュリティホールは許されない!」「ミスなんかありえない。再チェック、再々チェック、再々々チェックだ!!!」というプロジェクトマネージャー(あるいは体育会系のリーダー)からの声が聞こえてきそうです。
ちょっと待ってください。冷静になって考えてみましょう。私も別にミスを許容している訳ではありません。明らかなミスやセキュリティホールは潰すべきでしょう。しかし、その手のタスクを「スローガン化」してしまうことの弊害は、今一度考えた方がよいと思うのです。
「徹底的にやります」「全てチェックします」という宣言は一見頼もしいものです。真面目な部下が青ざめた顔でこう報告した時「うむ。そうか。頑張れ!」と言いたくなることもあるでしょう。しかし、部下を信頼して後押しするとしたら、残念ながらあなたはマネージャー失格です。
なぜでしょうか。それは具体性が欠けているからです。「徹底的」とは、「全て」とは具体的には何を指しているのでしょうか。実際の所あなたの部下はどのように作業をするつもりなのでしょうか。それはひょっとしたらムダな作業ではないでしょうか。
「セキュリティホールをなくす作業が、ムダなはずはない!」あるいは「バグを潰す作業がムダであるはずがない!」とおっしゃるでしょうか。残念ながらそれもまた原理主義的スローガンから派生する無思考に過ぎません。
具体的に考えましょう。例えば今構築しているのがイントラネットを対象としたWebアプリケーションだとしましょう。するとセキュリティホールの重要性は急激に下がります。バグにしたって業務に関係あるものだけを探せばいいわけです。では、どうやって探すか。業務に関係ある操作は、テストケースで網羅されているのではありませんか?だとすれば、テストが実施されていれば、業務に関係のないバグは、既に潰れているはずですよね。そうでないとすれば、やるべきはテストケースの漏れをチェックすることであってバグの洗い出しではないでしょう(テストケースの見直しが手遅れでなければよいのですが・・・)。
そもそも見てすぐに分かるようなバグなら、既に直っているはずです。これまでの切り口では見えないものが潜在バグなのです。とすれば、潜在バグを顕在化させるためには、顕在化させるような切り口が必要となります。具体的にそのような切り口が定義できるなら、そしてその切り口が現実的ならば実際に調査してもよいでしょう。しかしいたずらに「潜在バグ」という言葉のおどろおどろしさに不安になって「徹底的に潜在バグを潰す」というスローガンが生まれたとすれば、それは単なる無思考に過ぎません。
このようなバグをゴキブリに例えてみましょう。ゴキブリがいるかどうかは分かります。ゴキブリを実際に見つければいいのです。死骸でも写真でもいい。とにかくいることは分かります。目の前にゴキブリを見つけながら、いない、というのは要するにウソです。
しかし、ゴキブリがいないことはいつまでたっても分からない。確かに目の前にはいない、でも背後にいるかもしれない。物陰に潜んでいるかもしれない。気が付いていないだけかもしれない。いないことはいつまでたっても証明はできません。だとすれば「バグを0にする」などは不可能なのです。せいぜい「これまでのところゴキブリは見つかっていない」としか言うことはできない。明日ゴキブリが見つかるかもしれないのです。
人間の認識は本来有限なものです。真実はなかなか分からない。それを忘れて簡単に原理主義的な発想に陥るのは、思い上がりに過ぎません。そしてその思い上がりは大抵はよく考えられていない不安から生じるものです。そのような原理主義がプロジェクトを破壊してしまうことは、容易に想像できるのではないでしょうか。
2008年2月12日火曜日
DB2 v8.2 表スペースをDMSに変更する(4)
まだ手順が足りないようです。
というエラーが発生しています。
DB2のInfocenterによると
表がチェック・ペンディング状態にある。 表の保全性が強制されておらず、表の内容が無効である可能性があります。 従属表がチェック・ペンディング状態である場合は、チェック・ペンディング状態でない親表または基本表に対する操作も、このエラーを受け取る可能性があります。
とのことなので、チェックペンディングを解除します。
これで、SQL0668Nが出なくなりました。(それにしても自分のやっていることが分かってないのがバレバレですな)
DB2はリストアしたら'何とかペンディング'状態になるので要チェックです。(ほとんどFAQですが)
(2/13追記)
今はアーカイブロギングモードのDBでロードすると、デフォルトではバックアップペンディング状態になってバックアップが強制されるようです。
大量のデータが存在するときは要注意のようです。
参考)DB2逆引きWiki データをロードするには
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のグローバルメモリ使用率は以下の計算式で概算がでるようです。
当方の環境(icmnlsdb)で調べて見ると、以下の通りでした。
ざっくり計算すると、以下のような感じです。
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コマンドを使います。
以上です。
@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. 以下のパラメータを変更します。
c. DB2を再起動します。
手順例
ここでは、データベースへの変更が記録されたファイルをログと呼びます。
(情報やイベントやエラー情報を書き出すログではありません。)
ログには複数種類(後述)があり、ラッシュリカバリー、ロールフォワードやロールバックに使われるものです。
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に外から変数を渡す
これも基本だと思いますが、よく忘れるので・・・
です。# 方言はあるのでしょうか?AIX5.2とcygwinのGNU Awk 3.1.5で動きました。
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 を使ってみる
イベントモニター開始
※ディレクトリのパス名が間違っていると、2つ目のコマンド(3行目)でエラーが出ます。
SQLを実行します。
イベントモニター終了
イベントモニターの結果確認
※CMで実行してみましたが、コンテンツを一つ登録するのに相当SQL/ストアドプロシージャを発行しているようです。
CMの背後で実行されるSQLはほとんどブラックボックスとして捉えたほうがよさそうです。
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はほとんどブラックボックスとして捉えたほうがよさそうです。
登録:
投稿 (Atom)