Float on the flow

とあるエンジニアのブログ。「ゆったり・しっかり」がモットー。

データのインポート/エクスポート機能は必須でしょ

1000件近いデータをWebの画面からチマチマ入力するとかありえんw
Excelでデータ渡すから取り込んでよ」って頼んでみたらあっさり断られたし。
できないものは仕方ないんだけどさ。

じゃ、どうする?

CSVでいいから、インポート/エクスポート機能つけといてくださいお願いします。

オーダーメードのソフトでもほしいけど、パッケージソフトでは必須と思う。
だってカスタマイズできないもんねぇ。

使い勝手、便利さ

ユーザからみた使い勝手、便利さっていうのは、インタフェースなんです。
画面とかファイルとか、データ形式はともかく、インタフェースが重要です。
ユーザから見たら、中身はブラックボックスなので。見えるのはインタフェースだけなので。

というわけで

大量データを一気にやりとりするためのインタフェース、
すなわちインポート/エクスポート機能は必須でほしいです!

そうはいうけど開発側から見たら

開発工数増えるし、カスタマイズ費用をもらう機会が減っちゃうかもしれないし、
あんまりやりたくないよね。少なくとも優先順位は低くなるだろうな。

あと、開発者にとっての使い勝手、便利さって、言語やIDEのそれだったりしますよね。
結局それが仕事だから。

多次元構造をRDBで表現するのって難しいよね

こちらからのインスパイア。というか思い出したこと。

「今時の組織はSQL不向き? - Ognacの雑感」
http://blogs.wankuma.com/ognac/archive/2009/09/23/181540.aspx


以前、ワークフローエンジンを自前で組んだことがあったのですが、そのときにも大変苦労しました。

組織図ツリーと、ワークフローのリストと。
それぞれ時系列での変化への対応も必要で。

バージョン1はかなりきたないER図になってしまったことを思い出します。
各々のツリー表現と、相互の関係と、そこに使用開始日・終了日をもたせる構造にしてしまったので。
で、当然のごとく処理も重かったと。
(データがたまるとガンガン重くなった)


バージョン2では、楽々ERDレッスンとか読んで勉強した内容を元にER図から見直して、だいぶすっきりした構造にはなったのですが、外的要因によりコードは日の目を見ず。
(一部は活用しましたが)


オブジェクトDBでそのまま永続化できたらいいのになーと思うこともありますが、SQLの非手続き的な振る舞いもとても魅力なのでなかなか捨てられず。
(それとも、オブジェクトDBでもSQL的に集合論的な検索をかけられたりするんでしょうか??)



まぁ、今ではExcelのシートとかCSVファイルに対してSQLを発行する程度のことしかしてないんですけどね。
ふと思い出したもので。

FxUG第79回@北陸に参加!

9/12に開催されたFxUG第79回@北陸に参加してきました。

 ⇒http://www.fxug.net/modules/bwiki/index.php?Flex3%CA%D9%B6%AF%B2%F1%C2%E879%B2%F3%A1%F7%CB%CC%CE%A6%28%C0%D0%C0%EE%29%BB%B2%B2%C3%BC%F5%C9%D5


自分は仕事でFlexを使っているわけではないのですが、良い刺激になりました。懇親会も含めて。


ビンゴは残念ながら当たらず。
本もらえたら発表者やる覚悟きめてたんだけどなーw


Twitter×勉強会の組み合わせは最強

おもしろすぎました。Tweet Bubblesでのほぼリアルタイムな発表者と参加者とのかけあい。
自分はうっかりデモの邪魔をしてしまいましたがw

勉強会はパソコン必須

最近はネットワーク環境を整備していただけることが多いので、
パソコン持ち込みは必須ですね。PC有無で楽しさが100倍違ってくると思います。

デザイナーさん向けの内容ってなんだろう

FxUGの立ち位置とかいろいろあると思うんですが、デザイナーさんとかFlex初心者の人には結構ハードルが高い話が多かったような気も。

だからといってあまり簡単な話ばっかりだとコアなメンバーにはつまらなくなってしまうし。
難しい問題です。


