オブジェクト指向入門読み終わった

ちまちま読んでたオブジェクト指向入門を読み終わった。だいたい入門と言っているが、原題は"Object-Oriented Software Construction"で入門感はないし、上下巻あわせて2000ページくらいあって読みきるのが大変だった。

原著は18年前に発売された本だが、内容のほとんどは今でも有益で、全体を通してためになる。オブジェクト指向が解決しようとしている課題や、背景にある理論や考え方について解説してくれるだけではなく、実際にソフトウェアを設計する際にどのようにクラスを見つけ、どんな場面で継承を使い、ソフトウェア全体をどのように形作っていくのかという実践的な議論も充実している。

本の序盤では、ソフトウェアの品質の様々な側面についての解説や、オブジェクト指向以前から使われていたモジュールや型の概念のがもつ諸課題について詳しく解説してくれる。それらの問題をふまえ、次に、ソフトウェアの再利用性や拡張性、そして信頼性を担保する仕組みとしてオブジェクト指向が提案される。オブジェクト指向の考え方の後ろにあるのは抽象データ型の考え方だ。抽象データ型は、型と特性、公理、事前条件によって特徴付けられた抽象的なデータ構造の仕様記述でソフトウェアモデルを厳密かつ、過不足なく表現することができる。実は、オブジェクト指向におけるクラスは実装を伴う抽象データ型であるということが読み進めるとわかってくる。

抽象データ型をクラスとして記述するにあたって、公理をや事前条件をクラスの表記に組み込む必要がある。この本で解説につかっているプログラミング言語*1ではクラスに表明を記述することができ、ルーチンごとの事前条件や事後条件、クラス全体の不変条件を記述できる。ルーチンが呼び出し側に要求する事前条件とルーチンが呼び出し側に保証する事後条件を、契約のようにみなすこともできる(これが契約による設計のメタファだ)。

抽象データ型をベースにした考え方は本の全体で一貫していて、後半の実践部分でも、クラスを見つけるのに大事なのは、ソフトウェアの問題領域に対する適切な抽象を見つけることだと述べている。ソフトウェアが対象にしている問題領域に対する適切な抽象が見つかれば、適切なクラスとクラスがもつべき特性や表明、クラスが何を要求し何を提供してくれるのかといったことに対して、妥当な答えを出すことができるようになる。

最近はこの本で学んだこと参考に、抽象を意識してクラスの設計を考えてみている。別々のモノだと思っていたデータ群が実は同じ抽象に基づいていてひとつのクラスで表現したら見通しがよくなったり、似てるけど別々に実装されていた一連の処理群が実はある抽象に基づいていることに気づいて、特定のインターフェースを実装する形にしたらソフトウェアの他の部分とうまく適合したり、と有益な体験が続いている。機能ベースで考えてたりすると、ある機能を実装するメソッドをどのクラスに所属させるか悩むみたいなことがあったりするけども、悩むのは実はおかしいはずで、どのクラスにも機能追加するのが不自然であれば新たな抽象概念が登場したのではないかとか、いろいろ考えることができるようになった。

大学のころの研究室の先生が、「ソフトウェア開発っていうのは抽象化のことなんだよ」とおっしゃていたが、数年いろいろソフトウェア開発してみて、この本を読んでみると、少しはおっしゃっられていたことが、わかったような気がしたりしなかったりする。

オブジェクト指向入門 第2版 原則・コンセプト (IT Architect’Archive クラシックモダン・コンピューティング)

オブジェクト指向入門 第2版 原則・コンセプト (IT Architect’Archive クラシックモダン・コンピューティング)

