コードを短くすると単体テストが楽になる、の証明

感覚的には、コードを短くすると、単体テストが楽になり、結果的に品質があがり、最終的にはプロジェクトの成功率が上がる、ことは理解っているのだけど、人に説明すると、どうも「納得いか~ん」方が居られるので、ちょっと論理的に証明などしてみます。

# 実は、証明するよりも、「人は理解したいものを、理解する」という訳で、ロジックで説明しても無駄なことが多いんですけどね。ま、自分を納得させるためにも必要ということで。

■現状分析

ソフトウェア開発において、ステップ数でプロジェクト規模換算をしようとすると、請負側からすれば規模を大きく見せる≒プロジェクトを擬似的に大きく見せる、ためにステップ数を「実効数」よりも増やすという現象があります。
また、プロジェクトが終わった段階で、ステップ数が多いということが、イコール「たくさん仕事をした」ということで、報酬が多くなるという現象もあるわけです。

なので、ステップ数を減らすと、「仕事量が少ない」ゆえに「報酬が少なくなる」ということに成りかねないので、この話は、

・自社で、パッケージアプリケーションを開発する。
・プロジェクトの成否が、自社の報酬に影響する。

時に使ってください。

# F# などの関数言語を使ってみると、短く書く≒簡素に書くことの重要性がわかるのですが、全てのプログラマが関数言語を使ってみるというのも難しい話なので。

■背理法で証明する

厳密に言えば、最初は詭弁的な方法で論証してみます(笑)。手っ取り早いので。

1.ステップ数が多いコードがある。
2.ステップ単位で予想されるバグ件数は決まっている(品質上)
3.ゆえに、バグ件数は、ステップ数の比例する。

バグ件数 = ステップ数 × 予想バグ比率

ということで、ステップ数を増えれば、バグ件数が増える。
なので、バグ件数を減らすためには、ステップ数を減らせばよい。

証明おわり。

…っての考えたのですが、論理的に間違っているので「証明」にはなりません。「説得」にはなるけど。

weak point は、
・予想バグ比率は、一定とは限らない。
 → 例えば、自動生成されるコードは、バグを一切含まない。
・予想バグ比率は、実際は人依存である。
 → 例えば、ベテランと新人では、予想バグ比率が異なる。
・バグ件数が、そのままプロジェクトの負荷になるわけではない。
 → 例えば、細かいバグと重大バグでは、1件の重みが異なる。
 → システム試験などで見つかる(あるいは見つからない)潜在バグのほうが、プロジェクトの負荷となる。
のように続々とでてきます。

まぁ、これらの反論が、コード数を減らそうとはしない、という人の動きになるのですが。

経済心理学的に、ステップ数を減らすと短期的にコストが減る、という幻想を生み出しておくのと、現実にプロジェクトのコストが減る、という現実を作らないと駄目なのです。

■in/out を明確にして DFD 風に証明する。

ソフトウェア開発のプロジェクトの肝は、情報量を如何にして制御するか、です。
「情報量」ってのは、

・要件定義の工程で確定した契約 だったり
・アプリケーションの機能数 だったり
・Web アプリケーションのページ数 だったり

するわけですが、まぁ、一般的に「作る量」ってやつです。

# 「情報量」については、後に正確に定義しないと駄目だなぁと思っています。
# DFD を使うか、IDEF0 を使うか、そのあたりを制御しないと PERT 図に落とせないので。

ソフトウェア開発での作業量というのは、以下の法則があります。

・人が作成する量があれば、単純に時間がかかる。
 → 単純に人件費が、という話です。
 → なので自動化されるもの(自動化されたドキュメント、自動生成されたコード)は、作業量に含みません。
・人が作成するものが複雑であれば、単純に時間がかかる。
 → 同様に、頭を使う時間が必要ということです。
 → 複雑怪奇なコードでも、自動生成されたり、ライブラリでモジュール化されているものは、人に対しては「複雑」とは言いませんね。
・人とのコミュニケーションが発生すれば、時間がかかる。
 → 顧客との問い合わせ、遠隔地での電話会議、ひとりではなく複数名で作る場合などです。
 → いわゆるコミュニケーション・コストです。

さて、これを前提にすると、

コードの量が少ない場合、その状態として次が考えられます。

・コードをタイピングする時間が少ない
 → IDE などでインテリセンスを利用するとタイピングが減りますが、先の条件で「自動化」の部分にあてはまります。
 → コピー&ペーストも、タイピングを少なくする手段のひとつです。
・コードを簡素にする
 → 複雑なものよりも、簡単なもののほうが、時間が少なく書ける。
・ひとつのコードを、ひとりが扱う
 → ひとつのコードを複数名でやり取りするよりも、ひとりで完成させたほうがコミュニケーションコストは下がります。

これを因果関係で直すと、

1.コードのタイピングを減らす → 作業量が減る。
2.コードを簡素にする → 作業量が減る。
3.コードをひとりが扱う → 作業量が減る。

のいずれかのパターンになります。
つまりは、いずれかのパターンを取ると「作業量が減る」という結果が得られます。

# ちなみ言うと、「コードのタイピングを増やす」→「作業量が減る」という論理も正しいのです。
# こちらのほうは証明しません。命題は「確実に作業量が減る方法は?」なので。

この中で、1.のコードのタイピングを減らす方法で作業量を考えると、

1.コードのタイピングを減らす → 作業量が減る。
2.作業量が減る → コード量が減る。
3.コード量が減る → バグ混入率が同じであれば、バグの発生数が減る。
4.バグの発生数が減る → バグの難易度が同じであれば、不具合を直す総時間は減る。
5.不具合を直す時間が減る → アプリケーションの完成が早くなる

ゆえに、ひとつのアプリケーションを扱ったときは、コードのタイピングを減らせば、バグの発生数が減り、アプリケーションが早く完成するということになります。

ただし、これには仮説が入っています。

・バグの混入率が同じであること。
・バグの難易度が同じであること。

ですね。これはどうなのでしょうか?

例えば、perl のようなワンライナーの場合は、バグの混入率は違いますよね。また、難易度も違います。
このバグの混入率、難易度を「同じ」にする前提としては、

・コードが短くなっても、1行のコードの複雑度は同じ。

というケースが考えられます。
具体的に言えば、

