4年ぶりにインターンシップを開始することを2月にお知らせしました。そこで予告していた通り、4月からインターンシップを実施します。インターンシップをどのように実施するかを3行で説明すると以下の通りです。
詳細はインターンシップページを確認してください。
現時点で紹介している一緒に開発するフリーソフトウェアは以下の通りです。
1つめはJavaScriptやFirefoxに関連した開発になります。2つめはC、Objective-C、GTK+に関連した開発になります。
今回紹介するフリーソフトウェアはRubyやgroongaに関連した開発になります。
これまで紹介したフリーソフトウェアも含めて、ぜひクリアコードの開発方法を体験しながら開発したいと感じた方はインターンシップページにある方法で応募してください。
自分でセットアップしなくてもgroongaを使えたらステキではありませんか?groongaをサービスとして提供する、Groonga as a Service。略してGaaS(ガース)。そんなサービスを実現するためのフリーソフトウェアをインターンシップで開発します*1。
GaaSを使えば、Herokuアドオンとしてgroongaを提供することもできます。夢が広がりますね*2。
GaaSの構想は数年前からありましたが、groonga本体の開発などに注力しており未着手です。しかし、GitHub上にリポジトリを作成済みだったり、どんな構成にするのがよいかをスケッチしたりと実現に向けた準備は進めています。
GaaSは以下の機能を提供します。
一方、以下の機能は提供しません。
このことからGaaSは以下のようなケースで有用です。
シャーディング機能がないためレコード数(データ量)が多いケースには対応できませんが、レコード数がそれほど多くない場合は運用が楽になるため有用です。
GaaSの以下のそれぞれの機能の実現方法案を説明します。まだ作っていないので、実際に作ったらここから大きく方向が変わる可能性があります。
まずは、APIでgroongaサーバーを追加・削除する機能の実現方法案を説明します。
簡単のために、groongaサーバーを追加したい時、空いているサーバーはすでにあるとします*3。問題は初期データをどうするかです。初期データは指定したURLからHTTPでダウンロードすることにします。こうすることで、GaaS側では初期データを管理する必要がなくなります。また、追加するサーバーは常に最新の初期データを参照できるので、どのgroongaサーバーの初期化処理でも手順が同様になりgroongaサーバーの追加が簡単です。
起動時の流れは以下のようになります。
groongaサーバーの削除は、groongaサーバーを終了して関連ファイルを削除するだけです。
APIは作ればよいだけなので省略します。
検索サービスを複数のgroongaサーバーで分担して提供する機能の実現方法案を説明します。
groongaはHTTPサーバーとして検索APIを提供できます。そのため、すでにあるHTTP関連の技術を使うことができます。クライアントからのリクエストを複数のgroongaサーバーに振り分ける機能はリバースプロキシを使って実現できるでしょう。
レプリケーション機能の実現方法案について説明します。
fluent-plugin-groongaを使うことにより、1つのgroongaサーバーで実行した更新処理を他のサーバーでも実行することができます。これによりレプリケーション機能を実現できます。
残る問題は、クライアントからのリクエストが更新リクエストか検索リクエストかを判断する方法です。更新リクエストの場合はfluent-plugin-groongaで処理しなければいけませんが、検索リクエストの場合は別々のgroongaサーバーで処理したいです。これは、以下のような構成にすることで実現可能ではないかと考えています*4。
まず検索時の構成案を示します。
検索時 +--> fluentd -----> groonga クライアント --> リバースプロキシ --+--> fluentd -----> groonga +--> fluentd -----> groonga
検索時は、fluentdは単にデータを中継します。
更新時は、fluentdが更新クエリを全てのgroongaに配布します。以下は、真ん中のfluentdに更新リクエストが飛んだ場合です。同様に、他のfluentdに更新リクエストが飛んだ場合もすべてのgroongaサーバーに変更が反映されます。
更新時 fluentd +--> groonga クライアント --> リバースプロキシ -----> fluentd --+--> groonga fluentd +--> groonga
1つのGaaSシステムで複数のユーザーをホストするためには、他のユーザーのデータが読めないように認証機能が必要です。認証機能はHTTPの仕組みを使えばどうとでもなりそうです。
1つのGaaSシステムで複数のユーザーをホストした場合、1人のユーザーがリソースを使いすぎて他のユーザー用のサービスが提供できなくなることは問題です。そのため、groongaサーバー毎に使用可能なリソース量を制限し、制限を超えた場合は自動で再初期化したり、サービスを停止したりするような仕組みが必要です。GodやBluepillなどリソース監視も備えたプロセス監視システムはいくつかあるので、それらを使用すれば実現できるでしょう。あるいは、単に、ulimitとプロセス監視システムの組合せでもよいかもしれません。
groongaサーバーで更新されたデータをリアルタイムでバックアップするAPIがあれば、初期データを随時更新して、groongaサーバーを追加した時に使う初期データを最新のデータにしておくことができます。
GaaSのレプリケーション機能はfluent-plugin-groongaで実現するので、fluentdのcopy outputプラグインとforward outputプラグイン機能を使ってこの機能を実現できます。
groongaをサービスとして提供する仕組みGaaS(Groonga as a Service。ガース。)の構想とそれの実現方法案を紹介しました。
GaaSを一緒に開発しながらクリアコードの開発方法を体験したいという方はインターンシップページを確認の上、応募してください。
他のインターンシップ対象のフリーソフトウェアを再掲します。
*1 ここでは「GaaS」という単語をgroongaの機能を提供するサービスおよびそのサービスを実現するソフトウェアの両方を示すものとして使っています。サービスだけを提供するのではなく、サービスを提供するソフトウェアも提供することで、自分の環境にサービスを構築することもできるようにします。データを外部に出したくない場合でも使えるようになります。
*2 groongaをHerokuアドオンとして提供することに(インターンシップとは関係なく)興味のある方はお問い合わせフォームからご連絡ください。一緒に実現させましょう。
*3 Amazon EC2などを使えば追加したい時に動的にサーバーを追加することはできるので、このあたりはそんなに困らないはず。groongaサーバーを設定するためのChefのcookbookを作っていたりします。
*4 要検討
おととしに引き続き、クリアコードは今年もRubyKaigi 2013のスポンサーになりました。
また、須藤と沖元は発表者として参加する予定なので、会場で見かけたら声でもかけてください。
YARDというRuby用のドキュメンテーションツールがあります。以前、Cで記述したRubyの拡張ライブラリにYARD用のドキュメントを書く方法を説明しました。今回は、Rubyで定義したメソッドの引数についてYARD用のドキュメントを書く方法を説明します。
引数を対象とする理由は、引数のドキュメントを書く機会が多いからです。ライブラリのドキュメントは、メソッドについて書くことがほとんどです。メソッドには引数があることが多いため、引数の説明を書く機会が多いのです。
この記事では、まず、YARDで使う記法について説明します。その後、引数についてのドキュメントを書くための@param
タグについて説明し、実際にRubyのコードにドキュメントを書いていきます。ドキュメントを書くごとにHTMLを生成して、@param
タグで書いたドキュメントがどのように表示されるかを確認します。
まず、YARDでドキュメントを書くときに使う記法を説明します。
YARDには「タグ」と「ディレクティブ」という2つの記法があります。このタグとディレクティブを使って、コメントとしてドキュメントを書きます*1。タグとディレクティブは、それぞれ次のように使います。
記法 | 使い方 |
---|---|
タグ | コードに関するメタデータを埋め込む |
ディレクティブ | ドキュメントの内容そのものを操作する |
タグとディレクティブの詳細は公式のドキュメント(英語)に詳しく書かれているので、興味のある方はこちらをご覧ください。引数についてドキュメントを書くには、たくさんあるタグのうち@param
タグを利用します。それでは、この@param
タグについて説明します。
@param
タグ@param
タグは「引数」というメタデータを埋め込むためのタグです。引数がどんなクラスのオブジェクトであることを期待しているか(以降、「引数のクラス」と呼ぶ)や、引数の説明を文章で書くために使います。1つの引数につき1つの@param
タグを書きます。引数が複数ある場合は複数の@param
タグを書きます。
@param
タグの書式は以下の通りです。
@param 引数名 [引数のクラス] 説明
どこにどのように書けばよいかなど、実際の使い方は後ほど説明します。その前に、@param
タグの使い方を示すために使うサンプルコードを示します。このコードに対して@param
タグでドキュメントを書いていきます。
以下にRubyのコードを示します。このコードに対してドキュメントを書いていきます。
このコードはextract_overage
メソッドを定義しています。extract_overage
メソッドは、配列と数値を引数にとり、各要素から数値より大きい数(数値が指定されない場合は20より大きい数)を集めた配列を返します。例えば、extract_overage([17, 43, 40, 56], 40)
を実行すると、[43, 56]
を返します。
1 2 3 4 5 6 7 |
# Returns Array containing numbers exceeding limit_age. # For example, extract_overage([17, 43, 40, 56], 40) #=> [43, 56] def extract_overage(ages, limit_age=20) ages.select do |number| number > limit_age end end |
このコードを、以降、「サンプルコード」と呼びます。
サンプルコードで定義しているextract_overage
メソッドのコメントに、メソッドの説明を書いておきました*2。ただし、引数についての説明は書いていません。引数についての説明はこのあと@param
タグで書いていきます。
なお、YARDはメソッド定義の直前のコメントに書いている内容をメソッド全体の説明として扱います。それを確かめるために、サンプルコードからHTMLのリファレンスマニュアルを生成してみましょう。サンプルコードをexample.rbというファイルに保存して、次のコマンドを実行することで、HTMLのリファレンスマニュアルを生成できます。
$ yardoc example.rb
生成されたリファレンスマニュアルは以下のようになります。
図の赤枠の部分を見ると、コメントに書いた説明がメソッド全体の説明としてextract_overage
メソッドのところに表示されています。また、緑色の枠の部分には、メソッド全体の説明の1行目がサマリーとして表示されています。
@param
タグの使い方それでは、@param
タグで引数のドキュメントを書きましょう。ここからは、サンプルコード内のextract_overage
メソッドの中身を省略します。これは、ドキュメントを書く場所をわかりやすくするためです。メソッドの中身を省略すると以下のようになります。
1 2 3 4 |
# Returns Array containing number exceeding limit_age. # For example, extract_overage([17, 43, 40, 56], 40) #=> [43, 56] def extract_overage(ages, limit_age=20) end |
ではまず、1つ目の引数であるages
についてのドキュメントを書きます。@param
タグの書式を再掲します。
@param 引数名 [引数のクラス] 説明
1つ目の引数ages
について記述するので、引数名はages
、 引数のクラスはArray
となります。説明は「numbers checked if they exceeded from limit_age.」となります。
次に、@param
タグを書く場所を説明します。@param
タグは、メソッド全体の説明と同じく、メソッド定義の直前のコメントに書きます。メソッド全体の説明の下に空のコメント行を1行入れ、その下に書くとよいでしょう。このように書くと、コードに書かれたドキュメントを読むときに理解しやすくなります*3。この順序でドキュメントを書くと、ドキュメントを読む人はメソッド全体の説明を読んでから個々の引数の説明を読めるからです。全体を把握してから細部を見る、という順序で読むことができ、メソッドを理解しやすくなります。
それでは、@param
タグで引数ages
の説明を書きます。
1 2 3 4 5 6 |
# Returns Array containing numbers exceeding limit_age. # For example, extract_overage([17, 43, 40, 56], 40) #=> [43, 56] # # @param ages [Array] numbers checked if they exceeded from limit_age. def extract_overage(ages, limit_age=20) end |
上記のコードからHTMLのリファレンスを生成すると次のようになります。図の赤枠のところが今回追加された説明です。
引数ages
についての説明が追加されています。
次に2つ目の引数のlimit_age
についても同じように書いていきましょう。
1つの@param
タグで1つの引数の説明を書きます。引数が複数ある場合はその数だけ@param
タグを使います。コメントに書かれたドキュメントを読むときには、似たような情報がまとまっていた方が読みやすいので、引数のドキュメントは並べて書くのがよいでしょう。
1つめの引数から順番にドキュメントを書くとメソッド定義と対応がとりやすくなるので理解しやすくなります。これはコードに書かれたドキュメントを読むときもHTMLのリファレンスマニュアルを詠むときも同様です。HTMLのリファレンスマニュアルでは、同じタグ(ここでは@param
タグ)は書かれた順番に表示されるからです。
では、引数limit_age
についてのドキュメントを書きます。
1 2 3 4 5 6 7 8 |
# Returns Array containing numbers exceeding limit_age. # For example, extract_overage([17, 43, 40, 56], 40) #=> [43, 56] # # @param ages [Array] numbers checked if they exceeded from limit_age. # @param limit_age [Integer] limit_age limit used to extract # bigger ages than it. def extract_overage(ages, limit_age=20) end |
追加した@param
タグでは、説明の文章を折り返しています。# bigger ...
の行です。@param
タグで書くドキュメントを途中で折り返すときは、@param
タグの開始行よりもインデントしてください。インデントすると、YARDはインデントされた行を前の行の継続行として扱います。
それでは、上記のコードからHTMLのリファレンスを生成しましょう。次のようになります。図の赤枠のところが今回追加した説明です。
limit_age
についての説明が追加されています。折り返された説明は1つの文として扱われています。
extract_overage
メソッドを呼び出すときに引数limit_age
を省略すると自動的に20
がデフォルト値として使用されますが、HTMLのリファレンスマニュアルにはそのことが(default to: 20)
として表示されています。これは、YARDがメソッド定義から判断して表示しています。そのため、明示的にドキュメントに書かなくてもデフォルト値が表示されます。
ここでは以下のことを説明しました。
今回は、Rubyで定義したメソッドの引数にYARD用のドキュメントを書く方法を説明しました。ドキュメントを書くことで、ユーザーがソフトウェアを使いやすくなります。それだけではなく、開発者としてもよいソフトウェアを書くのに役立つのでドキュメントを書いてみてはいかがでしょうか。
次回は、@return
タグを使って戻り値についてドキュメントを書く方法を説明する予定です。
*1 これはCで記述したRubyのライブラリにYARD用のドキュメントを書く場合と同じです。
*2 ここではあえてタグを使っていません。理由は@param
タグに注目してもらうためです。
*3 HTMLのリファレンスマニュアルを生成するときには関係ありません。
今回は、Fedoraプロジェクトで新規パッケージをリリースする方法を、Cutterをリリースしたときの経験をもとに紹介します。
Cutterプロジェクトでは、従来はFedora向けに独自にリポジトリを用意してRPMを提供していました。しかし、この方法では、ユーザーがCutterをインストールするときにリポジトリを追加登録する手間がかかり、不便でした。 そこで、FedoraでCutterを利用したいユーザーがもっと簡単に導入できるように、FedoraプロジェクトからRPMを提供するようにしました*1。
新規パッケージの公開までの流れについては、Join the package collection maintainersに詳細がまとめられています。
このドキュメントは日本語訳もあります。 ところどころ内容が最新版に追従していませんが、参考としては十分です。
まずはじっくり上記ドキュメントを読まれることをお勧めしますが、簡単に紹介すると以下のようになります。
それでは、順を追って説明していきます。
まずはRed Hat Bugzillaのアカウントを取得します。
BugzillaのアカウントはNew Accountのリンクから作成します。
このアカウントは後述するレビューリクエストを行うときに必要になります。
Fedoraプロジェクトでパッケージをメンテナンスするためには、FASアカウントと呼ばれるメンテナンスのためのアカウントが必要です。
FASアカウントはFedora Account SystemにアクセスしNew Accountのリンクから作成します。
このアカウントはレビューリクエストを行う際や、レビューリクエストが承認されたあとのパッケージのインポートやコミット等のリポジトリ関連の作業に使います。
FASアカウントを登録したら、Contributors License Agreement(貢献者ライセンス同意書、以下CLA)に同意する必要があります。
同じくFASアカウントでログインした状態から complete the CLA のリンクをたどり、ライセンスを読んだうえで、同意します。
詳しくは1.5. CLA に署名するを参照してください。
CLAに同意すると、図の状態になります。
FASアカウントを登録したら、ログイン後、"My Account"メニューよりSSHの公開鍵を登録します。
ここで登録した鍵を用いて後述するfedorapeople.orgやリポジトリへとアクセスします。
後々の便利のために、~/.ssh/configに以下の設定を追加しておくと良いでしょう(IdentityFile ~/.ssh/id_rsa.fedora.pkeyの設定は個々の環境で読み替えてください)。
HOST *.fedoraproject.org fedorapeople.org *.fedorahosted.org IdentityFile ~/.ssh/id_rsa.fedora.pkey
これは必須ではありませんが、他のパッケージのレビューを見ることで、パッケージング作業についてより深く学べます。
他にもいくつか参考になるメーリングリストが存在します。 必要に応じて参加すると良いでしょう。
メーリングリスト | 説明 |
---|---|
devel-announce | アナウンス向けのメーリングリスト。流量が少ない。最近だとFedora 19のAlphaフリーズのアナウンスが流れた。 |
devel | 開発者向けのメーリングリスト。流量が多い。 |
package-announce | パッケージのリリースアナウンス向けのメーリングリスト。パッケージがstable入りしたのを知るために登録する。 |
新規パッケージを登録するためには、レビューというプロセスを経る必要があります。 レビューをしてもらうには以下の情報が必要です。
specファイルやSRPMファイルの場所は一般にアクセス可能な場所であれば、どこでも構いません。
Cutterの場合はSourceforge.netを利用していたので、一時ディレクトリを用意して、そこにファイルをアップロードしていました。
レビューリクエストを行うまえに、あらかじめパッケージに問題がないか確認する方法をいくつか紹介します。
パッケージに問題がないか確認する最もシンプルな方法です。
$ rpmlint -i *.rpm
パッケージのレビューに関してはReviewGuidelinesというドキュメントがあります。 このドキュメントには、レビュワーがしなければいけないことの1つとして「rpmlintの実行」が記載されています。
あらかじめrpmlintで報告されている警告やエラーを潰しておくと、レビューしてもらうときの余計なやりとりを減らすことができます*2。
Fedoraプロジェクト向けにRPMパッケージをビルドするシステムとしてKojiがあります。
Kojiを使うと複数のリリースもしくは複数のアーキテクチャ向けにRPMパッケージのビルドがうまくいくか確認することができます*3。
Kojiを使うにはいくつかセットアップが必要です。
Kojiについての詳細はUsing the Koji build systemを参照してください。
まずはfedora-packagerをインストールします。
$ sudo yum install fedora-packager
次にfedora-packager-setupを実行します。このとき、FASアカウントの入力が必要です。 また、ブラウザ向けのクライアント証明書のパスワードの入力も必要です。
$ fedora-packager-setup Setting up Fedora packager environment You need a client certificate from the Fedora Account System, lets get one now FAS Username: kenhys FAS Password: Saved: /home/kenhys/.fedora-server-ca.cert Linking: ~/.fedora-server-ca.cert to ~/.fedora-upload-ca.cert Setting up Browser Certificates Enter Export Password: Verifying - Enter Export Password: Browser certificate exported to ~/fedora-browser-cert.p12 To import the certificate into Firefox: Edit -> Preferences -> Advanced Click "View Certificates" On "Your Certificates" tab, click "Import" Select ~/fedora-browser-cert.p12 Type the export passphrase you chose earlier Once imported, you should see a certificate named "Fedora Project". Your username should appear underneath this. You should now be able to click the "login" link at http://koji.fedoraproject.org/koji/ successfully. importing the certificate is optional and not needed for daily use. you should also import the ca cert at ~/.fedora-upload-ca.cert
パスワードを入力し終わると処理が進みます。
fedora-packager-setupコマンドは以下の4つのファイルをホームディレクトリへと保存します*4。
この手順は通常一度だけ必要です*5。
これで、Kojiを使う準備が整いました。
Kojiを使ってビルドを試すには、以下の様に--scratchオプションを与えてkojiコマンドを実行します。
$ koji build --scratch f18 cutter-1.2.2-4.fc18.src.rpm
KojiでのビルドはすべてFedoraプロジェクトのビルドサーバーで行うので、他のビルドとの兼ね合いからビルドが完了するまでそれなりに時間がかかります。
依存関係などが適切に処理されているかについてはMockによるビルドを行うことで確認できます。
KojiもMockを使って実現しています。
Mockではローカルにchroot環境を構築してRPMをビルドするようになっています。
常用しているFedoraの環境とは異なりクリーンな環境でビルドを行うため、依存関係の抜け等をチェックすることができます*6。
Mockを使うにはいくつかセットアップが必要です。
まずはmockグループに作業ユーザ(任意)を追加します。この作業は初回のみ必要です。
$ sudo usermod -a -G mock (作業ユーザーアカウント)
次にmock環境を初期化します。この作業はビルドを試したい環境ごとに行う必要があります。
$ mock -r fedora-18-x86_64 --init
最後にmockの特定環境でビルドするには以下のコマンドを実行します。
$ mock -r fedora-18-x86_64 --no-clean cutter-1.2.2-4.fc18.src.rpm
mockコマンドはビルド結果のログを以下に生成します。また、ビルドしたRPMも同じ階層に保存します。
/var/lib/mock/fedora-18-x86_64/result/build.log
Mockの詳細についてはUsing Mock to test package buildsを参照してください。
fedora-reviewという専用のツールを使って確認することもできます。 以下のようにしてインストールします。
$ sudo yum install fedora-review
fedora-reviewはレビュワー向けのツールなので、パッケージに関するより細かいレポート結果を得ることができます。 ローカル環境で実行するには以下のようにSRPMを指定します。
$ fedora-review --rpm-spec --name cutter-1.2.2-4.fc18.src.rpm
実行が終了すると、fedora-reviewコマンドは(パッケージ名)/review.txtを生成します。 review.txtの内容は以下のように、チェックする項目とその結果を含んでいます。
Package Review ============== Key: [x] = Pass [!] = Fail [-] = Not applicable [?] = Not evaluated [ ] = Manual review needed Issues: ======= - Package do not use a name that already exist Note: A package already exist with this name, please check https://admin.fedoraproject.org/pkgdb/acls/name/cutter See: https://fedoraproject.org/wiki/Packaging/NamingGuidelines#Conflicting_Package_Names ===== MUST items ===== C/C++: [ ]: Package does not contain kernel modules. [ ]: Package contains no static executables. [ ]: Development (unversioned) .so files in -devel subpackage, if present. Note: Unversioned so-files in private %_libdir subdirectory (see attachment). Verify they are not in ld path. [x]: Header files in -devel subpackage, if present. [x]: ldconfig called in %post and %postun if required. [x]: Package does not contain any libtool archives (.la) [x]: Rpath absent or only used for internal libs. Generic: [ ]: Package is licensed with an open-source compatible license and meets other legal requirements as defined in the legal section of Packaging 以下省略
Join the package collection maintainersでは、Upload Your Packageというセクションで、specやSRPMのアップロード先としてfedorapeople.orgを紹介しています。 しかし、最初のレビューリクエストを投稿する時点では、fedorapeople.orgへファイルをアップロードする権限がありません。
fedorapeople.orgへのアクセスするには、自分のFASアカウントを後述するpackagerグループに追加してもらう必要がありますが、これはパッケージのレビューが承認された後になるからです。
そのため、この時点ではどこか他の場所にspecやSPRMをアップロードして、レビューしてもらえる状態にする必要があります。
specファイルとSRPMファイルが用意できたら、Bugzillaへレビューリクエストを投稿します。
レビューを投稿するときの雛形は、専用の入力フォームとしてfedora-reviewがあります。
Spec URL: <spec info here> SRPM URL: <srpm info here> Description: <description here> Fedora Account System Username:
Cutterの場合は以下のようなレビューリクエストを投稿しました。
Spec URL: http://sourceforge.net/projects/cutter/files/tmp/cutter.spec SRPM URL: http://sourceforge.net/projects/cutter/files/tmp/cutter-1.2.2-1.fc17.src.rpm Description: Cutter is a xUnit family Unit Testing Framework for C. Cutter provides easy to write test and easy to debug code environment. Fedora Account System Username: kenhys
レビューリクエストを行う際には、以下の点に注意する必要があります。
新規パッケージを投稿するときには、FE-NEEDSPONSORフラグを設定しなければなりません。
これはパッケージのメンテナンスの権限を有するpackagerグループのうち、より高度な権限を持つsponsorという権限を持っている人にレビューをしてもらう必要があることを示します。
FE-NEEDSPONSORフラグは、レビューリクエストの左側にあるBlocks:という項目を編集します。
fedora-reviewフラグを設定するには、レビューリクエストのFlags:という項目を編集します。
Flags:は登録したレビューリクエスト画面の右側に項目があります。
Flags:の隣りの(edit)をクリックするといくつかプルダウンが表示されます。
このうち、fedora-reviewという項目があるので、プルダウンから?を選択して更新します。 fedora-reviewに設定できる値とその意味は以下の通りです。
fedora-reviewフラグ | 説明 |
---|---|
? | レビューリクエスト中 |
+ | レビューが承認された |
- | レビューが却下された |
FE-NEEDSPONSORが設定されているレビューリクエストのみを一覧で参照することもできます。
レビューリクエストを投げたものの、それがそのまますんなり通るとは限りません。
Cutterの場合もレビューリクエストを最初に投げてから何度かspec記述上の問題点をレビュワーに指摘され、修正するというサイクルを繰り返しました。
レビュワーは、指摘事項の根拠となるドキュメントを示しながら、問題点をどう修正すべきかをコメントしてくれます。
例えば、Cutterの場合だと、指摘された問題点の一つにBuildRoot:タグを指定していたというものがありました。
> BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%(%{__id_u} -n) https://fedoraproject.org/wiki/Packaging:Guidelines#BuildRoot_tag The "fedora-review" tool complains about this tag, too.
すべての指摘事項を修正し、レビューを通ると以下の状態になります。
packagerグループに入るとFedoraのサーバーへアクセスできるようになります*7。
fedora-reviewフラグが+になったら、次のステップ「SCMリクエスト」に進みます。
パッケージのレビューが通ったら次にやることは、新規パッケージのためにリポジトリを用意することです。
リポジトリについては、レビューリクエストのバグのコメントにSCMリクエストと呼ばれる作業依頼のコメントを投稿します。
Cutterの場合は以下のようなSCMリクエストを行いました。
New Package SCM Request ======================= Package Name: cutter Short Description: Unit Testing Framework for C/C++ Owners: kenhys Branches: f18 InitialCC:
SCMリクエストを行ったあとは、しばらく待つ必要があります。 Cutterの場合は一日程度でした。 リポジトリを作成する権限のある人が、定期的にSCMリクエストをチェックし、順次対応してくれているようです。
SCMリクエストが処理され、リポジトリの準備が完了すると、レビューリクエストに以下のようなコメントが書き込まれます。
Git done (by process-git-requests).
またfedora-cvs granted:という件名で、通知メールがあらかじめ登録しておいたアカウントに届きます。
これで、specとSRPMをコミットするためのリポジトリが準備できました。
次のステップ「パッケージのインポート」へと進みます。
これ以降の作業(「パッケージのインポート」から「パッケージのアップデート」まで)は、master(rawhide)*8とSCMリクエストで指定したブランチごとにくりかえす必要があります。
作業しているブランチによって一部手順が異なりますが、詳細については「ブランチごとの作業まとめ」として後述します。
パッケージのインポートでは以下の作業が必要です。
以下、順に説明していきます。
レビューが通った後、レビュワーによりpackagerグループに追加してもらえます。 packagerグループに所属しているとFedoraのサーバーへとアクセスすることができます。
packagerグループに所属しているかどうかは、FASの"My Account"メニューを表示したときに表示される所属グループリストの"Fedora Packager Git Commit Group"でわかります。ここのStatus欄が"Approved"になっていると、packagerグループに所属していることになります。
以降の作業ではサーバーへのアクセスをともなうので、FASアカウントを作成したときに用意した秘密鍵を用いて、SSHでログインできるか確認します。
$ ssh-add 秘密鍵のファイルパス $ ssh -vvv -l (FASアカウント名) fedorapeople.org
SSHアクセスに成功したら、実際にパッケージのインポートを順に行っていきます。
Fedoraプロジェクトではパッケージのビルドやアップロードなどのメンテナンス作業にfedpkgというコマンドを使います。
fedpkgコマンドを使うには、あらかじめfedpkgパッケージをインストールする必要があります。
前述のKojiによるビルド確認を試している場合は、fedora-packagerのインストール時に、既に(パッケージの依存関係により)fedpkgをインストールしているはずです。 そうでない場合には以下の手順でインストールします。
$ sudo yum install fedpkg
fedpkgのインストールが完了したら、次のステップ「リポジトリのclone」に進みます。
まずは作業用のリポジトリをcloneします。 作業用のディレクトリを用意して、そこにcloneするのが良いでしょう。
$ fedpkg clone (パッケージ名)
上記コマンドを実行することでリポジトリをcloneすることができます。
Cutterの場合は以下のように作業ディレクトリを用意してcloneしました。
$ mkdir -p $HOME/work/fedora-scm $ cd $HOME/work/fedora-scm $ fedpkg clone cutter $ cd cutter
リポジトリのcloneができたら、SRPMを以下のコマンドにてインポートします。
$ fedpkg import (SRPMのパス)
fedpkg importコマンドは、SRPMからspecファイルやパッチ、ソースアーカイブを抽出し、作業ディレクトリへと展開します。 また、.gitignoreやハッシュ値を書きこんだsourcesファイルも生成します。
Cutterの場合は以下のようになりました。
$ ls -1 cutter-1.2.2.tar.gz cutter-configure-gtk-debug-detection.diff cutter-test-use-upper-case-gdk-literal.diff cutter.spec sources
ここまでで、パッケージのインポートが完了しました。
次のステップ「パッケージのコミット」へと進みます。
パッケージのインポートが完了したら、差分(新規追加)を確認した上でコミットします。 また、pushしてローカルのコミット内容をアップストリームへと反映します。
$ git commit -m "Initial import (#XXXXXX)." $ git push
pushが完了したら、次のステップ「パッケージのビルド」へと進みます。
パッケージのビルドを行うにはfedpkg buildを実行します。
CutterでFedora 18ブランチ向けにビルドしたときは、以下のようになりました*9。
$ fedpkg build Building cutter-1.2.2-4.fc18 for f18-candidate Created task: 4941489 Task info: http://koji.fedoraproject.org/koji/taskinfo?taskID=4941489 Watching tasks (this may be safely interrupted)... 4941489 build (f18-candidate, /cutter:5978273caa55d3d45ed8e760efc15919b6133ab9): free 4941489 build (f18-candidate, /cutter:5978273caa55d3d45ed8e760efc15919b6133ab9): free -> open (buildvm-17.phx2.fedoraproject.org) 4941490 buildSRPMFromSCM (/cutter:5978273caa55d3d45ed8e760efc15919b6133ab9): free 4941490 buildSRPMFromSCM (/cutter:5978273caa55d3d45ed8e760efc15919b6133ab9): free -> open (buildvm-16.phx2.fedoraproject.org) 4941490 buildSRPMFromSCM (/cutter:5978273caa55d3d45ed8e760efc15919b6133ab9): open (buildvm-16.phx2.fedoraproject.org) -> closed 0 free 1 open 1 done 0 failed 4941492 buildArch (cutter-1.2.2-4.fc18.src.rpm, i686): free 4941491 buildArch (cutter-1.2.2-4.fc18.src.rpm, x86_64): open (buildvm-18.phx2.fedoraproject.org) 4941492 buildArch (cutter-1.2.2-4.fc18.src.rpm, i686): free -> open (buildvm-07.phx2.fedoraproject.org) 4941492 buildArch (cutter-1.2.2-4.fc18.src.rpm, i686): open (buildvm-07.phx2.fedoraproject.org) -> closed 0 free 2 open 2 done 0 failed 4941491 buildArch (cutter-1.2.2-4.fc18.src.rpm, x86_64): open (buildvm-18.phx2.fedoraproject.org) -> closed 0 free 1 open 3 done 0 failed 4941510 tagBuild (noarch): free 4941510 tagBuild (noarch): free -> open (buildvm-21.phx2.fedoraproject.org) 4941510 tagBuild (noarch): open (buildvm-21.phx2.fedoraproject.org) -> closed 0 free 1 open 4 done 0 failed 4941489 build (f18-candidate, /cutter:5978273caa55d3d45ed8e760efc15919b6133ab9): open (buildvm-17.phx2.fedoraproject.org) -> closed 0 free 0 open 5 done 0 failed 4941489 build (f18-candidate, /cutter:5978273caa55d3d45ed8e760efc15919b6133ab9) completed successfully
ビルドが成功したので、次のステップ「パッケージのアップデート」へと進みます。
Fedoraプロジェクトではパッケージの追加/更新/削除やパッケージの公開・管理を行うためのシステムとしてBohdiを使っています。
BohdiはビルドしたパッケージをFedora ユーザーが参照するyumリポジトリへと反映します。
Bohdiへビルドしたパッケージを反映させるには、パッケージのアップデートを行います。
パッケージのアップデートをするには以下のコマンドを実行します。
$ fedpkg update
fedpkg updateを実行するとエディタが起動するので、アップデートに関する項目を編集します。 何のパッケージの、どんな更新なのかといったメタ情報を記述します。
必須なのはtypeで、新規パッケージの場合にはnewpackageを指定します。
Cutterの場合は以下のようにしました。
[ cutter-1.2.2-4.fc18 ] # bugfix, security, enhancement, newpackage (required) type=newpackage # testing, stable request=testing # Bug numbers: 1234,9876 bugs=887778 # Description of your update notes=Unit Testing Framework for C/C++ # Enable request automation based on the stable/unstable karma thresholds autokarma=True stable_karma=3 unstable_karma=-3 # Automatically close bugs when this marked as stable close_bugs=True # Suggest that users restart after update suggest_reboot=False
編集結果を保存するとfedpkg updateコマンドがその内容をBohdiへと送ります。
Creating a new update for cutter-1.2.2-4.fc18 Password for kenhys: Creating a new update for cutter-1.2.2-4.fc18 Update successfully created ================================================================================ cutter-1.2.2-4.fc18 ================================================================================ Release: Fedora 18 Status: pending Type: newpackage Karma: 0 Request: testing Bugs: 887778 - Review Request: cutter - A Unit Testing Framework for C Notes: Unit Testing Framework for C/C++ Submitter: kenhys Submitted: 2013-02-09 10:07:19 Comments: bodhi - 2013-02-09 10:07:47 (karma 0) This update has been submitted for testing by kenhys. https://admin.fedoraproject.org/updates/cutter-1.2.2-4.fc18
「パッケージのインポート」から「パッケージのアップデート」までは作業しているブランチごとに繰り返す必要があります。 ただし、作業ブランチによっては、やるべきこと、やらなくていいことがあります。
そこで、ここまでの作業手順を一旦まとめます。Cutterの場合には(当時Fedora 19ブランチはなかったので)、masterブランチとFedora 18ブランチについて作業しました。
作業 | masterブランチ | Fedora 18ブランチ |
---|---|---|
パッケージのインポート | 必要 | SRPMのインポートは不要。代わりにmasterブランチからマージする。 |
パッケージのコミット | 必要 | 必要(pushのみ) |
パッケージのビルド | 必要 | 必要 |
パッケージのアップデート | 不要 | 必要 |
パッケージのテスト | 不要 | 必要 |
パッケージのリリース | 不要 | 必要 |
まず、masterブランチ向けに「パッケージのインポート」から「パッケージビルド」まで行いました。 次にfedpkg switch-branch f18でFedora 18のブランチに切り替え、masterブランチからマージした後、パッケージのリリースまで行いました。
上記を具体的な実行コマンド列で比較すると以下のようになります。
masterブランチの場合
$ git import (SRPMのパス) $ git commit $ git push $ fedpkg build
Fedora 18ブランチの場合
$ fedpkg switch-branch f18 $ git merge master $ git push $ fedpkg build $ fedpkg update
Fedora 18ブランチの手順では以下のことを行っています。
ここまでの作業がブランチごとに完了したら、次のステップ「パッケージのテスト」へと進みます。
fedpkg updateでBohdiへとパッケージを更新するようにしむけても、それで終わりではありません。
投稿したRPMパッケージが一般ユーザーが利用しているyumリポジトリへと反映されるまでには、いくつかの段階があります。
Bohdiのステータス | 説明 |
---|---|
pending | リポジトリ反映前 |
testing | testingリポジトリへ反映されている |
stable | 一般ユーザーが利用するyumリポジトリへ反映されている |
RPMパッケージは一旦キューに入れられるのでpending状態になり、その後testingリポジトリ*10へと反映されます。
そしてtestingリポジトリで一定評価を得たパッケージがstable*11に入る仕組みになっています。
その際の評価はKarmaと呼ばれる仕組みによって行います。
Bohdiにアカウントを有しているユーザーは、Webインターフェースからパッケージに対するコメントをすることができます。 コメントするときには、あわせてパッケージを評価することができます。 この評価欄の集計がKarmaです。
ユーザーがパッケージに対してコメントするときに 「Works for me」にチェックを入れると+1となり、「Does not work」にチェックを入れると-1の評価となります。
デフォルトのKarmaは0からスタートします。 BohdiはKarmaが+3になったパッケージをstableリポジトリへと反映し、逆に-3に達したパッケージをtestingリポジトリから削除します。
このKarmaの閾値についてはfedpkg update実行時にその都度メタ情報として設定できます*12。
この仕組みの詳細については、QA:Updates Testingを参照してください。
一定評価(stable_karma)を得られたパッケージは、Bohdiが自動的に一般ユーザーが利用するyumリポジトリ(stableリポジトリ)へと反映します。
一定評価を得られていないパッケージであっても、一定期間(2週間程度)経過すると、手動操作でyumリポジトリへと反映することができます。
その場合は、パッケージをアップロードした人がBohdiのインターフェースから作業します。 該当パッケージの情報ページで「Mark as stable」をクリックするとyumリポジトリへ反映することができます。
新規パッケージをリリースするまでに必要な情報については、すでにFedoraプロジェクトによって文書化されています。 また、一部には日本語訳も用意されています。
ただし、実際にやってみないことにはわからないこともあります。
そこで今回は具体例をもとに実際にパッケージをリリースするところまでの流れを紹介しました。
フリーソフトウェアの開発元がかならずしも使っているディストリビューション向けにRPMパッケージを提供してくれるとは限りません。
ソースアーカイブからRPMを作成してくれるcheckinstallなどもあるので、手元の環境ではRPM化して管理しているという人もいるかも知れません。
しかし、自作RPMパッケージを手元でだけ管理している状態では、他の人もRPM化して管理したい場合には、また同様の手順を踏むことになります。 自分は問題を解決したけど、また再度同じ問題にぶつかる人がいるという状況に変化はありません。
成果物については手元の環境だけで眠らせておかずにディストリビューションへと還元するのをおすすめします。
今回は、新規にパッケージを登録するところまでを書きました。 パッケージは登録して終わりではありません。継続してメンテナンスしていくことも重要です。
既存パッケージを更新する方法については、またの機会に記事にしたいと思います。
*1 1.2.2をリリースして以降。
*2 rpmlintによりスペルミスとして警告されていても、固有名詞のため問題ない場合もあります。また、rpmlintはそれぞれのRPM単位でのチェックのため、メインパッケージに含まれていれば良いライセンス類がサブパッケージに含まれていないと警告として扱われたりします。
*3 例えば現在リリースされているFedora 18だけではなく、リリース前のFedora 19などでもビルド確認が行えます。
*4 fedora-browser-cert.p12についてはブラウザ経由でKojiへアクセスするときに必要です。セットアップ手順は上記のメッセージの通り証明書のインポートを行います。
*5 証明書の有効期限が切れたら更新する必要はあります。
*6 BuildRequires:の指定が抜けているなど。
*7 例えば、fedorapeople.orgに割り当てられたディスク領域を使うことができます。次回以降のレビューリクエストを行うときはこちらにspecファイルとSRPMを置くと良いでしょう。
*8 RawhideはFedoraの開発版を意味し、masterブランチのことです。
*9 masterブランチのビルドのときのログが残っていなかったのでFedora 18向けにビルドしたときのログです。
*10 testingリポジトリは、テスター向けのリポジトリです。標準では有効になっていないので、testingリポジトリのパッケージを実際にインストールするには別途有効にする必要があります。
*11 一般ユーザーが利用するyumリポジトリ
*12 stableリポジトリへ反映される基準値はstable_karmaで、削除される基準値はunstable_karmaで設定できます。それぞれデフォルト値は3と-3です。
YARDというRuby用のドキュメンテーションツールがあります。これまでに2回、YARD用のドキュメントの書き方についてククログで紹介しました。
今回は前回の「Rubyで定義したメソッドの引数についてのドキュメントをYARD用に書く方法」という記事の続きで、Rubyで定義したメソッドに戻り値のYARD用ドキュメントを書く方法を紹介します。
まず、戻り値のYARD用ドキュメントを書くための@return
タグ*1について説明したあと、実際にドキュメントを書くRubyのコードを示します。その後、実際に@return
タグを使ってドキュメントを書き、YARDのコマンドを使ってHTMLのリファレンスマニュアルを作成します。
なお、YARDについてや、YARDのタグの使い方、HTMLのリファレンスマニュアルの生成の仕方については前回の記事を参照してください。
@return
タグについてまず、@return
タグについて説明します。@return
タグはYARDのタグ(コードのメタデータを記述するための記法)の1つで、戻り値についての説明を書くためのタグです。他のタグと同様にコメントの中に書くことでYARDのタグとして認識されます。
@return
タグの書式は以下の通りです。
@return [戻り値のクラス] 説明
詳しい書き方は実際に書くときに説明します。では次に、実際にドキュメントを書くRubyのコードを示します。
戻り値のドキュメントを書くRubyのコードは、前回の記事にて、メソッド全体の説明と引数についての説明を書いたコードを使います。
1 2 3 4 5 6 7 8 9 10 11 |
# Returns Array containing number exceeding limit_age. # For example, extract_overage([17, 43, 40, 56], 40) #=> [43, 56] # # @param ages [Array] numbers checked if they exceeded from limit_age. # @param limit_age [Integer] limit_age limit used to extract # bigger ages than it. def extract_overage(ages, limit_age=20) ages.select do |number| number > limit_age end end |
このコードを、以降は「サンプルコード」と呼びます。サンプルコードについての説明を前回の記事から再掲します。
サンプルコードはextract_overage
メソッドを定義しています。extract_overage
メソッドは、配列と数値を引数にとり、各要素から数値より大きい数(数値が指定されない場合は20より大きい数)を集めた配列を返します。例えば、extract_overage([17, 43, 40, 56], 40)
を実行すると、[43, 56]
を返します。
サンプルコードにはすでに、メソッド全体の説明(コメントの最初から2行目)と、引数についての説明(コメントの4行目から6行目)が書かれています。これは前回の記事で書いたドキュメントをそのまま使っています。メソッド全体の説明と引数全体の説明の書き方については、前回の記事を参照してください。
前回と同様に、この記事ではドキュメントの書いてある場所をわかりやすくするために、シグニチャーの部分だけを抜き出したものを示します。
1 2 3 4 5 6 7 8 |
# Returns Array containing numbers exceeding limit_age. # For example, extract_overage([17, 43, 40, 56], 40) #=> [43, 56] # # @param ages [Array] numbers checked if they exceeded from limit_age. # @param limit_age [Integer] limit_age limit used to extract # bigger ages than it. def extract_overage(ages, limit_age=20) end |
なお、この状態でHTMLのリファレンスマニュアルを作成すると次のようになります。
メソッド全体の説明(画像の赤枠の部分)と、@paramタグ
で書かれた説明(画像の緑の枠の部分)がHTMLのリファレンスマニュアルに表示されているのがわかります。今回はこのサンプルコードのシグニチャーに、@return
タグを使って戻り値についてのドキュメントを書きます。
@return
タグの使い方@return
タグの書式を再掲します。
@return [戻り値のクラス] 説明
@return
タグの書式について説明します。戻り値のクラスのところには、戻り値のオブジェクトのクラスを示す任意の文字列を書きます。説明のところには、文章で戻り値の説明を書きます。例えば、今回の戻り値は配列なので、配列の中身について*2説明した文章を書きます。
また、1つのメソッドにつき@return
タグは複数個書けるので、戻り値の値が変わる場合はその数だけ書くのがよいでしょう。例えば、Array
クラスのshift
メソッドは、レシーバー*3の配列が空でないときはその先頭の要素を返しますが、空の場合はnil
を返します。このように戻り値が異なる場合は、戻り値が先頭の要素の時とnil
の時についてそれぞれ@return
タグを書きます。そうすると1つ1つの戻り値についての説明が分けて書かれるため読みやすくなります。この時、説明のところにはメソッドがその戻り値を返す条件を書くと、それぞれの戻り値がどんな時に返されるのかがわかりやすくなります。
なお、@return
タグを書く場所ですが、@param
タグの下がよいでしょう。なぜかというと、引数の説明の下に戻り値の説明が書いてあるとすんなり読めるからです。メソッドは引数を受け取り、その引数を使って処理をして、戻り値を返します。それと同様に、ドキュメントも引数、戻り値の順に配置しておくと、「引数を元にこのメソッドが戻り値が生成する」とメソッドの処理の流れと同じようにすんなり読めます*4。
それでは実際に書いてみます。サンプルコードのシグニチャーに@return
タグを使ってドキュメントを書いたのが次のコードになります。
1 2 3 4 5 6 7 8 9 |
# Generates Array containing numbers exceeding limit_age. Numbers is members of ages. # For example, extract_overage([17, 43, 40, 56], 40) #=> [43, 56] # # @param ages [Array] numbers checked if they exceeded from limit_age. # @param limit_age [Integer] limit_age limit used to extract # bigger ages than it. # @return [Array] Returns Array containing numbers exceeding limit_age. def extract_overage(ages, limit_age=20) end |
戻り値は配列なので、戻り値のクラスのところにはArray
を書きます。@return
タグで戻り値の説明は、メソッド全体の説明から該当する部分を抜き出して書きました。それに伴ってメソッド全体の説明も修正しました。このコードをexample.rbというファイルに保存し、次のコマンドでHTMLのリファレンスマニュアルを生成します。
$ yardoc example.rb
生成されたHTMLのリファレンスマニュアルは次のようになります。
図の赤枠の部分に戻り値についての説明があるのがわかります。また、図の緑色の部分2ヶ所には、@retrun
タグで書いた戻り値のクラスであるArray
が表示されているのがわかります。
今回は、前回の引数についてのYARD用ドキュメントを書く方法からの続きで、戻り値についてのYARD用ドキュメントを書く方法を説明しました。前回と今回の記事の内容を使うと、メソッドについての基本的な説明をYARDで書くことができます。
次は例を書くために使う@example
タグについて説明します。
もう1年以上前になりますが、コミットメッセージの書き方を説明しました。ざっくりまとめると、以下のことを説明しています。
この説明をしてからも、日々コミットしていくなかで新たに得られた「どうすればもっとわかりやすいコミットメッセージになるか」という知見が増えていました。これは、コミットへのコメントサービスの提供を開始した*1ことも影響しています。このサービスでは、コミットへコメントするときに「どうして自分は他の書き方よりもこの書き方をわかりやすいと感じるか」を説明しています。その過程で「なんとなくこっちの方がよさそう」だったものを「具体的にこういうときにこう感じるのでこっちの方がよさそう」と何かしら理由を考えるようになりました。これにより、今までそれぞれの開発者でなんとなくだった考えが共有でき、チーム全体として「では○○という理由があるからこっちの書き方にしよう」と、考えを共有した上で自分達のスタイルを作っていくことができるようになりました。
今回はそんな日々の開発の中で明文化されたわかりやすいコミットメッセージの書き方を紹介します。理由もつけて紹介するので、自分達のチームに取り入れるときは、自分達にとっても本当にわかりやすいかどうかを検討してから判断してください。
コミットメッセージをわかりやすくするための1つの方法として、「○○しました」だけではなく、どうして○○をしたのかなどの情報を入れるという方法があります。しかし、なんでもいれればよいというものではありません。長すぎるコミットメッセージは読む気が失せてしまうからです。それではどのような情報は入れた方がよいのでしょうか。
git revert
をすると自動で「このコミットをrevertします」というログが入ります。この状態でコミットしている人は結構多いのではないでしょうか。
それでは、このrevertコミットを読む人のことを考えてみましょう。「どうしてこのコミットがrevertされたのか」ということが気になるはずです。revertしたときはrevertした理由を付加情報として書きましょう。
例えば、以下のrevertコミットは必要なファイルを追加し忘れたのでコミットしなおすためにrevertしています。
commit a0b6d964ef41f85bb825928813a67533da3d4663 Author: Kouhei Sutou <kou@clear-code.com> Date: Tue Mar 19 19:05:18 2013 +0900 Revert "doc: update for renaming --query_expansion to --query_expander" This reverts commit 4837201f9fd01826c4dd21ced2b3f357a9e9bfcd. I forgot to add renamed files. Sorry...
定形処理は自動化して誰でも簡単に間違いなく実行できるようにしていますよね。そのような自動化された処理を実行して一括で変更した内容をコミットする場合は、実行したコマンドを付加情報として書きます。
以下は、バージョン番号を更新したコマンドを付加情報として書いている例です。
commit 6a27a9f890453bf4f08c972ee53b2a40ba066489 Author: HAYASHI Kentaro <hayashi@clear-code.com> Date: Tue Apr 23 11:48:41 2013 +0900 Bump up version number to 3.03 make update-version NEW_VERSION_MAJOR=3 NEW_VERSION_MINOR=0 NEW_VERSION_MICRO=3
コマンドを書いておけば、他の人が同じことをやろうとしたときにヒントになるため、役立ちます。
以前の記事では「コミットメッセージは英語で書きましょう」と説明していました。しかし、英語で表現することにこだわりすぎるのも考えものです。以前の記事で英語で書こうと説明していた理由は、多くの人が読めるからです。つまり、多くの人にわかりやすく伝えるために英語という手段を使いましょうということでした。もし、英語よりも多くの人にわかりやすく伝えられるのであれば、英語にこだわらずにその表現を使いましょう。
「どう変わったか」を伝える場合は比較対象を縦に並べます。
例えば、CommitCommentTools::CommitsAnalyzer
クラスのanalyze
メソッドをpareto
メソッドにリネームしたとします。この場合は英語にすると以下のようになります。
Rename analyze method to pareto method of CommitCommentTools::CommitsAnalyzer class
この中で大事なことは「analyze」と「pareto」の対比です。英語で表現すると、読むとわかりますが、パッとみただけでは、そこまで目立ちません。では、どのように表現すればよいでしょうか。
テスティングフレームワークを使って開発をしたことがある人はassert_equal
、assertEquals
、should ==
などが失敗したときにどのように表示されるかを思い出してください。以下のように期待値と実際の値を並べて表示しますよね。
expected: <analyze> but was: <pareto>
何かを比較するときは横ではなく縦に並べた方が違いがパッとみてわかりやすいのでこうなっています。例えば、「1文字目から違う」ということもわかりますし、「そもそも文字の長さが違う」ということもパッとみてわかります。
これをコミットメッセージに応用するとこうなります。
Rename method of CommitCommentTools::CommitsAnalyzer class analyze -> pareto
「どう変わったか」が大事なコミットメッセージを書くときは比較対象を縦に並べましょう。比較しているものが明確になりますし、違いもわかりやすくなります。
縦に並べればなんでも違いがわかりやすくなるわけではありません。例えば、typoの修正は縦に並べても見つけることは大変です。
そんなとき、ひと手間かけるとグッとわかりやすくなります。
commit 27df8ff1fd26187bbc8e2817b633c31932559f18 Author: Haruka Yoshihara <yoshihara@clear-code.com> Date: Thu Apr 4 11:02:17 2013 +0900 test: fix a typo TestDefaultPathRuels -> TestDefaultPathRules ^^
違っている箇所の下に「^」で印をつけます。これがあれば、読む人はここに注目すればよいということが一目瞭然なのでわかりやすくなります。直した人はどこが違っていたかをすでに知っているためできるテクニックです。
なお、違っている桁の下に「^」をつけるのはPythonのdifflibで使われているスタイルです。
リファクタリングなどでより便利な書き方をできるようにすることはよくあることです。それを伝えたい場合も必ずしも英語にこだわる必要はありません。
例えば、以下のようにGroonga::Context
をnew
して自分でclose
していたものを、ブロック内で実際の処理を行い、ブロックを抜けたら自動でclose
するようにしたとします。
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 27 28 29 30 31 32 33 34 35 36 37 38 39 |
diff --git a/lib/fluent/plugin/out_droonga.rb b/lib/fluent/plugin/out_droonga.rb index 1baea60..6979c43 100644 --- a/lib/fluent/plugin/out_droonga.rb +++ b/lib/fluent/plugin/out_droonga.rb @@ -83,21 +83,30 @@ module Fluent def ensure_database return if File.exist?(@database) FileUtils.mkdir_p(File.dirname(@database)) - context = Groonga::Context.new + create_context do |context| context.create_database(@database) do end - context.close + end end def ensure_queue - context = Groonga::Context.new + create_context do |context| context.open_database(@database) do Groonga::Schema.define(:context => context) do |schema| schema.create_table(@queue_name, :type => :array) do end end end - context.close + end + end + + def create_context + context = Groonga::Context.new + begin + yield(context) + ensure + context.close + end end def load_handlers |
この場合は、今、日本語で説明したことを英語で説明するのではなく、実際にどのように使い方が変わったかをコードで表現しましょう。コミットメッセージを読む人の多くは開発者です。開発者の多くは英語だけではなく、もちろん、コードのこともわかっているはずです。コードのことはコードで伝えましょう。その方が間違いなく伝わります。
commit badf11498eb38beaa6b104e0f51fb3eb3b27a331 Author: Kouhei Sutou <kou@clear-code.com> Date: Thu Apr 4 14:54:04 2013 +0900 Extract common create and close context code Before: context = Context.new ... context.close After: create_context do |context| ... end
コミットメッセージを書く上で大事なことは、英語で書くことではなく「多くの人にわかりやすく情報を伝えること」です。そのために英語で書くという手段を使っているのです。英語で書くことだけにこだわらず、本来目指していた「多くの人にわかりやすく情報を伝えること」を実現するにはどうしたらよいかを考えてみてください。
英語以外で表現した方がわかりやすいケースを紹介しましたが、英語の方がわかりやすいケースもあります。どのような表現がよいか「わかりやすさ」という観点で考えてみてください。
文字列リテラルに「'」(シングルクォート)あるいは「"」(ダブルクォート)のどちらも使えるプログラミング言語がいくつもあります。例えば、Rubyやシェルもそのような言語です。
同じソース内では表記を統一していた方が見通しがよくなります。そのため、「"」(ダブルクォート)に統一したとします。そのとき考えられるコミットメッセージには以下のようなものがあります。
Use "XXX" style string literal Use " for string literal Use '"' for string literal
最初のケースでは「"XXX"」で文字列リテラル一般を表現しようとしています。つまり、コードで表現してわかりやすくしようとしています。コードと同じ表記なのでわかりやすくなる人がいる一方で、「XXX」を強調している英語での書き方と見えてしまう人もいるため、かえってわかりにくくなる危険があります。
2つめは「"」そのものを書いています。ソース中では「double quote」と書くよりも「"」と書いていることの方が多いため、ソース中でよく見る字面にあわせてわかりやすくしようとしています。これもコードと同じ表記なのでわかりやすくなる人がいる一方で、「"」を英語での文脈で解釈してしまうと閉じる「"」を探してしまうことになり、かえってわかりにくくなる危険があります。
3つめは「"」だけだとわかりにくいため、「'"'」と「"」を強調しています。ただ、「'"'」と「"'"」で区別がつきにくいので「"」のことなのか「'」のことなのかがかえってわかりにくくなる危険があります。
このように違う意味で解釈される危険性を回避するために、英語表記も併記します。
commit 904e124f3459df3ee9138de5fef65450613c4058 Author: Kouhei Sutou <kou@clear-code.com> Date: Sun Apr 14 11:02:17 2013 +0900 Use " (double quote) for string literal
こうすれば、「"」をプログラムの文脈で読んでパッとみて理解できるケースと、「"」が何のことかわからなかったケースもどちらにも対応できます。
シェルでは文字列をクォートで囲む必要はありません。しかし、文字列内に空白が入るかもしれないケースを考慮するとクォートで囲んでおいた方が無難です。
そんなときのコミットメッセージとしてコード片を使うことを考えると、例えば以下のようになります。
Add missing "..."
この書き方では、「"..."」という文字列リテラルになっていなかったのでそうしたというのを表現しようとしています。しかし、「...」が抜けていたので追加した、というようにも読めてしまいます。
この場合はクォートしたと英語で書いた方が伝わるでしょう。
Quote string expression
コミットへのコメントサービスや日々の開発の中で試行錯誤してわかってきた、わかりやすいコミットメッセージの書き方を例と理由をあわせて紹介しました。理由もつけてあるので、自分達のチームに取り入れるかどうかは理由を検討した上で判断してください。
*1 現在、1社に提供しており、近いうちに導入事例を紹介できる見込みです。
こんにちは。クリアコードで組込み機器向けのサイネージシステムの開発やRubyでのmilter*1開発などを担当している沖元です。プライベートでは、るりまプロジェクトなどで活動しています。
先日このブログで紹介したインターンシップ制度では、クリアコードのメンバーが開発したいと考えているフリーソフトウェアの中から「これは」というものをインターンが選択します。本エントリで紹介する開発したいフリーソフトウェアはBitClust*2です。BitClustに以下の機能を追加してるりまをより便利にしたいと考えています。
各機能の開発内容の詳細を述べます。
Ruby-Doc.orgへのリンクを表示できるようにします。RDocの各クラスやメソッドへのリンクは機械的に計算することができるはずなので、そんなに難しくないと考えています。
この機能を追加するのは、るりまの内容とRDocの内容をウェブブラウザ上で簡単に比較できるようにするためです。また、次のような効果も期待しています。
特に挑戦ポイントはありません。RDocへのリンクを正しく生成する方法さえ見つけることができれば、あとは簡単です。
現在、るりまプロジェクトではサンプルコードの埋め込みは手で実行した結果をコピー&ペーストしています。しかし、すべてのサンプルコードの実行結果が正しいことを確認できていないので、ときどき、プロジェクトのITS*3に「サンプルコードが動きません」や「サンプルコードが間違っています」のような報告があります。また、Rubyのバージョンアップによって挙動が変化したものへの追従も手動で行なっているため、完全に追従できているわけではありません。
人力ですべてのサンプルコードをRubyのバージョンごとに実行し結果をコピー&ペーストするのは、現実的ではありません。我々はプログラマなので、自動化できるところは自動化したいと考えています。
そこで、インターンシップの期間を用いて以下の機能を開発したいと考えています。
ruby -v
も埋め込む機能。この機能を開発することにより、以下のことを期待しています。
BitClustはほとんど外部ライブラリを使用せずに開発されているのでブラックボックスになっている部分がありません*4。そのため外部ライブラリをあまり使用せずにRubyを用いてアプリケーションを開発するときの参考になるでしょう。機能を実現するのに既存のツールを使用するか自前で実装するのか決める必要があります。
BitClustの既存の記法と衝突しないように設計する必要があります。また、その記法が本当にそれでいいのかコミュニティと合意を形成する必要があります。
インターンシップで開発したいるりまをより便利にする機能を2つ挙げました。これ以外にも色々と開発したい機能はあるのですが、それについてはまた別の機会に書きます。この中に「挑戦してみたい!」と思える機能があれば、インターン募集ページから是非ともご応募下さい。
*1 milter managerを使うとRubyでmilterを開発することができます。
*2 るりまプロジェクトで使っているドキュメント生成や検索機能を提供するツール。
*3 Issue Tracking System
*4 ウェブアプリケーション部分の実装でRackを使っているくらいです。