windowsユーザのためのcvs入門

CVSとは

はじめに

オープンソースのプロジェクトはlinuxだけでなくたくさんあります。 そして、ほとんどのプロジェクトで、顔も知らないメンバー同士がインターネットで共同作業をしています。 それを可能とするのがCVSです。

CVSの最も基本的な機能は、ソースプログラムの変更履歴を記録することです。 つまり、ソースを昨日の状態や1ヶ月前の状態に戻すことができるのです。 他にもいろいろな機能がありますが、とりあえず、 この機能だけ使っていても、何か問題があった場合、 問題がない時点までさかのぼって解決する手段をとることができるわけです。

CVSはルーツがunix系でありコマンドラインベースのソフトですから、 ふだんWindowsを使っている開発者には、あまりなじみがないと思います。 しかし、現在はGUIのWindows版クライアントがありますから、 linux(UNIX系OS)の知識がなくても使えるツールです。 このドキュメントは、それをサポートするものです。

このドキュメントの前提条件

多くのオープンソースソフトウエアと同様に、 CVSもユーザ(=開発者)の要望でかなり進化を遂げたソフトです。 特に、対象プロジェクトが相当大きなプロジェクトで、たくさんの人が参加する 場合に便利な機能が多く含まれています。 一般的に、こういうものを覚えるには必要最小限のことからスタートして、 実地に使いながら必要に応じて少しずつ機能を覚えていくのがコツです。

ここでは、次のような前提条件でどうしても必要となる機能についてだけ説明し ていきます。

なお、CVSの実行形態としては、クライアントサーバ方式でリポジトリをサーバ が管理する方法と、サーバなしでクライアントが直接リポジトリを更新する方法 があります。 ここでは、windowsマシンで使いやすい(けどちょっと設定はめんどうな)クライアントサーバ方式のみを対象にします。

CVSの構成


サーバ  ←TCP/IP→ クライアント
  ↑                 ↑
  ↓                 ↓
リポジトリ         作業用コピー  ← 開発作業

CVSでは、全てのソースはリポジトリと呼ばれる一種のデータベースに格納され ます。 そして、クライアントはサーバを通してリポジトリにアクセスします。 クライアントとサーバ間はTCP/IP上の独自プロトコルで通信します。

開発作業(ソースの作成、コンパイル、テストなど)は、 リポジトリでなく、作業用コピーに対して行ないます。 リポジトリを直接修正することはなく、必ず作業用コピーに対して修正を行ない、 必要に応じてその作業用コピーに対する変更をリポジトリの反映するコマンドを 実行します。

サーバ側のソフトは、linuxを含むほとんどのUNIX系OSで稼働します。 windows用のCVSサーバもでてきたようですが、まだあまり一般的でないので、こ こではlinux用で説明します。

クライアント側のソフトは、各種UNIXはもちろん、windowsでも動作します。 また、GUIで簡単に使用できるクライアントソフトもいろいろあるようです。

CVSのリポジトリは、特殊なバイナリ形式でなく、人間が読むことのできるテキストファイルを使っています。 つまり簡単に見えるものなので、必要に応じて、各種管理ファイルを覗いてみてください。 理解が深まると思います。

リポジトリの形式は簡単に言うと、 最新バージョン+過去へさかのぼるための差分です。 つまり、過去の任意の時点のソースを復元できるわけです。

CVSのコマンド

cvsのコマンドは全て「CVS なんとか」というかたちになっています。 非常にたくさんのコマンドがあり、オプションもいろいろありますが、 もちろん、最初から全てを理解する必要はありません。

作業コピーを更新するコマンド

リポジトリから、情報を引き出し、手元のファイルを更新するコマンドは以下のとおりです。

コマンド名 処理内容
checkout 新規に作業コピーを作成する
update 作業コピーを最新の状態にする
export 管理ファイル抜きの作業コピーを作成する

リポジトリを更新するコマンド

作業コピーなどから、リポジトリを更新するコマンドは以下のとおりです。

