よいソフトウェア、よい名前

自分が作ったものに名前を付けるというのは難しい。よい名前のソフトウェアが必ず普及する訳では無いけれど、世の中に認知されたソフトウェアは皆よい名前である、位は言えるのではないだろうか。

映画ソーシャルネットワークの中でショーンパーカー(役のジャスティン・ティンバーレイク)が「The Facebook」の「The」を取れ、と言ったのはとても印象に残るシーンだった。他にもRuby誕生の由来や、MozillaブラウザがFirefoxになった時など、名前がソフトウェアのヒットに密接に関連するエピソードは枚挙に遑がない。

よい名前が大切だということは分かっている。でも名前を付けるのはとても苦しい作業なので、新しいソフトを思いついた時に

  • 「せっかくのいいソフトウェアなのに名前付けに失敗したらどうしよう」
  • 「よいソフトウェアであれば名前がイマイチでもきっとみんなが分かってくれる!」(苦しみから逃れるための言い訳)
  • 「自分の作った○○の方が△△よりも優れているのに名前で上手くやりやがって・・」(ただの嫉妬)

とか考えてしまう、ああ。

ソフトウェア本体の改善と名前付けにそれぞれどれだけ時間をさくべきなのだろうか?それぞれよい場合と悪い場合で考えてみる。

  • 悪いソフトウェア、悪い名前 .. テキストの羅列
  • よいソフトウェア、悪い名前 .. 誰にも使われること無く、その一生を終える
  • 悪いソフトウェア、よい名前 .. 使ってみたらなんか全然駄目、炎上!
  • よいソフトウェア、よい名前 .. 大ヒット、世界中で使われる!

・・つまりは内容と名前の両方が伴った時にはじめて広く使われるものになるというごくごく当たり前の結論になった。

名前はウェイトの大きなソフトウェアの一機能だと考えるのがいいのかもしれない。

上の例は極端だし、よい紹介記事が書けるかとか、どうやってクチコミを増やすかとか、実際は色々な要素が絡み合うけど「ソフトウェアの内容がよければ名前は大切でない」とか「名前でソフトウェアのイマイチな所を補おう」みたいな考え方だと上手くいかないのだ、という結論で自分の中の思考遊びを終わりにしようと思う。

※1 ブログ記事の中身と、タイトルの関係にも同じような問題がつきまとう

※2 納得いくものが出来るまで何度も直すのがいいと思う。けど、出来れば広く公開するまでの間に正式名が決まるとよい。

※3 mrubyソースコード検索の名前をmrubyserachからmruby-code-searchに変更した時にふと思いついて書いた

ネーミング辞典 第3版

ネーミング辞典 第3版

関連記事

mrubyソースコード検索エンジン、mrubysearchに検索したいソースコードを追加する

f:id:tuto0621:20131103162437p:plain

mrubysearch

mrubyソースコード検索エンジンです。mrubyとmrubyを使ったソフトウェアのソースコードを高速に検索することが出来ます。 前回から少しづつ改善を続けています。

mrubysearchのレポジトリを整備した

ongaeshi/mrubysearch

に置きました、他の環境でも同じものがデプロイ出来るはずです。具体的な手順はREADME.mdを参考にして下さい。

Milkode1.3に更新した

Milkode1.3の更新をmrubysearchにも組み込みました。

  • GitHubボタンの追加
  • キーワードのマッチ箇所をハイライト

が使えるようになっています。

国際化した(一部)

takahashimさんのプルリクエストのおかげで英語に対応することが出来ました!

support I18N (not finished) by takahashim · Pull Request #2

ユーザが検索したいソースコードをプルリクエスト出来るようになった

私以外の人がmruby関連のソースコードを追加出来るようになりました。

  • mrubyを組み込んだアプリケーションを作った
  • mrubyで使えるライブラリを作った
  • (mrubysearchに)読みたいmruby関連のあれが登録されていない

などありましたら、是非プルリクエストを頂ければと思います。

追加方法

Add The Source Code That You Want To Search

Milkode1.3リリース - GitHubボタンを追加、キーワードのマッチ箇所をハイライト

f:id:tuto0621:20131102222613p:plain

  • GitHubボタンの追加
  • キーワードのマッチ箇所をハイライト

