2015年10月28日水曜日

続・コメント

自身が以前、ある開発者組織の研修を経験したときに、おもしろい経験をしたので参考までに紹介したいと思う。
それはコメントに関する指針についてのレクチャだった。まず、例題としてごく簡単なクラスをひとつだけ実装して、その内容に応じたコメントを記述したもらった。
対象はヘッダからはじまって、コンストラクタ、フィールド、パブリックアクセサ、パブリックメソッド、プライベートメソッド、プロクテッドメソッド、そして デストラクタ。
奇妙なことに判を押したようにそれらのコメント群の記述、粒度、文言は一致していた。そのときの生徒数はおよそ15名。この程度の人数だと思うかもしれないが、この統制のとれたコメントのノーテーションには、非常にびっくりした記憶がある。驚いたというのは、とても優秀な成績だったということではなく、この奇妙な統制についてだ。
ある意味、これだけの人数のチームで、これだけの統一感があるというのは、とても望ましいことだと思う。しかし、自身が思ったのはまったく違った。
実際的なコメントを読むと、自身の水準に照らし合わせれば、悪くはないが合格点はあげられない出来だった。

何が問題なのか?

一般的にコメントは適度な粒度が必要だ。シンプルに、かつ、必要にして充分な情報を提供できなくてはならない。もちろんこれは本質ではあるが、一朝一夕で記述できるほど甘くはない。
まず、考えなくてはならないのは、文脈に即した情報を網羅できているのか? つまり、構造のコンテキストに応じた言葉の選択や論理で貫かれているだろうか? というのが第1のポイント。
2つ目に、よく考えてほしいのは、果たしてこのコメントを読んで3週間後の自分は理解できるだろうか? 半年後の自分は理解できるだろうか? そして未だ見ぬ未来の実装者は、ここから必要な情報を得られるだろうか?
読めばわかる、という考え方は実は閉ざされた地平でしか通用しないある種の文明なのだ。共通基盤と一定水準の知識があってはじめて成立する、いわば方言、地方言語でしかない。
コメントはローカルであってはならない。参考までに、プロプライエタリ系の言語世界では、よくローカルな方言に陥りがちだ。もちろん、これは経験的に感じた傾向ではある。

翻ってオープンソースの世界はまた違った側面を持っている。誰に強制されるわけでもなく、コメント文化は成熟しているのが常だ。もちろんすべてのソースコードがそういうわけではないが、傾向としてグローバルな文化が根付ているように見える。これは、コメントという小さな視点だけではなく、実装やプロジェクトの運営方針に対して極めて規範的な空気感が常に流れているからではないだろうか? と思うことが多い。
自らを律する。この地平で初めて他人のための仕事も成熟を遂げるのではないかと考えている。

2015年10月26日月曜日

ダメなコメント

「予約情報をチェックする」

というコメントがあったとする。

メソッドを見ると

CheckResavationData() : bool

とある。
メソッド名を見れば予約の情報をチェックしているのだろう、という察しがつくし、その結果を論理型で返すのだろうな・・・

という見当もつく。
それで? 結局、このメソッドは何をするのか? そしてどんな結果を返すのか? は不明だ。

予約情報の有無を調べているのか?
または、妥当性をチェックしているのか?
依然として不明だ。何より文脈がわからないのでどのように扱えばよいのかという点で理解はできない。

問題は、メソッド名の直訳的な説明しかコメントからは読み取れない。それ以上の情報は得られないのだ。
このメソッドを含むクラスはブラックボックス化されていて中の実装は気にしないでよい、ということを示唆しているわけだが、これでは上位の呼び出し側からはどんな論理を記述すればよいのかわからない。
世の中にはこういうコメントやメソッドが溢れている。

これは英語圏の表現からはかなり遠い(何しろ Far East なわけだし・・・)ところに本拠を置く我々の致命的な弱点なのかもしれない。では、仮に日本語でメソッド名を付けましょう、という運動でも展開すれば、この手の問題は解決するのだろうか?

2015年10月21日水曜日

expressでHTMLを直接扱う