・1行で扱う変数の数は、変わらない。
・1行で扱うメソッドの数は、変わらない(メソッドチェーンは、理解度を上げるが、複雑度を上げる)。

という指標があります。

なので、結論で言えば、

1行で扱う変数やメソッド数を変えずに、複雑度が上がらない状態で、
コード数を減らすと、アプリケーションが早く完成する。

ゆえに、プロジェクトの成功率が上がる。

という論法です。

さて、実務はどうなるかというのは後ほど。

カテゴリー: 開発, 設計 | コードを短くすると単体テストが楽になる、の証明 はコメントを受け付けていません

新規ソフトウェア開発においてのプランニング

通勤中にぽちぽちとまとめた結果をアップしておきます。

・要素を抜き出しているだけなので、別途つながりを検討する必要があり。
・一般的なウォーターフォール開発の流れで。
→ ただし、顧客の要望を取り込めるように、顧客からのフィードバックを用意する。
→ アジャイル開発の場合は別途作成する(予定…予定は未定)

>> 要件定義
 >> 顧客要望まとめ
  >> 業務分析
  >> 機能要件
  >> 性能要件
  >> 顧客スケジュール
 >> システム概要設計
 >> 見積もり
  >> 全体スケジュール
  >> 期間見積
  >> 配員計画
  >> 金額見積
>> 見積提出
 >> 交渉
>> プロジェクト計画
>> 設計工程
 >> システム設計
  >> オブジェクト指向設計
  >> データ構造設計
  >> ネットワーク構造設計
  >> ユーザーインターフェース設計
   >> 画面設計
   >> 顧客レビュー
>> 実装工程
 >> 詳細設計、内部設計
 >> 実装
 >> 単体試験
 >> 結合試験
>> 試験工程
 >> 試験計画
  >> 不具合票の取り回し
 >> システム試験
  >> 機能試験
  >> 性能試験
   >> 負荷試験
 >> ユーザー試験
  >> 実装へフィードバック
 >> 運用試験
>> システム導入
 >> 導入計画
 >> 導入作業
 >> 導入試験
 >> 運用マニュアル
 >> 試験運用
>> 運用
 >> 初期サポート
 >> 初期障害対処
 >> 運用研修/教育
>> 保守
 >> 限界値チェック
 >> ナレッジベースへの蓄積
 >> 変更要望
 >> 障害対処 

PMBOK の用語に合わせようと思ったけど、PMBOK の場合、実装(programing)が薄すぎるのでやめました。詳細設計から結合試験までを【実装工程】としました。全体のバランスのためです。
パレードの法則から言えば、より金額の掛かっているところ(あるいはリスクの高いところ)にプロジェクトの投資を注力するべきで、その他は現状の流れに任せてもよい、という考えです。お金もスタッフも限りがありますからね。ビジネス的に対費用効果を考える、ということです。

カテゴリー: プロジェクト管理, Plan Language | 新規ソフトウェア開発においてのプランニング はコメントを受け付けていません

Plan Language を実践中

計画言語を計画中でちょっと止まっておりますが(裏側で xUnit で頭を使っていたからというのもあり)、別件のサイトを作成中です。
いつものパターンならば、Excel で ToDo リストを出していくところなのですが、どうせならばと計画言語を使ってタスクを抽出してみました。

本番環境へリリース
<< データ投入
<< Excel から insert 文へ変換スクリプト
<< 画像ファイルアップロード
<< 本番環境での動作確認
<< oreoreMVC のコピー
<< PHP4 の文字コード確認
<< PHP4+MySQL の動作確認
v << 画像のネーミングを決定 -> slug で
<< 画像のフォルダ構成を決定

<< 本番 view を作成
<< 簡易 view を作成
<< controller 作成
v << 医院詳細表示
<< 医院名で検索
<< 医院名で探す
<< 「あ」をクリックしたときの地図
<< エリアで検索
<< エリアで探す画面
<< エリアを選択した後の地図
<< 駅名で検索
<< 駅名で探す画面
<< 駅名を選択した後の地図
<< お口の健診検索
<< すこやかちゃん検索
<< 口腔がん検診検索
v << 単一テーブルに対する model を作成

言語っぽいところは、

・「<<」で、前の WBS をブレークダウン
・インデント(ひとつの空白)でツリーを表現)

しているだけです。コンパイル可能にするためには Task[“…”] なりをつけないと駄目なんですが、これだとメモ帳などでコーディングが可能です…と言いますか、これ、iPad のメモで書きました。
通勤中にぽちぽちと計画が立てられるので便利です。

そこで思い出したのが、その昔 IBM の workpad で擬似プログラミングをしていたんですよね。やっぱりメモ帳を使って、簡略化した記号を使って書いていました。

さて、この plan langauge の要素を取り出してみると、

1.インデントで親子の WBS を表現する。
2.前後の行で時系列(逆時間)を表現する。先頭がトップ/完成すべき WBS です。
3.完了は「v」で表現する。
4.WBS の内容は、「<<」に続いて記述する。

という具合です。
作って&使ってみて気づいたのですが、実は 2 が重要です。単純なツリー構造の場合には、兄弟 WBS の前後関係は現れません。勿論、DOM のようにデータ構造として保持されますが、ブレークダウンする過程で兄弟 WBS の関連は失われてしまうのです。
なので、このテキスト版の plan language は、行の前後関係が情報として重要になります。時系列として下から上に作業をする、ということですね。

これらの情報を明確にしてデータ構造を作ると、次のように書けます。

class WBS {
public WBS parent ;
public List<WBS> childWBS ;
public List<WBS> beforeWBS ;
public List<WBS> nextWBS;
public string task ;
public bool completed;
}

こんな感じで、前後の wbs を識別します。beforeWBS と nextWBS が list になっているのは、PERT 図のように前後のタスクが複数になったときのためです。

まぁ、こうやってタスクを出してから、粛々とコーディングをする、というわけで。
ええ、もちろん、コーディングをする間も先のタスクは増えたり減ったりします。

カテゴリー: プロジェクト管理, Plan Language | 1件のコメント

コードを短く書く努力をするよ(VC++編)

さて、C# や VB でコードを短くするには限界があります。
という具体例を出しましょう。

まずは、先ほどの VB のコードを再掲します。

