檜山正幸のキマイラ飼育記 このページをアンテナに追加 RSSフィード

キマイラ・サイトは http://www.chimaira.org/です。
トラックバック/コメントは日付を気にせずにどうぞ。
連絡は hiyama{at}chimaira{dot}org へ。
蒸し返し歓迎!
このブログの更新は、Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama
ところで、アーカイブってけっこう便利ですよ。

2012-06-20 (水)

Catyの特徴と機能をイメージできるようなオハナシ

| 12:46 | Catyの特徴と機能をイメージできるようなオハナシ - 檜山正幸のキマイラ飼育記 を含むブックマーク

先ほど書いた記事を受けて、Catyに関する情報不足をナントカする試み。

技術的な背景や設計判断に関して述べることはいくらでもあるのですが、それ以前に、「それはなに?」「なにがうれしい?」さえも説明してない/できてないですね。

「それはなに?」「なにがうれしい?」のイメージがある程度は湧くように、次の2つのキャッチフレーズに絞って、どんなことがどのように出来るかを描き出したいと思います。

  1. ミーティングが終わったら出来ている
  2. 作り方を作れる

ミーティングが終わったら出来ている

例えば、新しいWebサービスに関してブレーンストーミングをするとか、顧客と業務システムの概要について打ち合わせをするとか、ひとしきりディスカッションをして、だいたいの合意が取れたとしましょう。「こんな感じかなー」というシステムイメージは、おおざっぱなロバストネス図として描けた、と、そうしましょう。

Catyではロバストネス図類似の視覚化表現をコマンド一発で描けます。(図は「ユースケース図もどき、とか」よりの引用)

この図のもとになるのは、一種の仕様書ですが、その一部を引用すると:(全文は「ユースケース図もどき、とか」にあります。)


resource 予約ページ  ("/reserve.html") {
   action 取得("/GET")
   :: @[in, out] #0 void -> void produces 予約注文画面 ;
};


state 予約注文画面 for 顧客 :: defered links {
 + 予約 --> 予約処理.予約;
};


resource 予約処理 ("/process.cgi") {
  action 予約("reserve/POST")
  :: @[in]  #in LunchOrder -> _        relays [ng, ok],
     @[out] #ng _          -> void     redirects 予約ページ.取得,
     @[out] #ok _          -> LunchOrder produces 確認画面
  ;
  // ...
  // ... 省略
  // ...
};

構文の詳細はともかくとして、画面やアクション(サーバー側で実行されるプログラム)が記述されているのはわかるでしょう。構文に慣れてしまえば、メモ書きや議事録として、この“仕様”をその場で書くことができます。

この仕様は、単に視覚表現の元データということではなくて、Catyにとって理解可能/実行可能な形式です。つまり、一種のプログラムであり、Webシステム実装の一部なのです。

実行可能な形式なので、その場でWebシステムとして動かすことができます。もちろん、デザインはまったくしてないし、プログラムロジックも一切記述されてないので、仕様に書かれたデータ型やハイパーリンク構造を確認できる程度ですが、最初のプロトタイプとしては使えます。

つまり、ミーティングが終わったら時点には、最初のプロトタイプが動き出します。

作り方を作れる

今までのハナシで、仕様からプロトタイプを作り出す機能をCatyが組み込みで持っていると思った方もいるでしょう。それは違います。そうじゃありません。Catyがもともと持っている機能は、データ型やらスクリプトやらのメタオブジェクトを通常のデータ(JSONデータです)に“落とす”機能です。

この機能を我々はレイフィケーション(reification)と呼んでますが、リフレクション(reflection)とかイントロスペクション(introspection)と呼ぶほうがお馴染みでしょう。設計時/プログラミング時に概念として意味を持つ情報が、実行時にもデータとして存在していて、かつ“概念を表現するデータ”(メタオブジェクト)をプログラムで操作可能なのです。

Webシステムの設計時に意味を持つ、クライアント状態(画面)、リクエスト処理、ハイパーリンクなどが、実行時のメモリ内にも存在します。そして、それらのメタオブジェクトをJSONデータとして取り出せて、JSON処理/文字列処理により好きなように加工できます。この加工それ自体は単なる普通のデータ処理に過ぎませんが、元々がメタオブジェクトだったのでメタプログラミングとなります。

メタプログラミングの応用のひとつとして、仕様に相当するメタオブジェクト群からプロトタイプを生成すること出来るわけです。Catyがもともと「プロトタイプを作る機能」を持っているのではなくて、「『プロトタイプを作る機能』を作る機能」を持っているのです。

Catyプロジェクトの初期の頃から、マゾ・テストというものを目標のひとつにしてきました。これは、「自分をテストするためのテストコードを自分で作り出して、自分自身をテストする」機能です。まだマゾ・テストは出来ません。課題が残っています。でも、メタプログラミングの能力を洗練・増大させれば、マゾ・テストもあながち夢でもなかろう、と思っています。

2011-11-08 (火)

WebアプリケーションフレームワークCatyの特徴と方向性

| 15:30 | WebアプリケーションフレームワークCatyの特徴と方向性 - 檜山正幸のキマイラ飼育記 を含むブックマーク

WebアプリケーションフレームワークCatyの現状と今後」と似たような題名の記事、まー続きのようなものです。Catyのプロモーション的なことをしてないので、少し宣伝風に書いてみようかと。

Catyプロジェクト/ソフトウェアについて」(2009年8月)あたりから勘定すると、Catyプロジェクトも2年以上が経過しました。Catyの開発は少しずつしか進んでいませんが、それでも歩みを止めたことはなかったので、気がつけば随分と成長しました。

~/ProjectCaty/OLD $ hg parent
changeset:   2343:753012695e08
tag:         tip
user:        m_hiyama
date:        Thu Aug 11 11:38:50 2011 +0900
summary:     混乱を避けるため、仕様文書を削除 その2

~/ProjectCaty/OLD $ cd ../dev

~/ProjectCaty/dev $ hg tip
changeset:   247:e318a0d5dd85
tag:         tip
user:        ckuwata
date:        Tue Nov 08 10:22:19 2011 +0900
summary:     Issue #163を修正

~/ProjectCaty/dev $ hg locate | wc -l
804

~/ProjectCaty/dev $

以前の古いリポジトリでリビジョン2343まで、今のリポジトリではリビジョン247です。公開リポジトリに登録されているファイル数は804、作業領域にはもっとたくさんのファイルがあります。

諸般の事情で、完成度が高い部分と放置状態の部分が混じってますが、特定の用途で安定した部分だけを使うなら、十分に実務で使える水準にあります*1

しかしCatyは、どんな用途でも使えるかというと、そうではありません。特定の状況を想定して、その状況に対する極端な最適化をしているので、その想定から外れる用途ではウレシクナイことになります。そしてもちろん、「想定している状況」にハマれば、とてもウレシイと思います。その「想定している状況」を次の3つの観点から説明します。

  1. どのような体制でサイト/アプリケーションを作るのか?
  2. どのようにサイト/アプリケーションが運用されるのか?
  3. どのような設計手法を使うのか?

最後のほうで、思い出話とか雑感とかを付け足します。

内容:

  1. チーム、ロール、専用言語
  2. 徹底的に分業できる
  3. 頻繁で激しい変化に対応する
  4. クライアント中心で設計する
  5. まとめ
  6. 檜山にとっての課題

チーム、ロール、専用言語

Catyでは、目的のサイト/アプリケーションを比較的小規模のチームで作ることを想定しています。10人以内くらいです。少人数ではあっても、複数の人々が関与するのが重大なポイントです。一人で作ることは想定していません(一人で作っても別にいいですけどね)。

作業者の分類として3つのロールを仮定します。そのうち2つは、Webデザイナとプログラマです。残る1つ、これを何と呼んでいいか悩みます。以前はスーパーバイザーと呼んでいたのですが、なんか違うな、と。システムの設計者という意味ではデザイナなのですが、それだとWebデザイナと区別付かないし。最近は、指揮者の意味でコンダクターとしていますが、適切かどうかわかりません。とりあえずは、コンダクター、Webデザイナ、プログラマとします。

これら3つのロールが、作業者個々人と対応するとは限りません。一人三役でもかまいません。Webデザイナのロールを、複数の会社で担うこともあるでしょう。あくまでも役割なのです。それぞれのロールが行うことは:

  • コンダクター: サイト/アプリケーション全体の構造を定義して、Webデザイナとプログラマの作業範囲を明確にする。
  • Webデザイナ: 静的ファイルとHTMLテンプレートを作る。CSSスタイルシートやJavaScriptコードの作成なども作業範囲に入ります。
  • プログラマ: CatyScriptまたはネイティブ言語(現在はPythonだけ)で、コマンドと呼ばれるプログラム実行単位を作成する。

それぞれのロールに対して、作業を進めていくための専用言語が与えられます。Catyに備わっている言語の種類は次のとおりです*2

  1. CatySchema*3 -- Catyスキーマ言語: 型の定義、コマンドの宣言と定義ができます。
  2. CatyResAct -- Catyリソース・アクション(・状態)記述言語: Webから見えるインターフェースであるリソースクラスとアクションの宣言と定義ができます。「WebアプリケーションフレームワークCatyの現状と今後」を参照。
  3. CatyScript -- Catyスクリプト言語: 実行可能なコマンドのコーディングができます。
  4. CatyTemplate -- Catyテンプレート言語: Smartyとよく似た(完全互換ではない)テンプレート言語です*4

ロールごとに使用する言語は:

  • コンダクター: CatySchemaとCatyResActを使います。
  • Webデザイナ: CatyTemplateとCatyScriptを使います。その他、標準的なHTML、CSS、JavaScriptなども当然使うでしょう。
  • プログラマ: CatyScriptとネイティブ言語(Python)を使います。

これは、典型例を単純化したもので、実際には、コンダクターがCatyScriptでコマンドを書いてしまうこともあるし、プログラマがCatySchemaを書く必要もあります。どのロールであってもCatyScript(最低でもJSON構文)の知識は必要です。

徹底的に分業できる

