Hatena::Grouperlang

檜山正幸のErlang未確認情報 RSSフィード

|

2009-04-17 (金)

デバッガー関連のコマンド(関数)

| 11:10

シェルからモジュールi(interpretのi)の関数を実行できる。i: は不要で、直接呼べる(コマンド)。

  1. im() -> pid()
  2. ii(AbsModules) -> ok
  3. ii(AbsModule) -> {module, Module} | error
  4. nini(AbsModules) -> ok
  5. ini(AbsModule) -> {module, Module} | error
  6. iq(AbsModule) -> ok
  7. inq(AbsModule) -> ok
  8. il() -> ok
  9. ip() -> ok
  10. ic() -> ok
  11. iaa(Flags) -> true
  12. iaa(Flags, Function) -> true
  13. ist(Flag) -> true
  14. ia(Pid) -> ok | no_proc
  15. ia(X,Y,Z) -> ok | no_proc
  16. ia(Pid, Function) -> ok | no_proc
  17. ia(X,Y,Z, Function) -> ok | no_proc
  18. ib(Module, Line) -> ok | {error, break_exists}
  19. ib(Module, Name, Arity) -> ok | {error, function_not_found}
  20. ir() -> ok
  21. ir(Module) -> ok
  22. ir(Module, Line) -> ok
  23. ir(Module, Name, Arity) -> ok | {error, function_not_found}
  24. ibd(Module, Line) -> ok
  25. ibe(Module, Line) -> ok
  26. iba(Module, Line, Action) -> ok
  27. ibc(Module, Line, Function) -> ok
  28. ipb() -> ok
  29. ipb(Module) -> ok
  30. iv() ->

随分イッパイある。しかし、名前が短すぎるよ。憶えるヒント。

im Monitor
ii Interpret
ini Net Interpret
iq Quit
inq Net Quit
il List modules
ip Processes
ic Clear information
iaa Set Attaching
ist Set Saving
ia Attach
ib Breakpoint
ir Remove breakpoint
ibd Breakpoint Disable
ibe Breakpoint Enable
iba Breakpoint Action
ibc Breakpoint Condition
ipb Print Breakpoints
iv Version

2009-04-16 (木)

pubファイルによるアプリケーション・メタ情報記述

| 11:03

システム的には、.appファイルがアプリケーションを記述するが、より一般的にアプリケーションに関するメタ情報を記述する形式にpubファイルがある。

supported syntaxe:

{author, {"Name", "EMail", {Year,Month,Day}}}.
{author, {"Name", "EMail"}}.

{packager, {"Name", "EMail"}}.
This is an optional field.
If packager field is not there, the author is declared as packager.

{category, ["Category"]}.
Category name must match one of the category listed on CEAN web site.
If you feel that a category is missing, you can set it into the .pub file, 
but please drop me a mail in that case.
You can also provide several category.

{name, "PackageName"}.

{vsn, "Version"}.
vsn can be a.b.c x.y string etc...
    1.2a > 1.2
    beta > alpha
    alpha > 1.0
note: package directory will be PackageName-Version

{depends, ["Package1","Package2",...]}.
Dependency is a list of package name.
Package name can include version:
    "stdlib" means requires stdlib any version
    "=stdlib-1.14.2" means requires stdlib version 1.14.2
    ">stdlib-1.14.2" means requires stdlib version newer than 1.14.2
    "<stdlib-1.14.2" means requires stdlib version older than 1.14.2
Note: No version checking by now. only "package" syntaxe is working.

{keywords, ["Word1","Word2",...]}.
These keywords will be used by the search engine.

{summary, "Summary"}.
Package description in one sentence, without trailing dot.

{abstract, "Long Description"
 "Can use several lines. "
 "and <i>can</i> use HTML tags."}.
Detailed package description.

{home, "http://www.your-web-site.org"}.

{sources, {git, "git://www.site.org/project"}}.
{sources, {svn, "http://svn.site.org/project/trunk"}}.
{sources, {cvs, ":pserver:anonymous@cvs.site.org:/cvsroot/project"}}.
{sources, {tar, "http://www.erlang.org/download/otp_src_R11B-2.tar.gz"}}.
{sources, {zip, "http://www.site.org/package.zip"}}.
{sources, {erl, "http://www.site.org/package.erl"}}.
Note: if archive name includes package version, you must check that it matchs the vsn field.

