Developers summit 2012 行ってきた

devsumiねデブサミ。今年も行って来ました。
17日午前中だけなんですけどね…色々と厳しい状況だったけどJenkinsだけはききたかったので!

「Continuous DeliveryとJenkins」

概要(記憶に残ったのだけ書いとく)
  • マシンの性能は上がっている。一方人の性能は変わらない→それなら自動でできることはマシンにやらせるべき
    • 高性能マシンを並列化しまくったら時間もかからないしコスト削減になる
    • というか時間=コストってことだもんなぁ、人月計算してる以上はと思ったりした
  • 人の性能は変わらんのでコード書く速度はそんなに早くもならない(むしろ大規模になると低下したりもする?)
  • 削れる時間はビルド時間、テスト実行時間→そこでCIツール
  • ただCIツールを入れるだけでなにもかも解決するわけではない
    • たいていはバージョン管理をしているが、サブミット(コミットとかチェックインとかツールによっていい方は様々だが要するにファイルを共有サーバに入れることだ)する前にビルドが通ること、などというルールがあったりすると、結局ローカルでビルドして直して…となってなかなかサブミットできないし、CIツールの意味がないし、ローカルの環境よりサーバのほうがスペック言いに決まっとる
    • 現状でうちでもビルドと単体テストと動的メモリテストなんかはJenkinsを使っているが、基本ローカルで単体テストに通ることを確認してから入れる決まりになっている。んで、うちはC++つかってるんだが、でかいやつになるとビルドに5,6分はかかる…ちょっと直してデバッグしてビルドして…で一日かかるとかザラ
  • なので、ビルドはもう完全にCIツールに任せてしまいましょう、という話だった。
  • あとこれとパイプライン方式を混ぜればなんかうまいこと運用を考えられそうだ
  • とりあえず思ったのは、
    • コードサブミット用ブランチをひとつ作る。開発者はここにビルド成功するかどうか分かんないけどとりあえずコードをサブミットする
    • Jenkinsはサブミットされたらビルドを開始する。ビルド中開発者は別の所を修正したりテストを書いたりとかしておく
    • ビルドが失敗したらメールが来る。開発者は直してサブミットしなおす
    • ビルドが成功したらJenkinsがテスト用ブランチにサブミットする。サブミットがあるとテスト用ブランチで自動テストが走る。失敗したら(ry)。成功したら次のブランチもしくはマスターブランチにサブミット
      • 問題になりそうなのは衝突が起こった場合だな。これはやっぱり手動でしないといけないかもしれない。
      • あといま、自動メモリテストのジョブが成功したら自動的にリリースビルドのジョブが走るようにしてるので、*用ブランチというのをいくつも作らんとサブミット用ブランチ一つとマスター用ブランチでよいかもしれない
      • Perforce連携のプラグインてないんですかね…

「仕事のバトン、渡っていますか? - プロジェクト管理におけるコミュニケーション基盤作り」