オブジェクト指向入門 第2版 方法論・実践 (IT Architects' Archiveクラシックモダン・コンピューティング)

オブジェクト指向入門 第2版 方法論・実践 (IT Architects' Archiveクラシックモダン・コンピューティング)

*1:プログラミング言語の名前は伏せられていて下巻の最後の方でやっと教えてくれる

リアクティブプログラミングの技術を用いてマウスストーカーを実装する

古き良きインターネットアプリケーションであるマウスストーカー*1をリアクティブプログラミングの技術を活用して実装してみるという取り組みをしましたのでご紹介します。リアクティブプログラミングというと主語が大きめですが、ここではbacon.jsを使ってるくらいの意味です。

できたもの

まずは完成したマウスストーカーを紹介します。チェーンのように連なった星がマウスカーソルの軌跡を辿ってついてきます。工夫してうごかすとなかなか綺麗です。下のボタンを押すと実際にこの画面でマウスストーカーを有効にすることができます(requestAnimationFrameに対応したPCブラウザのみ)。いろいろ動かして遊んでみてください。

 f:id:hakobe932:20150308230637g:plain:w300





実装

このマウスストーカーがどのように実装されているか紹介します。ソースコードはGitHubに公開していますので、適宜ご参照ください。手元でビルドして試す場合には、READMEの通りにビルドして、example.htmlを表示してみてください。

では順番に見ていきます。

マウスカーソルの位置の変化をEventStreamに変換する

まずは刻々と変化するマウスカーソルの位置変化を、取り扱いやすいようにbacon.jsのEventStreamに変換しましょう。document要素に対して発生したmousemoveイベントをEventStreamに変換するには以下のようにします。

var mouseCursorStream =
  Bacon.fromEventTarget(document, 'mousemove').map(function(me) {
    return {
      x: me.pageX,
      y: me.pageY
    };
  });

これでマウスカーソルの変化を1つのオブジェクトとして関数に渡したりすることができるようになりました。(pageX/pageYは標準化されていないフィールドですが、polyfillのためのコードを書くことは本題ではないので、ここでは雑に使っています。)

刻々と変化する位置を目指して動くオブジェクトを作る

次はマウスカーソル追いかける星に相当するStalkerオブジェクトを作ります。

このオブジェクトは初期化時に与えられたEventStreamによって表される刻々と変化する位置に向かって、星の画像を移動させます。例えば次のようにStalkerオブジェクトを作ると、マウスカーソルを1つの星が追いかけます。

new Stalker(mouseCursorStream); // マウスカーソルを目指して動くStalkerを作る

f:id:hakobe932:20150308235518g:plain:w300

Stalkerオブジェクトの中では目指す位置のEventStream( = targetStream)の変化があるごとに、自分の現在の目的地を更新します。

function Stalker(targetStream) {
  // ... 
  var targetPosition = {x: 0, y:0};
  targetStream.onValue(function(p) {

    targetPosition.x = p.x;
    targetPosition.y = p.y;
  });
  // ... 
}

ここで出てきたtargetPositionを目指して星を一定速度で移動させるアニメーションのコードは、以下のような雰囲気なりますが、詳細は省略します*2

// Stalker のコンストラクタ内にて
// animationFrameごとにStalkerのpositionを更新する
  animationFrame.onValue(function() {
      position = next();
      elem.style.left = position.x + 'px';
      elem.style.top = position.y + 'px';
    }
  });
刻々と変化するStalkerの位置をEventStreamにする

ここまでで星を1つ追いかけさせることはできるようになりましたが、あまりおもしろくありませんし、まったくリアクティブ感がありません。そこで少し工夫してみます。

StalkerオブジェクトはtargetPositionを目指して一定速度で移動します。この移動中のStalkerオブジェクト自身の位置をEventStreamとして取り扱えるようにしてみます。

bacon.jsのBusというオブジェクトを使うと自分で値をpushできるようなEventStreamを作る事ができます。Stalkerが星の位置を更新する箇所でBusとして作ったEventStreamに値をpushします。pushされた値が最後にpushされた値と同じ場合は無視したいので、skipDuplicatesメソッドによって作られた新しいEventStreamStalkerオブジェクトのpositionStreamフィールドにセットしておきます。

// Stalker のコンストラクタ内にて
// animationFrameごとにStalkerのpositionを更新する
  var ps = new Bacon.Bus();
  this.positionStream = ps.skipDuplicates(); // Busに同じ値がpushされても無視する

  animationFrame.onValue(function() {
    position = next();
    ps.push(position); // 位置の変化をStreamにpushする
    elem.style.left = position.x + 'px';
    elem.style.top = position.y + 'px';
  });

これにより、移動中のStalkerの位置もmouseCursorStreamと同じ形式のEventStreamとして取り扱えるようになりました。つまり、Stalkerはマウスカーソルだけではなく別のStalkerも追いかけられるようになりました。

Stalker をつなげる

お膳立ては済んだのでStalkerオブジェクトをたくさん作ってもう少しおもしろいマウスストーカーを作れます。

例えば、1つ目のStalkerがマウスカーソルを追いかけるようにし、3つ目のStalkerが1つ目のStalkerを、3つ目のStalkerが2つ目のStalkerを追いかけるようにしてみましょう。

  var one = new Stalker(mouseCursorStream);
  var two = new Stalker(one.positionStream.delay(100));
  var three = new Stalker(two.positionStream.delay(100));

f:id:hakobe932:20150309003632g:plain:w300

うまくいきました。positionStreamで発生したイベントを100msほどdelayしているのがポイントです。positionStreamの更新は頻繁に行っているため、delayしないと3つの星がほぼ同じ位置に表示されて面白みがありません。

はじめに紹介したマウスストーカーでは以下のように30個の星を鎖のようにつなげて、自分より前にならんだ星を追いかけるように設定しています。

  var cur = new Stalker(mouseCursorStream);
  for (var i = 0; i < 30; i++) {
    cur = new Stalker(cur.positionStream.delay(100));
  }

感想

リアクティブプログラミングの技術を活用したマウスストーカーを実装してみました。刻々と変化する位置の変化をEventStreamのオブジェクトとみなすことで、Stalkerを刻々と変わる目的地( = targetStream)を目指して動くオブジェクトである、というすなおでわかりやすいモデルにすることができました。

例えば、EventStreamに頼らずにmousemoveイベントのハンドラで目的の位置を更新するコードをStalkerの外に実装することもできるでしょう。

var s = new Stalker(mouseCursorStream);
document.addEventListener('mousemove', function(e) {
  s.updateCurrentTargetPosition({x: e.pageX, y: e:pageY});
});

ですが、目的の位置が変化した時にどのような反応をするかはStalkerである限りはそれほど変わりがない(現在の目的位置を更新する)と考えられるので、コードの重複や情報隠蔽の観点からStalker内に実装されているのが良さそうに思います。かといって、mousemoveのハンドラの登録を直接Stalker内に実装すれば、マウスカーソルではない別のStalkerの位置からイベントを受け取って星を連ねる、といった柔軟性を実現できなかったでしょう。

EventStreamという抽象化は大変便利です。EventStreamを使うことでskipDuplicatesdelayのような便利なメソッドも利用出来ました。

マウスストーカーがリアクティブプログラミングを学ぶ最適な課題というわけではないようには思いますが、今回は変化するイベントをオブジェクトとして扱い組み合わせられることの便利さを少しは感じられたと思います。

おまけ: http://mouse-stalkers.github.io/への寄稿を募集しています

マウスストーカーの実装を集める取り組みを始めました。みなさん何かしらのマウスストーカーを実装されたことがあるかと思います。おもしろいマウスストーカーが埋もれてしまうのは残念なので、ぜひmouse-stalkers.github.ioにPullRequestしてください。

*1:マウスカーソルの後ろに星がくっついてきたりするヤツ

*2:そしてアニメーションしているところのコードは雑です

関西2015年冬アニメ 放送時間まとめ

今期も関西における今期のアニメの放送状況を表にまとめました。いつもどおりしょぼいカレンダーのデータを利用させていただいています。ありがとうございます。予約設定時の確認などにお役立てください。

今季の関西最速は二作品となりました。なかなかの苦戦ですね。

蒼穹のファフナーEXODUSは2004年に初めて放送された蒼穹のファフナーシリーズの最新作です。もう10年前なんですね...。今季に放送される作品は、2004年のTVシリーズの2年後を描いた劇場版の後の時間軸の物語になっています。初見の人にも配慮されたストーリになっているそう。僕は2004年のテレビシリーズを途中までみたのですが、ストーリーが辛くなってきて見続けられなかった記憶があるので、今季視聴しようか悩んでいます。

ローリング☆ガールズは原作なしのオリジナル作品です。都道府県がそれぞれ独立した国家になった日本を舞台に主人公四人組が旅をするというストーリーとのことです。トレーラーをみるとなかなかポップな絵作りで楽しく見れそうな予感がします。キャラデザの原案がTARITARIと同じtaruさんなのが個人的な気になりポイントです。どういった作品になのか、まずは放送が楽しみですね。

実は、艦隊これくしょん -艦これ-DOG DAYS″は関東と同時刻の放送になります。完全勝利とはいきませんが、最速には違いありませんから、要チェックです。

お正月もあけたばかりですが、もう新番組の放送ははじまりつつあります。今季も気を抜かずにがんばっていきましょう。

関西2015年冬アニメまとめ


golangで書かれたSlack bot でエンジニアに話題提供しよう

こんにちは、id:hakobe932 です。はてなエンジニアアドベントカレンダーの18日目として、はてな社内で導入をためしている話題提供Slack botの機能と実装について紹介します。昨日はid:astj による Herokuとwerckerによる継続的インテグレーション・自動デプロイでperlのwebアプリケーションを開発するでした。

#enginnerで技術交換

はてなではメインのチャットツールとしてSlackを活用しています。チームや職種などの単位のたくさんのチャンネルがあり、それぞれのチャンネルでコミュニケーションが行われているのですが、もっぱら技術的な議論を行っているのが #enginner というチャンネルです。#engineer では、チームをまたいだ技術的な相談のほか、新技術や勉強会の紹介など、技術に関わるさまざまな話題で情報交換しています。

もっと技術の話題でわいわいしたい

基本的にはにぎやかな#engineerですが、どうしても業務で利用している技術の話題に偏りがちです。社内のエンジニアが興味があって調べている技術や、専門にしている技術などを自然に話題に取り上げられないかと考えていました。

engineerkun登場

そこで、最近はengineerkunという名前の、自動的に話題を提供してくれるSlack botを#engineerに常駐させています。engineerkunは、はてなブックマークは指定したタグで検索して、適度に人気で新鮮なエントリのURLを定期的に発言してくれます。

f:id:hakobe932:20141216085704p:plain:h400

単に定期的にURLを発言するだけだと人間の会話の邪魔になるので、以下のように適度に遠慮して活動するのが特徴です。

  • 人間が会話している時には遠慮して発言しない
  • 人間が会話していなくても連続で数回発言したらだまる (朝来たらログがうまっているということがない)

会話が途切れた時に適度におもしろURLが投稿されることで、多様な話題によるコミュニケーションがわいわいと起こることを期待しつつ動かしてみています。

engineerkun の使い方

engineerkunはbotの愛称で、実装は拙作のpresentというツールです。presentを使うと、engineerkunのような話題提供botを簡単に作ることができます。


hakobe/present · GitHub


golangで書かれているので、go getコマンドを利用するとすぐに利用することができます。

$ go get github.com/hakobe/present
$ PRESENT_SLACK_INCOMMING_URL="https://hooks.slack.com/services/ABCD1234/EFGH5679/abcdefghijk123456" \
  PRESENT_DB_DSN="id:pass@tcp(mysqldhost:3306)/dbname?parseTime=true&charset=utf8" \
  PRESENT_NAME=engineerkun \          # コマンドを実行するときに呼ぶbotの名前
  PRESENT_WAIT=900 \                  # URLを発言する頻度(秒)
  PRESENT_NOOP_LIMIT=3 \              # この回数だけ連続して発言したら一時停止する
  PORT="8080" \                       # WebHooksを待ち受けるHTTPサーバのポート
  $GOPATH/bin/present

presentは、発言用とチャンネルのログの監視のためにSlackのIncomming WebHooksとOutgoing WebHooksを一つづ利用します。また、タグや検索したURLを保存するストレージとしてMySQLが必要です。くわしくはREADMEで説明しているので参照してください。

heroku-buildpack-goを利用すると Heroku 上でも動作させることができます(適宜Godepsをリポジトリに含める必要があります。heroku-buildpack-goのドキュメントをご参照ください。)。

チェックするはてなブックマークのタグは、botを常駐させたチャンネルでengineerkun add perlのように発言すると追加することができます。例えばはてなでは以下のようなタグを設定しています。

f:id:hakobe932:20141218011016p:plain

この状態で放っておくと、環境変数で設定したPRESENT_WAIT秒後に、設定したタグに関する人気記事がbotを常駐させたチャンネルに投稿されます。

f:id:hakobe932:20141218011012p:plain

人間が会話している時には、botが適当に遠慮してURLが投稿されませんので、動作を検証したいときにはengineerkun plzのようにお願いするとよいでしょう。

f:id:hakobe932:20141218113311p:plain

もちろん、技術に関係のないタグを登録することもできますから、engineerkun add animeのようにして、ひたすらアニメ情報をウォッチするのもよいでしょう。

そのほかの機能については、engineerkun helpと発言するか、READMEを参照してください。

実装の紹介

presentはgolangを使って実装されています。ほとんど標準ライブラリのみを利用しています(MySQLのドライバだけはgo-sql-driver/mysqlを使っています)。いくつかおもしろポイントを紹介します。

goroutineを活用した設計

はてなブックマークを定期的にチェックするgoroutineSlackのOutgoing WebHooksを受け付けるWebサーバのgoroutine、そしてそれらを管理する スケジューラのメインルーチン の3つが協調して動作します。

それぞれのgroutineは自分のメインループを持ち、各々自分の仕事しています。goroutineの外部へのインターフェースとしてはchanelを公開するようにします。goroutineの中ではプログラムは逐次的に動作しておりデータ競合について考慮する必要はありません。たとえば 、はてなブックマークを定期的にチェックするgoroutineでは、概ね以下の様なメソッドをつかって新しいgoroutineを作っています。

func Start() (<-chan *RssEntry, chan<- []string) {
	ticker := time.Tick(10 * time.Minute)
	out := make(chan *RssEntry)
	newTags := make(chan []string)

	collect := func(tags []string, out chan *RssEntry) {
		...  
		out <- fetchedEntry // 結果をチャンネルに返す
	}

	go func() {
		tags := make([]string, 0)
		for {
			select {
			case <-ticker:
				collect(tags, out)
			case ts := <- newTags: // 新しいタグの一覧を受け取る
				tags = ts // 逐次的に動作するので同期化せずに状態を変更できる
				collect(tags, out)
			}
		}
	}()

	// インターフェースを公開する
	return out, newTags
}

このような機能を実装する場合、オブジェクト志向プログラミングでは、機能の持つ状態を抽象化したオブジェクトを定義することが多いですが、golangではプロセス( = goroutine)を使って処理を中心に機能を抽象化することができます。並行処理と相性が良く、Erlangのようなプロセスを中心にプログラムを行う言語ではよく利用されている方法です。

DB操作

golangの標準ライブラリである、database/sqlを使うとRDBMSに接続してSQLを実行することができます。コネクションプーリングを備えていたり、goroutineをまたいで使っても競合が起きない(= groutine safe)になっているなど、golangらしい特徴も備えます。素朴にSELECT文を実行すると以下のようになります。PerlのDBIのようにシンプルです。

func All(db *sql.DB) ([]string, error) {
	sql := `
		SELECT tag FROM tags ORDER BY tag ASC
	`

	rows, err := db.Query(sql)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	tags := make([]string, 0)
	for rows.Next() {
		var tag string
		if err := rows.Scan(&tag); err != nil {
			return nil, err
		}
		tags = append(tags, tag)
	}
	if err = rows.Err(); err != nil {
		return nil, err
	}

	return tags, nil
}

MySQLに接続するにはgo-sql-driver/mysql: Go-MySQL-Driver is a lightweight and fast MySQL-Driver for Go's (golang) database/sql packageが必要です。PerlのDBIと同じようなDSNを設定して接続するのでPerl使いにも馴染みがありますね。

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
)
db, err := sql.Open("mysql", "id:pass@tcp(mysqldhost:3306)/dbname?parseTime=true&charset=utf8")