{configure, "arguments"}.
This is an optional field.
Arguments given to configure script at compile time.

If your package does not include a LICENCE file on root directory, then the default LICENCE from
CEAN root directory is effective (ERLANG PUBLIC LICENSE).

ということです。以下にpubファイルの例をいくつか。

[追記]PHPのパッケージ記述形式

他のプログラミング言語でもそれぞれあるんだろうな、おそらく。

[/追記]

続きを読む

ETSのテーブルの種類

| 16:40

ETSテーブルは:

  1. セット型
  2. 順序付きセット型
  3. バッグ型
  4. 重複可能バッグ型

がある。この分類が分かりにくい。なんで分かりにくいんか? と考えたら、対称性が欠けているからだろう、と思った。

どんなコレクションであれ、コンピュータでは列(リスト)になる。順序がないとか言っても有るよ、必ず! で、テーブルつうかマップの場合、データのリストとキーのリストがある。それで分類して:

重複なし 重複を許す
キーリスト セット型 バッグ型
データリスト - 重複可能バッグ型

というわけで、2×2分類で一箇所が無意味で3種となる。重複のチェックをするとパフォーマンスは落ちる。

順序付きセット型とは、そもそも違うデータ構造を使って、セット型が常に一定の順序で並んでいることを保証する。これを入れて4種ってことね。

2009-04-15 (水)

Erlang modeのインデント

| 09:11

foo() ->
  Q = $",

うまくインデントできない。

foo() ->
  Q = $", % "

としてもダメだーー。

-define(QUOT, 34).
foo() ->
  Q = ?QUOT,

だせっ!

2009-04-14 (火)

YAWSのクッキー処理 その2

| 08:46

YAWSには、session_serverがあるが、session_serverを使わなくても次のようなことはできる。

setcookie関数で作ったヘッダを毎回ブラウザに押し込むことによって訪問回数をカウントする例。サーバー側では何も記録してないし、セッションも使ってない。

%% -*- coding: utf-8 -*-

%% @doc クッキーのテスト
-module(amod_cookie).

-export([out/1]).
-compile(export_all). % for test

-include("../../yaws/include/yaws_api.hrl").

%% @doc 一意的な訪問者IDを生成する.
%% @spec () -> string()
generate_visitor_id() ->
  "Hiyama". % 俺しかおらんわ

%% @doc 回数を1増やす.
%% 入力も出力も整数を表す文字列.
%% @spec (string()) -> string()
increment(TimesStr) ->
  Next = 
    try
      list_to_integer(TimesStr) + 1
    catch
      _:_ ->
        0
    end,
  integer_to_list(Next).