どうしようかなーと思ったんだけど一応行ってみた。ちょうど課題管理のことは問題になってるので。ちなみにうちはRedmineをつこうております。
記憶に残ったとこだけ

  • 課題管理は特に理由がないのならExcel最強
    • まぁたしかにそうだけど使いたくないよ
    • 人数多くなるとバージョン管理ツールで管理するのが辛くなる。マージできないし
    • ただ時間軸での管理はExcel最強
  • 曖昧なトリガはチケットとしては不適当。結局グレーのまま放置される
  • はっきりとしたバグとかそういうのだとチケット駆動にはしやすい
  • チケットの内容は丁寧に書きましょう
  • チケットは共有しているものだという意識を持ちましょう
  • 計画段階切っていくチケットはよっぽど慣れていない限りあんまり有効でない。計画の段階では大抵のことは曖昧なため(もしくは曖昧なこともわからない(まぁあるあるですな
  • あとツールはいくつも使うな(あるあるすぎますな
    • メール、電話の内容も全部課題管理表に書きこむこと(うちはこれをバージョン管理ツールでやってしまっている

いやあ本当にまっとうなことばかりだったのですみませんという感じでした。

Wordpressではてな記法を使えるようにしてみた。

http://rewish.org/wp/hatena_notation_plugin
こういうありがたいプラグインが!

今のところ記事ごとに切り替えというのができなくて、会社ローカルで導入する際にpukiwiki記法との併用が出来なかった(pukiwikiでかくとhtmlで吐き出されてしまう)のでちょっとだけカスタマイズした。突貫工事なのであってるかどうかは不明。

wp-hatena-notation.phpにあるrender関数を

public function render($content)
	{
		$tag = '/\[hatena\](.*?)\[\/hatena\]/s';   //追加
		preg_match($tag, $content, $matches);    //追加

		if (!isset($this)) {
			return self::getInstance()->render($content);
		}
		if (empty($this->option['after_enable_date']) && strstr($content, '[hatena]')) {    //条件追加
			return $this->_render($matches[1]);    //代入文字列変更
		}
		global $post;
		if ((self::df($post->post_date) > self::df($this->option['after_enable_date'])) && (strstr($content, '[hatena]'))  ) {    //条件追加
			return $this->_render($matches[1]);    //代入文字列変更
		}
		return $content;
	}

とかきかえた。これで[hatena]〜[/hatena]でくくったところははてな記法になるはず――なんだけどなぜか1ポストまるまるはてな記法になるのであれ?と思っているところ。うーむ。一応記事ごとの切り替えは出来ます。

あとはxoops上のwikiWordpressに吐き出さればいいんだが、エクスポートできないのか?プラグインどれ入れりゃいいのか全然わからん。。。

非Web屋の俺がOpen Flash Chartを使ってみた

いろいろと詰まったけど慣れてる人なら簡単に導入できると思われ。

Open Flash Chartとは

公式:http://teethgrinder.co.uk/open-flash-chart-2/
参考:http://fujitaiju.com/blog/php/open-flash-chartver2-x%E3%81%A8php%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%82%B0%E3%83%A9%E3%83%95%E3%82%92%E6%9B%B8%E3%81%8F%EF%BC%88%E5%B0%8E%E5%85%A5%E7%B7%A8%EF%BC%89/

Open Clash Chartとは、ウェブ上にFlashでグラフを描画するためのオープンソフトです。PHP, Ruby, Perl, Js< Pythonなどなどで使えるようです。DotNetもあるみたい。
仕事でwebUIをつくらんといけんくなった(デモ用)のでちょいちょいと使ってみた。
俺はWeb屋さんじゃないのでアパッチ起動するだけで一苦労です。
基本的にコンパイラのある言語しか使ったことないので、デバッグの仕方がわからNEEEE!!!

環境としてはRHEL 6.0 Enterprise 64bit, Apache2.2.18, PHP5.2.17を用意しました。エディタはしょうがない(?)のでEclipseプラグインを導入。Windows環境だったらxamppを導入すればオールインワンのはず。CentOSだと最新版がダウンロードされないかもしれないのでyumの設定を書き換えましょう。ここでは割愛。

Apache+PHPを最新版にしよう

古いのが入っていたので最新版へ。まぁいろいろなところにいろいろなことが書いてあるので今さら俺が書いてもしょうがないかもしれんが、一応。

Apacheの最新版をダウンロードして展開、インストール

さくっとな。
ひとつ気をつけないといけないのは、たぶんRedHatに最初から入っているApacheはconfigureのオプションでlibファイルを生成するオプションが有効になっていないっぽい。なので、単に./configureとするとその後でPHPのlibphp5.soができないらしい。これで一日死んだ。
参考:http://oss.poyo.jp/pipermail/php-study/2006-October/000309.html

$ tar zxvf httpd-x.x.x.tar.gz
$ cd httpd-x.x.x
$ ./configure --enable-so {ほかオプション}
$ make
$ make install

なお、Apache2.0は/usr/local/apache2以下にファイルが展開されます(特に指定しなかった場合)。ほんでもって実行ファイルは/usr/local/apache2/bin/httpdなんだけど、それを実行するスクリプトは/usr/local/apache2/bin/apachectlらしい。
展開したフォルダ/build/httpd.initを/etc/rc.d/init.d/httpdに移動して設定を書き換えるてサービス化すると、apachectlと/etc/rc.d/init.d/httpdスクリプトが両方叩かれて二重起動→80番ポート空いてないんですけど?って怒られる。
詳しい設定方法は詳しく書いているところがあると思うのでそちらを参照してください。
これがわからなくて一日死んだ。

PHPの最新版をダウンロードして展開、インストール

rpmがありゃ楽なんだけどなぁ。ま、さくっとな。libphp5.soファイルを作成するためにapacheのapxsが必要なようだ。
参考:http://www.oklab.org/language_c/php5_0_2_install_bug.htm
特定環境って書いてるけど、多分RedHatapacheのオプションの設定のせいだと思われ。

$ tar zxvf php-x.x.x.tar.gz
$ cd php-x.x.x
$ ./configure --with-apxs2=/usr/local/apache2/bin/apxs {その他オプション}
$ make
$ make install
$ su root find / -name libphp*

これでlibphp5.soがあればOK
libファイルを適当(適切という意味)なところへコピーして、あとはapacheを起動する。

cp /usr/local/apache2/modules/libphp5.so /usr/lib64/httpd/modules/libphp5.so
service httpd start

phpinfoを実行してhttpdphpのバージョンを調べよう。php知らない人のために書いておくと

<?php 
	phpinfo(INFO_MODULES);
?>

というファイルを作ってデフォルトだと/var/www/html/の下に置く。なおブラウザで閲覧する場合は
http://localhost/ファイル名
としてみよう(←それすら知らないのだった
http://localhost/ = /var/www/htmlです。これはhttpd.confのDocumentRootで変更可。
Forbiddenが出てしまう場合は
参考:http://www.cyberciti.biz/faq/apache-server-status/
とりあえずDeny from allをコメントアウトしとけばよいのかしら。

ようやくOpen flash chartへ

導入はとても簡単。/var/www/html以下にファイルをダウンロードしてきて展開すれば使えます。
なおOpen flash chartはv2.xになっているにもかかわらずググるとv1.xの方が上位に表示されるので注意。
公式(こっちね):http://teethgrinder.co.uk/open-flash-chart-2/
v1.x:http://teethgrinder.co.uk/open-flash-chart/
メソッド名やプロパティなどが変わっているので互換はない模様。

基本的にはチュートリアルのとおりやっていけばOKです。open-flash-chart.swfのパスの設定を忘れそうなら、同じフォルダに配置するのが吉。

とにかくやってみる。
<html><head>
<!-- グラフ表示のためのJsとフラッシュファイルを指定する -->
<script type="text/javascript" src="../../ofc/js/swfobject.js"></script>
<script type="text/javascript">
	swfobject.embedSWF("open-flash-chart.swf", "data", "550", "200", "8.0.0", "expressInstall.swf", {"data-file":"chart_data.php"});
	swfobject.embedSWF("open-flash-chart.swf", "data1", "550", "200", "8.0.0", "expressInstall.swf", {"data-file":"chart_data1.php"});
</script>
</head>
<body>
<!-- グラフを挿入する -->
<div id = "data"></div>
<div id = "data1"></div>
</body>
</html>

いきなり二つ表示させる場合をかいてしまいましたが。
swfobject.embedSWFの引数に

  • フラッシュのファイル
  • グラフのnameに当たる名前
  • グラフのwidth
  • グラフのheight
  • フラッシュのバージョン? 8.0.0または9.0.0とかいておけばよいぽい。10.0.0でもいいのかな
  • 複数のファイルを表示する場合は後ろの二つの引数が必要。expressInstall.swfはようわからんがおまじない
  • 最後の引数は{"data-file":"グラフに描画するデータ・グラフ設定について書いたphpファイル"}とする


ちなみに一個しか表示しないよという場合は後ろの二つの引数は省略できます。そのかわりブラウザに表示するときは
http://localhost/disp.php?ofc=chart_data.php
などとしないといけない模様。"?ofc="とかいてデータファイルを食わせるんだね。

さて、肝心のデータファイル

これもとりあえずTutorialに書いてある通りに書けばできるが一応。

<?php
	include 'php-ofc-library/open-flash-chart.php';//php5-ofc-libraryとしたほうがよいのかもしれない
	
	//create dammy data
	$data = array();
	for($i = 0; $i < 10; $i++){
		$data[] = $i;
	}
	
	//set title
	$title = new title("TITLE");
	
	//set line
	$dot = new dot();
	$dot->colour('#cd5e3c');
	$line = new line();
	$line->set_defaultdot_style($dot);	//hoverするとドットが表示される
	$line->set_values($data);	//データを与えてやる
	$line->set_width(3);
	$line->set_colour('#68bd8d');
	
	//set y axis
	$y = new y_axis();
	$y->set_range(0, 15, 3);
	
	//set chart chartを出力するとブラウザ上に表示できるようになる
	$chart = new open_flash_chart();
	$chart->set_title($title);
	$chart->add_element($line);
	$chart->set_y_axis($y);
	
	echo $chart->toString();
?>

chartに作った設定をくっつけてやると表示されます。結構C#ぽい実装なのでわかりやすい。

データベースからデータを取ってきて描画してみよう。

データベースはMySQLでもいいんだけど情報がないのでPostgresについて書いてみる。
表示用のPHPは大して変わらんのでそのままにしておくとして、チャートデータの方。

<?php
	include 'php5-ofc-library/open-flash-chart.php';
	//データベースを開く postgresというユーザーでpostgresという名前のデータベースにログイン
	//失敗した場合はその場で死ぬ
	$db = pg_connect("host=localhost port=5432 dbname=postgres user=postgres password=postgres") or die("failed to connect");
	//データを取ってくる 
	$tableName = 'testdb';
	$result = pg_query($db, "SELECT * from {$tableName};") or die ("faield to query\n");
	//fetchで実際にデータの値が取れる
	$data_all = pg_fetch_all($result);
	pg_close($db);
	
	//連想配列のままでは描画できないので項目ごとにarrayに分ける
	$data1 = array();
	$data2 = array();
	
	foreach($data_all as $key=>$tmp){
		$data1[] = intval($tmp['data1']);	//文字列で入ってくるらしいので数字に直してやる
		$data2[] = intval($tmp['data2']);
	}
	
	if(count($data1) == 0) die('An error occurred\n');
	
	$title = new title("TEST");
	
	$dot = new dot();
	$line = new line();
	$line->set_default_dot_style($dot);
	$line->set_values($data1);
	
	$bar = new bar_filled('#999', '#aaa');
	$bar->set_values($data2);
	
	$chart = new open_flash_chart();
	$chart->set_title($title)+
	$chart->add_element($bar);
	$chart->add_element($line);
	
	echo $chart->toPrettyString();
?>

文字列ってところがわからなくてかなり死んだ。
ただま、出来ちゃうとすごく簡単かな。日本語ドキュメントは少ないけど公式にもソースコードが乗っているのでそんなに困らないはず。

HudsonからJenkinsにアップデートしてみたら見事に嵌まった件

オラクル嫌いの上司からJenkinsに変えろと脅迫されたのでぽちっと(ぽちっとじゃないな)Jenkinsに変えてみました。や、まぁ楽だったんだけどね。本体は。

マスターがRedHat, スレーブがCentOSのマシンにインストールしました。

If you've previously imported the key from Hudson, the "rpm --import" will fail because you already have a key. Please ignore that and move on.

とのことなので、そうするしかなかったんだよ。

Jenkinsのインストール

yumが使えなくなっている(これだからRHELはいやなんだ)のでさっくりrpmをダウンロードしてインストール。あと俺はいつもこういうときめんどくさいのでroot権限で作業しております。

# ちゃんと止めてからやりましょう
$ /etc/init.d/hudson stop
# rpmパッケージのインストール
$ rpm -ivh [パッケージ名]

でOK。/var/lib/jenkinsができているかどうかを確認する
hudsonはそのまま残ってたけど、設定などは全部コピーされた模様。簡単だしすごく楽。ありがたいねー。ユーザーも全部作成してくれてるし。

フォルダの権限を確認

たぶんよほどのことがない限り大丈夫だと思うけれど一応。

$ ls -la /var/lib/jenkins

でフォルダの権限がjenkinsになっていることを確認。なっていない場合は

$ chown -R jenkins:jenkins /var/lib/jenkins

で変更しておくこと。

起動

$ /etc/init.d/jenkins start

たまに忘れるんだよねーあるよねー(俺だけだよ

マスターはここまで。
次はスレーブの設定。

スレーブを設定している場合

サニティチェックを別のサーバーでやらせている(時間がかかるので)ので、こちらにも設定が必要だった。自動ではやってくれないそうです。まぁそうか。
スレーブの起動とコマンドの実行はマスターがトリガをかける設定。設定自体はいいんだけどね…SSHの設定し直したのにPermission deniedになっちゃって起動しないので困った。
答えはjenkinsアカウントがスレーブに存在していなかったためだった。そりゃ拒否されるわ。

アカウントを作成する

まずjenkinsというアカウントがないので作る。設定は元々のHudsonのにあわせるために使うシェルはbashで、ホームディレクトリは/var/lib/hudsonで。パスワードはユーザー名と同じ。

$ useradd -d /var/lib/hudson -s /bin/bash jenkins
$ usermod -p jenkins jenkins

一応確認のため

$ id -a jenkins
$ grep jenkins /etc/passwd

でuidが100番台、パスワードがjenkinsに設定されていればおそらくOK。

おもむろにディレクトリの権限を変更する

$ chown -R jenkins:jenkins /var/lib/hudson

ディレクトリ名はめんどいので変えてません。

SSHの設定(パスワードを入力しなくてもログインできるようにする)

公開鍵RSAの設定に関してはいろんなところに描いてあるけど、まぁ一応書いておくか。
http://www.geocities.jp/turtle_wide/tools/sshpass.html

# jenkinsになる。(パスワードはjenkins)
$ su jenkins
$ ssh-keygen
# このあといろいろ聞かれるけど全部なにも入力しないこと!
# Your public key has been saved in /home/foo/.ssh/id_rsa.pub.
# と表示される場所にRSA認証の公開鍵ができるのでこれをリモートの/var/lib/hudsonにコピーする
$ scp /home/foo/.ssh/id_rsa.pub jenkins@hostname(もしくはIP):/var/lib/hudson/.ssh/

# ここからはスレーブサーバーでの作業
$ ssh jenkins@hostname
$ cd /var/lib/hudson/.ssh
$ touch authorized_key2

# 必ず600に設定すること!
$ chmod 600 authorized_keys2

$ cat id_rsa.pub >> authorized_key2

たまにやると忘れてるんだよなーとか思いつつさくさくと。


なんか執事みたいなマークが出てくるからうける。


追記:

javaが入ってないサーバにインストールする場合

jdkORACLEからインストールする。/usr/bin/javaがないと起動時に怒られるのでシンボリックリンクをはっておけばおK。
とりあえず特に何も考えずにjdkをいれると/usr/local/jdkほにゃらら/bin/以下にjava, javacができるので

ln -s /usr/local/jdkほにゃらら/bin/java /usr/bin/java
ln -s /usr/local/jdkほにゃらら/bin/javac /usr/bin/javac

として

java -version
javac -version

でバージョン情報が表示されれば問題なし。

ファイアーウォールの設定

/etc/sysconfig/iptablesを編集して

-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT

と追加する。Rejectよりは前に書いとかないといけないらしいけどtcp acceptグループのところに書いとけばまぁ間違いないでしょう

ふと思いついたので特定コアに処理を割り当ててみた

スレッド(C#の場合はデリゲート)を使うと、「プログラムは上から順番に実行される」原則が覆され、う ち ゅ う の ほ う そ く が み だ れ る!
と思ってしまう。それが初心者クオリティ。

参考:

やってみた。以下サンプル。

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <sched.h>
#include <pthread.h>

using namespace std;

pthread_mutex_t mutex;


int set_cpu_id(int cpu_id)
{
	cpu_set_t mask;
	__CPU_ZERO(&mask);
	__CPU_SET(cpu_id, &mask);
	
	if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
		std::cout << "Failed to set CPU affinity. " << endl;
	}
	else 
		std::cout << "Succeed to set CPU " << cpu_id << "affinity. " << endl;
	
	return 0;
}

uint32_t waste_time(uint32_t n){
	uint32_t i = 0;
	while (i < n*200000) {
		i++;
	}
	
	return i;
}

void* thread_main(void* pData){
	int* cpuID = (int*)pData;
	set_cpu_id(*cpuID);
	uint32_t num = waste_time((uint32_t)cpuID);
	
	std::cout << "count " << num << endl;
	pthread_exit(NULL);
}

int main(){
	pthread_t tid1, tid2;
	int num1 = 5, num2 = 6;
	int* cpuID1 = &num1;
	int* cpuID2 = &num2;
	
	pthread_mutex_init(&mutex, NULL);
	
	pthread_create(&tid1, NULL, thread_main, cpuID1);
	pthread_create(&tid2, NULL, thread_main, cpuID2);
	
	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);
	
	pthread_mutex_destroy(&mutex);
	
	return 0;
}

たまにガイドラインを読むと非常に面白いのである

"An error occurred while creating an error report" この例では、問題を示す文が非常に風刺的で、解決策も提示されていません

http://msdn.microsoft.com/ja-jp/library/aa511267.aspx

これはクソ笑った。
MSは実は要所要所に面白いものを挟んでくるのがうまい。iOSガイドラインは笑えるところなかったなぁ。



ちなみにGUI設計のポリシーはMicrosoftiOSでは微妙に異なっている。Microsoftは「できるだけユーザーに取って有用な情報をできるだけ与えろ、でも一気には見せるな。階層構造を作りグルーピングしろ」だけど、iOSはそれを載せるマシンの性質上の問題もあるのか、「できるだけなにも見せず選択をしなければならない場合にだけ見せろ、見せるときは階層を作るな。人目で全てに目が通せるようにしろ」というポリシーの様子。んーまー一長一短すな。そしておいらはほとんどCUIアプリケーションばっかり作ってるのであまり関係ないのだった。

僕がテストについて思うこと

単体テスト好きというよりはモックの素晴らしさを喧伝したくてしょうがない僕ですが、モックいいよ!(それだけか(大好きなんだけどまだうまく伝えられるまでになっていない俺

Twitterで#devsumiおっててちょろりとTDDの話を見かけたときに深く感銘を受けました。そのとおりだ。


僕は全くスキルのないへなちょこプログラマの卵(まだへなちょこにすらなれていない)ですが、そういうひとほどテスト、特に単体テストを書くべきだと思う。理由はとっても簡単で、勉強になるから。副次的な理由でちょう簡単な間違いやバグをいれこまなくて良くなるというのもあるけど、メインは勉強になるからだなぁ。
いまJSTQB(JSQTB?)の資格取るために適当な勉強をしているところなんだけど、テスト(レビュー含む)って教育の意味合いを含んでいるものが少なからずあって、まぁなんでかっつーと人の書いたコードや設計を理解しないとできないからなんだよね。特にレビューはね。レビューをされることで勉強になるだけではなく、することでもわかるようになることはとてもたくさんある。ましてや単体テストは第三者の書いたコードを読み、仕様を読み解き、設計の意図を理解し(隠蔽されててテストできねーとか言いながら)、というのが一気にできるのだ。こりゃなかなかない機会っすよ。僕も別にもう若くはない(職歴は短いが)けど未だに卵な訳で、これから先すーぱーはかーやすーぱーぷろぐらまーになれる予定はないと思うけれども、自分自身を成長させることはできるんだよね。

テストは、一人でも始められる。全く賛同されなくても始められる。いつからでも始められる。ひどいレガシーコードが目の前にあっても修正することはできないかもしれないけれど、テストを書くことはできる。最初から全てを書くことはないのだ。出来るところから手をつけていき、一つ一つ成功するテストケースを書き上げていけば、最後には必ず整然とした動きの理解できるプログラムが出来上がる。それをたった一人で始めることができる。どんなにスキルがなくても、言語に対する知識がなくても、アルゴリズムや設計がわからなくても、レガシーコードはたくさんのことを僕に教えてくれる。こんがらがった醜いコードには数えきれない教訓と学ぶべき事柄が眠っている。
テストを書こう。テストを保守し、プログラムを守ろう。