ジョジョAdvent Calendar 7日目 ジョジョが教えてくれたこと

この記事はジョジョの奇妙な冒険 Advent Calendar 2013 - Adventarの7日目です。

土曜日中に書くつもりだったのが日曜日になってしまった…。
まあ、最終的に書けばよかろうなのだァーッ!ってことで。
ドイツ軍人は締め切りを過ぎてもうろたえないッ!


最近のジョジョでグッときたところは常秀のスタンド「ナット・キング・コール」とカツアゲロードの「オータム・リーブ」ですね。狙い過ぎ感があって、ニヤっとしてしまった。
やっぱ枯葉と言えば、ナット・キング・コールです。
ジョジョリオンスティール・ボール・ランより好きかもしれない。
やっぱ杜王町は良い。


さて、エンジニアはジョジョを読んだ方が良いと思う理由について、ちょっと書いてみようと思う。
一言でまとめて言うなら、エンジニアが持つべき精神というものと非常に親和性が高いからだ。


ジョジョの登場人物は基本的に前向きであり、過去の自分や運命を乗り越える事を非常に重視している。
これは性質が悪だろうが善だろうが変化ない。
自分自身の現状を認識し、迫ってくる運命を自分の意思で乗り越えることが重要だと表現されている。
問題があった時、それを乗り越えられるかどうかは最終的に自分の意思であり覚悟なのだ。
成長する気の無い奴は何も変わらないし何も掴めない。
成長する意思、乗り越える意思の大切さをジョジョは教えてくれるのだ。
日々、新しい技術をキャッチアップして成長し続けていかなければならないエンジニアにぴったりですね!


そして、ジョジョにおいて勝敗を決定付けるのは観察力や応用力だったりする所に、自分は面白さを感じている。
自分の能力が限られたものでも、得意とするフィールドに持ち込んだり、相手の心のスキを突くことで状況を打開する。
自分の出来ることを最大限に活かすことが大事であり、そのためには自分をちゃんと知ること、そして物事を良く観察し理解すること、それが重要であることをジョジョは教えてくれる。
エンジニアも応用の効く能力を身に付けるということが大事だということが良く分かります。


特にエンジニアにオススメしたいのは五部だ。
少人数のチームで成果を挙げるためのリーダーの在り方、自分が正しさに向かいたいという意思を持ち続けることの重要さを教えてくれる。
特に五部は台詞がカッコいい!

「覚悟はいいか?オレはできてる」
「『言葉』ではなく『心』で理解できた!」
「『覚悟』とは!!暗闇の荒野に!!進むべき道を切り開くことだッ!」
「オレは「正しい」と思ったからやったんだ。後悔はない…こんな世界とはいえ オレは自分の『信じられる道』を歩いていたい!」

そう、SIerでエクセルと格闘して悶々とした日々を過ごしていた時、「信じられる道」を歩いていける自分になりたい、とそう思ってもっとプログラマーとして生きていける道を探すことが出来たのは、ジョジョを読んでいたからと言っても過言では無いかもしれないw

周りがユニットテスト書かないとかメンバーが新しい技術に興味が無いとかウォーターフォール至上主義の上司とか、中々正しいと思う事が出来ないって話を良く聞く業界ですが、正しさに向かう意思を失ったら辿り着く可能性は失われてしまう。
自分が信じられる道を歩くこと、歩こうとすることを止めないで居たいものです。

というわけで、無理にとは言いませんが、興味はあるけどまだ読んでないよーって人は五部までは読んでみることをオススメします。


次のジョジョ Advent Calendarはjune29さんです。

「我が心と行動に一点の曇りなし。全てが正義だ…」
To be continued...

パーフェクトRubyの心残り

この記事はパーフェクトRuby Advent Calendar 2013 - Adventarの6日目です。

Rubyサポーターズの一員としてパーフェクトRubyという本を執筆する幸運に恵まれました、joker1007です。
そもそもはryopekoさんに指名していただいて途中からの協力者という形で参加しました。
私が主に担当してたのは、12章から14章までの、Rubyの周辺ツールやgem周りの部分です。

原稿が揃うまでは、仕事終わってから夜中に黙々と格闘する日々が結構多くて、中々辛いこともありましたが、形に残るアウトプットが出せたことを非常に嬉しく思っています。声をかけていただいて本当にありがとうございました!


