.NET で日付の文字列化2016年11月06日 00時04分04秒

西暦で表示したい場合。ex: 2016年11月6日 (日)

use System;
use System.Globalization;

var culture = new CultureInfo("ja-JP", false);
var todayText = DateTime.Today.ToString("yyyy年M月d日 (ddd)", culture);

和暦で表示したい場合。ex: 平成28年11月6日 (日)

use System;
use System.Globalization;

var culture = new CultureInfo("ja-JP", false);
culture.DateTimeFormat.Calendar = new JapaneseCalendar();
var todayText = DateTime.Today.ToString("gy年M月d日 (ddd)", culture);
  • 曜日を日本語で表示したいのであれば、どちらの場合でもカルチャ名 "ja-JP" のカルチャを指定する。
  • 和暦で表示したい場合は更に DateTimeFormat.Calendar を設定。西暦の場合は逆に設定してはいけない (フォーマット文字列を yyyy にしても年数の表示が狂ってしまう)。

日本語 Windows 環境で Cwd::abs_path がうまく動かない件2015年09月26日 13時42分03秒

Excel 地獄に立ち向かうべく、複数の Excel ファイルから全検索をかけてどうにかするような処理を Perl の Win32::OLE を使って書こうかと思ったんだけど、 OLE での Workbooks.Open メソッドを Perl から呼ぶ場合、カレントディレクトリの解釈が異なるとかの理由でファイル名を絶対パスで渡さなきゃならない。

そこで、 Cwd なるパッケージの abs_path 関数を使ってファイル名の絶対パスを取得して渡すやり方を試してみたんだけど、特定のファイル名をこの関数に渡した時に例外が発生する現象に苛まれて結局その日のうちにツールを完成することができなかった。

手元の環境で再現状況のログを取ることができたので以下に掲載。

C:\Users\murachi\Documents>echo hoge > 確定申告.txt

C:\Users\murachi\Documents>perl -M"Cwd qw/abs_path/" -e "print abs_path('./確定申告.txt')"
./確定申: No such file or directory at -e line 1.

C:\Users\murachi\Documents>echo hoge > 表示画面.txt

C:\Users\murachi\Documents>perl -M"Cwd qw/abs_path/" -e "print abs_path('./表示画面.txt')"
C:/Users/murachi/Documents/示画面.txt
C:\Users\murachi\Documents>echo hoge > 画面表示.txt

C:\Users\murachi\Documents>perl -M"Cwd qw/abs_path/" -e "print abs_path('./画面表示.txt')"
./画面表: No such file or directory at -e line 1.

C:\Users\murachi\Documents>

どうやら内部でファイル名を Shift JIS で取り扱っているらしく、マルチバイト文字のオクテットに 0x5c (ASCII コードで言うところのバックスラッシュ \) を含む文字の取り扱いで文字を潰したりこけたりしてしまっている模様。

まだ試してはいないけど、もしかしたらディレクトリ自体にこういった文字が含まれるようなケースでもしくじるのかもしれない。

何はともあれ、絶対パスは何か別の方法で取ってこないとダメだなぁ…。

DB 操作の視点からオブジェクト指向を考える2013年06月23日 22時18分58秒

シナリオ

出席簿をつけるアプリケーションを想定してみることにします。まずマスターとして、学生、講師、講義の 3つが存在するものとします。

  • 学生

    • 学籍番号 (PK)
    • 氏名
    • 性別
    • 学年
    • etc...
  • 講師

    • 教員番号 (PK)
    • 氏名
    • 性別
    • 役職
    • etc...
  • 講義

    • 講義識別番号 (PK)
    • 講義名
    • 担当講師 (教員番号)
    • 場所
    • 時間割
    • 期間
    • 単位数
    • 概説
    • etc...

それから、マスター以外のテーブルとして、受講者リストと出席記録があるものとしましょう。

  • 受講者リスト

    • 講義識別番号 (PK)
    • 受講者 (学籍番号) (PK)
    • 点数
    • 成績 (優|良|可|不可)
    • etc...
  • 出席記録

    • 講義識別番号 (PK)
    • 受講者 (学籍番号) (PK)
    • 講義回数 (N回目) (PK)
    • 遅刻 (時刻)
    • etc...

さて、ログインした講師が受け持つ講義の 1つを選択し、新たに出欠をとる画面を開いたとします (講義回数は自動でカウントされるべきでしょう)。その画面には講義に参加する全ての学生が学籍番号順にリストアップされており、点呼を受けて講師自らが学生たちの出欠状況を入力していくものとします。これをどうプログラムで表現し、実装するべきか。

ありがちな過ち

オブジェクト指向をメタファー (隠喩) の表現のために用いること自体は必ずしも間違いではありませんが、メタファー自体も手段の一つと捉えるべきです。メタファー自体が目的になってしまうと、パフォーマンスが犠牲になることが多くなります。

例えば学生と講師はどちらも人なので、 Person クラスで抽象化して StudentTeacher に派生しよう、などと考えること自体は悪くないかも知れません。

// 人を表す抽象クラス
public abstruct class Human
{
    // 人を特定する番号 (学籍番号、教員番号等)
    public long Number { get; protected set; }
    
    // 名前
    public string Name { get; protected set; }
    
    // 性別 ("M": 男性 / "F": 女性 / "O": その他)
    public string Sex { get; protected set; }
    
    // etc...
}

