2010年5月29日土曜日

プリミティブ型をラップしたクラスを作る。

最近実際に意識している実装方法です。


プリミティブ型をラップしたクラスを作る。
intとかstringという型は抽象的すぎるので、
これを使ってると毎回変数名で意味を表現しなければならない。

ラップクラスを作成するまえは、
変数名がむやみに長くなってしまったり、
短くして意味がわかりにくくなっていました。

string だと文字列の意味しかありませんが、
すごい単純な例ですが
以下のようにTODOという名前のクラスでラップする事により、
stringに意味がつきました。
また必要な関数群を追加していけることもメリットとなります。
後で型を変えたくなっても変更も用意に出来ます。

class Todo
{
public string _todo;
}

出来るだけプリミティブ型は使わない方が、
汎用的に作れると思います。

C++ には便利なtypedefがあり簡単に名前を付ける事が出来るので是非活用したいですね。

.

haskellを触ってみよーってことでMacにインストールしてみた。

ここのサイトを参考に。
http://www.haskell.org/haskellwiki/Mac_OS_X

Haskellのプラットフォームをダウンロード。
http://hackage.haskell.org/platform/mac.html
haskell-platform-2010.1.0.1-i386.dmgをインストール。

コレだけでghcは使えるようになるはず。

ghcだけだとターミナルで使い勝手が悪いので、
hugsもインストールしてみる。

http://www.imasy.or.jp/~miyamoto/mac/install_memo.html
DarwinPortsをインストールしてそこからhugsをインストールする。
DarwinPortsはUnixで動作するアプリを自動ダウンロードインストールしてくれるツール
CentOSで使ったyumと同じようなものなのかも。(まだよくわかってない)

デフォルトのままだと以下のパスにDarwinPortsがインストールされる。
/opt/local/bin
root権限でportsコマンドを実行してhugsをインストール
sudo ports install hugs98

これでhugs98も動いた!

明日あーそぼっと。

.

2010年5月23日日曜日

レガシーコード改善ガイド

『レガシーコードとは、単にテストのないコードである』
という素敵なサブタイトルが興味をそそられます。

レガシーコードにテストコードを追加していく
様々な手法が紹介されています。
主には、キレイに依存関係を排除していく方法が書かれています。
リファクタリングツールがない場合の細かいリファクタリングのステップ等も記載されているので、
大変参考になります。

依存関係の排除以外にも
テストがないコードを保守していく際に必要なテクニックが満載です。

様々な状況別に対応策が記載されているのも分かりやすくてよかった

時間がない。
依存関係が多過ぎてテストが書けない
そもそも、どうやってテストコードを書いていいのかわからない。
etc...

これを気にテストコードを書いていく癖を付けたいものです。

2010年5月22日土曜日

HskellのMaybeクラスをC#で作ってみた。その3


HaskellのMaybeクラスをC#で作ってみた。その2
で作成した
Maybeクラスの単体テストもNUnitを使って書いているので、
それも一緒に公開しておきます。



