手続き型音楽の日常

関数型音楽に乗り換えたい

C#/VB.NET の XML コメントに `completionlist` という謎のタグがある件

ネット上の情報が少なすぎて何なのか解明するのに非常に時間がかかったので。

忘れないために。

<completionlist cref=""/>

標準化されていないけど正しくコンパイルされるXMLタグ。

Microsoft Docs にも情報が載っていないので、何のための機能か一切わからない。

日本語の情報はここしか見つけられなかった。

yan note: .NET 定数ファイルを作成する ~その4~ インテリセンスに候補を表示する

.NET 文字列型の列挙体 - ウマヤディア

ただ、reddit には英語でこんなスレッドが立っていた。

www.reddit.com

英語が読めないので翻訳して読んだけど、なるほどなと思った。確かにこれは知恵袋にでも訊いてみたい機能だ。

解説

要は、あるクラスの変数に何かを代入しようとしたとき、 Intellisense に表示されるべき候補をクラスの静的メンバとして定義することができる機能のよう。

例えば自作クラスを作ったとして、

/// <summary> なんかのクラス </summary>
public class Test
{
    public string Value { get; set; }
}

このクラスの変数を宣言する。

public class Program
{
    public static void Main(string[] arg)
    {
        Test x;
    }
}

ここで、 x = と入力しても本来は何も出ない。 x = new まで入力すると、new Test() が補完されるけど、単純な代入ではコンパイラは何を代入すべきか理解できない。

そこで <completionlist cref="Test"/> コメントをつけて、静的メンバを定義する。

/// <summary> なんかのクラス </summary>
/// <completionlist cref="Test"/>
public class Test
{
    public static Test A => new Test('A');
    public static Test B => new Test('B');
    public static Test C => new Test('C');

    public string Value { get; set; }
}

そうすると、先ほどの x = まで入力した段階で、

  • Test.A
  • Test.B
  • Test.C

が候補として登場する。

実装されてる例としては、例えば System.Drawing.Color 。確かに lblNavi.BackgroundColor = とか入れると出てくるよね、色。

所感

これはかなり便利な機能だけど、ドキュメントを定義するはずの XML コメントとしては場違いな気がする。

なぜ標準化されていないか理由は定かでないけど、もしかしたら単純に Visual Studio しか対応してないからなのかもしれない。

ただ、属性として定義すれば IDE 関係なく使えそうな気がするんだよね。例えば System.ComponentModel.BrowsableAttribute とか完全に IDE 向け属性じゃん?

docs.microsoft.com

例えばクラス側に CompletionAttribute 属性をつけたら、宣言された変数への代入に全部そのリストが使われるとか。

例えば変数やフィールド側に CustomCompletionAttribute 属性をつけたら、その変数やフィールドだけ特別な補完リストが出てくるとか。

うーん。今までのコンパイラが対応しないとなると、今更導入しても使われなさそうだなぁ…。

C# で ウェーブレット木 を実装したライブラリをアップデートした

かなり前の記事で書いたのですが、ウェーブレット木を C# で実装したライブラリを作りました。

今回、 Visual Studio 2019 Preview が出たので、それを機にアップデートしてみました。

github.com

アップデート内容

名前空間の変更、クラスの分割

名前空間はもともと単発の予定でつけたので、めっちゃ適当でした。今回は改めて名前を付けなおしました。

あと、最近よくわかってませんが、インターフェースだけ外出しして実装系を別ライブラリにするっていう方法を考えていまして。

今回その方法を試してみました。 IWaveletTree<T> だけを定義するプロジェクトと、それを参照して実装する WaveletTree<T> だけのプロジェクトみたいな。

どちらも .NET Standard 2.0 に準拠しているので、だいたいの実装系で使えます。

使う際は、 WabeletTree<T> を nuget で落としてくる時に依存解決で一緒に。。。と言って感じで想像しています。まだ nuget パッケージ作ってないけど。

WaveletTree.Select<T> メソッドの実装

今回実装にあたり、以下のサイトを参考にしました。

www.slideshare.net

こちらの方のスライド、めちゃくちゃわかりやすいのですが、この中に出てくる「完備辞書」と呼ばれるものを目指してみました。

実装するには Select 関数を実装しなければならないらしいので、書いてみました。

        /// <summary>
        /// 指定された値が最初に出現する位置を取得します
        /// </summary>
        /// <param name="value">位置を取得する値</param>
        /// <returns>位置</returns>
        public int Select(T value) => this.Select(value, 0);

        /// <summary>
        /// 指定された値がn回目に出現する位置を取得します
        /// </summary>
        /// <param name="value">位置を取得する値</param>
        /// <param name="index">n</param>
        /// <returns>位置</returns>
        /// <exception cref="ArgumentOutOfRangeException"><c>index</c> is out of range of tree values.</exception>
        public int Select(T value, int index) => _ids.ContainsKey(value) ? this._SelectInner(value, index) : throw new ArgumentOutOfRangeException();

