株式会社クリアコード > ククログ

ククログ


GDBでデバッグするなら-g3オプション

RubyやPythonなどのスクリプト言語では実行中に例外が発生するとバックトレースを出力してくれます。バックトレースがあるとどこで問題が発生したかがわかるためデバッグに便利です。一方、CやC++では不正なメモリアクセスをすると、バックトレースではなくcoreを残して*1終了します*2。デバッガーでcoreを解析するとバックトレースを確認できます。

このように、CやC++でデバッグするときにデバッガーはなくてはならない存在です。スクリプト言語にもデバッガーはありますが、デバッガーを使わなくてもデバッグできる範囲が広いため、CやC++をデバッグするときのほうがデバッガーのありがたさがわかります。

この記事では、広く使われているデバッガーであるGDBをもっと便利に使うためのGCCのコンパイルオプション-g3を紹介します。

サンプルプログラム

まず、この記事で使うサンプルプログラムを示します。マクロと関数があることがポイントです。

max.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* gcc -o max max.c */
#include <stdlib.h>
#include <stdio.h>

#define MAX(a, b) (((a) < (b)) ? (b) : (a))

static int
max(int a, int b)
{
  int max_value;
  max_value = MAX(a, b);
  return max_value;
}

int
main(int argc, char **argv)
{
  int a = 10;
  int b = -1;
  int max_value;

  max_value = max(a, b);
  printf("a=%d, b=%d, max=%d\n", a, b, max(a, b));

  return EXIT_SUCCESS;
}

次のようにビルドします。

% gcc -o max max.c

次のように実行します。

% ./max
a=10, b=-1, max=10

GDBでバックトレースを表示してみましょう。「(gdb)」がGDBのプロンプトで「(gdb)」の後にある「break max」や「run」が入力したGDBのコマンドです。

% gdb ./max
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /tmp/max...(no debugging symbols found)...done.
(gdb) break max
Breakpoint 1 at 0x400510
(gdb) run
Starting program: /tmp/max 

Breakpoint 1, 0x0000000000400510 in max ()
(gdb) backtrace
#0  0x0000000000400510 in max ()
#1  0x0000000000400554 in main ()
(gdb) continue
Continuing.

Breakpoint 1, 0x0000000000400510 in max ()
(gdb) continue
Continuing.
a=10, b=-1, max=10
[Inferior 1 (process 12138) exited normally]
(gdb) quit
%

バックトレースは次の部分です。

(gdb) backtrace
#0  0x0000000000400510 in max ()
#1  0x0000000000400554 in main ()

main()関数の中からmax()関数を呼び出していることがわかります。

-gオプション

GCCにはデバッグ情報を追加する-gオプションがあります。-gオプションをつけるとファイル名や行番号、引数の値もバックトレースに含まれます。

ビルド方法:

% gcc -g -o max max.c

バックトレース:

(gdb) backtrace
#0  max (a=10, b=-1) at max.c:10
#1  0x0000000000400554 in main (argc=1, argv=0x7fffffffe608) at max.c:21

max()関数がmax.cの10行目で定義されていることがわかるようになりました。

-O0オプション

デバッグをするときは最適化を無効にしたほうが便利です。これは、最適化をするとソースコードに書かれている処理の順番とコンパイル後の処理の順番が変わることがあるからです。ソースコードに書かれている処理の順番と実際に動く順番が異なると処理を追いにくくなります。そのため、デバッグをするときは最適化を無効にしましょう*3

GCCで最適化を無効にするには-O0オプションを使います。「Optimiaze」の「O」(アルファベット)に最適化レベルの「0」(数字)の組合せです。どちらも似たような字型なので気をつけてください。

ビルド方法:

% gcc -g -O0 -o max max.c

-g3オプション

-gオプションを指定するとファイル名などもわかるようになりますが、GDB内ではマクロを使えません。

マクロを使えないことを確認:

(gdb) print MAX(a, b)
No symbol "MAX" in current context.

ここで使っているMAX()マクロくらいであれば手で展開しても耐えられますが、groongaのGRN_BULK_HEAD()マクロぐらいになるとやってられません。GDB内でもマクロを使えると便利です。

-g3オプションを指定するとGDB内でマクロを使えるようになります。

ビルド方法:

% gcc -g3 -O0 -o max max.c

マクロを使えることを確認:

(gdb) print MAX(a, b)
$1 = 10

「-g3」は「-g」にデバッグレベル「3」を指定するという意味です。

-ggdb3オプション

多くの環境(パソコン上で動いているLinuxやFreeBSDなど*4)では-g3オプションを使うとGDBで便利になります。そのため、本当は-ggdb3オプションのことは気にしなくても構いません。もし、デバッガーとしてGDBを使うということがわかっている場合は-g3オプションの代わりに-ggdb3オプションを使えます。

-ggdb3オプションは「gdb」用のデバッグ情報をデバッグレベル「3」で出力する、という意味です。-ggdb3オプションを使っていると「あぁ、GDB用にビルドしているんだな」ということがわかりやすいという利点があります。一方、GCC以外のコンパイラーとの互換性の問題があります。

Clang 3.2以降では-ggdb3オプションも受け付けますが、それ以前では警告になります。

% clang -ggdb3 -o max max.c
clang: warning: argument unused during compilation: '-ggdb3'
%

ただ、Clangでは-gオプションでも-g3オプションでも動作は変わらず、-g3オプションを指定してもGDB内でマクロを使うことはできません。

改めて書きますが、多くの環境では-g3も-ggdb3も同じ動作になるため、通常は-g3オプションを使っていれば十分です。

ファイルサイズ

ビルド済みのバイナリファイルを配布するときはファイルサイズに気をつけてください。-gオプションでは1.X倍くらいファイルサイズが大きくなるくらいですが、-g3オプションを指定すると倍以上ファイルサイズが大きくなります。

% gcc     -O0 -o max-no-g max.c
% gcc -g  -O0 -o max-g    max.c
% gcc -g3 -O0 -o max-g3   max.c
% ls -lhS max-*
-rwxr-xr-x 1 kou kou  35K  5月  9 10:55 max-g3
-rwxr-xr-x 1 kou kou 8.3K  5月  9 10:55 max-g
-rwxr-xr-x 1 kou kou 6.8K  5月  9 10:55 max-no-g

ユーザーはGDBでデバッグしないはずなので、そのために倍以上ファイルサイズが大きくなるとうれしくありません。バイナリファイルを配布するときは-g3オプションなしでビルドするか、ビルドしたファイルからデバッグ情報を取り除いてから配布してください。参考までにstripコマンドでデバッグ情報を取り除いたときのファイルサイズを示します。-gオプションなしでビルドした時よりもさらに小さくなっています。

% strip -o max-g3-stripped max-g3
% ls -l --human-readable --sort=size max-*
-rwxr-xr-x 1 kou kou  35K  5月  9 10:55 max-g3
-rwxr-xr-x 1 kou kou 8.3K  5月  9 10:55 max-g
-rwxr-xr-x 1 kou kou 6.8K  5月  9 10:55 max-no-g
-rwxr-xr-x 1 kou kou 4.5K  5月  9 10:57 max-g3-stripped

ただ、-gあり・なし・strip済みは、-g3指定のときに比べればそれほど違いがないので、多くのケースでは-g3を指定するとき以外はファイルサイズをそんなに気にしなくてもよいでしょう。

configureでの指定の仕方

configureを使ってビルドするシステムでは以下のようにconfigureの引数にCFLAGSを指定することでデバッグ情報付きでビルドできます。

% ./configure CFLAGS="-g3 -O0" ...