// 学生クラス
public class Student : Human
{
    // 学年
    public int? Year { get; private set; }
    
    // ...
}

// 講師クラス
public class Teacher : Human
{
    // 役職 (11:助教 / 16:講師 / 21:准教授 / 26:教授 / 51:名誉教授 / 56:客員講師 / 99:その他)
    public int Roll { get; private set; }
    
    // ...
}

あー、ちなみに言語は C# で書いてます。テストしてませんが。

で、ここまでは良いんですが、ありがちな誤りとして、それぞれのクラスのコンストラクタに DB からの読み込み機能を持たせちゃうという試みがあります。

using Db = MyNameSpace.DbAccessor;

public class Student : Human
{
    // ...
    
    // デフォルトコンストラクタ (マスタ登録時用)
    public Student() { }
    
    // コンストラクタ (学籍番号から情報を取得)
    public Student(long number)
    {
        DataTable table = Db.StudentTable.SelectByPk(number);
        if (table == null || table.Rows.Count == 0)
            return;
        
        DataRow row = table.Rows[0];
        Number = number;
        Name = row["STUDENT_NAME"] as string;
        Sex = row["STUDENT_SEX"] as string;
        Year = row["STUDENT_YEAR"] as int?;
        // ...
    }
    
    // ...
}

さすがに面倒くさいので Teacher の方の実装例は割愛。

何故にこれがアカンのかと言いますと、まぁ例外との兼ね合いというのもあるのですが、何よりあまりにも気兼ねなく使え過ぎちゃって、知らず知らずのうちに無駄な DB アクセスが増えてしまう要因になりうるからです。あと、実際の使用に際しては実はあまり使われることのない存在になる可能性も小さくありません。

「データ取得用」のクラスは別に設ける

シナリオを読み返しましょう。講師が出欠をとるために開いた画面では、その講義への参加を登録している全ての学生が、学籍番号順にリストアップされるとしています。そのような複数の学生を特定する処理は、DB 側での SQL に任せてしまった方が効率がよいのは当然です。そこで、特定の講義に参加する学生のリストを取得するファクトリクラスを考えます。

using Db = MyNameSpace.DbAccessor;

public class Student : Human
{
    // ...
    
    // コンストラクタ
    internal Student(DataRow row)
    {
        Number = (long)row["STUDENT_NUMBER"];
        Name = row["STUDENT_NAME"] as string;
        Sex = row["STUDENT_SEX"] as string;
        Year = row["STUDENT_YEAR"] as int?;
        // ...
    }
    
    // ...
}

// 学生情報管理クラス - とりあえずファクトリとして実装
public class StudentManager
{
    // 学籍番号を指定して学生情報を取得
    public static Student Get(long number)
    {
        DataTable table = Db.StudentTable.SelectByPk(number);
        if (table == null || table.Rows.Count == 0)
            return null;
        
        return new Student(table.Rows[0]);
    }
    
    // 講義を指定して学生情報のリストを取得
    public static Student[] ListUpByLecture(int number)
    {
        // 特定の講義番号で登録されている受講者の学籍番号を受講者リストテーブルから
        // リストアップし、その学籍番号を用いて学生テーブルから学生の情報を引っ張る、
        // までを全部 SQL でやっつけてデータを返すメソッドを想定
        DataTable table = Db.LectureMembersTable.SelectByLecture(number);
        if (table == null)
            return new Student[] {};
        
        var students = new List<Student>();
        foreach (DataRow row in table.Rows)
            students.Add(new Student(row));
        
        return students.ToArray();
    }
}

Student のコンストラクタを internal にするのがミソです。こうすることで、同一ファイル以外からのアクセスがコンパイラによって禁止されます。それによって、 StudentManager クラスのメソッドを介さなければ Student のコンストラクタは呼べない、すなわち Student クラスのインスタンスを生成できないようになるわけです。同様のことは、 Java ならクラス内クラスにして protected で、 C++ なら friend を使う等で実現可能でしょう。

デフォルトコンストラクタは省いたのではなく敢えて書いていません。多分、マスタへの変更をする目的でわざわざ Student インスタンスを生成するべきではありません。理由はいくつかあって、例えばマスタ登録のためだけにアクセサのセッターまで public にしてしまうとメンテナンス性が損なわれるのではとか、そうではなくて全部の情報を引数に渡すコンストラクタを設けるぐらいならデータ管理用のクラス (まさにここで言うところの StudentManager クラス) にて全部の情報を引数に渡すメソッドを書くんでも変わらないよねとか。ついでに INSERT はもとより UPDATE するためにわざわざ SELECT で情報を全部引っ張ってきてからそれをコード上で上書きして UPDATE を呼ぶとかするんでなしに最初っから PK だけ指定して UPDATE だけ呼んだ方が速いに決まってるよねとか。

NULL 可能なフィールドとかもあるし全部を引数に渡すメソッドは現実的じゃないだろうとか言うんであれば、内部データだけを持つデータ構造を定義して分離可能にしてしまっても良いと思う。こんな感じで。

public class HumanData
{
    public string name;
    public string sex;
    // ...
}

public class StudentData : HumanData
{
    public int year;
    // ...
}

public abstruct class Human
{
    // フィールド構造体アクセサ
    protected HumanData Fields { get; set; }
    
    public long Number { get; protected set; }
    
    public string Name
    {
        get { return Fields.name; }
        protected set { Fields.name = value; }
    }
    
    public string Sex
    {
        get { return Fields.sex; }
        protected set { Fields.sex = value; }
    }
    
    // ...
}