今回の話だと、Adobe轟さんのFlash Catalyst の話とか、@shoitoさんのLTとかがちょうどよい内容だったのかな?
実務でデザイナーさんやってるわけじゃないので、よくわからないですが。どうなんでしょう。

テクスチャ重要

テクスチャとか素材感ってのが「オサレ度」をアップするキーポイントだと思いました。
金属、ガラス、カーボン、プラスチック、木、布、石…

Flash的には「動き」もキーポイントかな。
Beautiflに載ってる作品とか見てるとそう思います。

アイコン重要

懇親会で出ていた、「名札を用意して、そこにtwitterはてな等つかってるアカウントのアイコンを貼ったらいいんじゃね?」って意見に同意。
何回か会っているメンバーならいいですけど、そうでないと顔とアカウントが一致しなかったりしますので。

でも、準備するのが大変か?
参加登録サイトに印刷用データを作る機能があればラクチンか?


というわけで

存分に楽しめました。また参加したいです。
運営のみなさま、参加者のみなさま、お疲れ様でした!

VLOOKUP関数とINDIRECT関数

ExcelのVLOOKUP関数とINDIRECT関数が超便利。


Excelでいろいろ集計するシートを作っていると、計算式の中にシート名や「○○名称」などの文字列リテラルが入り込んでくる。
最初はそれでもいいんだけど、件数*1が増えてくると、メンテナンスが大変になる。


せっかくコンピュータを使ってるんだから、なるべく人間の作業は減らしたい。
Excelならオートフィル(範囲選択してドラッグしたら値や式ががーっとコピーされる、あれ)を使うとか。
そこまでできなくても、せめて「計算式中の部分文字列を選択して手入力で修正×大量のセル」っていう作業は無くしたい。


そんなとき、便利なのがVLOOKUPとINDIRECT。


VLOOKUPがあれば、どこかにある一覧表からデータを拾って来て、マスタ変換みたいなことができる。
INDIRECTがあれば、シート名とかをどこかのセルに書いておいて、それを参照しながら値を取れる。
文字列リテラルを計算式外に追い出すことができる。


すると、ひとつの計算式をがーっとコピーして、あとはキーになる値だけ入力してやればOKになる。



これ、かなり生産性が変わってきますよ。



#って、具体的なコードとかがないとよくわかんないですねぇ。

*1:行数、列数

TDD勉強会第2回終了時点のソースコード(Java版)

12章以降、id:kabakiyoさんはC#でコーディングされていたのですが、自分はそれを見つつ
教科書通りにJavaでコーディングしていました。

というわけで、Javaのコードを公開しておきます。
 ⇒17章終了時で、最終的に以下のようなコードになりました。 
 (自分の環境でGreenになったコード)

 ⇒感想等はこちら http://d.hatena.ne.jp/shozzy/20090627/1246110366



MoneyTest.java

import junit.framework.TestCase;

public class MoneyTest extends TestCase{
	
	public void testMultiplication(){
		Money five = Money.dollar(5);
		assertEquals(Money.dollar(10), five.times(2));
		assertEquals(Money.dollar(15), five.times(3));
	}

	public void testEquality(){
		assertTrue(Money.dollar(5).equals(Money.dollar(5)));
		assertFalse(Money.dollar(5).equals(Money.dollar(6)));
		assertFalse(Money.franc(5).equals(Money.dollar(5)));
	}

	public void testCurrency(){
		assertEquals("USD", Money.dollar(1).currency());
		assertEquals("CHF", Money.franc(1).currency());
	}
	
	public void testSimpleAddition(){
		Money five = Money.dollar(5);
		Expression sum = five.plus(five);
		Bank bank = new Bank();
		Money reduced = bank.reduce(sum, "USD");
		assertEquals(Money.dollar(10), reduced);
	}
	
	public void testPlusReturnsSum(){
		Money five = Money.dollar(5);
		Expression result = five.plus(five);
		Sum sum = (Sum) result;
		assertEquals(five, sum.augend);
		assertEquals(five, sum.addend);
	}
	
