2015年9月9日水曜日

Prototype宣言

オブジェクトというものを考えてみます。

とはいっても、所謂オブジェクト指向言語のオブジェクトではなく、プロトタイプベースのオブジェクトを考えてみます。
その前に従来のオブジェクト指向言語のオブジェクトを簡単に振り返ってみます。
まず、システムやソフトウェアはあるシナリオによって動作します。このシナリオをできるだけ細かく分解して汎用的な部分を共通化して合理的な実装に備えます。
しかし、これではまだ不充分で、特性や性質、あるいは、本質的に何を表現するのか? という観点でさらに分解されます。
つまり、ある事象の根本的な動作の表現、それを色づけるための特性や性質に分解されることに結実するのがオブジェクトに対するアプローチだと思います。
たとえば、前者がコンテキストだったり、後者がデータだったりします。
合理的な単位で分解されたものがオブジェクトになり得る候補になります。私たちがやることは、その分析結果をクラスという概念でモデル化して、電気信号に変えられインスタンスに変化します。 これがオブジェクトです。
ここで注意したいのは、このオブジェクトは既に特性や性質を兼ね備えているということです。それらはメンバという形で自然に存在します。
なぜなら、オブジェクトとして実体になるクラスがそのように定義されているからです。

さて、ECMAScriptの世界はどうでしょうか?
プロトタイプベースのオブジェクトは、実はそのように考えません。
オブジェクト自身は別のオブジェクトを追加することにより、新たな性質が加わります。
これがプロトタイプの考え方です。
では、そのプロトタイプベースの考え方に則りオブジェクトを生成してみます。

function Object() {}
var onj = new Object();

上のオブジェクト定義では retun がありませんが、下のステートメントで new されたときにオブジェクトインスタンスが得られます。

さらに初期化してみます。

function Object() {
    this.param = “done.”;
}
var obj = new Object();
Console.log( obj.param );
>Done. と表示されます。

今度は、このようなコードを書いてみます。
function Object() {}
Object.prototype.param = function() {
    console.log('Done.');
};
var obj = new Object ();
obj .param(); // Done. と表示される。

これでは、どうでしょう。
function Object () {
    this.param = function() {
        console.log('Done.');
   };
}
var obj = new Object ();
obj .param(); // Done.

ほぼ、同じです。
しかも同じように動作します。
しかし、大きな違いがあることがわかると思います。
後者のコードでは毎回インスタンス化されてしまうという違いがあります。 すべてのオブジェクトは prototype オブジェクトの参照を持っています。 この prototype オブジェクトに新たな特性や性質を付与することにより、細かなニュアンスの違いを表すことができます。
オブジェクト指向言語の継承に近い雰囲気を持っているように見えますが、性質が違います。
prototype に特性や性質を加えて、かつ、削除することも可能です。

ここでポイントです。
new により生成されたオブジェクトは、Object の prototype と同じ参照を持っています。
これによりオブジェクトは合理化されるわけです。

2015年9月8日火曜日

ASP.NETの吐き出すマークアップの矯正

知っている人も多いと思いますが、ASP.NET Web Forms の出力するHTMLコードがいかんともしがたい。
CheckBoxやRadioButtonListなどで顕著。
つまり、素直なHTMLツリーが出力されないのだ。

たとえば、以下のマークアップは
<asp:CheckBox ID="check" runat="server" class="myClass" />

このようなHTMLとしてレンダリングされる。
<span class="myClass"><input id="check" type="checkbox" name="check" /></span>

そう、<span></span>タグで括られてしまう。 これでは、フロントエンドでDOM解析をしたいときに非常に不便だ。と同時に input に属性を付与できないという最も大きな問題を引き 起こす。
そこでレンダリング方法をカスタマイズしてみたいと思う。

WebControlAdapterクラスを継承したクラスを作る。
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.Adapters;

public class CheckBoxAdapter : WebControlAdapter
{
    protected override void Render(HtmlTextWriter writer)
    {
        CheckBox targetControl = this.Control as CheckBox;
        if (targetControl == null)
        {
            base.Render(writer); return;
        }
        writer.WriteBeginTag("input");
        writer.WriteAttribute("type", "checkbox");
        writer.WriteAttribute("id", targetControl.ClientID);
        if (targetControl.CssClass.Length > 0)
        {
            writer.WriteAttribute("class", targetControl.CssClass);
        }
        writer.Write(" />");
    }
}

