TIM Labs

2010年12月アーカイブ

gitでは様々な方法でコミットログを書き換えることができます。 その一例として誤ったブランチに対して行った変更を正しいブランチへ移す方法を紹介します。

問題

これまで「新機能Xを追加する」という設定で以下のトピックについて解説していました:

これにはまず

$ git branch topic-x master
$ git checkout topic-x

としてこの作業用のトピックブランチを作成してそちらで作業を行うのが普通です。

しかし git branch を実行したところで安心してしまい、 git checkout を忘れて全く違うブランチで作業を行ってしまう というミスは時々やってしまいます (git checkout -b という方法もありますがここではそれも忘れていたとしましょう)。 例えば以下のような状況だったとしましょう:

$ git branch
  master
  topic-x
* topic-y

$ git log --oneline --decorate --graph
* c000022 (HEAD, topic-y) Update to use X
* c000012 Refactor - Sort using statements
* b000001 Add a neat feature X into the library
* 0100002 Update to use Y
* 0100001 Add a great feature Y in to the library
* 0000000 (master, topic-x) Initial import

日本語に訳すと以下の通りです:

  1. 新機能Yを追加するためのトピックブランチtopic-yをmasterから作成し、そこで作業を行った。 この時点でmasterは0000000を、topic-yは0100002を指していた。
  2. 新機能Xを追加するためのトピックブランチtopic-xをmasterから作成したが、 ブランチの切り替えを忘れていたため、 topic-xに対して行う変更をtopic-y上で行ってしまった。 結果としてtopic-yは0100002からc000022を指すようになった。

本来ならば以下のような形なっているところです:

$ git branch
  master
* topic-x
  topic-y

$ git log --oneline --decorate --graph master topic-x topic-y
* d000022 (HEAD, topic-x) Update to use X
* d000012 Refactor - Sort using statements
* d000001 Add a neat feature X into the library
| * 0100002 (topic-y) Update to use Y
| * 0100001 Add a great feature Y in to the library
|/
* 0000000 (master) Initial import

まだまだtopic-xの作業内容はどこにも公開されていないので、 いまのうちにコミットログを綺麗な形に書き換えるとしましょう。 しかし具体的にはどうすればよいでしょうか。

さて。
出展支援システム、前回はざっくりと要件をまとめました。
何をどこまで実現できるかわかりませんが、指針大事ということで。
今回は、それぞれについて概説します。

Emacsでも同じ事ができます。

問題

先日紹介した gitで1つのコミットを複数のコミットに分割する 例では 「using等の宣言の羅列をソートする」 などのリファクタリング的な修正が別のコミットに混じっていたため、 これを1つのコミットとして分割しました。

この手の宣言文の羅列ですが、 最初のうちは綺麗にソートされた状態になるよう変更が積み重ねられていくものです。 しかし歴史のあるコードベースだと大抵誰かがひょっこりと変な位置に宣言文を追加しています。 例えば以下のような感じです:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Linq;

これは気持ち悪いのでソートしましょう。 Vimでは:sortコマンドで行のソートができます。 この場合は宣言文のどこかにカーソルを置いてvip:sort<Enter>でソートできます:

using System.Collections.Generic;
using System.Linq;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Web;
using System;

ところがセミコロン(;)は0x3Bでピリオド(.)は0x2Eです。 単純にソートすると上図のように悲しい結果となります。 これを名前空間の階層に沿った綺麗な順序にソートするにはどうすればよいでしょうか。

Javaで高階関数を試してみたはいいけれど、
わりと王道っぽいことをしていなかったな...と思いました。
ということで、アキュムレーターです。

ローカル変数のスコープでクラス(っぽいもの)がお手軽につくれるのがいいと思います。

短く書くにはどうしたらいいんだろうと試行錯誤しているうちに...

悪ノリしてしまいました。
邪魔っぽいものを右に寄せたので、見てみぬふりしてください!