コマンド名 処理内容
import リポジトリ内に、新しいプロジェクトを作成する
commit 作業コピーに対して行なった修正をリポジトリに反映させる
add リポジトリ内のプロジェクトにファイルを追加する(実際の更新はcommit時)
remove リポジトリ内のプロジェクトからファイルを削除する(実際の更新はcommit時)

リポジトリの状態を表示するコマンド

リポジトリの状態を表示するコマンドは以下のとおりです。

コマンド名 処理内容
status リポジトリと作業コピーの更新状態を表示する
log リポジトリの更新履歴を表示する
diff リポジトリと作業コピーの差分を表示する
annotate ソースの行ごとに、この行は誰がいつ更新したものかを表示する。

annotateは以下のような情報を表示してくれます。

1.1          (chang    19-Jul-00): #include 
1.1          (chang    19-Jul-00): 
1.3          (mkoba    19-Jul-00): /*------------------------------------------*/
1.1          (chang    19-Jul-00): int main(int argc, char** argv)
1.1          (chang    19-Jul-00): {
1.1          (chang    19-Jul-00):    int i ;
1.1          (chang    19-Jul-00):    int sum = 0 ;
1.8          (mkoba    20-Jul-00):    int gusu = 0 ;
1.7          (chang    20-Jul-00):    int kisu = 0 ;
1.8          (mkoba    20-Jul-00): 
1.1          (chang    19-Jul-00):    for(i=0 ;i < 10 ; i++) {
1.1          (chang    19-Jul-00):       sum += i;
1.8          (mkoba    20-Jul-00):       if ((i%2) == 0)
1.8          (mkoba    20-Jul-00): 	gusu += i ;
1.8          (mkoba    20-Jul-00):       else
1.7          (chang    20-Jul-00):         kisu += i ;
1.1          (chang    19-Jul-00):    }
1.8          (mkoba    20-Jul-00):    printf("total=%d kisu=%d gusu=%d\n", sum, kisu, gusu) ;
1.9          (chang    20-Jul-00): 
1.9          (chang    20-Jul-00):    printf ("\n") ;
1.9          (chang    20-Jul-00): 
1.1          (chang    19-Jul-00): }

実際の使用方法(一般メンバー)

ここでは、既にサーバの設定とプロジェクトのimportが終わっていることを前提 として、 一般のメンバーのすることをまとめました。

WINCVSのダウンロード、インストール

http://www-vox.dj.kit.ac.jp/nishi/cvs/cvs.html を参照して、windows用のCVS(WINCVS)とSJIS対応バージョンをダウン ロードします。

そして、wincvsをダブルクリックして、インストールしてください。 インストールが終わったら、wincvs.exeをSJIS対応バージョンの同名のファイル と入れかえます。

リポジトリの設定とログイン

WINCVSを起動すると、最初に "WinCvs Preferences"という画面が出 ます。ここでは以下の項目を設定します。

General->"Enter the CVSROOT"
 :pserver:mochan@192.168.1.1:/home/cvs/root

192.168.1.1はCVSサーバのアドレスになります。 mochanはそこに設定してあるユーザ名です。 /home/cvs/rootはリポジトリのパスです。 これらの情報は管理者に問合せてください。

General->Authentication(選択)
 "passwd" file on the cvs server

WinCvs->HOME folder
 適当な書きこみ可能なディレクトリ
 (次の操作で入力するパスワードを記録するディレクトリになる)

ここでログインという操作を行ないます。 つまり、メニューから Cvs Admin->Loginを実行してパスワードを入力します。

CVSのログインはtelnetやftpと違って、その場限りのものではなく、 特別の操作を行なわない限り、ずっと有効になります。 つまり、上記のHOME folderで設定したディレクトリに、 パスワードが記録され、この後はずっとこのパスワードが自動的に使用されます。

チェックアウト(サーバから最新ソースをひっぱりだす)

Cvs Admin->Checkout modules..を実行して、ソースを展開するディ レクトリを指定します。すると"Checkout settings"という画面が出 るので、 「Enter the module name and path on the server」という所にプロジェクト名 を入力してOKをクリックします。

