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

ククログ


現状共有の会で進行役をするとき気をつけていること

複数人でおなじゴールに向かってものごとを進めていたつもりなのに、気づいたらそれぞれ違うゴールに向かっていたということがあります。違うゴールに向かっていると、達成しようと思っていたことがなかなか達成しません。たとえば、ソフトウェアがなかなかリリースできない、といった具合です。向かっているゴールが違うと達成したいこと以外の作業をしています。達成に向けた作業をしていないので、なかなか達成しないことはしょうがありません。

この「気づいたらそれぞれ違うゴールに向かっていた」という状況を避けるための方法はいくつかあります。

  • 各自、忘れないようにする。(たとえば、いつも見る場所にゴールを書いておく。)
  • 定期的にみんなでゴールを確認し、ずれていたらその都度修正する。
  • ゴールは少数の人だけが意識し、他の人はゴールを意識している少数の人の指示の下で行動する。
  • ゴールがずれないくらい短い単位の小さなゴールに分割し、どんどん「小さなゴール設定→達成→次の小さなゴール設定→…」というサイクルを回す。

それぞれがしっかりしているなら、最初の「各自、忘れないようにする」という方法で解消できるでしょう。それがムリなら2番目の「定期的にみんなでゴールを確認し、ずれていたらその都度修正する」方法で解消できるかもしれません。他の人の助けを借りても各自が向かっているゴールを意識した行動をすることがムリなら3番目の「ゴールは少数の人だけが意識し、他の人はゴールを意識している少数の人の指示の下で行動する」という方法もあります。長めのゴールだと気付いたら違う方向を向いてしまうなら、4番目の「ゴールがずれないくらい短い単位の小さなゴールに分割する」方法もあります。

それぞれのやり方にはよいところ・悪いところがあるのでどの方法がよいかは場合によります。さらに、そもそもゴールを共有した方がよいのかどうか、という話もあります。ここではそれらについては触れません。

ここでは、2番目の「定期的にみんなでゴールを確認し、ずれていたらその都度修正する」やり方を選んだときに気をつけていることを紹介します。このやり方のときは、「今、それぞれが向かっているゴールはなにか?」を確認するタイミングが定期的に必要です。この「現在の状況を共有する」場で進行役をするときに気をつけていることです。

次のことに気をつけています*1

  • 最初に会のゴールを確認する
  • 会を進める前に会の進め方を説明する
  • 話を聞くときはどうして聞くかを説明する
  • 話を聞いているときは自分が理解したことを書く
  • 話を聞いた後は自分が理解したことをまとめて話して確認する

最初に会のゴールを確認する

最初に、どうしてこの会を開いているかをみんなで確認します。つまり、今こうしてみんなで集まっている*2のは「定期的にみんなでゴールを確認し、ずれていたらその都度修正する」ためです、みなさんが思っていることとあっていますか?みたいなことを最初に確認します。

基本的にみんなあっているのですが、定期的にやっていると「やっていることが当たり前」になって「どうしてやっていたんだ?」ということを忘れてしまうことがあります。そのため、念のため、毎回最初にゴールを確認します。

確認したゴールは会の中では「判断基準」として使います。「その話はこの会のゴールにつながりますか?つながらなそうなら違う機会にしませんか?」とか「今はこのゴールに向かうために話していますが、そのゴールに沿って考えるとどうするのがいいでしょうねぃ。」といった具合です。

会を進める前に会の進め方を説明する

実際に会を進める前にどのように進めるかを説明し、みんなの同意を得ます。説明した進め方が必ずしも最善の順番の流れではないかもしれないので、そんなに強制力があるものにしなくても構いません。みんなが同じ基準を持てれば十分です。途中でもっとよい進め方が見つかったらその進め方に変更してもよいものです。「それでは、次回から新しい進め方を試してみましょう」、としてもよいものです。

説明は、たとえば、「最初に、この1週間でやった作業の概要とそれがこのプロジェクトのゴールにどう結びついていたかを聞きます。次に、これからやる作業の概要とそれがこのプロジェクトのゴールにどう結びつくかを聞きます。最後に、困っていることを聞きます。」というような感じです。

進める前に進め方を説明しておくと、進めている途中で話題がそれそうになったときに方向修正をしやすくなります。たとえば、「今はこの1週間の作業について話しているので、困っていることについてはその後にしませんか?最後に困っていることを聞くタイミングがありますし。」といった具合です。

話を聞くときはどうして聞くかを説明する

みんなでゴールを確認する会なので、みんなから話を聞く機会があります。話を聞くときは「○○について話してください」、「○○についてはどうですか?」というように話を振ります。そのとき、聞かれた人が答える前に「どうして自分はそう話を振っているか」を説明します。

たとえば、「どうしてこの質問をするかというと、△△がうまくいっていたのか確認したいからです。たとえば、××ならうまくいっていないので何か対策を立てたいですし、◎◎なら問題ないので今のまま進めていきたいと思っています。」というようなことを話します。できれば、予想回答とその回答のときにどうなるかも添えます。

事前に予想回答まで話すと回答を誘導してしまう危険性があります。しかし、「何か裏があって質問されているんじゃないだろうか?とするとここではどう答えるのが正解だろう。××だと思っているけど◎◎にしておこう。」という不安を解消できるのではないかと予想しています。また、こちらが質問した意図を伝えることで、その意図に沿った情報を提供してくれる気になるのではないかという予想もしています。