ここ最近文字コードはUTF-8で統一することが多くなったので、 いわゆる「文字化け」を目にすることは随分少なくなったが、 それでもまだ「化けて出る」のが日本語という奴ではある。

で、まあ文字コード関連のノウハウは色々あるようだけども、 今回はそういう話題ではない。

この幽霊たち、いくつかは特徴のある姿をしているので、 分かりやすい幽霊についてちょっと紹介してみようと思う。

こんなのはいかがでしょうか。 パラメータに複数の型を渡したいときが面倒ですね...。
一つ前の「Flask で始める Google AppEngine アプリ開発」の番外編です。
前回は Flask + Appengine という観点でアプリ開発を始め方について説明しましたが、
番外編ではアプリ移植の際に手間をかけたデータ移行について説明します。

@t2y から Python Web フレームワークアドベントカレンダー の担当がパスされてきました。

僕は Python を使い始めて 1年ぐらいになるのですが、主にコマンドラインのアプリを作っていて Web アプリには手をつけていなかったので、アドベントカレンダーに合わせて触ってみることにしました。

Web アプリの題材には、以前 Rails + Google Maps API で作った地図投稿アプリを使うことにしました。 以前 Rails 1.1 の練習題材として作ったのですが、バージョンアップの影響で いつの間にか動かなくなってしまった残念なアプリです。

フレームワークには python のマイクロフレームワークの一つである Flask を、 実行環境には Google App Engine (以下、appengine)を使うことにしました。

世の中には、展示会やイベント、即売会というものがあります。
その出展者の募集から公開までを支援するシステムをつくろう!
ある日、ふとそんなことを思い立ちました。

追記:既知のバグのようです

IE6のテスト中にはまったので紹介します。

社内で作成するWebアプリケーションではセッションハイジャック対策としてHTTPヘッダーのUserAgentやRemoteAddrがセッションの内容と異なっていた場合に破棄するというコードを組み込んでいます。 この仕組みを使っている場合にIETesterでAjax通信を行うとセッションの内容が取得できず呼び出したAPIから正常な結果が得られないという問題がありました。

何でだろう、、という事で調べてみました

コードを書いて何か具体的なものを作ることが、僕たちプログラマの仕事でありアイデンティティですが、 ただ、一日中コードを書き続けているわけではありません。 優れたコードを書くスキルを習得するためには、いろんな人たちが書いたコードを大量に読むことが欠かせません。
この、コードを読む(Code Reading)ことはなかなか奥が深く、読みこなすには骨が折れるものです。 なぜならその背景をコードから読み解く知識(データ構造、アルゴリズムやアーキテクチャ)や経験が要求されるからです。 しかし、Code Readingは何よりも楽しいものです。読み進めていると斬新なアイデアや綺麗に表現しているコードに出会ったときは興奮してしまいます。

では、コードはどうやって読むのでしょうか? 印刷して紙で読む? Webブラウザでsyntax highlightされたコードを読む?
いいえ。エディタです。
使い慣れたエディタは書くときにも最高に真価を発揮してくれますが、読むときにも便利な機能を提供してくれています。

今回は僕がVimでコードを読むときの一連の流れを紹介します。 EclipseやNetBeansをはじめとするIDEでは簡単にコード間を移動できますが、Vimを使う場合には少し手間をかけてあげなければなりません。 クラスや構造体、メソッドや関数、マクロといったものものに対してタグ(インデックス)をつけて、Vimがソースファイルのどこに移動すればよいか教えるわけです。

どのORMを採用するかでアプリケーションの作成方法は大きくかわってきます。 SQLをがりがり書くタイプのORMを採用したり、そもそもORMを使っていない場合、レイジーロードやシングルテーブルインヘリタンスなどの仕組みは自前で用意しなければなりません。