[TestFixture]
public class MaybeTest
{
[Test]
public void MaybeNothingTest()
{
Maybe<int> nothing = Maybe<int>.Nothing;
Assert.IsFalse(nothing.HasValue);
Assert.Throws<InvalidOperationException>(delegate { int i = nothing.Value; });
}

[Test]
public void MaybeFromTset()
{
DoMaybeFromTest((int)1);
DoMaybeFromTest(DateTime.Now);
DoMaybeFromTest(new InvalidOperationException());
DoMaybeFromTest(new Action<int>(DoMaybeFromTest));
}
[Test]
public void MaybeFromArgumentNullTset()
{
Assert.Throws<ArgumentNullException>(delegate { Maybe<InvalidOperationException>.Just(null); });
}

private static void DoMaybeFromTest<T>(T value)
{
Maybe<T> maybe = Maybe<T>.Just(value);
Assert.IsTrue(maybe.HasValue);
Assert.AreEqual(value, maybe.Value);
}
[Test]
public void GetValueTest()
{
Maybe<int> nothing = Maybe<int>.Nothing;
Assert.AreEqual(1, nothing.GetValue(1));

Maybe<int> maybe = Maybe<int>.Just(20);
Assert.AreEqual(20, maybe.GetValue(1));
}
[Test]
public void EqualsTest()
{
Assert.IsTrue(Maybe<int>.Nothing.Equals(Maybe<int>.Nothing));
Assert.IsTrue(Maybe<int>.Just(1).Equals(Maybe<int>.Just(1)));
Assert.IsTrue(Maybe<DateTime>.Just(new DateTime(2000, 10, 10, 10, 10, 10)).Equals(Maybe<DateTime>.Just(new DateTime(2000, 10, 10, 10, 10, 10))));

Assert.IsFalse(Maybe<int>.Nothing.Equals(null));
Assert.IsFalse(Maybe<int>.Nothing.Equals(Maybe<int>.Just(1)));
Assert.IsFalse(Maybe<int>.Just(19).Equals(Maybe<int>.Just(1)));
}

[Test]
public void OperatorEqualsTest()
{
Assert.IsTrue(Maybe<int>.Nothing == Maybe<int>.Nothing);
Assert.IsTrue(Maybe<int>.Just(1) == Maybe<int>.Just(1));
Assert.IsTrue(Maybe<DateTime>.Just(new DateTime(2000, 10, 10, 10, 10, 10)) == Maybe<DateTime>.Just(new DateTime(2000, 10, 10, 10, 10, 10)));

Assert.IsFalse(Maybe<int>.Nothing == null);
Assert.IsFalse(null == Maybe<int>.Nothing);
Assert.IsFalse(Maybe<int>.Nothing == Maybe<int>.Just(1));
Assert.IsFalse(Maybe<int>.Just(19) == Maybe<int>.Just(1));
}
[Test]
public void OperatorNotEqualsTest()
{
Assert.IsFalse(Maybe<int>.Nothing != Maybe<int>.Nothing);
Assert.IsFalse(Maybe<int>.Just(1) != Maybe<int>.Just(1));
Assert.IsFalse(Maybe<DateTime>.Just(new DateTime(2000, 10, 10, 10, 10, 10)) != Maybe<DateTime>.Just(new DateTime(2000, 10, 10, 10, 10, 10)));

Assert.IsTrue(Maybe<int>.Nothing != null);
Assert.IsTrue(null != Maybe<int>.Nothing);
Assert.IsTrue(Maybe<int>.Nothing != Maybe<int>.Just(1));
Assert.IsTrue(Maybe<int>.Just(19) != Maybe<int>.Just(1));
}

[Test]
public void CastTest()
{
Maybe<Encoding> maybe = Maybe<Encoding>.Just(Encoding.UTF8);
Assert.AreEqual(Encoding.UTF8, (Encoding)maybe);
}
}

HaskellのMaybeクラスをC#で作ってみた。その2


HaskellのMaybeクラスをC#で作ってみた
のMaybeクラスではdefault(T)が気持ち悪かったので、
ガサゴソと、クラスを分離してみた。



public interface IMaybe<T>
{
bool HasValue { get; }

T Value { get; }
}

public class Maybe<T> : IMaybe<T>
{
private readonly IMaybe<T> _maybeValue;

public Maybe(IMaybe<T> maybeValue)
{
_maybeValue = maybeValue;
}
public bool HasValue { get { return _maybeValue.HasValue; } }

public T Value { get { return _maybeValue.Value; } }

public T GetValue(T defaultValue)
{
if (HasValue)
{
return Value;
}
return defaultValue;
}

public static bool operator ==(Maybe<T> left, Maybe<T> right)
{
if (ReferenceEquals(left, right))
{
return true;
}
if (ReferenceEquals(left, null))
{
return false;
}
return left.Equals(right);
}
public static bool operator !=(Maybe<T> left, Maybe<T> right)
{
return !(left == right);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(this, obj))
{
return true;
}

Maybe<T> maybe = obj as Maybe<T>;
if (ReferenceEquals(maybe, null))
{
return false;
}
if (HasValue != maybe.HasValue)
{
return false;
}
if (HasValue)
{
return Value.Equals(maybe.Value);
}
return true;
}
public override int GetHashCode()
{
if (HasValue)
{
return Value.GetHashCode() * 751;
}
return 0;
}
public static explicit operator T(Maybe<T> maybe)
{
return maybe.Value;
}
public static Maybe<T> Nothing = new Maybe<T>(new Nothing<T>());

public static Maybe<T> Just(T value)
{
return new Maybe<T>(new Something<T>(value));
}

}

internal class Nothing<T> : IMaybe<T>
{
public bool HasValue
{
get { return false; }
}

public T Value
{
get
{
throw new InvalidOperationException("No Value");
}
}
}
internal class Something<T> : IMaybe<T>
{
private readonly T _value;
public Something(T value)
{
if (ReferenceEquals(value, null))
{
throw new ArgumentNullException("value is null");
}
_value = value;

}
public bool HasValue
{
get { return true; }
}

public T Value
{
get
{
return _value;
}
}
}