public class Student : Human
{
    public int Year
    {
        // こういうダウンキャストは酷くダサイですが…
        get { return (Fields as StudentData).year; }
    }
    
    // ...
    
    internal Student(DataRow row)
    {
        Number = (long)row["STUDENT_NUMBER"];
        
        var fields = new StudentData();
        fields.name = row["STUDENT_NAME"] as string;
        fields.sex = row["STUDENT_SEX"] as string;
        fields.year = (int)row["STUDENT_YEAR"];
        // ...
        Fields = fields;
    }
}

public class StudentManager
{
    // ...
    
    // 学生の情報をマスタに登録し、学籍番号を返す
    long RegistNewStudent(StudentData data)
    {
        // ...
    }
}

まぁ、この辺は好き好きで…。

マスタデータをプールする

頻繁に見には行くけどそうそう書き換わることのないデータであり、それをプールさせておく時間をそれほど長くないセッション単位に限定するのであれば、マスタデータのメモリ上でのプールはそれほど悪くないアイデアだと思います。

public class StudentManager
{
    // プール用コンテナ
    Dictionary<long, Student> pool = new Dictionary<long, Student>();
    
    // プールをクリアする
    public static void ClearPool()
    {
        pool.Clear();
    }
    
    // 学籍番号を指定して学生情報を取得
    public static Student Get(long number)
    {
        if (pool.ContainsKey(number))
            return pool[number];
        
        DataTable table = Db.StudentTable.SelectByPk(number);
        if (table == null || table.Rows.Count == 0)
            return null;
        
        return pool[number] = new Student(table.Rows[0]);
    }
    
    // 講義を指定して学生情報のリストを取得
    public static Student[] ListUpByLecture(int number)
    {
        // 特定の講義番号で登録されている受講者の学籍番号を受講者リストテーブルから
        // リストアップし、その学籍番号を用いて学生テーブルから学生の情報を引っ張る、
        // までを全部 SQL でやっつけてデータを返すメソッドを想定
        DataTable table = Db.LectureMembersTable.SelectByLecture(number);
        if (table == null)
            return new Student[] {};
        
        var students = new List<Student>();
        foreach (DataRow row in table.Rows)
            students.Add(pool[(long)row["STUDENT_NUMBER"]] = new Student(row));
        
        return students.ToArray();
    }
}

但し、どういうタイミングで StudentManager.ClearPool() を呼ぶべきかをちゃんと考えて使わないと、サーバー上で起動しっぱなしのプロセスでプールにデータがたまりっぱなし、しかもマスタメンテ画面で学生情報を修正したのに (学年とか) その変更が画面に反映されないぞー何でだーみたいなバグを誘引する原因になったりもするので、気をつけて使う必要はあると思います。特にグループ開発では。

まとめ

そんなわけで、結局のところ何が言いたいのかというと、オブジェクト指向というのは必ずしもメタファーのためだけにあるわけではないよということです。最近ではよく、「オブジェクト=物である、という説明を真に受けてはいけない」などと言われるようになりましたが、それは何でかというと、業務シナリオの中に出てくるような、実在する物だけをオブジェクトとして表現しようとすると、そのオブジェクトのクラスの中だけで何でもかんでもやり遂げなきゃならないような気になってしまうからです。学生を表現したいからと言って、必ずしも学生クラスの中だけで DB アクセスまで完結する必要はないわけです。あくまで、プログラム上での目的に応じたオブジェクト設計を心がけるべきなのです。

ASP.NET でありがちな話2013年06月20日 06時11分38秒

よーするに今の職場からでは恐らくこんなブログサイトはフィルタリングされて見られやしないだろう事を良いことに書きたい放題愚痴をまき散らしてしまえというお話です^^

単なる表示上の変化に過ぎないものまでポストバックで実現する

ポストバックというのは ASP.NET 用語で、よーするにフォーム操作で発生する POST 送信とそれに対するサーバーからの応答によって、同一ページ上でのユーザーとシステムとの対話を実現してしまおうというやり方のことです。これは問い合わせ内容に応じて結果表示を切り替える仕組みとして想定されているものですが、どうやら一般的な ASP.NET 開発者は DB への問い合わせが発生しないようなことにも平気でポストバックを使ってしまうようです…。

例えばラジオボタンの選択に応じて入力項目の表示が切り替わるような UI とか、クライアントサイドスクリプトで事足りるのにも係わらず、なぜか AutoPostback="true" とかにして、 SelectedIndexChanged イベントハンドラをわざわざ書いて、わざわざ POST が発生するような作りにしてしまう。マスターページを使ってると ID が変化しちゃうから… という声もありそうですが、 runat="server" にさえしなければ ID も変化しないわけで、だったら <div> なり <span> なりで包んで表示/非表示ぐらいは出来るだろうに (それはそれで微妙にダサイんですが…)。

何でもかんでも Page.Session に突っ込む

DB に対する問い合わせ結果を表にして表示するような UI は業務系の Web アプリでは多いですが、一般的な ASP.NET 開発者の中には DB から取得した問い合わせ結果の DataTable (配列の豪華版みたいなもん) をそのまんま Page.Session に突っ込んで、ユーザーがレコードを選択したときの値の突き合わせのために再利用しようとする人が多いみたいです。