最新のMilkodeを試してみたい時はmrubysearchをどうぞ。

インストール

$ gem install milkode

ダウンロード, Gems

GitHubボタンの追加

f:id:tuto0621:20131102222622p:plain

GitHubとMilkodeの連携を容易にするものです。GitHubからクローンしたレポジトリに付けられます。 ※ 古いMilkodeを使っている人はバージョンアップ後に milk update --all で設定されます。

ボタンをクリックすると関連ページへジャンプすることが出来ます。ngx_mrubyngx_mruby/src でそれぞれボタンを押してもらうと分かりますが、各自対応したソースコード位置にジャンプします。GitHubボタンを押す事で、検索で見つけたパッケージにそのままスターを付けたり、README.mdを整形された状態で読むことが出来ます。

キーワードのマッチ箇所をハイライト

f:id:tuto0621:20131102222637p:plain

今までは行全体がハイライトされていましたが、マッチ箇所のみがハイライトされるようになりました。

地味な修正ですが見やすくなります。

全文検索エンジンGroongaを囲む夕べ 4

11/29(金)のGroongaを囲む夕べ 4で今年も発表します。

というタイトルで、今年追加した機能の総括と来年のもくろみを話す予定です。よかったら聞いてやって下さい。

リリースノート

  • milk web

    • Highlight keywords
    • Add github button if package is github repository
    • Touch update time if exist update file only
    • Add test case
  • milk

    • GitHub repository check in 'milk update'
    • Improve to not stop the package directory even if there is no

関連記事

mrubyソースコード検索を作りました

f:id:tuto0621:20130929123940p:plain

http://mrubysearch.ongaeshi.me/

RubyKokubanを作るにあたってmrubyのソースやmgem(mrubyのRubyGemsみたいなやつ)に登録されたソースコードを簡単に読めるようにしたいなあ、と思い作ってみました。

一日一回レポジトリを最新に更新してインデックスの再構築を行っています。新しいmgemが追加された時は今の所手動で対応しています(そのうち自動化したい所です)。

自分が追加した(もしくは検索したい)mgemが追加されていない!って人はリクエスト頂ければ追加するので教えて下さい。 mgemじゃなくてもmrubyに関係がありそうなソースコードでしたら追加しますので是非。

※ 個人サイトのため突然停止したりするかもしれません、ご了承下さい。

使い方の例1 - "!"付きのメソッドはどうやってバインドするの?

例えばgsub!のような!マークのついたメソッドはどうやってバインドするのか?を知りたいとします。mrubyでは メソッド名を文字列で渡す必要があるのでそこを手がかりにします。!"で検索してみましょう(文字列の終端に引っかかることを期待しています)。

!" in root -mruby search

f:id:tuto0621:20130929124240p:plain

少し下に行くとswapcase!関数をバインドしてる箇所が見つかりました。

mruby-string-ext/src/string.c#173

f:id:tuto0621:20130929124250p:plain

mrb_str_swapcase_bangという関数名でバインドされていますね。!は _bangという名前でバインドされているようです。

他のライブラリではどうなっているか調べてみます。

'_bang' in root - mruby search

  • reverse! -> mrb_ary_reverse_bang
  • capitalize! -> mrb_str_capitalize_bang

も_bangという名前になっているので、よく使われているルールだと思ってよさそうです。

使い方の例2 - Cの関数内からyieldしたいのだけど

ブロック構文を使いたくなったので調べることに。おそらくeachという名前のメソッドはブロック構文を使っているのでそれを探してみます。

'each mrb_define_' in root - mruby search

eachだけでも探せるけどより検索精度を上げるためにmrb_define_キーワードを重ねています。いくつか関数を探してmrb_leapmotion_devicelist_each関数を詳しく読む事に決めました。

mruby-leapmotion/src/Leap.cpp#1067