さて、こうして世に出たパーフェクトRubyなんですが、技術書の常というか既に古くなってる情報がそれなりに存在します。
特に、発売した後になってふざけんなよ!と言いたくなるぐらいがっつり変わった代物が一つありまして…。

皆様ご存知のGitHub - capistrano/capistrano: Remote multi-server automation toolという奴です。

Capistranoの記事書くの本当に大変だったんですよ。
良く使われてるツールの割にドキュメント少ないし、技術書に動かないサンプル載せるとまずいからって、ちゃんとVMにノード3つぐらい作って一つ一つ実行して結果を確認しているわけです。時間も大分かかったと思う。

それなのにCapistrano3ですよ。
今までと全然互換性無いわ、Rails向けの機能は分離されるわ、そもそもコマンドも変わってるわで、本当ふざけんなよ!ですよ。

えー、あんだけ頑張って書いたのに、もう期限切れかよー…。と嘆き悲しみました。
マジ辛い…。
せめて、1年早く3を出しておいてくれれば…。
まあ、まだ2系は結構現役で活用されてると思うので、全く無用になったわけでは無いと思いますが。

というわけで、Capistranoについて参考にする場合には、バージョンに注意してくださいね。


後、もう一つギリギリのタイミングで載せられなかったのがGitHub - deivid-rodriguez/byebug: Debugging in Ruby 2についてです。
Ruby-2.0.0時代のデバッガーとして最近主流になってきているbyebugですが、パーフェクトRubyを執筆し終わった時点ではまだ存在を知らなかったため、デバッガーについて書いたコラムで紹介し損ねてしまいました。
そして、入稿が終わって発売までのタイムラグの中でbyebugについて知りました。
byebugを利用し始めたのはそれなりに早い方でしたが、後1ヶ月早く知ってればなあ、と思ったものです。

2.0系のRubyを使っていてデバッガーを探している方は、まずbyebugを使ってみるのが良いと思います。


心残りを吐露する機会があって、少し気が済んだかなw
次のAdvent Calendarはyui-knkさんです。よろしくお願いします。

[Ruby][Redis]オブジェクトをredisにキャッシュしたり検索したりするConcernを表現するgemを作った
Concernスタイルなモジュールを作ってみたかったので、Redisのキャッシュ機構をActiveSupport::Concernを使ってそれっぽくなるように書いてみた。
元々仕事で書いたコードだったけどちょっと直せば汎用化できそうだったので、夜なべしてgem化してみた。

GitHub - joker1007/redis-cacheable: It is concern style redis caching helper. It makes very easy to cache object.

使い方はこんな感じ

class MyObject
  include RedisCacheable

  attr_reader :id, :name

  redis_key   :id          # optional (default: :id)
  redis_attrs :id, :name # method names

  def initialize(attributes)
    @id = attributes[:id]
    @name = attributes[:name]
  end
end

class ProcObject < MyObject
  redis_attrs ->(obj) { obj.id * 10 } # can give proc
end
my_object = MyObject.new(id: 1, name: "my_object")
my_object.cache_to_redis # KEY = my_object.id, VALUE = MultiJson.dump({"id" => my_object.id, "name" => my_object.name})

MyObject.find_from_redis(1) # => {"id" => 1, "name" => "my_object"}

proc_object = ProcObject.new(id: 1, name: "proc_object")
proc_object.cache_to_redis # different namespace with MyObject
ProcObject.find_from_redis(1) # => 10

もし、どこかで使えそうな機会があったら検討してみてください。

デフォルトでは新しくredisのコネクションプールを生成しますが、既にredisのコネクションが存在するならそれを再利用することができます。

RedisCacheable::Connectable.redis_connection = $redis # $redis is Redis instance or ConnectionPool

Vimにmrubyインターフェースを組み込んでみた

週末の遊びとして、Vimにmrubyインターフェースを組込む実験をしてみた。
ほとんどCで書いた経験が無いので、出来るかわからんなーと思っていたが、構文を実行するだけなら何とか実現できたので、とりあえずまとめておく。
ほとんどmrubyというよりVimの話なんだけど。

mrubyについて調べる

