wordpress と iPhone/iPad の連携を考える

ふと、XMLRPC が使えるのだから、iPad から WordPress のブログを更新してもいいんじゃ?

0から始めるiPhoneからのWordPress更新術 | Feelingplace
http://www.feelingplace.com/wp_update_from_iphone/

と思った訳ですが(そんなわけで、Textforce が手元の iPhone に入っていたりします)、一度もこのブログに対して更新したことはありません。つーか、プログラムコードを載せるのが目的(だけでもないけど)だから、iPad でコーディングをするよりも、PC を使ったほうが断然楽なんですよね。なので、Visual Studio でコーディングして、エディタ(QX エディタとか sakura エディタ)で適当なタグを入れて、後は自作のスクリプトで更新処理をするか、ブラウザ上で書き込んでしまう、というのが私のスタイル。

が、専用アプリでブログを更新するのは、極めて便利なパターンがあるわけで、汎用的な場合は PC で書いてもいいんですが、

・写真だけを up したい写真ブログ
・食べ物の感想だけを up したい、写真&感想ブログ
・毎日の定型フォーマットを残しておきたい、定型のブログ

な風に「ブログ」でなくても、定型処理して up する場合は、それ専用のアプリあるいは入力フォーマットがあったほうが便利なわけです(業務的な視点で言えば、営業報告書みたいなものですね)。

この手のコンセプトは、いわゆる社内の業務アプリケーションにあるパターンと同じで、

・入力項目が限られている(あるいは必須項目がある)
・定型業務を高速に入力できる(作業能率をあげる)
・誰が入力しても(初心者が入力しても)同じフォーマットで入れられる(属人性が低い)
・データベース化して、何かと連携させる(フリーフォーマットではない)

のようなカスタムメイドっぽい入力方法を提供すればよいのです。

と、ここまで書いていて、昔 Workpad(palm) でメモを書いていた頃、そして iPad の標準的なメモ帳を使ってメモを書いてる自分を振り返ると、タイトルを1行目に書いて、以下本文を書くというフォーマットでも実は十分なのです。

この行がタイトルになる
以下は、本文
...
つづく

ただ、これだとメモ帳で見たときに見づらいことが多いので、1行空けています。

この行がタイトルになる
		← 空行を入れる
以下は、本文
...
つづく

さて、ここでカテゴリを加えるときにどうするのかというと、所謂 mail フォーマット(HTTPプロトコルのフォーマット)風なものを使います。

Title: この行がタイトルになる
Category: ブログ
		← 空行を入れる
以下は、本文
...
つづく

「種別」+「コロン」+「値」という形式です。
こうしておくと、perl やら ruby やらで整形するときに非常に便利なのです。

が、PC のように専用のキーボードがある場合、このような【冗長な】記号を使ってもいいのですが、palm や iPhone の場合には、この記号をタイピングするのが面倒だったりします。なので、キータイピングが遅い(あるいはキー入力を得意としない)端末を対象にする場合は、折衷案として、あらかじめ「種別」の部分をいれたテンプレートを作っておきます。

Title: 
Category: 
		← 空行が入っている

これを、テキストボックスやリストを貼り付けて選択させてもよいのですが、本文に注力する場合には【視覚的に】冗長なんですよね。なので、ノーマルなテキストにある程度の記号が入っているほうが思考を妨げません。
逆に言えば、写真ブログのように「写真」が中心な場合には、カテゴリはリストから選択、という方法をとったほうが楽です。というのも写真は
「文章」ではないので、「文章でないもの=写真」と「文章=カテゴリの入力など」、を行き来するよりも、「文章でないもの=写真」と「文章でないもの=カテゴリの選択」としたほうが、思考を妨げません。

じゃあ、カテゴリなんかはいちいちタイピングしないといけないのか?というと慣れていない iPhone のソフトウェアキーボードを使うと面倒ですよね。私はいまだにフリックのスピードが遅いので、ちょっと困りものです。

なので、アプリのほうが一工夫して、

Title: 
Category: .ブログ

のようにピリオドを打つと、候補が展開される、というようなインテリセンスな機能があると良いのかなぁと。まぁ、「ブ」を打った時点で「ブログ」まで出してくれてもいいのですが、カテゴリ全体を表示させたい場合は、なんらかのプレフィックスがあったほうがいいのです。

あるいは、「Category: 」のところで左にスライドをするとカテゴリのリストが現れるとか、タッチをすると「>」記号が現れて選択を示すとか。iPhone のナビゲーションはそういうスタイルになっているのでそれに合わせるのも良いですね。

とかなんとか、考えてみたという話です。

カテゴリー: ブログ, iPad | 2件のコメント

clang+llvm で objc を DataTable っぽく扱う

うれしげに、@property で DataRow を作って見た例。
もうちょっと整理しないと。

/*
clang -o main4 main4.m -I /llvm/include -I /GNUstep/GNUstep/System/Library/Headers -L c:/GNUstep/GNUstep/System/Library/Libraries -lobjc -lgnustep-base -fconstant-string-class=NSConstantString -Wno-format-security
*/
#import <stdio.h>
#import <Foundation/Foundation.h>
#import <Foundation/NSObject.h>

@interface Person : NSMutableDictionary
{
	@private
	int _id ;
	NSString *_name;
	int _age ;
}
@property (nonatomic) int id ;
@property (nonatomic,retain) NSString *name;
@property (nonatomic) int age ;
@end

@implementation Person
@synthesize id = _id ;
@synthesize name = _name ;
@synthesize age = _age ;
- (void)print 
{
	NSLog(@"%d %@(%d)", _id, _name, _age );
}
- (Person*)initWithId:(int)id Name:(NSString*)name Age:(int)age 
{
	_id = id;
	_name = name;
	_age = age;
	
	return self;
}
@end