static mrb_value
mrb_leapmotion_devicelist_each(mrb_state *mrb, mrb_value self)
{
  mrb_leapmotion_devicelist_t *data =
    static_cast<mrb_leapmotion_devicelist_t*>(mrb_data_get_ptr(mrb, self, &mrb_leapmotion_devicelist_type));
  if (data == NULL) {
    return mrb_nil_value();
  }
  mrb_value block;
  mrb_get_args(mrb, "&", &block);
  std::for_each (data->obj->begin(), data->obj->end(),
    mrb_each_func_t<Leap::DeviceList::const_iterator::value_type>(mrb, block));
  return self;
}

mrb_get_args_でブロックらしきものを"&"で取っているので間違いなさそうです。C++のコードなのでSTLを使っています。mrb_each_func_tから始まるテンプレート関数が処理の本体のようです。mrb_each_func_tは同じファイル内にあります。

template <typename T> struct mrb_each_func_t {
private:
  mrb_state *mrb_;
  mrb_value &block_;

public:
  mrb_each_func_t(mrb_state *mrb, mrb_value &block) : mrb_(mrb), block_(block) {}
  ~mrb_each_func_t() {}

  mrb_value operator () (T const &elem) const {
    return mrb_yield(mrb_, block_, mrb_leapmotion_obj_make(mrb_, elem));
  }
};

operator ()内にある mrb_yield がブロックを呼び出す関数のようです!長い道のりでしたが、

  1. mrb_get_args(mrb, "&", &block); でブロックを受け取る
  2. mrb_yield(mrb, block, value) で受け取ったブロックを実行

すればよいことがmurbyソースコード検索を使って分かりました!

その他の基本的な使い方はヘルプをどうぞ。

内部の話

構成

groongaがストレージエンジンも兼ねるのでMySQL等は使っていません。

groongaのCentOSへのインストール

先にgroonga-develをインストールしておくとrroongaのインストールが短く終わります。

 $ yum install groonga-devel -y
 $ gem install rroonga

Milkodeのサーバーへのセットアップ

milkode-webを使いました、bundlerで管理出来るのでとっても便利です。

milkode-web - Milkode web application bundler template for apache passenger https://github.com/y-ken/milkode-web

くわしくはgroonga(rroonga)を利用したソースコード全文検索エンジン"Milkode"をApache Passengerで軽快に動かす方法をどうぞ。

レポジトリ一覧の取得

mrubyのレポジトリはGitHubから追加します。

$ milk add  https://github.com/mruby/mruby

mgemのレポジトリ一覧は以下のようなスクリプトを使って取得しています。

# Create mgem repository list

require 'yaml'

mgem_dir = File.join(ENV['HOME'], '.mgem')
mgem_list = Dir.glob(File.join(mgem_dir, 'mgem-list/*.gem'))

repositories = mgem_list.map do |mgem|
  YAML.load(File.read(mgem))['repository']
end

repositories.each do |repo|
    puts "milk add #{repo} -p git"
end

コマンド文字列が生成されるので後はコピペするなりシェルスクリプトにまとめてサーバー上で実行します。

$ ruby mklist.rb 
milk add https://github.com/schmurfy/host-stats.git -p git
milk add https://github.com/cremno/mruby-allegro.git -p git
milk add https://github.com/ppibburr/mruby-allocate.git -p git
.
.

Milkode 1.2 リリース : ファイル名のマッチ個所に色づけ、ctags連携、~/.gitignoreのサポート

f:id:tuto0621:20130810193312p:plain

  • ファイル名のマッチ個所に色づけ
  • ctagsとの連携
  • ~/.gitignoreのサポート
  • milk update時にignore対象をデータベースから削除

インストール

$ gem install milkode

ダウンロード, Gems

ファイル名のマッチ個所に色づけ

ファイル名のマッチ箇所がハイライトされて分かりやすくなりました。(↑画像) 他にも同じファイルで複数箇所にマッチした時はまとめたりとwebアプリの使い勝手を改善しました。

ctagsとの連携

milk update と一緒にタグファイルを作成出来るようになりました。

# パッケージ単位で設定可能
$ cd /path/to/package

# milk update と一緒に'ctags -R'
$ milk config update_with_ctags true

# milk update と一緒に'ctags -R -e'
$ milk config update_with_ctags_e true
# 更新
$ milk update

# パッケージのルートディレクトリにTAGSファイルが作られる
$ ls
TAGS
.
.

milk config で設定可能な項目はmilk config -hで確認出来ます。