でもって ブラウザ定義ファイルに以下のコードを追加する。
<browser refID="Default">
<controlAdapters>
                        <adapter controlType="System.Web.UI.WebControls.CheckBox" adapterType="CheckBoxAdapter" />
        </controlAdapters>
</browser>

さて、この状態で以下のようなマークアップがどのように変化するのか・・・ というと
<div> <asp:CheckBox ID="check" runat="server" CssClass="myClass" /> </div>

きれいなHTMLコードをレンダリングするようになりました。
<div> <input type="checkbox" id="check" class="myClass" /> </div>

まぁ、いまさら ASP.NET Web Forms もないだろ・・ という声も聞こえてきそうですが、画面の初期化を Web Forms で画面の更新を Web API で実行するハイブリット方針も、これはこれでなかなか生産性が高い方法でもあるのです。

コミット・メッセージには気をつかっていますか?

コミット・メッセージには気をつかっていますか?
1か月も経てば、いや、1週間程度でほとんど記憶も吹っ飛び、自分が書いたメッセージさえ意味がわからないなんてことになっていませんか?
たとえば、Git界隈では、このあたりも積極的に議論が成され一定の規範に則って運用しようという文化が醸成されつつあります。
調べてわかればよい、という意見も多く聞かれますが、果たしてこの感覚は正しいものでしょうか?
いえ、正しい誤りという二律背反的な捉え方は無意味でしょう。 第一、時間の無駄です。調べるという行為には追跡という要素があります。この追跡という行為には推測という要素がつきものです。つまり、推測に誤りがあれば間違った情報や解釈に到達してしまう危険性があります。
たかが、コミットメッセージだけで大げさな… という見方もできるかもしれません。事はコミットメッセージだけに留まらずドキュメントやコードにまで影響するのです。

どういうことか?
コミットメッセージさえ気を使えなければ、ドキュメントもまたしかりだと思います。
これは作業品質の問題です。 あるいは、余計なことに頭を使う必要がなければ、もっと本質的な部分に注力することが可能になります。

2015年9月5日土曜日

boot2dockerを試す

WindowsやOSXな方は、boot2docker を導入することで、手軽に Docker のソリューションを試してみることができます。
とは言え、それなりにハマりどころが存在するのも、この手の技術の常です。

まずはインストールしてみましょう。
公式サイトに行って自身の環境にあった boot2docker のインストーラをゲットします。
インストール自体は非常にシンプルで、指示に従うのみです。
その際、VirtualBoxとcygwinもいっしょにインストールされますが、既に導入済みのかたはチェックを外せばいいでしょう。

さて、VirtualBox で 32 bit の仮想サーバーしか作れない、というトラブルに見舞われたなら、BIOSをチェックしてみてください。
VT-x が BIOS で OFF になっているケースが考えられます。

ということで、boot2docker のインストールが完了しました。デスクトップにあるアイコンをダブルクリックすると Dockerコンソールが起動します。このとき、コマンドプロンプトで入力待ち状態になります。これで boot2docker が起動しました。

バージョンを確認してみます。
docker -v

Docker Version 1.8.0. build 0d03096

と表示されれば正常です。

では、早速 Docker を作成します。
たとえば、
docker pull centos:latest

CentOSの最新イメージを取ろうと思います。

と、Pulling repository docker.io...
となったところで、connection refused.

ん。。。

DNSの指定をチェックします。

$ boot2docker ssh
docker@boot2docker:~$ vi /etc/resolv.conf

## そして、以下を追加して
## nameserver 8.8.8.8

docker@boot2docker:~$ cat /etc/resolv.conf
nameserver 8.8.8.8
docker@boot2docker:~$ exit
$ boot2docker restart

そして再び Docker pull

超えるべき壁は多い予感です。

2015年9月3日木曜日

急がば回れ

落ち着きのない仕事をたまに見かけます。というよりかなりの高確率で見かけます。
先を急いでもよいことはありません。

たとえば、ひとつのクラスの実装を終えました。
これから動作させてデバッグをしようと思いますが、果たして、そこで確認をするでしょうか? 再確認です。
クラスを生成してオブジェクト化するにあたり、事前条件は揃っていますか?
実際に動作させた後の事後条件と期待値は頭の中で整理できていますか?
そもそもコードのセルフレビューは実施しましたか?

こういった単純な準備作業は案外重要です。ここで一歩引いて俯瞰するゆとりが、あるのか?ないのか? で時間の節約の仕方がだいぶ変わります。それどころか、この段階でつまらないバグはつぶせるはずです。