ここで「分業できる」とは次のことを意味しています。

  1. 分割したパートごとの作業の範囲/境界線が明確である。
  2. パートごとの作業結果の正しさがソフトウェアにより(完璧じゃなくても)確認できる。
  3. 他のパートの進捗に影響されない。他のパートの作業が先行してようが、まったく未着手であろうが、それに無関係にパートごとの作業ができる。ただしコンダクターの作業は先行する必要がある(後述)。
  4. 他のパートの担当者と対面(face-to-face)による打ち合わせがほとんど必要ない。

これらのことを可能とするためには、コンダクターによる全体構造の記述が先行する必要があります。もし、コンダクターの作業負担が大きいなら、他のロール/パートの作業を開始できないので元も子もありません。だから、Catyはコンダクターの負担を減らすことに拘っています*5

また、コンダクターとWebデザイナ/プログラマがほぼ同時に作業を開始できるためには、設計が不完全/未完成であっても、やれる部分からドンドンやっていける必要があります。仕様が変わるのは当たり前なので、変化に対する負担を最小化して、変化を前提に作業をするのです。

技術的に言えば、「分業できる」を支えているのは型システムとバリデータです。パートの境界線には必ず型が定義されており、型の制約が常にチェックされます。型のチェックだけでは完全ではありませんが、それでもあきらかな矛盾はソフトウェアが検出します。仕様の変更により不整合が起きても、型エラーで報告されます。これによる心理的な効果はかなり大きく、変更に対する恐怖心や嫌悪感は薄らぎます。

他のパートからの影響を最小化するためには、パート内で完結したテストが行なえて、単体テストを通ることが統合時の安全性までも保証しなくてはなりません。「単体テストなんてやっても意味ない」という意見を聞くことがあります。その理由は「どうせ統合テストでさんざんにバグが出て直すハメになる。二度手間なだけで無駄」。Catyは型システムの助けを借りて、コンポネントレベルの正しさが全体の正しさを保証するように努めています(100%確実じゃないですけど)。

頻繁で激しい変化に対応する

Webサイト/アプリケーションが、一度作ってソレッキリということは少ないでしょう。とはいえ、内容は更新されるが構造は変わらないサイト/アプリケーションは意外に多いかもしれません。そのようなサイト/アプリケーションにはCMSが向いているのでしょう。

Catyは頻繁で激しい変化に対応できることを念頭に置いてますが、内容の変化ではなくて、サイト/アプリケーションの構造そのものがドンドン変わってしまうような状況を想定しています。例えば、トップページしかない状況で公開して、出来た順に機能を追加し、問題があれば遠慮無く変更や破棄をするようなサイトです。

構造が変わるということは、内容の差し替えでは対応できません。プログラムを書き換える/書き足す必要があるでしょう。全体の構成も変えるかもしれません。そのような変更をしたときに、全体の整合性は保たれるでしょうか? 稼動しているプログラムと、ヘルプやドキュメントが乖離してしまうのではないでしょうか? Catyはこれらの問題に対処する手段を提供しています*6

クライアント中心で設計する

Webサイト/アプリケーションは、主にサーバーサイドで動作します。よって、サーバー側に置いてあるデータベースとかバックボーンのシステムの構造に強く影響されることが多いと思います。

しかし、Webサイト/アプリケーションの利用者はWebクライアントを操作します。バックエンドの事情よりむしろ、クライアントからどう見えるかを重視すべきだと僕は思います。これは、クライアントが人間+ブラウザのときに限りません。Web APIであってもやはり、クライアント状態とその遷移を中心に考えるべきです。

このことは、「Webサービスを設計するための単純明快な方法」で書いたので、そちらも参照してください。

CatyResAct言語は、クライアント状態を中心に記述する構文を持っています。また、「WebアプリケーションフレームワークCatyの現状と今後」で触れた未完の機能「インスタントモックアップ」は、宣言されたクライアント状態をオンザフライで生成する仕組みです。

まとめ

冒頭に挙げた問に答えておきましょう。

  1. どのような体制でサイト/アプリケーションを作るのか? → 比較的少人数のチーム。メンバーは空間的地理的に離れていてもかまわない。それぞれの作業時間や進捗にバラツキがあってもかまわない。
  2. どのようにサイト/アプリケーションが運用されるのか? → 頻繁に激しく構造が変化するかもしれない。内容だけでなく、プログラムの追加変更もよく行われる。
  3. どのような設計手法を使うのか? → クライアント中心の設計。

檜山にとっての課題

Catyプロジェクト/ソフトウェアについて」に次の記述があります。

後から思い起こしたのですが、だいぶ以前に小さな実験的なプロジェクト/ソフトウェアにKatyという名前(これもアクロニムじゃない)を付けたことがあるので、僕はこのての名前が好きみたいです。

メモ編でKatyを検索してみると:

2006年の日記が引っかかりますが、それより前からやっていたものです。2008年くらいに少し試していた実験的Webフレームワークの名前はcathandでした。cathand実験はCatyプロジェクトと時間的にオーバーラップしています。

いずれのときも、僕の興味と課題は、先にも挙げた「コンポネントレベルの正しさが全体の正しさを保証する」ことです。このことが、フレームワークの使命と価値じゃないかと思ってます。

「正しさを保証する」というのは、とても難しいことで、あまり生真面目にやるのは精神衛生上よくありません。「正しさを保証する」意図は保ちながらも現実的な妥協をして「手を抜く」必要もあります。それで、手の抜き加減がまた難しい、と。

なにはともあれ、ハッキリしてないことを実装してしまっては「正しさを保証する」なんて出来っこありません。いやまー、現実的な設計判断でハッキリしてない機能が入ることも“ナキニシモアラズ”ですけど … 。可能な限りではありますが、形式意味論(モデル、セマンティックス)を持たない機構は採用しない方針でやっています。

Catyプロジェクト/ソフトウェアについて」の時点で既に次のように書いています。

コマンド(と呼ぶプログラム実行単位)は、半環圏の上のスタンピング・モナドのクライスリ射でモデル化できるようになっています。

[半環圏は] 2つのモノイド積を持ち、それらが半環(semiring)の法則を満たす圏です。2つのモノイド積を使って2種類のスタンピング・モナドを構成できます。一方が例外モナド、もう一方が副作用モナドに対応します。

昨日の「大量のモナド類似物を取り扱う方法:参考文献」とか、少し前の「デカルト作用圏が面白い」とか、その動機(の一部)はCatyのカテゴリカル・モデリングを確定したいからです。

理屈通りにはいかないのは承知ですが、だからといって理屈を無視してうまくいくわけもなく(破綻するでしょう)、「理屈通りにいったら素晴らしいだろう」という希望に賭けてみるほうがなんか楽しそうだ、と僕は思っています。

*1:インハウスで使う安定版がありますが、公開はしていません。

*2:CatySchemaとCatyResActは概念的には同じ言語で、実装もほとんど統合されています。用途が違うだけです。また、CatyScriptはCatySchemaに埋め込まれているので、CatySchema/CatyResAct/CatyScriptは、実質的には単一の言語です。

*3:SchemaをSchemeと書き間違えた。この間違えで検索とかに引っかかったらゴメンナサイ。

*4:仕組みとしては、テンプレート言語を自由に切り替えることが可能です。しかし、現在まともに使えるテンプレート言語はSmaty風のものだけです。

*5:IDEプラグインとかGUIデスクトップツールを用意できればいいんでしょうが、残念ながらそこまで手を回す余裕は全然ありません。

*6:カニンガムのFIT/FitNesseやクヌースの文芸的プログラミングに触発された機能です。が、高邁なものではなくて、安直で単純なものです。もう少し機能を追加して洗練させる必要があります。

かずくんかずくん 2011/11/10 01:29 > サイト/アプリケーション全体の構造を定義して、Webデザイナとプログラマの作業範囲を明確にする。
ディレクター?
ちょっと違うか...

m-hiyamam-hiyama 2011/11/10 16:28 かずくんさん、
第三のロールに要求されていることは: スキーマ言語を使って型定義をする、コマンドの入出力仕様を決める、URL設計をする、ハイパーリンクトポロジーを考える、とかです。
現在使われている「ディレクター」という言葉は、どうもそのような意味を持たない感じです。

2011-10-14 (金)

WebアプリケーションフレームワークCatyの現状と今後

| 16:11 | WebアプリケーションフレームワークCatyの現状と今後 - 檜山正幸のキマイラ飼育記 を含むブックマーク

最近どんな感じで、何を目指してやっているのかを簡単に紹介します。目指していることはイッパイあるのですが、特に「インスタントモックアップ」と我々(僕とKuwataさん)が呼んでいる機能にフォーカスします。インスタントモックアップは、最近着手したばかりで何も出来てないのが実状ですが、できたらけっこう便利そう。すごく便利かもしれません。

インスタントモックアップの目標は「Webサイト/Webアプリケーションのプロトタイプ作成の労力を、百分の一にする」ことです。効率を二桁上げたいわけね。なんかホラ話みたいでしょ。実際、誇張表現なんですが、まったく根拠がないわけでもないんですよ。

内容:

  1. 例題「ユーザー管理業務」
  2. Catyの用語を少しだけ
  3. モジュールの構造
  4. 定義が書いてないモジュール
  5. 何をすべきかはナントナク予想できる
  6. どんなに中途半端・不完全な設計でも動かす

例題「ユーザー管理業務」

1年たって、手書きから自動描画へ」と「ハイパーバリデーションに向けて」で、Catyで状態遷移図の自動描画が出来るようになったことを紹介しました。それで、Kuwataさんと僕が作ったサンプルじゃない例題を探していたら、http://terasoluna.sourceforge.jp/tutorial/server-web/Document/WebTutorial_2.html にある図(URL: http://terasoluna.sourceforge.jp/tutorial/server-web/Document/WebTutorialImg/WebTutorial_2.1_01.png)を発見しました。Webサイトというより業務アプリケーションですが、これはこれで典型的な例だと思えるので拝借します。

この図とほぼ同じ状態遷移をCatyにより定義して可視化すると次のようになります。

もとの図の初期画面というのは省略しました。他の画面は、Catyが描いた図の黄色い四角と対応します。

  1. ログオン画面 → dummy-logon
  2. メニュー画面 → menu
  3. 一覧表示画面 → list
  4. 登録画面 → register
  5. 結果画面 → result