事前に聞く理由も説明した方がよいかどうかはまだわかっていません。説明することを試している最中です。

話を聞いているときは自分が理解したことを書く

もし、ホワイトボードがあるなら、話を聞いているときは自分が話を聞いて理解したことの要点を書きます。自分だけが見える手元のノートに書くのではなく、みんなが見える場所に書いていくことがポイントです。

同じ話を聞いていても、人によって違う解釈をすることはよくあります。みんなが見える場所に要点を書きながら聞くことで、違う解釈をしているか気づきやすくなります。話している人が違う解釈をされていると気づくこともありますし、他の話を聞いている人が自分は違うように解釈していると気づくこともあります。

これは、より多くどのくらい伝わっているかを、話している人と話を聞いている人にフィードバックする方法です。うなずきながら話を聞くという方法も話している人に伝わっている感をフィードバックする方法ですが、それよりも具体性があり、フィードバック対象が多いフィードバックです。

書きながら話を聞いている人が話をしている人に質問するときは、「この人は単純にわからないから、自分の話を理解するために質問しているんだな」感が増すのではないかと仮説を立てています。質問すると、(そんなわけではないのに)「なにかアラを探しているんじゃないか…」感を持たれている人にとって、これは役に立つ効果でしょう*3

話を聞いた後は自分が理解したことをまとめて話して確認する

話を聞いた後は、自分が理解した要点を話してあっているかを確認します。たとえば、「今の話は、できれば肉の日にリリースしたい、ただし機能は減らす必要がある、ということであっていますか?」という感じです。

聞いた後に確認する理由は次の2つです。

  • 理解した内容が間違っているかもしれない。間違っていたら早めに修正したい。
  • 他の人にも伝えたい。

最初の理由は追加で説明する必要はありませんが、2つめは補足します。

質問をして話を聞いているときは、話をしている人は質問した人に向かって答えます。聞かれた人に向かって答えるのは当然ですね。そうすると、質問した人ではない人は横から話を拾い聞きすることになります。そうすると、自分(質問した人ではない人)は話がピンとこないけど質問した人はピンときてそうなときに、「今のところがわからなかったからもう少し説明してもらえないか」と聞きにくくなります。また、単純に聞こえなかったり聞きそびれることが増えます。

質問した人が話を聞いた後に確認をすると、もう一度話を聞く機会ができるので、理解しそこねたことを補完できます。確認したあとに「みなさんには伝わりましたか?大丈夫ですかねぃ。」と聞くと、それでもピンとこなかった人が質問するタイミングができます。ここで質問がでてピンとこないところが解消できれば、認識が違って話がかみ合わないことが減ります。

まとめ

「現在の状況を共有する」場で進行役をするときに気をつけている次のことを紹介しました。

  • 最初に会のゴールを確認する
  • 会を進める前に会の進め方を説明する
  • 話を聞くときはどうして聞くかを説明する
  • 話を聞いているときは自分が理解したことを書く
  • 話を聞いた後は自分が理解したことをまとめて話して確認する

試している最中なので、これらすべてが説明したような効果があるかはまだわかっていません。しかし、全体として前よりはうまくできるようになった感触はあるので紹介しました。

*1 気をつけようとしています。気をつけたらもっとよくなるんじゃないかと予想して試しています。

*2 オフラインでもオンラインでも集まり方は関係ない。

*3 仮説があっていれば。

2013-10-02

Windowsの32bit/64bit版Ruby用バイナリ入りgemをDebian GNU/Linux上で作る方法

2013年10月時点での情報です。長いです。

Windowsの32bit/64bit版Ruby用のバイナリ入りgemをDebian GNU/Linux上で作る方法を紹介します。

背景

どうしてこの方法を紹介するのか、その動機を伝えるために背景を説明します。

Rubyから簡単に使えるGroongaという高性能な全文検索エンジンがあります。Groongaを簡単に使えるのはRroongaというgemがあるからです。Groongaは主にC言語で書かれているためWindowsでインストールするのは大変です。しかし、RroongaはWindows用のバイナリ入りのgem(作り方)も配布しているのでWindowsでも簡単に使うことができます。

Groongaは64bit環境を想定した設計になっていて、32bit環境では(主にサイズ面で)いくつか制限があります。そのため、Windows上でも64bit環境で簡単にGroongaを使えるように64bit環境用にビルドしたバイナリを配布しています。

ただし、RubyからGroongaを使う場合はこの恩恵を受けられませんでした。なぜなら、64bit版Ruby用のRroongaのバイナリが配布されていなかったからです*1

どうして64bit版Ruby用のバイナリが配布されていなかったのか。それはMinGWでビルドされた64bit版Rubyのパッケージがなかったからです。そのため、まずはMinGWでビルドされた64bi版Rubyのパッケージを作ることからはじめました。これが2年前の話です。このときの成果が直接取り込まれたわけではありませんが、その後、RubyInstaller for WindowsはRuby 2.0.0用のパッケージから64bit版も配布するようになりました。8ヶ月前の話です。

MinGWでビルドされた64bit版Rubyのパッケージができたので、あとはRroongaの64bit版バイナリをDebian GNU/Linux上でビルドするだけです。これをするためにはrake-compiler 0.9.0の登場を待つ必要がありました。rake-compiler 0.9.0からWindowsの64bit版Rubyのサポートが始まったのです。rake-compiler 0.9.0の登場はWindowsの64bit版Rubyパッケージがリリースされてから半年後の今年の8月です。