昔から言い古されている言葉ですが、ゆっくり、落ち着いて、ひとつひとつ確実にこなすのが結局はいちばん早いのです。

2015年9月2日水曜日

ASP.NETのレガシー・マークアップ

ASP.NET4.5 Web APIで構築されたHTMLに対して Angular.JS でバリデーションをレンダリングしようと企てたのだが、form要素のname属性が捨てられていることに、いまさらながらに気づいた。
下記は MSDN の ASP.NET と XHTML というドキュメントからの抜粋。

---

XHTML に準拠するための ASP.NET 機能 
ASP.NET は、form 要素に action 属性を動的に追加します。既定では、form 要素には XHTML 1.0 Transitional 仕様で許可されている name 属性が含まれています。これ により、フォーム名を使用して form 要素を解決するクライアント スクリプトに依存する既存のアプリケーションとの下位互換性が保持されています。 
メモ : 
form 要素の name 属性は XHTML 1.1 ガイドラインでは許可されていません。name 属性をレンダリングしないようにアプリケーションを構成できます。 

ASP.NET ページとコントロールの XHTML レンダリングの制御 
ASP.NET コントロールで XHTML 1.1 仕様のより厳密な形式でマークアップをレンダリングすることが必要な場合があります。既定のレンダリングには、XHTML 1.1 仕様に 準拠していないマークアップも含まれています。たとえば、XHTML 1.1 標準では、HTML form 要素の name 属性の使用は禁止されています。 
メモ : 
レガシ マークアップをレンダリングするオプションは、主に既存のページを ASP.NET の最新バージョンに移行するために提供されているので、ASP.NET の将来のバージョ ンではサポートされなくなる可能性があります。 

レガシ レンダリング 
レンダリングをレガシに設定すると、ASP.NET のページとコントロールは、レンダリング機能を ASP.NET の以前のバージョンの動作に変更します。次のような変更が行われます。 
form 要素は、name 属性を使用してレンダリングされます。

---

以上を踏まえてASP.NETのマークアップを利用してレンダリングするには、次の3つの方法がある。

・Legacy (以前のバージョンの ASP.NET でのマークアップのレンダリング方法とほぼ同じ、典型的な例は、form タグの name 属性をレンダリングする場合)
・Transitional (XHTML 1.0 Transitional)
・Strict (XHTML 1.0 Strict)

どの方法を使ってレンダリングするかは、以下の方法で指定する。
Web.config ファイルの system.web 要素に xhtmlConformance 要素を追加する。次に、mode 属性を Legacy、Transitional、または Strict に設定する。

xhtmlConformance 要素が Web.config ファイルに定義されていない場合、既定の設定モードは transitional となる。

以下は、XHTML のレンダリングを無効にするコード例

<system.web>
<!-- other elements here -->
    <xhtmlConformance
        mode="Legacy" />
</system.web>

以下は、XHTML 1.0 Strict のレンダリングを指定するコード例

<system.web>
<!-- other elements here -->
    <xhtmlConformance
        mode="Strict" />
</system.web>

では、Legacyレンダリングに設定した場合の副作用は・・・
1)form 要素の内部の div 要素はコントロールのコンテナとして自動的にレンダリングされない
2)検証コントロールは、controltovalidate などのカスタム属性を使用して span 要素としてレンダリングされる
3)img 要素では、alt 属性と src 属性はそれらを明示的に含めない限りレンダリングされない
4)Autoポストバック機能をサポートする必要がある場合、コントロールは language="javascript" などの language 属性をレンダリングする。
5)コントロールの Wrap プロパティが false に設定されている場合、div 要素をレンダリングする Panel などのコントロールに nowrap 属性が追加される
6)ImageButton コントロールは、border 属性をレンダリングする
7)br 要素は、すべて <br> としてページにレンダリングさる。ただし、明示的に <br /> タグを記述すると、そのままレンダリングされる。
8)BackColor プロパティが設定されている場合、DataGrid コントロールと Calendar コントロールには、レンダリングされた table 要素に bordercolor 属性が含まれる

以上は押さえておくべきポイントです。

2015年9月1日火曜日

gulpモジュールで簡単なタスク自動化

gulp は Node.js 上で動作するタスク自動化のためのビルドツールです。
ソースファイルの圧縮、lessファイルのコンパイルやCSSのベンダープレフィックスの付与、CoffeeScriptのコンパイルなどを実行できます。
タスク定義をシンプルな JavaScript で記述して動作させるのが特徴です。このあたりが Grunt のJSONで宣言的に定義する方法より細かい制御がシンプルに記述できる理由です。