次のように環境変数ではなくconfigureの引数としてCFLAGSを指定していることがポイントです。

% CFLAGS="-g3 -O0" ./configure ...

環境変数として指定するとconfigure.acを編集するなどして自動でconfigureが再実行されたときにCFLAGSは指定されません。一方、configureの引数と指定しておくと再実行されたときでもCFLAGSが指定されます。そのため、環境変数ではなく引数として指定しておいた方がよいです。

まとめ

GDBで便利にデバッグするためのGCCの-g3オプションを紹介しました。

CやC++でGDBを使ってデバッグするときは使ってみてください。

*1 limitulimitでコアファイルのサイズを制限している場合はcoreを残さないこともあります。

*2 catchsegv ./a.outというようにcatchsegvコマンド経由で実行するとC/C++で書いたプログラムでもバックトレースを出力します。

*3 最適化を有効にしたときだけ発生する問題もあるため、最適化を無効にすると問題が再現しなくなることがあります。そのときは最適化を有効にしたままデバッグしましょう。

*4 もっと興味がある場合はGCCのソースを確認してください。gcc/opts.cのset_debug_level()grep -r "#define PREFERRED_DEBUGGING_TYPE" gcc/config | grep -v DWARF2_DEBUGなどを確認するとよいでしょう。

2013-05-08

働く環境としてのクリアコード(福利厚生編)

はじめに

クリアコードでは一緒に働くプログラマーを募集しています。昨年6月からパッチ採用という採用方法にしましたが、それ以来、採用へのお問合せがほとんどなくなりました。今年2月からインターンの募集を開始しましたが、まだお問合せがありません。しかし、採用やインターンシップページヘのアクセスは増加しています。採用ページを見た方がクリアコードは何か特別なスキルを要求しているように感じたり、パッチ採用のプロセスは時間や労力がかかりそうだがそれだけのコストを払う価値があるか判断できない、あるいはそもそも応募するかどうか判断するための情報が不足していることが原因ではないかと仮説をたてました。

実際、パッチ採用を開始する前の去年4月に入社した社員に聞いてみると、「いやあ、パッチ採用してなくても応募するのは敷居が高かったですよ。踏ん切りつけるのに1ヶ月ぐらいかかりました。面接して次はペアプログラミングと言われたときは結構プレッシャーかかりましたよ。もしパッチ採用をその時にやっていたら、ああ、求められているものが高いんだなあ、自分では無理だろうなと、諦めて応募しなかったかもしれません。」と言っています。なお、その社員は普通にクリアコードで活躍しているので、やはり応募者にとって必要な情報を提供できていなかったといえます。

クリアコードでは、ククログやRuby会議での発表などを通じて、主に開発に関する情報を発信してきました。一方でクリアコードにはどんな人が働いているのか、またどのようなワークスタイルなのかといった情報はこれまであまりお伝えする機会がありませんでした。そこで今後はこのような情報をククログを通じて発信したり、関心を持っていただいた方との交流の機会を多く設けてクリアコードのことを伝えていきます。

今回は、働く環境としてクリアコードはどんなところなのか福利厚生の面からご紹介します。

社員の健康

クリアコードでは「健全なコードを書くためにも健康であるべき」という考えのもと、社員の健康をとても大事にしています。健康を維持するためには社員の自己管理が大切です。会社としても社員の健康管理を支援する目的で、残業をなくして休暇を取りやすくし、健康診断を通じた健康管理を行っています。

フレックスタイム制で残業はほとんどなし

一般的に裁量労働制によって社員が働きやすくなるケースもありますが、クリアコードでは労働時間を管理して、残業や休日出勤が発生しないようにしています。フレックスタイム制を採用しており、コアタイムは10時から15時です。そのため、社員は遅くとも10時には出社します。10時に出社した場合、終業は19時となります。20時を過ぎて会社にいることはほとんどありません。夕方から予定がある場合などは、朝7時に出社して16時に退社することもあります。最近では遅刻はほとんどなくなり、残業は月平均で3時間程度です。

年1回の健康診断で健康状態を把握

年1回すべての社員が健康診断を受診します。一昨年からはアルバイトも健康診断を受診しています。希望すれば会社の全額負担で人間ドックを受けることもでき、今年は全員で人間ドックを受診します。クリアコードに就職して健康診断の結果が毎年改善されるケースはよく見受けられます。

完全週休2日制、各種休暇制度も完備

土日は必ず休みとなる完全週休2日制です。有給休暇は入社後6ヶ月で10日、その後1年毎に法定通りに有給休暇を付与します。有給休暇の消化率は50%程度であまり高いとは言えませんが、申し出をすればほぼ希望通りに有給休暇を取れます。有給休暇の半日取得も可能です。休暇を取りづらい雰囲気も特にありません。夏季休暇は有給休暇とは別に特別休暇として3日あり、毎年全員が取っています。その他結婚、出産時の慶弔休暇もあります。昨年1月から12月の年間休日数の平均は132日です。なお、休暇中に仕事の連絡があることはまずありません。事前にお客様に通知したり、他の担当者がカバーできる体制を用意しています。

就業場所

ほとんどの仕事が持ち帰りの案件です。客先常駐で作業を行うことはありません。以前は特定労働者派遣事業の届出をしていましたが、昨年10月をもって廃止しました。現在は全員がオフィスに出社して業務を行っています。これは、場を同じにすることで、状況を共有したり、気軽に相談できたり、思いがけない情報にであったりするメリットがあるからです。そのため、お客様と一緒に開発するような案件では、お客様と打合せしたり、一緒に開発するために週1回など定期的にお互いのオフィスを行き来しています。

肉の会と社員旅行で親睦を図る

毎月29日あたりに肉の会と称して、社員全員参加の飲み会を実施しています。29日のリリースを祝い労うことが目的です。一緒に開発している取引先の開発者や社員がフリーソフトウェア活動を通じて出会った方をゲストとしてお招きすることもあります。

また、毎年社員旅行に出かけています。毎回貸別荘を借りて自炊し、同じ釜の飯を喰らうことで結束力を高めています。今年は2泊3日で房総半島に行く予定です。肉の会、社員旅行とも費用は会社が負担しています。

まとめ

クリアコードに入るとどんな働き方になるのか、福利厚生の面から、社員の健康管理、残業、休暇、就業場所、社内のイベントについて紹介しました。この他にも社宅退職金についての制度もありますので、是非参考にしてください。

タグ: 会社
2013-05-16

GtkIMCocoaの動作状況

はじめに

今回は、以前紹介したMac OS XのCocoa版GTK+で日本語入力を行うためのgtkimmodule(GtkIMCocoa)の開発の続きです。

前回の記事に対してはいくつかの反応を頂きましたが、中でも興味深かったのは、Xamarin Studio(旧MonoDevelop)でも日本語入力ができるようになるかもしれないという記事でした。筆者は、現時点ではCocoa版GTK+に対応したバイナリを配布しているアプリケーションはほとんどないと認識していたので、これは意外な反応でした。この記事をきっかけに知ったのですが、Mac版MonoDevelopでは何年も前からCocoa版GTK+を採用しており、当初からユーザーの間では日本語入力の問題が取り沙汰されていたようです。MonoDevelopはメジャーなゲームエンジンの一つであるUnityにも採用されており、潜在的なユーザーは意外と多いのではないか?ということに気づきました。

そこで今回は、いくつかのGTK+アプリケーションにGtkIMCocoaを組み込んでみて、現時点のGtkIMCocoaがどの程度動作するのかを確認した結果を紹介致します。問題点を把握することで開発を加速させることが目的であり、現時点での実用性をアピールするものではありませんので、その面での期待はしないでください。