これでWindowsの64bit版Ruby用のバイナリ入りのgemをリリースする準備が整いました。rake-compiler 0.9.0が登場した次の月、Rroonga 3.0.8はWindowsの32bit版Ruby用のバイナリ入りgemだけではなく64bit版Ruby用のバイナリ入りgemもリリースしました。

前置きがだいぶ長くなりましたが、Windowsの32bit/64bit版Ruby用のバイナリ入りgemをDebian GNU/Linux上で作る方法を紹介します。

仕組み

まず仕組みを説明します。次のように順を追って仕組みを説明します。

  1. バイナリ入りgemの仕組み
  2. 複数バージョンのRuby(1.9.3と2.0.0とか)に対応したバイナリ入りgemの仕組み
  3. 32bit版用と64bit版用のgemを提供する仕組み
バイナリ入りgemの仕組み

まず、バイナリ入りgemの仕組みについて説明します。

バイナリ入りgemを作る時のポイントは次の2点です。

  • gemの中に.so(バイナリ)を入れる
  • gemにextconf.rbを登録しない

「gemの中に.soを入れる」というのはGem::Specification#filesに.soを入れるということです。これを忘れるとバイナリが入っていないgemになってしまいます。そのため、忘れてはいけないとても大切なことです。

なお、.soを入れる前に.soを作る必要があります。Windows用のバイナリ入りgemをDebian GNU/Linux上で作るときはWindows用の.soをクロスコンパイルしなければいけません。

「gemにextconf.rbを登録しない」というのはGem::Specification#extensionsにextconf.rbを入れないということです。これを忘れるとせっかくバイナリがgemの中に入っているのにインストール時にバイナリをビルドしようとします。これではバイナリを入れている意味がありません。

クロスコンパイルも含めてこれら2つのことをやってくれるのがrake-copmilerというgem*2です。rake-compilerを使うと、Rakefileに次のように書くだけでこれらのことをやってくれます。

1
2
3
4
5
require "rake/extensiontask"
# specはGem::Specification
Rake::ExtensionTask.new(spec.name, spec) do |ext|
  ext.cross_compile = true
end

便利ですね。

rake-compilerの準備(後述)が済んでいれば、次のコマンドでWindowsの32bit版Ruby用のgemができます。

% rake RUBY_CC_VERSION=1.9.3:2.0.0:2.1.0 cross clean compile native gem

fat_gem_sampleというサンプル拡張ライブラリを用意しました。このサンプルを使うとすぐに試すことができます。次のコマンドでバイナリ入りgemができます。

% git clone https://github.com/kou/fat_gem_sample.git
% cd fat_gem_sample
% rake RUBY_CC_VERSION=1.9.3:2.0.0:2.1.0 cross clean compile native gem

pkg/fat_gem_sample-1.0.0-x86-mingw32.gemができているはずです。

複数バージョンのRubyに対応したバイナリ入りgemの仕組み

次に、複数バージョンのRubyに対応したバイナリ入りgemの仕組みについて説明します。

gemに.soを入れるのは単にGem::Specification#filesの中にファイルを1つ追加するだけです。そのため、1つのgemに複数の.soを入れることは簡単なことです。

複数バージョンのRubyに対応したバイナリ入りgemを作る時のポイントは次の2点です。

  • それぞれのRuby用の.soを入れる
  • requireされたときに対応するRuby用の.soだけを読み込む

「それぞれのRuby用の.soを入れる」というのはそれぞれのRuby用の.soをクロスコンパイルして、できた.soをすべてGem::Specification#filesに入れるということです。これは前述のrake-compilerがやってくれます。Rakefileの内容も前述のままで大丈夫です。

requireされたときに対応するRuby用の.soだけを読み込む」というのはRUBY_VERSIONを見て読み込む.soを変えるということです。具体的には次のようにします。

1
2
3
4
5
6
7
# lib/groonga.rb
begin
  major, minor, _ = RUBY_VERSION.split(/\./)
  require "#{major}.#{minor}/groonga.so"
rescue LoadError
  require "groonga.so"
end

これで、require "groonga"とすると使っているRubyのバージョン用の.soが読み込まれます。rescue LoadErrorしている部分は、バイナリ入りgemを使っているケース用の処理ではなく、通常のケース用の処理です。通常のケースとはバイナリの入っていないgemをインストールしているケースのことです。このときはインストール時に自分でビルドします。

requireしているパスについて少し補足します。rake-compilerはビルドした.soをlib/1.9/lib/2.0/のようにlib/#{メジャーバージョン}.#{マイナーバージョン}/以下のディレクトリに置きます。そのため、require "#{major}.#{minor}/groonga.so"と指定しています。

なお、このように1つのgemに複数バージョンのRuby用のバイナリが入っているgemをfat gemと呼びます。

32bit版用と64bit版用のgemを提供する仕組み

最後に32bit版用と64bit版用のgemを提供する仕組みについて説明します。

ポイントは次の1点です。

  • gemをわける

複数バージョンのRuby用のバイナリは1つのgemに入れられますが、複数プラットフォーム(32bit用と64bit用)に対応した1つのgemは作れません。これは、1つのgemには1つのプラットフォーム情報しか設定できないからです。

