価値あるシステム開発の為に

開発技術は日を追う毎に複雑になってきます。
昔勉強したものも今現在では役に立たない、むしろ固執することで足かせになることが多いかもしれません。

なまじ過去に成功体験を多く持っている人は、時代の変化によって、勝利の方程式だと信じてやまないプロセスが通用しなくなってきたことに焦りや苛立ちを持っているのではないでしょうか。私もその中の一人だったりします。

システムの利用者にとって「価値あるもの」の定義も時間とともに変化していきます。システム開発当初に合意した仕様が今も正しい仕様である保証はありません。ビジネス自体が変化しなければならないのにシステムが追いつけなくて足かせになっている、というのは非常に不幸な状況です。


システムの作り方に問題があるのでしょうか?
開発言語の選定が甘かったのでしょうか?


ケース・バイ・ケースではあるでしょうけど、ただ、1つ言えるのは、時間の経過により、仕様の『鮮度』が落ちるものがある、ということです。システムは作って終わりではありません。
長期間変更が不要な保存の効く仕様ばかりではありませんし、システムが提供する機能に対して使用されているのか、仕様はこのままで良いのかの棚卸が必要ではないでしょうか。

要件定義の際には必要だと思われた機能が今では誰からも使用されていない場合、思い切ってdropし、機能を必要最低限のものとして保守工数を減らし、その分新しい機能の追加工数に充てる、とか、技術的、ビジネス的な観点でジャッジできる体制にならなければなりません。

一括請負の受託開発の場合

仕様の決定に関しては開発費用を出すユーザ側が立場が上であることが多く、その決定は開発側だけでは如何ともし難い状況が多いでしょう。場合によっては、ユーザ側は予算の中で開発側に機能をいくつ作らせるか腐心することもあるかもしれません。機能が多いからといって、良いシステムになるわけではないのに、です。一般的にはお金を払う側が強いので、主従関係となってしまうことが多いでしょう。
このような関係では、良い提案が出てくる可能性は皆無で、開発側は提示された仕様を愚直にシステム化することだけに専念します。契約から逸脱すること無く、それ以上でも以下でもないシステムが出来上がることになります。
で、開発現場の若手は今までの成功事例を元にした超保守的な仕事が面白くないもんだから社外の勉強会に参加するようになって新しいことを学ぶんだけど「結局今の状況じゃ何も変わらない」と思って社内で活かすことをせず、「誰かの目に止まらないかな」と淡い期待を込めながらgithubにソースコードを上げてキャッキャウフフすることに注力するようになります。悪循環。

頑張ってシステムを完成させて、利用者から改善要望が来た場合、追加工数が無ければ何もしないと突っぱねます。要件の考慮漏れだったとしても同様。金を貰わずに作業をするのではビジネスは成り立たないのも理解できます。
多くの人が受託開発に見切りをつけようとしているこの状況を改善するには、継続的にシステムに携わることのできる契約形態を模索しなければならないと思います。

システム開発の成功は、QCDも確かにあるかもしれませんが、当初の予定通りの費用対効果が出たか、ということであるべきで、「完成したか」ではないはずです。ですが、一括請負の受託開発の場合、契約として成果物責任があるので完成させなければなりません。

アジャイル開発と呼ばれるものの本当のメリット

小さな機能に分割して作りながら様子を見ながらやりましょうよ、と言ってますけど、基本的には開発側と利用者でゴールを共有しようよ、ということが大前提にあるはずです。
契約で縛り合うのではなく、良好な信頼関係を築くほうが生産性は何倍も上がるだろうし、多少の無理は聞くでしょう。基本的に開発側は利用者に喜ばれたいんですから。

契約による縛りとその限界

一括請負の契約で縛ることで開発側は下手な見積を出すわけにもいかず、それなりに精査し、リスクを積み、失敗しないようにしようとします。時間もかかるし結局高くつくことでしょう。一括請負は「発注したシステムが完成しなかった」リスクを回避する為の契約で、「価値あるシステムを保証する契約」ではありません。

これからはシステム開発に関しても費用対効果を鑑みることが重要だと思います。「システムが完成しない」よりも「コストをかけて価値がないシステムを作った」方がよりリスクだと考えなければならないでしょう。

企業と社内システムのあるべき形とまとめ

仕様の叩き台を元に開発(実現)するための工数と、得られる効果を天秤にかけて、実施のジャッジ/合意をするようにならなければ、システム化の目的がブレてしまいます。また、機能を詰め込みすぎてシステムが肥大化し、リプレースを行う時のハードルにならない様にするために、機能の棚卸も必要でしょう。使わないものは捨てる、部屋と一緒ですよ。
本来、そのジャッジはユーザ企業で行う必要があるのですが、社内システムを内製する文化にない企業では難しいでしょう。実現する為の工数が検討もつきませんから。そこで、信頼出来るパートナーを見つけることと、いつでも相談できるような契約を結ぶ、ということが必要だと考えます。

ユーザ企業と開発側が、契約でなく信頼関係で結ばれれば、受託開発も面白く感じる人が増えるんじゃないかなぁ、と考えます。幅広くそれなりのスキルがなければやっていけないと思いますけどね。ただ、厳しい時代には変わりない。