ソースの修正、追加

ここまでの操作で、作業コピーが作られているはずです。 ここからは、普通どおりローカルで作業を行ないます。 もし、新規のソースを追加する場合は、 そのディレクトリにソースをコピーしてから、 Cvs Files→add filesを行ないます。

リポジトリへの書き戻し

ひととおりの作業を終えたら、commitの操作を行ないます。 Cvs folders→commit foldersです。

もし、ここであなたが修正したファイルを他の人が同時に修正していると conflictというエラーが発生します。 この場合は、次節で述べる操作を行なって、あなたの修正と他の人の修正をマー ジしてください。

conflictの解消

conflictは、厳密に管理されているプロジェクトでは発生するはずがないことで すが、現実的には発生することがなかなか避けられません。RCSなど他のバージョ ン管理システムでは、修正する前に対象のファイルをロックし、終わったらアン ロックするようにして、conflictが発生しないような管理をしていますが、 これはこれで非常にめんどうなものです。

CVSがここまで広く普及した理由のひとつは、このconflictという問題に対して 非常に現実的な解決策を持っているからです。 すなわち、conflictが起きるのはしょうがないものとして、同時に行なわれたふ たつの修正をマージする作業を便利にしようとしているのです。

ここでは、次のようなソースを例にして、どのようにconflictが発生し、どのよ うに解消されていくかを述べることにします。

#include 

/*------------------------------------------*/
int main(int argc, char** argv)
{
   int i ;
   int sum = 0 ;

   for(i=0 ;i < 10 ; i++) {
      sum += i;
   }
   printf("total=%d\n", sum) ;
}

conflictの発生

上記の例題ソースに対して、AさんはユーザのXさんから「単に1〜10までの総和でなくて、その中の 奇数だけの和も計算してほしい」という依頼を受けました。 そこで、上記のソースを自分のノートパソコンにcheckoutして修正作業を開始しました。

ところが、この作業は予想以上に難しいので、 Aさんは、自宅に持ちかえって作業をすることにしました。

Aさんが帰宅してまもなく、ユーザのYさんから電話があり、Aさんがいないので かわりにBさんが電話を受けました。 Yさんは「明日の朝までに、1〜10までの偶数の和を計算できるように修正してほしい」と 言いました。 そこで、Bさんはすぐにそのソースをcheckoutして、徹夜で作業を行ないました。

#include 

/*------------------------------------------*/
int main(int argc, char** argv)
{
   int i ;
   int sum = 0 ;
   int gusu = 0 ;

   for(i=0 ;i < 10 ; i++) {
      sum += i;
      if ((i%2) == 0)
        gusu += i ;
   }
   printf("total=%d gusu=%d\n", sum, gusu) ;
}

そして、この修正をcommitして帰宅しました。

次の日の朝、Aさんが出社して、自宅で作業した次のソースをcommitしようとしました。

#include 

/*------------------------------------------*/
int main(int argc, char** argv)
{
   int i ;
   int sum = 0 ;
   int kisu = 0 ;

   for(i=0 ;i < 10 ; i++) {
      sum += i;
      if ((i%2) != 0)
        kisu += i ;
   }
   printf("total=%d kisu=%d\n", sum, kisu) ;
}

すると、conflictというエラーが発生しました。 そこで、Aさんはcvs logで調べてみると、なんとBさんがゆうべのうちにこのソー スを修正しているではないですか。 logには「顧客のYさんの依頼により偶数計算機能追加」と書いてあります。 それで、Xさんに電話してみると、昨日Yさんが偶数計算の機能を要望したことがわかりました。 そして、結論として両方計算してほしいとのことです。 それで原因と対策はわかりましたが、Aさんは自分の作業を捨てて、 この修正に奇数計算を追加する必要があるのでしょうか?

conflictの解消

こういう時は、あわてず騷がずとりあえずupdateを行ないます。 そうすると、問題のソースは次のようになります。


#include 