画面遷移を引き起こす“操作”の対応は下に挙げます。ログオン関係は省略しています(それでダミーログオンと命名)。「5ページ進むリンク」「5ページ戻るリンク」も煩雑になるという理由で省いています。Catyの図の辺ラベルに付いているプラス記号は気にしないでください。状態遷移を引き起こす操作の名前にプラスが付いていると思ってください*1

  1. 「一覧画面」ボタン → + to-list
  2. 「登録画面」ボタン → + to-register
  3. 「前へ」リンク → + next
  4. 「後へ」リンク → + prev
  5. 「ページ番号」リンク → + go-to
  6. 「登録」ボタン → + do-register
  7. 「メニュー」リンク → + menu
  8. 「ログオフ」ボタン → + logoff

もとの図とCatyが描いた図が、ほぼ対応が取れていることが分かれば十分です。(グラフのレイアウトは、Graphvizレイアウトエンジンに任せているので、画面ノードの配置までもとの図に似せることはできないです。あしからず。)

Catyの用語を少しだけ

説明のためには、基本的な言葉が必要です。

  • アプリケーション -- ひとつのWebサイトやWeb APIプロバイダに対応する単位です。1個のCaty実行インスタンスにより複数のアプリケーションを提供できます。
  • モジュール -- アプリケーションの挙動を宣言・定義するファイルです。ひとつのアプリケーションはいくつかのモジュールから構成されますが、簡単なアプリケーションなら単一モジュールで十分です*2。モジュールには、後述する状態、アクション、リソースクラスの定義が含まれます。
  • 状態(≒画面) -- アプリケーション状態、あるいは単に状態とは、Webクライアントの実行時スナップショットのようなものです。典型的な状態はブラウザの画面なので、状態とは画面だと思ってかまいません。
  • アクション -- HTTPリクエストで起動されるサーバー側のプログラム(リクエストを処理する単位)のことです。
  • リソースクラス -- アクションをグループ化したものがリソースクラスです。リソースクラスはURLのパターンを持ち、このパターンにマッチするURLとHTTPメソッド等でアクションが識別されます。

モジュールの構造

僕が毎日実際に使っているアプリケーションのモジュールを紹介しましょう。Wiki記法で書いた仕様文書を提供するだけの簡単なアプリケーションで、単一モジュールで出来ています。

/** specdocsアプリケーションのリソース&アクション 
 */
module specdocs in cara;

/** ディレクトリ・リソース
 */
resource Dir("/" | "*/") {
  /** ディレクトリへのGETリクエスト */
  action dir-get("/GET") 
  ::
  {
   %CATY_APP  | $.name > app;
   { 
     "wikifiles" : lsdir %PATH_INFO .wiki | each {pv name},
     "subdirs"  : lsdir --kind=dir %PATH_INFO | each {pv name},
     "path" : %PATH_INFO,
     "app" : %app,
     "title" : [%app, " ", %PATH_INFO] | text:concat
   } | print /list-files.html
  };
};


/** Wikiファイル・リソース
 */
resource Wiki("*.wiki") {
  filetype {
   "contentType" : "text/x-wiki",
   "isText" : true,
  };

  /** WikiファイルへのGETリクエスト */
  action wiki-get("/GET")
  ::
  {
    {
      "content": file:read %0 | text:creole, 
      "title"  : %0 | path:trunk 
    } | print /show-wiki.html
  };
};

小さなモジュールでも、はじめて見ると複雑な印象を持つかも知れません。単純化してみましょう。specdocsと名付けられたモジュールには、2つのリソースクラスが含まれます。

/** specdocsアプリケーションのリソース&アクション 
 */
module specdocs in cara;

/** ディレクトリ・リソース
 */
resource Dir("/" | "*/") {

 // ...

};


/** Wikiファイル・リソース
 */
resource Wiki("*.wiki") {

 // ...

};

Dirという名前のリソースクラスに注目すると:

/** ディレクトリ・リソース
 */
resource Dir("/" | "*/") {

  /** ディレクトリへのGETリクエスト */
  action dir-get("/GET") 
  // ...

};

dir-getというアクションがあります。Dirリソースクラスは、このアクション1つしか持ちません。同様に、Wikiリソースクラスもwiki-getという1個のアクションだけで出来ています。

Catyのコンソールヘルプで見ると、次のような感じです(見た目がショボい(苦笑))。

定義が書いてないモジュール

モジュールには、アプリケーションを構成する状態(画面)、リソースクラス、アクションを記述します。実際に動作するのはアクションですが、このアクションはCatyScriptといスクリプト言語を使って書きます。

ところが、アクションの内容は書かなくてもCatyは何も文句を言いません。先の例題「ユーザー管理業務」を記述したモジュールでも、アクションの中身は何も書いてません。以下に実物を示しましょう。

/** ユーザー管理業務モジュール */
module user-mgr in cara;


/* == 型定義 == */

/** ユーザーリストの型 */
type UserList = deferred; // 後で定義

/** 登録UIが持つデータの型 */
type RegisterUI = deferred;

/** 登録されるユーザー情報の型 */
type UserInfo = deferred;

/** 登録完了時に戻されるデータの型 */
type Result = deferred;


/* == リソースと画面(状態)の定義 == */

/** メニュー画面の生成 */
resource Menu ("/menu.html") {
 action get("/GET")
 :: @[in, out] #1 void -> void produces menu ;
};

/** メニュー画面 */
state menu :: void links {
 + to-list     --> List.get;
 + to-register --> Register.get;
 + logoff      --> DummyLogon.get;
};

/** ユーザー一覧の生成 */
resource List ("/list.cgi") {
 action get("/GET#dont-care")
 :: @[in, out]#1 void -> UserList produces list  ;

 action next("next/GET#dont-care") {"current": integer}
 :: @[in, out]#1 void -> UserList produces list ;

 action prev("prev/GET#dont-care") {"current": integer}
 :: @[in, out]#1 void -> UserList produces list ;

 action go-to("go-to/GET#dont-care") {"current": integer, "target": integer}
 :: @[in, out]#1 void -> UserList produces list ;

};

/** ユーザー一覧画面 */
state list :: UserList links {
 + list  --> List.get;
 + next  --> List.next;
 + prev  --> List.prev;
 + go-to --> List.go-to;
 + menu  --> Menu.get;
};

/** 登録画面の生成 */
resource Register("/register.html") {
 action get("/GET")
 :: @[in, out]#1 void -> RegisterUI produces register ;
};

/** 登録画面 */
state register :: RegisterUI links {
 + do-regster --> DoRegister.do;
 + menu       --> Menu.get;
};

/** 登録処理実行 */
resource DoRegister("/do-register.cgi") {
 action do ("/POST#dont-care")
 :: @[in] #in UserInfo -> _          relays [ok, ng],
    @[out]#ok _        -> Result     produces result,
    @[out]#ng _        -> RegisterUI produces register
 ;
};

/** 結果表示画面 */
state result :: Result links {
 + menu --> Menu.get;
};

/** ダミーのログオン画面の生成 */
resource DummyLogon ("/dumy-logon.html") {
 action get("/GET")
 :: @[in, out]#1 void -> void produces dummy-logon ;
};

/** ダミーのログオン画面 */
state dummy-logon :: void links {
  + menu --> Menu.get;
};

アクションがどう動くかの手続きは一切書いてありません。全体の構造が把握しやすいように、リソースクラスとアクションも含めた図をCatyに描かせてみましょう。

緑の箱がリソースクラスで、そのなかに入っている薄緑の丸がアクションです。画面を表す黄色の四角から出ている紫の線がHTTPリクエスト、サーバー側にいるアクションから出ている赤い線がHTTPレスポンスです。

何をすべきかはナントナク予想できる

モジュールに手続きを一切書いていませんが、宣言は丁寧にしています。先に挙げた画面遷移図やリソース&アクションの構成図は、モジュール内の宣言だけに基づいて描いています。

もっと局所的な情報、例えば「Menu.get というアクションを呼び出している状態(画面)達」を知りたいなら次のようにします。

さらに、アクション定義が書いてないにもかかわらず、アクションが何をするのか?分かってしまうようなケースもあります。ユーザー登録を実際に行うアクションであるDoRegister.doを見てみましょう。

どうですか? 次のようなことがソコハカトナク読み取れます。

  1. register画面からdo-registerというボタン(かなんか)を押して、DoRegister.doを呼び出す。
  2. このとき、フォーム(かなんか)で、UserInfo型のデータをサーバーに送る。
  3. UseInfo型データを受け取ったDoRegister.doは、入り口(in)でそれが正しいかどうかバリデーションする。
  4. バリデーションが成功(ok)だったら、Result型データの情報を持ったresult画面を表示する。
  5. バリデーションが失敗(ng)だったら、RegisterUI型データの情報を持ったregister画面をもう一度表示する。

僕ら人間が、この程度のことをたやすく推測できるってことは、ある程度賢いプログラムなら同じことを推測できるでしょう。そのような推測を実際に行なって、定義が何も書いてないモジュールからでも動作するWebアプリケーションを瞬時に作り出してしまう機能 -- それがインスタントモックアップです。

どんなに中途半端・不完全な設計でも動かす

モジュールは、Webサイト/Webアプリケーションの仕様だとも言えます。しかし、単なる文書や指示ではなくて、それは実装の一部に組み込まれて動作します。設計成果物であると同時に、実行されるソースコードなのです。