Xamarin Studioへの適用方法と動作検証結果

前回の記事でも紹介した通り、GtkIMCocoaはGTK+本体を修正すること無く組み込むことができるように設計されています。このため、バイナリ形式で配布されているGTK+に対しても、GtkIMCocoaのモジュールファイルを追加して、設定ファイルを更新するだけで適用することができます。

GtkIMCocoaの対応バージョン

2013年5月22日現在、Xamarin Studioに同梱されているGTK+は、正式にMac OS Xに対応した3.0系ではなく、2.0系にCocoa対応パッチを当てたバージョンが採用されています。これに対して、GtkIMCocoaは主にGTK+3をターゲットとしており、前回の記事でリリースしたgtkimcocoa-0.0.0も、GTK+3のみをビルド対象としています。

しかし、その後の修正でGTK+2に対してもビルドできるように対応しておりますので、GTK+2アプリケーションに組み込みたい場合は、GitHubから最新のソースコードを取得してください。

Xamarin Studioに対するGtkIMCocoaのビルド方法

GtkIMCocoaの基本的なビルドおよびインストール方法は前回の記事を参照してください。

Xamarin Studioに同梱されているGTK+に対するビルドも、基本的にはこれと同じ方法で行います。ただし、インストールされているパスやGTK+バイナリの対応アーキテクチャに合わせて、configureスクリプト実行時に環境変数を調整する必要があります。GTK+が/Library/Frameworks/Mono.framework/Versions/2.10.12にインストールされている場合のインストール例を以下に示します*1。前回と同様にjhbuildのshellで実行します。

$ ~/.local/bin/jhbuild shell
$ export GTK_PATH=/Library/Frameworks/Mono.framework/Versions/2.10.12
$ git clone git://github.com/ashie/gtkimcocoa.git
$ cd gtkimcocoa
$ ./autogen.sh
$ ./configure ¥
  PATH="$GTK_PATH/bin:$PATH" ¥
  PKG_CONFIG_PATH="$GTK_PATH/lib/pkgconfig" ¥
  CFLAGS="-arch i386" ¥
  LDFLAGS="-arch i386"
$ make
$ sudo make install
$ $GTK_PATH/bin/gtk-query-immodules-2.0 | sudo tee $GTK_PATH/etc/gtk-2.0/gtk.immodules

Xamarin Studioに含まれるGTK+はi386用のバイナリですが、x86_64環境で普通にビルドしてしまうとx86_64用のバイナリが生成されてしまうため、CFLAGSおよびLDFLAGSにオプションを追加して適切なバイナリを生成するようにしています。

動作検証結果

前述の方法でGtkIMCocoaを組み込んだXamarin Studio 4.0.1を実行したところ、トップ画面の検索エントリで日本語を入力できることを確認しました。

Xaramain Studioの検索エントリでの日本語入力の様子

次にテキストエディタで入力を試みたところ、こちらでは問題が発生しました。

  1. 未確定文字列が表示されない
  2. Enterでの確定時に、改行が挿入されてしまう
  3. 日本語入力OFF時に文字が2重に入力されてしまう
  4. 日本語入力OFF時に、前回の未確定文字列が常に表示されてしまう

Xaramain Studioのテキストエディタウィジェットでの日本語入力の様子

GTK+が標準で用意しているテキスト入力ウィジェットについては、前回の記事である程度の動作は確認できています。しかし、アプリケーションの中にはテキスト入力ウィジェットを独自実装して提供しているものもあります。このようなウィジェットでは、テキスト入力処理の動作がGTK+標準のウィジェットとは微妙に異なることによって、不具合が発生することもしばしばあります。このため、immoduleの開発にあたってはさまざまなアプリケーションと組み合わせての動作検証や調整が必要であり、時にはアプリケーション側の修正も必要となります。Xamarin Studioのテキスト入力ウィジェットもアプリケーション独自のウィジェットであるため、このケースに当たってしまったようです。

原因を究明するにあたり、まずはUbuntu上のXamarin Studioでも簡単に動作確認を行ってみました。UbuntuではGtkIMCocoaは動作しませんので、Ubuntu標準のibusというimmoduleで動作を検証しています。これにより、問題がアプリケーション側にあるのか、immodule側にあるのかを大雑把に切り分けることができます。

結果としては、

  • 1.の問題はUbuntu上のXamarin Studioでも再現するため、アプリケーションの問題である*2
  • その他の問題は再現しないため、GtkIMCocoaの問題である

ということになりました。

この検証結果を受けてGtkIMCocoaには修正を入れ、2.〜4.の問題については解決しています。しかし、1.の問題については着手できておらず、今後の調査が必要です。

Sylpheedでの動作検証

一つのアプリケーションだけでは問題を把握しきれない可能性が高いため、Xamarin Studioに加えて、Sylpheedでも動作検証を行いました。

Sylpheedのビルド方法

SylpheedについてはMac OS X用のバイナリは配布されていませんので、ソースからビルドする必要があります。筆者の場合は、GTK+2をjhbuildでインストールし、GtkIMCocoaとSylpheedもjhbuildのshell上でビルドしました。

GTK+2のインストール

前回の記事を元にGTK+3をインストール済みの環境の場合、追加で以下を実行することでGTK+2をインストールすることができます。

$ ~/.local/bin/jhbuild build meta-gtk-osx-core
GtkIMCocoaのインストール

GtkIMCocoaについては、GTK+2用のimmoduleを追加するために、最新のソースコードを取得して、前回と同様の手順でビルドおよびインストールします。

$ ~/.local/bin/jhbuild shell
$ git clone git://github.com/ashie/gtkimcocoa.git
$ cd gtkimcocoa
$ ./autogen.sh
$ ./configure
$ make
$ make install
$ gtk-query-immodules-2.0 > ~/gtk/inst/etc/gtk-2.0/gtk.immodules
Sylpheedのインストール

Sylpheedのサイトからソースコードをダウンロードして、同様の手順でビルドします。

$ tar xvfj sylpheed-3.4.0beta3.tar.bz2
$ cd sylpheed-3.4.0beta3
$ ./configure --prefix=~/gtk/inst
$ make
$ make install
Sylpheedでの動作検証結果

SylpheedではGTK+標準のウィジェットしか使われていないため、一見すると普通に動いている様にも見えます。

Sylpheedでの日本語入力の様子

しかしながら、よくよく確認してみると、以下のような問題があることがわかりました。

  1. キー操作で入力モードを切り替えると、フォーカスウィジェットが勝手に切り替わってしまう
  2. フォーカスが当たっているウィジェットと、実際に入力されるウィジェットが異なる場合がある
  3. 注目文節(2重下線部)の表示が間違っている*3

その後の修正で2.の問題については解決していますが、1.および3.の問題については今後の調査が必要です。

まとめ

今回の検証では、当初の設計意図通り、バイナリ配布されているCocoa版GTK+アプリケーションに対して、GtkIMCocoaのモジュールファイルを一つ追加するだけで日本語入力が可能となることは確認できました*4。しかしながら、細かい挙動ではまだまだ課題も多く、引き続き地道な検証および調整作業が必要なこともわかりました。また、Xamarin Studioについてはアプリケーション側の修正が必要な事もわかりました。

引き続き弊社インターンシップの題材としても挙げていますので、修正にチャレンジしてみたいと思われる方はご応募頂ければ幸いです。

*1  パス中のバージョン番号はインストールされているXamarin Studioによって異なると思われますので、その場合は適宜読み替えてください。

*2  未確定文字列をマウスで選択状態にして反転させると表示されることから、GTK+のスタイル定義の問題である可能性もあります。