/*------------------------------------------*/
int main(int argc, char** argv)
{
   int i ;
   int sum = 0 ;
<<<<<<< cvstest1.c
   int gusu = 0 ;
   
=======
   int kisu = 0 ;
>>>>>>> 1.11
   for(i=0 ;i < 10 ; i++) {
      sum += i;
<<<<<<< cvstest1.c
      if ((i%2) == 0)
	gusu += i ;
=======
      if ((d%2)!=0)
	kisu += i ;
>>>>>>> 1.11
   }
<<<<<<< cvstest1.c
   printf("total=%d gusu=%d\n", sum, gusu) ;
=======
   printf("total=%d kisu=%d\n", sum, kisu) ;
>>>>>>> 1.11
}

つまり、両方のソースを機械的にマージしてくれるのです。 ここから、作業をはじめれば、簡単にモレなく両方の機能を持ったソースを作成 することができます。 このケースだと、衝突しているのは3個所ですが、最初の2つはcvsが入れた <<<<<とかいう行を削除するだけで、そのまま使えるものになります。


#include 

/*------------------------------------------*/
int main(int argc, char** argv)
{
   int i ;
   int sum = 0 ;
   int gusu = 0 ;
   int kisu = 0 ;

   for(i=0 ;i < 10 ; i++) {
      sum += i;

      if ((i%2) == 0)
	gusu += i ;
      if ((d%2)!=0)
	kisu += i ;
   }
<<<<<<< cvstest1.c
   printf("total=%d gusu=%d\n", sum, gusu) ;
=======
   printf("total=%d kisu=%d\n", sum, kisu) ;
>>>>>>> 1.11
}

つまり、conflictと言っても、両者が別々の行に対して作業している場合は、ほ とんど機械的にマージしてくれるのです。 もちろん、最後の表示の行のように、同じ行を同時にいじった場合は手作業が必 要ですが、両方を見くらべながら作業することができます。 それから、2つのif文は、ひとつにマージできますので、これも手作業でいっしょにやっておきましょう。


#include 

/*------------------------------------------*/
int main(int argc, char** argv)
{
   int i ;
   int sum = 0 ;
   int gusu = 0 ;
   int kisu = 0 ;

   for(i=0 ;i < 10 ; i++) {
      sum += i;

      if ((i%2) == 0)
	gusu += i ;
      else
	kisu += i ;
   }
   printf("total=%d gusu=%d kisu=%d\n", sum, gusu, kisu) ;
}

これで修正完了ですメデタシメデタシ。

その他のCVSの機能

タグ

CVSでは、チェックアウトの時に日付を指定することで、最新バージョンでない 過去のソースを一式引っぱりだすことができます。 しかし「結合テスト完了時点のソースを見たい」と言った場合には、 いちいちそのイベントの日付を確認しなくてはいけないし、 日付単位でなく「出荷した瞬間のソース」が見たいということもあります。

そのために、CVSではタグという機能があって、 イベントがあった時点にラベルをはることができます。 ラベルはrelease_1_0のような英数字ですが、 ピリオドを含むことはできません。

ブランチ

よくあるケースとして、次のようなパターンがあります。

  1. 機能を限定してV1.0リリース
  2. すぐにV2.0の開発にかかる
  3. V2.0の機能のために、一部の設計変更が必要と判明
  4. そのプログラミング作業をはじめた所で、V1.0のバグが判明
  5. V1.0のソースに対してバグ修正を加える
  6. V2.0の開発を継続するが、このバグの修正を含めるのを忘れた
  7. V2.0のリリース時に、直したはずのバグが復活してしまう

このように、一度直したバグが復活してしまうのは、 新しいバグが増えるよりカッコ悪く、 場合によっては、顧客の信頼を失なっていまいます。

CVSでは、ブランチという機能があって、上記のような場合、 V1.0に対する修正はブランチとして行ないます。 ブランチを分割している間は、両者は独立のプロジェクトのように 別個に作業することができます。 つまり、バグの修正中や確認中も並行してV2.0の作業ができます。