インスタントモックアップとは、実装作業が何ひとつ出来てなくても設計成果物さえあればプロトタイプが動く、ということです。もちろん、アクションがちゃんと書いてあればその書かれたスクリプトが動作します。スクリプト部分に何も書いてなかったりコメントアウトされていると、それらしい動作をCatyが作り出します。(そうなる予定

こう言うと、「ソースコード自動生成か」と思う人がいるでしょうが、そうではありません。ソースコード自動生成は弊害もあり、僕はいい方法だとは思っていません。「それらしい動作」は、CatyScriptのインタプリタがその場で考えて行うのです。

今、「設計成果物が動く」と言いましたが、その設計成果物が完成品である必要はありません。そもそも何をもって完成なのか分かりませんしね。Catyは、モジュールの整合性チェックをゆるやかに行うので、行き先のないリクエストや、未定義の型(deferred型)があってもエラーとはしません。なにかしらモジュールに書いてあれば、書いてある分だけの情報でそれなりに(モジュールの不完全さを反映した不完全さで)動くでしょう。(そうなる予定


以上に述べたことは構想に過ぎません。が、夢想ではありません。かなり強力な型システム、たいていの処理は書けるようになったスクリプト言語とそのインタプリタ、型推論機構(これは未完)、型付きテンプレートエンジン、可視化ツールのような周辺ユーティリティ、などは既に存在します。「プロトタイプ作成の労力を、百分の一にする」は、誇張が含まれるという意味でホラですが、ウソやデタラメではないだろうと思っています。

*1:実際には、静的HTMLファイルやテンプレートなどの担当者が責任を持つリンクにプラスが付いています。

*2:正確には、cara(キャラ)モジュールと呼ばれるものですが、今回の話に出てくるモジュールはcaraモジュールだけです。

2011-08-30 (火)

1年たって、手書きから自動描画へ

| 16:47 | 1年たって、手書きから自動描画へ - 檜山正幸のキマイラ飼育記 を含むブックマーク

今から1年と少し前に「Webサービスを設計するための単純明快な方法」という記事を書きました。そのなかで次のような手書きの絵を出しました。

Webサービスの設計:Webの状態遷移図の描き方」では、図に関する説明を追加しました。

上の図で番号が付けられている各部の名称は次のとおりです。

  1. トリガー
  2. リクエスト辺
  3. アクションノード
  4. レスポンス辺
  5. 状態ノード

このような絵を、僕はもう手書きしなくて済みそうです。状態、トリガー、アクションなどの繋がり具合を記述するファイルから、状態遷移グラフを生成できるようになりました(Graphvizを使っています)。

このグラフのもとになるデータは単に図のための記述ではありません。それ自体がWebアプリケーションの設定ファイルになっています。“設定”というより、Webアプリケーション“そのもの”だ、と言ってもいいかもしれません。なぜなら、Webアプリケーションの外部仕様を決定しているファイルだからです。

もう少し完成度が上がったら詳細を報告することにします。(あと1年はかからないと思います :-))


[追記] Kuwataさんが作ったサンプル「Wikiシステム」の絵が手頃な大きさで見ばえもいいので載せておきます。

このサンプル自体は以前からあったものですが、絵で見ると構造がハッキリと分かりますね。この程度の絵は1秒以内で生成できるし、ソフトウェアとの乖離もありません。絵の元データが、Wikiシステムを駆動しているスクリプトそのものなので乖離するはずがないのです。[/追記]

2010-12-13 (月)

2010年末に再び考える、Catyスキーマとユーザーインターフェース

| 09:44 | 2010年末に再び考える、Catyスキーマとユーザーインターフェース - 檜山正幸のキマイラ飼育記 を含むブックマーク

1年半ほど前、「JSONスキーマとユーザーインターフェース」とか「JSONスキーマと列挙型」において、ランチの注文フォームを素材にスキーマとユーザーインターフェースの問題を考えてました。今、2010年末ならこの問題をどう扱うか?

まず、データ型の定義は次のようになります。

/** 
 * ランチの注文 
 */
type LunchOrder = {
  /** 会員識別情報 */
  "ident" : {
    "name" : string,
    "memberNum" : integer
  },
  /** 今日の注文 */
  "order" : {
    "mainDish" : (
                 "special"|
                 "fish"|
                 "meat"
                 ),
    "drink" : (
               "teaHot"|
               "teaIce"|
               "coffeeHot"|
               "coffeeIce"
               ),
    "dessert" : (
                "pudding"|
                "strawberryShortcake"|
                "bavarianCream"|
                "gateauChocolat"
                )
  }
};

この定義は、今や擬似コードではなくて、Caty内でちゃんと動きます。

caty:test> lunch-order.caty
{
    "ident":{
        "memberNum":1234,
        "name":"m-hiyama"
    },
    "order":{
        "dessert":"bavarianCream",
        "drink":"coffeeHot",
        "mainDish":"special"
    }
}
caty:test> lunch-order.caty | validate LunchOrder
@OK {
    "ident":{
        "memberNum":1234,
        "name":"m-hiyama"
    },
    "order":{
        "dessert":"bavarianCream",
        "drink":"coffeeHot",
        "mainDish":"special"
    }
}
caty:test>

問題は単にデータ型だけではありません。ユーザーインターフェースを構成するHTMLフォームの生成に必要な情報を、スキーマ内に埋め込もうとしていたのです。とりあえず、フォームの入力用部品(フォームコントロール)を復習しておきます。

要素 属性 略称 説明
input type="text" text 単一行テキストの入力
input type="password"password パスワードの入力
input type="radio" radio ラジオボタン
input type="checkbox"checkbox チェックボックス
textarea textarea 複数行のテキスト入力
select single-select セレクトボックス
select multiple multiple-select 複数選択セレクトボックス

各フォームコントロールからどんなデータ型を入力するかをまとめると:

コントロール データ型
text string, number
password string
radio enum(列挙型), boolean
checkbox bag(バッグ型)
textarea string
single-select enum
multiple-select bag

逆の順序でまとめれば:

データ型 コントロール
number text
string text, password, textarea
boolean radio
enum radio, single-select
bag checkbox, multiple-select

この他に、フォームコントロールをグループ化するfieldset、フォーム全体を表すformがあります。

どのフォームコントロールを使うかを、uiというアノテーションで注記することにします。Catyスキーマのアノテーション構文では、@[ui("text")] (textコントロールを使う)のようになります。それと、UIで使うラベル文字列が必要なので、@[label("お名前")] のようにして示します。

データ型に対するデフォルトのコントロールは、上の表にある最初のコントロールとします。例えば、string型はデフォルトでtextコントロールを使います。トップレベルのオブジェクトはformになり、入れ子のオブジェクトはfieldsetとしてグループ化されます。

ラベルのデフォルトは次のとおり。

  1. オブジェクトのプロパティのラベルはプロパティ名
  2. 列挙型(値のユニオン型)の各値のラベルは、その値の文字列表現
  3. その他のデフォルトのラベルは空

このルールで、先のLunchOrder型からHTMLフォームを作ると次のようになります。

<form method="post" action="lunchOrder.cgi">
  <fieldset id="ident"><legend>ident</legend>
    <div class="textField" id="ident.name">
      name:<input type="text" name="ident.name">
    </div>
    <div class="textField" id="ident.memberId">
      memberId:<input type="text" name="ident.memberId">
    </div>
  </fieldset>

  <fieldset id="order"><legend>order</legend>
    <div class="checkboxGroup" id="order.mainDish">
      mainDish:
      <input type="radio" name="order.mainDish" value="special" />
      special
      <input type="radio" name="order.mainDish" value="fish" /> 
      fish
      <input type="radio" name="order.mainDish" value="meat" />
      meat
    </div>

    <div class="radioGroup" id="order.drink">
      drink:
      <input type="radio" name="order.drink" value="teaHot" />
      teaHot
      <input type="radio" name="order.drink" value="teaIce" />
      teaIce
      <input type="radio" name="order.drink" value="coffeeHot" />
      coffeeHot
      <input type="radio" name="order.drink" value="coffeeIce" />
      coffeeIce
    </div>

    <div class="checkboxGroup" id="order.dessert">
      dessert:
      <input type="checkbox" name="order.dessert" value="pudding" />
      pudding
      <input type="checkbox" name="order.dessert" value="strawberryShortcake" />
      strawberryShortcake
      <input type="checkbox" name="order.dessert" value="bavarianCream" />
      bavarianCream
      <input type="checkbox" name="order.dessert" value="gateauChocolat" />
      gateauChocolat
    </div>
  </fieldset>

  <p><input disabled type="submit" value="送信する"></p>

</form>

表示はこんな感じ。

ラベルを日本語にしたいなら、次のような @[label]アノテーションを付けることになります*1。@[checked]は、checkedまたはselectedを付けることを示すアノテーションです。

type LunchOrder = {
  @[label("ランチ会員情報")]
  "ident" : {
    @[label("お名前")]
    "name" : string,
    @[label("会員番号")]
    "memberNum" : integer
  },
  @[label("本日のご注文")] 
  "order" : {
    @[label("メイン")]
    "mainDish" : (
                 @[label("日替わり")] @[checked]
                 "special"|
                 @[label("魚")]
                 "fish"|
                 @[label("肉")]
                 "meat"
                 ),
    @[label("お飲み物")]
    "drink" : (
               @[label("紅茶 (ホット)")]
               "teaHot"|
               @[label("紅茶 (アイス)")]
               "teaIce"|
               @[label("コーヒー (ホット)")] @[checked]
               "coffeeHot"|
               @[label("コーヒー (アイス)")] 
               "coffeeIce"
               ),
    @[label("デザート")]
    "dessert" : (
                @[label("プリン")]
                "pudding"|
                @[label("苺ショートケーキ")]
                "strawberryShortcake"|
                @[label("ババロア")]
                "bavarianCream"|
                @[label("ガトーショコラ")]
                "gateauChocolat"
                )
  }
};

これだけ@[label]が頻出するなら、「アノテーションに単に文字列を書いたらラベルになる」というショートハンドの約束をしたほうがいいかもしれません。このショートハンドを使うと、少しスッキリします。

type LunchOrder = {
  @["ランチ会員情報"]
  "ident" : {
    @["お名前"]
    "name" : string,
    @["会員番号"]
    "memberNum" : integer
  },
  @["本日のご注文"] 
  "order" : {
    @["メイン"] 
    "mainDish" : (
                 @["日替わり", checked] 
                 "special"|
                 @["魚"]
                 "fish"|
                 @["肉"]
                 "meat"
                 ),
    @["お飲み物"]
    "drink" : (
               @["紅茶 (ホット)"]
               "teaHot"|
               @["紅茶 (アイス)"]
               "teaIce"|
               @["コーヒー (ホット)", checked]
               "coffeeHot"|
               @["コーヒー (アイス)"] 
               "coffeeIce"
               ),
    @["デザート"]
    "dessert" : (
                @["プリン"]
                "pudding"|
                @["苺ショートケーキ"]
                "strawberryShortcake"|
                @["ババロア"]
                "bavarianCream"|
                @["ガトーショコラ"]
                "gateauChocolat"
                )
  }
};

このアノテーション付きスキーマから、次のようなフォームが生成できるはずです。

<form method="post" action="lunchOrder.cgi">
  <fieldset id="ident"><legend>ランチ会員情報</legend>
    <div class="textField" id="ident.name">
      お名前:<input type="text" name="ident.name">
    </div>
    <div class="textField" id="ident.memberId">
      会員番号:<input type="text" name="ident.memberId">
    </div>
  </fieldset>

  <fieldset id="order"><legend>本日のご注文</legend>
    <div class="checkboxGroup" id="order.mainDish">
      メイン:
      <input checked type="radio" name="order.mainDish" value="special" />
      日替わり
      <input type="radio" name="order.mainDish" value="fish" /><input type="radio" name="order.mainDish" value="meat" /></div>

    <div class="radioGroup" id="order.drink">
      お飲み物:
      <input type="radio" name="order.drink" value="teaHot" />
      紅茶 (ホット)
      <input type="radio" name="order.drink" value="teaIce" />
      紅茶 (アイス)
      <input checked type="radio" name="order.drink" value="coffeeHot" />
      コーヒー (ホット)
      <input type="radio" name="order.drink" value="coffeeIce" />
      コーヒー (アイス)
    </div>

    <div class="checkboxGroup" id="order.dessert">
      デザート:
      <input type="checkbox" name="order.dessert" value="pudding" />
      プリン
      <input type="checkbox" name="order.dessert" value="strawberryShortcake" />
      苺ショートケーキ
      <input type="checkbox" name="order.dessert" value="bavarianCream" />
      ババロア
      <input type="checkbox" name="order.dessert" value="gateauChocolat" />
      ガトーショコラ
    </div>
  </fieldset>

  <p><input disabled type="submit" value="送信する"></p>

</form>

表示は次のようでしょう。

型定義からフォームを生成することは、それだけを目的にすればさほど難しくはないでしょうが、まっとうな型システム/アノテーションシステムの副産物として導出するのはけっこうな手間です。例えば、アノテーションはターゲット構文構成素の直前に出現しますが、実用性からは次の位置にアノテーションを許す必要があります。

  • オブジェクト型の直前
  • 配列型の直前
  • 列挙型/ユニオン型の直前
  • オブジェクト型のプロパティ(property)の直前
  • 配列型の項目(item)の直前
  • 列挙型/ユニオン型の選択肢(choice, altenative)の直前

しかも、アノテーションを付与された型定義をデータとして扱える必要があります。「アノテーションを含む型」のレイフィケーション(reification)、あるいはメタ循環(メタ巡回)構造です*2。Catyのメタ循環構造はまだ不完全なのですが、少しずつ整備しています。そのうち、副産物としてランチ注文フォームが作れるようになるでしょう。


ついでに、僕がなんでメタ循環構造に拘るかをチョット:
コンピュータが扱えない対象物に対する操作は、人間がやることになります。その作業が十分に知的で、コンピュータでは出来そうにない事ならやる意義も価値もあるでしょう。しかし、さして知的でもない作業を人手でやるのはウンザリ。型の定義を目視で見て、対応するHTMLフォームを書き下すなんて作業はウンザリの典型ですね。

この作業をコンピュータができない理由は(それがあるとすれば)、型定義がコンピュータが扱えるデータになってないから; それだけです。型や手続きや関係やらが、データになっていれば、通常は人間がやるような概念的(に見える)操作もコンピュータに任せることができます。つまりは、現実の世界や概念の世界の事物をコンピュータのなかに押し込めればいいのです。コンピュータのなかの世界には、当のコンピュータ(プログラム)自身も入れ子に埋め込まれることになります。これがメタ循環構造です。

メタ循環構造を実現すれば、コンピュータがやれる作業が増えて、僕らは楽できます。

*1:列挙値の値に対するアノテーションを除けば、現状のCatyでもパーズできます。

*2:圏論の言葉で言えば、閉構造です。内部ホム対象、あるいは指数(ベキ)が閉構造を与えます。

2010-04-07 (水)

最近のCatyスキーマを解説します

| 09:37 | 最近のCatyスキーマを解説します - 檜山正幸のキマイラ飼育記 を含むブックマーク

Catyのスキーマ記述言語は、JSONスキーマ仕様(http://tools.ietf.org/html/draft-zyp-json-schema-01)に基づいています。構文は違いますが、できる限り本家JSONスキーマのセマンティクスを保存するように努めています。ですから、JSONスキーマの書き方がなんとなくでも理解できた人なら、Catyスキーマも書けます。そして、Catyスキーマのほうがはるかに簡潔に記述できます。

以下では、「最近のJSONスキーマを解説します」と同じ構成で、Catyスキーマの記述パターンを説明します。Catyスキーマがいかに単純明快かが分かると思います*1

内容:

  1. 事例
  2. 型の分類
  3. Catyスキーマの記述パターン
    1. 基本スカラー型
    2. リスト型
    3. タプル型
    4. タプル+リスト型
    5. 閉じたオブジェクト型
    6. 開いたオブジェクト型
    7. ユニオン型
    8. 列挙型
    9. 全称型
    10. オプショナル指定
    11. リテラルとシングルトン型
    12. スキーマ属性

事例

「しょうがないので、マイクロフォーマットのデータモデルを僕が考えた」で例題とした、マイクロフォーマットのhCardに適合した簡単な人物情報の例を挙げましょう。インスタンスは次のようなものです。

{
  "vcard" : {
    "fn" : "檜山 正幸",
    "email" : ["hiyama{AT}chimaira{DOT}org"],
    "url" : ["http://www.chimaira.org/", "http://d.hatena.ne.jp/m-hiyama/"]
  }
}

次の約束をします。

  1. fnプロパティは必須
  2. emailプロパティは最低1つの項目を持つ配列
  3. urlプロパティは任意個数の項目を持つ配列、空でもよい

メールアドレスとURLは、本来なら専用のデータ型を定義すべきでしょうが、文字列で済ませます。

Catyスキーマの型表現は、インスタンスとほとんど同じ形になります。次のとおりです。

{
  "vcard" : {
    "fn" : string,
    "email" : [string, string*],
    "url" : [string*]
  }
}

JSONスキーマなら以下のようになります。

{
  "type" : "object",
  "properties" : {
    "vcard" :  {
      "type" : "object"
      "properties" : {
        "fn" : {"type", "strning"},
        "email" : {
          "type" : "array",
          "items" : [
            {"type": "string"}
          ],
          "additionalProperties" : {"type": "string"}
        },
        "url" : {
          "type" : "array",
          "items" : {"type": "string"}
        }
      }
    }
  }
}

本家JSONスキーマに不公平にならないように、JSONスキーマのメリットも言っておきます。(「最近のJSONスキーマを解説します」より引用):

JSONスキーマの特徴は、型表現がまたJSONデータであることです。これはメタデータをデータとして扱えるという大きな利点があります。


Catyスキーマの型表現自体はJSONデータではありません。JSONデータとすごく似てますが、実は違います。よって、JSONデータを扱うツールでCatyスキーマを扱うことはできません。例えば、JSONデータをコンテキストとするテンプレートエンジンへの入力としてCatyスキーマは使えません。JSONスキーマならそれができます。

型の分類

「最近のJSONスキーマを解説します」にある分類とまったく同じ内容ですが再掲します。

  1. 基本スカラー型: integer, number, string, boolean, null
  2. リスト型: 項目がすべて同じ型である配列型、項目の個数は任意
  3. タプル型: 決まった個数の項目を持つ配列型
  4. タプル+リスト型: 決まった個数の項目と、それに続く同じ型の任意個の項目を持つ配列型
  5. 閉じたオブジェクト型: 決まった個数のプロパティを持つオブジェクト型
  6. 開いたオブジェクト型: 決まった個数のプロパティと、同じ型の任意個のプロパティを持つオブジェクト型
  7. ユニオン型: 複数の型のどれかを意味する型
  8. 列挙型: 有限個の定数リテラルのどれかを意味する型
  9. 全称型: any

Catyスキーマの記述パターン

型の分類ごとに、どのようにスキーマを書くかを説明します。

基本スカラー型

型の名前そのものを書きます。

<型の名前>

例えば、integer とか。

基本スカラー型の名前は次の5つで全部です。nullはスカラーとは別な「特殊な型」として扱うこともあります*2

  1. integer
  2. number
  3. string
  4. boolean
  5. null

リスト型

リストの項目の型表現を、<項目の型表現>と書くとします。リスト型は次のとおりです。

[<項目の型表現>*]

星印は正規表現の「任意回の繰り返し」の記号です。例えば整数値のリストは [integer*] です。空リストも含まれます。

タプル型

タプルの項目ごとの型を表現する型表現を、<項目の型表現1>、<項目の型表現2>などと書くとします。タプル型は次のとおりです。

[<項目の型表現1>, <項目の型表現2>, ..., <項目の型表現n>]

例えば、[string, string, integer] とか。

タプル+リスト型

タプルの項目の型を表現する型表現を、<項目の型表現1>、<項目の型表現2>など、残りの項目の型は<残余項目の型表現>と書くとします。タプル+リスト型は次のとおりです。

[<項目の型表現1>, <項目の型表現2>, ..., <項目の型表現n>, <残余項目の型表現>*]

例えば、最初が真偽値で、後は文字列が並ぶような配列なら、[boolean, string*] です。

閉じたオブジェクト型

オブジェクトのプロパティ名を<プロパティ名1>、<プロパティ名2>など、プロパティ値の型を表現する型表現を、<プロパティの型表現1>、<プロパティの型表現2>などと書くとします。閉じたオブジェクト型は次のとおりです。

{
  "プロパティ名1" : <プロパティの型表現1>, 
  "プロパティ名2" : <プロパティの型表現2>, 
  ...
  "プロパティ名n" : <プロパティの型表現n>
}

開いたオブジェクト型

オブジェクトのプロパティ名を<プロパティ名1>、<プロパティ名2>など、プロパティ値の型を表現する型表現を、<プロパティの型表現1>、<プロパティの型表現2>など、残りのプロパティの型は<残余プロパティの型表現>と書くとします。開いたオブジェクト型は次のとおりです。

{
  "プロパティ名1" : <プロパティの型表現1>, 
  "プロパティ名2" : <プロパティの型表現2>, 
  ...
  "プロパティ名n" : <プロパティの型表現n>, 
  * : <残余プロパティの型表現>?
}

最後の<残余プロパティの型表現>には疑問符を付けるのが正統的記法ですが、「しばしば忘れる」という人間的な理由で疑問符の省略を許します。

ユニオン型

ユニオン型を構成する型の表現を <型表現1>、<型表現2>などとします。ユニオン型は次のとおりです。

(<型表現1> | <型表現2> | ... | <型表現n>)

縦棒で区切って型表現を並べます。外側を囲んでいる丸括弧は省略することもあります。Catyでは、成分となる各型(alternatives)が排他的であることを要求します。

列挙型

列挙型は次のとおりです。

(<リテラル1> | <リテラル2> |  ... |<リテラルn>)

縦棒で区切って定数リテラルを並べます。外側を囲んでいる丸括弧は省略することもあります。一番短い表現になるように、各リテラルは違う値になるように書く必要があります。

全称型

any です。

オプショナル指定

プロパティや項目がオプショナルであることを表すには、次のように書きます。

<型表現>?

お尻に疑問符を付けます。正規表現と同じです。

リテラルとシングルトン型

すべてのJSONリテラルは、その値だけを持つシングルトンセットである型を表します。型表現とリテラルを自由に混ぜることができます。例えば、{"family-name" : "檜山", "given-name" : string(minLength=1)} とか、(integer | "infinity" | null) とか。

スキーマ属性

型ごとに有効なスキーマ属性は、型表現に続けて (<属性名1>=<属性値1>, <属性名2>=<属性値2>, ...) の形で書きます。integer(minimum=0, maximum=5)、[string*](maxItems=10) とか。属性の名前と値は、本家JSONスキーマに従いますが、一部の属性(requires, default, readonlyなど)はサポートしません -- 型システムの整合性を壊してしまう可能性があるからです。型システムと相性が悪いスキーマ属性はアノテーションとして記述するかもしれません。

*1:諸般の都合により、Catyの公開リリースが滞っています。新スキーマ構文を解釈できる次期バージョンまで、もうしばらくお待ちください。

*2:JSONのnullは実体的な値で、非存在とかヌルポインターではないことには注意してください。イミュータブルなシングルトンオブジェクトと考えるのが適切です。

2009-11-06 (金)

浅海さんによるCatyの感想記事

| 11:45 | 浅海さんによるCatyの感想記事 - 檜山正幸のキマイラ飼育記 を含むブックマーク

BPStudy#26から1週間たってしまったのですが、今ごろになって浅海智晴さんによる記事を見つけました。

浅海さん、いらっしゃっていたのなら声かけてくれれば/せめてトラックバックいただければ、と思いましたが … 以下に少しだけ反応を:

流通するデータ構造をXMLではなくJSONにしている [...] 正確にはJSONの上位互換の独自アイデアのプロパティ付きJSONであり、意味論的にはXMLに近くなっている。

概念と表層構文は確かにJSON上位互換です。けど、シンタックスシュガーを剥ぎ取れば、通常のJSONにマーシャリング可能です。マーシャルした結果は、人間には読みにくいですが、任意のJSONツールで扱えます -- このために互換性を維持したのですよね。

「意味論的にはXMLに近くなっている」はまったくそのとおりで、「独自アイデアのプロパティ」を我々は単に「タグ」と呼んでいます。XMLのタグと意味/用法がほぼ同じなので。

最終形はJSON静的型付純粋関数型Webコンポーネント糊言語ということになりそうである。

さすが、ズバリ本質をついた表現ですね。ただし、「静的型付」を看板にするのは誇大かもしれません。静的解析でガンバルつもりですが、諸般の事情により静的に型安全を保証できないケースもあります。静的であれ動的(実行時チェック)であれ、ともかく手段を選ばず強い型付けを実現する、という方針です。

したがって、「JSON強烈型付純粋関数型Webコンポーネント糊言語」でしょうか。「烈」の字は単に雰囲気、意味はありません。

一般的には状態遷移する現実世界を純粋関数型言語で扱うためにはモナドといった道具立てが必要になってくるはずなので、この点をどのように対応していくのかというのが技術的に面白そうな論点である。

ここは、一番つっこんで欲しいツボですね :-) 通常ですと、モナドについてよく知っている人がモナド実装を書くのですが、Catyにおけるポイントは、モナドの知識を一切持たないプログラマに、結果としてモナドを書いてもらうようにすることです。

モナド法則の成立をソフトウェアにより保証する(法則を機械的に証明する)とかは、ちょっと現実性がないので、コンベンションやモラルに頼ることになりますけど。

goldenportgoldenport 2009/11/06 12:37 人が沢山ごったがえしていたので声をかけそびれてしまいました。すみません。Caty期待してます。

m-hiyamam-hiyama 2009/11/06 13:45 goldenport(浅海)さん、
適切かつ好意的なレビューをありがとうございます。
> 人が沢山ごったがえしていたので
あー、そうでしたね。またの機会に。

kosakikosaki 2009/11/06 14:31 ああ、「本人の意見は少数意見なので却下します」プロトコルですね。小さいのによく教育が行き届いているなぁ :-)