まとめ

以上 engineerkunをその実装である present の紹介でした。presentを使うとエンジニア向けに限らない話題提供botを気楽につくることができます。 はてな社内での評判はまずまずですが、だいたいうまく機能しているのでぜひおためしください!

はてなエンジニアアドベントカレンダー の明日の担当は id:wtatsuru さんです!

はてなでは、golangやエンジニア同士の交流の仕方に興味のあるエンジニアを募集しています。

関西2014年秋アニメ 放送時間まとめ

今期も関西における今期のアニメの放送状況を表にまとめました。いつもどおりしょぼいカレンダーのデータを利用させていただいています。ありがとうございます。予約設定時の確認などにお役立てください。

今期の関西最速は三作品となりました。

なんといっても、Gのレコンギスタが関西最速なのがうれしいところです。いうまでもない注目作品ですから、十分に最速を味わいながら視聴しましょう!前作がとてもおもしろかったガンダムビルドファイターズトライも放送され、今期はガンダムの新作が同時に二作も放送されるといううれしい事態になっています。

神撃のバハムート GENESISは同名のソーシャルゲームが原作のアニメーションです。僕は原作はほとんど知らないのですが、監督がTIGER & BUNNYのさとうけいいちさんとのことで期待できそうです。PVを見るとダークファンタジーの世界という感じですね。