今回も Node.js における expressフレームワーク の小ネタを。
一般的には、あるいは、モダンにHTMLを構築してレスポンスを返すという点では、既にこのフレームワーク は充分に洗練された機能を持っていると思います。
それは、たとえば、JadeのHTMLコンバータだったり ejsのテンプレートエンジンだったりするわけです。 しかし、これらの機能を使いこなすには従来のHTMLに関するパラダイムシフトがある程度は必要なわけです 。
この部分の考え方は、モダンであると同時にシンプルでもあるし効率的でもあるとも思います。
ただ、このシフトがいまひとつピンと来ない人や、これらのテンプレートの表現になじめない人もいると思 います。
そこで、今回はHTMLを直接扱う方法の紹介です。
ちなみに、Jadeやejsとは何か? ということに少し説明を加えようと思います。

Jadeは、HTMLからタグを取り払いインデントの階層でドキュメントを表現し、その構造をJadeテンプレートに投入してHTMLに変換する機能です。
コードとしては以下のような雰囲気になります。

extends layout

block content
  h1= title
  p Welcome to #{title}

  h3 BootStrap3 Sampler
  ul
    li: a(href="./bootstrap-nav") ボタン・サンプル

リクエストで受け取ったパラメータから title という文字列を取り出して画面に表示します。加えて上記の例では Bootstrap3 を装飾として使用しています。
ejsは、もっとHTMLそのものに近く直感的にわかりやすいと思います。それは、たとえば NetFrameworkの ASP.NET MVC で採用されているスキャフォールディングや、Ruby on RailsのViewの構造に近いとも言えます。

さて、本題に戻ります。
目標はHTMLの表現でViewを作り、そのままレスポンスとして返す方針の解決法です。

package.json に ejs のモジュールを追加します。
"ejs": "latest"

続いて

$ npm install

これで ejsモジュールがプロジェクトに追加されます。

app.js に以下を記述します。

app.engine('htm', require('ejs').renderFile);
app.engine('html', require('ejs').renderFile);

後は、個別に js ファイルにRESTを作成します。例えば下記のようにです。

router.get('/', function (req, res) {
    res.render('index.html', { title: 'Express' });
});

ここで出現した index.html はHTMLのルールに基づいて作成したファイルです。
これで素のHTML構造を返すことが可能になります。

2015年10月16日金曜日

コンテナ・インジェクションのアンチパターン

以前 C#におけるインジェクションテクニックのうち、Bastard Injection の紹介をしましたが、今回は Late Binding の手法を使ってみようと思います。
2000年代半ばの Java のフィールドでは数多くのプラクティスが生み出されましたが、他ならないリフレクションの最も基本的な実装方法とも言えます。
Spring framework では、最も洗練されたDIコンテナ(依存性の注入)の運用が編みだれました。
その中心的な考え方は、実装とインスタンスの生成を完全に切り離してしまうものです。それを今回はC#で試してみようという寸法です。

まずは、プログラムのインタフェース規約を定義します。

namespace Sample.DISampler.Injection
{
    interface IMessageWriter
    {
        void Execute();
    }
}


続いて、規約に基づいた実装です。

namespace Sample.DISampler.Injection
{
    public class ConsoleMessageWriter : IMessageWriter
    {
        public void Execute()
        {
            Console.WriteLine("OK!");
        }
    }
}


さて、コンフィギュレーションでは、検索のkeyとなるキーワードに対して、valueにコンテナ実装をフルネームで記述します。

<appSettings>
    <add key="InjectMessage"
         value="Sample.DISampler.Injection.ConsoleMessageWriter"/>
</appSettings>

最後に呼び出し方法です。

var typeName = ConfigurationManager.AppSettings["InjectMessage"];
var type = Type.GetType(typeName, true);
IMessageWriter writer =
(IMessageWriter)Activator.CreateInstance(type);
writer.Execute();


つまり、設定ファイルに記述された文字列から対応するクラスをインスタンス化して実際に動かすという目論見です。
動くまでは、どんな型になるのかは決まりません。
クラスの依存を動的に解決するわけです。

2015年10月13日火曜日

Vagrantfile で仮想環境を生成しよう

先日、Vagrantを使いコマンドラインから仮想環境を生成する方法を紹介しましたが、今回は、Vagrantfileに仮想環境の作成手順書を記述することにより、仮想インスタンスを生成する方法を書いてみようと思います。
Vagrantfile というのは、作成したい仮想環境をテキストとして記述しておくことにより、生成状態が常に一定の結果が期待される、いわゆる Infrastructure as Code の中心的な考え方を実現する手法です。
当然、ターミナルを開いてコマンドラインで1ステップづつ実行する場合と同じ結果が得られることを目標とするわけですが、結果を得るまでの品質がまったく違います。
コマンドラインの実行は誤りを犯しやすいわけですが、コードとして実行手順を記述すると、結果は常に同じになるわけです。
加えて、最も大切なポイントとして、環境を構築するコードは、実際的な「手順書」になるわけです。ここは、ぜひとも押さえておいてください。