m-hiyamam-hiyama 2009/11/06 14:39 kosakiさん、
>「本人の意見は少数意見なので却下します」プロトコル
はじめて聞いたプロトコルだ。いつごろRFCになりますか?

hokuto-heihokuto-hei 2009/11/06 21:43 私も抜いた鼻毛が白かったとき「あ〜ジジイになったなぁ」と思いました。

m-hiyamam-hiyama 2009/11/07 12:25 hokuto-heiさん、
そうですなー、まったくジジイになりました。

2009-10-31 (土)

BPStudy#26 お疲れさまでした、あと、感想/補足/反省とか

| 14:06 | BPStudy#26 お疲れさまでした、あと、感想/補足/反省とか - 檜山正幸のキマイラ飼育記 を含むブックマーク

昨日10月30日(金曜)の夜、BPStudy#26にて、Kuwataさんと一緒にCatyについて発表しました。みなさん、お疲れさまでした。

けっこう空席があるなー、と思ったのですが、もともと80席用意されていたので、60人ほど集まったとのことです。かなりヘンテコリンでまだ出来上がっていないソフトウェアの話を聞きたいという酔狂な方が、そんなにいるとはちょっとビックリしました。

以下に、感想とか補足とか反省とかをダラダラと:

[追記]Kuwataさんも補足説明を書いてます:http://return0.dyndns.org/log/2009/10/31#s_1

