2013年4月21日日曜日

libdwarfのインストール

softiesプロジェクトで使用するかは未だ決めてないが、実験のため Open Solarisに libdwarfをインストールしてみた。

ダウンロード (download)下载

David A's DWARF Pageから
libdwarf-20130207.tar.gzをダウンロードした。

ビルド (build) 构建

tarで展開し、dwarf-20130207にチェンジディレクトリして
sudo ./BLDLIBDWARF

すると自動的にビルドが始まるが、dwarfdumpをビルド中にコケてまう。

# gcc -E tag_tree.list does not work, so use a .c name
rm -f  tmp-t1.c
cp ./tag_tree.list tmp-t1.c
gcc  -g -O2 -I. -I. -I./../libdwarf -DCONFPREFIX=/usr/local/lib  -E tmp-t1.c
  > ./tmp-tag-tree-build1.tmp
./tag_tree_build -s  -i tmp-tag-tree-build1.tmp  -o tmp-tt-table.c
make: *** [tmp-tt-table.c] Segmentation Fault (core dumped)
make: *** Deleting file `tmp-tt-table.c'

欲しいのはライブラリとヘッダのみのため、libdwarfの中だけビルドする。


./configure, makeすれば良いのだが、configure時のオプションでビルドするライブラリのタイプを選択できる。

ライブラリタイプ.configureのオプション
libdwarf.aオプションなし
libdwarf.so--enable-shared --disable-nonshared
両方--enable-shared

インストール (install) 安装

make installは提供されてないので、ハンドコピーする。

ファイルインストール先ディレクトリ
libdwarf.h, dwarf.h/usr/local/include
libdwarf.a, libdwarf.so/usr/local/lib

libdwarf.hは展開したファイルには無く、configure時に libdwarf.h.inからコピーされる。

2013年4月11日木曜日

コーディング規約 その3 (code conventions 3)

コーディング規約の 3回目は、ソフトウェアメトリクスに関するものである。

我々は、2005年にはメトリクスの計測ツールを導入したが、その後、使用するツールの都合により一時的に自動的な計測を停止している。
それでも、以下に掲げる規約は有効である。

なお、これらの基準を逸脱しなければならない場合は、実験的なプロジェクトの場合を除いて社内レビューを行い、その妥当性の検証が必要となる。

関数の大きさ

1個の関数(メソッド)の大きさは、7行までが理想で、多くともこれに +2した 9行が良い。

ただし、言語によっては使用できる構文が違うため、多少差をつけることにしたい。
  • Java -- 12行
  • c++ -- 24行
  • c -- 30行
  • ほか -- T.B.D.
1980年代半ば、私が学生アルバイトをしていた会社の社長と、関数(アセンブリ言語だったのでサブルーチンと読んでいたが)を小さくすると各々は単純になるが、数が増えたり、レベルが深くなって判りにくくなることを議論した記憶がある。そのときには良い答えを見つけることはできなかった。

2000年代に入っても、プロジェクトのメンバにリファクタリングして関数を単純にしてもらえないか相談したときに、彼らから同じような答えが返ってきた。 彼もまた、解決法を見つけていないようだ。

大事なのは関数が大きくなればなるほど「関数を分けなければならないのではないか?」という疑問を持つことである。

上記の基準はちょっと厳しいと思われるかもしれないが、頭の中でトレースするのにはあまり長くないほうが良い。

ほかの考え方としては、できれば 1個の関数を読むために、左右はもちろん、上下にもスクロールしたくない。

引数の数

気軽に使ってよいのは 3個まで。
Immutableなオブジェクトをコンストラクタで全部初期化したい場合でも 7個まで。

ローカル変数の数

3個までに収めるのが理想。言語別上限はつぎの通り。
  • Java -- 5個
  • C++ -- 7個
  • C -- 7個

制御構文の深さ

if, switch-case, for, while, do, try-catchおよび、 ? : 演算子を合わせて 3レベル。

厳しいと思われるかもしれないが、これを守るとコードが読みやすくなる。

使われ方としては、
  • tryを使う場合には、中に一重のループとその中に if文が 1レベル。
  • 二次元データを扱うにはループを二重に使いたい場合があるので、そうするとあと if文が 1レベル。
  • switch-caseの中に if文があって、その中で ? : 。
なお、3レベル以内だったとしても switch-caseの中で switch-caseを使用するのは非推奨。(我々の規約では 8タブを使用するので良いが、 4タブだとどの caseがどの switchに対応するか追跡するのが面倒になり、間違いの元になる。

クラスの大きさ

メンバの変数や関数の数に制約は無いが、空行、コメントを合わせて理想は 500行まで。最大 1000行まで。

大事なことは、凝集度。

分けてはいけないものを分けると無駄な相互作用が発生し、そのためのアクセサが増えるだけでなく、そのアクセサが外部に公開されてしまうことが適切かどうかという問題が生ずる。

逆に一緒である必要のないものを1つにしてしまうと、ある部分の変更が外の部分に影響が及ばないか検証する範囲が広がり、無駄なコストが発生することである。

目覚めよ!正恩。

2013年4月9日火曜日

コーディング規約 その2 (code conventions 2)

前回に引き続き、弊社のコーディング規約を紹介する。

なお、命名規約はローカル変数やプライベートなメンバを除いて設計規約の一部として扱っているため、コーディング規約には現れない。

マクロ置換の禁止 (Prohibition of the macrosubstitution)

マクロはしばしば取り上げられるような引数評価の副作用が問題であるだけでなく、可読性を悪化させる原因にもなる。
本機約では、例外的に標準ライブラリを使用する上で必要となる最小限の使用を認めているが、それ以外の使用は原則的に禁止である。
softiesプロジェクトではこの原則を 2つ破っている。

一つは、importを実現するためのもの。

もう一つは、例外機構の try, catch, finallyである。

前者は置換のルールが単純で混乱を起こすことは少ないと思われるが、後者は危険が多い。そのため例外機構は完全な実験状態であり、ライブラリ中で使用している箇所はまだないのである。
外にも publicや privateなどの可視性を表すものなどがあるが、使用するかしないかは選択できるようになっている。


Javaではアノテーションが追加されるまではコンパイル制御機能はソースコード上に記述できなかったため、記号定数は全てクラスの定数として使用される。
問題は、 C/C++の場合である。
本規約では、記号定数は全てマクロではなく定数 (constant value)として定義しなければならない。
関数型マクロは、C++の場合テンプレートで置換することができる。
Cにはテンプレートが無いため、全て通常の関数を記述しなければならない。多態性実現のために関数型のマクロをしては成らない。
なお、C++のテンプレートもデバッグを難しくする恐れがあるため、慎重に定義しなければならない。それが難しい場合には C同様にいちいち通常の関数を記述することになる。


記号定数の置換のメリットは、単にリテラルをロジックから排除することによる可読性の向上だけでなく、使用されない定数が多くある場合には通常の定数を用いるよりもメモリ削減になる点である。
我々はそのメリットを犠牲にしても、混乱を避けることを選択した。

条件付コンパイルの禁止 (Prohibition of conditional compilation)

#if, #ifdefなどの条件付コンパイルはマクロ置換よりもさらに可読性を悪化させる。
そのため本規約では、多重インクルード防止目的のもの意外の使用は禁止である。

製品コードの中に #if 0 などが含まれるのは論外で、仮にデバッグ用に使用されたとしてもコミット時までには除去されなければならない。
コードが複数の機種や仕向けの仕様を共通で使用するためにも #ifが仕様されることがあるが、弊社では禁止である。
バージョンの切り替えも禁止である。
これらは、デザインパターンで回避するか、適切な構成管理を行うことで解決が可能である。
なお、回避、解決法は何通りかのパターンがあるため、ここでは触れないが、機会があれば紹介したい。

goto文の使用 (using goto statement)

多くの場合、可読性を低下させる。
エラーハンドリングでは gotoを使ったほうがコードがすっきりするという考え方もある。
実際、μITRONのある実装では gotoを使った場合の効果的なエラーハンドリングのコードを見たことがあるが、誰がやってもうまくいくとは限らない。特に関数の中の構造が複雑だとうまくいかない。
弊社の設立前、1990年代中ごろに筆者が携わったものの中にすさまじいコードがあった。それは国内のある会社が実装した CADDAM用のカスタムコード(プラグインソフト)が正常に動作しないため改修を請け負ったのだが、1個の switch caseが 6千行あり、そのほとんどの caseが breakではなく gotoで終わっているような代物だったのである。
goto文を breakに置き換えてみるとなんと、相対ジャンプの距離が遠すぎてコンパイルエラーになるではないか。
つまり、元の作者はそのエラーを逃れるために gotoを用いたようだ。
このような使い方をしなければならない状況と言うのは、何か怪しいのである。まず、保守不可能と言ってよいだろう。


話が遠回りしてしまったが、本規約では goto文の使用は C++では禁止。Cでは禁止しないが、限りなく非推奨に近い。


例外処理機構を有効に用いる手段ができれば、Cでも禁止することになるだろう。

do while文

do while文の使用は禁止していないが、for文、while文を優先的に使用することが推奨される。

定数との比較

定数との比較時に、誤って代入してしまうのを防止するために、しばしば比較する定数を左辺に記述する規約が存在する。
例) WRONG
    if (0 == value)
        ...

本規約では、このような書き方は禁止であり、つぎのように記述しなければならない。
例) RIGHT
    if (value == 0)
        ...

これは、valueが 0と等しいかどうかを判定したいのであり、0が valueと等しいかを判定したいのではないからである。
2000年頃に私が隣のプロジェクトのメンバとした議論の中では、前の書き方でも『0 と valueが等しいかと読めばよいだろう。』という意見がったが、比較するものの主語がどちらかを考えると 0 == valueでは不適切である。


我々の記述方法では誤って値を代入してしまうではないかと思われるかもしれないが、徹底した単体テストで補うことで解決している。
なお、Javaでは、 if (value = 0)と書いてしまってもコンパイルエラーになるため、バグになることは無い。

ブール値との比較禁止

ブール値の判定に比較演算子を用いてはならない。
たとえば、次の例は禁止である。
例) WRONG
    if (files.hasNext() == true)
        ....

この例では、==と trueの組み合わせであるからまだマシなほうで、これが !=や falseとの組み合わせであったら読み手が理解しにくい。

つぎの例のように、定数との比較を行わないことが正しい。
例) RIGHT
    if (files.hasNext())
        ...

hasNextは「次を持っている」と読めるので、何も trueと比較して等しいことを確認する必要は無いのである。
逆に言えば、関数名を付ける場合には hasXXXや isXXX、containsのように「読める」名前を使用しなければならない。

悪い関数名の代表は check()。 チェックしてどうなったら trueなのか、ドキュメントを参照しなければ理解できないだろう。

我々が使用する関数名で validate()というのがあるが、これはブール値を返すのではなく受理されない場合には例外を返すため問題ではない。

関数の途中からの脱出

原則として関数の途中脱出は禁止である。

これには幾つかの例外がある。つぎの場合の途中脱出は認められる。
  • 関数の冒頭で引数や状態異常を検出したことによる return文によるリジェクト
  • 例外がスローされる場合
このほかに exit()もあるが、正常終了であれ異常終了であれ、可能な限り関数の最後に exit()を記述しなければならない。


鳥インフルエンザが流行りそうだな。万一のときはドクターに頼んでコルドラジンをほんの数滴打ってもらうことにしよう。
Bird flu seems to be popular. Let's decide to have I ask a doctor at the time of emergency and inject just several drops of Cordrazine.

2013年4月7日日曜日

コーディング規約 その1 (code conventions 1)

弊社にはプログラミングを行う際のコーディング規約があり、Sofitiesを含めた自社プロジェクトは勿論、請負業務などで先方から指定された規約が無い限り常にこれが適用されている。

業界で一般的に推奨されているものとは異なるものや時代錯誤的なものがあり、また多少流動的でもあるが、全く合理性を欠くものではない。
幾つか紹介してみよう。

字下げは、タブ文字を使用(use tab character for indentation)

XMLには空白文字(半角スペース) 4字以下の字下げを使用することがあるが、そのほかの言語ではほぼ例外なくタブを使用する。
Digital Reserch社の CP/M 2.2時代の名残である。
当時は主記憶、外部記憶の容量が小さかったため空白文字を沢山並べるのは不経済であった。
タブ文字を使用すると多くの場合ファイルサイズが半分以下になる。
欠点としては、タブ文字と空白文字を混在させてしまうと、醜くみにくくなること。

8タブを使用(8 characters tab stop)

弊社の規約の多くが Kernighan and Ritchieの "THE C PROGRAMMING LANGUAGE"に由来しているが、これは例外の一つ。
同書では原点、共立出版による邦訳版ともに 5文字タブを使用している。
多くのテキストエディタが 4または 8文字がデフォルトであることを考えると、5文字は半端である。
4タブを使用する会社が多い中、8タブを使用する理由はつぎの通り。
8タブを使用すると、ネストを深くしたときに内容がどんどん右にいってしまう。すると4タブを使用したい誘惑に駆られるが、そうしてしまうと 1個の関数、サブルーチンが複雑になってしまう。
8タブを守らせることによって、ネストが深くなりそうなときに関数を分割する習慣が付くようになる。

1行は 80文字以下(line length limit at 80 characters)

文字端末は 80文字までしか表示できないものが多かった。
ビットマップが主流となった現在ではハード的な理由は無くなった。しかし、画面が広くなったからと言って際限なく長い行はいただけない。
目で追うときに画面の右端まで行って、つぎの行の先頭に戻るときに見失ってしまう。 況してや左右方向にスクロールさせるなどは持っての外である。
画面を左右に並べてマージ作業するときなどを考えると 80文字くらいが丁度良い。

空白のとり方(spacing)

つぎのいづれかの文字の後には原則として空白類が必要、前には置かない。 ',', '.', ';', ':', '!', '?', ')', '}', ']'
例)
    a[i] = 0;           RIGHT
    a [ i ]= 0;         WRONG


単項演算子のうち次のものの後には空白類は置かない。 '*'(C, C++), '&'(C, C++), '-', '!', '~', キャスト, 前置の '++', '--'
例)
    void *p;            RIGHT
    void * p;           WRONG

    --index             RIGHT
    -- index            WRONG

    (int)longValue      RIGHT
    (int) longValue     WRONG


後置の "++", "--"の前後には空白類は置かない。
例)
    pointer++;          RIGHT
    pointer ++ ;        WRONG


乗法演算子、加法演算子、シフト演算子、関係演算子、等値演算子、ビットごとの演算子、論理的演算子、条件演算子、代入演算子の前後には空白類が必要。
例)
    a = b + c;          RIGHT
    a=b+c;              WRONG


次の演算子の前後には空白文字は置かない。 '.', "->"(C, C++), "::"(C++) ただし、行を折り返す場合は可。
例)
    record->field1 = 0;         RIGHT
    record -> field1 = 0;       WRONG


関数の宣言、定義、呼び出し時の小括弧の前には空白は置かない。
例)
    printf("Hello.\n");         RIGHT
    printf ("Hello.\n");        WRONG


関数の宣言、定義、呼び出しの小括弧の内側には引数、パラメタをコマで区切る箇所を除いて空白は置かない。
例)
    Math.max(a, b)      RIGHT
    Math.max( a, b )    WRONG


関数呼び出しの跡の乗法演算子、加法演算子、シフト演算子、関係演算子、等値演算子、ビットごとの演算子、論理的演算子、条件演算子、代入演算子との間には空白類が必要。それ以外には置かない。
例)
    fabs(v) < 1.0               RIGHT
    fabs(v)< 1.0                WRONG

    fp = fopen("text", "r");    RIGHT
    fp = fopen("text", "r") ;   WRONG
キーワードと小括弧の間には空白文字が必要。ただし、sizeof演算子の場合は置かない。
例)
    if (true)           RIGHT
    if(true)            WRONG

    sizeof(int)         RIGHT
    sizeof (int)        WRONG
sizeof演算子は括弧つきで使用する。
例)
    sizeof(int)         RIGHT
    sizeof int          WRONG
ブロックの中括弧の前には空白が必要。
例)
    if (true) {         RIGHT
    if (true){          WRONG

中括弧の取り扱い (braces)

条件分岐や繰り返しの制御構文の中が単一の文の場合はブロックを使用しない。
例)
    if (end)            RIGHT
            exit(0);

    if (end) {          WRONG
            exit(0);
    }
業界では括弧の対応が不一致になるのを恐れて {を強制する規約が多いと思う。 しかしそれは記述が複雑だったり、ネストが深くなるからであり、シンプルに書くことを心がければ、反って不要な括弧などは付けないほうが良い。 行の折り返しが必要な場合を除いて、{の前で改行しない。
例)
    if (true) {         RIGHT

    if (ture)           WRONG
    {

    int atoi(int i) {   RIGHT

    int atoi(int i)     WRONG
    {
ブロックを使用しない制御構文であっても、条件式の行と制御される行の間は改行する。
例
    while (!end)                RIGHT
            call();

    while (!end) call(); WRONG
} と elseの間は改行しない。
例)
    if (ready) {        RIGHT
      ...
    } else {

    if (ready) {        WRONG
      ...
    }
    else {

文字コードは UTF-8 (using UTF-8)

2000年ころまでは EUC-JPを使用していたが、中国語などの日本語以外の文字を混在させようとしたときを考慮して、UTF-8に切り替えられた。
お尻かゆい虫~

2013年4月2日火曜日

パッケージ一覧

昨年末、本社から徒歩移動可能なところに開発室用のオフィスを借り、1月には主要な開発機材を移転した。

2~3月には大小併せて 340個近いプロジェクトのファイルのマージに追われた。
法人化前から作り散らかし、ディレクトリ単位でフォークが発生していたもので気の遠くなる作業だった。
ずいぶんと不精したものだ。
8"FDや QICの接続が未完の為、1998年以前のものは未だマージできていない。


分類プロジェクト数
J2ME4
J2ME/PBP3
J2ME/XLET2
J2SE1
C17
LWT57
NetBeans3
Swing51
実験段階160
自社用途6
そのほか33

LWTには組み込み Java用のサービスやライブラリ、フレームワークで、既に出荷済みの RDBや サーブレットコンテナ、状態遷移マシンなどが含まれている。

softiesプロジェクト パッケージ一覧

softiesプロジェクトもフォークしていたものが見つかったので、マージが行われた。
下記に現状のテストサマリを示す。 パスしてないテストも多い。 カバレッジレポートは示してないが、これも低い。

coreパッケージ


langパッケージ


ioパッケージ


netパッケージ


utilパッケージ


javaパッケージ


x11パッケージ



アイちゃんが逝く! そういえば長いこと日糧パン食べてないな。敷島か山崎しかないし。