@interface Persons : NSObject
{
	@private 
	NSMutableArray *_rows ;
}
@property (nonatomic,retain) NSMutableArray *rows ;
@end

@implementation Persons
@synthesize rows = _rows;

- (id)init
{
	[super init];
	_rows = [[NSMutableArray alloc] init];
	return self;
}
- (void)print 
{
	for ( int i=0; i< [_rows count]; i++ ) {
		Person *p = [_rows objectAtIndex:i];
		[p print];
	}
}

@end



int _main(int argc, char *argv[])
{
	Person *masuda = [[Person alloc] initWithId:1 Name:@"masuda" Age:40];
	Person *yamada = [[Person alloc] initWithId:2 Name:@"yamada" Age:50];
	Person *tanaka = [[Person alloc] initWithId:3 Name:@"tanaka" Age:20];
	Persons *persons = [[Persons alloc] init];
	[persons.rows addObject:masuda];
	[persons.rows addObject:yamada];
	[persons.rows addObject:tanaka];
	[persons print];
	
	return 0;
}

int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    int retVal = _main(argc, argv);
    [pool release];
    return retVal;
}



カテゴリー: 開発, Objective-C | clang+llvm で objc を DataTable っぽく扱う はコメントを受け付けていません

コードで学ぶ ASP.NET MVC アプリケーション開発入門 全10回

コードで学ぶ ASP.NET MVC アプリケーション開発入門
http://msdn.microsoft.com/ja-jp/asp.net/gg490787

が全10回で連載終了しましたッ!!! ってことで、まとめリンクです。
後で、固定ページにでも移しておきます。

はじめに「MVC パターン」とは何か
本連載では、日経 BP 社から発売された「ひと目でわかる ASP.NET MVC アプリケーション開発入門」をもとにして、執筆時に気づいたことや紙面の都合で書ききれなかった技術を紹介します。

第 1 回 ASP.NET MVC 概要
連載第 1 回は、ASP.NET MVC 2 の具体的な開発の全体像をみていきましょう。

第 2 回 アクション メソッドについて
連載の第 2 回目は、ASP.NET 4 で導入された「URL ルーティング」と、ASP.NET MVC 2 で必ず理解が必要な「アクション メソッド」についてお話ししましょう。

第 3 回 ViewDataDictionary を利用する
連載の第 3 回目は、コントローラー (Controller) からビュー (View) に直接データを渡すための ViewData プロパティ (ViewDataDictionary クラス) についてお話していきましょう。

第 4 回 Entitiy Frameworkを利用する
連載の第 4 回目は、データベースを扱うフレームワーク「ADO.NET Entity Framework」を使ってサンプルを動かす方法についてお話していきましょう。

第 5 回 HTML ヘルパー メソッドを使用する
連載の第 5 回は、ASP.NET MVC アプリケーションのビューで使われる HTML ヘルパー メソッドについてお話していきます。

第 6 回 Site.Master の編集とページ デザイン
連載の第 6 回は、ADO.NET Entity FrameworASP.NET MVC アプリケーションの全体的なデザインを担っているマスター ページに関して解説をしていきます。

第 7 回 JavaScript と jQuery を利用する
連載の第 7 回は、Web アプリケーションでは今や必須の技術となった JavaScript との組み合わせについて解説していきます。ASP.NET MVC でも JavaScript は重要な技術です。

第 8 回 Action Filter について
連載の第 8 回は、ASP.NET MVC のアクション メソッドを拡張するアクション フィルターについて解説します。アクション フィルターは、メソッドの属性として設定されます。クラスの静的なデータとして設定されるため、クラス内の共通処理を行う場合に使うことができます。

第 9 回 出力キャッシュの利用
Web アプリケーションでは、ご存じのようにクライアント (ブラウザー) と、サーバーの間にネットワークがあり、そのネットワークを通じてデータのやり取りをしています。ブラウザー上でひとつの画面から別の画面に移るたびにサーバーで処理が行われ、データのやり取りが発生しています。出力キャッシュは、このサーバーの処理を軽減するための機能になります。

最終回 コントローラー アクション メソッドの単体テスト
ASP.NET MVC アプリケーションの単体テストを取り上げます。Visual Studio 2010 で ASP.NET MVC アプリケーションのプロジェクトを作ると、最初に「単体テストのプロジェクトの作成」のダイアログが開きます (ASP.NET MVC 3 の場合は、「単体テストのプロジェクトを作成する」のチェック ボックスを ON にします)。

おまけとして、コードレシピへのリンク


カテゴリー: 開発, ASP.NET | コードで学ぶ ASP.NET MVC アプリケーション開発入門 全10回 はコメントを受け付けていません

clang+llvm で objective-c 2.0 をコンパイルする

LLVM-GCC 4.2 Front End Binaries for Mingw32/x86
http://llvm.org/releases/download.html#2.9
KMC Staff Blog:Clang と LLVM を使ってみる。
http://blog.kmckk.com/archives/2435798.html

実は、よく分からんというのが本音ですが、mingw + gnustep の組み合わせだと objective-c の @property がコンパイルできません。

なので、先のリンクから↓の3つをダウンロードしてきて c:\llvm とかに移動

Clang Binaries for Mingw32/x86 (23M)(.sig)
LLVM Binaries for Mingw32/x86 (23M)(.sig)
LLVM-GCC 4.2 Front End Binaries for Mingw32/x86 (26M) (.sig)

別に入っている

GNUstep Windows Installer
http://www.gnustep.org/experience/Windows.html

の include を設定すると、@property がうまくコンパイルできます。かつ、うまく動きます。

#import <stdio.h>
#import <Foundation/Foundation.h>
#import <Foundation/NSObject.h>

@interface Hello: NSObject
{
	@private
	NSString *_msg ;
}
@property (nonatomic,retain) NSString *msg;
@end

@implementation Hello
@synthesize msg = _msg ;