資料(スライド)は、http://return0.dyndns.org/doc/bpstudy/bpstudy26.odp[/追記]

ロールとワークフロー

まず感じたことは、水曜のリハーサル「やっぱりパスタの会」がすごく役に立ったなー、ということです。「やっぱりパスタの会」参加者のみなさん、再度ありがとうございます。

パスタの会での指摘をもとに、BPStudy前日(29日)に導入したロールという概念、特にスーパーバイザ・ロールにより、説明がすごくクリアになったと思います。これで、僕が「デザイナ」という言葉を使うたびに(相手に)生じていた違和感、齟齬がだいぶ解消されます。

ロールに関して言えば、業界でマークアップ・エンジニアと呼ばれている職種・職能に対応するロールはどうよ? みたいな話も出ました。「「プレBPStudy」または「やっぱりパスタの会」の後日メモ」にも書いたように、ロールとワークフローはまだ十分に理解してないことなので、これから考えます。

ラーメン屋さんのため

「ラーメン屋さんのサイトを作るためのフレームワーク」というキャッチフレーズは、「やっぱりパスタの会」参加のid:bonotakeさんの提案です。これも、Catyの特性を表現するには非常に有効でした。次のような質問には、「ラーメン屋さんのサイトに、そんなのいらないでしょ」と答えれば済むので。

  1. スケーラブルじゃないのか?
  2. 大量アクセスをどうやってさばくのか?
  3. 数百万件規模のデータベースを扱うには?

Catyは言語処理系なので、インタプリタのパワーを上げれば、上記の要求に応えられなくもないですが、そこをガンバル気はありません。柔軟性を上げるためにURLを動的にディスパッチするなんてのは、鼻からやるわけありません。

テンプレートエンジン

言語処理系としてのCatyにとって、テンプレートエンジンはprintコマンドの実装のひとつ(one-of)に過ぎないのだけど、実務上では重要な部分です。(狭義の)Webデザイナやマークアップエンジニアが直接に触るのはテンプレートの部分なので、問題点の指摘とか良いアイディアがあれば、それは取り入れます。テンプレート展開エンジン(VM)が構文とは切り離されているので、ある程度の融通は効きます。

現状、Smarty風構文のほうばかりやっていて、Genshi風構文がほったらかしなんですが、Genshi風構文にも良い点や独自の可能性があるので、Smarty風が安定したら、Genshi風も使えるようにしたいと思います。

Catyスクリプト

僕たちの心づもりでは、「ラーメン屋さんのためのWebフレームワーク」としてのCatyの紹介が主眼で、インサイドCatyの話題は時間が余ったらのオマケ、という位置付けでした。しかしやっぱり、集まったメンバーが技術者/プログラマなので、オマケのほうがウケた感じでしたね。Kuwataさんのテンションも上がって(上がりすぎて)いたし -- 用途はWebフレームワークなんだから、Yコンビネータが短く書けてもエラクはないんだけど。

構文を決めた僕が言うのもナンですけど、Catyスクリプトは、いいかげん変な、クセのある構文を持ちます。ただ、経験上、ああいう変態構文をいじくりたがる変態人間はヤッパリいるもので、Kuwataさん以外でも、20行もある膨大なCatyスクリプトを書く人間が現れるかもしれません。

構文はともかくとして、強い型付け、並列処理モデル(現在の実装は逐次だけど)、マップ関数あたりは、割とまっとうなんですよ、いやマジで。