ASP.NET では、セッションに紐付いた情報はデフォルトではプロセスのメモリに格納されるとあります (だからラウンドロビン構成にしても同一セッションでのアクセスは常に同一の Web サーバーによって処理されるわけですね)。上記のような実装を想定してセッション状態ストアプロバイダーとやらを独自に実装していたり、 Web サーバのメモリ容量を十分に確保していたりしているなら良いのですが、ちゃんとそこまで想定していらっさる開発者さんってどれくらいいらっさるんでしょうね…。

何でもかんでも View State に突っ込む

ユーザーコントロールを実装する場合、コントロールの表示状態を保持するために、関連する情報を View State と呼ばれる場所に格納しておくものなんだそうです。いや、本当に表示状態に関する情報 *だけ* をここに突っ込むんであれば良いのでしょうが、データグリッドの DataSource に突っ込むようなでかいデータをそのまま View State に放り込む人とかも結構居て、そのおかげで出力される HTML がすさまじいことになったりするケースもちらほら見かけるようです… あれは BASE64 かなんかでエンコードした文字列をそのまんま hidden に書き出しますからね…。

他にもいろいろと言いたいことはあったような気もしますが、よーするにまとめてしまうと、何でもかんでもブラックボックス化して取っつきやすさばかりを重視した開発ツールなんて、もう初学者の学習教材専用ということにしてしまって、プロの現場に持ち込むのは止めましょうよという話だったりするわけです。ぐんにゃり。

ASP.NET2013年06月03日 08時11分27秒

かつては EC サイト構築に活用されていたとか何とか言われていた ASP.NET が、今では企業向け業務用 Web アプリケーションの分野でばかり使われているような気がする現状について考えてみる。

考えるまでもないだろ、とか言われそうな気もしますが…。

とりあえずインターネットに公開する一般向けサイトの開発に向かない、というかそっち方面ではほとんど見向きもされない理由は分かるんです。個人のサイトで使う分にはちょっと仰々しすぎるというか大げさというか、準備しなきゃならないものがあまりにも多すぎてコスト高だと思うし (そも個人がサイトを開くレベルのホスティングサービスで Windows Server が使えるところ自体あんまり聞かない)、企業が作る Web サービスとかだと、仮に人気が出ちゃってアクセス集中しだしたときにスケールアップの難しさ云々以前に ASP.NET の仕組み自体が高トラフィック要求しすぎというか無駄が多すぎで話にならない。

一方で企業がイントラで使う業務用 Web アプリの分野では通信コストのスリムアップはそれほど要求されないし、むしろ要求されたらサーバー増築でさらにお金をせびる口実にもなるし、技術的には決まり切った作法に則って行われる単純作業に集約できてリスクも軽減できそうだしで良いことづくしにも見える。何より自由なソフトウェアはサポートが無くて既存のバグに由来する不具合も全て自前で責任をとる必要がある。何か問題があったラベンダー任せに出来るという安心感が、その辺の業界での採用を下支えしている感もある。

ただ、当のベンダーである Microsoft はその状況をよしとしているのかね? MVC モデルの登場は、むしろそうした状況を打破したいようにも見える。 UA へのアウトプットを概ねコントロール可能にすると言うことは、通信コストの軽減を意味するものでもあり、あるいは他の Web フレームワークと同じ土俵にたつための変更であるとも言える。ホスト OS が IIS という時点で同じ土俵には立ててない感もあるけど。

ASP.NET を利用して開発を行う企業や開発者について言えばもっと心配だ。 MVC に関して言えば、デスクトップアプリで言うところの WPF ぐらいの勢いで敬遠されている節もある。まぁいつだって業務アプリ界隈は保守的な人々の巣窟な訳だけど、 ASP 以外の普通の Web 開発現場ではむしろ MVC モデルを採用したフレームワークの利用が一般的だし、そうでなくても HTML5 や、 JQ でもいいからクライアントサイドスクリプティングが普通にこなせるようでないと潜り込んでいくのは難しい。 ASP.NET で開発やってました= Web 開発経験ありますとは到底言えないのが現状なのではないかと思うがどうか。

VSS2013年05月24日 06時48分49秒

どうも、ご無沙汰でやんす。

つなぎの、というつもりでもなかったんですが、とりあえず 1ヶ月半ぐらいやらせていただける案件があって、食いつなぐためにもやらせていただいているんですが、その現場のネット環境が非常に厳しい (外部とのメールのやりとり NG、 Web 閲覧は Google Web検索、 Google Map、Yahoo のトップページ、 MSDN Library 以外は概ね NG、その他のプロトコルも当然 NG) 為、仕事自体もやりにくかったりでいろいろとフラストレーションを抱え込んだりもしているわけですが。

仕事の内容は ASP.NET で作られている業務用 Web システムの機能追加のお手伝いで、 ASP の部分、つまりは表示と UI 制御辺りの実装を主に… まぁ仕事の内容の話はいいや。古いバージョンに拘泥している割にはガッチガチに M$ 様の支配下にいらっさるようで、ソースコードのバージョン管理も VSS を使用、当然 Trac のようなタスク管理ツールや BTS はなし。線表も顧客向けのを Excel かなんかで書いてただけみたいで (Project ぐらい使えよ)、進捗管理とかスケジュール管理とかの概念自体が微妙に希薄な印象…。