%% @doc YAWSのコールバック関数
%% @spec (#arg{}) -> term()
out(A) ->
  H = A#arg.headers,
  ReceivedCookie = H#headers.cookie,
  case yaws_api:find_cookie_val("visitor", A) of
    [] ->
      CookieHeaderVisitor = yaws_api:setcookie("visitor","Hiyama","/"),
      CookieHeaderTimes = yaws_api:setcookie("times","1","/"),
      Ehtml = {ehtml,
              {html,[],
               [
                {body, [],
                 ["I just set your cookie."]
                 }
                ]
               }
              },
      [Ehtml, CookieHeaderVisitor, CookieHeaderTimes];
    Visitor ->
      CookieText = io_lib:format("~p~n", [ReceivedCookie]),
      Ehtml= {ehtml,
              {html,[],
               [
                {body, [],
                 [
                  "Hi, " ++ Visitor ++ ".",
                  {hr, ,},
                  "I have received: " ++ CookieText,
                  ""
                 ]
                }
               ]
              }
              },
      NewTimes = increment(yaws_api:find_cookie_val("times", A)),
      CookieHeaderTimes = yaws_api:setcookie("times", NewTimes, "/"),
      [Ehtml, CookieHeaderTimes]
  end.

クッキーヘッダの構文

| 09:31

YAWSソース中にRFCからの抜粋を発見。

%%  Parse a Set-Cookie header. 
%% 
%%  RFC (2109) ports are from RFC 2965
%% 
%%  "Cookie:" cookie-version 1*((";" | ",") cookie-value)
%%  "Set-Cookie:"  cookies
%%  "Set-Cookie2:" cookies
%%  cookie-value    =       NAME "=" VALUE [";" path] [";" domain] [";" port]
%%  cookie          =       NAME "=" VALUE *( ";" cookie-av )
%%  cookie-version  =       "$Version" "=" value
%%  NAME            =       attr
%%  VALUE           =       value
%%  path            =       "$Path" "=" value
%%  domain          =       "$Domain" "=" value
%%  port            =       "$Port" "=" <"> value <">
%% 
%%  cookie-av       = "Comment" "=" value
%%                  | "CommentURL" "=" <"> http_URL <">
%%                  | "Discard"
%%                  | "Domain" "=" value
%%                  | "Max-Age" "=" value
%%                  | "Path" "=" value
%%                  | "Port" [ "=" <"> portlist <"> ]
%%                  | "Secure"
%%                  | "Version" "=" 1*DIGIT
%% 

YAWSのクッキー処理 その3:セッションサーバー

| 11:16

YAWSのセッションサーバーは、次のAPIを経由して使える。

Create a new cookie based session, the yaws system will set the cookie. The new random generated cookie is returned from this function. The Opaque argument will typically contain user data such as user name and password.

As above, but allows to set a session specific time-out value, overriding the system specified time-out value.

  • new_cookie_session(Opaque, TTL, CleanupPid)

As above, but also sends a message {yaws_session_end, Reason, Cookie, Opaque} to the provided CleanuPid where Reason can be either of timeout or normal. The Cookie is the HTTP cookie as returned by new_session() and the Opaque is the user provided Opaque parameter to new_session(). The purpose of the feature is to cleanup resources assigned to the session.

  • cookieval_to_opaque(CookieVal)
  • print_cookie_sessions()
  • replace_cookie_session(Cookie, NewOpaque)
  • delete_cookie_session(Cookie)

クッキー、クッキーと言っているが、セッションサーバーHTTPクッキーとは一切何の関係もない。 単に、タイムアウトTTL)付きでkey/value pairを保存するストレージ。キーのほうがセッションIDだが、これを cookie string = cookie value と呼んでいる。非常に誤解を与えやすく困ったもんだ。

key/value pairのvalueのほうはopaque data、まったく任意。cookie session とは、「cookie value とopaque data の対」のことだと思えばいい、それ以上の意味は何もない。セッションサーバーは内部でETSを操作しているだけ。

CRUD API関数 ETS操作
Create new_cookie_session/{1,2, 3} insert
Read (Query) cookieval_to_opaqu/1 lookup
Update replace_cookie_session/2 lookup, insert
Delete delete_cookie_session/1 delete

サンプルは後で。

日本語とか雑多なライブラリとか

| 12:01

Erlangは、以前から僕がやりたかったこと、例えば「がんがん実稼働させながら、ゆるゆるデバッグ」とか、「猿を1000匹くらい雇ってモンキーテストしたい」とか、まー「おまえはアホかっ!?」的な妄想を実現してくれそうな気がして、頭を突っこんでいるわけだが、

  • 日本語の扱いがやっぱり辛いなー、UTF-8がサポートされりゃいいって問題でもない、
  • ちょっとしたことをやる雑多なライブラリがあまりころがっていない。

ここらは苦労しますわ。しょうがないけど。


ころがってないか探す場所(再掲):

2009-04-13 (月)

YAWSのクッキー処理 その1

| 18:47

「YAWSのクッキーセッション」にて:

yaws_apiにあるいくつかの関数を使う。説明をそのうち書くだろう、たぶん。

今日は、次の2つの関数だけ。

  • yaws_api:setcookie/[2-6]
  • yaws_api:find_cookie_val/2

クッキーについての記述は次が原典(つっても詳しくない)。

setcookie関数

  • setcookie(Name, Value, [Path, [ Expire, [Domain , [Secure]]]])

Sets a cookie to the browser.

クッキーのデータは、名前/値ペアの集合なので、基本は NameとValueを指定する。

引数 説明 データ型
Name セットするクッキー項目の名前 アトムまたは文字列
Value 名前に対応する値(内容) アトムまたは文字列
Path そのドメインのどのパスから下で有効になるか文字列
Expire 有効期限(無効になる時刻)文字列、秒単位までの時刻文字列
Domain どのドメインに送るか 文字列
Secure 暗号化するときだけ送るかどうか アトム on, off

このsetcookie関数は、{header,{set_cookie, "foo=bar;"} } のようなSet-Cookie:ヘッダを作って返すだけ。戻り値であるヘッダ指定をそのままYAWSに出力すればよい。関数名は make_cookie_headerとかが適切だったろう。