では、Vagrantfle をまず作成します。
そのまえに、VirtualBox と Vagrant が導入してある前提です。OSは何でもよいと思います。自分の環境で構いません。
任意のディレクトリで以下のコマンドを実行します。

> vagrant init

この結果、Vagrantfile が作成され、あらかじめ必要なひな形は既にできています。
そこで、内容を以下のように編集します。

# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

  config.vm.box = "centos65"
  config.vm.box_url = "https://github.com/2creatives/vagrant-centos/releases/download/v6.5.3/centos65-x86_64-20140116.box"

  config.vm.hostname = "vagranthost"
  config.vm.network "forwarded_port", guest: 80, host: 8080
  config.vm.network "private_network", ip: "192.168.33.10"
  config.vm.network "public_network"

  config.vm.synced_folder "host", "/guest"
  config.vm.provision :shell, :inline => "echo hello world"
  config.vm.provision :shell, :path => "provision.sh"
  config.vm.provision "file", source: "test.html", destination: "/guest/test.html"
end

do ~ end までがひとつの括りです。
では、ひとつづつ見ていきます。

config.vm.box_url
ここには、仮想環境を生成するうえで基になるBoxの入手先のURLを記述します。
以前も書いたように Vagrantbox.es などから、使用するOSイメージの入手先をコピーするのが簡単です。
例では、CentOS 6.5 のイメージを使用します。
そして config.vm.box には、任意の名前をつけます。

つづいてネットワークの設定です。
ホスト名にしたい任意の文字列を設定します。ここでは”samplehost ”という名前にしています。
config.vm.hostname = "samplehost"

ポートのフォワード設定には、ホストOSとゲストOSのポートの転送を設定します。
たとえば、ゲストOSの80番ポートをホストOSの8080に転送する場合、次のように記述します。
この設定を行うと、ホストOSでlocalhost:8080にアクセスすると、ゲストOSの80番ポートにアクセスできます。
config.vm.network "forwarded_port", guest: 80, host: 8080

ゲストOSにプライベートネットワークを設定します。
この例の場合、ホストOSから192.168.33.10のプライベートアドレスで、ゲストOSにアクセスできます。
config.vm.network "private_network", ip: "192.168.33.10"

ゲストOSにパブリックネットワークを設定できます。
プライベートネットワークの設定と同じようにStatic IPを指定できますが、次の例のようにIPアドレスを指定しなかった場合は、ゲストOSにホストOSと同じネットワーク環境でDHCP用のIPアドレスが設定されます。
config.vm.network "public_network"

ホストとゲストでディレクトリを共有します。
通常、Vagrantfileを置いたディレクトリがゲストから見ると /vagrant になります。
下記の例では、Vagrantfileを配置したフォルダに”host”フォルダを作成しました。
次にVagrantfileに以下の設定を行います。これにより、ホストOSの”host”フォルダとゲストOSの” /guest”が共有されます。
config.vm.synced_folder "host", "/guest"

プロビジョニング設定では、仮想環境構築時にあらかじめ用意しておいたシェルスクリプトを実行したり、ファイルを配置したりできます。
また、Chefなどの他のプロビジョニングツールと連携して環境を構築できます。
下記の例はもっともシンプルなシェルスクリプトによるコマンド実行の例について説明します。
まず、Vagrantでシェルを実行するには、config.vm.provision :shellを設定します。
例では、シェルをinlineで実行し、コンソールに”hello world”を出力する例です。
config.vm.provision :shell, :inline => "echo hello world"

実行したいコマンドを別ファイルに書いて一括で実行することもできます。
次の例では、"provision.sh"というファイルに書かれたコマンドを実行するための設定です。
provision.shは、Vagrantfileを格納したのと同じ階層のディレクトリに配置します。
config.vm.provision :shell, :path => "provision.sh"

ちなみに、provision.sh の中には次のような記述をします。
sudo yum -y install httpd
sudo service httpd start
ln -fs /guest/ /var/www/html
そうです。apache httpdサーバをインストールして起動しています。