そして、V1.0のバグ修正が終了した時点で、ブランチのマージを行なうことができます。 この場合も、confilictのマージとほぼ同じ操作で、別の枝で行なった作業を、 本流に含めることができるわけです。

emacsのpcl-cvs

emacsには、pcl-cvsというパッケージがあって、 各種操作を対話的に行なうことができます。 特に、マージの操作を対話的に行なうemergeという機能は 一見の価値があります。

CVSの設定

linuxとCVSのインストール

まずは、回りで一番遅いマシンを選んでlinuxをインストールしましょう。 これをcvsサーバにします。 ついでに、linux勉強のマシンにしてlinuxも勉強しましょう。 私のおすすめはKondara MNU/Linuxですが、Redhat系のlinuxなら、 ほぼ、ここに書いた手順でセットアップできると思います。

インストールの選択肢は、全部既定値でタイプはサーバとしてインストールします。 そして、下記のようなコマンドでcvsがインストールされているか確認します。

$ rpm -qa |grep cvs
cvs-1.10.8-1k1

もしこのようなパッケージ名が表示されなかったら、 linuxのCD-ROMから、以下のようにCVSをインストールします。

# mount /mnt/cdrom
# cd /mnt/cdrom/Kondara/RPMS
# rpm -ivh cvs-1.10.8-1k1.i386.rpm

リポジトリの作成

CVS管理のためのユーザを作成します。

# adduser cvs
# passwd cvs
(パスワード入力)

そして、このCVSというユーザでログインしなおして、 以下のコマンドでリポジトリを作成します。

$ cvs -d /home/cvs/root init

CVSサーバの設定

通常は、CVSサーバはtelnetやftpと同様、 inetというデーモンから起動されます。 そのinetdの設定のためには、rootになって/etc/inetd.confに以下の行を追加します。

#       
cvspserver       stream      tcp     nowait  root   /usr/bin/cvs  cvs --allow-root=/home/cvs/root pserver

そして、inetdを再起動します。

# /etc/rc.d/init.d/inet restart

ユーザの登録