Windowsの32bit版Ruby用なら「x86-mingw32」というプラットフォームで、64bit版なら「x64-mingw32」というプラットフォームになります*3

これもrake-compilerを使うといい感じにやってくれます。Rake::ExtensionTask#cross_platformにクロスコンパイルしたいプラットフォームを指定するだけです。

1
2
3
4
5
6
require "rake/extensiontask"
# specはGem::Specification
Rake::ExtensionTask.new(spec.name, spec) do |ext|
  ext.cross_compile = true
  ext.cross_platform = ["x86-mingw32", "x64-mingw32"]
end

簡単ですね。

gemを作るコマンドは変わりません。

% rake RUBY_CC_VERSION=1.9.3:2.0.0:2.1.0 cross clean compile native gem

これで次のファイルができます。

  • pkg/fat_gem_sample-1.0.0-x86-mingw32.gem
  • pkg/fat_gem_sample-1.0.0-x64-mingw32.gem

ここまでが仕組みの説明です。Windowsの32bit/64bit版Ruby用のバイナリ入りgemがどのような仕組みで実現されているかわかりましたか?また、複数バージョンのRubyのバイナリを1つのgemに入れる方法がどんな仕組みで実現されているかわかりましたか?

rake-compilerの準備

仕組みがわかったということにして話を進めます。仕組みがわかったので実際にgemを作ってみましょう。

ここまでの説明でrake-compilerを使えばWindowsのRuby用バイナリ入りgemを簡単に作れることがわかっているはずです。ここからは、rake-compilerを使うために最初にしなければいけないことについて説明します。

まず、クロスコンパイル用のビルドツールをインストールします。以前はMinGWを使っていましたが、今はMinGW-w64を使います。MinGW-w64は32bit版のビルドにも64bit版のビルドにも対応しているからです。

% sudo apt-get install -y -V mingw-w64

次に、rake-compilerをインストールします。

% gem install rake-compiler

最後に、バイナリを作りたいプラットフォームのRubyをビルドして準備は完了です。複数バージョンのバイナリをビルドする場合はそれぞれのバージョンのRubyをビルドします。次のコマンドを実行するとRubyをビルドできます。プラットフォームとバージョンは引数で指定します。

% rake-compiler cross-ruby HOST=#{プラットフォーム} VERSION=#{Rubyのバージョン}

例えば、32bit版Rubyの2.0.0-p247をビルドしたい場合は次のようにします。

% rake-compiler cross-ruby HOST=i686-w64-mingw32 VERSION=2.0.0-p247

64bit版Rubyの2.1.0-preview1をビルドしたい場合は次のようにします。

% rake-compiler cross-ruby HOST=x86_64-w64-mingw32 VERSION=2.1.0-preview1

32bitと64bitの両方対応で、さらに、1.9.3、2.0.0、2.1.0用のバイナリ入りgemを作りたい場合は次のようにします。

% rake-compiler cross-ruby HOST=i686-w64-mingw32 VERSION=1.9.3-p448
% rake-compiler cross-ruby HOST=i686-w64-mingw32 VERSION=2.0.0-p247
% rake-compiler cross-ruby HOST=i686-w64-mingw32 VERSION=2.1.0-preview1
% rake-compiler cross-ruby HOST=x86_64-w64-mingw32 VERSION=1.9.3-p448
% rake-compiler cross-ruby HOST=x86_64-w64-mingw32 VERSION=2.0.0-p247
% rake-compiler cross-ruby HOST=x86_64-w64-mingw32 VERSION=2.1.0-preview1

これでrake-compilerの準備は完了です。

前述した次のコマンドが動くようになっているはずです。

% git clone https://github.com/kou/fat_gem_sample.git
% cd fat_gem_sample
% rake RUBY_CC_VERSION=1.9.3:2.0.0:2.1.0 cross clean compile native gem

次のgemができましたか?

  • pkg/fat_gem_sample-1.0.0-x86-mingw32.gem
  • pkg/fat_gem_sample-1.0.0-x64-mingw32.gem

このように、rake-compilerを準備すれば、rake一発でバイナリ入りgemが作れるようになります。拡張ライブラリーでも簡単にリリースできますね。

gemに依存ライブラリも入れる

実は、ここで説明している方法だけではRroongaのバイナリ入りgemは作れないのです。ただの拡張ライブラリーであればここまでの方法で大丈夫です。しかし、なにかのライブラリーのバインディング*4ではそうはいきません。gemにバインディングのバイナリーは入っていても、「なにかのライブラリー」そのものは入っていないので動かないのです。そして、RroongaはGroongaのバインディングなのです。GroongaがないとRroongaは動きません。

これを解決する方法は2つあります。

  • gemとは別に「なにかのライブラリー」をインストールしてもらう
  • gemの中に「なにかのライブラリー」のバイナリも入れる

Rroongaは後者の方法を使っています。つまり、gemの中にGroongaのバイナリも入れているということです。こうすると、gemをインストールするだけで追加の手間は必要ありません。

ただし、このやり方はrake-compilerでは想定外のやり方なので、ひと手間かけないといけません。

rake-compilerはgemを作るときに一時ディレクトリーにファイルをコピーしてからそのディレクトリーを元にgemを作ります。この一時ディレクトリーを「stage」と呼んでいます。次のようなコマンドを実行しているイメージです。「tmp/stage/」ディレクトリーが「stage」に相当します。