まずは公開メソッド。n回目という部分を実装するため、引数は2つ必要でした。というわけで、引数1つの時は強制的に最初に出てくる位置を取得するようにしています。

また、そもそも文字が含まれていない可能性があるので、その場合は例外をスローしています。

        /// <summary>
        /// 指定された値がn番目に出現する位置を取得します
        /// </summary>
        /// <param name="value">位置を取得する値</param>
        /// <param name="index">n</param>
        /// <returns>位置</returns>
        private int _SelectInner(T value, int index) =>
            this._depth == 0 ?
                (0 <= index && index <= this.Pairs.Count()) ? index : throw new ArgumentOutOfRangeException() :
            this._CheckTop(value) ?
                this._rightPairs?[this.Right?.Select(value, index) ?? 0].Index ?? 0 :
                this._leftPairs?[this.Left?.Select(value, index) ?? 0].Index ?? 0;

        /// <summary>
        /// 最上位ビットを見て0か1を判定します
        /// </summary>
        /// <param name="value">検査する値</param>
        /// <returns><c>true</c>: 1, <c>false</c>: 0</returns>
        private bool _CheckTop(T value) => (this._ids[value] & (1 << (this._depth - 1))) != 0;

そして内部の実装。結構考え込んで、このような形にしました。

何をしているかというと、実は「n番目に出てくる要素Xのインデックスを取得しろ」という情報を「Xを持っている葉」まで伝達しています。

すると、「Xを持っている葉」にとって「n番目に出てくる要素Xのインデックス」は「n」なので、そのまま受け取った「n」を返します。

その親は X がどちらの節にあるかを判別し、「その節のn番目に出てくる要素は、自分自身ではy番目」という逆引きを行い、それを返します。

というアルゴリズムを続けて、最後にオリジナルのシーケンスの中でのインデックスが変えるという寸法です。

めちゃくちゃ回りくどいです。もはや無駄です。ですが LINQ を使ったいい方法がこれしか思いつきませんでした…

安直に while 回したほうが早かったかもしれません。

感想

今回のアップデートは、破壊的というか根本的に名前空間を変えているのであれですが、極力クラスの内部は変えないように心がけました。

LINQ を使った実装を頑張ったので、ちょっと実用的でないコードがたくさんありますが、楽しかったから良し。

もしアドバイス等あれば、コメントお待ちしております。

kintone hive NAGOYA vol.3 に参加してきた話

ちょっとタイムリーな話題?

kintone ってなんぞ

kintone はサイボウズ株式会社が開発しているクラウド型データベース系業務アプリ構築サービスのこと。

詳しくは以下の Qiita がめっちゃわかりやすい。

kintoneとは、サイボウズ株式会社が開発しクラウドで提供するWebデータベース型業務アプリ構築サービス(作成したアプリケーションを連携したりシステム管理機能も活用できるよ) qiita.com

私の kintone レベル

実は業務で触ってたりします。

転職した関係でフロントエンドな Web アプリケーションを触ることが多くなりましたが、大概この kintone を使ったアプリを開発しています。

アプリを開発しているというか、 kintone のカスタマイズをしているというほうが正しいのか…。

kinotne CRETIFIED も Associate だけ取ってたりします。もう App Design と Customize も取っていい気がしますけど勉強する時間が…

cybozu.co.jp