*3  このスクリーンショットの状態では本来は「件名」の部分が注目文節になっているのですが、2重下線は「本当は」の部分に描画されています。

*4  現在判明している主な問題点を解決出来た際には、GtkIMCocoaのコンパイル済みバイナリを配布することも検討しています。

2013-05-23

コミットへのコメントサービス導入事例のご紹介

はじめに

昨年12月、クリアコードは「コミットへのコメントサービス」を始めました。このサービスは、「みんながみんなのコードを読む」文化づくりを支援するサービスです。どうして「みんながみんなのコードを読む」文化づくりを支援するかというと、よいコードを書くことを当たり前にするためにはまず「みんながみんなのコードを読む」文化にすることからはじめるのがよいという考えからです。

今年2月からミラクル・リナックスさんに対してこのサービスを提供しています。この導入事例を通じて、コミットへのコメントサービスがどのようなものなのかを紹介します。

開発チームの紹介

はじめに、コミットへのコメントサービスを利用しているミラクル・リナックスの開発チームを簡単に紹介します。この開発チームは、デジタルサイネージやサーバー監視に関するソフトウェアを開発しています。開発は次のプロセスで進めています。

  1. BTSにバグや新機能を報告
  2. 開発者が手元でバグや新機能の内容を確認し、ソースコードを修正
  3. ソースコードを修正したらBTSにパッチをアップロードし、自分以外の誰かにレビューを依頼
  4. レビューが通ったらリポジトリ(Subversion)にコミット
  5. コミットしたらコミットしたリビジョンをBTSに書き込み、バグをクローズ

このプロセスでは開発者が書いたコードは誰か別の人が必ず読む仕組みになっています。しかし、みんなが読むわけではありません。

パッチをBTSにアップロードする前の状態は共有していません。開発者ごとにgit-svnquiltを使って、手元で作業を進めています。

導入の経緯

次に、ミラクル・リナックスの開発チームがどうしてこのサービスを導入したのかを説明するために、導入までの経緯を紹介します。

最初に、開発チームのメンバーにサービス内容を紹介しました。開発チームのメンバーからは、「他の人がパッチをアップロードするまでどうやって試行錯誤しているかに興味がある」、「コードを読んでもらえるとうれしい」など、コミットへのコメントサービスの導入に前向きな意見をいただきました。また導入による次の効果を期待されていました。

  • 作業途中の状況を共有できるようになる
    • これまでは間違った方向に進んでいても、レビューで指摘されるまで気がつかないケースがあった
  • コーディングスタイルを共有できるようになる
    • コードのスタイルに統一感がないケースがあった

開発チームの後押しもあり、経営層のサービスに対する理解も得られ、2月からサービスをはじめることになりました。現在はこの開発チームのうち4名が「みんながみんなのコードを読む」ことに取り組んでいます。

以上が導入までの経緯です。いくつか認識している課題があり、このサービスによりそれらを解決できそうだという期待があったことがサービス導入の決め手になりました。

導入後の流れ

それでは、サービス導入後はどのように進めたかを紹介します。導入直後のみの作業と日々の作業をわけて紹介します。

  • 導入直後のみの作業
    • コミットメールの配送開始
    • 導入研修の実施
  • 日々の作業
    • コミットを読む
    • 読んだことを記録
導入直後のみの作業:コミットメール配送と導入研修

導入後すぐに、開発者が手元の変更をコミットするとコミットメールが流れるようにしました。コミットメールの設定方法は今後ククログの記事でまとめる予定です。

その後、導入研修を実施しました。導入研修では、コミットメールを読む目的の説明とコミットメールを読む練習を行いました。導入研修は、DevLOVE 2012でのセッション「リーダブルコードを読んだ後」に沿った内容です。導入研修では、コミットを読みやすくするためにはどうすればよいか参加者全員で議論し、翌日からどのようにコミットするのか、その方針を共有しました。

日々の作業:コミットメールを読む。読んだことを記録する。

導入研修の翌日からコミットメールを開発チームのメンバーとクリアコードの担当者が読み始めました。クリアコードの担当者はコミットメールを読んで気づいた点があればコメントしました。コメントはコミットを読みやすくするためのアドバイスが中心でした。例えば、より変更内容が伝わるコミットメッセージの書き方や、よりわかりやすい名前の提案、読みやすいコードの書き方の提案などです。もちろんtypoなど誤りがあった時もコメントします。

一日の終わりに、その日読んだコミットメールについて次の記録をつけます。

  • コミットメールの何割読めたか(割合は個人の直感)
  • 印象に残ったコミット

「何割読めたか」を「正確な値ではなく直感でよい」としているのは正確な値が必要ないからです。値は傾向を把握するために使うだけなので概算値で十分です。必要のない情報を取得するために日々の作業の負荷があがってしまわないように直感でよいことにしました。

ふりかえり

導入後、ある程度経った頃にこのサービスについてふりかえる会「ふりかえり」を何度か行いました。

ふりかえりは開発チームとクリアコードの担当者が一同に会して行います。コミットメールを読んだりコメントしたりする上での疑問や課題を共有し、解決策を検討することが目的です。導入から3週間が経過した時に最初のふりかえりを行いました。次に、導入から6週間が経過した時に2回目のふりかえりを行いました。2回目のふりかえりでは収集したデータから、「みんながみんなのコードを読む文化」がどれくらい根付いたか測定し、見つかった課題に対しては対策を検討しました。

3週間経過時のふりかえり

導入研修から3週間の状況は次のとおりでした。

  • 1日あたり50通から100通のコミットメールが流れている
  • 開発チームのメンバーは平均すると50%程度のコミットメールを読んでいる
  • クリアコードのメンバーだけでなく開発チームのメンバーもコメントしており、コミットメールを契機にした議論が活発だった
  • 日々の記録の「印象に残ったコミット」はあまり記録されなかった

開発チームのメンバーからコミットメールを読むようになってからの変化について次の意見が挙がりました。

  • パッチが細かくなって機能修正とインデントの修正が分けられるようになったのはよい効果だと思う
  • 読む側としては変化を感じないが、書くときはコミットを小分けにするようになった
    • 以前なら2,3個の大きなパッチだったものが、10個ぐらいの小さなパッチになった
  • パッチは以前よりも小さくなった
    • 小さくなったことで読みやすくなった
  • コミットメッセージを書くことに時間がかかるようになった
  • コミットメールを読む人の立場を考えると、コミットメッセージは詳しく書いてあるほうがわかりやすいと思うが、どこまで詳しく書くべきか悩む

コミットメールを読むこと、気づいたことにコメントすることが当たり前という文化ができつつありました。ひとつのコメントから議論が盛り上がることもよくありました。また、読まれることを考えてコードを書くことが習慣となってきました。

一方、うまくいかないこともありました。読みやすいコミットについて判断がつかなかったり、読みやすくするためにどうするのがよいかは試行錯誤していました。

この時、読む人の立場という観点に関連して、これまで困ったことがあるケースが1つ挙がりました。研究開発したソフトウェアを製品化する過程で、なぜ研究開発時にそのようなコードを書いたのか理由がわからず、製品化するときに判断できないというケースです。研究開発でプロトタイピングしている場合でも、意図を伝えるよう意識して欲しいという要望です。これについては、実際に研究開発している開発者がコミットメッセージを詳しく書くことでコードの意図が伝わるか試すことになりました。

日々の記録に印象に残ったコミットを書かない理由として、自分のプロジェクトのコミットメールだと新たな気づきが少ないとの意見が挙がりました。この対策として自分が関わっていないプロジェクトのコミットメールも流すようにしました。またHTMLメールだと、特定のメールクライアントで表示がくずれるケースがあることがわかったため、テキストメールに変更することにしました。