で、 VSS なんですが、実はおいらはこいつを使うのは今回が初めて。いやーこれはこれはありがたい経験をさせていただいております限りでございまして…。おかげでこいつがネット上では情報収集および発信に熱心なプログラマーたちの間で何で嫌われているのかが理解できてきましたよ。使う前までは単にマージではなくロック方式だから嫌われているだけなんだと思っていたのですが…

まず戸惑うのは言葉の違い。これはまぁ方式の違いもあるので仕方ないことではあるのですが、チェックインという言葉は使ったことがなかったので… この辺は恐らくホテルのチェックイン・アウトと同義だと思えばいいのかなと。

ソースの取得 (Subversion 辺りでいうところの update) も微妙に戸惑いますね… 何で毎回「サブプロジェクトも取得」とか「ツリーを構築する」とかチェックボックスにチェック入れなきゃあかんのでしょう… んなもん指定した場所以下は全部落とせに決まってるじゃないですか… ていう。それでディレクトリが追加されていたりすると「ディレクトリ無いけどどうする? 作るの?」みたいな確認ダイアログをわざわざ出してきてブロックする… メール確認してたりで VSS ほったらかしにしてるとそのダイアログが裏に隠れちゃってたりして気がつかないまま作業開始しちゃって、あれ、直したって言われてたビジネスロジックの動きが変わってないなぁ、何か間違えてるのかなぁ… なんてことに無駄に時間を割いたり… orz あと自分でチェックインした以外の変更があれば「xxx を置換」ってログメッセージが出るから取得が終わったんだなって分かるけど、そうじゃないと何にもログ吐かんのな。キャンセルボタンが消えてるから一応気づきはするんだけど、時間かかるんだからせめてもうちょっと「終わったよ!」ってのアピールして欲しい ('A`)。

で、作業に入るわけですが、 Visual Studio は VSS と自動で連携していて、 Visual Studio 上で書き換えようとした瞬間に、そのソースファイルのチェックアウトをしに行ってくれるようになってる。まぁロック方式ですし、手動でやらされることを考えれば便利なんでしょうけど、間違えて触っちゃってアンドゥで直してそっ閉じしたファイルがチェックアウトしっぱなしになっていてチームにご迷惑を… みたいなのは方々で多発していらっさるんでしょうなぁとか思うとちょっと胸熱…。

ロック方式とマージ方式のどっちかが絶対に優れているとかは言うつもりはないです。普通の開発体制であれば同じファイルを複数人が同時に触るということはそうそうないですし、チェックインし忘れによる不便とコンクリフト発生時の面倒を秤にかけても仕方ないですし。個人的には、テキストファイルをテキストファイルとして編集するようなもの (ソースコードとか XML とか HTML とか) はマージ方式、それ以外 (バイナリファイル全般とか、 XML でも MS-Office のドキュメントみたいにアプリ上での状態まで保存するためにちょっといじっただけでファイル全体にわたって diff が出まくるようなものとか) はロック方式で管理するのがやりやすいかなとか思っていたりはするわけですが。 Subversion なんかはファイルの種類ごととかディレクトリごととかでマージ方式かロック方式かを指定できたりするのは良いですよね。

それから VSS では変更内容のログを残しておくという文化がないっぽいのも気になります。一応、 Visual Studio 上でチェックインを行う際にはログメッセージを記入することも出来るようにはなっているのですが、現場の人には「別に特に書かなくて良いですよ」とか言われてしまい、それでもなんか嫌なので何かしら変更内容を記入するようにはしていたんですが、変更履歴のログを見る機能とかそういえば使ったこと無いですね… (一応無いことはないらしい)。 この辺はちゃんとやろうと思えばやって出来ないことではないとは思うんですが。

ログと関連して、最近は Trac や Redmine などといったタスク管理ツールと連動させる使い方が結構広まってきていると思うんですが、 VSS にはそういうソリューションってあるんですかね? コミットログにはチケット番号を、チケットにはリビジョン番号を書いて相互リンクとかやると結構便利だったりするわけですが…。

そんなわけで、結論としては VSS 不便だなぁというお話でした。それでもこうすればもうちょっと便利に使えるよ、という話はあるのかも知れませんが、 VSS と Visual Studio で完結できない話であるなら、そも今の現場はネットからファイルをダウンロードすること自体フィルタリングで物理的に不可能なので、まぁ 1ヶ月半だし我慢しましょうという感じですかね。(*sigh*)

Excel 列名変換問題やってみた2011年11月12日 16時50分01秒

問題1: Excel列名変換問題
  • 仕様
    • 入力されたアルファベットを数字に変換する。
    • 変換ルールはExcelの列名と同等。
    • 例) A=1、B=2、Z=26、AA=27、XFD=16384
  • 起動時引数
    • [0] アルファベット (A~ZZZZ...[上限なし])
  • 実行例
    • ExcelColConv.pl A → 1
    • ExcelColConv.pl AA → 27

問題2: Excel列名変換問題(逆変換)
  • 仕様
    • 入力された数字をアルファベットに変換する。
    • ただし、問題1で作ったプログラムを拡張すること。
  • 起動時引数
    • [0] 0=数字へ変換、1=アルファベットへ変換
    • [1] 変換する数字またはアルファベット(どちらも上限なし)
  • 実行例
    • ExcelColConv.pl 0 AA → 27
    • ExcelColConv.pl 1 27 → AA