- (void)print
{
	// NSLog( _msg );
	printf("%s\n", [_msg cString]);
}
- (void)dealloc
{
	NSLog( @"in dealloc" );
	[super dealloc];
}
@end


int main(int argc, char *argv[])
{
	puts("hello obj-c world.");
	Hello *hello = [[Hello alloc] init];
	hello.msg = @"hello objc world.";
	[hello print];
	[hello release];

	return 0;
}

こんな風に @property を使ったコードを書いておきます。

そして、最初は clang だけでコンパイルしてみると。

clang -o main3 main3.m -I /llvm/include -I /GNUstep/GNUstep/System/Library/Headers -L c:/GNUstep/GNUstep/System/Library/Libraries -lobjc -lgnustep-base -fconstant-string-class=NSConstantString

のようにコンパイルして実行すると、次のようにうまく動きます。

C:\work\alice\objc>main3
hello obj-c world.
2011-07-05 18:12:32.113 main3[2400] in dealloc

~~~

試しに vm 上で動かしてみようと

clang -emit-llvm -S main3.m -I /llvm/include -I /GNUstep/GNUstep/System/Library/Headers
llvm-as main3.s
lli main3.s.bc

な風にコンパイルしましたが、

C:\work\alice\objc>lli main3.s.bc
LLVM ERROR: Program used external function '__objc_exec_class' which could not b
e resolved!
Stack dump:
0.      Program arguments: lli main3.s.bc
1.      Running pass 'X86 Machine Code Emitter' on function '@.objc_load_functio
n'

な風に実行エラーになりますね。objc のランタイムを clang でコンパイルして配置するんでしょうが。

カテゴリー: 開発, Objective-C | 2件のコメント

objective-c の autorelease の動き

C# のガベージコレクションと同じなのかなぁ、と思ったけど、動き的には c++ のスマートポインタに近いのかな。
autorelease を指定すると、NSAutoreleasePool のオブジェクトに溜め込まれるようです。ここで、間違って release してしまうと落ちてしまう(core dump)ので、alloc と release の対応は、malloc/free, new/delete 並に厳しいコーディングをしないと駄目ですね。
一律、autorelease を使って release を使わないで記述するか、autorelease を使わずに release 自体をまめにコーディングしていくか悩むところ。

UIImage のように大きめなメモリを取得するものは、autorelease にするとメモリを占有してしまうので、release をするってのが適当ですね。

/*
export INCLUDE=/GNUstep/System/Library/Headers
export LIB=/GNUstep/System/Library/Libraries
export CFLAGS='-fconstant-string-class=NSConstantString  -enable-auto-import'

gcc -o main main.m -lobjc -lgnustep-base -I $INCLUDE -L $LIB $CFLAGS
*/
#import <stdio.h>
#import <Foundation/Foundation.h>
#import <Foundation/NSObject.h>

@interface Hello: NSObject
{
	@private
	NSString *_msg ;
}
@end

@implementation Hello
- (void)setMessage:(NSString*)msg 
{
	_msg = msg;
}
- (void)print
{
	// NSLog( _msg );
	printf("%s\n", [_msg cString]);
}
- (void)dealloc
{
	NSLog( @"in dealloc" );
	[super dealloc];
}
@end

int _main(int argc, char *argv[])
{
	puts("hello obj-c world.");

	// autorelease を使った場合
	Hello *hello = [[[Hello alloc] init] autorelease];
	[hello setMessage:@"hello objective-c in hello class"];
	[hello print];
	
	// autorelease を使わない場合
	Hello *hello2 = [[Hello alloc] init];
	[hello2 setMessage:@"hello objective-c no autorelease"];
	[hello2 print];
	[hello2 release];
	
	return 0;
}

int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    int retVal = _main(argc, argv);
	NSLog(@"before pool release");
    [pool release];	// ここで一気に解放される
	NSLog(@"after pool release");
    return retVal;
}

実行結果

$ main
hello obj-c world.
hello objective-c in hello class
hello objective-c no autorelease
2011-07-05 15:46:23.484 main[4124] in dealloc
2011-07-05 15:46:23.545 main[4124] before pool release
2011-07-05 15:46:23.545 main[4124] in dealloc
2011-07-05 15:46:23.545 main[4124] after pool release
カテゴリー: 開発, Objective-C | objective-c の autorelease の動き はコメントを受け付けていません

美女Linux on iPhoneを作る(1)

電子書籍アプリとは別に、ごく簡単な「美女Linux on iPhone」を作ってみます。
まあ、電子書籍アプリのほうは、UIViewContoller 絡みがややこしそうなので、そのあたりベタベタに書こうと思って(所詮、スクリプトで出力させるわけだし)。

目的としては
・独立した iPhone アプリができればよい。
・Apple Store に無料版として up できればよい。
ってところですね。

「無料版」を up させるところが練習なわけで、最終的には「有料版」(美女Linuxじゃないけど)ができることが最終目標。
「独立した」というのは、ネットワークに接続せずに画面切り替え、ってところです。最終的にはしかるべき web サイトから画像をダウンロードするわけですが、3G 契約だったりすると通信料の課金の関係から、ネットにつなぐ/つながないはシビアに考えたほうがよいですよね。日本の携帯電話の場合、そのあたり通信回線に接続するのにシビアなのに、iPhone アプリがルーズなのが気になるところです(まぁ、広告を表示するのに、いちいち「回線に接続するか?」と問い合わせるのも変な話なんですしょうが、一応、apple の指針では回線接続の場合には問い合わせが推奨のようです)。

iPhone で動いている画像があればよいのですが、iPhone では iPhone を写せないというジレンマが(笑)、あるので、開発中の画面なぞ(実機でも動いています。画像は非常にきれいです)。

<001>