6週間経過時のふりかえり:データの分析

コミットメールを読み始めてから6週間が経過したときに2回目のふりかえりを行いました。この間にクリアコードではコミット数や読めた割合といったデータを収集し、分析ツールによって期待される効果がでているか検証しました*1。期待される効果がみられないものについては、それが問題あるものかどうか検証し、問題だと判断したものについては、対応策を検討しました。

主に次のデータを収集し分析しました。データは月毎に集計し、開始月(2月)と翌月(3月)との間の傾向を分析しました。

  • コミットサイズ
  • コミット数
  • コメント数
  • コミットメールを読めた割合
コミットサイズ

コミットサイズは徐々に平均値が小さくなる傾向を期待しています。わかりやすいコミットはコミットの内容が小さくまとまるからです。読みやすくすることを意識してコミットするようになると、コミットのサイズが小さくなるはずです。

データを分析すると、デジタルサイネージ、サーバー監視のどちらのプロジェクトでも、サービス導入後にコミットサイズが小さくなっていました。また、興味深いことに、導入開始翌月は、それぞれのコミットサイズの平均値が非常に近い値となっていました。同じ開発言語(C++)で書かれていること、適切な粒度でコミットできていることが理由だと考えられます。コミットサイズについては、期待される効果がでていることが確認できました。

一方、コミットサイズだけを指標として扱うことに対する懸念が挙がりました。コミットサイズが小さければ小さいほうがよいのであれば、意味もなくコミットを分割することにつながってしまうのではないかということです。つまり、コミットサイズだけではなくわかりやすさも加味した分析を行う必要があるということです。このような分析をどのように行うかはこのサービスの現在の課題です。

コミット数

期間内の開発の規模が同じだった場合、コミットサイズが小さくなることに反比例してコミット数が増えることを期待しています。これは、全体で書くコード量が変わらないからです。「コミットサイズ × コミット数 = 開発規模(コード量)」という式が成り立ち、「開発規模」が変わらず、「コミットサイズ」が小さくなった場合は、「コミット数」が増えるはずです。

データを分析すると、コミット数の増加傾向はみられませんでした。これは、どちらのプロジェクトも開発規模が開始月と翌月で異なったことが原因でした。コミットのコメントサービスを始めたことによって、コミットするときに考えることが増えて時間がかかるようになっているとの意見はありましたが、開発量に影響を与えるものではなかったようです。そのため、今回はコミット数は有意なデータとはなりませんでした。

コメント数

コメント数は増加する傾向を期待しています。これは、コミットメールを読むことに慣れてくると、より多くのコミットを読むことができるようになり、気になることが増え、コメントする機会が増えるだろう、という理由からです。

開始月と翌月を比較するとコメント数は若干減少する傾向にありました。これは期待した傾向ではないので別途検証しました。

コミットメールを読めた割合

コミットメールを読めた割合は増加する傾向を期待しています。コミットメールを読むことに慣れる、読みやすいコミットメールが増える、この2つの効果によって1つのコミットメールをより短い時間で読めるだろう、という理由からです。

開始月と翌月を比較すると、読めた割合が全員減少していました。これは期待した傾向ではないので別途検証しました。

読めた割合を分析しているときに、印象に残ったコミットに関するコメントが記録されない日が増えていることにも気づきました。これは期待した傾向ではないので別途検証しました。

6週間経過時のふりかえり:期待した傾向が見られない項目の検証

期待した傾向が見られなかった次の項目についてはその原因を究明し、対策を立てるため、なぜそのような結果になったのか仮説を立てて検証しました。

  • コミットメールを読めた割合が減っている
  • コメント数が減少している
  • 日々の記録のコメントが書かれていない
コミットメールを読めた割合が減っている

減った要因として以下の5つの仮説を立てました。

  1. 忙しくて読めなくなった。
  2. コミットメールを読んでもメリットがないと感じている。
  3. コミットメールはHTMLメールのほうが読みやすかった。テキストになり読みにくくなった。
  4. コミットメールの読み方を変えた。たとえば、ひとつひとつ時間をかけて読むようになった。
  5. 自分が関わっていないプロジェクトのコミットメールを読むのが辛い。
  6. コミットメールの量が多くなったので、コミットメールを読み飛ばすようになった。

メンバーに確認したところ、1.、4.、6.に該当することがわかりました。6.のケースでは、朝一番に大量のコミットメールが届いていると読む気になれず、読めた割合が減っていました。4.のケースでは、コードレビューを集中的に行なう時期だったのでコードレビューと同じモードでじっくりと時間をかけて読むようになった結果、読める量が減っていました。また読めた割合をつけていると100%が求められているように感じ、読めていないときは挫折感があるという意見も聞かれました。

これらの対策として、読めた割合が100%になることを目指すものではなく、毎日一定の時間コミットメールを読む習慣をつけることが目指すべきところであることを再確認しました。また読む時間を確保する方法として、毎日少なくとも1回コミットメールを読む時間をとることを提案しました。

コメント数が減少している

コメント数が減少した要因として以下の仮説を立てました。

  1. 読む割合が減ったのでコメントする機会が減った。
  2. コメントをするのに時間がかかるのでコメントしなくなった

1.は事実として読む割合が減っているので正しいと言えます。2.については、メンバーに確認したところ、気になることがあったときに、コメントせずに流しているケースがあることがわかりました。コミットメールを読んで、こうしたらいいのになという案は浮かぶが、なぜそれがよいかパッと出てこないときにコメントすることを諦めてしまうことがあるようです。

クリアコードでは、コミットメールにコメントする際、次の3点を含めることにしています。

  • どこが気になったか
  • なぜ気になったか。(例:○○だから読みにくい。)理由がなければないことを表明する。
  • 改善案があるかないか。改善案があればそれを書く、なければないことを表明する。

このルールに従えば、理由や改善案がない場合でもそう表明すればよいだけなので、コメントしやすくなります。理由が浮かばないという理由でコメントすることを諦めないようにするために、コメント時にこのルールを参考にすることを提案しました。

日々の記録のコメントが書かれていない

読めた割合を記録する際、あわせて印象に残ったコミットについてコメントすることになっています。しかし、読めた割合は記録されている日でも、印象に残ったコミットについての記録されない日が多くなりました。コミットメールを読むことに慣れてきて、よいコードに気づく機会がさらに増えてくれば、気になったコメントを記録する日が増えることを期待していました。しかし、逆の傾向になっていました。どうして逆の傾向になっているか、次の仮説を立てました。

  1. 書くことがなくなった。
  2. 書く目的がわからない。
  3. 何を書いていいかわからない。

メンバーに確認したところ、そもそもの書く目的が明確でなく、書くこともなかったので、次第に書かなくなったということでした。一方で、印象に残ったコミットが記録されているとそれに対する反応はよくありました。そのため、読み物としては人気のあるコンテンツと言えます。ただ、自分が書くとなるとなかなか書けないという状況であることがわかりました。そこで、まずどのように書けばよいか、参考として、クリアコードの担当者が書く日々の記録もコミットメールで流すようにしました。また、記録する内容を気になったコミットに限定せず、コミットやプロジェクトに関連していれば何でもよいことにしました。

その他

ふりかえりを通じて、コードの書き方に悩んでいることがわかりました。よいコミットとそうでないコミットの基準が固まっていないため、コミットをどのような単位で行えばよいか考える時間が増えたようです。そこで参考としてクリアコードが行なっているフリーソフトウェア開発のコミットメールをこの開発チームにも流すようにしました。

