top-image

LATEST ARTICLES

Twitterで何か作りたいとか言ってたら、@lasting_xxxからお声がかかったので行ってきました。

javaとか普段書かなくなってたけど、書けない事はなかったです。

さて、何をして来たかといういうと、へぇボタンのバージョンアップのお手伝いをしてきました。

もともとは、@ken_b4u@lasting_xxxがハッカソンで時間のない中で作ったもので。

こいつに設定機能を追加してやると。

まず、このへぇボタンはTwitter連携していて、ボタンを押す毎に「へぇ」と音声出力 and Twitter投稿がされるもの。

ここにTwitter投稿のON/OFF、投稿内容の設定を出来るようにする。

だって、押すたびにTwitter投稿されちゃったらTLがアレな感じになっちゃうもんね、と。
 
 
やったこと:

①起動時のAlertDialogによるTwitter投稿の設定

②Preferencesでの設定内容の保存

③設定画面の作成

※詳しくはコチラをご覧ください。
 
 
で、自分が主にやったのは②の部分です。

そもそもAndroidアプリ開発なんぞ、入門本をちょこっとやったのみ。

ほぼ教えてもらいながらです。

で、画面が増えてActivityクラスが複数個になったのでインターフェースにしよう、抽象化にしようと思って、結局、普通に親クラスを作成したりしました。

設定情報を共通化するため、getter/setterなどが必要になったので。

javaってこういう時にクラス設計とか楽しい。

まあ、オブジェクト指向なら言語関係ないかもしれないけど、javaは型も強いし、特にそのへんを感じます。

ここでサボると後々大変だぞーって脅されてる気すらします。

で、重要な部分は@ken_b4uにまかせたので、アプリ開発については本当に②の部分を覚えて帰った気がします。

今回はアプリ開発も楽しかったのですが、githubを初めて使いました。

これがまあ、便利で・・・マージとか、マージとか。
 
 
感想

最初、諸々の設定をしてもらったり、途中、お好み焼きを頂いたり、と、至れり尽くせり、本当にありがとうございました!

色々と最初の一歩が踏めたと思うので、これからも開発していきます!

BTSというか最近ではITSなRedmine。

仕事でも使用しており、さっさとワークフローなど固めていきたいと思っているため、これは良いと参加して来ました。

勉強会はブログに書くまでが勉強会、ということでサクッとメモなり感想なりを書いておきます。

()でくくった部分は感想です。

あくまで個人的です。

———————————————————————-

http://shinagawa.redmine.r-labs.org/projects/shinared/wiki/%E7%AC%AC%E4%B8%80%E5%9B%9E%E5%8B%89%E5%BC%B7%E4%BC%9A

日時:2011/09/08 19:00~21:00
会場:文京グリーンコートセンターオフィス
目的:Redmineの発展、普及、情報共有
ハッシュタグ:#47redmine

講演:
「障害管理からチケット駆動開発へ@あきぴーさん」
・Excelによる障害管理の課題
⇒バグ情報が散在して混乱しやすい
⇒バグが増えて行くと手に負えない
⇒Excelやメールに作業履歴が散らばっている
 (進捗が分かりにくいですよね。下手したら漏れも発生するし)
⇒バグ集計や報告書作りに手間がかかる
 (↑にもあるけど一元管理できないことが多い)
⇒バグ集計と検証のワークフローが複雑
 (確認者との連携がうまくいかない場合があったりしますよね)
⇒リリース管理が大変
 (リリース毎にエクセル管理は本当に面倒)

・BTSの特徴
⇒バグの情報をチケットで一元管理
 →チケットに作業履歴を集約
 →過去のバグを検索・集計が楽
  (作業履歴で新規メンバーへの引継ぎ的にも使用できますよね)
⇒チケットのステータス繊維で制御
 (これをメンバー間で守れないと使ってても意味ない気がします)
⇒終了チケットが残せる

・BTSからITS
BTSを拡張した課題管理システム
Wiki1など

・チケット駆動開発
Tracのチケット管理から生まれた
→TDD
→チケットなしのコミットはしない
→TiDD

・チケット駆動開発の意義
BTSをアジャイル開発のタスク管理への適用
BTSのワークフロー管理をSW開発全般への拡張
トレーサビリティで変更管理をサポート
ツール進捗で新しい運用方法を見いだす
(チケットだと作業が明確でリーダー・メンバー間の認識のずれが起こりにくいですよね)

・Agile化したチケット駆動開発
SW開発の3種の神器
(これマジ重要)
→ITS
→SCM
→CI