セットアップ時にあらかじめゲストOSに任意のファイルを配置することもできます。
次の例では、ホストOS上に用意したtest.htmlをゲストOS上の"/guest"フォルダに配置しています。
config.vm.provision "file", source: "test.html", destination: "/guest/test.html"

さて、では次のようなコマンドを入力してみてください。

> vagrant up

先日、ご紹介したコマンドと同じです。
ただし、今回は Vagrantfle を元に仮想環境を自動で構築して、さらにプロビジョニングまで実行します。その結果、Webサーバが起動して htmlファイルをホストするまでを確認できます。
確認してみてください。

2015年10月2日金曜日

Bower

今回は、HTML/JavaScriptのパッケージ管理ツールを紹介したいと思います。
ふだん、あまりこの分野に関わりのない方は、ちょうど Visual Studio での .NET系の開発に NuGetを活用したり、Rubyでいうところの RubyGems だと考えてもらえればイメージしやすいと思います。

そんなわけで、今回ターゲットにしたいのは Bower です。
Bowerは、HTML/JavaScriptを対象に、CSSなども含めて依存性を解決しつつ管理することができます。
ここで思うのは、同じ対象を管轄範囲とする npm とキャラクターが重なります。
確かにそうなのですが、きちんと住み分けができていますので、簡単に整理しておきます。

Bower: jQueryや、CSSなどフロントエンドに関わるものが中心
npm: サーバーサイドを軸に開発系のパッケージ管理なども含む

さて、早速 Bower を導入しようと思いますが、Node.jsとGitが必要です。
以下のコマンドでインストールしますが、グローバルオプションを指定します。

$ npm install -g bower

これでインストールは完了です。
任意のディレクトリに移動して、jQueryをダウンロードしてみます。

$ bower install jquery

バージョンを指定してダウンロードしたい場合は

$ bower install jquery#1.11.3

また、直接GitHubのURLを指定してダウンロードすることもできます。

$ bower install git://github.com/jquery/jquery.git

加えて、GitHubのユーザ/リポジトリを指定してもOKです。

$ bower install jquery/jquery

さらに、任意のURLを指定してダウンロードすることも可能です。

$ bower install http://xxxyyy.com/script.js


今度は Bootstrap を導入してみます。依存するjQueryも判断してダウンロードしてくれます。

$ bower install bootstrap


これらの結果は、bower.jsonに設定されます。
あるいは、bower.json に記述してから

$ bower init

でもOKです。
使い勝手は npm とほぼ同じです。

今度は逆のアプローチをとります。必要なパッケージをダウンロードして、bower.json にリストします。

$ bower install bootstrap --save

これも npm と同じコマンドオペレーションです。

では、最後に導入したパッケージをリストします。依存性がツリーの形式で表現されます。

$ bower list


このような管理系の問題は人手で解決するのは難しいものです。
ぜひとも、オートメーション化して、正しい手の抜きかたを実現したいものです。
さらに大きなメリットとして、このような解決が難しい問題の本質は、ドキュメントと実装が乖離していくという点で、そのような問題を防止できるということを指摘できます。
現代のシステム構築でこれをクリアするのははっきりいって困難だと思います。無駄な努力はさっさとあきらめて、jsonスキーマに管理をまかせてしまうのも一手だと思います。
つまり、源泉はただひとつ、という方針を貫くのです。jsonスキーマであれば、管理の属人性も排除できますし、いかようにも加工ができるという点で大きなアドバンテージになるのではないでしょうか。

2015年10月1日木曜日

Docker - 削除系のTips2題

Docker でいろいろ試行錯誤をしていると、さて。。となることがよくあります。
そんなときの軽いTips2題。

$ docker imgaes
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
<none>  <none>  c395172a74e5  8 hours ago  1.151 GB
<none>  <none>  05a17381460b  8 hours ago  1.151 GB
<none>  <none>  eb3ce0796961  8 hours ago

と、こんな状況に陥ることがまれにあります。
そんなときは、以下のコマンドで <none> のイメージをきれいに削除できます。

$ docker images | awk '/<none/{print $3}' | xargs docker rmi

では、すべてのイメージを一気に片付けたい場合は

$ docker images | awk '{print $3}' | xargs docker rmi

で、一気にきれいになくなります。
必ず使うコマンドなので、メモしておくとよいです。