流石にもう試してる人は結構居るみたいなので、mrubyをCのプログラムから実行して結果を取得するのはすぐに分かった。
しかし、なんかいくつかパターンがあるっぽいので繰り返し実行するのに良さそうなのをチョイス。
実行方法の違いが良く分かってない。

#include <mruby.h>
#include <mruby/compile.h>
#include <stdio.h>

int main() {
  mrb_state *mrb;
  mrbc_context *cxt;

  mrb = mrb_open();

  if (mrb == NULL) {
    printf("Error\n");
  }

  cxt = mrbc_context_new(mrb);
  mrb_load_string_cxt(mrb, "puts \"Hello, world\"", cxt);

  mrbc_context_free(mrb, cxt);
  mrb_close(mrb);
  return 0;
}

Vimのif_ruby.cを読む

RubyのコードをCに組込む方法はある程度知っているので、Vimがどういう作法でそれを読んでいるのかを調べる。
マルチプラットフォームな分岐が混じっていて非常に読みづらかったが、要はensure_ruby_initializedという関数で、ruby_init_stack()とruby_init()を読んで、load_pathを設定し、vimとやりとりするオブジェクトを仕込んでいるらしい。
そして、呼び出しのキック元はex_ruby()とかex_rubydo()とかの関数で、それぞれがVimの:rubyコマンド等に対応している。
その対応関係は、ex_docmd.cとかex_cmds.hあたりで定義されている。


ensure_ruby_initializedはこんな感じの関数。

static int ensure_ruby_initialized(void)
{
    if (!ruby_initialized)
    {
#ifdef DYNAMIC_RUBY
	if (ruby_enabled(TRUE))
	{
#endif
#ifdef _WIN32
	    /* suggested by Ariya Mizutani */
	    int argc = 1;
	    char *argv[] = {"gvim.exe"};
	    NtInitialize(&argc, &argv);
#endif
	    {
#if defined(RUBY19_OR_LATER) || defined(RUBY_INIT_STACK)
		ruby_init_stack(ruby_stack_start);
#endif
		ruby_init();
	    }
#ifdef RUBY19_OR_LATER
	    {
		int dummy_argc = 2;
		char *dummy_argv[] = {"vim-ruby", "-e0"};
		ruby_process_options(dummy_argc, dummy_argv);
	    }
	    ruby_script("vim-ruby");
#else
	    ruby_init_loadpath();
#endif
	    ruby_io_init();
	    ruby_vim_init();
	    ruby_initialized = 1;
#ifdef DYNAMIC_RUBY
	}
	else
	{
	    EMSG(_("E266: Sorry, this command is disabled, the Ruby library could not be loaded."));
	    return 0;
	}
#endif
    }
    return ruby_initialized;
}

:mrubyコマンドを動かせるようにする

マルチプラットフォームとかはとりあえずスルー。
Vimとのデータのやり取りも置いといて、:mrubyコマンドで構文を実行する所までを目指す。

#ifdef HAVE_CONFIG_H
# include "auto/config.h"
#endif

#include <stdio.h>
#include <string.h>

#include <mruby.h>
#include <mruby/proc.h>
#include <mruby/compile.h>

#include "vim.h"
#include "version.h"

static int mruby_initialized = 0;
static int ensure_mruby_initialized(void);
static mrb_state* vimMrb;

void ex_mruby(exarg_T *eap)
{
    char *script = NULL;
    mrbc_context *cxt;

    script = (char *)script_get(eap, eap->arg);
    if (!eap->skip && ensure_mruby_initialized())
    {
      cxt = mrbc_context_new(vimMrb);
      if (script == NULL) {
        puts((char *)eap->arg);
        mrb_load_string_cxt(vimMrb, (char *)eap->arg, cxt);
        mrbc_context_free(vimMrb, cxt);
      } else {
        EMSG(_("no mruby script"));
      }
    }
    vim_free(script);
}

static int ensure_mruby_initialized(void)
{
  if (!mruby_initialized)
  {
    vimMrb = mrb_open();
    mruby_initialized = 1;
    return mruby_initialized;
  } else {
    return mruby_initialized;
  }
}

void mruby_end()
{
  mrb_close(vimMrb);
}


