mokky14's IT diary

IT関係の仕事メモ、勉強会の感想など書いてます。

CentOSにPostgresql 9.2をyumからインストール

CentOS6にPostgresqlのバージョン9.2をインストールしたときのメモ。
(CentOS 6に同梱されてるPostgresqlのバージョンは8.4)

ここを参考にインストール実施。

まずPostgresql9.2のyumリポジトリCentOSに登録。
ここからCentOS 6 - x86_64をダウンロード。
ダウンロードしたリポジトリパッケージファイルからリポジトリ追加。

[root@cent6 ~]# rpm -ivh ./pgdg-centos92-9.2-6.noarch.rpm 
警告: ./pgdg-centos92-9.2-6.noarch.rpm: ヘッダ V4 DSA/SHA1 Signature, key ID 442df0f8: NOKEY
準備中...                ########################################### [100%]
   1:pgdg-centos92          ########################################### [100%]

後はyumからパッケージ指定指定でインストール。

[root@cent6 ~]# yum install postgresql92-server postgresql92-devel postgresql92-contlib
Loaded plugins: fastestmirror, refresh-packagekit, security
Loading mirror speeds from cached hostfile
 * base: ftp.tsukuba.wide.ad.jp
 * epel: mirror01.idc.hinet.net
 * extras: ftp.tsukuba.wide.ad.jp
 * updates: ftp.tsukuba.wide.ad.jp
pgdg92                                                   | 3.7 kB     00:00     
pgdg92/primary_db                                        | 102 kB     00:00     
Setting up Install Process
No package postgresql92-contlib available.
Resolving Dependencies
--> Running transaction check
---> Package postgresql92-devel.x86_64 0:9.2.8-1PGDG.rhel6 will be installed
--> Processing Dependency: postgresql92 = 9.2.8-1PGDG.rhel6 for package: postgresql92-devel-9.2.8-1PGDG.rhel6.x86_64
---> Package postgresql92-server.x86_64 0:9.2.8-1PGDG.rhel6 will be installed
--> Running transaction check
---> Package postgresql92.x86_64 0:9.2.8-1PGDG.rhel6 will be installed
--> Processing Dependency: postgresql92-libs = 9.2.8-1PGDG.rhel6 for package: postgresql92-9.2.8-1PGDG.rhel6.x86_64
--> Running transaction check
---> Package postgresql92-libs.x86_64 0:9.2.8-1PGDG.rhel6 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
 Package                  Arch        Version                 Repository   Size
================================================================================
Installing:
 postgresql92-devel       x86_64      9.2.8-1PGDG.rhel6       pgdg92      1.4 M
 postgresql92-server      x86_64      9.2.8-1PGDG.rhel6       pgdg92      3.9 M
Installing for dependencies:
 postgresql92             x86_64      9.2.8-1PGDG.rhel6       pgdg92      973 k
 postgresql92-libs        x86_64      9.2.8-1PGDG.rhel6       pgdg92      187 k

Transaction Summary
================================================================================
Install       4 Package(s)

Total download size: 6.4 M
Installed size: 28 M
Is this ok [y/N]: y
Downloading Packages:
(1/4): postgresql92-9.2.8-1PGDG.rhel6.x86_64.rpm         | 973 kB     00:03     
(2/4): postgresql92-devel-9.2.8-1PGDG.rhel6.x86_64.rpm   | 1.4 MB     00:08     
(3/4): postgresql92-libs-9.2.8-1PGDG.rhel6.x86_64.rpm    | 187 kB     00:01     
(4/4): postgresql92-server-9.2.8-1PGDG.rhel6.x86_64.rpm  | 3.9 MB     00:23     
--------------------------------------------------------------------------------
Total                                           173 kB/s | 6.4 MB     00:37     
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
Warning: RPMDB altered outside of yum.
  Installing : postgresql92-libs-9.2.8-1PGDG.rhel6.x86_64                   1/4 
  Installing : postgresql92-9.2.8-1PGDG.rhel6.x86_64                        2/4 
  Installing : postgresql92-server-9.2.8-1PGDG.rhel6.x86_64                 3/4 
  Installing : postgresql92-devel-9.2.8-1PGDG.rhel6.x86_64                  4/4 
  Verifying  : postgresql92-server-9.2.8-1PGDG.rhel6.x86_64                 1/4 
  Verifying  : postgresql92-9.2.8-1PGDG.rhel6.x86_64                        2/4 
  Verifying  : postgresql92-libs-9.2.8-1PGDG.rhel6.x86_64                   3/4 
  Verifying  : postgresql92-devel-9.2.8-1PGDG.rhel6.x86_64                  4/4 