本来は、練習として interface builder を使いたいところなのですが、まだ使い方がわからないので、ベタに記述します。

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    _page = 1;
    
    // 背景画像を UIImage, UIImageView で作成
    NSString *backName = [NSString stringWithFormat:@"iphone_back%02d.png", _page  ];
    NSLog( @"%@", backName );
    UIImage *back = [[UIImage imageNamed:backName] autorelease];
    UIImageView *backview = [[[UIImageView alloc] initWithImage:back] autorelease];
    backview.frame = self.view.bounds;
    [self.view addSubview:backview];
    // タイマーイベントで使うので保存しておく
    _backview = backview;
    
    // 「次へ」ボタンの作成(デバッグ用)
    // UIButton *btnNext = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    UIButton *btnNext = [UIButton buttonWithType:UIButtonTypeCustom];
    [btnNext setTitle:@"NEXT" forState:UIControlStateNormal];
    [btnNext setFrame:CGRectMake(0,0, 50, 50  )];
    [btnNext addTarget:self action:@selector(btnNextDidPush) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btnNext];
    
    // 日付を表示する
    UILabel *lblClock = [[UILabel alloc] init];
    lblClock.frame = CGRectMake(0, 50, 300, 50);
    NSDate *now = [NSDate date];
    NSDateFormatter *fmtr = [[NSDateFormatter alloc] init] ;
    [fmtr setDateFormat:@"yyyy/MM/dd HH:mm:ss"];	// 日付のフォーマット
    lblClock.textColor = [UIColor whiteColor];
    lblClock.backgroundColor = [UIColor clearColor]; // 背景を透明にする
    lblClock.font = [UIFont fontWithName:@"AppleGothic" size:20];
    lblClock.text = [fmtr stringFromDate:now];
    [self.view addSubview:lblClock];
    [fmtr release];
    _lblClock = lblClock;
    
    // 日時切り替え用のタイマー(1秒間隔)
    _timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(onTimerClock:) userInfo:nil repeats:YES];
    // 画像切り替え用のタイマー(15秒間隔)
    _timer = [NSTimer scheduledTimerWithTimeInterval:15.0f target:self selector:@selector(onTimer:) userInfo:nil repeats:YES];
    
}
// 次へボタン
- (void)btnNextDidPush {
    
    _page++;
    if ( _page > 3 ) _page = 1;
    
    // 新しい UIImage を作成
    NSString *backName = [NSString stringWithFormat:@"iphone_back%02d.png", _page  ];
    UIImage *back = [[UIImage imageNamed:backName] autorelease];
    // UIImageView に設定する
    [_backview setImage:back];
    
}
// タイマーで切り替え
- (void)onTimer:(NSTimer*)timer {
    NSLog(@"on timer");
    _page++;
    if ( _page > 3 ) _page = 1;
    // btnNextDidPush と同じことをやっているが、まぁ、いいか(コピー&ペーストで)
    NSString *backName = [NSString stringWithFormat:@"iphone_back%02d.png", _page  ];
    UIImage *back = [[UIImage imageNamed:backName] autorelease];
    [_backview setImage:back];
}

// 日時の表示
- (void)onTimerClock:(NSTimer*)timer {

	// このあたりも、viewDidLoad とダブっているけど、まぁ良しとする。
    NSDate *now = [NSDate date];
    NSDateFormatter *fmtr = [[NSDateFormatter alloc] init] ;
    [fmtr setDateFormat:@"yyyy/MM/dd HH:mm:ss"];
    _lblClock.text = [fmtr stringFromDate:now];
    [fmtr release];
}

美女Linuxの画像は iPhone4 用に 960×640 で用意しておきます。縦横比が写真と異なるので加工が必須ですね(拡大縮小をしてもいいんでしょうけど、綺麗さが損なわれるのでやめます)。

シミュレーターを動かしながら、try & error を繰り返すわけですが、このぐらいのコードであれば 2 時間で書けるようになりました(2時間も掛かるという話もあるッ!!!)。NSDateFormatter の使い方がわからんとか、NSTimer は autorelease しちゃいけないとか、落ちるところには落ちまくったので、もう一度作るときはまぁ大丈夫です。

大枠はできたので、他に加工するところは、

・日時表示をもう少し綺麗に
・美女Linux のロゴを表示(透過PNGを使う)
・画像の切り替えをアニメーションで(お手軽にできれば)
・美女Linux のロゴをクリックしたら、通信回線を調べて、ブラウザで表示。

ぐらいですかね。ある程度できたら、さっさと apple store に公開してみよう。

カテゴリー: Objective-C, iPad | 美女Linux on iPhoneを作る(1) はコメントを受け付けていません

PMBOKの開発工程が手薄なので、100プロセス追加してみるテスト

PMBOK ってのは、プロジェクト マネージメントなので、管理者側(management)の視点から書かれているのがご存知の通り。な訳ですが、実際、ソフトウェア開発をする上では、開発(development or impliment)の作業が必須なわけで、SWEBOK が良いというかというとそうではなくて、managment から見た pmbok 配下の開発工程プロセスの手薄さは、プロジェクト自体の破綻を招くのではないかッ!!! とかいうことをあえて【妄想】してみて、100 項目ほど挙げてみます。

ま、7月頭だし、たまにはコーディング以外の頭も廻すということで。

一応、アジャイル開発も意識していますが、PMBOK ベースなのでウォーターフォール開発中心のプロセス/tipsになります。

・いわゆる「software factory」状態にすること(最近の microsoft ではやらないが)
 文章中、人=機械となっているのは、このためです。
・ムリ・ムラ・ムダを気に掛けること。
・完了しないリスクに対して、最大限対処すること。
 → 開発工程については設計に沿っての【完遂】が優先事項であるため。