% cp -a groogna.gemspec tmp/stage/
% cp -a lib/ tmp/stage/
% cp -a ext/ tmp/stage/
...
% cd tmp/stage
% gem build groonga.gemspec

Rroongaのgemの中にGroongaのバイナリも入れるためには上記の「cp -a ...」のタイミングでGroongaのバイナリも「stage」にコピーしなければいけません。それを実現すると以下のようになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
require "find"

def collect_binary_files(spec)
  # 「vendor/#{プラットフォーム名}/」以下にGroongaのバイナリがあるとする
  Find.find("vendor/#{spec.platform}/").to_a
end

Rake::ExtensionTask.new(spec.name, spec) do |ext|
  ext.cross_platform = ["x86-mingw32", "x64-mingw32"]
  ext.cross_compile = true
  ext.cross_compiling do |_spec|
    binary_files = collect_binary_files(_spec)
    _spec.files += binary_files
    stage_path = "#{ext.tmp_dir}/#{_spec.platform}/stage"
    binary_files.each do |binary_file|
      stage_binary_file = "#{stage_path}/#{binary_file}"
      stage_binary_dir = File.dirname(stage_binary_file)
      directory stage_binary_dir
      file stage_binary_file => [stage_binary_dir, binary_file] do
        cp binary_file, stage_binary_file
      end
    end
  end
end

これでgemの「vendor/#{プラットフォーム名}/」以下にGroongaのバイナリが入ります。後は次のように環境変数PATHにGroongaのDLLがある「vendor/#{プラットフォーム名}/bin/」を加えれば完成です。この処理は「require "#{major}.#{minor}/groonga.so"」の前にやることがポイントです。groonga.soがGroongaのDLLを使うからです。

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
require "pathname"