	public void testReduceSum(){
		Expression sum = new Sum(Money.dollar(3), Money.dollar(4));
		Bank bank = new Bank();
		Money result = bank.reduce(sum, "USD");
		assertEquals(Money.dollar(7), result);
	}
	
	public void testReduceMoney(){
		Bank bank = new Bank();
		Money result = bank.reduce(Money.dollar(1), "USD");
		assertEquals(Money.dollar(1), result);
	}
	
	public void testReduceMoneyDifferentCurrency(){
		Bank bank = new Bank();
		bank.addRate("CHF", "USD", 2);
		Money result = bank.reduce(Money.franc(2), "USD");
		assertEquals(Money.dollar(1), result);
	}

	
	public void testIdentityRate(){
		assertEquals(1, new Bank().rate("USD", "USD"));
	}
	
	public void testMixedAddition(){
		Expression fiveBucks = Money.dollar(5);
		Expression tenFrancs = Money.franc(10);
		Bank bank = new Bank();
		bank.addRate("CHF", "USD", 2);
		Money result = bank.reduce(fiveBucks.plus(tenFrancs), "USD");
		assertEquals(Money.dollar(10), result);
	}
	
	public void testSumPlusMoney(){
		Expression fiveBucks = Money.dollar(5);
		Expression tenFrancs = Money.franc(10);
		Bank bank = new Bank();
		bank.addRate("CHF", "USD", 2);
		Expression sum = new Sum(fiveBucks, tenFrancs).plus(fiveBucks);
		Money result = bank.reduce(sum, "USD");
		assertEquals(Money.dollar(15), result);
	}

	public void testSumTimes(){
		Expression fiveBucks = Money.dollar(5);
		Expression tenFrancs = Money.franc(10);
		Bank bank = new Bank();
		bank.addRate("CHF", "USD", 2);
		Expression sum = new Sum(fiveBucks, tenFrancs).times(2);
		Money result = bank.reduce(sum, "USD");
		assertEquals(Money.dollar(20), result);
	}

	/*
	//最後に削除されてる
	public void testPlusSameCurrencyReturnsMoney(){
		Expression sum = Money.dollar(1).plus(Money.dollar(1));
		assertTrue(sum instanceof Money);
	}
	*/
}

Money.java

public class Money implements Expression{
	protected int amount;
	protected String currency;
	
	Money(int amount, String currency){
		this.amount = amount;
		this.currency = currency;
	}
	
	public boolean equals(Object object){
		Money money = (Money) object;
		return amount == money.amount
			&& currency().equals(money.currency());
	}
	
	static Money dollar(int amount){
		return new Money(amount, "USD");
	}
	
	static Money franc(int amount) {
		return new Money(amount, "CHF");
	}

	public Expression times(int multiplier){
		return new Money(amount * multiplier, currency);
	}
	
	String currency(){
		return currency;
	}
	
	public String toString(){
		return amount + " " + currency;
	}

	public Expression plus(Expression addend) {
		// TODO Auto-generated method stub
		return new Sum(this, addend);
	}
	
	public Money reduce(Bank bank, String to){
		int rate = bank.rate(currency, to);
		return new Money(amount / rate, to);
	}
}

Expression.java

interface Expression {
	Money reduce(Bank bank, String to);

	Expression plus(Expression addend);

	Expression times(int multiplier);
}

Bank.java

import java.util.*;
class Bank {

	public Money reduce(Expression source, String to) {
		// TODO Auto-generated method stub
		return source.reduce(this, to);
	}

	public void addRate(String from, String to, int rate) {
		// TODO Auto-generated method stub
		rates.put(new Pair(from, to), new Integer(rate));
	}
	
	int rate(String from, String to){
		if(from.equals(to)) return 1;
		Integer rate = (Integer) rates.get(new Pair(from, to));
		return rate.intValue();
	}
	
	private Hashtable rates = new Hashtable();
}

Sum.java

public class Sum implements Expression{
	Expression augend;
	Expression addend;

	Sum(Expression augend, Expression addend) {
		// TODO Auto-generated constructor stub
		this.augend = augend;
		this.addend = addend;
	}