■進捗関連
001 開発工程の初期に「巡航速度」を把握する(平均的なコーディング量、生産性を把握する)
002 巡航速度に従ったときに、開発工程の納期が間に合うかを定期的にチェックする。
003 間に合わない場合は、増員を準備する(この時点で「生産性」を上げることは難しい)
004 間に合わない場合は、生産量を減らす(設計工程の手戻りとなる)
005 間に合わない場合は、ムダな作業を減らす(自動化できるところを自動化する。ただし、設計工程の手戻りとなる)
006 巡航速度よりも早い場合は、燃え尽き症候群に注意する。
007 巡航速度よりも早い場合は、不用意なコピー&ペーストに注意する(全体の生産量が上がってしまう可能性がある)
008 巡航速度よりも早い場合は、不具合の発生率が高くなる(不良品の混入率が高くなる)
009 巡航速度よりも早い場合は、勤務時間に注意する(単位時間あたりの巡航速度を守る)
010 巡航速度よりも早い場合は、嘘の報告に注意する(意図的に生産性を挙げている可能性がある)

■不具合関連
011 開発工程の初期で不具合発生数を最初に決める(不具合を直す時間をとる)
012 不具合発生率の高い人員を見つける(人=生産機械と考えると、不具合の多い機械ということになる)
013 不具合発生率が高い場合は、巡航速度を下げる(不注意なバグが減る)
014 不具合発生率が高い場合は、コード量を減らす(不具合の発生しやすい箇所をひとつにまとめる)
015 軽度な不具合は、発生率としてカウントしない(xUnit 内での不具合をカウントすると時間コストがかかる)
016 軽度な不具合は、コーディングの生産量を抑えて調節する(xUnit を用いて、コード&テストを一体化する)
017 重度な不具合は、周知する場所を作る(軽度/重度を区別する)
018 重度な不具合は、修正サイクルを遅く廻す(すぐに修正しようとすると、コーディング自体が止まってしまう)
019 修正サイクルを遅く廻すには、不具合票を取り回す(あえて、重たい紙の不具合票や、手順が多い不具合票にする)
020 重度な不具合は、コーディング&テストのサイクルに含めない(コーディングの速度を不意に上げ下げしてしまう)

■規約関連
021 コーディング規約は、周知できるものにとどめる(開発者のスキルにあわせる)
022 コーディングスタイルを合わせることも規約のうちに含める(初心者が多い場合は、ベテランが修正する可能性が高いので)
023 平易に書けるコーディング規約にする(IDE などの規約にあわせる)
024 規約に合わせるリファクタリングを許す(巡航速度の範囲で)
025 規約には例外があることを周知する(規約は「ルール」や「モラル」でしかない)
026 規約のための問い合わせを減らす(コミュニケーションコストを減らす)
027 テンプレートを随時用意する
028 一度、テンプレートに従ってコーディングをしてみる(コーディング時の規約による負担がわかる)
029 多すぎる規約は、減らす(規約に頭を取られるのは問題)
030 コーディング状態に合わせて規約を追加する(コーディングの現状にあわせる。最大公約数を使う)

■品質システム関連
031 開発工程の途中で、開発物をチェックする時間をとる。
032 チェック自体は形式的でもよい(「チェックする」こと自体が重要)
033 重度の不具合は常にカウントし、監視する(多くならないようにする)
034 重度の不具合を発生箇所(人)を監視する(多くならないようにする)
035 重度の不具合について、「理由」を明確にする(理由があればOKとする)
036 監視作業はできるだけ管理者自身が行う(虚偽の報告を減らすため)
037 監視作業はできるだけ自動化する(人手を減らす、あるいは人的理由で進捗の進退が変わらないように)
038 監視作業は、監視されているこを意識させないようにする(計測されることに注力されてしまう)
039 リスクが減ったら、監視自体をやめてもよい(単純なモニタリング作業に戻す)
040 「監視されている」という意識だけを植え付けて、実際監視作業はしなくてもよい(モラルの問題、性善説風な性悪説手法)

■稼動率関連
041 定時の作業を監視する(巡航速度を守るためムリな徹夜、残業をしない)
042 定時の作業量を監視する(一定の生産量を計測する)
043 休日に関しては、あらかじめ確保しておく(週単位の進捗量ではなく、日単位を監視する)
044 休出に関しては、時間をカウントする(巡航速度を守るため)
045 残業に関しては、時間をカウントする(巡航速度を守るため)
046 生産性は、人単位で計測する(人=機械の生産性のばらつきを考慮する)
047 難易度が異なる場合は、大枠で生産量をカウントする(早くなったり遅くなったりをカウントするのを正確にカウントするとコストがかかる)
048 別作業が割り込みであった場合は、時間を減算する(巡航速度を守るため)
049 月20日、8時間/日の 160h/月でカウントすると大枠で正しい。
050 開発工程を完遂することが目的なので、そのほかの稼動率は考慮しない(細かいところにコストを掛けない)

■コミュニケーション関連
051 コミュニケーション自体には「コスト」があることを意識する(会議にはコストがかかっている)
052 会議コストは、開発工程の初期に計上しておき、生産性から外す(巡航速度を計測するため)
053 会議コストは、主に資料集めにある(管理者は例外)
054 会議コストは、物事が決まらない場合は「最大値」となる(いわゆるムダな会議となる)
055 進捗報告は、監視側(管理者側)が抽出した資料をもとにする(虚偽を防ぐため)
056 進捗報告は、常に開発工程の完了を意識する(目的を明確にする)
057 軽度の遅れの見込みは、無視してよい(会議コストが上がるため)
058 進捗のムラに関しては、長期的な監視の対象とする(巡航速度が下がっていなければよい)
059 開発自体にムリがないことを確認する(ムダな作業が、貴重な時間を押しつぶしていないか)
060 開発自体のムダを省くように管理者は注力する(ムダな作業で、貴重な時間を使っていないか)