$ milk config -h
Usage:
  milk config [options] KEY VALUE

Options:
  -d, [--delete]   # Delete key.
  -h, [--help]     # Help message.
      [--version]  # Show version.

Config package settings.

  $ milk coinfig no_auto_ignore true

Configs:
  no_auto_ignore           # Not add package's .gitignore
  update_with_ctags        # Update with 'ctags -R'
  update_with_ctags_e      # Update with 'ctags -R -e'
  update_with_git_pull     # Update with 'git pull'
  update_with_svn_update   # Update with 'svn update'

~/.gitignoreのサポート

全てのパッケージに適用されるグローバルな.gitignoreファイルを指定出来るようになりました。

$ milk ignore --global ~/.gitignore

milk update時にignore対象をデータベースから削除

milk add した後に milk ignore で設定を追加して milk update してもいままで対象ファイルがデータベースから除外されなかったのですが、今回から除外されるようになりました。

何か設定を間違えていても修正してmilk updateさえすれば大丈夫になりました。

リリースノート

  • milk web

    • Hightlight filename keywords
    • Not show file infomation when same file name continue
    • Delete auto search feature 'w:0' and 'fp:a b'
    • Bugfix relative URL (clippy, 同名ファイルへのリンク) (thanks nicklegr)
  • milk

    • milk update
      • Remove ignored files with update
    • milk ignore
      • Support global ignore. 'milk ignore --global ~/.gitignore'
    • milk config
      • Add 'milk config KEY VALUE' command.
      • e.g. 'milk config update_with_ctags_e true'
    • milk remove
      • Faster DocumentTable#remove_records
      • Not remove package non exist filename
    • milk cleanup
      • Add milk cleanup options. -p, -a
    • milk add
      • 'milk add' can't use already exist package

関連記事

Milkode 1.1 リリース : 待望の相対URLに対応、gmilkの高速化

インストール

$ gem install milkode

ダウンロード, Gems

相対URLに対応

今までは

http://example.com/
http://milkode.example.com

のように専用URLが無いとデプロイ出来なかったのですが、

http://example.com/milkode

にも設置出来るようになりました。

Apache+Passengerでの設定方法

  1. 事前にApacheやPassengerの設定は済んでいるものとします
  2. http://example.com/milkodeに設置したい
  3. /home/example/web/html がドキュメントルート
  4. Miilkodeのアプリケーションフォルダは/home/example/web/milkode
  5. 書き換えるhttpd.confは以下
<VirtualHost *:80>
  ServerName example.com
  DocumentRoot /home/example/web/html
</VirtualHost>

まずRackBaseURIを追記します。

<VirtualHost *:80>
  ServerName example.com
  DocumentRoot /home/example/web/html
+  RackBaseURI  /milkode
</VirtualHost>

次に/home/example/web/milkodeを作成、合わせてpublicフォルダを掘る。

$ mkdir /home/example/web/milkode
$ cd /home/example/web/milkode
$ mkdir public

次に/home/example/web/milkode/config.ruを作成する。

require 'milkode/cdweb/app'
run Sinatra::Application

publicフォルダへweb/htmlからmilkodeという名前でシンボリックリンクを貼る。

$ cd /home/example/web/html
$ ln -s /home/example/web/milkode/public milkode

これで準備終わり。あとはhttpdを再起動すればOKです。

$ sudo /etc/init.d/httpd restart

この辺りは普通のRackアプリやSinatraアプリと変わらないので他にも色々な方法があると思います。あくまで一例です。

gmilkの検索速度を高速化

ファイル数が多い時にgrepを使って検索速度の高速化を行いました。

詳しくはこちらをどうぞ。

リリースノート

  • milk web
  • milk
    • 'milk files' add --all option
  • gmilk
    • Add exist_command?('cat')
    • Change how to call exist_command?
  • etc

関連記事

Milkodeをgrepと組み合わせたら検索速度が40倍速くなった

ファイル数が多いとgmilkが遅くなるという指摘があったので高速化しました。

f:id:tuto0621:20130611002855j:plain

その1. テスト、ソースコード数の多いパッケージを登録

テスト用にlinuxをパッケージに登録。