ふりかえりの重要性

ふりかえりは2回とも2時間にも及びました。コミットメールを読むこと、読みやすいコミットを心がけることは開発チームにとって、新しい習慣です。そのため、これまでの開発スタイルに少なからず影響を与えます。取り組むことによって、上手くいかないことや、迷ったりすることが出てくるので、それを解決していくためには、チーム内で課題を共有し、改善策を検討・試行していくことが不可欠です。定期的なふりかえりは課題を共有したり改善策を検討する場となるので重要です。

サービス提供側としてのクリアコードのふりかえり

ミラクル・リナックスの開発チームとのふりかえりを踏まえて、クリアコードではサービス提供者としてこれまでをふりかえりました。

導入教育について

コミットへのコメントサービスの目的を伝えることはできました。一方で、ふりかえりでは読みやすいコミットに関する質問が多くあったので、導入教育の段階でよいコミットとはどのようなものか伝える必要があることがわかりました。伝える方法として、たとえば、よいコミットと悪いコミットの例をあげることによってよいコミットを伝えたり、よいコミットについて議論することが考えられます。

コミットメールの配信について

開発チームのコミットメールだけでなく、開発チーム以外のプロジェクトのものも最初から流すようにしたほうがよいことがわかりました。自分たちのプロジェクトだけがコメントされるのではなく、他のプロジェクトがコメントされるのを見ることによって、コメントによるコミュニケーションの仕方や判断基準を考える機会になります。その場合、最初から多くのコミットメールが流れることになるので、コミットメールの読み方(読む時間を確保する方法など)を紹介する必要がありそうです。

日々のコミットメールへのコメントについて

コメントすることによって相手との関係がギクシャクするのではないかと心配していましたが杞憂でした。しかし、コメントしても返事がないときはコメントが適切でなかったのではないかと不安になることがありました。導入研修で、コメントされたら返事するよう伝えるのがよさそうです。

また、気になったことがあっても、理由や改善案が思いつかずコメントしないケースがクリアコードの担当者にもありました。コミットメールを読んで「気づく」ということはとても価値のあることです。理由や改善案がパッと思いつかなければ、なぜそう思ったのか考えるよい機会になります。考えることによって自分がなぜそう思ったのか理由が明らかになり、それをコメントを通じて相手に伝えることによって、今までそれぞれの開発者でなんとなくだった考えを共有でき、自分たちのスタイルを作っていくことができます。考えることや伝えることを避けてしまうと、このような機会を失ってしまいます。考えることや伝えることをたくさん経験すると、コミットメールを読んで気づくことが増え、それをコメントすることができるようになります。もしかしたらコメント数の増加は開発者の成長を表す指標となるかもしれません。

日々の記録について

クリアコードの日々の記録を配信するようになって、「印象に残ったコミット」が記録されることが増えましたが、まだまだ記録されない日も多いです。再度、記録を残せない原因をヒアリングして対策をするとともに、日々、記録を書くことの目的を明確にする必要があります。

ふりかえりについて

データの分析方法が確立でき、問題点の洗い出しが容易になりました。また、見つかった課題を開発チーム、クリアコードで共有し、対策を立てて次のターンで実践する流れができました。ふりかえりはこのサービスにおいて最も重要な活動だといえます。

まとめ

ミラクル・リナックスさんへのコミットへのコメントサービス導入事例を紹介しました。コミットメールを読むことで、開発チームは読みやすいコミットや自分たちのスタイルを考え、共有する機会が増えました。次のステップでは、社内の別の開発チームへ展開します。その時はクリアコードの担当者ではなく、いまサービスを受けている開発チームのメンバーが伝道師となって「みんながみんなのコードを読む文化」を伝えます。

このサービスでは、コードを読むことによってどんなよい変化が生まれるのか理解した上で、コードを読むことからはじめ、「みんながみんなのコードを読む文化」を根付かせます。読む習慣が身につくと、コードを読んだ時に気づくことが多くなります。気づいたことは、考え、話し合い、共有することによって、自分たちのスタイルとなります。これは間違いなく開発チームの財産です。そしてこの財産はよいコードを書くために活かされます。

クリアコードは、コミットへのコメントサービスを通じてみんながみんなのコードを読む文化をより多くの開発チームに伝えていきたいと考えています。コミットへのコメントサービスについて詳しく知りたい、自分たちの開発チームにも導入可能か検討したい方がいらっしゃいましたら、是非ご連絡ください。

*1 なお、分析ツールは近日公開し、その使用方法やデータの見方はククログにて紹介する予定です。

2013-05-27

RubyKaigi 2013の予告:ステッカー・チラシの配布とRubyHirobaでの企画案と発表内容 #rubykaigi

早いもので今週後半(2013/5/30-6/1)はRubyKaigi 2013です。クリアコードはシルバースポンサーとしてRubyKaigi 2013を応援しています。

今回はRubyKaigi 2013に関連した以下の情報をお伝えします。

rroongaステッカーの配布

RubyKaigi 2013ではスポンサーがノベルティを配布する場所を用意してくれるそうです。ちょうどrroongaのステッカーがあるのでそれを配布する予定です。以下のデザインです。

rroongaステッカー(黒背景)

このステッカーは最近公開したrroongaステッカーデータを試しに印刷したもので、文字部分はシルバーになっています。試しに印刷したもので手持ちが少ないため、5枚のみ配布します。残念ながら会期中に入手できなかった人はステッカーデータをダウンロードして自分で印刷してください!

なお、rroongaステッカーとあわせてmroongaステッカーとgroongaステッカーも配布します。mroongaステッカーも試しに印刷したもので数が少ないため5枚のみの配布です。groongaステッカーは20枚配布します。

ところで、「rroonga」が何か知っていますか?知らない人は第4回 rroongaを使ったソースコード検索エンジンMilkode:隔週連載groongaを読んでみてください。

チラシの配布

RubyKaigi 2013ではスポンサーがノベルティを配布する場所を用意してくれるというのは前述のとおりです。クリアコードではgroongaサポートコミットへのコメントサービスインターンシップパッチ採用をしているので、それらのチラシをステッカーと一緒に配布します。

これらのことについて、会期中にクリアコードの人に直接聞いても答えます。会期中に会えるかわからない、話しかけるのが苦手、などという方は配布しているチラシを利用してください。

RubyHiroba 2013でやりたいこと

RubyKaigi 2013が終わった次の日、RubyHiroba 2013というイベントがあります。どうやら自由にスペースを使ってもよいということなので、1つやってみたいことがあります。実現可能かどうかわからないのですが、興味がある人は何らかの形でその意思を表明してください。たとえば、@_clear_code宛にツイートしたり、会期中にクリアコードの人に声をかけたりです。

やりたいことは、去年の7月(2012/7/6)に開催されたDevLOVEでのリーダブルコードのイベントの中でやった「リーダブルコードとはどんなコードかを現実のコードを読みながら考える」ワークショップと同じようなことです。これは楽しかったのですが、1ターンの時間が短かったのが心残りでした。この年の12月にDevLOVE 2012の「リーダブルコードを読んだ後」でも同じようなことをやりたかったのですが、「現実のコードを読みながら」というところまで辿りつけませんでした。

もし、RubyHiroba 2013で5-6人が1-2時間くらい集まれるスペースがあるのならRubyistたちと同じようなことができるのではないかと考えました。ただ、スペースがあるのか、一緒にリーダブルなRubyのコードについて考えたい人たちがいるのかということがわからないため実現できるかどうかわかっていません。