Mountain Lionへのupdate

遅ればせながら、OS XをMountain Lionへupdateしました。その中で、開発していたRoR環境が動作しなくなったので備忘録的に。

テストが通らない!

unit testでエラーが出てしまいます。挙動が云々でなく、そもそもDBサーバが動いてねぇよ、的なメッセージ。

rake aborted!
could not connect to server: No such file or directory
        Is the server running locally and accepting
        connections on Unix domain socket "/var/pgsql_socket/.s.PGSQL.5432"?

あれー?Posgres逝ったか??と思って、ターミナルからpsqlを叩くと・・・接続できる・・・。なんじゃい、こりゃ??で、ネット上に情報が落ちてないかウロウロしてた所、ありました。
API Only - Stack Exchange

どうも、database.ymlの中で接続先の指定をする際に、localhost上のPostgresを参照するので設定していなかったのですが、Mountain Lionにすると指定が必要なようです。

test:
  adapter: postgresql
  ・・・
  host: localhost

hostを指定した所、動作しましたとさ。

Titanium.Network.HTTPClientを使ってGAEの認証を通す(その2)

前回、Titaniumを使ってGAE上の認証を通すことを書きましたが、どうも、500のレスポンスが帰ってこなくなるだけで、必要なデータがとれていなかったようなので、再度確認しました。前回の奴は嘘です。忘れて下さい。

GAEアプリでなく、Google側の認証でエラーが発生しているので、ログを確認しようにもできません。ローカル環境で確認したところ、AndroidとiOSでリクエストヘッダは違いこそありますが、根本的に違うわけでは無さそうでした。*1

Client認証を行い、その結果をパラメータとしてURLに直接設定してブラウザを叩くと通ります。当然のことながら認証成功時に含まれる文字列を変更すると、エラーが返って来ます。iOSで帰ってくる500の画面と同じです。

私のコードはsendメソッドにリクエストパラメータを渡していましたが、URLに直接設定してみると・・・通りました。
うーん、httpの時は、GETでsendメソッドの引数にパラメータを設定することで送れていることは確認できたのですが、httpsだとダメ・・・なんでしょうかね?
よくわからないけど試してみたら動いた、という気持ち悪い結果になりましたが、TitaniumでiOS用のソースコードを記述する時は、https通信を行う場合、GETリクエストはURLに書いたほうがよさそうです。


ソースは以下の感じ。

//GAEに対するログイン
//Googleに対してClient認証を行い、その結果をauthTokenに設定
function loginAppEngine(loginParam, authToken) {
	
	var appid = loginParam.appid;
	
	var baseUrl = "https://" + appid + ".appspot.com/";
	var xhr = null;
	if(Ti.Platform.osname === 'android') {
		xhr = Titanium.Network.createHTTPClient();
	} else {
		//iOSの場合、SSLチェックを緩くする
		xhr = Titanium.Network.createHTTPClient({
		    	validatesSecureCertificate: false,
		    	tlsVersion: Titanium.Network.TLS_VERSION_1_0
		});
	}
	
	var query = "?continue=" + baseUrl + "&auth=" + authToken;	
	var url = baseUrl + "_ah/login";

	//POSTだとAndroidでもiOSでも500エラーが返るので、GETメソッドでないといけない
	xhr.open('GET',url + query);
	
	//レスポンスを受け取った際のイベント
	xhr.onload = function(){

		indicator.hide();

		//以降、ごにょごにょする
	};
	
	// エラー発生時のイベント
	xhr.onerror = function(error){
		indicator.hide();
		
		//以降、ごにょごにょする
	};
	
	//リクエスト送信
	var indicator = Ti.UI.createActivityIndicator({
		message : "Loading..."
	});
	indicator.show();

	xhr.send();
}

で、レスポンスヘッダからCookieに設定されているJSESSIONIDをGAEアプリへのリクエストに含めることで、AndroidでもiOSでも認証が必要なGAEアプリからJSONデータを取ってくることができます。

Titanium SDK 2.0.2だからなのか、そもそもだったのかわかりませんが、Androidで動作してiOSで動作しない時はこの辺りを疑ってもいいかもしれません。こんなにハマるとは思わんかった・・・。

*1:ConnectionがcloseだったりKeep-Aliveだったりの差はありましたが、確認した所、このお陰でエラーになっているわけではありませんでした

動的にheightが変わる場合のScrollView

1画面に収まらないデータを表示する画面を実装するのに、ScrollViewを使用していましたが、Androidでは思い通りだったのですが、iOSではスクロールしませんでした。

var self = Ti.UI.createWindow();
var scrollView = Ti.UI.createScrollView({
  contentWidth:'auto',
  contentHeight:'auto',
  layout : 'vertical',
  showVerticalScrollIndicator:true,
  showHorizontalScrollIndicator:true
});
self.add(scrollView);

var view = Ti.UI.createView({
  backgroundColor:'#336699',
  width:'100%',
  top:'10dp',
  layout : 'vertical',
  height : 'auto'
});
scrollView.add(view);