$ tar xzvf linux-3.10-rc4.tag.xz
$ cd linux-3.10-rc4
$ milk add .
package    : linux-3.10-rc4
result     : 1 packages, 42810 records, 42810 add. (22m 39.2s)
*milkode*  : 188 packages, 201999 records in /Users/ongaeshi/.milkode/db/milkode.db.

4万ファイル、1600万行です。データとしては申し分無いです。

$ cd linux-3.10-rc4
$ milk info
Name:      linux-3.10-rc4
Records:   42810
Breakdown: C:34005(79%), Makefile:1713(4%), Text:1707(3%), .S:1375(3%), other:1688(3%), unknown:2322(5%)
Linecount: 16916142

その2. 古いバージョンで検索

Milkode1.0.0、キーワードはint mainで検索してみます。

$ time gmilk int main | wc 
    8375   59821  717038

real    1m22.843s
user    1m0.299s
sys 0m1.965s

1分22秒かかりましたこれはいかんですね。

※ 最後のwcは出力にかかる時間を省力して純粋に検索にかかった時間を調べるため

その3. マッチしたレコード数を調べる

gmilk -mでキーワードにマッチしたレコード数を調べることが出来ます。(1.0.2から)

$ gmilk int main -m | wc
    9027    9027  711003

int mainを含む行を持つ可能性のファイルが9027個。これを一つずつ探索するのはスクリプトなのでオーバーヘッドはそこかなあと予想。ファイルリストさえ作ったらそれを検索するのはgrepとかagに任せた方が速いのでは?というアイデアを思いついたのでやってみることに。

その4. シェルで頑張る

-mでファイルリストを生成、結果をxargs grepに渡して、さらにその結果をgrepに渡します。(後半はよくあるgrepでAND検索のテクニックです)

time gmilk int main -m | xargs grep -n int | grep main | wc
real    0m2.962s
user    0m1.564s
sys 0m0.217s

1m22s -> 2.96s と大分速くなりました(約40倍!)。同じキーワードを何回も入力しないといけないのが面倒ですね。

その5. -eオプションの追加

gmilkに-e grepを付けると、その4でやったことを自動でやってくれるようにしました。

$ time gmilk int main -e grep | wc 
   19427  124715 2623891

real    0m3.062s
user    0m2.685s
sys 0m0.429s

-e agも出来ます。意外にもgrepの方が速かったです。

$ time gmilk int main -e ag | wc 
   19427  124715 2623891

real    0m6.356s
user    0m5.584s
sys 0m0.784s

その6. 自動で"-e grep"する

マッチするレコードの数が500を超えると自動で-e grepの検索に切り替えます。(xargsとgrepがある環境のみ。)

$ time gmilk int main | wc 
Number of records is large. Use auto external tool (gmilk -e grep)
   19427  124715 2623891

real    0m3.038s
user    0m2.662s
sys 0m0.448s

レコード数が遅くてもスクリプトで検索したい時(ちゃんと行内の単語だけでマッチさせたい時など)は--no-externalオプションを使って下さい。

$ time gmilk int main --no-external | wc 
    8375   59821  717038

気にしなくても勝手に速くなるよ!ってことです。

ダウンロード

速くなったMilkode を是非一度お試し下さい。

$ gem install milkode

ダウンロード, Gems

milk webは検索結果を1ページに表示出来る数だけ少しずつ検索していくのでこの問題はそもそもありません

おまけ. gmilkのいい所

  1. AND検索のたびにコマンドをパイプでつなげなくてよい(私的にはgrenの頃から大切)

  2. 検索ディレクトリを指定せずに検索出来る

$ cd /a/proj/lib/command/
# プロジェクト全体から検索したい・・
$ grep -r -i a_keyword ../../

# ディレクトリ変わったのでパスも書き換えないと・・
$ cd foo/bar
$ grep -r -i a_keyword ../../../..

これが個人的には結構面倒です。gmilkだとパッケージを認識するので常にパッケージ全体を検索します。

$ cd /a/proj/lib/command/
$ gmilk a_keyword

$ cd foo/bar
$ gmilk a_keyword

常にgmilk キーワード1 キーワード2 …で検索出来ることを大切にしています。