「RedmineのSCM機能@丸山さん」
→コミッタになった経緯、Redmine開発など
(Redmine自体の開発については知識がなさ過ぎて話がついていけませんでした)

「私のRedmineの使い方@中村洋さん」
RxTStudy
・Redmineとタスク管理の勉強会
事例紹介
・ある3つのPJのお話
1:メンバー全員が初めて
⇒カスタムクエリを工夫
GJ:
プログラミング好きのリーダーが楽しそうだった!
今やる事に集中出来た
BAD:
チケットが大き過ぎた→粒度を細かく(1チケット2.5〜4時間
(これが最初の課題ですよね)
2:2回目のPJ
・自分がリーダー
ほぼチケット駆動開発
ガントチャートはマイルストーンのみ
イテレーション毎に動くものを見てもらった
(コンセンサス重要っす)
GJ:
チケットを取るようになった(メンバーもチケット発行
(この状態になったら軌道に乗ってるんだと思いました)
余計な管理作業がなかったので、実装に集中出来た
追加仕様がなく、良い評価!(イテレーション毎に確認していたため
BAD:
マネージャからガントチャートをみたいと言われた
→Redmineを見せてとにかく説明
3:社内向けシステム/東京大阪で開発
経験豊富なメンバーが多く、チャレンジ出来る環境だった
管理者権限GET!プラグインなどを導入した。
・チケット駆動開発
・Scrumで開発
GJ:
トレースしやすくなった(仕様が決まった経緯なども分かった
プラグイン/CodeReview/BurndownChart/WorkTime/RedmineGraphActivities
三種の神器を連携させると色々と楽
Bad:
他のチームへの展開が課題

まとめ
・5年間を振り返って
言いたい事は2つ
1:Redmineはあくまでツール。銀の弾丸じゃない。日常のプロセスやマインドを変えていくこと!
 (最終的には人が使うってことを忘れちゃいけない!)
2:メンバーやリーダーの振る舞いが変わる。リーダーがタスクを割り当てる、ではなく、メンバーがタスクを割り当てる。
チームでコミットメントする!!トップダウンでやらせる感じではなく、使ってもらう立場から、、母性的な・世話役的な感じで接する。

LT:
「Redmineを利用した定量的プロジェクト管理」
⇒ITプロジェクトと見える化

「うちのRedmineの使い方」
システム運用の現場から
⇒議事録はWikiに書く(履歴/回覧チェック/変更リマインダ
⇒朝会のすすめ(開発だけじゃない。全員がしゃべり、得手不得手を補う。
⇒工数集計work_time(チケットの工数付替できる

「プラグイン開発者への道」
⇒プラグインジェネレーター
⇒Ruby on rails
⇒Rlabsに登録する!

まとめ
参加した理由としてRedmine運用をどのようにやっているかを知りたかったからがありました。
色々な話が聞け、特に「Redmineの使い方」というのは本当に参考になったと感じてます。
個人的にもRedmineを使用しており、ゆくゆくは開発だけではなく、運用も巻き込んだかたちを考えていたため、成功例として最高だったと思います。
本当に感じるのですが、使ってるというより使わされてる感が出てしまうとこういったツールは本来の意味をなさなくなりますよね。効果半減というか。。
これはどこでも同じことで、リーダーとメンバー間でコミュニケーションが上手く取れてないと結局は使わないほうがマシなんてことになりかねないです。だからこそ、コンセンサスを取って、良い方向に進めていくことを忘れず、積極的に動けるようにしておかないといけないと思います。
そういえば、昔、テレビを見ていたら元プロ野球監督の野村克也さんが、一番最初に選手に何を教えるか、という質問に、まずは人間教育、と答えたことを思い出します。結局、能力を引き出すための初歩としては認識を良い方向に向けるというのが大事なんでしょう。システム開発もチームで行う場合は同様なんだと思います。講演の中にもありましたが、「銀の弾丸」ではないといことを肝に銘じてチームを活性化するためにもRedmineの使い方を間違えずにやっていきたいです。

最後に
スタッフの方々、ありがとうございました!!
次回も参加させて頂ければと思います。

ちょっと仕様変更があってカラム名を変更した。

コード部分を修正して問題ないことを確認しての本番環境(サービス稼動前)アップを行うとSQLエラー。

どうやら元のカラム名でクエリが発行されている模様。

もしかしてカラム名を指定してる部分がコードに残ってるのかもと調べてみたけど勿論なかった。

そして本番以外では問題なく動いている。

で、よくよく考えてみたらCakePHPのキャッシュだな、と。

app/tmp/cache/models/ のファイルを削除したら本番でも問題なく動いた。

CakePHPはデフォルトでキャッシュしてくれているので、次からは気をつけなくちゃなー。

CakePHPでORとANDを組み合わせて条件指定したい。

やりたいこと:

(A or B) AND (c or D)

ソース:

$conditions = array();

$or = array();
$or['or']['a'] = $a;
$or['or']['b'] = $b;
// $or = array('or' => array('a'=>$a, 'b'=>$b));
$conditions[] = $or;

$or = array();
$or['or']['c'] = $c;
$or['or']['d'] = $d;
// $or = array('or' => array('c'=>$c, 'd'=>$d));
$conditions[] = $or;

$params['conditions'] = $conditions;
$blog= $this->Blog->find('all', $params);

こんな感じで出来ます。

最近はCakePHPを書いていましたが、丁度良い案件があったため気になっていたCodeigniterを試してみました。

基本的にはCakePHPやよくある感じのMVCでした。

http://oreno.host/Controller名/Function名/パラメータ/

みたいにURL構成も同様。

試しに簡単なControllerとして

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Blog extends CI_Controller {
	public function index() {
		$data['message'] = 'こんにちは、世界!';
		$this->load->view('blog/index', $data);
	}
}

みたいなかたちで値を渡してviewを表示。
$this->load->view() で複数のviewも呼び出せるらしい。
ヘッダー、フッターとかに使えるのかな。

↑Controller用にviewを用意

<HTML>
<BODY>
<?php echo $message ?>
</BODY>
</HTML>

これで「こんにちは、世界!」と表示されました。

続いてDBも使用して登録・編集フォームを作成してみます。
DB接続のためにdatabase.phpに設定を記載します。
今回はこれのために適当にDB作成してblogテーブルを作成しました。
テーブルのデータを扱うためにモデルクラスを作成します。

<?php
class Blog_model extends CI_Model {

	function __construct() {
		parent::__construct();
	}

	function get_data() {
		$query = $this->db->get('blog');
		return $query->result();
	}

	function get_data_by_id($id) {
		$query = $this->db->get_where('blog', array('id' => $id));
		return $query->result();
	}

	function add($post) {
		$data['title'] = $post['title'];
		$data['content'] = $post['content'];
		$this->db->insert('blog', $data);
	}
    
	function edit($post) {
		$data['title'] = $post['title'];
		$data['content'] = $post['content'];
		$this->db->where('id', $post['id']);
		$this->db->update('blog', $data);
	}
}

用意した機能は全データ取得、id指定データ取得、データ登録、データ編集の4つです。
FW側で用意されている機能を使用すればSQLを書く必要なしです。
これをControllerで↓のように使用しました。

class Blog extends CI_Controller {
	/**
	 * 一覧表示を行う。
	 */
	public function index() {
		$this->load->model('blog_model', '', TRUE); // blogモデルを呼び出し
		$data['list'] = $this->blog_model->get_data();// blogモデルの機能呼び出し
		$this->load->view('blog/index', $data);
	}
	/**
	 * 入力フォーム表示を行う。
	 */
	public function input($id) {
		$this->load->model('blog_model', '', TRUE); // blogモデルを呼び出し
		$data['data'] = $this->blog_model->get_data_by_id($id);// blogモデルの機能呼び出し
		if (isset($data[0])) {
			$this->load->view('blog/input2', $data); // 編集
		} else {
			$this->load->view('blog/input1', $data); // 新規
		}
	}

	/**
	 * 登録処理を行う。
	 */
	public function add() {
		if ($this->_input_check() == false) {
			$this->load->view('blog/input1');			
			return;
		}
		$this->load->model('blog_model', '', TRUE); // blogモデルを呼び出し
		$this->blog_model->add($this->input->post());// postされた値を配列として全て渡す
		$this->load->view('blog/add');
	}
	
	/**
	 * 編集処理を行う。
	 */
	public function edit($id='') {
		if ($this->_input_check() == false) {
			$this->load->view('blog/input1');
			return;
		}
		$this->load->model('blog_model', '', TRUE); // blogモデルを呼び出し
		$this->blog_model->edit($this->input->post());// postされた値を配列として全て渡す
		$this->load->view('blog/edit');
	}

	/**
	 * 入力チェックを行う。(全項目set_valueする)
	 */
	private function _input_check() {
		$this->load->library('form_validation');
		$this->form_validation->set_rules('title', 'タイトル', 'trim|required');// 入力必須
		$this->form_validation->set_rules('content', '内容', 'trim|required');// 入力必須
		return $this->form_validation->run();
	}

まずはblogモデルを呼び出します。
これで後は定義しておいた機能が呼び出せます。

続いて登録・編集のために入力チェックを追加しました。
validation用にlibraryとしてform_validationが用意されているので、これを使用しました。
独自のvalidationも追加できるようです。
viewの方では、このvalidationのエラーメッセージを表示できます。
下記のようにform_error()を使用します。
また、set_rules()を使用するとviewでset_value()が使用でき便利です。
値を引き継ぐことができます。が、set_rules()しないと引き継げないので自分で拡張する必要がありそうでした。
またDBから取得した値はset_valueでは使用できないため、別のviewで表示しました。
この辺りの解決方法はあるのでしょうが、調べが足りませんでした。

input1.html
<HTML>
<BODY>
<form action="/blog/add/" method="post">
■タイトル<br>
<?php echo form_input(array('name'=>'title','value'=>set_value('title'), 'size'=>50));?><?php echo form_error('title'); ?><br>
<br>
■内容<br>
<?php echo form_textarea(array('name'=>'content','value'=>set_value('content'), 'cols'=>80, 'rows'=>10));?><?php echo form_error('content'); ?><br>
<br />
<input type="submit"><br />
<?php echo form_hidden('id', set_value('id'));?>
</form>
</BODY>
</HTML>
input2.html
<HTML>
<BODY>
<form action="/blog/add/" method="post">
<?php $data = $data[0];?>
■タイトル<br>
<?php echo form_input(array('name'=>'title','value'=>$data->title, 'size'=>50));?><?php echo form_error('title'); ?><br>
<br>
■内容<br>
<?php echo form_textarea(array('name'=>'content','value'=>$data->content, 'cols'=>80, 'rows'=>10));?><?php echo form_error('content'); ?><br>
<br />
<input type="submit"><br />
<?php echo form_hidden('id', $data->id);?>
</form>
</BODY>
</HTML>

ただ単純にページを作成するだけ、CakePHPなどでは重いー、といった方には良いかも知れませんね。

CakePHP2.0 勉強会@Tokyo(2011/06/25)に行ってきました。

最近、1.3を使う機会が多かったこともあり2.0も気になってたので。

candycane@yandoさん】
・RedmineをCakePHP化している
・開発合宿で誕生した
・インストールが容易です(確かにRedmineはRailsの設定とか面倒
・大勢でワッとやるとソースの統一感がなくなる(リファクタリングとかするらしい
・1.3 or 2.0化するらしい
・PHP Matsuriで人柱を募集しているw

【CakePHP2.0:@hiromi2424さん】
[intro]
・1.3からの移行が可能なように互換性がある
・RequestとResponseをオブジェクト化した
・Authを分けた(Authenticate・Authorize
などなど…

[ハンズオン]
mysql.sockの設定がダメだったらしくModelをBake出来ず…
その後はMaster見ながら話を聞いてました
・AuthComponentの設定が多くなってた
・Validationメッセージが複数表示できるようになってた
・テストはPHPUnitになってた
などなど…
あまり付いていけてなかったです(;^^A

【CakePHP2.0で初めてのテスト:@mon_satさん】
・テストを書くとメンテナンスが楽
・会社でテスト書いちゃダメってとこもある
・SimpleTestからPHPUnitになる
・メソッド名が変わって、2.1で削除される予定
・fixtureって便利

ロード第1章@cakephperさん】
http://www.ustream.tv/recorded/15605906
・2.0から階層を再帰検索しない(自分で定義する
・ファイルの読み込み、インスタンス化が動的になった

【懇親会】
あんまり多くの人とは話せませんでしたが立て続けに行なわれるLTが楽しかったです。
サービスを作っている人の話が直接聞けてテンション上がりました。
CakePHPでも大規模は出来るとかスゴイ。
ついでにLTでサイト紹介させてもらえて最高でした!

会場を提供してくださったトライコーン株式会社様、ありがとうございました!

こんな素敵な勉強会を開催してくださったスタッフの皆様、ありがとうございました!!

CakePHPでValidationを書いていたときのメモです。
$form->datetime() を使用したときの動きやら時間の前後チェックやら独自チェックの書き方やら、ちょいちょい分からなかったりしたのがあったので書いておきます。
もっと他に良い方法がありそうですが。。。

[バージョン]
PHP 5.1.6
CakePHP 1.3.8

model

<?php
class Hoge extends AppModel {
	public $name = 'Hoge';
	public $validate = array(
						'start_date' => array(
								array(
									'rule' => array('notEmpty'),
									'message' => '開始日時を選択してください。'
								),
								array(
									'rule' => array('datetime'),
									'message' => '開始日時が正しくありません。'
								),
						),
						'end_date' => array(
								array(
									'rule' => array('notEmpty'),
									'message' => '終了日時を選択してください。'
									),
								array(
									'rule' => array('datetime'),
									'message' => '終了日時が正しくありません。'
									),
								)
					);
	
	public function validates($options = array()) {
		// 親を呼び出す
		$errors = parent::validates($options);
		if ($errors) {
			// 日付前後チェック
			if (strtotime($this->data['Hoge']['start_date']) > strtotime($this->data['Hoge']['end_date'])) {
				$errors = false;
				$this->validationErrors['end_date'] = '終了日時を後に設定してください。';
			}
		}
		return $errors;
	}

	/**
	 * 日付チェック(Y-m-d H:i:s)
	 * @param  $check
	 * @return boolean
	 */
	public function datetime($check) {
		list ($key, $datetime) = each($check);
		if (is_null($datetime)) {
			return true;
		}
		// format check (Y-m-d H:i:s)
		$regex = '/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}:(\d{2}))$/';
		if (!preg_match($regex, $datetime)) {
			return false;
		}
		$list = explode(' ', $datetime);
		$date = explode('-', $list[0]);
		// date check (Y-m-d)
		if (!checkdate($date[1], $date[2], $date[0])) {
			return false;
		}
		$time = explode(':', $list[1]);
		// time check (H:i:s)
		if ($time[0] < 0 || $time[0] >=24 || $time[1] < 0 || $time[1] >=60 || $time[2] < 0 || $time[2] >=60) {
			return false;
		}
		return true;
	}
}

view

期間:<?php echo $form->datetime('start_date', 'YMD', '24', null, array('minYear' => 2011, 'maxYear' => date('Y')+1, 'monthNames' => false, 'separator'=> '/')); ?> ~ <?php echo $form->datetime('end_date', 'YMD', '24', null, array('minYear' => 2011, 'maxYear' => date('Y')+1, 'monthNames' => false, 'separator'=> '/')); ?><br>
<?php echo $form->error('Hoge.start_date');?><?php echo $form->error('Hoge.end_date');?>

どうやら通常のValidationRuleでは複数項目の指定が出来ないようです。
そのためvalidatesをオーバーライドしてvalidates処理後に複数項目の整合性チェックを書いてます。
ちなみに$this->dataの項目を指定すれば、それでも可能です。
そっちの方が汎用的な気がします。
また、今回は書いてませんが、項目によってValidationRuleを制御したい場合はmodel内にsetValidationRuleみたいなメソッドを作って$this->validateを設定できるようすると出来ます。
コントローラーで$this->Hoge->validates()を呼ぶ前に、それを呼び出せば可能になります。

この場合の$form->datetime()でPOSTされた値は「Y-m-d H:i:s」形式で取得出来ました。
年単位、月単位とかでチェックするのは面倒なので助かりました。

参考:
複数のフィールドにまたがるバリデーションは?

/etc/aliases

を編集するだけで大丈夫。
(postfixインストール済)
ファイルの一番下に下記のように追記すればOK。

php: “| /www/mail/test.php”

このファイルはメールの転送を定義するものだが、それを利用してPHPなどプログラムを起動することも可能。
編集した後は

newaliases

コマンドで設定を反映する。

php@example.com

にメールを送信すると

/www/mail/test.php

が実行される。
メールから記事更新とか出来て当たり前ですもんね。
空メ送信からの登録処理なんかもこの流れが多いですね。

自分でもFizzBuzzを書いてみました。

1から100までの数を表示します。
ただし、3の倍数はFizz、5の倍数はBuzz、3と5両方の倍数はFizz Buzzと表示します。

for ($i=1; $i<=100; $i++) {
	if($i % 3 == 0 && $i % 5 == 0) {
		$str = 'Fizz Buzz';
	} elseif($i % 3 == 0) {
		$str = 'Fizz';
	} elseif($i % 5 == 0) {
		$str = 'Buzz';
	} else {
		$str = $i;
	}
	echo $str;
}

試しに書いてもらったソースです。


//1~100まで表示
//3で割り切れる→Fizz
//5で割り切れる→Buzz
//3,5で割り切れる→Fizz Buzz

for($a = 1; $a <= 100; $a++) {
	if($a % 3 == 0) {
		if($a % 5 == 0) {
			echo "Fizz Buzz<br>\n";
		} else {
			echo "Fizz<br>\n";
		}	
	} else {
		if($a % 5 == 0) {
			echo "Buzz<br>\n";
		} else {
			echo $a."<br>\n";
		}
	}
}
Page 1 of 4:1 2 3 4 »
bottom-img
Get Adobe Flash player