結城友奈は勇者であるは原作なしのオリジナルアニメーションです。サイトのドメインがかわいいですね。サイトを見ると舞台が勇者部であったり、主人公がどうやら変身したりするらしいことはわかるのですが、くわしいところははっきりしません。一見、日常系ゆるふわアニメですがオリジナルアニメーションですから、油断せずに行きましょう。

今期は個人的にも注目作品が多く、たのしい期になりそうです。それでは関西のみなさん今期も頑張りましょう。


社内技術勉強会でScalaのおすすめポイント解説した

はてなでは週に一回、社内技術勉強会というのをしています。今週は僕の当番だったのでScalaの入門的な話をしました。

普段使いの言語として、Scalaの便利なところをまとめたというつもりです。とはいえ、他の言語にもある特徴もわりと紹介してるので、もうちょっとScala独自の内容にフォーカスしてもよかった... むずかしい。時間の都合で全部話きれなくて、会が終わった後でimplicitまわりの話とか数人にご紹介したら一番おもしろかったと言う話になったので無念。

あの機能を紹介してないとはけしからんみたいなのがあったら教えて下さい。そうはいってもとりあえず
Scalaスケーラブルプログラミング第2版を読むといいです。



↓ 資料はgist形式でembedしてあります ↓


https://gist.github.com/hakobe/e1aa2501a64e7f801b55