	public Money reduce(Bank bank, String to) {
		// TODO Auto-generated method stub
		int amount = augend.reduce(bank, to).amount + addend.reduce(bank, to).amount;
		return new Money(amount, to);
	}

	public Expression plus(Expression addend) {
		// TODO Auto-generated method stub
		return new Sum(this, addend);
	}

	public Expression times(int multiplier) {
		// TODO Auto-generated method stub
		return new Sum(augend.times(multiplier), addend.times(multiplier));
	}
}

Pair.java

public class Pair {

	private String from;
	private String to;
	
	Pair(String from, String to){
		this.from = from;
		this.to = to;
	}
	
	public boolean equals(Object object){
		Pair pair = (Pair) object;
		return from.equals(pair.from) && to.equals(pair.to);
	}
	
	public int hashCode(){
		return 0;
	}
}

TDD勉強会 第2回も参加!

Kanazawa.processことTDD勉強会第2回に参加してきました。
新規参加の方も交えつつ、今回も濃い時間をすごせました。


会場を用意していただいたid:mac10 ++
お茶・お菓子を準備していただいたid:katzchang ++


会場に無線LANがあるのはとーってもありがたいですね。
すぐに調べ物とか、思ったことをtwitterに流したりできるので。

内容

今回はPart1完了まで進みました(10章〜17章)。
Moneyクラスを拡張していく話とか。なんだけど、最終的にどういう仕様に落ち着かせたいのが見えてないと、どうしてそんなテストをしたくなるのかが理解できなかったり。

前回範囲よりだいぶ難易度が高かった感じがします。


各種IDEリファクタリング機能比較とかが面白かったですね。
EclipseJavaエディタの高機能っぷりに驚いたり。まさに「変態」。

関連エントリ

id:katzchangによるリアルタイムの記録。
http://kanazawa-process.g.hatena.ne.jp/katzchang/20090627/1246076909

メモ

勉強会でおやつをつまむときは割り箸があったほうがいいというライフハック via id:Nagise
(遠くに届くし、指が汚れない=キーボードが汚れない)

「流れるようなインタフェース」

マッケーブの循環的複雑度

augend:被加数 addend:加数 (被加数なんて聞いたこと無いw 表意文字のおかげで想像できるけど)

日本語コーディングのススメ(いまどき、日本語で書いても問題がでることはほとんど無い模様)

感想とか

前回に引き続き濃い感じで楽しかったし、勉強になりました。

一方で、自分ももっとネタを提供できるようにならないとなー、と焦燥感を覚えたり。
前職にしても現職にしても、その小さな世界の中では「できる人」な位置にいるだけに、勘違いしちゃうんですよね。
大海を知らなかった井の中の蛙が大海に足を踏み入れてみた感じというか。

ま、できることからぼちぼちとやっていきます。
(エントリ書いたりとかね)


参加者のみなさま、お疲れ様でした!

Pythonもインストール

18章以降はPythonなんだった!*1
ということで、このあたりからダウンロードしてインストール。http://www.python.jp/Zope/download/pythonjpdist


あと、Eclipse用のプラグイン「PyDev」もインストール。
Eclipseを起動し、Help - Install New Software - "http://pydev.sourceforge.net/updates/" Add... - AddSite Name:"PyDev" OK - Check "PyDev" - Next - Finish


インストールが完了すると、New - Project したときに PyDev という項目が出るようになります。

インタプリタを使用するには、PythonProjectを作成しようとしたときの「Click here to configure an interpreter not listed.」を設定する必要あり。

ついでにHello world

動くか試すためにHello worldしておく。
New - Project - PyDev - PyDev Project で、適当な名前(ここではPythonTest)をつけ、Finish。
(Nextを押すとReferences設定だけど、不要そう)

srcフォルダで、New - PyDev Module を選択。Nameを適当につける(ここではhello)。
すると、hello.pyができるので、コードを書く。
たとえば

print "Hello, world!"

これで、あとは普通にrunすればOK。

それにしても

Pythonって自由にインデントできないらしいね。インデントが意味を持ってるから。

*1:一応、本に書いてることは忠実に再現しておきたいので「ここはRubyでしょ」とかは今はやらないことにした。