■人員関連
061 マイナス生産者を外す(他開発者への邪魔となるため)
062 マイナス生産者を隔離する(他開発者への影響をさげるため)
063 マイナス生産者に規定の作業を与える(作業見積がしやすい、超過がわかりやすい)
064 マイナス生産者に定期作業を与えるとプラスに転じる(定期作業は不具合のリスクが低いため)
065 初心者には定型作業を与える(巡航速度が把握しやすい)
066 初心者にはシンプルな作業を割り振る(不具合が発生しにくい)
067 ベテランには複雑な作業を割り振る(開発工程全体の生産性をあげるため)
068 ベテランには不具合発生率の高い作業を割り振る(重度不具合の対処など)
068 ベテランは、初心者のフォローに廻るだけでもよい(不具合の対処、ライブラリ作成など)
069 ベテランは、時には生産性を考慮しない(巡航速度だけを守るため)
070 開発スピードは標準的な開発者を集めた場合を考慮する(巡航速度を守るため)

■制約条件関連
071 外してよい制約があれば、即外してしまう(ムダな規約、細かすぎる進捗報告など)
072 制約は時間依存である(時間経過により状況が変わると、制約が変わる)
073 制約は前提依存である(前提条件が変わると、制約が変わる)
074 制約を見つけたあとは、その制約を利用すると(見かけ上)生産性があがる(ムダが減るなど)
075 取り除けない制約には、ベテランを配置する(生産性が一番高い人を配置する)
076 ベテランを、長期に縛る作業に割り当てない(変化する制約に対処させるため)
077 ベテランを、休ませない(常に働かせる状態がよい)
078 他の作業が止まりそうな不具合は即対処する(他作業がとまってしまうので)
079 他作業が止まらない作業にはベテランを配置しない(キーとなる合流プロセスで利用する)
080 インプットとアウトプットを固定して、内部を変化可能にする(契約プログラミングなど)

■モチベーション関連
081 人=機械ではないので、プロジェクトが終わった後の人を意識する。
082 不定期なガス抜きを考慮する(定期的なガス抜きは時には負担になる)
083 一定量のコーディングをしたら、その日は帰る(ムリな作業はしない)
084 一定量の不具合をつぶしたら、その日は帰る(ムリな作業はしない)
085 効率化を求める場合は、3 倍以上のスピードになることを確認する(2倍以下では全体に大きく関わらない)
086 手作業ではなく頭を使う作業をする(疲れるが、そのほうが作業効率がよい)
087 手作業が必要な場合は、時間を決めて作業をする(開発者自身の作業効率を知る、巡航速度を守る)
088 使い捨ての道具「治具」を作る時間を確保する(一時的に作業量が減る)
089 「治具」は過度に高度化させない(所詮、使い捨てなので過度に自動化させない)
090 プロジェクト内に過度に「遊んでいる」人を作らない(ばらつきはあってもよいが、他の人のモチベーションに関わる)

■コスト関連
091 人的コストよりも、既存ソフトウェアコストのほうが安い(購入できれば、それを使う)
092 セキュリティによる制約コストは高い(ウィルススキャン、フリーソフトの導入不可など)
093 調査コストは非常に高い(インターネットで探せればそれに越したことはない)
094 書籍コストは非常に安い(人的コストに比べると安い)
095 複雑化されたコードよりも、単純化されたコードのほうが保守コストが低い。
096 人依存でないコードのほうが、保守コストは低い。
097 製品寿命を考慮したコーディングをするほうが、開発コストが低い。
098 管理されたリスクに対しての対処コストは低い(管理されてないリスクに対しては非常に高い)
099 コード量が少ないほうが、保守コストは低い
100 保守コストが高くなる場合のみ、開発期間を延ばしてよい。

と、ざっと書き下しましたが(2時間程度)、プロセスでなくて、チェックシートみたいになってしまいましたが、ひとまずこれで up することにします。機会があれば、もうちょっと手直しをするということで。
リスク発生 → 対処方法 の流れがないといけないし、PDCA の Check → Action → Plan の繋がりがないと駄目ですからね。

カテゴリー: プロジェクト管理, Plan Language | PMBOKの開発工程が手薄なので、100プロセス追加してみるテスト はコメントを受け付けていません

UIScrollView 上では UIViewController 上のボタンイベントを拾えない

電子書籍のおおまかな構造設計をしている途中なのですが、どうも腑に落ちない現象に出会ったのでメモ的に。
結論から言うと、タイトル通り、UIScrollView 上にある UIViewController のイベントは、手軽には拾えません…という話です。

■設計要件

まずは、次のように設計を考えました。

・ページ捲りの部分は、UIScrollView を使う。
 → スライドさせたいので、ページを横に並べてスクロールさせるとよい。
 → ページ捲りのアニメーションよりも、手軽に作れる、と思う。
 
・ページ単位は、View で作りたい。
 → 手軽にページを構成したいので、ページ単位で作りたい。
 → これは UIViewController にボタンなどを乗せるのがよいかなと。
 
・ページ間で共通のボタンがある。
 → ナビゲートボタンのように、ページ間で共通の場所にボタンがある。
 → 自動生成をするか、スクロールさせても移動させない、のどちらか。
 
最終的には、スクリプトを書いてページを構成するための objective-c のソースコードを出力させたいわけです。

■クラス構造

これを踏まえてクラス構造を考えて、素直に以下の構造にしました。

UIApplication
+ MainViewController : 最初の View
 + UIView
  + UIScrollView
   + UIViewController
    + UIView
     + Button : ボタン
     + Movie : 動画
     + Image : 背景画像 

なんか、ややこしそうに見えますが、

・MainView の上に ScrollView が乗っかる。
・ScrollView の上にページ単位となる ViewController が乗っかる。
・ページ単位の ViewController の上に Button などが乗っかる。

という感じです。

■Button のイベントは、ViewController で取れる筈

そんなわけで、Button を貼り付けて、UIViewScroller で取ろうとしたのですが、なぜか飛ばない。