というわけで、 kintone には結構ディープに関わっています。今まで黙っててごめんね (何

当日

当日はなかなかの盛況でした!

会場となった Zepp Nagoya の後ろのほうまで人がいる状態。なんか映画館みたいな感じでした。

もともとはライブ会場だけあって椅子は全部パイプだったり、音響はめっちゃばっちりだし後ろに DJ ブースみたいな部分もあったりして、こんなところでやるんだなぁって面白味を感じました。

登壇者1 : ちらし屋ドットコム 河田 菊夫​ 氏

岐阜を中心に展開している Web 製作会社。

これまで少人数だったため散在していた各資料を kintone にまとめることで、コストを可視化して意識を一つにしていったということ。

新しいプラットフォームに移行するため、帰りのドアに kintone の利用を懇求する紙を張ったり、会議中に kintone への登録をする時間を作ったり…。

自分がやりたい!だけでなく、みんなの協力があって kintone の活用に成功したという話でした。ぐうわかる。

システムだけではどうにもならない、みんなが使ってこそのシステムだってことが伝わってきました。

あと、ビール飲みながらサッカー観戦が好きらしく、暇そうなサイボウズ社員と一緒に観に行ってきたそう。

登壇者2 : ミッドランド税理士法人 小泉 直哉 氏

初っ端からインパクトの強い体験談をいただきました。

会社を立てたけど仕事が追いつかなくなり、アル中になり、太り、破産し、死んでしまうかもしれないという恐怖に怯えた日々から一転、筋トレをして痩せたり税理士法人の方に採用されたり。

人々を救うということが税理士法人になったきっかけだそうですが、今後この職業は AI に取って代わられて無くなってしまうと言われている。

いや、そうではない!無駄な業務をコンピュータ化して、人間は高度な判断が必要な業務に専念すれば良い!ということに行き着いたそう。

そこで kinotne を使って新たな業務改革 "LawyTech" を推進していこうということらしい。

必要な機能をシステムにして人間は人間の仕事をしていくという、着眼点にとても共感しました。いいなぁ、こういう世界。

登壇者3 : チヨダセキュリティサービス 吉本 大介 氏

名前からはなかなか想像できない、ガス会社を経営されている方。

先代である父が作り上げた会社がリーマンショックで打撃を受け、売却を考えていたところ取って代わって取締役に。

苦労を重ねながらもなんとか従業員数を増やし、九州にも支店を構えるようになったそう。

最近は新しい事業を始めるなど活躍する舞台を増やす中、自分は次第に経営者の道へ進もうと決意。

今までは目で見て実感していたことが、現場を離れることで見えなくなる。そこで、 kintone を使って情報共有を行うようになったそう。

システムを通じて企業が成長し世界が広がっていくということを発表されました。これからは、他の企業の立て直しも行っていきたいとのこと。

非常に愛のあるセッションでした。

登壇者4 : ジヤトコ株式会社 岩男 智明​​ ​氏

規模の大きな会社ですが、情報システム部の主任が秘めたる思いも同じだけ大きかった話。

もともと社内 SNS を作って暗黙知の共有を推進するなど、エンジニアとしてよりよい環境を作っていこうと活動されていたそう。

そんな中 kintone と出会い、本当にもとめていたシステムはこれだ!と感激。

現場にあったシステムを作るには、現場が主体となってシステムを作らなければならないという原点に立ち返り、 kintone を使って "現場が業務アプリを作る" という仕組みを作ったそうです。

また、それにあたって社内で統一的なルールを作ったりコミュニティで情報交換を行ったりし、社内で広く使ってもらおうと情熱を燃やしているそうです。

小さな会社にしか勤めたことがないので、全社展開とか正直最初はピンと来なかったのですが、1万人以上の組織で kintone という一つのシステムが使われるようになるとすれば、それはとても素晴らしいことだと思います。

一人の情熱がみんなの情熱を呼び覚ます、そんな社風と重ねたプレゼンが心に響きました。

kintone hack セッション

その後、開発者目線での kintone の活用例も披露されました。

1人は、Alexa を使って社内にコンビニを作り、声で購入できるシステムを作った方。

もう1人は、ノンコーディングでドローンを飛ばし、ノンコーディングで kintone に随時情報を書き込むという方。

kintone を使って派手なアクションを披露する、面白い場でした。でもやっぱドローン飛ばした、株式会社GEクリエイティブ​の伊藤さんがすごかったな……。

感想

kintone ってモバイル対応があまり進んでいないとか、トランザクションに弱いとかの理由から、大規模開発や汎用的なシステム基盤から避けられてきたように思います。

でも逆に、小規模から積み上げていく "成長する" システムなんかはめっちゃ作りやすかったり、外部連携機能やプラグインによって進化したり、様々な面で発展を続けていると思います。

今度のアップデートでは、モバイル版の画面がかなり充実するそう。期待が大きですね!

kintone.cybozu.co.jp

というわけで、 kintone hive NAGOYA vol.3 への参加レポでした。楽しかったです!皆様お疲れ様でした!

Node.js の exports と require() をなんとなく理解する

ブラウザで動く JavaScript を書いてて、初めて Node.js を触ると絶対にびっくりする、モジュール。

そもそもスコープが共有されていないことに驚愕するのですが、じゃあどうやったらモジュールとかが使えるのか、ライブラリはどうやったら使えるのか、というのをざっくりまとめてみた。

Node.js におけるグローバル空間

ブラウザだと、ファイルの一番大きな部分に変数を宣言したり、そもそも宣言せずに変数を使った場合、その変数は window オブジェクトのプロパティとして定義されます、

var test = 1; // ルートで宣言

function a() {
    test2 = 2; // var がついていないのでグローバル
    console.log(test2); // 2
    console.log(window.test2); // 2
}

function b() {
    test = 10; // 変数宣言の巻き上げによってローカル変数になる
    var test = 11;
    console.log(test); // 11
    console.log(window.test); // 1
}

a();
b();

console.log(test); // 1
console.log(test2); // 2

そして、 Node.js で同じことを行うと、 global オブジェクトのプロパティになります。要するに、 window の代わりとなるのが global オブジェクトです。

test = 1;
console.log(global.test); // 1

この global オブジェクトは、1ファイルごとにそれぞれ生成されます。つまり、ブラウザにおける window オブジェクトと違い、ファイルをまたいで変数が共有されることはありません。

例えば a.jsglobal.test = 1 を定義したとしても、 b.js では global.testundefined を返します。というかそもそもプロパティ自体がありません。

これによって、不用意なグローバル汚染をなくすことができます。

即時関数パターンを使わなくてもいい

これに伴って、実はブラウザ向け JavaScript プログラムでよくやる "ファイル全体を即時関数パターンで囲う" ということをしなくてよくなります。イメージ的には Node.js が勝手に囲ってくれている感じに近いです。

なので、ファイルの一番上で 'use strict' しようと、ファイルのルートでどれだけ変数を宣言しようと、ほかのファイルには一切影響しません。

変数の公開

さきほどから散々 "ファイル間で変数の共有ができない" と言っていますが、ではどうしたら複数のファイルで変数の共有ができるでしょうか?

その答えは、 Node.js の "モジュール" という概念です。 Node.js には、モジュールをインポートしたりエクスポートして、ファイル間で情報を共有する機能があります。

そのカギとなるのが、 require 関数と exports オブジェクトです。

require 関数

require 関数は、モジュールをインポートする関数です。つまり、モジュールを使う側が情報を得るために使います。

使い方は2つです。

var test = require('./test'); // 自ファイルと同じ階層にある test.js を読み込む
var test2 = require('test2'); // node_module ディレクトリ、もしくはビルトインモジュールの test2 を読み込む

これによって、モジュールの情報が変数に入ることになります。

この関数、実は 指定したファイルを一番上から実行する 機能があります。

ブラウザの JavaScript で言うなら、 script タグで埋め込んだスクリプトが順次動くとか、途中で Element.appendChild(scriptElement); みたいな感じで動かすのと似ています。

指定したファイルを実行し、それによって得た情報を戻り値として返す、それが require 関数です。

exports オブジェクト

フルで書くと global.module.exports になるのですが、 module.exports 、あるいは exports とも書けます。

この exports オブジェクトが、 require 関数で呼ばれた際の戻り値になります。

意味が分からないって?分かりました。 JavaScript で書きますね。 JavaScript なら皆さんも読めますね?

// test.js

exports.a = 1;


// index.js

var test = require('./test'); // { test: 1 }
console.log(test.a); // 1

test.jsexports オブジェクトにプロパティ a を生やしています。つまり、 test.js 上では、 exports{ test: 1 } となります。

index.js ではこれを require 関数で呼び出しています。戻り値は { test: 1 } になります。

そうです、 exports オブジェクトが、 require 関数の戻り値になります。

公開、非公開を意識する

名前空間などでしっかり管理されている場合は、もう何も言うことはありませんので、どうぞ読み飛ばしてください

通常、ブラウザで動く JavaScript を書いていると、関数の公開、非公開なんて意識しません。だって全部グローバルだから。

でも、モジュールを自作するとなると厄介になります。例えば…

// これを別ファイルから使えるようにしたい
function getName(id) {
    return get('/person/name', id);
}

// これは実は見られたくない
function get(url, id) {
    var xhr = new xmlHttpRequest();
    ...
}

get 関数は、単純に GET リクエストを送信する関数です。この関数はバージョンアップによって引数が増えたり、そもそも生で使ってほしくないので、公開したくありません。

でも、ブラウザで動く JavaScript は全部共有してしまうため、結果的に外から見られてしまいます。

そこで、次のようにスコープを分けてしまう、という手があります。

var getName;
(function () {
    getName = function (id) {
        return get('/person/name', id);
    };

    function get(url, id) { ... }
})();

getName('hoge'); // ok
get('/person/name', 'hoge'); // ReferenceError: get is not defined

こうすれば、外から見られたくない関数が呼び出されることはありません。

さてこれが Node.js の場合ですが、先ほど即時関数パターンが要らなくなると書きました。つまり、こんな感じです。

getName = function (id) {
    return get('/person/name', id);
};

function get(url, id) { ... }

でもこれだと、外部に関数を公開できません。公開する場合は、 exports オブジェクトのプロパティにする必要があります。

// public function
exports.getName = function (id) {
    return get('/person/name', id);
};

// private function
function get(url, id) { ... }

こうすることで、 Node.js でも公開する関数、非公開にする関数を分けることができました。

最後に

実は Node.js あんまり使ってません。

実際の業務ではブラウザで動く JavaScript を書いていますし、趣味で何かするときはもっぱら C# で書いてしまうので、クライアントもサーバサイドも事足りてしまうんですよね。

でも、 AWS Lamda とかだと Node.js が結構頻繁に使われますし、今の時代 Node.js を知らないと大変なこともたくさん。これだけは基本中の基本なのでしっかり押さえておかないと、後から苦しむことになると思います。

というわけで、今回はモジュールの基本概念についてまとめてみました。完全に自分用です。

次回、モジュールについて書くときは、 ES6 の Module との相互運用について、でしょうか…?

.net standard プロジェクトでnull許容構造体の循環参照が検出されない

先日、ウェーブレット木の記事を書くときに C# 書いていて、あれおかしいな?と感じたところを突き詰めた結果、こんなことが分かった次第です。

Visual Studio 2017 で現象を確認しましたが、 Visual Studio 2019 Preview 2 でも同じく確認したので。

現象詳細

構造体定義の中に、自分自身のnull許容構造体のフィールドを入れたとき (struct Test { Test? test; } みたいな感じ)、通常であればコンパイルエラーになるが、 .net standard プロジェクトでのみコンパイルエラーにならず実行時エラーが発生する。

再現手順

1. プロジェクトの作成

.net standard プロジェクトと、 .net core コンソールプロジェクトを作ります。そして .net core プロジェクトから .net standard プロジェクトを参照します。 .net core のほうは、 .net standard でも OK です。

.net standard プロジェクトは移植可能な DLL を作成するのみで、ビルドしても実行可能なバイナリは生成できません。そのため、別のプロジェクトから参照する形で実行します。

f:id:yuzutan_hnk:20190203155459p:plain
.net standard プロジェクトのプロパティ

2. コードの記述

検証用のコードは至ってシンプルです。 .net standard 側で構造体を定義し、 .net core 側でそれをインスタンス化します。

まずは .net standard プロジェクトの構造体定義。

namespace netstandard_structtest
{
    public struct TestData
    {
        TestData? test;
    }
}

そして、 .net core プロジェクトのエントリポイント。

using System;

namespace netcore_structtest
{
    class Program
    {
        static void Main(string[] args)
        {
            var x = new netstandard_structtest.TestData();

            Console.WriteLine("Press key to continue...");
            Console.Read();
        }
    }
}

これで準備は完了です。

3. 実行

現状で、エラーは無くビルドが通ります。なので、そのまま実行します。

実行時エラーで起動できません。

f:id:yuzutan_hnk:20190203160537p:plain
型が読み込めない

4. 別パターン

インスタンスを作らない

エントリポイント内でインスタンスを作らないことにしてみます。つまり、定義だけで利用しません。この場合は、実行できます。

using System;

namespace netcore_structtest
{
    class Program
    {
        static void Main(string[] args)
        {
            //var x = new netstandard_structtest.TestData();

            Console.WriteLine("Press key to continue...");
            Console.Read();
        }
    }
}

f:id:yuzutan_hnk:20190203160807p:plain
動くのかい

null許容にしない

構造体の定義で null許容を外して完全に自分自身を参照します。結果は、たぶん定義通りの動きだと思います。

namespace netstandard_structtest
{
    public struct TestData
    {
        TestData test;
    }
}

f:id:yuzutan_hnk:20190203161352p:plain
わかりみが深い

.net core プロジェクト側で定義する

構造体の定義を .net core プロジェクトでやってみます。コンパイルエラーになります。

using System;

namespace netcore_structtest
{
    class Program
    {
        static void Main(string[] args)
        {
            var x = new netstandard_structtest.TestData();

            Console.WriteLine("Press key to continue...");
            Console.Read();
        }
    }

    struct TestData
    {
        TestData? test;
    }
}

f:id:yuzutan_hnk:20190203161624p:plain
コンパイルエラー

null許容じゃなくてクラスにする

null許容にしたいのであれば、クラスでラップすれば事足りるのではないか?という発想。

namespace netstandard_structtest
{
    public struct TestData
    {
        NullableTestData test;
    }

    public class NullableTestData
    {
        TestData value;
    }
}

f:id:yuzutan_hnk:20190203162039p:plain
まあ、動くよね。

所感

単純に考えて、自分自身を構造体で参照したらレイアウトが循環するのは正しいと思います。

いくら null許容と言っても、実際には Nullable<T> 構造体の中で自分自身の変数が定義されるので、結果的に循環参照になるはず。

.net core 側では事前にチェックされてコンパイルエラーになるのに、 .net standard ではならないということは、何か理由があるのか?それともコンパイラの単なる実装バグ?

一体、これはどこに報告すれば回答が得られるのでしょうか?詳しい方、ぜひ教えてください。

お兄ちゃん!そこは名前空間パターンだよ!

タイトルは釣りです(お約束)

名前空間パターンのススメ

みなさん、名前空間パターンを使っていますか。私はよく使いますよ。

一体なんの話だって?もちろん JavaScript の話ですよ。

最近はサーバで動かすプログラムも書けるほど、活躍の場を広げていますよね。もともとは Web ブラウザで動かすスクリプト言語でしたが。

というわけで、そんな JavaScript でのプログラミングで知らず知らずのうちに使われている 名前空間パターン に注目していきます。

名前空間パターンのイロハ

まず、 JavaScript の世界には 名前空間なんて無い ということをまず覚えておきます。これはとても重要なことです。

一般的にオブジェクト指向と呼ばれるプログラミング言語には、複雑な階層構造をサポートするために名前空間 (あるいはモジュール) という機構が備わっています。

これを用いると、 複数のファイルをまたいでプログラム部品をまとめる ことや、 フォルダ階層のようにして目的の部品を見つけやすくする ことができます。

たとえば、 "Alex.cs" と "Lexa.cs" というファイルがあったとします。

namespace Mitsurin.Service
{
    public class Alex
    {
        public dynamic Mic;
    }
}
namespace Mitsurin.Service
{
    public class Lexa
    {
        public dynamic Phone;
    }
}

あっ、手が勝手に C# のコードを書いてしまいました…許してください。

この場合、 namespace Mitsurin.Service という名前空間が宣言してあります。これは "Mitsurin の Service である ○○" という意味に見て取れるようになります。

Alex クラスと Lexa クラスは名前空間として宣言されているため、コンパイルすると、当然2つのクラスは同じ名前空間に属することになります。フルネームで表すと、つぎのようになります。

Mitsurin.Service.Alex クラス
Mitsurin.Service.Lexa クラス

例えば他に、 Mitsurin.Item 名前空間があったとします。この場合は、 "Mitsurin の Item である ○○" のような分類になります。

Mitsurin.Item.Echo クラス

C# では using 文で名前空間の記述を省略できるようになるのですが、今回の場合は

using Mitsurin.Service;
using Mitsurin.Item;

namespace hoge
{
    public class Program
    {
        static void Main(object[] args)
        {
            var x = new Alex(); // Mitsurin.Service.Alex
            var y = new Echo(); // Mitsurin.Item.Echo
            var z = new Mitsurin.Service.Lexa(); // フルネームで指定することも可能
        }
    }
}

のように書くことができます。

というわけで、これを JavaScript でやろうって話です。

やらないとどうなるの?

John くんは、駆け出しのプログラマです。ある日彼は、ネットでこんなプログラムを見つけました。

function getRandom(i) {
    return parseInt(Math.random() * i);
}

彼はこのプログラムを気に入りました。なんて発想だ!これまで3ヶ月も JavaScript とにらめっこしたのに、こんな発想は思いもよらなかった!引数で指定した数を上限に、ランダムな整数が関数1つで帰ってくるなんて!

そうだ、このプログラムを使って、面白いことをしよう。彼はすぐさま行動に移しました。10分後には、彼のディスプレイには素晴らしいスクリプトが表示されていました:

<script>
function getRandom(i) {
    return parseInt(Math.random() * i);
}
window.onload = function () {
    alert("Welcome to my homepage! Your lucky number is " + getRandom(100) + "!!!");
};
</script>

これは、ホームページを訪れた人みんなが楽しくなるだろう!彼はハイテンションで実際のホームページにアップロードしました。

ブラウザで彼のページを開くや否や、ダイアログが表示されました。 "Welcome to my homepage! Your lucky number is 52!!!"

大成功です! 彼は飛び上がらんばかりの喜びを感じました。

しかし、そのダイアログを閉じると表情は一変。これまで動いていた 背景に雪を降らせるライブラリ が動かず、ただ単色の背景が表示されてしまったのです。これは大問題。

なぜ動かなくなったのだろう?さっきまでは動いていたのに。調べていくと、どうやら彼は大きな過ちを犯していたようです。

彼のホームページに使われていた例のライブラリは、 random.js という外部ファイルを参照していました。これには次のような関数が書かれていたのです。

function getRandom() { return Math.random() * 100; }

そう、実は getRandom という名前の関数が別にあったのです! そして彼はその関数を上書きしてしまいました。もともと引数を受け取らない関数を、引数を受け取る関数に書き換えてしまったのです!

なんってこった!こんな罠に引っかかるなんて。彼はイライラしながら、自分の関数を書き換えていきました。


とまあ、大げさに書いてはみたものの、実際に起こりうる話です。

大きなウェブアプリになってくると、同じような名前の関数がいくつも出来上がり、まれにファイルをまたいで名前が衝突してしまうことがあります。

こうしたことを起きにくくする、という観点のもと、関数を階層構造にまとめる仕組みが出来上がりました。

それが 名前空間パターン です。

How to?

(function () {

    // グローバル空間にオブジェクトを生成 (既にある場合はそのまま)
    window.myApp = window.myApp || {};

    // グローバル空間のオブジェクトにプロパティを追加
    window.myApp.john = window.myApp.john || {};
    window.myApp.tony = window.myApp.tony || {};

    // 外からは参照できない
    var list = [];

    // 関数の定義
    window.myApp.john.getRandomA = function () {
        var r = parseInt(Math.random() * 1000);
        return r;
    };

    window.myApp.john.getRandomB = function (i) {
        var r = parseInt(Math.random() * i);
        return r;
    };

    // いくつも名前空間を生やすことができる
    window.myApp.tony.push = function (obj) {
        list.push(obj);
    };

    // 変数 (プロパティ) も可
    window.myApp.tony.count = [];
})();

名前空間パターンは、 グローバル空間に公開するオブジェクトを最小限にする 事から始まります。 JavaScript でのグローバル空間は、ブラウザでは window オブジェクト、 Node.js では global オブジェクトになります。つまり、この直下に作るオブジェクトを最小限にします。

上記の例では、グローバル空間に公開されているオブジェクトは window.myApp のみになります。また、即時関数パターンで囲まれているため、中で var キーワードによる変数宣言があっても、スコープを分けることができます。

yuzutan-hnk.hatenablog.com

こうすることで予期せぬ名前の衝突をできるだけ少なくし、移植性を高めます。

詳しいやり方

やり方はいろいろあります。とにかく、公開するオブジェクトを少なくすればよいです。

(function () {
    window.myApp = window.myApp || {};
    window.myApp.func = function () { return void 0; };
})();
var myApp = {};
(function () {
    myApp.func = function () { return void 0; };
})();
var myApp = {
    func: function () { return void 0; },
};
window.myApp = (function () {
    var num = 100;
    return {
        func: function () { return num; },
    };
})();

他にもいろいろなやり方があります。文字列から名前空間を取得・生成する関数を作ってもいいかもしれません。私は個人的に、一番上が気に入っています。

Using

名前空間を定義するのはいいですが、これらの関数を使うためには名前空間の中まで入っていかなければいけません。

階層が多くなると、どうしても名前が長くなってしまいます。これでは、逆に使いづらいです。

var a = myApp.john.getRandomA(); // グローバルオブジェクト (window) は省略できる

こういう時のために、 C# などでは using などのステートメントで省略できるようになっています。

using System;
using System.IO;

namespace myApp
{
    public static class john
    {
        // Stream のフルネームは System.IO.Stream
        public Stream test()
        {
            return new TextStream();
        }
    }
}

JavaScript ではこうした概念は存在しないので、変数で代用します。

var tony = myApp.tony;
var random = myApp.john.getRandomA();

tony.push(1);
var x = random();

厳密には変数なので中身の入れ替えが自由自在なのですが、コーディング規約などでルールを徹底すれば、コードの保守性が上がるかもしれません。

最後に

素人が生意気にすみませんでしたJavaScript なんて書けないです奥が深すぎて抜けられません・・・。

本業で使用言語がだんだん C# から JavaScript に変化してきたんですが、なかなか難しく、手っ取り早くコードをきれいにしようと思って手を付けたのが名前空間パターンでした。

JavaScript で継承とかなにやらやろうと思ったらかなり多くのコードを書かなきゃいけなくて、素人が見ても なんじゃこりゃ・・・ なコードにしかならないなと思って、試行錯誤した結果です。許してください。

class 構文?そんな新しい子しりませんねぇ・・・ (遠い目)

yuzutan-hnk.hatenablog.com

2019年、将来の自分へ、今年の目標を、

謹んで新年のお祝辞を申し上げます。

本年もどうぞよろしくお願いいたします。

前回の記事はまだクリスマスプレゼントの記事なので年明けにカウントしないことにしますね。異論は認める。

今年の目標について

まずはじめに結論から始めたいと思います。今年は、次のことに挑戦してみたいと思っています。

  1. 1週間に1件 は、ブログを書くこと
  2. ゆずたんのAP対策日記 を、継続して更新すること
  3. 楽曲アレンジ動画を 2本 は投稿すること
  4. サイトを作ること

yuzutan-hnk-ap-taisaku.hatenablog.com

yuzutan-hnk.hatenablog.com

もう既に1つめから破綻 前回の記事までまだ年明けていないのでセーフです。

というわけで、今年は上記のことを目標にします。言ったからにはやらなきゃ。


自分を、振り返る

過去の反省は、個人的にはとても大事だと思っています。

2019年、どんな年にしようかなぁと考えたときに、やっぱり経験をもとに考えなくちゃいけなくて、必然的に過去の自分を見ざるを得ないと思うんですよね。

今までどこが良かったのか、どこがだめだったのか、結果的にどうなったのか、何が因果関係だったのか、っていう自問自答を繰り返す。

結論は出ないかもしれないけど、それで得るものは大きいと思う。

今回は、去年の自分を振り返ってみることにします。

2018年、全然活動できなかった年

2017年はいろいろなことに挑戦していた記憶がありますが、去年は全然なにも起きませんでした。うん。

守るものも増え目標も増え、どこに身を置くべきなのか悩み、大きな一歩を踏み出せない毎日を過ごしました。

どれもこれも思い当たるフシはたった一つで、やはり転職したことが一番大きかったんだろうなぁという結論に落ち着きます。

上半期は転職に向けてひた走り、転職してからは新しい職場環境になれるため頑張り、これからの人生を見つめ直す機会が社内で何度も訪れ、ストレスの現れなのか1年間の収支がゴニョゴニョ……

プライベートでは勉強会に行く頻度が極端に減り、画面に面と向かって座って開発したり作業したりする気が無くなり、ずーっとスプラトゥーンで遊び続け、前半頑張っていたMUSECAも休み始め、本職のはずの楽曲アレンジ動画もついに1本も投稿せず。。。

なぜ私はこんなにも堕落した生活をしているのか!?やる気は十分にあるのに体がついてこないのはなぜだ!?厄年か!?新手の厄年か!?!?(錯乱)

何もかも、2017年と変わってしまいました。自分でなんとかしようとか、自分から何かを起こそうとか、そういった気が全く失せてしまいました。全部受動的。

一人暮らししようとか目標を立ててましたが、そんなこと言っている場合じゃありませんでした。

何もできなかった2018年。正直に言って後悔しています。

2019年、自分自身が試される年

新しい年に過去の悔みを引きずるのは良くないので、気分を転換しよう。いや、発想を転換しよう。

つまり、2018年の自分を鏡に、今年の自分を見直そう。

転職という大きなことを成し遂げたんだ。いや、個人的にはめちゃくちゃショートカットして楽に済ませたけど、本当は大きな一歩なんだ。その後の変化が無いわけがないのだ。

だから、今の自分を原点に、また新たな自分を見つけていかなきゃいけないと思う。

そして、これまでの自分を取り戻すことも、とても大事だと思う。だって、今までの自分がなければ、これからの自分も無いのだから。

新しい自分と、これからの自分。どちらも同じ自分、見つめ直さなきゃいけない時期にきたのかな。

教えられること、学ぶこと

先日は、成人式でした。今年成人式を迎えられた皆様、おめでとうございます。

あまりニュースを見ていないので今年はどんなどんちゃん騒ぎが起こったのか知りませんが、耳に入らないってことはそんなに起こっていないのかなと思います、誰も怪我しなかったことを願います。

わたしの成人式は、本当に質素なものでしたし、特に思い出もありませんが、記憶には鮮明に残っています。皆様にも、そんな大切な思い出の一つとして残っていけばいいなと思います。

こんなふうに、年を取るごとに、自分より若い世代がどんどん社会に出てきて、びっくりしちゃうんですよね。今まで上の人にびっくりさせられることが多かったのに、どんどん若い人たちに驚かされる。

驚かされるという表現をしたけれど、厳密には 教えられる というほうが適切かもしれない。

1ヶ月ほど前、NGK2018Bという 勉強会 忘年会に行ったとき、たまたま近くの席に座った人が高校生でした。話をさせていただきましたが、全然話についていけませんでした。

IT系にいるとたまに太陽光パネル買ってる人が居たりブレードサーバを買っている人が居たりして面白いなと思いますが、高校生がここまで話せるとはにわかに信じがたいものがありました。

でも、現に目の前で喋ってる。本物だ。

自分の知識不足というよりかは、世の中にはいろいろな人が居て、いろいろな考え方があるんだな、ということをまじまじと教えられた気分でした。

あまりいろいろな人と関わってこなかった人生、社会に出て人と接することで驚かされ教えられ、成長しなければならないことがどんどん増えてきました。

まだまだ学ぶことが絶えないことを、肝に目地て置かなければならないなと感じています。

時間は有限であること

実は少し前に下書きして完成しなかった記事に、「ハタチが終わる日に向けて、人生が終わる日を考える」というのがあります。完成してないから公開もしてません。

人が居なくなる、この世になくなる、そういう経験を最近は身近に感じるなということを書きたかったのですが、なかなかまとまらず放置してあります。もう書く気はありません。

でも、今でもその時の気持ちは生きていて、何をしているときでもはっと感じるときがあります。

今、私は21歳。もうすぐ22歳になります。まだ半年以上ありますけど、きっとすぐに来る。

限られた時間の中で何をすればいいのか、何をすれば自分の理想に近づけるのか、何をすれば自分のやりたいことができるのか。

そして、どうしたら大切な人を守ることができるのか。

ずっと自分に問いかけ続けています。

さいごに

すみません、持論というか感情の押しつけというか、完全に自己満足な記事になってしまいました。ここまでお付き合い頂きありがとうございます。

今年も精一杯、がんばります。OWASPへのボランティアもできたら再開したいし、個人開発のソフトもいっぱい作りたいし、色んな場所へ旅もしたい。

そして今年こそは一人暮らしを始めたいので、それを見据えて最初に立てた目標に絞りましたが、できるならとことん挑戦していきたいと考えています。

どうぞ、これからもよろしくお願いします。

現在 0000/00/00 00:00 を生きています。