非常に適当だが、とりあえずif_ruby.cからコードの構造をパクってきてでっち上げた。


続いて、ex_cmds.hとex_docmd.cを弄る。

diff -r f6cacdc34495 src/ex_cmds.h
--- a/src/ex_cmds.h	Wed Aug 07 21:13:23 2013 +0200
+++ b/src/ex_cmds.h	Sun Aug 11 16:00:41 2013 +0900
@@ -785,6 +785,8 @@
 			NEEDARG|EXTRA|NOTRLCOM),
 EX(CMD_runtime,		"runtime",	ex_runtime,
 			BANG|NEEDARG|FILES|TRLBAR|SBOXOK|CMDWIN),
+EX(CMD_mruby,		"mruby",		ex_mruby,
+			RANGE|EXTRA|NEEDARG|CMDWIN),
 EX(CMD_ruby,		"ruby",		ex_ruby,
 			RANGE|EXTRA|NEEDARG|CMDWIN),
 EX(CMD_rubydo,		"rubydo",	ex_rubydo,
diff -r f6cacdc34495 src/ex_docmd.c
--- a/src/ex_docmd.c	Wed Aug 07 21:13:23 2013 +0200
+++ b/src/ex_docmd.c	Sun Aug 11 16:00:41 2013 +0900
@@ -289,6 +289,9 @@
 # define ex_rubydo		ex_ni
 # define ex_rubyfile		ex_ni
 #endif
+#ifndef FEAT_MRUBY
+# define ex_mruby		ex_script_ni
+#endif
 #ifndef FEAT_SNIFF
 # define ex_sniff		ex_ni
 #endif


mrubyをちゃんと片付けられるように、mruby_endの呼び出しをmain.cに加える。

diff -r f6cacdc34495 src/main.c
--- a/src/main.c	Wed Aug 07 21:13:23 2013 +0200
+++ b/src/main.c	Sun Aug 11 16:00:41 2013 +0900
@@ -1478,6 +1478,9 @@
 #ifdef FEAT_RUBY
     ruby_end();
 #endif
+#ifdef FEAT_MRUBY
+    mruby_end();
+#endif
 #ifdef FEAT_PYTHON
     python_end();
 #endif


関数のプロトタイプ宣言を追加するために、proto/if_mruby.proを作成。

diff -r f6cacdc34495 src/proto/if_mruby.pro
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto/if_mruby.pro	Sun Aug 11 16:00:41 2013 +0900
@@ -0,0 +1,4 @@
+/* if_mruby.c */
+void mruby_end __ARGS((void));
+void ex_mruby __ARGS((exarg_T *eap));
+/* vim: set ft=c : */


ヘッダの読み込みを追加する。

diff -r f6cacdc34495 src/proto.h
--- a/src/proto.h	Wed Aug 07 21:13:23 2013 +0200
+++ b/src/proto.h	Sun Aug 11 16:00:41 2013 +0900
@@ -196,6 +196,9 @@
 # ifdef FEAT_RUBY
 #  include "if_ruby.pro"
 # endif
+# ifdef FEAT_MRUBY
+#  include "if_mruby.pro"
+# endif
 
 /* Ugly solution for "BalloonEval" not being defined while it's used in some
  * .pro files. */


後はせっせとautoconfのスクリプトを弄って、--enable-mrubyinterpみたいなオプション足したり、FEAT_MRUBYを定義したり、って感じでコンパイルをでっち上げる。


実際には、autoconfを弄る前に手動でMakefileを直で弄ってコンパイル通らねー、と頭を悩ませたりしてた。
一通り通って動かせるようになってからautoconfを弄っている。


結果、こんな感じでconfigureしてコンパイルすれば動くようになった。

% ./configure --with-features=huge --enable-multibyte --enable-luainterp=yes --with-luajit --with-lua-prefix=/usr/local --enable-rubyinterp=yes --enable-mrubyinterp=yes --with-libmruby=/Users/joker/mruby/build/host/lib/libmruby.a --with-mruby-include=/Users/joker/mruby/include
% make




なんか表示が狂ってておかしいけど、とりあえず実行出来てるっぽい。
パっと見:rubyコマンドと何も変わらないので、少し寂しいが結構楽しかった。


出力はさておき、Vim側とのインターフェースをちゃんと書けば、mrubyでvimプラグインとか書けるかもしれないし、mrbgemsの資産使えたりするんじゃね?とちょっと思っている。
が、そこまでやる気が続くかは分からないw
正直、C書いたりautoconf弄ったりするの辛い…。LLerには厳しい世界であった。
ぬるま湯最高!


編集差分のgistは → https://gist.github.com/joker1007/6203801

TDD Anti-patterns catalogue at Stack Overflow を簡単に訳してみた

Stack OverflowのTDD Anti-patterns catalogueというスレがとても面白かったので訳してみた。


Stack Overflowのvoting機能でアンチパターンへの投票を行っている感じ。
上から投票の多い順になっている。


得票数はこの記事執筆時点(2013.7.9)のもの。
SQLアンチパターンっぽく、パターン名はそのまま片仮名にしてみた。
また、内容がかなり被っているとか、状況がかなりレアじゃないかと思うものは、一部省略しました。

(ブコメで訳間違ってるよ、って教えてもらったので、一部修正しました 2013.7.10)

フリーライド (テストのただ乗り) 50pt

新しいテストケースを書くのではなく、他の機能のテストに新しいアサーションを追加して既存のテストケースに乗っかる。

セカンドクラス シティズン (二等市民) 47pt

プロダクションコードのようにリファクタリングされないテスト。大量の重複やメンテしづらいテスト達。

ハッピーパス 42pt

正常系のハッピーパスだけテストされており、例外や境界値のテストが無い。

ローカルヒーロー (御当地の英雄) 42pt

特定の開発環境に依存したテストケースが存在し、誰かが別の環境で実行するとテストは失敗する。

ヒドゥン ディペンデンシー (隠された依存関係) 42pt

ユニットテストがいくつかのデータが存在する事を前提に書かれており、前提条件が名言されていない。もしデータが適切に準備されていないとテストが落ちる上、適切なエラーメッセージが表示されない。

チェイン ギャング (ギャングの序列) 41pt

あるテストケース同士の組み合わせを特定の順序で実行しなければならない。一つのテストがグローバルな状態(グローバル変数、データベースのレコード)を変更してしまい元に戻さない。
データベースのロールバック漏れ等で良く見られるケース。その他、グローバルな状態を操作する時にtry/catchでラップする事を忘れている場合等にも発生する。

ザ・モックリー (モック過剰) 37pt

テストケースが大量にモックやスタブを含んでおり、実際の挙動では無くモックが返す値をテストしている状態。
(コメントで、レイヤー同士の依存関係が多過ぎる事が原因と考えられるので、リファクタリングしなければいけない状態であると指摘されている)

サイレント キャッチャー (沈黙のキャッチ) 32pt

もし例外が投げられた時に通過して欲しいテストケースがあった場合、その例外が開発者の意図と異なる形で発生してもテストが通ってしまう状態。例えば、期待する例外の型を広く取り過ぎて、意図していない例外もキャッチしてしまっている場合。

アナル プローブ (ケツの穴の検査) 25pt (← Good Naming!!)

あるテストが普通ではなく非常に不健康な方法で実行されている場合。例えば、プライベートなフィールドを読むためにJavaのsetAccesibleを利用したり、クラスを拡張したりテストコードを特定のパッケージに組込む等。このパターンが見られる時は、データを過剰に隠蔽し過ぎている可能性がある。

インスペクター (観察者) 24pt

コードカバレッジを100%にするためにカプセル化の原則を破壊している。

イクセッシブ セットアップ (準備過剰) 23pt

テストケースの事前条件を準備するために、数百行のコードや環境の準備をしなければならない状態。テストにノイズが多くなり本当に検証したい事が分からなくなる。

テスト ウィズ ノーネーム (名無しのテスト) 19pt

バグトラッカー等から書き起こされたテストケースに、具体的な名前が付けられていない状態。例えば'testForBug123'のように。時間が経ってからテストが落ちた時、バグチケットを見るまでその意図が分からなくなる。

スロウ ポーク (のろまなツッコミ) 17pt

ユニットテストの実行が信じられないぐらい遅い状態。開発者はテスト開始をキックした後、トイレに行ったり煙草を吸いにいったりする。ひどい場合は、帰宅する前のその日の終わりにテストを実行する事になる。

インアプロプリエイトリー シェアード フィクスチャー (不適切なフィクスチャーの共有)

複数のテストケースがsetup/teardown処理に必須ではないフィクスチャーを共有している。新しいフィクスチャーを用意するのをサボっている状態。

ザ・ジャイアント (巨人テスト) 15pt

あるユニットテストがめちゃめちゃでかい。実質的に大量のテストケースを含んでしまっている。これは所謂「神クラス」の兆候でもある。テストコード自体にバグが入り込む可能性も高くなる。

ザ・バタフライ (バタフライエフェクト) 14pt

頻繁に変更されるデータを含んだものをテストしなければならないのに、結果を固定値に落とし込む方法が無い状態。例えば現在時刻等を含む構造。出力結果に注意を払わないテストケースになってしまう。

フリッカリング テスト (ちらつき) 13pt

落ちたり落ちなかったりするテスト。特定の時刻ではなく、状態競合等によるもの。典型的には非同期処理に対するテストで発生する。

ウェイト アンド シー (待機、そして観測) 12pt

実行結果を取得するために、一定期間のウェイト処理を挿入し、その後に値を取得するテスト。例えば「Thread.sleep」で待ってから値を確認する等。低スペックの環境や、利用の激しいCIサーバー等でテストが失敗する可能性がある。

フォーティ フット ポール 10pt

テストしようとしているクラスとの結び付きを恐れる余り、過剰な抽象化やレイヤーでロジックを分離しようとする。そのせいで、とても脆く壊れやすいテストになってしまっている状態。

ビリーブ イット ウェン アイ シー (見るまで信じない) 9pt

本当のユーザーのようにテストしようと、無理やりGUI経由でテストを実行しようとする。ビジネスロジックのテストがGUIと結びついていると、GUIの変更で数多くのテストケースが破壊されてしまう事になる。

エンヴァイラメンタル ヴァンダル (環境の侵略者) 9pt

テスト実行のために、環境変数や特定のTCPポート等が必要になる場合。利用できないポートがある時はテストが失敗する。テストで利用するポート番号等がハードコードされていると、同時に複数環境向けのテストを実行した時にテストが失敗する事になる。

スリーパー (休火山) 9pt

未来のある日時が訪れた時に失敗してしまうテスト。日付やカレンダーに関わるロジックで発生する。
「このコードは2000年より前に書き直されるだろう」 1960年代の多くのプログラマーの言

カッコー (カッコウの鳴き声) 9pt

あるテストケースが他のいくつかのテストケースに依存している状態。他のテストと同じsetupメソッドを使っているにも関わらず、その成果物を捨てている。
インアプロプリエイトリー シェアード フィクスチャーの一例。

チューリング テスト 8pt

なんらかの効果なツールが魔法のように自動生成したテストケースが多数存在する。

デッド ツリー 8pt

スタブが生成されているが、そのコードの実装が無い。

ウェット フロア 5pt

テストが生成したデータがどこかに保存され、テストが終了した時に適切にクリーンアップされていない状態。テストを続けて実行すると失敗する可能性がある。例えば、tempディレクトリにファイルを保存するようなテストを別々の実行ユーザーで実行した時、パーミッションの問題で適切にデータが削除されない事があり、テストが壊れてしまう。

自宅サーバをHaswell機に更改 VT-dとかを試す

夏前にPCが二台ぶっ壊れてしまい、流石にそろそろ新しいマシンを組もうと久々にパーツまとめて買って自作する事にした。


せっかくなので出たてのHaswellを使ってみることに。


CPU: Core-i7 4770 (4770KはVT-dが無効になってるので)
MB: ASUS Z87-PRO
MEM: 32GB (8GBx4)
Intel SSD 520 240GB
まとめ買いの割引で大体総額10万弱ぐらいかな。


後はヤフオクで、IBM ServeRAID M1015を落札して購入。
以前買ってOpenIndianaでの稼動実績があるし、オクなら1万円しないので。
SASの口二つあって、SATA8台直で刺せるしSolarisでも動く。
新品でLSIのHBA買うと3、4万ぐらいかかるので、かなりお得。
とりあえず、ITファームウェアに書き換えて利用する。


その後、稼動してた自宅のストレージサーバを解体して、HDDを全部繋げ替えた。
12台を抜いて繋ぎ替えるのにめっちゃ疲れた。


以前からVMWare ESXiを利用していたので今回もESXiを入れる事にする。
KVMとかで運用しようかとも考えたが移行と管理が面倒だった。


ファームウェアを書き換えたServeRAIDを二枚刺して、VMWare ESXiのPCIパススルーの設定を行う。
これでRAIDカードが直接VM上のOpenIndianaに見えるはず。
HDDの認識は簡単に上手くいったので、後はzfsをimportすればほぼ移行は完了。
今回はこれが一番やりたかった。


別々になってたストレージサーバとVMサーバを集約したのでPC1台で済むようになった。
しかも動画のエンコード速度が倍ぐらいになって、最近のCPUのパワーを思い知った。
後、GentooVMが10秒ぐらいで起動するようになった。IntelSSDすげー。


実は作ってる途中メモリ16Gで動作確認し、後から16G追加したらマザボがぶっ壊れてしまい、初期不良の交換に行くというハイパー面倒なことになってしまった。
既にケースに入れてネジ止めしちゃってるしHDDも13台繋いだ後だったのに…。
おかげで、かなりの肉体労働をする羽目になったし、移行がちゃんと完了するのに2週間ぐらいかかった…。
やっぱ、自作は結構面倒だなーと思う。
とは言え、極端なマシン構成だと自作で組むのが一番安いのでどうしようもない。

RubyhirobaでのLTの謝罪と、表現の自由と不快感と社会性について

ちょうど、この一つ前の記事について書いた事を余りにも正直にLTで話してしまった事についてです。

Rubykaigi本編でのジェンダー発言については、私は聞いておらず良く分かりませんので、そちらの話はしません。

私の話は、非常に幼稚で多くの人に不快感を与えたことについては、完全にその通りであり、謝罪するしかありません。
申し訳ありませんでした。


当事者として、多少思う事があるので、いくつかツイートしましたが、Twitterで書いてると、断片的になって誤解を生んでしまうので、ちゃんと文章としてまとめておきます。
意図とは違う受け止め方をしているかもしれませんが、ただ謝罪するだけで何も言わない事はむしろ不誠実だと思うので、自分なりに考えた結果を書いています。


私は、どういう内容を語ろうが、どういう表現方法を使おうが、人を不快にさせる時は不快にさせるし、傷つけることもあると思っています。
現実的に損害を被る事もあるかもしれません。
ただ、人が不快に感じるからというだけでは、発言を他の誰かが差し止めることはできない。そんな事やってると、誰も一言も喋れなくなります。
本来は、人は何をどういう口調で語ってもいいものです。


とは言え、表現内容によっては実際に辛い思いをし、不利益を被る人が居るわけで、「自由」が衝突している状態になることもあります。
上手くやるには、どちらかの「自由」を制限しなければならない。
表現内容によって損害を被る人が一定割合を越えた時、社会の要請によって構成員の代表である国家がそれを規制することもあります。
人は、それぞれが「自由」であり、人として尊重されるべき存在であるが、その多様性のためにお互いが上手くやっていけない事が沢山ある。
その中で、より多くの人が自由である世界を実現するために、共通の価値観に基いて自由が制限されていきます。


人はその多様性によって衝突するため、自分の立場を肯定する話は、それが何かを蔑ろにするものであっても、その事に気付かない事があると思います。
ある種のジョークもそういう要素を持ち合わせています。
難しいのは、自分自身の立場やその場に存在している価値観が、社会的な規範と常に一致するとは限らないことです。
人間のコミュニケーションが全て社会の規範に則った内容であるなんてことはありえないし、そうである必要もないと思います。
そういう意味で、全ての表現は社会の価値観にそぐわないものである可能性があり、場の状況と表現内容次第でどうにでも変化する問題なのだと思っています。


一方で、今日の社会において最も尊重されるべき考えというものがあります。その一つが性別に関わる事です。
そうなっているのは、過去に多くの問題があり、実際に多くの権利が奪われるまでに至ったものだからです。
だからこそ、最も重要なものとして考えなければならないものです。
とりわけ国際的な場で繊細に扱われるのは、文化や価値観の違いが色濃く出る側面があるからだと思います。
政治、法律が身近な国では、我々から見れば過剰とも言える程の配慮が求められています。
こういった権利を蔑ろにする表現は、あらゆる場で不適切とは限りませんが、公の場で許容する事を決して認めてはならないものです。
私は、それを破ってしまった。許容するべきでないのは当然の事だと思います。
敢えてそういった価値観に言及する事で、議論を進めたり、対象を絞ったジョークとする事も世の中にはあると思いますが、それには事前に状況をしっかり構築しておく必要があります。


一つ言っておきたいのは、表現の内容そのものが問題ではないということです。私はそう思っていません。
私が、自分自身で最も問題だったと思っているのは、内容そのものよりも誰の承認も得ずに実行した事です。
非常に卑怯であり、危険な行為だったと思います。
最悪、訴訟沙汰になる可能性もあるでしょう。
その場の判断で行われる事こそ、最も注意しなければならないことです。
人には娯楽を享受する権利もあるし、不快なものから目を背ける権利もある。
でも、それを完全に行う事はできない。
どうやっても世の中には自分の許しがたいものが存在して、それを見なきゃならない事がある。
自分が楽しみにしていたものが、ある日突然禁止されて弾圧の対象になる事がある。
お互いがそれぞれの立場を想像して、現実的な判断で交渉する事が必要です。
私は、そのための努力を欠いた行いをしました。
自分の世界だけが全てじゃないことを忘れ、傷付く必要の無い人を傷付けた事は恥ずべきことです。


本来、人は何を思ってもいいし、何を喋ってもいいはずです。
ただ、それが適切かどうかは、社会やその空間が決める事です。
極端な話、500年前の世界で人種差別的な発言や性差別的な発言をした所で、大した影響はなかっただろうと思います。そんな共通の概念も無かったしょう。
今迄の歴史の中で獲得してきたものによって、たまたま今日ではそうなっているという事です。
大事な事は、人は共同体の中で生きている事を忘れないでいることです。
共通の認識として存在する価値観をちゃんと知って、それを守って生きていくのが、この社会の構成員として成熟した一人であるということです。
私は、いただいた指摘をそう受け止めました。
発してくれた人が、そういう考えをしてるかは分かりませんが。


ポルノ云々の捉え方については、世の中には男性が消費される側にまわる事もあるわけで、実際にそれについて私が言及できるかっていうと、中々難しいと思う事もあります。
全体としてどっちが辛い思いをする事が多いかは言うまでもないことですが、最終的には多い少ないの話です。
ジェンダーに関わる事だからどうこう、ポルノに関わるからどうこう、ってわけではなくて、その他のマイノリティはどうなんだ、って事をちゃんと考えなきゃいけない。
女性の中にだって、そういう話題を語る権利も場所も存在するわけで、場が適切であるかないか、という問題です。
常にどちらか一方が弱者であるとは限らない。自分自身の今いる状況と関係無く評価される表現もありえない。
今までの人生で、一度もその場に居ないマイノリティの存在を貶める発言をした事無い人なんて、ほぼ居ないでしょう。
本当に常に一切言及する事が許されない話なんてものは、世の中にない。
最終的には状況が決める事、そういう意味で濃淡の問題なんだと私は思っています。
もちろん、誰もそこまで言ってるわけじゃないのは分かってます。


私が馬鹿だったのは、表現内容ではなくあの場でそれを行ったことです。
公の場で話してよい内容かどうかを自分勝手に判断した事です。
自分の知らない誰かの感情を真剣に考えなかったことです。他者との関わりを忘れたことです。
その結果として、対等の人間を排斥される弱者に貶めた事です。恥ずべきことだと思います。


長々と色々書いたのは、自分なりに真摯に受け止めて、色々考えてみた結果です。
考え方の相違を感じる点はありますが、全面的にご指摘いただいた方が正しいと思っていますし、敬意を持って受け止めています。


私は非常に愚かな子供だったと、改めて認識しました。反省しています。
多くの関係者の方にご迷惑をおかけしたかもしれないことについて、改めて謝罪いたします。
本当に申し訳ありませんでした。