Public Sub InitStatusBar()
 SETSTATUS(Button1, "先頭のボタンです")
 SETSTATUS(Button2, "真ん中のボタンです")
 SETSTATUS(Button3, "一番舌のボタンです")
 SETSTATUS(ComboBox1, "項目を選択します")
 SETSTATUS(TextBox1, "名前を入力します")
 SETSTATUS(TextBox2, "年齢を入力します")
 SETSTATUS(TextBox3, "住所を入力します")
End Sub

Private _statusdic As New Dictionary(Of Control, String)
''' <summary>
''' フォーカス時のメッセージを設定
''' </summary>
''' <param name="c"></param>
''' <param name="msg"></param>
''' <remarks></remarks>
Public Sub SETSTATUS(ByVal c As Control, ByVal msg As String)
 _statusdic.Add(c, msg)
 AddHandler c.MouseEnter, AddressOf COM_MouseEnter   'MouseEnter
 AddHandler c.MouseLeave, AddressOf COM_MouseLeave   'MoueeLeave
End Sub

Public Sub ChangeFocus(ByVal sender As Object, ByVal b As Boolean)
 If b = False Then
 ToolStripStatusLabel1.Text = ""
 Else
 ToolStripStatusLabel1.Text = _statusdic(CType(sender, Control))
 End If
End Sub

Private Sub COM_MouseEnter(ByVal sender As System.Object, ByVal e As System.EventArgs)
 ChangeFocus(sender, True)
End Sub
Private Sub COM_MouseLeave(ByVal sender As System.Object, ByVal e As System.EventArgs)
 ChangeFocus(sender, False)
End Sub

これでも十分短いですよね。しかも Dictonary を使っているから効率が良さそうです。
ですが、Dictonary を使っているために、イベントがワンクッション遅くなっています。大抵のイベントはこれでいいのですが、高速化が問題になるときは、この【ワンクッション】が致命的になります。

じゃあ、ってんで VB や C# の場合は冗長パターンに書き直す(あるいは、スクリプトを使ってコードを自動生成する)ことになるんですが、C++ を使うとこの両方の条件を満たすことができます。

#define SETEVENT( cn ) \
this->cn->MouseLeave += gcnew System::EventHandler(this, &Form1::cn##_MouseLeave); \
this->cn->MouseEnter += gcnew System::EventHandler(this, &Form1::cn##_MouseEnter);

#define SETSTATUS( cn, msg ) \
private: System::Void cn##_MouseEnter(System::Object^  sender, System::EventArgs^  e) {    \
 this->ToolStripStatusLabel1->Text = msg;    \
} \
private: System::Void cn##_MouseLeave(System::Object^  sender, System::EventArgs^  e) { \
 this->ToolStripStatusLabel1->Text = "";    \
}

private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
 // ステータスバーのイベントを設定
 SETEVENT( Button1 );
 SETEVENT( Button2 );
 SETEVENT( Button3 );
 SETEVENT( ComboBox1 );
 SETEVENT( TextBox1 );
 SETEVENT( TextBox2 );
 SETEVENT( TextBox3 );
}

/// ステータスバーの設定
SETSTATUS( Button1, "先頭のボタンです");
SETSTATUS( Button2, "真ん中のボタンです");
SETSTATUS( Button3, "一番下のボタンです");
SETSTATUS( ComboBox1 , "項目を選択します");
SETSTATUS( TextBox1, "名前を入力します");
SETSTATUS( TextBox2, "年齢を入力します");
SETSTATUS( TextBox3, "住所を入力します");

既にマジックなコードになっていますが、見かけ上は分かりやすいですよね。
保守という点では、SETEVENT と SETSTATUS でマクロが2つに分かれていますが、先の VB のコードのように

・一時的な List や Dictonary を使わない(メモリ効率)
・イベント呼び出しにワンクッション置かない(高速化)

という条件が満たされています。

ここでトリッキーな使い方をしているのが #define のところで、ボタン名などの名前からイベント名を作成しています。イベント名を個別に作成するので、見掛け上は 1 行のコードですが、実際は複数行書かれています。
C/C++ の場合は、割とこのようなコードを書くのが通常のパターンなのですが、残念ながら VB や C# の場合は、このパターンが使えないんですよね。

カテゴリー: 開発, 設計, C++ | 6件のコメント

コードを短く書く努力をするよ(2)

コードを短く書く努力をすると、テストが省ける | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/2135/

の続きです。上記では refactoring 前を書いていないので、メリットが良く分からない。ということで、冗長な書き方をさらしておきます。

■ステータスバーを設定(冗長パターン)