90分はかからなかったけどなぁ… まぁ、時間なんてちゃんと測ってないけど。

use strict;
use warnings;

sub exCol2Num ($) {
    my $col = shift;
    $col =~ /^[a-z]+$/io or die "Invalid Excel colmun name '$col'";
    my $num = 0;
    for my $letter ($col =~ /[a-z]/igo) {
        $letter = uc $letter;
        $num = $num * 26 + (unpack('c', $letter) - unpack('c', 'A') + 1);
    }
    $num;
}

sub num2ExCol ($) {
    my $num = shift;
    $num =~ /^\d+$/io or die "Invalid number '$num'";
    $num == 0 and die "Can't convert 0 to Excel colmun name.";
    my $col = '';
    do {
        my $subnum = $num % 26;
        $subnum = $subnum == 0 ? 25 : $subnum - 1;
        $col = pack('c', $subnum + unpack('c', 'A')) . $col;
    } while (($num = int(($num - 1) / 26)) > 0);
    $col;
}

my ($mode, $input) = @ARGV;
my $result =
    $mode eq '0' ? exCol2Num $input :
    $mode eq '1' ? num2ExCol $input : die "Unknown mode parameter '$mode'";
print "$result\n";

まぁでもよい問題ですた。

最近買った本、捨てた本2011年09月04日 16時43分11秒

仕事部屋を片付け中なんですが、疲れたので一休みがてらブログでも…。

最近買った本