Installed:
  postgresql92-devel.x86_64 0:9.2.8-1PGDG.rhel6                                 
  postgresql92-server.x86_64 0:9.2.8-1PGDG.rhel6                                

Dependency Installed:
  postgresql92.x86_64 0:9.2.8-1PGDG.rhel6                                       
  postgresql92-libs.x86_64 0:9.2.8-1PGDG.rhel6                                  

Complete!

hostsの変更が反映されなかった時の対処

/etc/hostsの、ホストに対応したIPアドレスを変更したのに、変更前に定義していたIPに接続し続ける事象に当たり、少しハマったのでメモ。
環境はRHEL6。

ホスト名をキャッシュしてるサービスを再起動することで解決した。

# /etc/init.d/nscd restart
nscd を停止中:                                             [  OK  ]
nscd を起動中:                                             [  OK  ]

C++でXerces使ってxml解析

Xerces-C++xml解析するプログラム作ったのでメモ残しとく。


xmlのパーサはXercesを使用することにした。
(最初はlibxml2を使おうとしたけど、APIが多すぎてイヤになった)

インストは以下手順でインスト。

$  tar xvzf xerces-c-3.1.1.tar.gz 
$  cd xerces-c-3.1.1
$  ./configure
$  make
$  sudo make install

まずは写経してみる。
解析するxmlファイルはこんなやつを用意。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE infos [
		<!ELEMENT infos (info)*>
		<!ELEMENT info (id, status, datas?)>
		<!ELEMENT id (#PCDATA)>
		<!ELEMENT status (#PCDATA)>
		<!ELEMENT datas (data)*>
		<!ELEMENT data (#PCDATA)>
		<!ATTLIST data
				type CDATA #REQUIRED
				value CDATA #REQUIRED>
		]>
<infos>
	<info>
		<id>id1</id>
		<status>0</status>
		<datas>
			<data type="1" value="user@123"/>
		</datas>
	</info>
	
	<info>
		<id>id2</id>
		<status>1</status>
	</info>
	<info>
		<id>id3</id>
		<status>2</status>
		<datas></datas>
	</info>
	<info>
		<id>id4</id>
		<status>3</status>
		<datas>
			<data type="1" value="user@123"/>
			<data type="2" value="user@12345678"/>
			<data type="5" value="12345678"/>
		</datas>
	</info>
</infos>


ソースはここのやつを参考(というか丸パクリ)にして作成。
xmlからDOMを生成して頭から表示するプログラム。

#include <iostream>
using namespace std;

#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMElement.hpp>
#include <xercesc/dom/DOMNode.hpp>
#include <xercesc/dom/DOMText.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/sax/HandlerBase.hpp>
using namespace xercesc;

#define OK 0
#define NG 1

#define XMLFILE_PATH "sample.xml"

void writeNode(DOMNode* node);
void writeElement(DOMElement* element);
void writeText(DOMText* text);

int main(int argc, char** argv) {
	try{
		XMLPlatformUtils::Initialize();
	}
	catch(const XMLException& exp) {
		char* message = XMLString::transcode(exp.getMessage());
		cerr << "Xerces-C++ 初期化エラー" << endl;
		cerr << message << endl;
		XMLString::release(&message);
		return NG;
	}
	
	XercesDOMParser* parser = new XercesDOMParser();
	parser->setValidationScheme(XercesDOMParser::Val_Always);
	parser->setDoNamespaces(true);

	ErrorHandler* errHandler = new HandlerBase();
	parser->setErrorHandler(errHandler);

	
	try {
		const char* xmlFile = XMLFILE_PATH;
		parser->parse(xmlFile);
		DOMDocument* dom = parser->getDocument();
		writeNode(dom);
	}
	catch ( const XMLException& exp ) {
		char* message = XMLString::transcode(exp.getMessage());
		cout<< "Exception message is: \n" << message << endl;
		XMLString::release(&message);
		return NG;
	}
	catch ( const DOMException& exp ) {
		char* message = XMLString::transcode(exp.getMessage());
		cout<< "Exception message is: \n" << message << endl;
		XMLString::release(&message);
		return NG;
	}
	catch (...) {
		cout << "Unexpected Exception" << endl;
		return NG;
	}

	delete parser;
	delete errHandler;
	
	return OK;
}

void writeNode(DOMNode* node) {
	assert(node != NULL);

	switch( node->getNodeType() ) {
		case DOMNode::ELEMENT_NODE:
			writeElement(static_cast<DOMElement*>(node));
			break;

		case DOMNode::TEXT_NODE:
			writeText(static_cast<DOMText*>(node));
			break;
	}

	DOMNode* child = node->getFirstChild();
	while(child) {
		writeNode(child);
		DOMNode* next = child->getNextSibling();
		child = next;	
	}
}

void writeElement(DOMElement* element) {
	char* name = XMLString::transcode(element->getTagName());
	cout << "tag     :" << name << endl;
	XMLString::release(&name);

	DOMNamedNodeMap* map = element->getAttributes();
	for ( XMLSize_t i = 0; i < map->getLength(); i++ ) {
		DOMAttr* attr= static_cast<DOMAttr*>(map->item(i));
		char* attr_name = XMLString::transcode(attr->getName());
		char* attr_value = XMLString::transcode(attr->getValue());
		cout << attr_name << ": " << attr_value << endl;

		XMLString::release(&attr_name);
		XMLString::release(&attr_value);
	}
}

void writeText(DOMText* text) {
	XMLCh* buffer = new XMLCh[XMLString::stringLen(text->getData()) + 1];
	XMLString::copyString(buffer, text->getData());
	XMLString::trim(buffer);
	char* content = XMLString::transcode(buffer);
	delete[] buffer;

	cout << "content :" << content << endl;
	XMLString::release(&content);
}

実行結果。

tag     :infos
content :
tag     :info
content :
tag     :id
content :id1
content :
tag     :status
content :0
content :
tag     :datas
content :
tag     :data
type: 1
value: user@123
content :
content :
content :
tag     :info
content :
tag     :id
content :id2
content :
tag     :status
content :1
content :
content :
tag     :info
content :
tag     :id
content :id3
content :
tag     :status
content :2
content :
tag     :datas
content :
content :
tag     :info
content :
tag     :id
content :id4
content :
tag     :status
content :3
content :
tag     :datas
content :
tag     :data
type: 1
value: user@123
content :
tag     :data
type: 2
value: user@12345678
content :
tag     :data
type: 5
value: 12345678
content :
content :
content :

一応動いた。

最終的にやりたいのは、このDOMオブジェクトに対して、任意のtagを指定したアクセスなので、もう少し勉強してみる。

アジャイル×テストに行ってきました

今回はすくすくスクラムソフトウェアテスト勉強会のコラボ企画で、細谷泰夫さん(@yasuohosotani)による講演とワークショップ。

細谷さんの講演(スクラムと品質)

気になったトピックなど。

  • 品質が悪くなる要因は、オーバーコミットメント(能力以上の作業を割り振られる)、階層的な組織構造(実行不可能な計画を、実行可能な計画に戻すまでに時間が掛かる)が原因。こういったムリをチームで吸収させられることがないように、スクラムのルールが決まっている。
  • スクラムではバッファを必要としない(スプリント期間は変えない)。チームのベロシティに合わせてスコープを変動させる。スコープを縮める代わりにチームは品質を保障する。
  • チームの見積もりに対して、上司等の外部の人間が「もっと早く出来るんじゃないか?」とか言ってはいけない。ルール違反。
  • チームが情報を隠すのはルール違反。
  • ルールが守られないと、プロダクトの価値や品質が価格と釣り合わない結果になる。

こうして読むと、まっとうな事を言ってるだけに感じるんだけど、このまっとうな事が難しい。。
「スコープが変動する」事を客に受け入れて貰うのは簡単ではないと思う。このあたりは契約含めて考えないといけない話。
アジャイルの見積もりは全然勉強してないので、このあたりをどう持っていくかはまだ勉強が必要。


続いて、入社1~2年のC#未経験者を集めてC#での開発を行った話。

  • 入社1~2年の開発言語未経験の新人でも、短い期間(数日程度)で要求分析~テストを行うプロセスを繰り返し実行させたところ、短期間で成長が見られた。
  • 要求分析、方式設計は経験者の助けが必要だが、詳細設計、実装、テストは経験の浅いメンバーでも作業可能(支援は必要)。
  • 設計に原因結果グラフを使うことで、複雑なロジックのメソッドが作られることを抑止できる。

このアプローチは興味深かった。
確かに、実装したことない人間がまともな設計なんて出来るわけもないし、実装してみて、その反省をすぐに次の設計に活かせる環境だと成長するというのはよく分かる。手段として覚えておくとよさげ。

この後は、アジャイル開発とテスト品質に関する話。

アジャイルとテストについてのワークショップ

5グループに分かれて、グループ内の一人が携わっている開発の内容を題材にしてワークショップを実施。
うちのチームは、大学情報データベースを題材にした。

まず、大学情報データベースを、誰が、何の目的で使用するかの洗い出し。
f:id:mokky14:20131207232027j:plain

上げた人の中から、特にフィードバックが欲しい人を選択し、いつ、どんなフィードバックが欲しいかを考える。
f:id:mokky14:20131207232523p:plain

フィードバックが欲しい人達に対して、どんな順番でどんな機能を提供していくかを考える。
(画像ちょっとピンぼけ)
f:id:mokky14:20131207232604j:plain

フィードバックが欲しい機能に、どのような品質が必要で、その品質をどうやって確保するか考える。
ここでやっとテストの話になる。
f:id:mokky14:20131207232544p:plain

フィードバックばかりになって、テストで品質を確保するという方向にならなかった。「フィードバックを貰うための品質」がこのワークショップのテーマなので勘違いしてた。

アジャイル開発は、優先度が高い機能から順に早く提供していくための手法なので、テストで力を入れる所も、その機能の使用目的を果たせるように考える必要がある、というふうに理解した。

うちのチームでは、教員の情報を使用する人からのフィードバックを真っ先に貰った方がよいと考えて、データを使用する人からのフィードバックをスケジュールにしたけど、このスケジュールを説明したとき、実際に運用するのは事務の人だろうから、そちらから先にフィードバックを貰った方が良いんじゃないかという意見を頂いた。
どちらの意見が正しいとかがあるわけではないけど、「どこに価値を置くのか」の意識合わせって大事だなと改めて実感した。

アジャイルって何?」という人がチームに2人いて、その人たちの意見を引き出せなかったのはちょっと反省点。

ビアバッシュ

妻に参加OKしてもらったので、久しぶりにビアバッシュ参加。
ビアバッシュで聞いた話メモ。

  • 入社1年目だからやってくれるけど、これが5年目にもなると自分のやり方が出来てるので難しい。
  • 手が空いた人は、その時点で最も優先度が高い機能を実装するルールにしてる。その機能の実装に必要なスキルとかは考えないで割り当てられるので、知識の偏りが出ない。
  • ハードの人はアジャイルに理解がある。ハードはリリースしたら修正が効かないので、何度も試作品を作ってテストを繰り返すらしい。

後半はアジャイルウォーターフォールで盛り上がってた。
個人的には「アジャイルじゃなきゃダメだ」と言うつもりはなくて、ウォーターフォールアジャイルも開発の品質確保手段でしかないと思ってる。
ただ、アジャイル開発は、開発手法以上にユーザに提供する価値を考えることが重要なので、「言われた通りに作りました。何に使うのかは知りません」な開発者は相当な意識改革が必要になると思う(本来はアジャイルに限らず考える必要があるだろうけど、アジャイルはプロセスに考えるための仕組みが取り入れられているので)。そういう点でアジャイルをやってみたいな、と思ったりしている。

何か今回はあまりテストの話にならなかった。。

Linuxでiptablesとかフォワーディングとか

Linuxiptablesとかフォワーディングとか色々いじってたのでメモ。

※ ここで実行するコマンドは全てroot権限が必要。

複数のポートをまとめて指定

INPUTチェインで複数ポートへのアクセスをまとめて許可したいときとか、-m multiportモジュールをロードすると、複数ポートをまとめて登録することが出来る。

# iptables -I INPUT 8 -p tcp -j ACCEPT -m multiport --dports 53,80,8080

上記は送信先ポートに53,80,8080を指定する例。送信元のポート番号を指定するオプションとして--sportsもある。
なおmultiportモジュール使用時は-p で、tcpudp、udplite、sctp、dccpのいずれか指定が必須。なので、TCPUDP両方まとめて指定とかはできない。
(udplite、sctp、dccpについてはmanには記載なかったけど、-pを省略してコマンド実行したら以下のようなエラーになったので、指定出来るのだろうと判断)

# iptables -A INPUT -m multiport --dport 10000,20000
iptables v1.4.7: multiport needs `-p tcp', `-p udp', `-p udplite', `-p sctp' or `-p dccp'
Try `iptables -h' or 'iptables --help' for more information.

フォワード設定

フォワーディングの有効化

以下コマンドを実行する。

# sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1

フォワーディングが有効になっているか確認。

# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

1であれば有効。0だと無効。

上記だけだとOS再起動後は反映されないので、OS再起動後もフォワーディングを有効にするためには、以下ファイルの設定を更新する必要がある。

  • /etc/sysctl.conf
変更前 net.ipv4.ip_forward = 0
変更後 net.ipv4.ip_forward = 1
ルーティング設定の変更

フォワードするパケットの宛先、応答がある場合はその応答パケットに対するルーティングをルーティングテーブルに設定する。
設定方法はCentOS スタティックルートの追加とかを参考に。

フォワードするパケットの限定

上記設定だけだと、どんなパケットもフォワードしてしまう。
フォワードするパケットを限定するためには、iptablesでFORWARDのデフォルトポリシーをDROPにした上で、フォワードを許可するパケットのみを通すルールを追加する。

# iptables -P FORWARD -j DROP
# iptables -I FORWARD -p udp -i eth1 -s 10.1.1.0/24  -d 100.40.1.0/24 --dport 11111 -j ACCEPT

DNAT(送信先IPアドレス、ポート番号の変換)

natテーブルのPREROUTINGチェインに設定する。

# iptables -t nat -A PREROUTING -i eth1 -d 10.1.1.10 -p udp --dport 1000 \
 -j DNAT --to-destination 192.168.10.120:2000

DNAT先は 「--to-destination ipaddr[-ipaddr][:port-port]」 のオプションで指定。
ポート番号省略時はポート番号の変換はなし。IPアドレス、ポート番号は範囲指定可能。
複数の --to-destination オプション指定で、それらのアドレスを使用したラウンドロビンも可能。

SNAT(送信元IPアドレス、ポート番号の変換)

natテーブルのPOSTROUTINGチェインに設定する。
インタフェースはパケットを送信するインタフェースを-oで指定する。

# iptables -I POSTROUTING -t nat -o eth2 -p udp -s 10.1.1.0/24 -m multiport \
 --dports 1111,1112,1113 -d 100.200.1.0/24 -j SNAT --to-source 10.4.1.240:10000

SNATするアドレス、ポート番号は 「--to-source ipaddr[-ipaddr][:port-port]」で指定。
IP、ポート番号の範囲指定や複数指定についてはDNATと同様に可能。

コネクションのトラッキングを止める

iptablesでは、ある要求に対する応答を追跡してルールを適用する機能がある模様。例えば、natテーブルにDNAT設定したら、その設定によりDNATされた要求に対する応答にはDNATの逆の変換(SNAT)が行われる。
これを止めさせたいような場合、rawテーブルにNOTRACKターゲットを設定する。(やりたい人居るかは知らん)

# iptables -I PREROUTING -t raw -p udp -i eth1 -s 10.4.1.0/24  -d 10.1.1.0/24 -j NOTRACK 

なお、CentOS6では、rawテーブルの内容は、日本語のiptablesのmanにはなく、英語版のmanにしか記載がない。(2013/11/27時点での確認)

TRACE

パケットがiptablesの、どのテーブルの、どのチェインの、どのポリシーやルールを通っているのか確認したいとき、rawテーブルにTRACEターゲットを設定すると、カーネルログにTRACEの内容を出力することが出来る。

# iptables -I OUTPUT -t raw -p udp -o eth2 -j TRACE
# iptables -I PREROUTING -t raw -p udp -i eth1 -j TRACE

OUTPUTチェインに設定したTRACEは、自マシンから送信するパケットのトレース、PREROUTINGチェインに設定したTRACEは、自マシンが受信したパケットのトレースを取得する。
ログはカーネルログに出力されるが、CentOS6では、デフォルトのrsyslog設定ではカーネルログは出力しないようになっていたので、ログ出力時は、合わせてrsyslogの設定も変更する必要がある。
以下は、デフォルトの/etc/rsyslog.confのカーネルログの設定。

#kern.*                                                 /dev/console

なお、幾つかのパターンについてTRACEを取ってみた結果、以下の順番でチェインを通過していることが分かる。

  • 自サーバで受信するパケットが通るチェイン

raw:PREROUTING→mangle:PREROUTING→filter:INPUT

  • 自サーバより送信するパケットが通るチェイン

raw:OUTPUT→mangle:OUTPUT→nat:OUTPUT→filter:OUTPUT→mangle:POSTROUTING→nat:POSTROUTING

  • 自サーバが転送(FORWARD)するパケットが通るチェイン

raw:PREROUTING→mangle:PREROUTING→nat:PREROUTING→mangle:FORWARD→filter:FORWARD→mangle:POSTROUTING→nat:POSTROUTING



参考:

ルーティング
http://redhatlinux.kt.fc2.com/cont/router.htm

NAPT
http://saoshi.gooside.com/

iptables
http://ft-lab.ne.jp/cgi-bin/wiki.cgi?page=iptables
http://alpha-netzilla.blogspot.jp/2012/08/napt.html

rawテーブル
http://d.hatena.ne.jp/elf/20090310/1236615360

ソフトウェアテスト勉強会~メトリクスを使ってプロジェクトを診てみよう に行ってきました

先週行ってきたソフトウェアテスト勉強会の感想。
f:id:mokky14:20131123154920j:plain

今回はテスト技法ではなく、メトリクスの分析。

やってみた感想としては、これだけのデータがあっても、数字見ただけでは実際のところは分からないもんだな、というのが大きな感想。

自分が仕事でやったことあるのは、自分が担当するプロジェクトで、メンバーも知ってて、それぞれのメンバーの作成した設計書やソースを見ているというバックボーンがある上でメトリクス分析してたので、それなりの対策が出来てた(と思う)けど、プロジェクトの状況も分からなければメンバーも分からないという状況での分析だと、仮説は立てても推測にしかならないな、という風に感じた。

とは書いてみたものの、まずい点はそれなりに気づけるわけで、自分が気になった点を列挙してみる。

  • 機能テストで出たバグをシステムテスト期間中に修正しているものがあるけど、修正部分に対する機能テスト、システムテストは出来ているのか?
  • 5/7~5/10は消化した試験数の割にはバグが1件も検出されてないが、進捗遅れ挽回のために、仕様よく分かってない人投入してテストさせるとかしてないか?
  • 試験外で見つかったバグが多い機能(特に沸騰機能)は試験項目の抽出には問題なかったのか?
  • バグのオープン日が長い機能の修正に時間掛かった理由は?大幅な改修が必要だったのであれば機能テスト、システムテストのやり直しが必要になるのでは?
  • システムテストで見つかったバグに、機能テストレベルのバグが含まれていないか確認した方がよいのでは?(機能テストの抽出が十分に行われているかの確認のため)

色々と怪しいところはあるものの、机上分析結果なので、実際に問題なのかは分からない。
そもそも分析した数値がどれくらい正しいものなのかも分からない。今回の演習のメトリクスも、休日出勤を誤魔化と思われる数値だったし。
自分の経験としても、炎上してるプロジェクトほどメトリクスの数値を誤魔化したり適当に付けてることが多い気がする。そもそも取ってないところもあるし。このあたりは、問題が発生してからメトリクス確認するんじゃなく、小まめに問題がないかをチェックしていく必要があるんだろうと思う。
勉強会の中で@nemorineさんも言ってたけど、出来る限り、実際の現場に足を運んで状況を確認した方がいいんだろうな。

メトリクスって、取得するデータが増えるほど現場には負担になる。最近は短納期の開発やアジャイルな開発が増えてきていて、あれもこれも取ってると、メトリクス取得の負荷が大きすぎる。
なので、開発どんなメトリクスを取れば品質確保出来るんだろうなーと思ってたところに、ちょうどよいイベントが。
アジャイル×テスト
まだ空きがあるようなので、興味がある方はどうぞー。

原田さんと遊ぼう DDD×Scrum に行ってきました

ゆるいイベント名ですが、内容はガチのワークショップでしたw
プライベートでの来仙にも関わらずワークショップ開いて頂いた原田さん、とりまとめの木村さんありがとうございました。

ワークショップのテーマは2チームでそれぞれレンタルサイクルのモデルを考えるというもの。
まずは1店舗で自転車を借りて返すという単純なモデルを考えるところから始めて、最終的には、借りた店と返す店が別の店でもOKというモデルにする。

で、チームであれこれやってみましたが、
f:id:mokky14:20131102121724p:plain
結果、1スプリントも回らず、全くScrumにならなかった。

最初のモデル検討はあれこれと議論になるけど、「これで行けるかな..?」という状態になったら、そこから話が進展せずに時間浪費。とりあえず実装してみると、実は処理もテストシナリオも書けないという状態だったことが分かったりしてた。色々と考えて設計しても実装してみたら実は決まってない部分があるなんて、普段の業務でしょっちゅう経験してるのに。。
TDDBCで言っていた「対象を小さくして、一つずつ相手にする」ということが全く出来てなかったんだなと。モデルを熟考してから実装に入ってたけど、最初に実現するシナリオ決まったらあれこれ考えず、さっさと実装してみた方がよかったのかも知れない。

で、ふと思い出したのが、TDDBCのときに出てたこの図。
f:id:mokky14:20131014003130p:plain
Scrumで進めるなら青い線(設計が汚くても動くコードを優先)で作業を進めるべきだったんだろうけど、赤い線(綺麗な設計が出来てから実装する)の方になってた気がする。この意識も変えていかないといけないんだろうな。

ちなみに最後に原田さんから模範解答的に提示されたモデルはすごくシンプルなモデルだった。アナパタの一種らしい。
f:id:mokky14:20131102233719p:plain
チームで検討してたのはビジネスを表すクラスの設計だけで、「自転車の場所」がコアドメインだというところまでは全然及んでなかった。

TDDもDDDもまだ自分の身になってないことを痛感。。
もっと素振りが必要だ。

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)