こちらもおすすめ

Scalaスケーラブルプログラミング第2版

Scalaスケーラブルプログラミング第2版

  • 作者: Martin Odersky,Lex Spoon,Bill Venners,羽生田栄一,水島宏太,長尾高弘
  • 出版社/メーカー: インプレスジャパン
  • 発売日: 2011/09/27
  • メディア: 単行本(ソフトカバー)
  • 購入: 12人 クリック: 235回
  • この商品を含むブログ (46件) を見る
すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

AnimeKansaiをHeroku化した

ずいぶん昔に関西のアニメ放送情報を10分前に通知してくれるAnime KansaiというTwitter botを作った。


Twitter/AnimeKantoがうらやましかったのでTwitter/AnimeKansaiを作った - はこべブログ ♨

このTwitter botは自分のVPSで動かしてて、10分ごとにcronで起動されているという仕組みだった。結構便利に使って頂いてるのだけど、TwitterのAPIの仕様が変わるとか、うちの怠慢とかがあって、よく止まってしまっていた。

これまでは、スクリプトが自分しかアクセスできないVPSに置いてあって、とくにリポジトリで管理されてなかったのでとりあえずコード変更がしづらかった。cronでちまちまうごかしているというのも、プログラムの様子を調べずらくて厳しかった。VPSをたまに引っ越すときとかにも移管が地味に面倒だった。

ということでAnimeKansaiのコードをHerokuで動くbotとして書きなおした。今どきはHerokuの無料枠でbotをうごかし続けられるので大変便利。開発やDeployも気楽にできるしログの様子も簡単に見れる。もともとはPerlで書かれたすぐに終了するスクリプトだったけど、Node.js + CoffeeScript で常時起動するスクリプトに書き換えてcronいらず。

READMEにも書いてあるけど、任意の地方のアニメ放送情報をツイートできるようになってる。しょぼいカレンダーのアカウントとbot用のTwitterアカウントがあればだれでもbotをDeployできるはず。以下のボタンからご利用ください。

ボタンを押すとHerokuのログインしたら以下の様な画面が出てくるの環境変数を入れたら利用開始できるのでお手軽。bot用のTwitterアカウントでTwitterアプリケーションを作って、管理画面のAPI Keysタブから Create my access tokenすると、楽にaccess tokenが取得できるでしょう。

f:id:hakobe932:20140907122507p:plain