ここではEnumを使ってシングルテーブルインヘリタンスをサポートしていないORMでもシングルテーブルインヘリタンスを実現する方法を紹介します。 (S2JDBCのドキュメントにあるEnumを使って多態を表す例を参考にしました)

gitでは様々な方法でコミットログを書き換えることができます。 その一例として1つのコミットを複数のコミットに分割する方法を紹介します。

問題

先日紹介した gitで複数のコミットを1つにまとめる 例ですが、 そこでは以下のコミットログを:

$ git log -n 4 --oneline --reverse
0000001 Add a neat feature X into the library
0000002 Update to use X
0000003 Fix a typo in X
0000004 Fix a bug in X

以下のような形になるよう書き換えました:

$ git rebase -i HEAD~4
[detached HEAD b000001] Add a neat feature X into the library
 8 files changed, 94 insertions(+), 9 deletions(-)
Successfully rebased and updated refs/heads/topic-x.

$ git log -n 2 --oneline --reverse
b000001 Add a neat feature X into the library
b000002 Update to use X

ライブラリ側の変更点(0000001と0000003と0000004)を1つにまとめて 順序を入れ替えた形になります。

当初のコミットログから比較するとかなり美しくなりました。 しかし改めて git log -p などとしてコミットログを確認していると新たな問題が発覚しました。 b000002は新機能Xを使うようアプリケーション側を変更するコミットだったのですが、 よくよく見返してみると「新機能Xを使うよう更新する」変更とは関係のない 「using等の宣言の羅列をソートする」 といったリファクタリング的な変更がいっしょくたになっていました。 これは美しくありません。

この場合、b000002を「新機能Xを使うよう更新する」と「using等の宣言の羅列をソートする」の2つに分割すれば よりコミットログが美しくなります。 しかし具体的にはどうすればよいでしょうか。

「遷移図生成ツール blockdiag の紹介」というタイトルで Python Workshop 2010/12 で話をしてきました。
人生初発表 & 初LT !!
(訂正:よく考えたら Plone 関連で発表してました :p)


Slideshare だとなんか文字がずれて表示されますね。ちょっといまいち...。
ソースコードの色付けについて調べていたらよさそうなperlモジュールを見つけたので使ってみました。

分散バージョン管理システムつかってますか?

世の中ではgitやhgなどの分散型のバージョン管理システムが流行していて、「もうsvnなんて、、、」「まだsvnつかっているの、、、」という風潮になっています。 弊社内でもgitのレポジトリが立ったり、svnのプロジェクトでも自分の環境だけはgit-svnで分散バージョン管理を使う人が増えています。

「自分の環境だけはgit-svnで」。そう、社内ではまだまだsvnを使っているプロジェクトが多いのです。「日本語のファイル名が使えない」「デザイナーさんに使ってもらうためのわかりやすいクライアントが無い」「svnからなかなか移行するコストが、、」などの理由でsvnを使い続けているプロジェクトも多いと思います。

というわけで、分散バーション管理システムではなく社内で運用されているsvnでのブランチマネジメントについて、備忘録もかねて説明します。

みなさん、GoogleAppEngine (GAE) で開発をしてますか?
僕も最近 Python をよく使うようになったので、GAE 用のアプリをいくつか作っています。

Python の開発環境を作る際は buildout を使うと非常に便利です。
必要なeggパッケージのインストールや svn からのチェックアウト、Apache/MySQL のセットアップなどの作業を
設定に基づいて自動的に行ってくれます。

GAE 用のアプリを作る際の設定は @shimizukawa の?Google App Engine の開発をbuildoutで行う?に細かく書いてあります。

しかし、この設定では私の環境ではそのままでは動かなくてハマってしまいました。
この設定で利用している appfy.recipe.gae:app_lib というレシピは、
指定したライブラリをGAEで利用しやすいようZIP ファイルにまとめる仕組みを提供しているのですが、
この「指定したライブラリ」が開発環境に既にインストールされていると ZIP ファイルには含まれなくなります。
そのため、ローカル環境で動作確認すると正しく動くのですが GAE 上ではライブラリが足りずにちゃんと動作しません。