Catyスクリプトは、JSONのスーパーセットなんですが、動作する部分(コマンド呼び出し)を取り除いても、次の4つの点でベターJSONになっています。

  1. 余分なカンマを許す
  2. コメントが書ける(/* ... */ と // ... が使えます)
  3. 三重引用符(''')により、WYSIWYG文字列が書ける
  4. 任意のデータにタグが付けられる

コメント以外は、通常のプレーンJSONにマーシャリング可能で、JSONに対するシンタックスシュガーとして利用可能です。[追記]ただし、拡張されたJSONを使い慣れると、プレーンなJSONとしてはエラーが出て困惑するかもしれません。使い勝手と互換性のトレードオフが難しいですね。[/追記]

この「データ記述言語としてのCatyスクリプト」の話は予想外にウケたみたい。みんな、「JSONのココが不便」と思っていたのかな?

型システム

Catyは、安全性(セキュリティ、フールプルーフなど)には力を入れているのですが、それを支えるのは型システムです。JSONデータしか扱わない! と割り切った上で、JSON上にかなり精密な型システムを構築しています。

型システムを定義する実体はスキーマモジュール(拡張子が.casm, .pcasmのファイル)ですが、スキーマモジュール内でユーザー型定義(type文を使用)とコマンド宣言(command文を使用)が行えます。インタプリタ(Catyシステムの中核)は、実行環境内のすべてのスキーマモジュールをロードしてから実行開始します(効率上の都合で遅延ロードも予定してますが)。

外部から来たデータやテンプレートコンテキストも含めて、ありとあらゆるデータに対して、すべてのタイミングで型チェックが走ります。当然にこれは効率上のオーバヘッドを招きます。しかし、効率より安全性を優先するので、型チェックをやめる気は毛頭ありません。ただし、静的に確認できることはできるだけコンパイル時に済ませ、実行時型チェック=オーバヘッドの最小化は目指します。

ファシリティとmafs(マフス)

[追記]この節は後から足しました。[/追記]

ファシリティについてあまり話せなかったので、ここで補足しておきます。

Catyジャーゴンでは、コマンド/スクリプトが実行されるサンドボックス環境を「Catyちゃんハウス」と呼びます(リカちゃんハウスにインスパイアされました)。Catyちゃんハウスは、外部(OS、Webサーバー、ファイルシステム、コンソールとウィンドウシステムなど)から完全に遮蔽されています。Catyちゃんハウス内で動いているコマンド/スクリプトは、外部について知るすべはありません。

しかし、ファイルシステムをはじめとするストレージ(IOの対象物)がないと、たいていのプログラムは仕事ができません。外を見ることはできない(窓もドアもない)Catyちゃんハウスなんですが、電気・ガス・水道はないと困るだろう、ってわけです。そのようなインフラ設備を提供するのがファシリティです。OSに例えると、デバイスドライバのようなもので、コマンド/スクリプトが要求するストレージアクセスと、実際のIO資源との仲介をします。

特に、ファイルシステムを抽象化/単純化したファシリティをmafs(minimum abstract filesystem)と呼びます。現状、まともに動くファシリティはmafsだけですが、JSONストレージ・ファシリティ、ログデバイス・ファシリティなどは近いタイミングで利用可能となるでしょう。

コマンドから見ると、ファシリティはインターフェースだけで規定され、シェルからのインジェクションで提供されます。コマンドはファシリティの実体を知ることはできません。ファシリティ実装は自由に切り替えることが出来るのです。これにより、コマンドのIOを監視したり、キャッシュ/キューイングしたり、セキュリティラッパーを付けたり、排他制御をしたりが、任意に追加削除できます。別な言い方をすると、コマンドは余計なことを考えずに、素朴にIOすればよくて、面倒なことは(必要があれば)シェルとファシリティがやってくれます。

追記:コマンドのプログラミング

[追記 date="2009-11-04"]デザイナとスーパーバイザの作業負担を軽くする話が多いので、プログラマは難しい作業を強いられる、とか思ったら、それは誤解ですよ。プログラマの作業を軽減するにはどうしたらいいかは、容易に想像も実現もできるので、あえて話題にする気力が湧かないのですが、Catyコマンドのプログラミングは簡単です。

「Catyに関して重要で一般的な注意:表側と裏側は違う」を参照 -- コマンド・プログラマもCatyを使う側の人に分類されます。

ファシリティのプログラミングはそこそこの技量が要ります。が、ファシリティを作る人は少数でも十分です。[/追記]

今後

Catyが解こうとしている問題は単純明快です:低スキル、低予算、短期間の条件下で、ラーメン屋さんのサイトをちゃんと立ち上げてちゃんと運用することです。

サイト作成に関わる人々に、知識や技量を要求することはしません。まー、正確に言えば、要求する知識と技量を最小にすべく努力しますよ、ってことですがね。やり方や選択肢が多ければ人間は迷うので、可能ならば1つのやり方だけを提供し、オプションや設定は極力排除します。柔軟性とカスタマイズ性? そんなの知りません。

悪意のあるなしに関わらず人間は間違います。間違いや混乱を誘発する要因をできるだけ少なくして、人間が間違ってもソフトウェアがそれを検出する。検出が事前にできなかった場合でも実行時に「良くないデータ/コード」の処理/実行を食い止めようとします。

僕とKuwataさんにとってこれらの要求は自然であり、それが実現できないフレームワークでは、「気持ちよく安心して使えないよな」と感じるのです。でも、「ラーメン屋さんのサイトを迅速に作るときに、気持ちよく安心して使える」をマジメに実現しようとすると、解決すべき問題と実装すべき機能のリストが、ちょっと気が遠くなる長さになってしまうのですよね。たまにタメ息をつくのだけど*1、まー、やってみよう。

*1:僕より大きなため息をついているのはKuwataさんですけど。

tmiyatmiya 2009/10/31 17:08 お疲れさまでした>kuwataさん、檜山さん。プレと本番と両方聞きましたが、全然違う発表になっていて、両方楽しめました。
オマケの話をするまでは、会場の雰囲気は「良いフレームアークなんじゃない?」という肯定的な雰囲気一色だったのが、オマケの話を話したとたん皆の印象が「なんか予想以上に(あるいは必要以上に)すごい事をやっている」と微妙なものへと変貌していく感じが興味深かったです。
とはいえ、やっぱりエンジニアの集まりなんで、ああいう話を入れて良かったんじゃないかなぁ...但し、最後の印象が強過ぎて、「デザイナーには使いこなせないほどすごい言語」という印象を抱いて帰った人もいたみたいでしたが,,,。

m-hiyamam-hiyama 2009/10/31 17:16 tMiyaさん、
> 「デザイナーには使いこなせないほどすごい言語」という印象を抱いて帰った人もいたみたいでしたが,,,。

ガーーーンンン。

やっぱりオマケやめておけばよかったかなぁー。
おまいがYコンビネータ出すから、、、>クワタくーん。

tmiyatmiya 2009/10/31 17:29 あー、帰りにビルを出るまでのところで、そんなことを友人と話している人がいました。
Yコンビネータ自体は、さらっと流してたからいいんじゃないでしょうか。
じゃあどうしてそういう印象になっちゃったのかというと...どうしてなんでしょうね?

tmiyatmiya 2009/10/31 17:37 > そんなことを友人と話している人が
s/友人/その人の連れ/
ですね、正確には。私の知っている人じゃないので、友人同士なんだと見えたけど本当の事は判らないので。

_kaolu__kaolu_ 2009/11/02 13:53 面白いと思うよと誘われて、初めて勉強会に参加したデザイナーです。

> 「デザイナーには使いこなせないほどすごい言語」という印象を抱いて帰った人もいたみたいでしたが,,,。

とのことですが、
私個人の意見としては、「使いやすそう」という印象です。

確かに後半の「裏側」の話については、半分以上わかりませんでしたが。。。
でも、何が凄いかっていうことが分からないなりにも、すごいんだということは伝わってきました。

「表側」のデザイナーが触る部分は、書き方というかデザイナーから見えている見た目としては、MT4のソースみたいな感じなのかなと思いました。
しかも、MT4みたいに専用CMSツールを使わなくてもいいなら、
大変すばらしいではないかと思いましたよ。
(理解が間違っていたら、すみません)

m-hiyamam-hiyama 2009/11/02 17:31 _kaolu_さん、
> 初めて勉強会に参加したデザイナーです。
僕らが一番フィードバックを期待しているのは、デザイナーさんや、当日説明したスーパーバイザー相当のロールの方々です。なぜなら、そういう人々からどう見えるかが、実感としては分からないので。

> しかも、MT4みたいに専用CMSツールを使わなくてもいいなら、
そこはコダワリがあって、とにかく素朴に素朴に素朴に、
特殊な道具は何も使わない方針です。
サイトの構造をラフに作るなら、開発サーバーさえ要らなくて、テキストエディタとコンソールシェルだけあればなんとかなる、という感じにしたかった。

> 大変すばらしいではないかと思いましたよ。
ありがとうございます。

2009-09-29 (火)

Catyの目的とか方針とか:今日は前置きだけ

| 11:02 | Catyの目的とか方針とか:今日は前置きだけ - 檜山正幸のキマイラ飼育記 を含むブックマーク

明日9月30日に、Caty最初のリリースをします。つっても、アーカイブをどっか(たぶんbitbucket)にコソッと置くだけですけど。

ソフトウェアがそれ自身について語れるといいのですが、今の段階では、Catyをインストールして実行してもらっても、「へっ? なにこれ」という反応になりそうです。僕(人間の檜山)がソフトウェアについて語らないと意図が伝わりそうにありません。[追記]いずれは、Caty自身がCatyについて語れる、つまり自己記述的にするつもりです。[/追記]

CatyはWebフレームワークです。実装は、開発用Webサーバーも含めてフルPythonです。が、プログラミング言語中立になるように注意しています -- Webサイト/Webアプリケーションの構築の際には、実装言語(Python)とは別なスクリプト言語スキーマ言語を使います。コマンド(と呼ばれるソフトウェアコンポネント)を書く人以外は実装言語を意識する必要はありません。

Catyは、現存する多くのWebフレームワークとは違った仕様や方式を採用しています。「なんでこんなことをするんだ?」「何を考えてんだ?」といぶかしく思うかもしれません。別に奇をてらったわけではありません。Catyは、その目的や想定している使い方が多くのWebフレームワークとは違うのです。異なった目的を持てば、異なったメカニズムになるのは不思議ではないでしょう。

で、その目的とは、Webサイト/Webアプリケーション/Webサービスを作る工程のなかでプログラマの出番を出来るだけ少なくすることです。ここでプログラマとは、通常の汎用プログラミング言語(今のCatyではPython)によるプログラムを書く人のことです。プログラミング作業をゼロには出来ないにしろ、その量を少なく、しかも限定的にしたいのです。

これ以上話を進める前に、誤解をまねかないように、「プログラマ」とか「Web制作者」という言葉を、Catyの説明の文脈ではどういう意味で使うのかを前置きすることにします。このエントリは「前置き」だけで終わって(力尽きて)しまいますが、引き続く説明のなかでもこの「前置き」の注意は適用されます。


プログラマ」、「Web制作者」という言葉は、職種や職能のことではありません。個人を分類するラベルでもありません。単に作業上の役割を指している言葉です。ですから、一人の人間が「プログラマ」であり「Web制作者」でもあってもいいのです。Pythonコードを書いているAさんは役割としてプログラマであり、同じAさんがHTMLファイルを作っているときは、役割としてWeb制作者なのです。

Catyでは、Catyスクリプト/Catyスキーマ言語/テンプレート言語といった人工言語を使いますが、これらのスクリプト/スキーマ/テンプレートを書く役割は「プログラマ」と呼ばないことにします。汎用プログラミング言語でプログラムを書く役割が「プログラマ」です。それ以外の作業 -- HTML, CSS, JavaScriptなどによるコンテンツを作ったり、サイトの階層構造、ページ遷移/ナビゲーション、ユーザビリティなどを考える役割は、総称として「Web制作者」と呼びます。

ファイルやデータベースなどのストレージに関しては、Web制作者が論理的な要求をまとめ、プログラマが具体的な実現方法を考えるということになります。ストレージにアクセスするロジックは、Catyスクリプトやテンプレート言語で直接的には書けません。プログラマが汎用言語で書いたコマンド(と呼ばれるソフトウェアコンポネント)を経由してストレージにアクセスします。ただし、既に目的のコマンドがあれば、スクリプトからそのコマンドを呼ぶだけでストレージを操作できます。

さて、「Web制作者」という役割(くどいが、職種・職能、個人などを意味しない)に対して、次の知識・技量は仮定、あるいは期待するとします。

  1. ファイルとフォルダの概念を理解している。
  2. HTML文書を作れる。
  3. URLとHTTPのごく基本的なことを知っている。
  4. JSONデータを読み書きできる。

これらの前提は、「常識だ」とは言い切れないのかもしれませんが、これらに関する知識・技量を獲得するための資料・手段・機会は世の中に豊富に準備されていると思います。ですから、新たにお勉強するとしても「特別なお勉強」ではないでしょう。

今列挙した知識・技量だけでCatyが使える、とは言いませんが、これらに対する比較的自然な拡張(例えば、HTMLに対してテンプレート構文を加える)を学べばCatyは使えます。学習コストは小さいと考えます(実証はまだないです)。少なくとも、Model-View-Controllerだの、三層アーキテクチャだの、データベース設計だのという、難しげな概念を持ち出すことはありません。比較的小規模で、ビジネスロジックもさほど複雑でないWebアプリケーションに対して、そんな大げさなことを言う必要性なんてありません。ずっとずっと素朴な発想で十分です。

その素朴な発想については、リリース(アーカイブのセッティング)後に説明します。

2009-08-10 (月)

Catyプロジェクト/ソフトウェアについて

| 08:52 | Catyプロジェクト/ソフトウェアについて - 檜山正幸のキマイラ飼育記 を含むブックマーク

http://return0.dyndns.org/log/2009/08/08#s_1 :

ところで既に何度か書いている通り、今の俺の仕事は檜山さんの配下で世界を転覆させるソフトウェアを開発することなのだが、ここ数日はそこで使うための対話シェルとスクリプト言語の開発をやっていた。

“世界を転覆させる”ことができるかどうか、あんまり自信がないのだけど、Kuwataさんの実装力のおかげで、当初の目論見通りに進捗はしてます。

それらの詳細はまあここではどうでもいい。

と、Kuwataさんは具体的な内容を書かないので、僕が書きます。まー、僕のほうが広報担当だから ^^;

「新ユニット結成のお知らせ + GAE上でファイルシステムの模倣」で次のように述べました。

僕もKuwataさんも「おぼしき事言わぬは腹ふくるるわざ」な人なので、やろうとしていること/やっていることを特に機密扱いしたりはしません。口頭で NNDA [Non-(Non-Disclosure) Agreement] を結んでいます :-)

設計方針や仕様に関しては、できるだけ公開しようと思っているのですが、逐次にレポーティングするのはえらい大変。レポートは断片的にならざるを得ませんね。ソフトウェア自体は、一段落したところでソースも含めて公開します。しかし、それで「何を目指しているのか」「何に使えるのか」「他と何が違うのか」などが分かるとも思えないので、説明の労力を省くことはできないでしょう。

後でまとめて文書を作るなんてことは出来そうにないので、折に触れて「何を目指しているのか」「何に使えるのか」「他と何が違うのか」を書いていこうと思います、断片的にでも。

名前

プロジェクトとソフトウェアの名前はCaty(キャティ)です。何かのアクロニム(略号)でもなく、面白い由来もありません。前身のプロジェクトが猫に由来する名前だったので、それから猫(cat)を取って、なんとなくyを付けただけです。

「キティ」と発音が似ているので、「キティちゃんをロゴに採用しよう」と提案したら、Kuwataさんに「サンリオに怒られるからやめたほうがいい」と反対されました。「キティちゃんにインスパイアされたキャティちゃんロゴを作る」案も「サンリオによけい怒られる」と却下、でした。ちなみに、キャティちゃんは女の子で、たぶん猫です*1

後から思い起こしたのですが、だいぶ以前に小さな実験的なプロジェクト/ソフトウェアにKatyという名前(これもアクロニムじゃない)を付けたことがあるので、僕はこのての名前が好きみたいです。

さらに事後的なコジツケをすると、僕が設計すると、カテゴリカルになるだろうから、catはcategoricalのcatだと言ってもいいでしょう。実際、コマンド(と呼ぶプログラム実行単位)は、半環圏*2の上のスタンピング・モナドのクライスリ射でモデル化できるようになっています。

ジャンルと特徴

ソフトウェアのジャンル(種類)は極めて平凡なもので、Webフレームワークです。世に五万とあるWebフレームワークに対して、(五万+一)番目を付け足すのかというと、そんなつもりはないし、たぶんそうはならないでしょう。

プログラミング言語にもプラットフォーム(OS、Webサーバー、Webサーバーとのインターフェースなど)にも依存しないように注意を払っています。でも、この点は利用者(Web制作者)からは見えないし、まだポーティング例がないので、現状あんまり大声では言えません。

利用者から見てのメリットは「簡単」なことです。この特徴も、ありきたりな表現しかできないのですが、「世界一簡単」が目標です、マジで。

開発用のシェルがあり、プロンプトに対してコマンドラインを入力できます。コマンドラインはキーボードから手で入力するので、通常数十文字、長くとも200文字程度だと思います。このコマンドラインがうまく動くのを目視で確認したら、コマンドラインをそのまま(加工や編集は不要)ファイルに収めます。

こうして出来たスクリプトファイルがWebアプリケーションの実体になります。「数十文字のスクリプトファイルが数個」で実現できる動的Webサイトでも、相当に広範囲の要求に応えられるだろうと踏んでいます。

魔法が使えるわけではないので、裏の仕掛けや制約は当然に存在します。複雑で高度な機能を必要とするWebサイトは最初から守備範囲外です。「簡単なモノなら簡単に作れる」ってことです。そんなの当たり前だろう、って? そうです、当たり前です! しかし僕が見るところ、簡単なモノでさえ簡単に作れない現状があるので、Catyに意義があるだろうと思うのです。

技術と方針

最小抽象ファイルシステム (Minimum Abstract Filesystem; mafs)、厳密分離指向テンプレート言語/エンジンMVCR方式、JSONとJSONスキーマなどは、Catyの構成要素となる技術です。

「簡単でわかりやすい」が第一の目標なので、複雑さをまねく要因は徹底的に排除します。たいして使いもしない機能や親切心でのカスタマイズ可能性/自由度が累積すると、手が付けられない複雑さとなるので、ミニマリズムを貫く態度が必要です。ある段階で導入した機能でも、後で「要らない」と判断すれば容赦なく切り捨てます。もったいないから残しておくなんて事はしません。

正直言って「いくらなんでも機能不足かな」と感じることはあります。しかし、経験上、「いつか使うかもしれない」「誰かが使うかもしれない」「あれば便利かもしれない」「あっても邪魔じゃない」のような誘惑に屈することは、極めてリスキーなので、禅僧のごとくにストイックな気持ちで仕様を考えているのです。

困っていること

「簡単でわかりやすい」が第一の目標だとするなら、「簡単さ/わかりやすさ」に関する尺度・基準が必要です。その尺度によって計って、より簡単/わかりやすいほうを選択したり、目指したりするわけです。

ところが、この尺度にあんまり自信がない。僕が「簡単でわかりやすい」と思っていることが、ターゲットユーザーである“Web制作をする人々”の「簡単でわかりやすい」感覚と一致してるか不安だということです。

「簡単でわかりやすい」なんて感覚は個人差があるし、平均値とか統計的に有意な情報が取れる見込みはないでしょう。一方、普遍的に共有できる簡単さ/わかかりやすさが存在するような気もするし。原理的に計量・計測困難であります。だからまー、仮説を取っ替え引っ替え進むしかないのだろう、とも思っています。

誤解/勘違いして欲しくないのは、最終的な利用者にとっての「簡単さ/わかりやさ」を実現するための背景理論、設計原理、実装方式が簡単容易であるなんてことはないことです。むしろ、単純さを保ちながらも抜けなく整合的なシステムを構成するには、かなり膨大な量の問題を解かなくちゃなりません。

僕が今後断片的にレポートするであろう内容は、出会った問題と、それを解くための試行錯誤(うまくいけば解決策)ですから、簡単でもなきゃ分かりやすくもないかも知れません。

*1:Catyハウスというお家に住んでます。技術ジャーゴンとしての「Catyハウス」はある種のサンドボックス環境のことです。

*2:2つのモノイド積を持ち、それらが半環(semiring)の法則を満たす圏です。2つのモノイド積を使って2種類のスタンピング・モナドを構成できます。一方が例外モナド、もう一方が副作用モナドに対応します。