もし、クリアコードの人たちとRubyHiroba 2013で昼過ぎ(やるとしたら13:00-15:00の間)にリーダブルなRubyのコードについて現実のコードを読みながら考えたいという人がいたら@_clear_code宛にツイートしたり、会期中にクリアコードの人に声をかけたりしてください。

6/1 13:30からの発表「Be a library developer!」の内容

RubyKaigi 2013の最終日、2013/6/1の13:30からホールAで「Be a library developer!」というタイトルで須藤が発表します。その内容を紹介します。発表資料は以下の場所にあります。どちらも同じものです。英語で書いてありますが発表は日本語です。

発表前に発表内容を公開すると「聴いたときにおもしろくなくなるからやめたほうがよい」という考えもあるかもしれません。しかし、本当にそうでしょうか。文字と発表資料で伝わることと、発表者の話し方と発表資料で伝わることは違うはずです。

実は、札幌Ruby会議2012での発表のときも発表の少し前に資料を公開していました。発表の後、発表を聴いていた人から「発表の前に資料だけ読んだときはあんまりおもしろくなさそうだと思ったが、聴いたらおもしろかった」という感想をもらいました。このようなこともあるので、「事前に内容を公開する」ということが必ずしも「おもしろさが減る」ということにはつながるとは限りません。むしろ、事前に内容を知ることにより予習ができ、当日、深く理解することができるかもしれません。そのため、RubyKaigi 2013でも事前に発表内容を公開することにします。

もちろん、事前に公開された内容をみて「おもしろくなさそうだから違う発表を聴こう」ということもありえます。残念ですが、それはしょうがありません。違う発表を選んだことを後悔するくらいがんばりましょう。

ということで、「Be a library developer!」の内容です。以下のセクションの内容は発表用の原稿*1を元にしているので書き方が変わります。なお、発表資料と原稿はGitHubに置いてあります。

ライブラリ開発者になろう

このセッションでは、みなさんにライブラリー開発者になって欲しいなぁ、という話をします。私自身、いろいろなライブラリーを開発してきましたが、ライブラリーを開発することで得られたことがたくさんあったなぁと思います。それはみなさんにとっても役に立つことだと思います。これから話すことは私がライブラリーを開発してきて得られたことのエッセンスです。

概要

大まかにいうとこのような順に話します。

まず、1つ例をだしながら今回の話のゴールを説明します。聴いているみなさんと私が設定したゴールを共有できたならここでの話は成功です。

次に、共有したゴールを実現するためにキーとなる考えを説明します。これは、私がいろいろなライブラリーを開発している中で得られた考えです。

その後、いくつかの例に対してキーとなる考えを適用していきます。ここで、キーとなる考えで何をしようとしているかを聴いているみなさんがピンときたら成功です。

これで一通り説明が済んだのでおさらいします。聴いているみなさんが再確認できればいいなぁと思います。

最後に、ライブラリー開発者になった後のことについて少しだけ匂わしておしまいです。

ゴール

それでは、例を出しながら今日の話のゴールを説明します。

まず、今日の話のゴールです。ゴールは「よりよいソフトウェアを開発するための方法をみなさんが知ること」です。このゴールを私と共有できそうですか?私はそのゴールを達成するためにこれから簡単な例をだしながら説明します。みなさんはこの方法は本当によりよいソフトウェアを開発する方法だろうかと自分の経験も踏まえながら考えてください。よりよいソフトウェアとはどんなソフトウェアか、それを開発するにはどうしたらよいかを考えるきっかけになるとうれしいです。

それでは、まずはよりよいソフトウェアとはどんなソフトウェアかを例を見ながら考えてみましょう。どうやって開発するかは、よりよいソフトウェアはどんなソフトウェアかを考えてからです。

こんなAPIがあります。これはrcairoというライブラリーのAPIです。rcairoはcairoというグラフィックスライブラリーのRubyバインディングです。

1
2
3
4
context.save
context.circle(50, 50, 10)
context.stroke
context.restore

saveで現在の描画情報を保存しておいてrestoreでsaveした状態まで戻します。描画情報とはどのように線を書くかとか、線の太さはどのくらいとか、そういうやつです。間にあるcircleとstrokeで円を書いています。

では、これをよりよくするためにはどうしたらよいでしょうか。「よりよい」の基準は人それぞれですが、まずは自分の「よりよい」の基準で考えてみてください。「よりよい」の指針のひとつは後で説明します。

saveとrestoreに注目してみるとどうでしょうか。

ここに注目するとブロックを使った書き方を思いつきます。こちらの方がよりよいAPIです。

1
2
3
4
context.save do
  context.circle(50, 50, 10)
  context.stroke
end

では、どうしてブロックを使ったほうがよりよいAPIなのでしょうか?それは、よりRubyらしい書き方だからです。「Rubyらしい」とはどういうことでしょうか?「○○らしい」とは「他と似ている」ということです。「Rubyらしい」書き方だとまわりのコードと似たような記述になります。つまり、まわりのコードと統一感が出るということです。統一感がでると読みやすくなります。読みやすくなるとメンテナンスが楽になるため開発を継続するためにはよりよいことです。よって、「Rubyらしい書き方」がよりよい基準のひとつです。

では、このブロックの使い方は「Rubyらしい」のでしょうか。Fileクラスを思い出してください。

1
2
3
file = File.open(path) # 前処理
file.read
file.close             # 後処理

Fileクラスではopenでファイルを開きます。これは前処理です。readして使い終わったら閉じています。これは後処理です。

ただ、このように明示的にcloseを書くのはRuby初心者です。Rubyに慣れた人はこのようにブロックを使って書きます。

1
2
3
File.open(path) do |file| # 前処理
  file.read
end                       # 後処理

こうすることの利点は2つです。1つはcloseのし忘れがなくなるということです。もう1つは具体的にどう後処理をしなければいけないかを意識しなくてもよくなるということです。ファイルの場合の後処理はcloseで、Dir.chdirのときは元のディレクトリーに戻る、などと使いわける必要はありません。ブロックを抜けたら「いい感じ」に後処理をしてくれます。これが、Rubyの組み込みライブラリーで使われている後処理のためにブロックを使う方法です。つまり、これと「似た」使い方をすれば「Rubyらしい」ということです。

では、もう一度rcairoの例を見てみましょう。

1
2
3
4
context.save do # 前処理
  context.circle(50, 50, 10)
  context.stroke
end             # 後処理

saveが前処理の部分、ブロックを抜けたところで実行するrestoreは後処理の部分です。Fileと「似た」使い方ですね。ということで「Rubyらしい」といえます。

おさらいします。「よりよい」の基準の1つは「Rubyらしい」ということです。いいかえると「他と似ている」ということです。今日の話のゴールを覚えていますか?「よりよいソフトウェアを開発するための方法をみなさんが知ること」です。いいかえると、「似ているとはどういうことかを知って、それと同じようにすること」です。

私が設定したゴールを共有できましたか?共有できていれば、ここまでの話は成功です。

キーとなる考え

次は、このゴールを実現するためのキーとなる考えを説明します。

キーとなる考えは、「想像するんじゃなくて思い出す」です。

「想像すること」は難しいことです。これはまだ知らないことだからです。

では、「思い出すこと」はどうでしょうか?これは、簡単なことです。すでに知っていることですから。ただし、知っていても忘れてしまうと思い出せません。

では、思い出せるようにするにはどうしたらよいかというと、知ることです。知るためには自分で経験する方法、人から聞く方法、観察して学ぶ方法などがあります。この中でも一番初めにやることは経験してみることです。経験すれば知っているので思い出せるようになります。

ということで、キーとなる考えは「想像するんじゃなくて思い出す」です。