UIApplication
+ MainViewController 
 + UIView
  + UIScrollView
   + UIViewController ←ここに飛んで欲しい
    + UIView
     + Button : ボタンのイベント
     + Movie 
     + Image  

試しに、Main の ViewController の上に Button を置くとうまくイベントを拾えます。

UIApplication
+ MainViewController : ←ここで拾える
 + UIView
  + Button : このイベントは
  + UIScrollView
   + UIViewController
    + UIView
     + Button 
     + Movie 
     + Image  

同じコードを打っているはずなのに何故に???ってことで調べていくと、どうやら、ScrollView のほうが先にタッチイベントを取ってしまうので、その上に乗っているコントロールにはイベントがいきわたらないのですね。なるほど。

# ボタンクリックのイベントは UIControlEventTouchUpInside で取得すればよいのですが、ScrollView のスクロールのために取られてしまうという現象。

■解決にはどうすればいいのか?

UIScrollView をサブクラス化して、なんらかの Touch イベントを拾えば解決できそうなんですが、ScrollView 内に複数の ViewController が乗ることになるので、これにはひと工夫必要そう。

なので、まだ未解決。まあ、ボタンなんかは MainViewController に貼り付けておいて、Main のほうでイベントを拾うってのが逃れ方なのでしょうけど、あまりスマートではないし。なにしろ Page 単位の ViewController が複数あるので、ちょっと考えないと、というところです。

カテゴリー: 開発, iPad | 6件のコメント

iPad の電子書籍アプリを作るよ(1)

とある六本木でとある電子書籍アプリを作っている途中でして…全くの iPad/iPhone の素人プログラマ(.NET プログラミングに関してはプロねッ!!!プロッ!!!) が、玄人になるまでの航跡だったらいいなぁと。

iPad電子書籍アプリ開発ガイドブック
http://www.amazon.co.jp/dp/4844329065

賛否両論ありましょうが、最初の一冊が↑です。
電子書籍アプリに特化しているので、その他のアプリ(ゲームアプリとかネットにアクセスするアプリとか)には全く役に立ちませんが、逆に言えば、取っ掛かりとしては十分です。

これを読んで、電子書籍アプリの作成をする際に、

・文章も含めて背景を貼り付ける。
・動画やアニメーションを重ね合わせる。
・透明ボタンを重ね合わせて、ボタン機能を作る。

という方針を決めました。まぁ、お手軽に作るのと、電子書籍自体のページ数がそう多くない場合(50頁以下ぐらい?)ならば、こっちのほうがやりやすいかなと。

以下は、上記を実現するためのコードメモです。

■背景画像の貼り付け

UIView を継承している PageView クラスの drawRect に記述する。
背景で使う画像ファイル(title.jpg)は、Resource フォルダに突っ込んでおく。

in PageView.h

#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>

@interface PageView : UIView {
}
@end

in PageView.h

- (void)drawRect:(CGRect)rect {
	UIImage *img = [UIImage imageNamed:@"title.jpg"];
	[img drawInRect:CGRectMake(0,0,768,1024)];
}

■動画の表示

よくわからんですが、UIView::initWithFrame のところ(初期化かな?)で、MPMoviePlayerController クラスを使って動画を表示させます。カレントビューに [self addSubview:movie.view]; な形で追加して指定した矩形に表示させます。
本当は、動画の終了を検知しないといけないんですけどね、これは後ほど。

- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        // Initialization code
		self.backgroundColor = [UIColor whiteColor];
		
		MPMoviePlayerController *movie = [[MPMoviePlayerController alloc] 
			initWithContentURL:[NSURL fileURLWithPath:[
			[NSBundle mainBundle] pathForResource:@"m01" ofType:@"mov"]]];
		movie.controlStyle = MPMovieControlStyleNone;
		movie.scalingMode  = MPMovieScalingModeFill;
		movie.view.frame = CGRectMake(50,50,400,300);
		[movie play];
		[self addSubview:movie.view];
    }
    return self;
}

■横スクロールさせる

ページ送りは、いくつか方法があるのですが、指でスライドさせることでページを送れるスクロール方式にします。
ちょっと、方法は後で変えるかもしれませんが、実験コードということで、ざっと。

UIView を継承した PageView クラスの表示部分で、3 枚の背景画像を貼り付けます。
なので、横幅が、768 x 3 ドットのビューができますね。

in PageView.m

- (void)drawRect:(CGRect)rect {
    // Drawing code
	UIImage *img1 = [UIImage imageNamed:@"title.jpg"];
	[img1 drawInRect:CGRectMake(768*0,0,768,1024)];
	UIImage *img2 = [UIImage imageNamed:@"winemovie01.jpg"];
	[img2 drawInRect:CGRectMake(768*1,0,768,1024)];
	UIImage *img3 = [UIImage imageNamed:@"last.jpg"];
	[img3 drawInRect:CGRectMake(768*2,0,768,1024)];
}

これを横スクロールさせるために UIViewController クラスを継承した SamplePad04ViewController のようなクラスの loadView メソッドを書き換えます。

in SamplePad04ViewController.m

- (void)loadView {
	[super loadView];
	PageView *pageView = [[PageView alloc]
						  initWithFrame:CGRectMake(0,0,768*3,1024)];
	UIScrollView *scrollView = [[UIScrollView alloc]
								initWithFrame:self.view.bounds];

	[scrollView setContentSize:pageView.frame.size];
	[self.view addSubview:scrollView];
	[scrollView addSubview:pageView];
	[scrollView setDelegate:self];
	[scrollView setPagingEnabled: YES];
}

表示するビューの親子関係は UIViewController -> UIScrollView -> PageView になります。
親子関係は addSubview メソッドを使います(そうらしい)。

■参考にしたサイト