ボタンなどのコントロールの、MouseEnter と MouseLeave にちまちま書きます。

    ''' <summary>
    ''' Button1 の MouseEnter
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Button1_MouseEnter(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.MouseEnter
        ' ステータスバーにメッセージを表示
        ToolStripStatusLabel1.Text = "一番最初のボタンです"
    End Sub

    ''' <summary>
    ''' Button1 の MouseLeave
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Button1_MouseLeave(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.MouseLeave
        ' ステータスバーのメッセージをクリア
        ToolStripStatusLabel1.Text = ""
    End Sub

    ''' <summary>
    ''' Button2 の MouseEnter
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Button2_MouseEnter(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.MouseEnter
        ' ステータスバーにメッセージを表示
        ToolStripStatusLabel1.Text = "真ん中のボタンです"
    End Sub

    ''' <summary>
    ''' Button2 の MouseLeave
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Button2_MouseLeave(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.MouseLeave
        ' ステータスバーのメッセージをクリア
        ToolStripStatusLabel1.Text = ""
    End Sub

    ''' <summary>
    ''' Button3 の MouseEnter
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Button3_MouseEnter(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.MouseEnter
        ' ステータスバーにメッセージを表示
        ToolStripStatusLabel1.Text = "一番下のボタンです"
    End Sub

    ''' <summary>
    ''' Button3 の MouseLeave
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Button3_MouseLeave(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.MouseLeave
        ' ステータスバーのメッセージをクリア
        ToolStripStatusLabel1.Text = ""
    End Sub

長い…長すぎますッ!!! Visual Studio を使うとヘッダのコメントは自動生成してくれるのですが、これで 3 つしかボタンに割り当てていません。
コード的には、MouseEnter と MouseLeave のワンセットで 20 行かかります。
なので、10 個のボタンがあれば、200 行掛かるわけですね。

■ステータスバーを設定(イベントを共通化、でも冗長)

これでは、あまりにも、なのでイベントを共通化します。

    ''' <summary>
    ''' Button1 の MouseEnter
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub ButtonCom_MouseEnter(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles _
        Button1.MouseEnter, _
        Button2.MouseEnter, _
        Button3.MouseEnter
        ' ステータスバーにメッセージを表示
        Dim msg As String = ""
        If sender Is Button1 Then
            msg = "一番最初のボタンです"
        ElseIf sender Is Button2 Then
            msg = "真ん中のボタンです"
        ElseIf sender Is Button3 Then
            msg = "一番下のボタンです"
        End If
        ToolStripStatusLabel1.Text = msg
    End Sub

    ''' <summary>
    ''' Button1 の MouseLeave
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub ButtonCom_MouseLeave(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles _
        Button1.MouseLeave, _
        Button2.MouseLeave, _
        Button3.MouseLeave
        ' ステータスバーのメッセージをクリア
        ToolStripStatusLabel1.Text = ""
    End Sub

おお、ずいぶんすっきりしましたね。イベントをひとつにまとめたので【共通化】されています。elseif の羅列のかわりに select case を使う方法もあります。

    ''' <summary>
    ''' Button1 の MouseEnter
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub ButtonCom2_MouseEnter(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles _
        Button1.MouseEnter, _
        Button2.MouseEnter, _
        Button3.MouseEnter
        ' ステータスバーにメッセージを表示
        Dim msg As String = ""
        Dim cont As Control = TryCast(sender, Control)
        Select Case cont.Name
            Case "Button1"
                msg = "一番最初のボタンです"
            Case "Button2"
                msg = "真ん中のボタンです"
            Case "Button3"
                msg = "一番下のボタンです"
        End Select
        ToolStripStatusLabel1.Text = msg
    End Sub

さて、日曜プログラマならば、この程度で許せるのですが、【業務プログラマー】ならば、この時点で2点気づかないと駄目です。

・Button1.MouseLeave 等が、二重に記述されている。
・メッセージが埋め込まれている。

イベントが多くなると、Handles を2箇所修正しないと駄目ですね。VB v2.0 特有ではありますが、継続記号「_」を書く必要があるので、結構面倒です。
また、elseif でも select case でも、所詮は【設定】なのですから、配列/リスト/ディクショナリを使ったほうが、【設定】として際立ちます。

■ステータスメッセージとイベントを設定風に変える

これが、前回書いたときのの【意図】です。
設定として記述するので、SETSTATUS のような関数を使って並べていきます。

Public Sub InitStatusBar()
	SETSTATUS(Button1, "先頭のボタンです")
	SETSTATUS(Button2, "真ん中のボタンです")
	SETSTATUS(Button3, "一番舌のボタンです")
	SETSTATUS(ComboBox1, "項目を選択します")
	SETSTATUS(TextBox1, "名前を入力します")
	SETSTATUS(TextBox2, "年齢を入力します")
	SETSTATUS(TextBox3, "住所を入力します")
End Sub

ここのメッセージを enum なり const string なりを参照しても良いですし、外部ファイルから読み込みをしても構いません。

	Class STATMSG
		Public cont As Control
		Public msg As String
	End Class
	Private _status As New List(Of STATMSG)
	''' <summary>
	''' フォーカス時のメッセージを設定
	''' </summary>
	''' <param name="c"></param>
	''' <param name="msg"></param>
	''' <remarks></remarks>
	Public Sub SETSTATUS(ByVal c As Control, ByVal msg As String)
        Dim sm As New STATMSG()
        sm.cont = c
        sm.msg = msg
        AddHandler c.MouseEnter, AddressOf COM_MouseEnter   'MouseEnter
        AddHandler c.MouseLeave, AddressOf COM_MouseLeave   'MoueeLeave
		_status.Add(sm)
	End Sub
''' <summary>
''' フォーカス時のメッセージを設定
''' </summary>
Public Sub ChangeFocus(ByVal sender As Object, ByVal b As Boolean)
	If b = False Then
		ToolStripStatusLabel1.Text = ""
	Else
		For Each cm In _status
			If cm.cont Is sender Then
				ToolStripStatusLabel1.Text = cm.msg
			End If
		Next
	End If
End Sub

ここまで共通関数で、以下のイベントを form に追加します

Private Sub COM_MouseEnter(ByVal sender As System.Object, ByVal e As System.EventArgs)
	ChangeFocus(sender, True)
End Sub
Private Sub COM_MouseLeave(ByVal sender As System.Object, ByVal e As System.EventArgs)
	ChangeFocus(sender, False)
End Sub

こうすると、コントロールが増えても InitStatusBar 関数に1行追加するだけで済みます。
また、メッセージをファイル読み込みするときは、InitStatusBar 関数でメッセージをファイルから読み込むように書き換えるだえけでいいのです。

■高速化するためにリファクタリングする

この設定では List を使ったのですが、Dictonary を使ったほうがループがなくなります。これはリファクタリングの範囲なので、インターフェースは変わらないように作ります。

    Private _statusdic As New Dictionary(Of Control, String)
    ''' <summary>
    ''' フォーカス時のメッセージを設定
    ''' </summary>
    ''' <param name="c"></param>
    ''' <param name="msg"></param>
    ''' <remarks></remarks>
    Public Sub SETSTATUS(ByVal c As Control, ByVal msg As String)
        _statusdic.Add(c, msg)
        AddHandler c.MouseEnter, AddressOf COM_MouseEnter   'MouseEnter
        AddHandler c.MouseLeave, AddressOf COM_MouseLeave   'MoueeLeave
    End Sub

    Public Sub ChangeFocus(ByVal sender As Object, ByVal b As Boolean)
        If b = False Then
            ToolStripStatusLabel1.Text = ""
        Else
            ToolStripStatusLabel1.Text = _statusdic(CType(sender, Control))
        End If
    End Sub

Control から string を引き出すだけなので Dictionary が使えます。
まあ、List をループさせても、コントロール数はそう多くないので(1万個とかではないでしょう)、スピードは大して変わりません。

というわけで、こんな風に行数を減らしていきます。
今回のポイントとしては、

・冗長な部分を共通化させて、行数を減らす。
・設定なのかロジックなのかを区別する。設定ならば、設定風に書き換える。
・リファクリングをして高速化する。

ってのがミソです。

業務コードの場合、単純にコピー&ペーストで済めば、それを使っても良いのですが、コード自体が冗長になる場合は考え直したほうがよいですね、という話です。このあたりは、保守性も含めると、短いコード(保障されたコードを再利用する)というのが、業務コードを書くときのコツです。

カテゴリー: 開発, 設計 | 1件のコメント

コードを短く書く努力をすると、テストが省ける

まぁ、がしがしとタイピングするのも楽しいけど、私は作業量を考えて短くするのが好きです。
行数にするとアウトプットの量が減るんですけどねw、気にせず。

こんな風な画面で、マウスをポイントしたとき(MouseEnter と MouseLeaveイベント)の時にステータスバーにメッセージを表示します。
あと、チェックボックスを切り替えた時に、各ボタンの有効/無効が変えられます。

ざっと、ソースコード。何故か VB で(笑)

Public Class Form1

	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
		' 有効/無効を設定
		InitEnableMode()
		' 動的にイベントを追加
		AddHandler RadioButton1.CheckedChanged, AddressOf RadioButton1_CheckedChanged
		AddHandler RadioButton2.CheckedChanged, AddressOf RadioButton1_CheckedChanged
		AddHandler RadioButton3.CheckedChanged, AddressOf RadioButton1_CheckedChanged

		' ステータスバーの設定
		InitStatusBar()
		' イベントを追加
		Dim items As New List(Of Control)
		items.Add(Button1)
		items.Add(Button2)
		items.Add(Button3)
		items.Add(ComboBox1)
		items.Add(TextBox1)
		items.Add(TextBox2)
		items.Add(TextBox3)
		For Each c In items
			AddHandler c.MouseEnter, AddressOf Button1_MouseEnter
			AddHandler c.MouseLeave, AddressOf Button1_MouseLeave
		Next
	End Sub

	''' <summary>
	''' 有効/無効を設定
	''' </summary>
	''' <remarks></remarks>
	Public Sub InitEnableMode()
		Dim o As Boolean = True
		Dim x As Boolean = False

		'' Mode 1, 2, 3, コントロールの順で指定
		SETMODE(o, o, o, Button1)
		SETMODE(o, o, x, Button2)
		SETMODE(o, x, x, Button3)
		SETMODE(o, x, x, ComboBox1)
		SETMODE(o, x, x, TextBox1)
		SETMODE(x, o, o, TextBox2)
		SETMODE(x, o, o, TextBox3)

	End Sub

	Private _modes As New List(Of List(Of Object))
	Public Sub SETMODE(ByVal ParamArray params As Object())
		Dim max As Integer = params.Length
		Dim items As New List(Of Object)
		items.Add(params(max - 1))
		For i As Integer = 0 To max - 2
			items.Add(params(i))
		Next
		_modes.Add(items)
	End Sub

	Public Sub ChangeMode(ByVal mode As Integer)
		For Each items As List(Of Object) In _modes
			Dim c As Control = CType(items(0), Control)
			c.Enabled = CType(items(mode + 1), Boolean)
		Next
	End Sub
	Private Sub RadioButton1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
		If sender Is RadioButton1 Then
			ChangeMode(0)
		ElseIf sender Is RadioButton2 Then
			ChangeMode(1)
		ElseIf sender Is RadioButton3 Then
			ChangeMode(2)
		End If
	End Sub


	Class STATMSG
		Public cont As Control
		Public msg As String
	End Class
	Private _status As New List(Of STATMSG)
	''' <summary>
	''' フォーカス時のメッセージを設定
	''' </summary>
	''' <param name="c"></param>
	''' <param name="msg"></param>
	''' <remarks></remarks>
	Public Sub SETSTATUS(ByVal c As Control, ByVal msg As String)
		Dim sm As New STATMSG() With {.cont = c, .msg = msg}
		_status.Add(sm)
	End Sub

	Public Sub InitStatusBar()
		SETSTATUS(Button1, "先頭のボタンです")
		SETSTATUS(Button2, "真ん中のボタンです")
		SETSTATUS(Button3, "一番舌のボタンです")
		SETSTATUS(ComboBox1, "項目を選択します")
		SETSTATUS(TextBox1, "名前を入力します")
		SETSTATUS(TextBox2, "年齢を入力します")
		SETSTATUS(TextBox3, "住所を入力します")
	End Sub

	Public Sub ChangeFocus(ByVal sender As Object, ByVal b As Boolean)
		If b = False Then
			ToolStripStatusLabel1.Text = ""
		Else
			For Each cm In _status
				If cm.cont Is sender Then
					ToolStripStatusLabel1.Text = cm.msg
				End If
			Next
		End If
	End Sub

	Private Sub Button1_MouseEnter(ByVal sender As System.Object, ByVal e As System.EventArgs)
		ChangeFocus(sender, True)
	End Sub
	Private Sub Button1_MouseLeave(ByVal sender As System.Object, ByVal e As System.EventArgs)
		ChangeFocus(sender, False)
	End Sub
End Class

眠たいので、詳しい解説は後ほどやる…かもしれず。

メモ的に書いておくと、モードの設定のフォーマットがミソです。

	''' <summary>
	''' 有効/無効を設定
	''' </summary>
	''' <remarks></remarks>
	Public Sub InitEnableMode()
		Dim o As Boolean = True
		Dim x As Boolean = False

		'' Mode 1, 2, 3, コントロールの順で指定
		SETMODE(o, o, o, Button1)
		SETMODE(o, o, x, Button2)
		SETMODE(o, x, x, Button3)
		SETMODE(o, x, x, ComboBox1)
		SETMODE(o, x, x, TextBox1)
		SETMODE(x, o, o, TextBox2)
		SETMODE(x, o, o, TextBox3)

	End Sub

bool 値を「o」と「x」に割り当てているのは、こんな風に表形式で設定したいからです。かつて、VC++ の時に作ったノウハウです。その時には、define を使ったり外部ファイルを include したりしたのですが、vb ではできません。ture, false を使ってもいいのですが、visual studio が勝手にフォーマットしてしまうから、桁がずれるんです。なので、こんな風に「o」と「x」を使うわけです。
なんとなく分かり易いですね。
モードが増えた場合は、行を増やせばいい訳です。

同じようにステータスバーの切り替えの設定も書けます。

	Public Sub InitStatusBar()
		SETSTATUS(Button1, "先頭のボタンです")
		SETSTATUS(Button2, "真ん中のボタンです")
		SETSTATUS(Button3, "一番舌のボタンです")
		SETSTATUS(ComboBox1, "項目を選択します")
		SETSTATUS(TextBox1, "名前を入力します")
		SETSTATUS(TextBox2, "年齢を入力します")
		SETSTATUS(TextBox3, "住所を入力します")
	End Sub

こんな風に、SETSTATUS 関数を作ります。クラスを作って new SetStatus() With { … } な形で書いてもよいのですが、new やらクラス名やらを設定するのが面倒ですよね。所詮、使い捨ての関数ですから、べたべたに書いてしまいます。

		' イベントを追加
		Dim items As New List(Of Control)
		items.Add(Button1)
		items.Add(Button2)
		items.Add(Button3)
		items.Add(ComboBox1)
		items.Add(TextBox1)
		items.Add(TextBox2)
		items.Add(TextBox3)
		For Each c In items
			AddHandler c.MouseEnter, AddressOf Button1_MouseEnter
			AddHandler c.MouseLeave, AddressOf Button1_MouseLeave
		Next

マウスイベントも、こんな風にまとめて書いてしまいます。Handles に書いてもいいのですが、数が少ないときはいいけどこんな風に多くなると大変ですよね。なので、使い捨てのリストを使ってどしどしと追加します。

なんで、私がこんなコードを書くのかというと、

  • 使い捨てのコードは、効率よりも分かり易く書く。
  • 分かり易く書くと、あとからの変更がしやすい。
  • コードを見て分かり易いと、テストを省略できる。

からです。
コントロールの有効/無効の処理なんかは、if 文と control 名を使ってずらずらと書き並べることはできるのですが、それをやってしまうと、

  • 抜けがあると、何処が悪いのか分かりづらい。
  • 抜けがでやすいので、テストする必要がある。

ってことが理由なのです。先のように(トリッキーではありますが)あたかも Excel で設定しているように x と o を使って桁を揃えていくと、抜けが明確になります。

コードを短くすると生産性が悪くなるという弊害がw出ますが、まぁ、タイピングするのが仕事ではないので、昔から短いコードをたくさん書きます。そう、プログラマの仕事はコードを書くことではなくて、動くプログラムを作ることですからね、ってことです。

カテゴリー: 設計, 雑談, xUnit | 3件のコメント

Gantt Chart を IDEF0 風に記述する

大雑把ですが、ガントチャートを IDEF0 風に分解すると、こんな図になります。

・インプット方向のタスク(前工程のタスク)がある。
・アウトプット方向のタスク(後工程のタスク)がある。
・タスクは、一定の作業量を持つ。
・タスクは、一定の作業を行うと終了する(開始と終了がある)。
・作業は、配員(人)が行う。
・配員は、一定の作業能力(属人性、能力差)を持つ。

・配員は、リソースとしての制約がある(同時に2つの場所で働けないなど)。
・タスクは、時間制約がある(無限に長い期間でやってはいけない)。
・タスクは、期間制約がある(無限に期限を延ばしてはいけない)。
・1日の時間は、24時間である(週単位の勤務時間は40時間である、など)。

ここで、前者の項目は「前提条件」であり、ある条件をクリアすると「完了」になります。RPG ゲームみたいなものです。

後者の制限は、制約条件で「ルール」になります。ルール違反をすることはできません…というか、ルール自体がないと「ルール違反」って現象がないですよね(と、現象学的な話とか)。

これだけの条件を出しておけば、プログラミング可能/検証可能になります。いわゆる XP で言うところの計画ゲームが可能です。

で、これをベースにして擬似コードを書いてみると。


// 制約条件を設定
Task.制約("40時間勤務");
Task.制約("残業なし");
Task.制約("リリース時期", 2012/01/01 );

// 属人性, 能力差ポイントを設定
Person("masuda").属人性("HP", 100 );
Person("masuda").属人性("MP", 200 );  // 魔法が使えるとか

Person("tomoaki").属人性("HP", 200 ); // 体力が多いとか
Person("tomoaki").属人性("MP",  50 ); 

// リソース(配員)を設定
Plan.リソース(Person("masuda"),  0.5 );
Plan.リソース(Person("tomoaki"), 1.0 );

// タスクの作業ポイントを設定
Task("本タスク").作業ポイント( 200 );

// 連携を設定
Task("前タスク") -> Task("本タスク");
Task("本タスク") -> Task("後タスク");

こういう風に設定しておいて、


// ガントチャートを作成して
Plan.CreateGanttChart();

シミュレートする場合は、こんな風に。


// こんな風にして、100 回ほどシミュレートする
Plan.Simulate(100) 

現実にプロジェクトの実績を入れる場合は、次のように。


// 実績を設定
Plan.Task("本タスク").実績( 100 );

// タスクが無くなったら、即削除して再計画
Plan.RemoveTask("削除タスク");
Plan.CreateGanttChart();

// タスクが増えたら、即追加して再計画
Plan.AddTask("追加タスク");
Plan.CreateGanttChart();

// タスクが追加されたので、シミュレーションをやり直してみる。
Plan.Simulate(100) 

ここで、成功確率なんかが出ると、実に「それらしい」感じになるんでうすがどうでしょう?

アジャイルが一見すると「計画」を捨てているように見えるのは、それぞれのタスク/ストーリーカードの繋がりを「視覚化」しないところにあります。これは、視覚化することによるオーバーヘッドを避ける≒コミュニケーションコストを下げる、ことに一役買っています。

なので、逆に言えば、計画を視覚化することのコストが限りなく低ければ、再計画時の情報となるので、不明確部分が減り、成功確率があがります(と予想されます)。まぁ、計画倒れとか取らぬ狸のなんとやら、というのもありますから「再計画」が絶対という訳ではありませんが、ひとつの選択肢が増えますよね、ってことで。

カテゴリー: プロジェクト管理, Plan Language | Gantt Chart を IDEF0 風に記述する はコメントを受け付けていません

verifiable plan language の目指すところを考察してみる

検証可能な計画言語ってことで、おおまかな目標のメモです。Javaのカラー本を真似してして色分けしてみました。「色」自体に意味があるのですが、これは後ほど。

ざっと見て分かるとおり、PDCA(Plan/Do/Check/Action)を元に情報の流れをチェックしています。データの流れも PDCA に順じているので、このフローを使うことになるのかなと。

■計画(Plan)

いきなり、Gantt Chart を作り始めるのは無謀なので、WBS なり、ストーリーカードなりで項目の抽出を行います。
作業項目の抽出は、主に 3 つの方法があります。

・PMBOK/WBS のようにトップダウンで
・XP/SCRUM のようにボトムアップで
・CCPM のようにエンドから

いずれにしても、「タスク抽出」という工程になりますね。このあたりは、plan なところで、抽出したタスクには、属性があります。

・作業量(人月/人日/人時間/作業ポイント/ストーリーポイント)

このタスクを実行する場合に、属人性の高さにより 3 つに分けられます。

・誰がやっても、一定時間かかる作業
・属人性がある作業(専門など)
・能力差がある作業(人依存)

属人性と能力差の例としては、

・そのプロジェクトに従事していた人であれば、○○時間で済むが、別の人をアサインすると××時間、これが「属人性」
・同じプログラミングでも、ベテランの人がやれば○○時間で済むが、新人がやれば××時間かかる、これが「能力差」

となります。属人性の場合は、年齢や経験よりも「専門性」が重視され、能力差の場合は「経験」が重視されるという形です。このあたりを加味しないと、正確なガントチャートはできませんよね、という具合です。

■実行(Do)

計画に従って実行する訳ですが、ここでは実際に実行する場合とシミュレーションする場合との 2 つに分けます。
シミュレーションの場合は、XP で言うところの「計画ゲーム」であったり「ブレーンストーミング」であったりします。
サイコロを転がしてゲーム的にやってもいいのですが、コンピュータのパワーを使ってランダム要素で、100 回ぐらいプロジェクトを稼動させれば、それなりに収束するような気もします。

このあたりは、ワインバーグ氏がシステムダイナミクスを使ったり、ゴールドラット氏が CCPM のシミュレーションをしたりしています。

■監査(Check)

進捗なり実績を入れたならば、チェックしなければ意味がありません。逆に言えば、チェックする必要の無い値ならば、観察する必要はありません、というのがデマルコの言葉です。

なので、実績に従って、進捗率を計算します。EVM でも良いし、工事進行基準でも良いし、バーンダウンチャートでも良いし、よく言われる「見える化」ってのは、ここのことですね。

■見直し(Action)

世の中のプロジェクトで一番できていないのが、この見直し/再計画です。
最初の計画からずれていてもそのまま進めてしまったり、現実と離れているにもかかわらず計画表を直さなかったり…と言いますか、計画/配員表のメンテナンスそのものに労力が掛かり過ぎるために、計画を見直さないという状態がほとんどです。現状と乖離しているわけですね。

なので、VPL(Verifiable Plan Language)では、この部分を厚く保護していきます。

・タスクの追加や削除
・配員(リソース)を調節
・スケジュール(プロジェクト期間、マイルストーン)を調節

が「手軽に」できるようにします。まぁ、少なくとも計画(Plan)と同じ程度の手間でできるようにします。

さて、これを具体的にどうするのかというのを落とし込みますか。

カテゴリー: プロジェクト管理, Plan Language | verifiable plan language の目指すところを考察してみる はコメントを受け付けていません

F#でER図を書こうと思ったけど止めておくの巻

#light

let (||-||) x y =
    printfn "%A join %A: 1 vs 1"
let (>|-||) x y =
    printfn "%A join %A: 1..* vs 1"
let (>@-||) x y =
    printfn "%A join %A: 0..* vs 1"
let (|@-||) x y =
    printfn "%A join %A: 0..1 vs 1"

F# ではオペレータの再定義が自由なので、色々な演算子が作れる…ってことは、ER図の鳥足みたいのもできるのでは?と思ったのがこれ。

演算子としては異様、と言いますか単純に外部結合をするだけのために使う、のかな。

Products.category_id >@-@| Categories.id

のような感じで、Products テーブルと Categories テーブルが「多対1」のように示すわけですが、思いついてはみたけれど何のために使うのかわかりません。O/R マッピングを XML ファイルで定義するよりも使い手があれば、それでもいいんですが。

そういえば、xml 形式の定義で思い出したのですが、設定ファイルというのは何も xml 形式やバイナリ形式にする必要もないのです。設定ファイルというと、昔は ini ファイル形式だったり、適当なバイナリ形式だったり、テキスト形式だったりして、最近は xml 形式が流行りな訳ですが、コード自身をファイルに保存しておくという形式があります。

TeX 形式や postscript 形式がそうで、実はコードとデータを兼ねた形式になります。あと、LISP もコードとデータを混在させることが可能です。

と言葉で書いても良くわからないので、具体例を出してみます。

<persons>
	<person>
		<name>masuda tomoaki</name>
		<addr>tokyo</addr>
		<telephone>03-0000-0000</telephone>
	</person>	
</persons>

このような XML 形式があるとします。これを INI ファイル形式で書くとすると、一例としてこんな風に書けます。

[persons]
name="masuda"
[person.masuda]
addr="tokyo"
telephone="03-000-0000"

あと LISP で書くとこんな感じです。

(persons
 (person 
  (name "masuda")
  (addr "tokyo")
  (telehphone "03-0000-0000")))

# 本当はクォートしないといけないような気がするのですが、まあ、こんな感じです。
実は、XML 形式と LISP 形式はトポロジー的に似ています。閉じ括弧/タグが必要という点で同じですね。

今度は TeX 風に書いてみると、

\begin{persons}
 \begin{person}
  \set name="masuda"
  \set addr="tokyo"
  \set telephone 
 \end{person}
\end{persons}

な感じです。\set のような書き方があったハズですが、覚えていません。
さて、肝心の C++ のコード自体でデータ構造を表そうとすると次のように書けます。

Persons.Add( 
 new Person( 
  new Name("masuda"),
  new Addr("Tokyo"),
  new Telephone("03-0000-0000")));

XML 形式や LISP 形式に似ています。これならば、XML 形式にしたほう楽だろうと思うかもしれませんが(いや、それは事実なんですけど)、このように C++ のコードにしておくと、コードの中にデータを埋め込めるという利点があります。
このデータ構造を data.txt というファイルに記述しておき include します。

void func() 
{
#include "data.txt";

	// Persons に対して操作をする
}

こんな風にすると、データの差し替えが手軽にできます。今で云えば、JSON の埋め込み型の要領です。
実はこの技、データだけを他の処理系(Excelなど)から生成して、C++ で取り込むということができます。C# や VB だとこれが使えないんですよね…ちょっと不便かなぁと。

カテゴリー: 雑談 | F#でER図を書こうと思ったけど止めておくの巻 はコメントを受け付けていません

久し振りにアナリシスパターンを紐解いて計画パターンを見直す

Verifiable Plan Language(検証可能な計画言語の思索)
http://plan-language.com/

ってことで、【ネタ的に】ドメインを取って、ひとまず wordpress を立てました。

言語ってことになっていますが、UML のように記号化のところに重きを置くのではなくて、【検証可能な】というのが主題です。なので、プログラム言語自体は、F# でも C# でも何でもいいのです(ってのが目標)。当面は、私の知っている言語が対象になるので、C#, F#, Java, PHP ですねぇ。スクリプト系の言語として、Python か Ruby なんですが。多分、Python になると思います。

さて、Verifable Plan Language 略して VPL は、計画段階からプロジェクト/プロダクトのプロセスの実行までを言語化します…って、こういうと自分でも何を言っているか分からないのですがw、PMBOK の Planning プロセスを言語化するというのが正しいのかなぁ。WBS なり、Gantt Chart なり、IDEF0 や DFD なりと planning から design process にながっる手法はいくつかあるのですが、やっぱり「検証できない」というのが致命的だと思っています。

そう、その計画は「妥当なのか?」というの妥当性は、プロジェクトの最後にならないと分からないとう「不確実性」を抱えたままなのです。勿論、プロジェクトの初期段階では、不確実性が多いのは確かなのですが、プロジェクトの終わりになっても「同じ計画を抱えたまま」では不確実性が多いままになってしまうのが問題です。現実問題として、明日リリースできるものが手元にあるのであれば、不確実性は限りなく 0 に近いと言えるわけです(勿論、不慮の事故というのもあるんですが)。

で、この手の論証なんかは、plan-language.com のほうでやるとして(moonmile.net/blog のほうは、もっと現場に接した「技術」的なところのおすそ分けなので)、ここでは、UIDD 的に WBS を作成するプロセスをプログラミングします。って、言っても分かりづらいので、実例を。

namespace PlanLanguage.Test
{
	public class TestGanttChart
	{
		public void MakeWBS()
		{
			// プロジェクトを作成する
			var proj = new WBSProject("WBSプロジェクトの作成");
			
			// トップダウンでWBSを作成する
			proj.CreateWBS("100", "要件定義");
			proj.CreateWBS("200", "設計工程");
			proj.CreateWBS("300", "実装工程");
			proj.CreateWBS("400", "結合試験");
			proj.CreateWBS("500", "システム試験");
			proj.CreateWBS("600", "試験運用");

			// ブレークダウン
			proj.WBS["100"].BreakDown("101", "機能要件");
			proj.WBS["100"].BreakDown("102", "性能要件");
			proj.WBS["100"].BreakDown("103", "開発期間");
			proj.WBS["100"].BreakDown("104", "開発規模(金額)");
			proj.WBS["100"].BreakDown("105", "開発規模(人員)");
			proj.WBS["100"].BreakDown("106", "システム概要設計");
			proj.WBS["100"].BreakDown("107", "既存システム解析");

			// PERT情報(期間)を設定
			proj.WBS["101"].Period = 10;
			proj.WBS["102"].Period = 10;
			proj.WBS["103"].Period = 5;
			proj.WBS["104"].Period = 5;
			// PERT情報(前後関係)を設定
			proj.TopWBS.NextTask = proj.WBS["101"];
			proj.WBS["101"].NextTask = proj.WBS["102"]; // 並行作業
			proj.WBS["101"].NextTask = proj.WBS["103"]; // 
			proj.WBS["102"].NextTask = proj.WBS["104"]; // 合流
			proj.WBS["103"].NextTask = proj.WBS["104"]; 
			proj.WBS["104"].NextTask = proj.WBS["105"];

			// マイルストーンの設定
			proj.TopWBS.MileStone = new DateTime(2011, 4, 1);

			// リソースを設定
			proj.AddStaff("masuda", 0.5);
			proj.AddStaff("yamada", 1.0);
			proj.AddStaff("tomoaki",1.0);
			
			// ガントチャート作成
			GanttChart gc = proj.CreateGanntChart();

			// クリティカルパスの取得
			List<WBS> cp = proj.GetCriticalPath();
		}
	}
}

WBS(Work Break down Structure)の作り方は、各社まちまちなのでここでは解説しませんが、大まかに言えば「トップダウン」で作ります。トップにプロジェクト自身があって、下へ下へとツリー状になっていきます。WBS の良いところは(PMBOK で言われていることは)、各タスクが重複しないところです。トップダウンで分類がされているので、下層にあるタスクは重複しません。
# と同時に、「重複できない」という制限があるのですが。これは論理学的にという意味で。

手順としては、

1. 大項目の WBS を出す。
2. WBS を作業単位になるまでブレークダウンする。
3. PERT 図を作成するための、期間(period)と前後関係(relation)を設定する。
4. Gantt Chart にするために、時間軸(マイルストーンなど)を設定する。
5. リソース(人,場所,機械など)を設定
6. ガントチャートを作成

という流れになります。

# コードのほうは、Project に直接挿入しているけど、本来は Plan ですよね。
# これは後から修正。

で、ここまでは計画段階なので、この計画を基にして実行プロセスを動かします。
PMBOK では、実行プロセスは非常に薄い(進捗管理程度しかない)のですが、現場のプロジェクトとしては、

・各タスクの進捗率
・各タスクの遅延状況
・タスクの削除/追加
・再計画/スケジューリング

が必須になります。あと、人員が減ることもある(俗に言う、ウエディングリスク)ので、これを実行プロセスを言語化します。

もうひとつ、CCPM 的に、タスクの遅延確率(あるいはプロジェクトバッファ)を計算する必要があるので、全体スケジュールに影響を及ぼす可能性のあるタスク(合流タスク、あるいは障壁となるタスク)の監視を行います。

こっちの具体例はのちほど。

カテゴリー: UIDD, プロジェクト管理, Plan Language | 久し振りにアナリシスパターンを紐解いて計画パターンを見直す はコメントを受け付けていません