ブラウザにSet-Cookie:ヘッダが入ったレスポンスが届くと、クッキーの名前/値ペアがローカルストアに押し込まれる。

幸いに、次にクッキーの詳しい解説がある。

YAWSのsetcookie関数は、引数から次のようにしてSet-Cookie:の文字列を作っている。

  • " Domain="++Domain++";"
  • " Expires="++Expire++";"
  • Secureがonなら、" secure;"
  • 最後に "~s=~s;~s~s~s Path=~s", [Name,Value,SetDomain,SetExpire, SetSecure, SetPath]

EShellで実験できる。

305> {header, {set_cookie, X}} = yaws_api:setcookie("User", "hiyama"), io:format("~n~s~n", [X]).

User=hiyama;
ok
306> 

find_cookie_val関数

  • find_cookie_val(Cookie, Header)

This function can be used to search for a cookie that was previously set by setcookie/2-6. For example if we set a cookie as yaws_api:setcookie("sid",SomeRandomSid), then on subsequent requests from the browser we can call: find_cookie("sid",(Arg#arg.headers)#headers.cookie)

The function returns [] if no cookie was found, otherwise the actual cookie is returned as a string.

上記のhttp://www.studyinghttp.net/cookiesによると、クッキー文字列はこんな感じの文字列らしい。

Customer="Tarou_YAMADA"; Part_Number="IBMPC_01";

エスケープすると、 "Customer=\"Tarou_YAMADA\"; Part_Number=\"IBMPC_01\";" ですな。

値がダブルクォートされているのは仕様(構文)ではない気がする。イコールとセミコロンがデリミタで、イコールからセミコロンのあいだが問答無用で値とみなされるようだ。空白は無視されるようだが、名前とイコールの間の空白は許されない。セミコロンをエスケープする方法はないみたい(みたいみたい)。

find_cookie_val(Cookie, A) when record(A, arg) ->
    find_cookie_val(Cookie,  (A#arg.headers)#headers.cookie);

となっているので、第二引数にArgを入れても大丈夫。

find_cookie_val関数は単なる文字列処理関数で、第1引数の名前文字列をキーとする値を探して返すだけ。値が見つからなければ空文字列("" = 空リスト)を返す。ただし、テストするときは、第二引数にArgじゃなくて、文字列のリストを入れることができる。僕は、シェルでテストしてクッキー文字列の構文を推測したのだった。

Erlang文字列処理ってコンナだよ、ってサンプルとしてソースを貼っておく。

続きを読む

2009-04-08 (水)

乱数からIDを作る

| 13:42

YAWSソースから抜き出したサンプル。

%% -*- coding: utf-8 -*-

%% @doc 乱数に基づく「ほぼID」の生成
-module(randomid).
-export([init/0, gen/0]).

%% spec () -> {integer(), integer(), integer()}
seed() ->
  now(). % {X, Y, Z}

%% @spec () -> ok
init() ->
  {X,Y,Z} = seed(),
  random:seed(X, Y, Z),
  ok.

%% @spec () -> string()
gen() ->
  N = random:uniform(16#ffffffffffffffff), %% 64 bits
  integer_to_list(N).

YAWSのクッキーセッション

| 13:47

yaws_apiにあるいくつかの関数を使う。説明をそのうち書くだろう、たぶん。

-record(myopaque, {udata,
                   times = 0,
                   foobar}).

out(A) ->
    H = A#arg.headers,
    C = H#headers.cookie,
    case yaws_api:find_cookie_val("baz", C) of
        [] ->
            M = #myopaque{},
            Cookie = yaws_api:new_cookie_session(M),
            Data = {ehtml,
                    {html,[],
                     ["I just set your cookie to ", Cookie, "Click ",
                      {a, [{href,"session1.yaws"}], " here "},
                      "to revisit"]}},
            CO = yaws_api:setcookie("baz",Cookie,"/"),
            [Data, CO];
        Cookie ->
            {ok, OP} = yaws_api:cookieval_to_opaque(Cookie),
            OP2 = OP#myopaque{times = OP#myopaque.times + 1},
            yaws_api:replace_cookie_session(Cookie, OP2),
            Data = {ehtml,
                    {html,[],
                     [
                      "Click ",
                      {a, [{href,"session1.yaws"}], " here "},
                      "to revisit",
                      {p, [], f("You have been here ~p times", [OP2#myopaque.times])},
                      {p, [], f("Your cookie is ~s", [Cookie])}]}},
            Data
    end.

2009-04-07 (火)

YAWS for Windows

| 16:18

バージョン 1.80 からインストラー付きの win32 version of yaws が付いたようだ。Yaws-1.81-windows-installer.exe をダウンロードして実行してみたが、確かに何もしないでインストールできた。

が、起動ファイルが yaws.exeなのが不便。バッチファイルは無理だったのかな? ちょいと変更するにもCのビルド環境が必要なのは困るな。Windowsだとビルド環境が面倒だもん。[追記]自分でバッチファイル書けばいいだけのハナシだわな。[/追記]

2009-04-04 (土)

T. Parrの用語法

| 12:56

T. Parrは形式言語理論の専門家だし、大きなサイトの運用経験もあるから、彼の意見は信頼できる。僕が一番アテにしている資料だ。が、用語法が僕らが日常的に使っている言葉と異なっているのでとまどうかも。

T. Parr わしら
attribute コンテキストから取れる値
single-valued attribute コンテキストから取れるスカラー
multi-valued attribute コンテキストから取れるリスト/配列
aggrigate attribute コンテキストから取れるオブジェクトプロパティリスト
(set of) attributes コンテキスト
template reference テンプレート内から他のテンプレートへの参照
attribute reference テンプレート内からコンテキストへの参照(パス)
action 属性参照、テンプレート参照を実際に評価する操作
predicate ブール値を持つ属性、ブール値を返す関数/メソッド

ああー、難しい;分離とコミュニケーションコスト

| 12:56

T. Parrによれば、テンプレート言語にビジネスロジックを書ける能力を持たせると書いてしまうからダメだ、と。よって、論理演算や算術計算も禁止する。

だが、条件判断や計算が、ビジネスロジックだけで使われるわけじゃない。プレゼンテーションを組み立てるときに参照や計算が必要になるケースもあるだろう。特に、リスト(配列)の長さとか、要素の順番/キーとか。

プレゼンテーションロジック組み立てのために、デザイナがプログラマに依頼をするとすれば、これは本末転倒。モデル、ビジネスロジックの情報で、プレゼンテーションに出していいものが不足してるなら、これを要求するのは許される。例えば、注文金額の総額の計算は、テンプレートでできないからコンテキストに含めてもらう、とか。

次は、たぶん必要だ。

  1. リストの長さ
  2. 繰り返しのボディ内で、要素の順番/キー名。

JSON in Erlnag

| 15:22

本編に以前書いたけど、繰り返す。

  1. YAWS付属のjson.erl (http://yaws.hyber.org/
  2. LShft社提供のrfc4627.erl (http://hg.opensource.lshift.net/erlang-rfc4627/
JSON YAWS LShift
true, false, null true, false, null true, false, null
number number() number()
string string() binary()
array {array, element_list()} array()
object {struct, proplist()} {obj, [{key(), value()}]}

// yw_ YAWS版
// ls_ LShift版

number() = integer() | float()
element_list() = [yw_value()]
proplist() = [{yw_key(), yw_value()}]
yw_key() = string() | atom()
yw_value() = (true | false | null) | 
             number() |
             string() |
             {array, element_list()} |
             {struct, proplist()}

array() = [ls_value()]
ls_key() = binary() | atom() 
ls_value() = (true | false | null) |
             number() |
             binary() | 
             array() | 
             {obj, [{ls_key(), ls_value()}]}

Erlangに標準で入ったら追加しよう。

2009-04-03 (金)

cathandメモ

| 11:14

どこに書いたらいいか迷ったがココにする。[連絡的]というタグが付いたエントリーは、檜山本人と身内しか意味がわからない。それでも公開で書くのは、内輪の連絡からでさえなにがしかの情報や示唆を得る人がいないとも限らない、と考えるから。

基本は T. Parrの論文

コンテキスト(Parrのいう属性)概念がキモ。コンテキストをコアコンテキストと拡張コンテキストに分ける。コアコンテキストはプログラマが準備し、拡張コンテキストはデザイナが必要なら準備する。拡張コンテキストを構成する素材は

  1. ファイルシステムディレクトリツリー)そのもの
  2. 定数ファイル(拡張子 .const

定数ファイルは便宜上のもの、あれば便利そうだから入れただけ。

コアコンテキスと定数ファイルは、リテラル値を提供する。リテラルのなかにはもはや変数(プレイスホルダ)がない、値そのもの。テンプレートがさらにテンプレートに展開される再帰処理は、すべてデザイナの責任、プログラマは無関係。

ファイルシステム内のファイルがテンプレートリテラルかを判断するのは、ファイル先頭に埋め込まれた宣言を使う。その他のコンベンション拡張子とか)、設定は使わない。「ファイルパスと宣言のあるなし」の関係は効率のためにキャッシュされる。


考えるべき事は:

  1. パスマッピング -- URLローカルファイルの対応
  2. テンプレートの構文と能力 -- 純関数型、モナド
  3. コンテキストサーチ -- URLやリクエスト情報からコンテキストを探す、または生成
  4. コンテキスト管理 -- コンテキストは寿命を持つので管理する必要がある。
  5. 変数に対して値がないときの処理 -- ここは、理論と現実のギャップを埋めるところ。

理論上は、リテラル値(定数)とテンプレート(式)をさほど区別する必要はないが、現実にはウルトラ厳密分離の要求があるで、値とテンプレートはまったく別扱い。プログラマからは値しか見えないし、値(構造的値)だけでテンプレートインターフェースする。

テンプレート展開エンジンは、純粋なモナド実装。つまり、Kleisli圏の結合を計算するだけ。リソース管理などを入れるとロクデモナイことになるので、直接にファイルを触ったりしては絶対にダメ。このへんはDIっぽく作る。ファイルリソースも含めてコンテキスト(チェーンに編成される)を準備して、それをテンプレート展開エンジンに渡すのはエンジンを使う側の責任。


「これはテンプレートだよ」と宣言するのは、テンプラのコメントを使う。

  1. 先頭から3行目までなら宣言開始行を書ける。(4行目以降は探さない)
  2. 宣言そのものは消すが、その他は改行も含めて残す(出力に送る) -- 仕様変更
  3. 知らない属性(Name = "Value" 構文)をエラーとしない。
  4. 複数行に渡って書いてもよい。

例:

<!--
{*! template="true" 
    context="../foo.ctx" 
    constants="../../const.const" *}
-->

ヘッダファイルのオマジナイ

| 13:08

あー、C言語のヘッダでやってたよなー。なつかし。

-ifdef(FOO_HRL).
-define(FOO_HRL, true)
 %% ...
 %% ...
-endif. % FOO_HRL

心変わりしたところ、要求、目標

| 18:13

昨日から今日で心変わりしているのだが、それは、プログラマプログラミングだけする人)とデザイナ(その他のことをする人)を対称的にしようと思ったこと。実際には、プログラマとデザイナの中間の人とか、両方できる人とか、ディレクターだか何だかどっちでもない人とかがいるが、単純化して考える。

  1. サイト全体の構成に関しては、プログラマが主導でもデザイナが主導でもどっちでもいい。
  2. フォーム送信データのデータ形式、ページに対するコンテキストのデータ形式をデザイナが決めてもいい。
  3. いずれにしても合意は絶対に必要だが、合意事項=仕様はデータとして残る。
  4. 仕様が決まったところから並行作業ができる。
  5. 合意事項=仕様の変更時にはコミュニケーションが必要(これはどうにもならない!)

どっちでもよくない作業は:

  1. データベース設計とビジネスロジックプログラマの責任
  2. プレゼンテーションユーザビリティはデザイナの責任

合意事項=仕様さえお互いに守っていれば、かつ信頼関係があれば、コミュニケーションコストは最小になる。

それと、非常に重要なことは、互いの進捗にかかわらず担当部分のテストができること。デザイナはプログラムがなくてもプレゼテーションの確認ができるし、データのやり取り(例:フォーム→DBテンプレート)のおおよその確認もできる。同様に、プログラマプレゼンテーションなしでもテストができる。

どっちかというと、デザイナ側のテスタビリティのほうが緊急の話。次が要求:

  1. ローカルファイルシステム+ブラウザだけでもプレゼンテーション(見た目)のおよその確認ができる。
  2. ローカルファイルシステム+ブラウザだけでもリンクをたどることができる。
  3. ローカルファイルシステム+ブラウザだけでもCSSの効果やJavaScriptAjaxではない)の確認ができる。
  4. ヘッダ、フッタなどのお決まり部品のメンテナンスが容易。
  5. サイトコンテンツ(単一ZIPファイル)をアップロードするだけで配備完了。
  6. プログラムまったくない状態でも、動的ページとフォームが動作する。
  7. データベースの代わりに、簡単なテキスト形式データ(たぶんJSON形式)をダミーに使える。

2009-04-02 (木)

void, nullがない。

| 16:34

voidとかnullのように、標準的などうでもいい型、無効値がない。

アームストロングvoidというアトムが好きらしい。okを返している例も多い。undefinedもよくあるな。僕はnoneが好きでよく使っている(標準ライブラリでもnoneの例がある)。

最近思ったのだが、noneやundefinedは、積極的に「値がない/未定義」を意味するから、ほんとにどうでもいい、値を使うのはやめてくれ、捨ててくれ、ってときはvoidのほうがいいかも知れない。捨てられるのだから何だっていいんだけど、コンベンションとしてね。

エラー処理と責任問題

| 16:34

apply、アブネーー関数の存在確認、例外のリスローの問題だが、状況にもよるが、apply(M, F, A) だけして何もしないのが正解かもな。

undefだけ捕まえるのは明らかにマズイ、事前に存在確認しても例外が出るときは出る。対処のしようがないからそれは捕まえない。だったら、事前に存在確認もいらねーんじゃん。ダメなときゃダメなんだから。

コールバックを正しく作って正しく配備するのはそっち(誰?)の責任だから、呼び出す側は「正しくくセットされている」という前提で仕事して、そうじゃないなら天災人災だが)と考える。

Erlangだと「俺の責任」以外は「天災/もう知らん」と思ったほうが健全そうだ。

ホーア論理とブルートフォース・テスト

| 17:00

ホーア論理に始まりホーア論理に終わる -- 何が? まーともかく、仕様記述つったらホーア論理が基本でしょ。

一方、僕はモンキーテストとかブルートフォース式のテストが好き。理由は、猿とか猿に近い人とかに任せられるから。知的努力をするより、猿に任せた方がバグが出たりする。

受け入れテストをチャンとしている例を知らないのだけど、そもそも「受け入れテストをチャンとする」の意味がわからないし、イメージが湧かない。本来(?)なら、発注側が仕様を決めるから、発注側は仕様に対応するホーア式を持っているべきだろうが、そんな例を知らない。

受け入れテストをもしやるにしても、ブルートフォースになるんじゃなかろうか。実際のところ、リテラルで書かれたエクスペクテーションをイッパイ準備してもらって、はじからチェックするような形だろう。Excelファイルだったりするんだろう。

現実迎合派の僕としては、ブルートフォース・テストで済ませたいし、ブルートフォース or モンキーは絶対にやるべきだとも思っている。また一方、プログラマはホーア式を書くべきだとも思っている。しかし、そのホーア式がブルートフォースと一緒に使えないと意味ない。

つまり、ホーア式による仕様記述、実装プログラムコード、ブルートフォース用のデータ/エクスペクテーションをうまく協調させたい。プログラマがテストを嫌う状況を改善するのはどうも無理な気がするから、せめて「猿にテストさせやすいコードを書く」ように強制したい、圧力をかけたいのだよね。

size/1, tuple_size/1

| 17:31

size/1以外にtuple_size/1てのもある。もちろん、tuple専用。なぜか、binary_size/1はない。sizeが型オーバーロードしているなら、listのlengthも分かればいいのに。

wbdjkcqcpswbdjkcqcps2013/08/28 02:13vvoskfsmboh, <a href="http://www.teetlxcydi.com/">zeptfodakf</a> , [url=http://www.lfprwfvnog.com/]hrjlynvtod[/url], http://www.gjjqilpgam.com/ zeptfodakf

thxpfkitzuthxpfkitzu2014/03/18 18:03mxfmdfsmboh, <a href="http://www.cgeuxhshnw.com/">jxarsqwhxg</a> , [url=http://www.pfyavtpqjp.com/]pficlukqwf[/url], http://www.alpsvdvtvq.com/ jxarsqwhxg

lelocffzgtlelocffzgt2014/04/12 15:46vsmpafsmboh, <a href="http://www.mvqsrcvjyt.com/">jwqzrmhbxn</a> , [url=http://www.wnopwsfrwr.com/]xmzsismghz[/url], http://www.zpckatvivp.com/ jwqzrmhbxn

|