iPhoneアプリ開発、その(118) UIScrollViewはどうやって使うのか?|テン*シー*シー
http://ameblo.jp/xcc/entry-10322378932.html
UIScrollView
http://iphone-tora.sakura.ne.jp/uiscrollview.html

カテゴリー: 開発, iPad | iPad の電子書籍アプリを作るよ(1) はコメントを受け付けていません

SqlBulkCopy のスピードは 20 倍ぐらい早い

SQL Server に insert を繰り返してデータを入れる場合は、

・bcp を使う。
・bulk insert を使う。
・SqlBulkCopy を使う。

を使います。bcp や bulk insert の場合は、ファイルからインポートするのでちょっと扱いづらい。SQL Server が別のマシン(サーバー機)にある場合は、一度ファイル転送をするか、ファイル共有をしないといけないので、ちょっと面倒です。

なので、SqlBulkCopy を使う…ってところまでは知っていたのですが、果たしてどのぐらいのスピードかどうかは定かだではないので、測定してみました。

結論から言えば、20 倍ほど早くなります。SQL Server 2008 の場合は 30 倍ほど、SQL Server 2000 の場合は 10-20 倍ほどなので業務コードに入れる場合は実測が必須ですね。

以下は、

create table bulk0 (
  id int,
  val varchar(100)
)

のテーブルに 10 万件のデータを挿入したときの結果です(CPU 1.7GHz程度)

Normal 3.37 sec
Insert 46.34 sec
Normal 4.00 sec
Insert 43.29 sec
Normal 1.85 sec
Insert 47.50 sec
avg. Normal     3.07 sec
avg. Insert     45.71 sec

以下は、実験用のコード。
SqlBulkCopy には、DataTable あるいは DataRow の配列を渡せるので、大量データの挿入が非常に楽になります。まあ、大量すぎる場合は、DataTable のメモリ溢れに注意する必要がありますが on memory に乗る量であれば、この程度で ok ということで。

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

namespace SampleBluk
{
	class TestBulk
	{

		public void Go()
		{
			double t1 = 0.0;
			double t2 = 0.0;
			_dt = MakeDataTable();

			int max = 3;
			for (int i = 0; i < max; i++)
			{
				DateTime start;
				double span;

				setup();
				start = DateTime.Now;
				TestNormal();
				span = ((TimeSpan)(DateTime.Now - start)).TotalSeconds;
				Console.WriteLine("Normal {0:0.00} sec", span);
				t1 += span;

				setup();
				start = DateTime.Now;
				TestInsert();
				span = ((TimeSpan)(DateTime.Now - start)).TotalSeconds;
				Console.WriteLine("Insert {0:0.00} sec", span);
				t2 += span;

			}
			Console.WriteLine("avg. Normal	{0:0.00} sec", t1 / max);
			Console.WriteLine("avg. Insert	{0:0.00} sec", t2 / max);
            // avg. Normal     3.07 sec
            // avg. Insert     45.71 sec
		}

		int _max = 100000;
		DataTable _dt;
		// 接続文字列
		const string CNSTR =
			@"Data Source=.\sqlexpress;Initial Catalog=stress;Integrated Security=True;Pooling=False";

		private string toMD5(string s)
		{
			//文字列をbyte型配列に変換する
			byte[] data = System.Text.Encoding.UTF8.GetBytes(s);

			//MD5CryptoServiceProviderオブジェクトを作成
			System.Security.Cryptography.MD5CryptoServiceProvider md5 =
				new System.Security.Cryptography.MD5CryptoServiceProvider();
			//または、次のようにもできる
			//System.Security.Cryptography.MD5 md5 =
			//  u  System.Security.Cryptography.MD5.Create();

			//ハッシュ値を計算する
			byte[] bs = md5.ComputeHash(data);

			//byte型配列を16進数の文字列に変換
			System.Text.StringBuilder result = new System.Text.StringBuilder();
			return BitConverter.ToString(bs).ToLower().Replace("-", "");
		}

		public DataTable MakeDataTable()
		{
			DataTable dt = new DataTable();
			dt.Columns.Add(new DataColumn("id", typeof(int)));
			dt.Columns.Add(new DataColumn("val", typeof(string)));
			string s = toMD5(DateTime.Now.ToString());
			for (int i = 0; i < _max; i++)
			{
				DataRow row = dt.NewRow();
				dt.Rows.Add(row);
				row["id"] = i;
				row["val"] = s;
				s = toMD5(s);
			}
			return dt;
		}
		public void setup()
		{
			SqlConnection cn = new SqlConnection(CNSTR);
			SqlCommand cmd = new  SqlCommand("truncate table bulk0", cn);
			cn.Open();
			cmd.ExecuteNonQuery();
			cn.Close();
		}


		public void TestNormal()
		{
			DataTable dt = _dt;

			SqlConnection cn = new SqlConnection(CNSTR);
			SqlBulkCopy bc = new SqlBulkCopy(cn);
			bc.DestinationTableName = "bulk0";
			cn.Open();
			bc.WriteToServer(dt);
			cn.Close();
		}
		public void TestInsert()
		{
			DataTable dt = _dt;

			SqlConnection cn = new SqlConnection(CNSTR);
			SqlCommand cmd = new SqlCommand("insert into bulk0 ( id, val ) values ( @id, @val ) ", cn);
			cmd.Parameters.Add(new SqlParameter("@id", SqlDbType.Int));
			cmd.Parameters.Add(new SqlParameter("@val", SqlDbType.VarChar, 100));

			cn.Open();
			foreach (DataRow row in dt.Rows)
			{
				cmd.Parameters["@id"].Value = row["id"];
				cmd.Parameters["@val"].Value = row["val"];
				cmd.ExecuteNonQuery();
			}
			cn.Close();
		}
	}
}
カテゴリー: 開発, C# | SqlBulkCopy のスピードは 20 倍ぐらい早い はコメントを受け付けていません