//・・・以降、viewに対してLabelをaddする
//Labelのheightは一意に決まらない

思い切って、
Titanium BBS(JP unofficial)
で聞いてみたところ、viewのheightを'auto'からTi.UI.SIZEとすれば良いという回答をもらいました。

var view = Ti.UI.createView({
  backgroundColor:'#336699',
  width:'100%',
  top:'10dp',
  layout : 'vertical',
  height : Ti.UI.SIZE
});

実際に試した所、想定通りに表示されました。あー、そういうことだったんですね。返信いただいた方、ありがとうございました!

いやー、JavaScriptだけでAndroid/iOSアプリができるって、楽ですねぇ。

Titanium.Network.HTTPClientを使ってGAEの認証を通す

※2012/06/24追記 この方法では正常動作しません。修正版はこちら

TitaniumでGAEアプリからJSONでデータを取るような実装をしていて、認証部分の処理を書いていました。

//GAEに対するログイン
//Googleに対してClient認証を行い、その結果をauthTokenに設定
function loginAppEngine(loginParam, authToken) {
	
	var appid = loginParam.appid;
	
	var baseUrl = "https://" + appid + ".appspot.com/";
	var xhr = null;
	if(Ti.Platform.osname === 'android') {
		xhr = Titanium.Network.createHTTPClient();
	} else {
		//iOSの場合、SSLチェックを緩くする
		xhr = Titanium.Network.createHTTPClient({
		    	validatesSecureCertificate: false,
		    	tlsVersion: Titanium.Network.TLS_VERSION_1_0
		});
	}
	
	var url = baseUrl + "_ah/login";

	xhr.open('GET',url);
	
	//レスポンスを受け取った際のイベント
	xhr.onload = function(){

		indicator.hide();

		//以降、ごにょごにょする
	};
	
	// エラー発生時のイベント
	xhr.onerror = function(error){
		indicator.hide();
		
		//以降、ごにょごにょする
	};
	
	//パラメータ作成
	var param = {};
	param["continue"] = encodeURI(baseUrl);
	param["auth"] = encodeURI(authToken);

	//リクエスト送信
	var indicator = Ti.UI.createActivityIndicator({
		message : "Loading..."
	});
	indicator.show();

	xhr.send(param);
}

ところが、Androidでは問題なく動作するのに、iOSでは500エラーが発生します。


数日間悩んでいたのですが、理由は簡単

	var url = baseUrl + "_ah/login";



	var url = baseUrl + "_ah/login/";


とすれば良かったのです。
えー、Java(jmeter)だと大丈夫だったのになー。Objective-Cの仕様なんでしょうか?Androidで動いてiOSでエラーになるhttpリクエストがある場合、URLを見なおしてみると良いかもしれません。


あと、iOSの場合の

		xhr = Titanium.Network.createHTTPClient({
		    	validatesSecureCertificate: false,
		    	tlsVersion: Titanium.Network.TLS_VERSION_1_0
		});

が異様にキモい。

GAE上で動作するアプリを作ってみた

ふと、仕事以外のコードを書きたくなって。
時間を見つけて書きためてました。


IT以外の人でも、redmine的なもの(ITS)って必要だよね*1

でも、サーバ管理とか面倒だろうし

クローズドな人たちで使えて、かつデータはインターネット上にあった方がいいよね


ということで、個別のGoogle App Engineにデプロイしてもらう形のアプリを作りました。


Mishimaと言います。


無料クォータでどこまでいけるかは使い方次第ですが、数人のプロジェクトならなんとか大丈夫かな?と思います。

マニュアルめいたものも書いてみました*2


Amazonとかでサービス公開したらもっと実装が楽なんでしょうけど、いかんせん、そんな環境を維持する余裕がないものでGAEアプリになります(最近は価格改定のせいで下火なんですかね??)

GAE + slim3 + jQueryという形で動作するWebアプリで、GitHubにもソース公開しています。
ライセンスの相談には id:daisuke-m に乗ってもらいました。ありがとうございます。

次はTitanium Mobileでスマフォアプリ対応してみようかな。

*1:多分

*2:これが一番面倒でした

IPv6セミナー + Hackathon in 新潟に参加してきたze!

ネットワークもよくわかりませんが、技術者たるもの「IPv6」くらい試しておかないとね、くらいのノリで参加してきました。まぁまぁ準備はしてたんですけど、思うようにはいきませんでした。でも、Javaは結構優秀で、IPv4IPv6意識しなくてもそこそこいける気がします。さすがー

作ったGAEアプリとか、GAEの認証周りにおけるJMeterのシナリオの作り方のコツとかはおいおいまとめます。
関係者の皆様、お疲れ様でした。やるじゃん、長岡!

Ipv6+JMeter+GAE


※2012/05/29追記
GoogleIPv6サービスは6月6日まではwhitelistモードで、Google over IPv6に登録されたDNSを使ってないと、まだIPv6では接続できないはずという情報を頂きました。なるほど。
[twitter:@maz_zzz]さん、ありがとうございます!