会社の会計期が変わったので、参考書を 2冊ばっかし買いますた。わーい、昨期は赤字だー (泣

  • Android NDK ネイティブプログラミング

    会社での当面の主要テーマと称して、otoco という音楽制作・再生環境システム・ライブラリ群 (予定) を開発 (しようと) しているわけですが (全然着手できてないけど T-T)、将来的にこいつを Android に移植する可能性を鑑みて (というか妄想して) 今のうちにある程度勉強しておきたいなー、と購入。

    なんだかおいらの予想に反して結構な勢いでフィーチャーフォン(笑) がスマートフォンに置き換えられて行っているようなので (あんまり望ましい進行状況では無さげですが… 商習慣含めて)、当初予定していたケータイゲーム SNS 向けゲーム開発プロジェクトも中止にして Android アプリ開発に注力しようかなという魂胆でもあります…。まぁ iPhone でもいいんだけど。

  • Android Hacks —プロが教えるテクニック & ツール

    で、NDK の解説書だけだと Android での開発における基本的な文化というか慣習を身につけるのは困難だと思ったので、それほど古くない範囲で Android での開発に関するトピック全般を網羅的にかいつまんで解説してくれていそうな本書を合わせて購入。当面はこっちを読み進めることにしています。

    開発環境ぶち込んでエミュレータぶち込んでとりあえず動くものから代表的なライブラリを扱ったものまで作って覚えて NDK とかにももちろん踏み込んでいてさらにデバッグに関するアドバイスとかまで押さえてくれているっぽいです。さすがは安心の O'REILLY ブランド。

最近捨てた本

っていうか、今日の片付けで捨てることにした本です。明日の資源ゴミに出す予定。

  • Networking Linux

    何でこんなのずっと持ってたんだろう…。 1997年に刊行された本です。流石に古い…。

    いや、なんぼ古くてもネットワークの基礎知識として体系的に学べるような本であれば捨てることはないのですが、内容的にはモデム接続の時代にローカル PC に Linux を入れて PPP 接続することを前提とした解説書なので、DSL 接続に必要な情報ではないし、 BIND (named) とかにも触れてないし、メールサーバーは Sendmail オンリーだし… といった感じだったので、流石に捨てちゃうことにしました…。

    ネットワーク周りの知識は正直あんまり自信がないので、ちゃんと体系的に学べる本が欲しいんですけどね…。

  • Vine Linux 2.1システム管理ブック

    未だに Vine とか使ってる人いるの? っていう… これも相当昔に買った本です。捨てずにいた自分にも驚きですが、ちゃんと Amazon で検索して Hit する (しかも画像もちゃんとある!) ことにさらに驚きです (苦笑)。

  • PERLクイックリファレンスPerl5.6完全リファレンスブック

    前者は確かラクダ本と間違えて買った本ですw。後者は Perl5.6 が出た後にいち早く出版された本で、情報管理社さんの思惑通りに掴まされましたw。いずれにせよ、この手のリファレンスは perldoc にアクセスすれば十分なので (完全ではないけど日本語訳も充実してるし)、古くなってきたし、もう持ってる意味ないかな、という感じです。

  • MySQL徹底入門―ウェブに最適な高速フリー・データベース・サーバー

    この本、もう第3版まで出てるんですね。最新版ではもうちょっとマシになってるんでしょうか? 少なくともこの最初の版は、はっきり言ってセキュリティーホールそのものでしたね。ネット上で prepared statement 使えよっていう議論が盛り上がるよりずっと前の本だったので仕方なかったのかもしれませんが…。

  • HTMLポケットリファレンスJavaScriptポケットリファレンス

    もう、ゴールしてもいいよね…。

    まぁ古いというのもそうなんですが、最近はこの辺は専ら Web 上の情報を参照しています。そっちの方がむしろ正確だったりするんですよね…。 HTML と CSS はとりあえず閲覧性の高いとほほのWWW入門、正確な仕様を確認したい場合は W3C が公開している勧告仕様、 JavaScript は MDC や、 DOM ならやっぱり W3C のこの辺のテキスト辺りを見に行けば大体事足りちゃうので…。

  • 入門CVS 第2版

    sshd_config の書き方とかもあって結構参考になったのですが、今は専ら Subversion (+Trac) を使っていて、流石にもう使うことはないかな、という感じなので…。さらに git に移行すべきかどうかも思案中だったりはするのですが…。

  • 入門 Ajax

    買ったはいいものの、序盤で掲載されている「簡易クロスブラウザライブラリ」という名のオレオレライブラリに辟易してあんまり読んでいません。それだったらもうちょっとまともなライブラリ拾って使うよ、っていう…。

  • 改訂新版 基礎PHP

    当時仲間内で PHP を使うことがあったので買ったんですが、 PHP5 対応を謳いながら内容的にはほとんど PHP4 で止まっている感じで、もうちょっと新たに盛り込まれた言語仕様を活用して愉しみながら楽をしようという発想には至らないものかと首をもたげた覚えしかないです…。 PHP 絡みで優良なリファレンスって公式マニュアルだけなんじゃないかな… いやその公式も結構怪しいもんだけど…。

    その後、おいらもどちらかというと PHP を dis る勢力に荷担することになるわけですが、最近は modern perl と似たようなノリで Modern PHP Programming を謳う勢力も出てきているようで、 PHP プログラミングの慣習も大分まともなものに様変わりしつつあるようですね…。そういう意味でももはや過去の情報となった本書は紙資源へとリサイクルされるべきなのでしょう。

  • 基礎からのJava2

    古いってのもあるんですが、他にも Java の参考書は持っていて、内容的に被るので、より古くて内容の薄い本書は廃棄することに…。つってももう一つ持ってる方も相当古いんですけどね…。

    Android の開発が基本的には Java が主体になるので、できれば Java 言語をちゃんと学べる本 (で、比較的情報が新しいもの) が欲しいんですが、結城さんの本も望洋先生の本も内容が 4~6年前ぐらいで止まっちゃってるのでどうしたもんかなぁ…でも洋書に手を出すほどの元気もないし…っていう。

目的指向プログラミング2010年08月14日 13時53分57秒

からリンクを辿って

を読み、ブクマで糞を投げてみたものの、年配の日本人プログラマーにおいては割とありがちな傾向なのではないかと思うところもあり、ちょっと書いてみようかしらとか思った次第。

オブジェクト指向にありがちな、それもとっても日本人的な誤解のひとつに、「オブジェクト = 物、物体」という解釈があると思う。確かに object という英単語には「物、物体」という意味があるのだけれど、実際には物体を表現しているわけではないオブジェクトについてまで、それを物体だと見立てて思考展開するんだ、と無理矢理自分を納得させながら Java や C# やその他のオブジェクト指向 (に対応した) プログラミング言語で頑張っている人って、実は若手でも少なくないんじゃないかと思う。

object という英単語には他にも「対象」や「目的、目標」などの意味がある。そのことを踏まえた上で、オブジェクト指向による設計について考えてみて欲しい。

例えば Window という名前のクラスがあるとする。このクラスの概要を説明する際、大抵の人は「ウィンドウを表すクラス」と書いてしまうのではないかと思う。これは多分、「オブジェクト = 物、物体」という前提をかなり意識した書き方だと思う。

あるいはポリモーフィズムを意識している人ならばもう少しマシに、「ウィンドウを表す基本クラス」などと書くかも知れない。そして派生クラスとして、FrameWindow があったり、 DialogBox があったり、はたまた見た目にも概念的にもウィンドウとは似ても似つかない FormControl なんてのがあったりするかも知れない。それでもこれらは「ウィンドウを表すオブジェクト」の一種をインスタンスとして生成するためのクラスとして扱われることになる。

まぁでもここまでは、それはそれでいいのかも知れない、とある程度納得できてしまうレベルの話なのかも知れない。フォーム部品もウィンドウの一種だと無理矢理納得することが、思考展開する上で圧倒的に不可能なことだとは思わない。でもそう思えるのは、これらは実行したときに、画面上で割と物体っぽく振る舞う概念だからなのではないか。

ちょっとしたゲームを作ろう、ということになって、その設計を考えたときに、そんなにたいそうなプログラムになるわけでもないし、ということで、実行時のシーンに応じてクラスを分けてみよう、と考えたとする。例えば以下の通りだ。

  • GameTitle
  • GamePlay
  • GameOver

名前を見ただけで、これらのクラスの「役割」は理解できると思う。GameTitle クラスはゲームのタイトルを表示する。プログラム実行時に最初に呼び出されるシーンだ。GamePlay クラスは実際にゲームを遊ぶプレイ中の制御処理を行う。タイトル表示シーンから特定のコントロール操作 (「start」ボタンを押す、等) により呼び出される。GameOver クラスはゲームオーバーになったときに行われる動作だ。スコアを表示したり、ハイスコアランキングに登録したり、といった処理が考えられる。

そもそもこのような設計手法は妥当なのか? 現実問題としてこのプログラムを実行時のシーンに応じてモジュール分けすると言うことは十分考えられることなので、少なくとも手段のひとつとして絶対にあり得ないと言うことはないだろう。個人的にはこれはこれで十分アリだと思うが、実際の開発においてはチームで議論するなり、リーダーが自身のセンスに基づいて主導するなりすればよいことだ。閑話休題。

さて、これらのクラスの概要を書くとしたら、あなたはどんな風に説明するか? 「ゲームタイトルを表すクラス」? 「ゲームプレイを表すクラス」? 「ゲームオーバーを表すクラス」? どれもクラス名以上のことは書いていない。そろそろ、「○○を表すクラス」論法は無理が生じてきていると言えるのではないだろうか?

それよりも、「本クラスにおいて、」と前置きして (あるいはそう前置きされている物と仮定して)、「ゲームタイトルのアニメーション表示を実装する」、「ゲームプレイ中の中枢的な制御を実装する。具体的には以下の制御が対象となる: …」、「ゲームオーバーの処理を実装する。ハイスコアランキングの登録を含む」などと説明した方が、すっきりするだろう。

オブジェクト指向の「オブジェクト」とは、観念的に「物」や「物体」を表すことを指す、と考えるより、設計においてプログラムを個別の部品というかモジュールに分ける際に、そのモジュールが何を「目的」として実装されるのか、そのモジュールが「目的」としている「対象」は何なのか、をはっきりさせるための、プログラミング上での表現手法、と考えるべきだ。

生成されるインスタンスを観念的に「物」と言い表すことはできるかも知れないが、オブジェクト指向プログラミングにおいて重要なファクターは、必ずしもそこだけではないはずだ。「クラスもインスタンスも両者を含めてオブジェクトと言います」なんて説明で日本人プログラマーをはぐらかすのはもう止めよう。オブジェクト指向とは、プログラムを「目的」単位でモジュール化する手法である。その単位こそが (文字通り) クラスであり、従ってクラスの説明は実装の目的を記述することであるべきだ。

そのことを念頭に置き、そうした観念に頭が慣れるまでは、「オブジェクト指向」という語は封印し、代わりに日本語で潔く、「目的指向」と言い表すようにした方がよいのではないか、と提案する次第なのである。

JavaScript: どんな型の値でもとりあえずメンバフィールドに値を突っ込んでみるテスト2010年08月05日 13時06分43秒

えー。長らく更新をサボって申し訳ない。しかも今回の内容は完全に個人的なメモなのでなおさら申し訳ないw

JavaScript って割とオブジェクト指向的な性格の強い言語だと思うんだけど、いわゆるオブジェクト型の値に限らず、関数型の値であってもメンバフィールドを持つことができたりして、その辺どうなっているのか、っていう辺りを整理しておきたかった。

で、以下のような HTML を書いてみたわけだ罠。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>

<head>
	<meta http-equiv="content-type" content="text/html; charset=UTF-8">
	<meta http-equiv="content-style-type" content="text/css">
	<meta http-equiv="content-script-type" content="text/javascript">
	<title>member field test</title>
    <script type="text/javascript" language="JavaScript"><!--
window.onload = function() {
    var table = document.getElementById("result");
    if (table.firstChild.nodeName.toLowerCase() == "tbody") // IE6 対策
        table = table.firstChild;
    var testdata = [ 1, "", true, undefined, null, Infinity, NaN, function() {} ];
    for (var i = 0; i < testdata.length; i++) {
        var tr = document.createElement("tr");
        // 値を表示
        var td = document.createElement("td");
        td.appendChild(document.createTextNode(
            typeof testdata[i] == "function" ? testdata[i].toString() :
            typeof testdata[i] == "string" ? '"' + testdata[i] + '"' :
            testdata[i] === null ? "null" : // Gecko はこうしないと空欄になっちゃうので…
            testdata[i]));
        tr.appendChild(td);
        // 型を表示
        td = document.createElement("td");
        td.appendChild(document.createTextNode(typeof testdata[i]));
        tr.appendChild(td);
        // フィールドへの代入を試みる
        td = document.createElement("td");
        var result;
        try {
            testdata[i].hoge = "Hoge!!";
            result = testdata[i].hoge;
        }
        catch (ex) {
            result = ex.toString();
        }
        td.appendChild(document.createTextNode(result));
        tr.appendChild(td);
        table.appendChild(tr);
    }
};
    //--></script>
</head>

<body>

<table id="result" frame="border" border="1" rules="all">
  <tr><th>値</th><th>型</th><th>x.hoge</th></tr>
</table>

</body>

</html>

結果はこんな感じ。一応 IE6、Firefox、Safari にて動作確認済み。

結論をまとめると以下の通り。

  • ブラウザ間で動作の差異は見られなかった。
  • null の動作が意外なほど undefined の動作に酷似している。オブジェクト型のくせに。ていうか、全くの別物なのに。
  • メンバフィールドに入れた値をその後も利用できるのは、通常のオブジェクト型の値を除けば関数型の値のみ。
  • 数値、文字列、真偽値については、メンバフィールドへの値の代入のようなことをやっても例外は発生しない。が、あとでそのフィールドを参照すると undefined が返される。中途半端な動作だな。 undefinednull は代入しようとした時点で例外が発生。
    • ついでに言うと、undefinednulltoString() メソッドを適用することもできなかった (例外を送出する)。undefined についてはそも値ではない (より厳密には「インスタンスではない」) からということで納得がいくんだが、null についてはなんだろ…オブジェクトなんだけどオブジェクトじゃないものであるということをことさらに表現したい、ってことなのか??