NUnitのテストコード
も公開しています。
.

HaskellのMaybeクラスをC#で作ってみた。

Maybeクラスを作ってみました。
Nothingの場合にnullにしていたんですけど、コンパイルエラーに!
default(T)なんてのがあるんですね。

しかし、default(T)は必要あるのか?
Nothingの場合は値を持つ必要が無いので、Valueで例外、HasValueでfalseを返すだけのクラスがあっても良さそう。


HaskellのMaybeクラスをC#で作ってみた。その2

default(T)を消してクラスを分離したバージョンを作成しました。



public class Maybe<T>
{
private readonly T _value;
private readonly bool _hasValue;
public Maybe(T value)
: this(value, true)
{
if (ReferenceEquals(value, null))
{
throw new ArgumentNullException("value is null");
}
}
private Maybe(T value, bool hasValue)
{
_value = value;
_hasValue = hasValue;
}
public bool HasValue
{
get { return _hasValue; }
}

public T Value
{
get
{
if (_hasValue)
{
return _value;
}
throw new InvalidOperationException("No Value");
}
}

public T GetValue(T defaultValue)
{
if (_hasValue)
{
return _value;
}
return defaultValue;
}

public static bool operator ==(Maybe<T> left, Maybe<T> right)
{
if (ReferenceEquals(left, right))
{
return true;
}
if (ReferenceEquals(left, null))
{
return false;
}
return left.Equals(right);
}
public static bool operator !=(Maybe<T> left, Maybe<T> right)
{
return !(left == right);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(this, obj))
{
return true;
}

Maybe<T> maybe = obj as Maybe<T>;
if (ReferenceEquals(maybe, null))
{
return false;
}
if (_hasValue != maybe.HasValue)
{
return false;
}
if (_hasValue)
{
return _value.Equals(maybe.Value);
}
return true;
}
public override int GetHashCode()
{
if (_hasValue)
{
return _value.GetHashCode() * 751;
}
return 0;
}
public static explicit operator T(Maybe<T> maybe)
{
return maybe.Value;
}
public static Maybe<T> Nothing = new Maybe<T>(default(T), false);

public static Maybe<T> Just(T value)
{
return new Maybe<T>(value);
}
}



NUnitのテストコード
も公開しています。
.

Dynamic Language Runtime

Microsoft DLRというライブラリ
http://dlr.codeplex.com/

動的言語をCLR上で動作させることが出来るライブラリです。

IronPythonで作成されたロジックを分岐させて作られたライブラリとのこと。

PythonやRuby等のスクリプト言語を
外部ファイルから受け取りアプリの動作を簡単に変えることが出来るので、
プラグインの作成なんかに使えるかもしれません。

動的言語を作成するための仕組みもライブラリ内に存在しているので、
数種類のライブラリを使って作成していたのがDLR一つだけで出来るのも良いところですね。

動的言語のサンプルは以下のサイトにありました。
http://blogs.msdn.com/shozoa/archive/2008/02/17/7741759.aspx
http://blogs.msdn.com/shozoa/archive/2009/01/29/tech-days-2009-dynamic-language-runtime-s-samples.aspx

.

ボーイスカウトの掟

自分が訪れた状態より、より良い状態にして帰ろう。
そういう目標があるみたいです。
(実際のボーイスカウトの掟とはまた違ってるかも)

それにならって、ソースコードも
自分が見た状態より、より良い状態にしてコミットしよう!

リファクタリング環境が良くなってきているので、
変数名や関数名・クラス名の名前を変更することは
低リスクで実行出来ます。

こういう小さい修正を日々行うことができれば、
綺麗なコードに近づいていくのではないかと思います。

少し探して見つけました。
ボーイスカウトの「3つのちかい」と「8つのおきて」
ちかい
・神と国とに誠を尽くし、おきてをまもります
・いつも他の人々を助けます
・体を強くし心をすこやかに、徳を養います

おきて
・スカウトは誠実である
・スカウトは友情にあつい
・スカウトは礼儀正しい
・スカウトは親切である
・スカウトは快活である
・スカウトは質素である
・スカウトは勇敢である
・スカウトは感謝の心を持つ

【参考文献】
http://bsm5.org/outline/oath.html

.

ラベル