RAID1とかRAID5とか、冗長性確保という意味では確かに便利だけども、 ハードウェアのサポートが必要だったりとか、書き込みホール問題だとか色々あるワケで、 まあ色々面倒なところはある。 で、その辺の問題を解決したぜ! と主張するのがSolaris由来のZFSでサポートされるRAID-Z。

http://blogs.sun.com/bonwick/entry/raid_z5

ほほう、なかなか良さそうじゃあないですか。 でもって普段使ってるFreeBSDにもZFSがportされてきたらしいじゃないですか。 こりゃあ試さないといかんでしょう。

さて、今回こちらに生まれも育ちも異なるが、 容量は大体全部250GBくらいのHDDが4玉ございます。 1玉だけ300GB近くあるけど気にせずに、ちょっくらRAID-Z2を組んでみようではございませんか。

なお今回特に冗長性が必要な運用を想定しているわけでは全くないので、 おおむねRAID-Z2とかはオーバースペックではある。 が、どのみち今回使用予定のHDDはどれもこれも少なくとも3年、 長いものは6年以上使っていていつ寿命がきてもおかしくないドライブなので、 そういう意味では冗長化も全く無駄ではなかろう。 ...いや要するに、「ZFSのRAIDを使ってみたい!」が半ば目的なわけだが。

まあ巷の噂ではCPUリソースを食うとかメモリもバカ食いするとか色々あるみたいだけど、 今回の構成はCPUはCore2Duo、メモリは4GBだ。 ZFSを使うのに十分かどうかはともかく、問題はないだろう。多分。

で、インストール手順は下記Wiki記事にある。

http://wiki.freebsd.org/RootOnZFS/GPTZFSBoot/RAIDZ2

以上。

うん。以上。これで終わらせても問題ないくらいにはなにもなくインストールが完了してしまった。

しかしまあこれだけというのもさみしいのでちょっと補足。

webのリッチインターフェースのUIが主流になってきた昨今、Javascriptファイルのサイズが肥大化し

リクエスト時のトラフィックもそれに応じて肥大化してきています。

webページのパフォーマンス改善のためにも読み込むJavascriptやCSSのサイズはなるべく小さくしたいものです。

そこでGoogleが公開しているClosure Compilerを使ってJavascriptを圧縮してみます。

Closure Compiler

Closure Compilerを使うにあたって選択肢は3種類あります。

  • Closure Compiler Service UI を使う
  • Closure Compiler Service API を使う
  • Closure Compiler Application を使う

Service UIを使いたい場合は Closure Compiler Serviceからweb UIを使用することができます。

Service APIを使いたい場合は Closure Compiler Service API Reference を参照してください。

今回はClosure Compiler Applicationを使います。

JPAの@Enumeratedに渡せるEnumTypeって、なんでSTRINGとORDINALしかないんでしょうか。

JPAではSTRINGを指定した場合はname()メソッドの結果を、ORDINALを指定した場合ははordinal()メソッドの結果をDBに保存するようになっています。(といってもS2JDBCの知識ですが。) このルールはJavaの言語仕様からするととても明確で、重複を許さなく、一意の変換が行えるという利点があります。

でも、そのきれいな設計には悲しい欠点が。たとえば次の様な時刻の区分値とか。

10:00
14:00
18:00

もしくは飛び飛びの数字とか

-5
-1
0
1
5

数字から始まったり大文字じゃなかったりとか

empty
1st
2nd

こんなコード体系の場合もSTRINGやORDINAL使わないといけないのでしょうか?現実はもっと残酷だよ。。。。

というわけで、S2JDBCで任意の文字列、数字を扱える様なクラスを書いてみました。

このアーカイブについて

このページには、2010年12月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2010年11月です。

次のアーカイブは2011年1月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。