base_dir = Pathname.new(__FILE__).dirname.dirname.expand_path
local_groonga_dir = base_dir + "vendor" + RUBY_PLATFORM
local_groonga_bin_dir = local_groonga_dir + "bin"
if local_groonga_bin_dir.exist?
  prepend_path = lambda do |environment_name, separator|
    paths = (ENV[environment_name] || "").split(separator)
    dir = local_groonga_bin_dir.to_s
    dir = dir.gsub(/\//, File::ALT_SEPARATOR) if File::ALT_SEPARATOR
    unless paths.include?(dir)
      paths = [dir] + paths
      ENV[environment_name] = paths.join(separator)
    end
  end

  prepend_path.call("PATH", File::PATH_SEPARATOR)
end

begin
  major, minor, _ = RUBY_VERSION.split(/\./)
  require "#{major}.#{minor}/groonga.so"
rescue LoadError
  require "groonga.so"
end

これで、ただの拡張ライブラリーだけでなく、バインディングもgemをインストールするだけですぐに使えるようになります。

ただし、「何かのライブラリー」(Rroongaの場合はGroongaに相当)のバイナリをどうやって用意するかについては触れていないので注意してください。これについてはrake-compilerは助けてくれません。Rroongaの場合はGroongaが配布しているバイナリをそのまま使っています。rcairoの場合は自分でクロスコンパイルしています。自分でクロスコンパイルする場合はDebian GNU/LinuxでWindows用バイナリをビルドする方法を参考にしてください。2年前の記事ですが今でも有効です。

まとめ

Windowsの32bit/64bit版Ruby用バイナリ入りgemをDebian GNU/Linux上で作る方法を説明しました。64bit版のWindowsでも簡単にRroongaを使えるように!と2年前からコツコツ進めていたことがようやく実現できました。Rubyの拡張ライブラリーやバインディングをWindowsでも簡単に使えるようにしたいという方はぜひrake-compilerを使ってみてください。

*1 能楽堂にRroongaが同梱されているので64bit版RubyでもRroongaを使うことはできましたが、Groonga/Rroongaの方がバージョンアップが早いため最新のGroonga/Rroongaを使うことはできなくなっていました。

*2 RubyInstaller for Windowsをやっている人が作っているgemです。

*3 RubyInstaller for WindowsのRubyの話です。Ruby Microsoft Installer PackageのRubyなどでは違うプラットフォームになります。

*4 「なにかのライブラリー」をRubyから使えるようにするための拡張ライブラリー

タグ: Ruby
2013-10-16

消費税率引き上げへの対応

はじめに

2013年10月1日、来年4月から予定通り消費税率を8%に引き上げるとの発表がありました。そこでクリアコードでも消費税率引き上げに対して、どのような対応が必要か確認してみました。すると、すぐに対応しなければいけないものがあることがわかりました。そこで、今回は消費税率引き上げにともないクリアコードで実施した対応とこれから必要となる対応を紹介します。

今回の消費税率引き上げの概要

消費税とは

消費税は、国内におけるほぼすべての商品の販売、サービスの提供に課税する間接税です。消費税は、事業者が販売する商品やサービスの価格に含まれて、次々に転嫁されます。そして最終的に商品を消費、またはサービスの提供を受ける消費者が消費税を負担します。消費税を負担するのは消費者で、消費税を申告、納付するのは事業者となります。このように負担者と納税者が異なる税金のことを間接税と呼びます。では、消費税の納税義務はいつ成立するのかというと、原則として商品の引き渡しやサービスの提供をした時になります。

消費税率引き上げの対応にあたっては、この商品の引き渡しやサービスの提供がいつになるかによって税率が変わるので、注意する必要があります。また売上を計上するタイミングが消費税の納税義務発生のタイミングになるので、売上計上基準によって、適用される消費税率が変わることがあります。

消費税率引き上げの内容

消費税率は平成9年に3%から5%に引き上げられました。今回は17年ぶりの消費税率引き上げとなります。

「社会保障の安定財源の確保等を図る税制の抜本的な改革を行うための消費税法の一部を改定する等の法律」(以下、「消費税法改定」)により、消費税率は平成26年4月1日に8%、平成27年10月1日に10%へと2段階で引き上げられることになりました。この法律には「経済財政状況の激変にも柔軟に対応する観点から、消費税率引き上げ前に、経済状況を総合的に勘案した上で、消費税率の引き上げの停止を含め所要の措置を講ずる」ことが定められており、平成25年10月1日の閣議で平成26年4月1日に8%に引き上げることが正式に決定しました。

経過措置

今回の消費税法改定では、税率引き上げに伴う経過措置が設けられました。本来平成26年4月1日以降に行われる資産の譲渡等には8%の税率が適用されます。しかし経過措置によって、一定の条件を満たす取引については、8%に引き上げられた後でも5%を適用することができます。

たとえば、平成25年9月30日以前に契約したソフトウェア受託開発案件の場合、納品が平成26年4月1日以降であっても、5%の税率が適用されます。他には、平成26年4月1日以降に利用する鉄道や飛行機の交通運賃も、平成26年3月31日までに支払った場合は、5%の税率が適用されます。

経過措置の内容は、国税庁の資料「平成26年4月1日以後に行われる資産の譲渡等に適用される消費税率等に関する経過措置の取扱いQ&A」に詳しく記載されています。自社の取引の中で、経過措置に該当するものがないか、この資料をひと通り目を通して確認するのがよいでしょう。

売上への影響と対策

クリアコードでは、まず業績への影響が大きい売上への影響と必要な対策を確認することにしました。

売上への影響

クリアコードのサービスは請負契約と保守/サポート契約にもとづき提供しています。

契約形態によって売上計上の方法が異なるため、消費税率引き上げの売上への影響と、必要な対策をそれぞれ確認しました。

請負契約

請負契約では納品日に売上計上しています。契約締結日が平成25年10月1日以降で納品日が平成26年4月1日以降の契約は経過措置の対象外となるので、消費税率は8%となります。もしこれに該当する契約を消費税率5%で契約してしまっている場合は対応が必要です。なお、経過措置の対象となるのは物品の引き渡しがあることが条件となります。納品物の定めがない場合は経過措置の対象にはならないので注意が必要です。

確認のポイントは次のとおりです。

  • 平成26年4月1日以降が納期の請負契約
    • 契約締結日が平成25年9月30日以前なら経過措置の対象となり、請求時の消費税率は5%でOK
    • 契約締結日が平成25年10月1日以降なら、請求時の消費税率は8%

契約書に消費税率5%で算出した請負金額を記載してしまっている場合は、発注元に対して消費税率8%で算出した請負金額への変更をお願いしなければなりません。5%の金額で受け取った場合は、自社で差額の3%分を負担しなければなりません。

例えばもとの請負契約が次の内容で、消費税率上げにともなう請負契約の変更を行わなかったとします。

  • 契約日 平成25年10月1日
  • 納品日 平成26年4月30日
  • 請負金額 3,150,000円(消費税込)

納品日の平成26年4月30日に無事納品、検収が完了したとすると、この日に売上3,150,000円を計上します。この取引は経過措置の対象外となるため、8%の消費税が発生します。よって売上金額の3,150,000円には8%の消費税が含まれているとみなされます。消費税額は3,150,000 / 1.08 * 0.08 = 233,333円となり、売上に含まれる消費税額は233,333円 - 150,000円 = 83,333円増加します。つまり、消費税率引き上げによって、83,333円の消費税を自社で負担しなければならず、利益が減ってしまうことになります。

原則課税の場合、受け取った消費税から支払った消費税を差し引いた額が消費税の納税額となります。発注元が原則課税を採用している場合はこの取引で支払う消費税が増えても、納税時に支払う消費税額がその分減るので、業績への影響はありません。まずは消費税率改定にともなう変更契約の締結を発注元に依頼するのがよいでしょう。一方、発注元がもし簡易課税制度を採用していると売上金額から消費税額を算出するため、支払った消費税額が増えても納税額は変わりません。つまり支払う消費税額が増えれば利益が減ってしまいます。契約の変更が難しい場合は、納期を平成26年3月31日以前に変更すれば収益の減少は避けられますが、開発メンバーからの批判は避けられないでしょう。

また、これから契約するものについては、納期によって消費税率が変わってきますので、見積書作成の段階から注意が必要です。

保守/サポート契約

クリアコードでは過去に構築したシステムの保守/サポート契約を1年契約で締結していて、売上は毎月一定額を計上しています。保守は物の引渡しを要しない契約であり、経過措置の対象外となります。一方で保守契約の代金は契約時に一括して受け取っており、受け取った消費税はすべて5%でした。しかし現在の売上計上基準では、来年4月以降に売上計上するものについては消費税率が8%になってしまいます。つまり平成26年4月1日以降に契約期限が到来するものについては対応が必要となります。

確認のポイント

  • 平成26年4月1日以降に契約期限が到来するもの
    • 平成26年3月31日までは消費税率5%
    • 平成26年4月1日以降は消費税率8%

例えば次の保守契約を締結していたとします。

  • 契約期間 平成25年10月1日から平成26年9月30日
  • 契約金額 252,000円(内消費税12,000円)
  • 代金受取 平成25年10月31日

この保守契約では、毎月月末に21,000円を売上計上しています。平成25年10月から平成26年3月までは消費税率は5%となるので、売上金額のうち、1,000円が消費税となります。しかし平成26年4月からは消費税率8%となるので、もし消費税率引き上げ分を追加でもらうことができなければ、売上金額のうち、21,000 / 1.08 * 0.08 = 1,555円が消費税とみなされるため、1,555 - 1,000 = 555円を自社で負担しなければなりません。 対策としては、平成26年4月から平成26年9月までの6ヶ月分の代金120,000円について、消費税の差額 120,000 * ( 8% - 5% ) = 3,600円をお客様に追加で負担してもらう方法が考えられます。また、別の方法としては売上の計上時期を変更することによって消費税率改定による売上減少の影響を回避することができます。保守契約の場合、代金受け取り時に一括して売上計上することが認められているので、平成25年10月31日に全額を売上計上すれば消費税率は5%となります*1。ただし、売上計上基準を変更した場合はすべての取引について同じ基準を適用し、かつ毎期継続的に適用しなければなりません。

また、これから契約を締結するものについては、平成26年3月までは5%、平成26年4月以降は8%の消費税率を適用しなければなりません。さらに契約が平成27年10月を超える場合は、平成27年10月以降は10%とする必要があります。ただし、平成27年10月に10%に引き上げられることが確定していませんので、もし引き上げが行われなかった場合は差額を返還するなどの対応が必要となります。

支出面での影響

クリアコードの場合、請け負った業務について外注することはないので、売上への影響で行った平成26年4月をまたいだ契約のチェックは不要でした。またその他の経費の支払いについては、原則課税を選択しているので、支払う消費税額が増えても、それは納税額が減るだけなので業績への影響ないことが確認できました。

簡易課税を採用している企業だと、納税額は売上高から算出されるので、消費税の支出を抑えればその分利益が増えます。簡易課税の場合は3月末までに経費支出をするのがよいでしょう。

まとめ

消費税率引き上げによって業績にどのような影響があるのか、また影響がある取引についてどのような対策が必要か、クリアコードで検討した結果を紹介しました。請負契約、保守契約のいずれも平成26年4月1日をまたぐものについては、対策が必要となる可能性があります。対策が必要となった場合、お客様にも影響が及びますので、早期に確認するのがよいでしょう。

*1 経理処理については税理士事務所等にご確認ください。

タグ: 会社
2013-10-24

segv-handler-gdb:Rubyスクリプトがクラッシュしたときにより詳しくCレベルのバックトレースを出力するgem

Rubyで拡張ライブラリーを使っているとクラッシュすることがあります。自分が開発している拡張ライブラリーならどうにかして直したいものです。そのときに役立つのがGDBなどのデバッガーです。Cレベルのより詳細な情報を取得できるため、問題の特定に役立ちます。しかし、次のようにデバッガー上でクラッシュさせることが難しいことがあります。

  • GDB上で動かすとクラッシュしない

消極的な理由ですが次のようなケースもあります。

  • なかなかクラッシュしないので、ずっとGDB上で動かしているわけにもいかない
    • SIGPIPEなどを捕まえて止まって欲しくない。「handle SIGPIPE nostop」などをするのが面倒。
  • クラッシュしたら自動で起動しなおしてサービスは継続して欲しい
    • GDB上でいろいろ作業しているとポートを専有したままで起動できない。

そのようなときに便利なgemがsegv-handler-gdbです。

似たようなツール

便利と書きましたが、便利なケースは限られています。多くの場合は次の似たようなツールの方が便利です。

  • sigdump
    • Rubyレベルの詳細な情報をダンプするツール
    • segv-handler-gdbの方が向いているケース:Cレベルの情報が欲しい場合
  • gdbruby.rb
    • coreからCレベル・Rubyレベルのバックトレースを表示するツール
    • segv-handler-gdbの方が向いているケース:クラッシュした瞬間のバックトレースを知りたいけど、プロセスサイズが大きくてcoreを出力したくないケース。例えば、Rroonga*1で数10GB以上の大きなデータベースを開いているケース。

では、どのようなときに便利なのか。このgemを作った背景を説明するとどのようなときに便利なのかわかるでしょう。

背景

segv-handler-gdbはRroongaがクラッシュする問題を調査するために作ったツールです。既存のツールでは問題を調査するには不便だったのです。それでは、何が不便だったのかを説明します。

RroongaはGroongaというC/C++で書かれた全文検索エンジンを使用しています。Rroongaレベルでクラッシュすることもあれば、Groongaレベルでクラッシュすることもあります。どちらかというとGroongaレベルでクラッシュすることが多いです。クラッシュした問題の原因を調べる場合はCレベルのバックトレースがあると役立ちます。

既存のツールでもCレベルのバックトレースを出力する機能がありました。例えば、RubyはクラッシュするとCレベルのバックトレースを出力します。

% ruby -e 'sleep' &
[1] 12621
% kill -SEGV 12621
-e:1: [BUG] Segmentation fault
ruby 2.0.0p299 (2013-08-29) [x86_64-linux-gnu]
...
-- C level backtrace information -------------------------------------------
/usr/lib/x86_64-linux-gnu/libruby-2.0.so.2.0(+0x176a5b) [0x7fa26684ba5b]
/usr/lib/x86_64-linux-gnu/libruby-2.0.so.2.0(+0x64aca) [0x7fa266739aca] vfscanf.c:653
/usr/lib/x86_64-linux-gnu/libruby-2.0.so.2.0(rb_bug+0xb3) [0x7fa26673a1d3] vfscanf.c:651
...

rb_bugのように関数名も入っていますし、ファイル名や行数も入っています。これはbacktrace(3)を使った出力で、よく見かけるフォーマットです*2。Groongaもコマンドとして使った場合は同じように出力します*3

たしかにCレベルのバックトレースは手に入っています。しかしこれだと足りないのです。引数の情報があるともっとうれしいのです。引数の情報もあると、「引数にNULLが渡ってしまっているからクラッシュしたんだな」などということがわかります。

デバッグシンボル付きでビルドしたバイナリーなら、GDBを使えば引数の情報も取得できます*4

% groonga -d
14129
% gdb --pid 14129 --batch --eval-command 'backtrace'

warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
0x00007f782398dfb3 in __epoll_wait_nocancel () at ../sysdeps/unix/syscall-template.S:81
81	../sysdeps/unix/syscall-template.S: そのようなファイルやディレクトリはありません.
#0  0x00007f782398dfb3 in __epoll_wait_nocancel () at ../sysdeps/unix/syscall-template.S:81
#1  0x00007f7824f00fe6 in grn_com_event_poll (ctx=0x7fff86e7fc40, ev=0x7fff86e7f330, timeout=1000) at com.c:578
#2  0x0000000000405393 in run_server_loop (ctx=0x7fff86e7fc40, ev=0x7fff86e7f330) at groonga.c:534
#3  0x0000000000405a5e in run_server (ctx=0x7fff86e7fc40, db=0x18a8b90, ev=0x7fff86e7f330, dispatcher=0x40a42b <g_dispatcher>, handler=0x40aa30 <g_handler>) at groonga.c:595
#4  0x0000000000405bab in start_service (ctx=0x7fff86e7fc40, db_path=0x0, dispatcher=0x40a42b <g_dispatcher>, handler=0x40aa30 <g_handler>) at groonga.c:625
#5  0x000000000040ae04 in g_server (path=0x0) at groonga.c:1597
#6  0x000000000040c913 in main (argc=2, argv=0x7fff86e80038) at groonga.c:2508

grn_com_event_poll (ctx=0x7fff86e7fc40, ev=0x7fff86e7f330, timeout=1000)」というように引数の情報も入っています。

「backtrace」だけでなく、「backtrace full」にするとローカル変数の情報も入ります。

% gdb --pid 14129 --batch --eval-command 'backtrace full'
...
#1  0x00007f7824f00fe6 in grn_com_event_poll (ctx=0x7fff86e7fc40, ev=0x7fff86e7f330, timeout=1000) at com.c:578
        nevents = 0
        com = 0x0
        ep = 0x7f7825463010
        __FUNCTION__ = "grn_com_event_poll"
#2  0x0000000000405393 in run_server_loop (ctx=0x7fff86e7fc40, ev=0x7fff86e7f330) at groonga.c:534
No locals.
...

スレッドを使っている場合は、さらに「thread apply all backtrace full」とします。

デバッグの役にたちそうですね!

要件

backtrace(3)ではなくGDBを使えば引数の情報などより詳細な情報を取得できます。それならクラッシュした時のcoreをGDBで開いても問題ありません。

しかし、Rroongaの場合はcoreを出力することが現実的でない場合が多いのです。Groongaはデータベースの内容をメモリー上にマップして使います。coreはメモリーの内容を含むので、Groongaがデータベースの内容すべてをメモリー上にマップしている場合はデータベースと同じくらいの大きさのcoreができます。データベースが数10GBあればcoreもそのくらい大きくなります。そのサイズのcoreを出力すると大量のディスクI/Oが発生し、システムにも影響がでます。

そのため、Rroongaで便利に使うためにはcoreを出力せずにクラッシュした瞬間のバックトレースを取得する方法が必要だったのです。

まとめ

Rroongaがクラッシュしたときに問題の調査が便利になるgem、segv-handler-gdbを紹介しました。多くの場合はsegv-handler-gdbではなく他のツールの方が便利でしょう。

*1 Ruby用の全文検索機能を提供する拡張ライブラリー。

*2 少し補足すると、ファイル名と行数が入っているのはRubyが頑張っているからで、backtrace(3)の機能ではありません。

*3 GroongaではRubyほど頑張っていないのでファイル名と行数は入っていません。

*4 昔のGDBは--eval-commandがなくてファイルにGDBコマンドを書いて渡さないといけなかったのですが、最近のGDBはコマンドラインからGDBコマンドを指定できて便利になりました。

タグ: Ruby
2013-10-31

«前月 最新記事 翌月»
タグ:
年・日ごとに見る
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|