キーとなる考えを適用する

では、このキーとなる考えを適用してみましょう。

まず、このキーとなる考えで実現したいゴールの再確認です。ゴールは「よりよいソフトウェアを開発するための方法をみなさんが知ること」でしたね。

では、このゴールを実現するために何を経験すればいいでしょうか。それは、「Rubyユーザー」としての経験です。これは、すでにみなさん経験していますよね!

では、実際にその経験を活かしてみましょう。

1
2
window.get_property("opacity")
# よりよいAPIは???

これは、Ruby/GTK2というライブラリーのAPIです。Ruby/GTK+はGTK+というGUIツールキットのRubyバインディングです。

windowオブジェクトのopacityプロパティを取得しています。opacityとは透明度ですね。では、これをどうすればよりよいAPIになるか考えてみてください。よりよりAPIとはRubyらしいAPIでしたね。どうすればよりRubyらしいAPIになるでしょうか。

(15秒くらい待つ。)

1
2
window.get_property("opacity")
window.opacity # よりよいAPI

よりよいAPIとしてopacityというメソッドを提供しています。オブジェクトのプロパティを取得するためにプロパティ名のメソッドを使うというのはRubyではよくやる方法なのでRubyらしいです。プロパティを属性といいかえるとわかりやすいかもしれません。Rubyにはattr_readerというそのためのショートカットも用意されています。

ところで、みなさんは、今、よりよいAPIを考えられましたか?「思い出す」って「難しいじゃん」って思いませんでしたか?そう、難しいんです。「思い出せ!?」「Rubyらしいって何!?」そう思ったことでしょう。

すでに知っているはずなのにどうして思い出すことが難しいのでしょう。それは、「想像するんじゃなくて思い出す」という経験をしていないからです。今、みなさんは経験したのではなく、「聞いただけ」という状態です。

それでは、もう一度。ゴールを実現するためには何を経験したらよいのでしょうか。それは、ライブラリー開発者としての経験です。ここでようやくこの話のタイトルがでてきました。

ライブラリー開発者はRubyユーザーとして使いやすいAPIとはどういうAPIだろうと考えたり、ライブラリーのユーザーとしてわかりやすいドキュメントはどんなドキュメントだろう、ということを考えます。他にもいろいろ考えます。そして、これらを何度も何度もたくさん考えます。考える機会がたくさんあるのです。「たくさん」というのはとてもよい練習になります。そのため、「想像するんじゃなくて思い出す」をうまくやるためにはライブラリー開発者になることをオススメします。

それでは、APIとドキュメントの例を考えてみましょう。まずはAPIです。プロパティの値を取得するには以下のようにプロパティ名と同じメソッドを用意するのがRubyらしいのでしたね。

1
2
3
4
# 低レベルなAPI
window.get_property("opacity")
# よりよいAPI
window.opacity

それでは、visibleというプロパティという場合はどうでしょう。ヒントはvisibleは真偽値を返すということです。

1
2
3
4
# 例レベルなAPI
window.get_property("visible")
# よりよいAPIは?
# ???: ヒント: "visible"は真偽値を返す

(15秒くらい待つ)

Rubyらしくするならメソッド名の最後に「?」をつけますね。

1
2
3
4
# 例レベルなAPI
window.get_property("visible")
# よりよいAPI
window.visible?

では、なんでもメソッド名にすればよいのでしょうか?この例ではどうでしょう。

1
2
3
4
# レコードを「コレクション」と考えるならよりよいAPI
record["name"]
# レコードを「オブジェクト」と考えるならよりよいAPI
record.name

ここのrecordはテーブルの中の1つのレコードです。このレコードのカラムの値にアクセスするにはHashのようにアクセスするのとメソッドでアクセスするのはどっちがよいでしょうか?レコードをコレクションと考えるならHashのようにアクセスするのがRubyらしいですし、オブジェクトと考えるならメソッドでアクセスするのがRubyらしいですね。

ドキュメントについても考えてみましょう。

インストール方法:

  Debian GNU/Linuxでは:
    % sudo apt-get install libgtk2.0-dev
    % gem install gtk2
  OS Xでは:
    ...

Ruby/GTK2は拡張ライブラリーなので事前にGTK+というCのライブラリーをインストールしておく必要があります。ユーザーのことを考えるとドキュメントにはその旨を書いておかないと、となります。でも、これでよいのでしょうか?よりよいドキュメントならこうするべきです。

インストール方法:
  % gem install gtk2

gemをインストールするときは「gem install gem名」が普通のやり方です。これがRubyGemsらしさです。普通はこれでインストールするなら、これでインストールできるようにするべきなのです。Ruby/GTK2はgem install gtk2とやったら必要なパッケージを自動でインストールするようにして、インストールドキュメントはgem install gtk2だけにしています。

ということで、実際に「想像するんじゃなくて思い出す」というキーとなる考えを適用してみました。Rubyユーザーとして普通はどうやっているかを「思い出す」、そしてそれと同じようにする、という例を示しました。ピンときましたか?

まとめ

まとめます。この話のゴールは「よりよいソフトウェアを開発するための方法をみなさんが知ること」でした。「よりよい」とは「Rubyらしい」、言い換えると「他と似ている」ということです。これを実現するためのキーとなる考えが「想像するんじゃなくて思い出す」です。なぜなら想像することは知らないので難しく、思い出すことは知っているので簡単だからです。ソフトウェア開発に当てはめてみると、思い出すためにはRubyユーザーとしての経験が必要です。あとはその経験を思い出せばいいのです。しかし、「思い出す」という経験がないので「思い出す」ことが難しいことでしょう。「思い出す」経験をするためにはライブラリー開発者になることをおすすめします。ライブラリーを開発すると何度も何度も「思い出す」必要があり、とてもよい練習になります。という話をしました。

次のステップ

最後にライブラリー開発者になった後の話をして終わりにします。

「ライブラリー開発者」としての経験を他のことにも使ってください。たとえば、他のソフトウェアの開発に使ってください。Rubyでもいいです。他のソフトウェアを開発するときには、よりよいバグレポートはどんなバグレポートだろうとか、よいパッチはどんなパッチだろうとかを「思い出して」ください。例えば、バグレポートなら再現方法があるとうれしいですし、期待する結果もあるとうれしいですね。パッチならわかりやすい単位で分割されているとうれしいですし、適切なコミットメッセージがついているとうれしいですね。ライブラリー開発者としてバグレポートをもらった経験を思い出せばいろいろわかるはずです。

ということで、ライブラリー開発者になりましょう!

参考までに

参考情報

クリアコードというシルバースポンサーな会社はインターンシップへの応募を受け付けています。このインターンシップではクリアコードのメンバーとライブラリーを開発します。よりよいソフトウェアを開発するためのよい経験になるはずなので、ぜひ検討してみてください。

以上が「Be a library developer!」というRubyKaigi 2013の最終日2013/6/1の13:30からホールAでの発表の内容です。直接聴いてみたいという方はぜひ聴きにきてください。この内容を読んで思うところがあった人は会期中に声をかけてください。

ちなみに、須藤のRubyKaigi 2013の会期中の夜の予定はほぼ未定です。思うところがあった人はぜひ声をかけてあげてください!

まとめ

RubyKaigi 2013でのクリアコード関連情報をお知らせしました。それでは、会場で会えることを楽しみにしています!

*1 これまで原稿を用意したことはなかったのですが、RubyKaigi 2013では同時通訳をするということで通訳者の事前資料として役に立つからということで用意しました。

タグ: Ruby
2013-05-28

«前月 最新記事 翌月»
タグ:
年・日ごとに見る
2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|