2012年6月22日金曜日

Eclipse EGit によるタグの作成とプッシュ

バージョン管理システムにおけるタグとは、特定の時点でのリポジトリの状態です。一般的にソフトウェア開発ではリリースしたバージョンをタグとして保存することが多いようです。私の場合現在仕事でアジャイルで開発しており、イテレーションごとにタグを作成する方針を採っています。

Eclipse でEGitプラグインを使っていますので、タグの作成方法について書こうと思います。(使用しているのはEGit 1.3.0.201202151440-r です。)

Gitにおけるタグの種類

まず、Git のタグには3種類あります。(参考・・・Git公式サイト:2.6 Git の基本 - タグ
  • Lightweight (軽量)タグ
    特定コミットへの単なるポインタです。 
  • Annotated (注釈付き)タグ
    チェックサムが付き、タグを作成した人の名前・メールアドレス・作成日時・タグ付け時のメッセージを保持します。 
  • Signed (署名付き)タグ
    Annotated (注釈付き)タグにさらにGPG秘密鍵による署名を付与します。対応する公開鍵により検証を行うことができます。 

EGitがサポートするタグ

これらのうち、EGit でサポートされているのはAnnotated (注釈付き)タグのみです。とはいえ、公式ドキュメントでも Lightweight (軽量)タグよりもAnnotated (注釈付き)またはSigned (署名付き)タグの利用が推奨されていますし、GPGで署名を検証する必要がある場面は少ないと思いますので、Annotated (注釈付き)タグのみで十分な場合が多いでしょう。

なお、Lightweight (軽量)タグの作成は出来ませんが読み取りは可能です。Signed (署名付き)タグについてはサポート外とされています。(参考:Light-weight and Signed Tags | EGit/User Guide

タグの作成

タグを作成するにはプロジェクトを右クリック→チーム→拡張→タグ...とメニューをたどり、タグ名と注釈を入力して「OK」ボタンをクリックすればタグが作成されます。


タグを作成した後再度タグ作成のダイアログを開いてみると、作成したタグが追加されています。なお、アイコンに黄色い人のマークが付いているものが注釈付きタグ、黄色い人のマークがないものは軽量タグです。


ちなみに軽量タグが存在する理由は、もともとリポジトリをSVNサーバから移植した際に、SVNサーバ上のタグが自動的に軽量タグに変換されたからです。(前述のとおりEGit上では軽量タグを作成できません。)

タグのプッシュ

デフォルト設定ではローカルリポジトリに作成したタグはリモートにプッシュしないようになっています。これはEGitだからというわけではなくそもそもGit自体そういう仕様のようです。

設定は以下のメニューから変更します。プロジェクトを右クリック→チーム→リモート→アップストリームからプッシュ構成…(ちなみにどうでもいいですが「アップストリームからプッシュ構成…」って誤訳ですよね。正しくは「アップストリームへプッシュ構成…」だと思います。)

出てきた「プッシュ構成」ダイアログで「参照マッピング」の「編集…」ボタンをクリックします。


「Push Ref Specifications」ポップアップが出ます。「Add All Branches Spec」ボタン、「Add All Tags Spec」ボタンをクリックして設定を追加し、「完了」ボタンをクリックします。


参照仕様が追加されているのを確認し、「保管およびプッシュ」ボタンをクリックします。
これでローカルリポジトリに作成したタグがリモートにプッシュされます。

2012年6月17日日曜日

[アジャイル] 不確実性コーンのモデル式とベロシティ予測

現在仕事で担当しているプロジェクトではアジャイル開発を採用しています。

アジャイル開発では繰り返し単位であるイテレーションにおいてどのくらいの進捗があったかを表す値をベロシティと呼び、このベロシティの見積りがスケジュールを立てる、あるいは進捗の予測を立てる上で非常に重要です。

マイク・コーン著 「アジャイルな見積りと計画づくり」(安井力、角谷信太郎 翻訳) によると、ベロシティの見積りには不確実性コーンを活用できる、とあります。
(不確実性コーン自体の説明はこちら→ アジャイルな見積もりと計画づくりに学ぶ 不確実性のコーン | Act as Professional - hiroki.jp by HIROCASTER

その方法は実施したイテレーション数に基づき、ベロシティの予測値に幅を持たせるための下限係数と上限係数を不確実性コーンによって決めるというものです。具体的な数値も示されています。

実施したイテレーション数下限係数上限係数
10.601.60
20.801.25
30.851.15
4以上0.901.10
(出典:「アジャイルな見積りと計画づくり」p.194 表16.1)

例えば実施したイテレーション数が2の場合、下限係数0.80、上限係数1.25ですので、仮にベロシティの実測平均値を10とすれば、ベロシティの予測は8~12.5の範囲ということになります。

しかしイテレーション数で決めるのもいいですが、それだと全イテレーション数の違いを計算に含めることができません。例えば、実施したイテレーション数が2の場合、全体のイテレーション数が8の時は進捗率25%ですが、全体のイテレーション数が15の時は進捗率13%です。

進捗率が違えば、本来なら不確実性コーンによる下限係数と上限係数も違わなくてはなりません。そこで不確実性コーンのモデルを近似式で作って進捗率から下限係数と上限係数を計算できるようにできないか、と考えました。

というわけで作ったモデル式がこちらです。

下限係数log10(63+進捗率×937)/3
上限係数2-log10(16+進捗率×984)/3
(0 <= 進捗率 <= 1)

Excel でグラフを出すとこんな感じになります。

不確実性コーンのモデル式とグラフ
不確実性コーンのモデル式とグラフ

対数関数を選んだのは単純に不確実性コーンに合わせやすいと思ったのが理由です。

進捗率は「実施したイテレーション数/全イテレーション数」でもいいですが、「完了ストーリーポイント/全ストーリーポイント」のほうが正確だと思います。後者の方が実際の状況を表していますので。

ここで「アジャイルな見積りと計画づくり」でも指摘されているように、プロジェクトの進捗が進んでくると不確実性コーンの右の方では下限係数・上限係数共に1に近づくため、ベロシティの幅を持たせるには範囲が狭すぎるという問題があります。上限係数の方は下がっても問題ないかもしれませんが、下限係数の方を上げ過ぎるとベロシティが落ちるリスクを少なく見積もりすぎてしまうので危険です。

したがって下限係数による予測はプロジェクトの進捗にともなって実績値による指標に置き換える必要があります。「アジャイルな見積と計画づくり」ではベロシティの実績値による指標として

  • 直近8イテレーションの平均値
  • ワースト3の平均値
  • 最後のイテレーションの値

の3つを挙げています。これらのうち最初の2つが統計的意味を持つので、私は次のようにしています。

平均予測
ベロシティ
直近8イテレーションの平均値(小数点以下四捨五入)
(実施したイテレーション回数が8より少ない場合は全ての平均値)
最高予測
ベロシティ
平均予測ベロシティ×不確実性コーンの上限係数(小数点以下四捨五入)
最低予測
ベロシティ
平均予測ベロシティ×不確実性コーンの下限係数(小数点以下切り捨て)

ワースト3の平均値(小数点以下切り捨て)
のうち、値の小さい方

上記のようにすることにより、プロジェクト中盤~終盤にかけては下限係数による予測よりもワースト3平均のほうが小さくなるため、実測に基づくより安全な値を採用することができます。

2012年6月16日土曜日

Symfony1.4でログフォーマット変更方法の公式ドキュメントが間違っている件


Symfony1.4 でのログフォーマットの変更方法が書かれた公式ページは次のリンク先にあります。
http://www.symfony-project.org/gentle-introduction/1_4/ja/16-Application-Management-Tools

そこではアプリケーションの factories.yml を次のように変更すると書かれています。

all:
  logger:
    param:
      sf_file_debug:
        param:
          format:      %time% %type% [%priority%] %message%%EOL%
          time_format: %b %d %H

しかしこれをそのまま書いても効きません。正しくは、

all:
  logger:
    param:
      loggers:
        sf_file_debug:
          param:
            format:      %time% %type% [%priority%] %message%%EOL%
            time_format: %b %d %H

となります。追加した “loggers:” 以降の行のインデントは1段深くします。

以下、発見の経緯。

公式どおり設定しても効かないからおかしいと思って色々調べると、 factories.yml のペルプに行き着いて、形式の違いに気づきました。
http://www.symfony-project.org/reference/1_4/ja/05-Factories#chapter_05_logger

念のため、Symfony のパッケージ内部を覗いてデフォルト設定を確認すると、
(lib/vendor/symfony/lib/config/config/factories.yml)

all:
  logger:
    class: sfAggregateLogger
    param:
      level: debug
      loggers:
        sf_web_debug:
          class: sfWebDebugLogger
          param:
            level: debug
            condition:       %SF_WEB_DEBUG%
            xdebug_logging:  false
            web_debug_class: sfWebDebug
        sf_file_debug:
          class: sfFileLogger
          param:
            level: debug
            file: %SF_LOG_DIR%/%SF_APP%_%SF_ENVIRONMENT%.log

となっています。
なるほど確かに “loggers:” が足りない、と言うことで前述の通り設定して解決しました。

2012年6月15日金曜日

Eclipse EGit で作業ファイルの変更を個別に元に戻す方法

ファイルをいじっていて、前回コミットした状態まで戻したくなることってありますよね。

git コマンドを使う方法なら検索すると色々出てきますが、せっかく Eclipse を使っているので、ここは EGit プラグインから GUI 上で操作をしたいところ。

これが Subversion の場合だと Subversive プラグインには「ファイルを右クリック → チーム → 戻す」メニューがありましたが、EGit では「チーム」メニューにはそれらしきものがありません。

さらに検索すると、Stack Overflow で同様の質問をしている人を発見。
http://stackoverflow.com/questions/6788881/undo-single-file-local-uncommitted-change-in-egit-e-g-svn-revert
Right click on the file -> Replace With -> File in Git Index
そっちのメニューにあったのか。

Pleiades で日本語化している場合は例えばHEADに戻す場合は
ファイルを右クリック → 置換 → HEAD改訂
とやればできます。

いやはや、EGitではファイル1つのためにもハードリセットしかないのかと一瞬思いましたが、さすがにそんなことはないって話です。

2012年6月13日水曜日

Symfonyのlimeで使えるCSSセレクタのまとめ

Symfony でユニットテストやファンクショナルテストをする際、組み込みのテストフレームワークである lime を使うことが多いと思います。

しかしながら lime はネット上の情報源が少なく、特にテスト駆動開発をしようと思うと結構苦労します。結局 Symfony パッケージ内部のソースコードを見て調べることもあるでしょう。

ファンクショナルテストにはレスポンス内容を検査する sfTesterResponse::checkElement() メソッドの使用頻度が多いので、sfTesterResponse::checkElement() で使えるCSSセレクタをソースコードを見て調べてみました。対象バージョンはSymfony 1.4 です。

sfTesterResponse::checkElement() から CSSセレクタによってノードを選択する際、最終的に sfDomCssSelector::getElementsForNode() およびsfDomCssSelector::matchCustomSelector()
が呼び出されています。その中で正規表現を用いて CSSセレクタの機能を実現しているようです。

以下、ソースに記述のあったCSSセレクタを列挙します。

IDセレクタ及びクラスセレクタ

#id
指定されたIDを持つ
.class
指定されたクラスを持つ

属性セレクタ

[attr]
attr 属性を持つ
[attr=”val”]
attr 属性を持ち、値が val に一致する
[attre^=”val”]
attr 属性を持ち、値が val で始まる
[attr$=”val”]
attr 属性を持ち、値が val で終わる
[attr*=”val”]
attr 属性を持ち、値に val が含まれる
[attr~=”val”]
attr 属性を持ち、値をスペースで区切ったうちの1つに val が一致する
[attr|=”val”]
attr 属性を持ち、値が val または val- で始まる

範囲を限定するセレクタ

elem
要素セレクタ(elem 要素)
elem1 elem2
子孫セレクタ(elem1 要素の孫要素である elem2 要素)
elem1 > elem2
子セレクタ(elem1 要素の直下の子要素である elem2 要素)
element1 + element2
兄弟セレクタ(elem1 要素の直後の兄弟要素である elem2 要素)

擬似クラス

:contains(“val”)
文字列 val を含むもの
:nth-child(n)
親要素のn番目の子要素であるもの(n は 1 から始まる番号)
:first-child
親要素の最初の子要素であるもの
:last-child
親要素の最後の要素であるもの
:lt(n)
インデックス番号 n より前の要素(n は 0 から始まる番号、n 自体は含まない)
:gt(n)
インデックス番号 n より後の要素(n は 0 から始まる番号、n 自体は含まない)
:nth(n) または :eq(n)
インデックス番号 n の要素(n は 0 から始まる番号)
:odd
奇数番目の要素
:even
偶数番目の要素
:first
最初の要素
:last
最後の要素

注意点

lime の CSSセレクタには ID セレクタ及びクラスセレクタと属性セレクタを同時に使うと意図通りマッチしないというバグがあります(Symfony1.4.10で確認)。
これを回避するには、 ID 指定やクラス指定も属性セレクタと同様に [id=”foo”] や [class=”bar”] の形式にします。

例:
input#foo[checked] → 意図通りマッチしません。
input[id=”foo”][checked] → 意図通りマッチします。
input.bar[checked] → 意図通りマッチしません。
input[class=”bar”][cheched] → 意図通りマッチします。

ハマりやすいポイントだと思いますので注意してください。(私はハマりました・・・)

また、擬似クラス指定の :nth-child(n) の引数に指定できるのは整数のみです。

それから属性指定の [attr|=”val”] は本来 attr 属性の値が val そのものか、val- で始まるものを指定するはずですが、ソースコードを見る限り val で始まるものも許容しています。

参考

http://simonwillison.net/static/2003/getElementsBySelector.html
http://trac.symfony-project.org/ticket/6691

2012年6月9日土曜日

Symfony の url_for() の書き方でどれが速いか

Symfony でurl_for()やlink_to()にはいくつかの書き方がありますが、どれが一番速いのかと思っていたら公式ページに記述がありました。 なお、バージョンはSymfony 1.4 です。

速い順に、

  • url_for('ルート名', パラメータの連想配列)
    例: url_for('article_by_id', array('id' => $article->getId()))
  • url_for('@ルート名+パラメータのクエリ文字列')
    例: url_for('@article_by_id?id='.$article->getId())
  • url_for('モジュール/アクション+パラメータのクエリ文字列')
    例: url_for('article/read?id='.$article->getId())
となっているようです。

まず、モジュール/アクションの形式よりもルート名指定のほうが速いのは、リンクにマッチするルーティングルールを見つけるためにすべてのルールを探す必要がないという理由です。
さらに、パラメータをクエリ文字列ではなく連想配列で指定すれば、余分なパースが不要となり高速化できます。


参考
http://www.symfony-project.org/gentle-introduction/1_4/ja/09-Links-and-the-Routing-System#chapter_09_sub_9c0012b84a321294dad618cb44debc4004bf29c0

2012年6月8日金曜日

SVNリポジトリをGitに移行して中央リポジトリとして使う

現在関わっているプロジェクトでバージョン管理システムを Subversion から Git に移行したのでその時の手順をまとめてみました。

Subversion を移行する Git リポジトリは中央リポジトリとしてSSH経由でアクセスするものとし、develpoers グループに所属するユーザにアクセスを許可することにします。

また、Subversion との併用ではなく、Subversion リポジトリは残すものの基本的には Git メインで使っていくことを想定しています。

まず、Git リポジトリ用のディレクトリを作成します。
# mkdir /var/git
# cd /var/git
# mkdir repos-name.git
Git リポジトリを初期化する前に、 ディレクトリの所有者を共有用グループに変更し、グループ書き込み権限を与えます。
# chown root:developers repos-name.git
オプションに --bare と --shared=group を指定して Git リポジトリを初期化します。
# cd repos-name.git# git init --bare --shared=group
ここで作るリポジトリは中央リポジトリとして使うので、作業ファイルは不要なため --bare オプションを指定しています。また、 --shared=group オプションを指定すると、 グループでの共有に適した権限を付与してくれます。(グループ書き込み権限やディレクトリのsetgidなど。)

データを実際に移行する前に、設定ファイルを編集します。先ほどの初期化コマンドでディレクトリ内に config という名前で設定ファイルが生成されています。
# vi config

[core]
repositoryformatversion = 0
filemode = true
bare = true
sharedrepository = 1
[receive]
denyNonFastforwards = true
[svn-remote "svn"]
url = http://example.com/svn/repos-name
fetch = trunk:refs/heads/master
branches = branches/*:refs/heads/*
tags = tags/*:refs/tags/*
追加したのは赤字で示した部分です。

さらに、コミット履歴のユーザ情報を名前+メールアドレスに変換するためのファイルを用意します。
# vi ../users.txt

username = Mail Address <mail.address@example.com>
nanashi = Gonbe Nanashi <gonbe.nanashi@example.com>
ここまでできたら、あとは Subversion リポジトリからデータを取得して完了です。
# git --bare svn fetch -A ../users.txt
これでコミット履歴も含めて Git リポジトリにデータを引き継ぐことができます。


参考にしたサイト
http://blog.practical-scheme.net/shiro?20110226-sourceforge-git-migration
http://jarp.does.notwork.org/diary/200902b.html#20090213