では gulp をインストールしてみます。今回はWindowsで試してみます。
まずは npm で gulpモジュール をグローバルオプションでインストールします。
npm install -g gulp

C:\Users\username\AppData\Roaming\npm\node_modules\gulp\bin\gulp.js
gulp@3.9.0 C:\Users\username\AppData\Roaming\npm\node_modules\gulp
├── pretty-hrtime@1.0.0
├── interpret@0.6.5
├── deprecated@0.0.1
├── archy@1.0.0
├── tildify@1.1.0 (os-homedir@1.0.1)
├── minimist@1.2.0
├── v8flags@2.0.10 (user-home@1.1.1)
├── chalk@1.1.1 (supports-color@2.0.0, escape-string-regexp@1.0.3, ansi-styles@2.1.0, strip-ansi@3.0.0, has-ansi@2.0.0)
├── semver@4.3.6
├── orchestrator@0.3.7 (sequencify@0.0.7, stream-consume@0.1.0, end-of-stream@0.1.5)
├── liftoff@2.1.0 (extend@2.0.1, rechoir@0.6.2, flagged-respawn@0.3.1, resolve@1.1.6, findup-sync@0.2.1)
├── gulp-util@3.0.6 (array-differ@1.0.0, array-uniq@1.0.2, lodash._reevaluate@3.0.0, lodash._reescape@3.0.0, beeper@1.1.0, object-assign@3.0.0,  lodash._reinterpolate@3.0.0, replace-ext@0.0.1, vinyl@0.5.1,lodash.template@3.6.2, through2@2.0.0, multipipe@0.1.2, dateformat@1.0.11)
└── vinyl-fs@0.3.13 (graceful-fs@3.0.8, strip-bom@1.0.0, defaults@1.0.2, vinyl@0.4.6, mkdirp@0.5.1, through2@0.6.5, glob-stream@3.1.18, glob-watcher@0.0.6)

任意のディレクトリに再度gulpモジュールをインストールします。
これは、グローバルでインストールした gulp がローカルインストールの gulp を実行する役割に使われるためです。
プロジェクトによって gulp のバージョンを合わせることなくタスクを実行できます。
npm install gulp

また、以下のようなオプションでインストールすると package.json で管理できるようになります。
これは、プロジェクトメンバ間でパッケージモジュールそのものを管理するのではなく、package.json を基にして、その都度インストールするときに便利です。
npm install --save-dev gulp

バージョンを確認します。
gulp -v
[23:05:23] CLI version 3.9.0
[23:05:23] Local version 3.9.0

次に gulpfile.js というファイル名で gulp の設定ファイルを作成します。

'use strict'
var gulp = require('gulp');
 
// 監視タスク
gulp.task('watch', function () {
    gulp.watch('*', function (event) {
        console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
    });
});
 
// デフォルトタスクとしてwatch
gulp.task('default', function () {
    gulp.run('watch');
});

では、gulpを動作させます。コマンドは次のようにシンプルです。
gulp

[23:15:09] Using gulpfile C:\xxx\Gulp_Test\gulpfile.js
[23:15:09] Starting 'default'...
gulp.run() has been deprecated. Use task dependencies or gulp.watch task triggering instead.
[23:15:09] Starting 'watch'...
[23:15:10] Finished 'watch' after 12 ms
[23:15:10] Finished 'default' after 21 ms
File C:\xxx\Gulp_Test\新しいテキスト ドキュメント.txt was added, running tasks...
File C:\xxx\Gulp_Test\新しいテキスト ドキュメント (2).txt was added, running tasks...
File C:\xxx\Gulp_Test\新しいテキスト ドキュメント (2).txt was deleted, running tasks...
File C:\xxx\Gulp_Test\新しいテキスト ドキュメント (3).txt was renamed, running tasks...
File C:\xxx\Gulp_Test\新しいテキスト ドキュメント (3).txt was deleted, running tasks...
^Cバッチ ジョブを終了しますか (Y/N)? y

任意のディレクトリ配下のファイル変更を監視し、変化があればコンソールにメッセージを表示します。
gulpコマンド実行後、いろいろなファイルを作成して試してみてください。

以上のような特性を利用して、テストランナーを走らせたり、ビルドタスクを実行したりするわけです。