CVSを使用できるのは、次の2種類のユーザです。

  1. そのマシンにアカウントを持っていて、リポジトリを読み書きできるユーザ
  2. マシン(OS)上のアカウントと関係なく、 CVS内部だけで登録したユーザ

    前者は、リポジトリを複数のユーザに読み書きすることが(素人には)面倒です。 そこで、ここでは後者の方法を説明します。 この場合は、まず以下のスクリプトをテキストファイルで保存してください。

    #!/usr/bin/perl -w
    #
    # usage: cvsadduser >> $CVSROOT/CVSROOT/passwd
    #
    use strict;
    
    main();
    
    sub main () {
        srand(time() ^ ($$ << 15));
    
        print STDERR "cvs account: ";
        my $cvs_account = ;
        chomp $cvs_account;
    
        print STDERR "password: ";
        system "stty -echo";
        my $passwd = ;
        system "stty echo";
        chomp $passwd;
        print STDERR "\n";
    
        print STDERR "Re-enter password: ";
        system "stty -echo";
        my $tmp_passwd = ;
        system "stty echo";
        chomp $tmp_passwd;
        print STDERR "\n";
    
        unless ($passwd eq $tmp_passwd) {
            print STDERR "ERROR! They don't match.\n";
            exit 1;
        }
    
        print STDERR "real account (can be omitted): ";
        my $real_account = ;
        chomp $real_account;
    
        my $salt = draw_salt();
        my $encoded_passwd = crypt($passwd, $salt);
    
        print "$cvs_account:$encoded_passwd";
        print ":$real_account" unless $real_account eq "";
        print "\n";
    }
    
    sub draw_salt () {
        my $salt_chars =
            'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./';
    
        my $idx1 = int(rand() * length($salt_chars));
        my $idx2 = int(rand() * length($salt_chars));
    
        my $chr1 = substr($salt_chars, $idx1, 1);
        my $chr2 = substr($salt_chars, $idx2, 1);
    
        return ($chr1 . $chr2);
    }
    
    

    このスクリプトの内容は理解する必要はありません。 CVSのユーザ登録は /home/cvs/root/CVSROOT/passwd というファイルに特殊な方法で記述するのですが、 このスクリプトは、このファイルの作成を助けてくれるものです。 次のように実行してください。

    [cvs@ryoma cvs]$ perl cvsadduser
    cvs account: chang
    password: changpass
    Re-enter password: changpass
    
    real account (can be omitted): cvs
    cvs
    chang:kids2m/PKmbsE:cvs
    

    最後の項目は、実際に処理を実行する時のユーザIDですが、 ここでは専用のアカウントを作ってますから、 cvsと入力してください。

    そして、最後に表示された行を、 そのまま/home/cvs/root/CVSROOT/passwdに追加します。

    インポート

    ここまで来たら、実際のソースをディレクトリ(プロジェクト)単位で登録(import)できます。 importする前には、プロジェクト全体のディレクトリ構造をよく検討します。 ファイルの追加や削除は簡単ですが、 下位のディレクトリ構造の変更があると、 操作もめんどうだし、 CVS上では別のファイルとして管理されてしまうので、 統一した管理ができません。

    ディレクトリ構造が決まったら、下記のようにimportします。

    $ cvs -d ":pserver:chang@ryoma:/home/cvs/root" login
    cvs -d ":pserver:chang@ryoma:/home/cvs/root" login
    (Logging in to chang@ryoma)
    CVS password: changpass
    $ cvs -d ":pserver:chang@ryoma:/home/cvs/root" import -m "CVS TEST START" cvstest brain start_of_cvstest
    

    最後の2つ(ベンダータグとリリースタグは、ほとんどの場合意味がない(使用しない)ので、適当でいいです。

    バックアップ

    リポジトリ(上記の例では/home/cvs/root)以下のファイルは必ず別のマシンにバックアップをとってください。 CVSさえあれば、相当ひどいトラブルでも復旧できますが、当然ですけどリポジトリを失なったら手も足もでません。 リポジトリは普通のプログラムソースより重要なものです。 できれば、複数の方式で複数の媒体またはマシンにバックアップをとってください。

    CVSとオープンソースとXP

    従来のウォーターフォールという開発モデルは、 業務としては給料計算、言語としてはCOBOLやアセンブラ、 開発ツールとしてはパンチカードによるバッチ処理の時代に基本的な概念が作られています。 当然ながら、現在のソフトウエア開発にはなじまない部分が多くあります。

    一方、オープンソースソフトウエアの多くはプログラマの日常の業務を効率化するために開発されたものです。 プログラミングというのは、高度に知的な作業で最も不定形な業務のひとつです。 現在のソフトウエア開発も高度な知的作業を支援するものが多く、 オープンソースと通じる点が多くあります。

    そのため、CVSのようなツールだけでなく、 開発方法論としても、オープンソースの中には参考になる所がたくさんあります。 ただし、オープンソースのプロジェクトはボランティアベースで極端に言うと趣味の延長からスタートしていますので、 意識的にきちんとした方法論を持って運営しているものは少く、 そのエッセンスを抽出するのは難しい面もあります。

    XPは、成立ちはオープンソースと関係ありませんが、 変化の激しい業務におけるソフトウエア開発にとって理想的な方法論をめざすうちに、 意識的か無意識的かオープンソースのエッセンスのようなものを含んでいます。

    これは、全くの私見ですが、 このような経緯のため、 CVSを活用するためにXPという開発方法論が適用できるような気がします。 つまり、CVS+XPで、 ダイナミックな開発を管理するのに適した開発手法が、 非常に手軽に導入できると私は思うのです。

    XPのエッセンスは「テスト主導デザイン」という手法です。 簡単に言うと、詳細設計のフェーズで設計ドキュメントを書かないで、 そのプログラムのテストルーチンを先に書いてしまうのです。 そして、そのテストルーチンの中身(=実際のプログラム)を埋めていくことがプログラミングとなるわけです。

    そして、この時にテストルーチンは、全てが自動実行されるものである必要があります。 つまり、テストデータ等は全てプログラムの中に含まれていて、 オペレータが入力する必要はないようにします。 この完全自動化テストルーチンを毎日毎日、何回でも実行しながら開発をすすめます。 このようにしておくと、開発したものは常にテスト済のプログラムになります。 つまり、品質保証という作業が不要になってしまうわけです。

    これが有効なのは、非常に変化が激しいプロジェクトです。 つまり、仕様変更が多いプロジェクトです。 現在は、給料計算や銀行のATMのように、業務内容が事前にきちっと記述できるような業務は、 ほとんどコンピュータ化されています。 従って、今後発生する開発作業は、自然と不定形の複雑な作業になり、 エンドユーザにも仕様が確定できない、つまり、 実際に動かしてみてから「ああでもないこうでもない」といじることになります。 ウォータフォールの時代には、こういうのは例外的な事態でありプロジェクト管理の失敗でもあったわけですが、 現在は、日常的な風景であるとも言えます。 従って、XP+CVSはこのような時代の要請に適合した方法論だと思います。

    この「完全自動化テストルーチン」とCVSが用意されていると、 非常に短いサイクルで少しずつ機能を追加しながら目標に近づくことができます。 つまり、設計、開発、テストを2〜3週間で繰り返しながら、 目標とする機能に到達したら開発完了となるわけです。

    このようなスパイラルモデルの障害となることのひとつは、 バグ修正と機能追加が並行して進むことです。 そのため、複数の作業が同時に行なわれてconflictが発生してしまうわけです。 CVSがあると、このようなことが機械的に管理できるし、 conflictが発生してもすぐに修復できます。

    そして、もうひとつの問題は、新規開発の中に細い修正が多く発生するので ソースがつぎはぎ状態となり、無駄が多く保守しずらいソースとなることです。 XPでは、これに対してリファクタリングという手法で対応します。

    リファクタリングとは、 プログラムの機能(メインとなるモジュールの入出力)を固定したまま、 ソースのぜい肉を取る工程です。 プログラムの修正は、常にバグを作りこむ可能性をはらんでいるため、 従来は、テストが終わったソースをいじるなどという行為は問題外でした。 そのため、最初のうちにちゃんとしたソースを書くように務め、 事前に仕様をドキュメント化して原則として変更を許さないことが要求されます。 しかし、繰り返しになりますが、 現在の業務ではこういうことは現実的に不可能なので、 結局、アンフォーマル、イリーガルな変更をどこかにもぐりこませる必要がでてきて、 いろいろな歪みがたまってきて、プロジェクトが破綻するわけです。

    しかし、完全自動化テストルーチンが作ってあれば、 こういう作業も安全に進めることができます。 修正するたびに、テストを行ない、修正前と同じ動きをすることを確認しながら、 作業を進めるわけです。

    また、オブジェクト指向言語では、 言語の記述能力が高いので、このようなリファクタリングという作業をすすめることの意味が非常に大きいのです。 XPでは、「WHYのコメントは書くが、whatやhowはコメントを書かない」というルールもあります。 whatはメソッド名(関数名)で表現できるし、howはコードそのもので表現できる、という意味です。 もし、表現できないとしたら、設計かコーディングに問題があるから、その問題を直すべきであり、 問題を放置したままコメントでごまかすのは、本末転倒だ、という考え方です。

    このようにリファクタリングというのは充分理にかなった手法ですが、 CVSの元で行なうと、リーダや経験のあるプログラマが、 他のメンバーの作業を監視したりサポートすることが容易であり、より安全に進めることが可能です。 cvs logやcvs diffで作業の状況をトレースできるし、 おかしい所は問答無用で直してしまえばいいのです。 直す時に、どこがおかしくて何故直すのかをログとして記録しておけば、 直された人もそれをすぐ確認できるし、 万が一、間違っていてもすぐに戻せるわけですから。

    CVSは単にツールとして導入しても充分効果を得ることは可能ですが、 オープンソースの開発手法やXPを段階的に取りこむための媒体としても活用できます。

    line