読者です 読者をやめる 読者になる 読者になる

理系学生日記

おまえはいつまで学生気分なのか

忍者TOOLS

没入したのは恐怖でした、BIOHAZARD 7

usual day

遅ればせながら、BIO HAZARD 7 をクリアしました。グロテスク ver. の方です。

BIO HAZARD 7 については「原点回帰」と言われていたのですが、その評判は確かでした。 初代の BIOHAZARD を想起される恐怖がそこかしこに満ちていて、ゆっくり開くドアの向こうに潜むであろう得体の知れないものを恐れながら、ただただ進まざるを得ないという何とも言えない感覚に支配されていて、ぼくはこのゲーム、今でも一人でプレイしたくありません。

初代の BIOHAZARD に回帰しながらも大きく違うのは、1 つは没入感だと思います。 初代 BIOHAZARD は固定カメラ視点で展開されていきますが、BIOHAZARD 7 ではいわゆる First Person View で物語が進んでいきます。

主人公であるイーサンが体験する視界はゲームをプレイする自分が体験する視界であり、イーサンが体験する未知は自分が体験する未知になります。 そして眼前に広がる世界は、PS1 を遥かに凌駕する精細さで目の前に展開されて、この不気味な廃屋に自分だけが取り残されたかのような、そんな感覚から逃げ出すことができませんでした。

また、イーサンは戦闘に関しては素人です。少ない武器、乏しい体術、攻撃を除けることもままならない中、いつ何が出てくるか分からない状態での探索というのは過大なストレスを作ります。 きしむ足音、うなる風音の一つにも反応してしまうほどに空気を張り詰めさせ、人間が本能として持っているのであろう恐怖センサーを過敏にし、もう勘弁してくれという状況で襲いくる敵との対峙。退屈を全く感じさせないゲームでした。

誰だよ絶対 PS VR でプレイしようとか言ってたのはよー。これ VR でやったらトイレ行けなくなるだろうがよー。

やって損はしないゲームだと思います。しかし、グロテスク ver. と無印の価格差は一体なんだったのか。

tabindexで消耗していた話

technology

tabindex には苦しまされることが多いです。

ぼくは以前に tabindex でタブオーダーが明示的に指定されているシステムのテストを行うことになったんですが、タブオーダーが設計上で明示的に指定されている以上タブオーダーがテスト観点に挙がり、打鍵でタブオーダーを一つ一つ確認するというテストを行いましたが、 タブオーダーのようなユーザインタラクションに関するテストについては「どのようにそのテスト実施者が行ったテスト実施結果の正しさを確認するのか」という問題があり、たいへんつらいものでした。

今日のエントリでは、そもそも論として、tabindex の機能、そして、その使い方のベストプラクティスは何なのかを考えてみます。

tabindex とは

tabindex というのは、HTML 仕様で定義されている属性で、

  1. tabindex 属性を付与された要素がフォーカスを持てることを示す
  2. (TAB キー等で)フォーカスを移していく操作によって、フォーカスを移動できるかを示す
  3. フォーカスの移動順(タブオーダー順)を示す

といったことを可能にします。最後に示した フォーカスの移動順 というのは、実は tabindex 属性のオプション機能でしかありません。

tabindex が付与されていないタグに対しては、ブラウザはデフォルトの動作を適用します。 具体的には、<a><audio><button><img><input> といったタグ (これらを Interactive Content と呼びます) に対しては、デフォルトでフォーカスが当たります。 逆に言えば、<span><div> といった Interactive Content ではないタグに対してフォーカスを当てるためには、明示的な tabindex 属性の付与が必要です。つまり、tabindex 属性はタグを Interactive Content に変える、といっても良いかもしれません。

tabindex の使い方

tabindex については、大きく分けて 3 つの使い方があります。

  1. tabindex="0" を指定する
    • 指定されたタグは、ブラウザ上でフォーカスを受けることが可能になります。"0" が指定された場合、そのフォーカス順 (タブオーダー) はブラウザが決めます。ブラウザは通常、DOM 上での出現順にタブオーダーを割り当てます。
  2. tabindex="-1" 等、負の数を指定する
    • 指定されたタグは、フォーカスを当てることは可能になりますが、タブオーダーの中には含まれません(タブを押すだけでは、フォーカスを与えられません)。フォーカスを当てるためには、JavaScript 等で明示する必要があります。
  3. tabindex="1" 等、正の数を指定する
    • 指定されたタグは、ブラウザ上でフォーカスを受けることが可能になります。また、タブオーダー順で考慮されます。

最後の「タブオーダー順で考慮される」っていうのはちょっと複雑なんですが、大まかに言うと、

  1. tabindex が指定されている要素の方が、指定されていない要素よりも前
  2. tabindex の値が正の数の場合、tabindex が 0、または負の数の要素よりも前
  3. あとは大体、tabindex の値順

っていう感じになります。

ベストプラクティス

長々と書いてしまいましたが、tabindex については、

  • 使うなら負の数指定、あるいは 0 指定
  • 正の数は指定するな

が推奨になります。 これは、W3C の HTML 仕様ARIA のベストプラクティス にも記載があります。

W3C HTML 仕様

Using a positive value for tabindex to specify the element’s position in the sequential focus navigation order interacts with the order of all focusable elements. It is error-prone, and therefore not recommended. Authors should generally leave elements to appear in their default order.

ARIA-Practices

When using roving tabindex to manage focus in a composite UI component, the element that is to be included in the tab sequence has tabindex of “0” and all other focusable elements contained in the composite have tabindex of “-1”.

正の値を指定しないのは、タブオーダーの指定がミスしやすいからです。

通常のタブの遷移は、いわゆる Z 型、左から右、上から下に遷移するというのが自然なタブオーダーとされていて、普通に HTML/CSS を書くと、このあたりはブラウザが標準で行ってくれます。 しかし、tabindex 属性で正の値を指定する場合、これらのタブオーダー遷移が崩れやすくなります。要素の追加、削除に伴なって、tabindex の値を正しく保つのは並大抵のことではありません。

この保守コストを支払ってでも、タブオーダーを操作したいケースというのはそうそうあるものではないと思うので、tabindex を使って明示的にタブオーダーを操作する必要があるのかは、慎重に考えた方が良いところだと思います。

Macを切り替えたら exec-path-from-shellで環境変数が引き継がれなくなる

emacs

ずっと MacBook Air で日常を暮らしてきて、やっぱりデカいディスプレイで暮らしたいなぁということで、昔つかってた iMac に乗り変えました。 そこで困ったのが、Emacs で環境変数が引き継がれてこないということでした。

Emacs では、exec-path-from-shell を使うことで、zsh に定義した環境変数を Emacs でも使えるようにしているんですが、PATH とか GOPATH とかが使用できなくなっている。なぜだ。

これ、原因は、デフォルトシェルを切り替えていないからでした。これで解決。

$ sudo echo '/usr/local/bin/zsh' >> /etc/shells
$ chsh -s /usr/local/bin/zsh
$ sudo shutdown -r now

内容

exec-path-from-shell は、環境変数の引き継ぎを「シェルを実際に Emacs 内部で実行し、printf 等を使用して環境変数の値を出力させ、それを読み取る」という形で実現しています。 そして、ここで実行されるシェルというのは、以下のように決定されます。

  1. exec-path-from-shell の exec-path-from-shell-shell-name で定義されたもの
  2. Emacs の shell-file-name で定義されたもの
  3. (Emacs から見える) SHELL 環境変数の値

具体的な関数はこちら。

(defun exec-path-from-shell--shell ()
  "Return the shell to use.
See documentation for `exec-path-from-shell-shell-name'."
  (or
   exec-path-from-shell-shell-name
   shell-file-name
   (getenv "SHELL")
   (error "SHELL environment variable is unset")))

Emacs の設定を色んな環境で使用しようと思うと、elisp の変数に対してパスを設定することは望ましくありませんから、ぼくはこのうちの 3. を使っていました。 結果として、デフォルトシェル(bash)の環境変数が使用されていたというお話。

JavaでのQRコード生成

java

QR コード

あまり知られていませんが、QR コードは日本発の規格になります。 スマートフォンで打ち込むのが面倒なデータをカメラ読込のみで入力できることから世界的にも普及しておりまして、先日は iOS の Chrome に QR コードをスキャンする機能も追加されたのは記憶に新しいところです。

Java における QR コードライブラリ

Java で QR コードを作る場合、zxing (Zebra Crossing) を使用するのがスタンダードのようです。 これとは別に、QRGenというライブラリもあるのですが、こちらも内部で zxing を使用しています。QRGen については、すごく使いやすいインタフェースを提供してくれているので、そちらを使うという選択もアリだとは思います。

本日(2017/03/11) 時点でのデータは以下のとおり。

ライブラリ ライセンス Star 最終 commit
zxing Apache License 2.0 12,454 2017/03/08
QRGen Apache License 2.0 593 2016/10/31
Barcode4J Apache License 2.0 - 2012/????

zxing を用いた実装

最初に、作成した画像をそのままブラウザに返却する想定の実装例です。これにより、以下のような QR コードが生成されます。

    // QR コードで表現するコンテンツ
    final String contents = "kiririmodeのQRコード";

    // QR コード生成用のオプション
    final Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
    hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
    hints.put(EncodeHintType.MARGIN, 2);
    hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8);

    try {
      // QR コード用一時画像ファイルの作成
      final Path path = Files.createTempFile("qr", ".png",
          PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rw-------")));

      // QR コードデータの生成
      final BitMatrix matrix =
          new QRCodeWriter().encode(contents, BarcodeFormat.QR_CODE, 1024, 1024, hints);
      // QR コードを画像化
      MatrixToImageWriter.writeToPath(matrix, "PNG", path);

      final HttpResponse response = new FileResponse(path.toFile(), true);
      response.setContentType("image/png");
      return response;
    } catch (WriterException | IOException e) {
      throw new RuntimeException(String.format("converting [%s] to qrcode fails", contents));
    }

QR コード生成用のオプションは、個々に EncodeHintType として表現します。

エラー訂正のレベル

まず、ERROR_CORRECTION はエラー訂正のレベルになります。QR コードは wikipedia:リードソロモン符号 をベースとしており、誤り訂正を行うことができます。

エラー訂正レベルを上げるほど、一部が隠れていたり滲んでいたりしても QR コードとして読み取ることができますが、そのぶんデータ量が多くなります。データ量が多くなれば、クライアント側の読み取り速度にも影響を与えることがあります。 デンソーに依れば、エラー訂正レベル M (15 % まで訂正可能) で使われることが多いようです。

文字コード

また、文字コードのデフォルトは、ISO-8859-1 なので、日本語が表現できません。日本語を QR コードに埋め込みたい場合は、実装例のように CHARACTER_SET に対して UTF-8 等を明示的に指定する必要があります。

バージョン

QR コードにはバージョンがありますが、これは仕様としてのバージョンではなく、その QR コードのサイズによって分類されています。 そのサイズによって当然ながら QR コードに含められる情報量は変化します。ただ、zxing はそのあたりの面倒を自動的に見てくれる (コンテンツのデータサイズによって、自動的にバージョンを判別し、それに応じたサイズの QR コードを出力してくれる) ので、実装上あまり悩むことはないと思います。

全体として

全体として、zxing はすごく使いやすいライブラリだと思います。 最初だけ、どこから手をつけれんば良いんや…という状態でしたが、色々なサンプル実装を見た後で JavaDoc を読み解けば、なるほどこうすれば書けるのかというのが掴めてきます。

個人で実装するのは相当つらそうだったので、有り難く使わせてもらおうと思います。

PoEAA: Page Controller

poeaa

Page Controller は、特定ページ/Action に対するリクエストを処理するオブジェクトです。

本書では、これを実現する方法として、

  1. Server Page (ASP/PHP/JSP 等) に混ぜる
  2. Script (CGI/Servlet) で記述する

という方法を謳っていますが、このうちで Server Page に混ぜる方法については、構造が汚くなるぞという念押しがされています。まぁ実践としても、コントローラは独立した Object として分離するというのがどこでも実施されている方法だと思います。 分離したコントローラの基本的な責務としては、

  1. URL のデコードと、Form データの抽出
  2. モデルの作成と、作成したモデルにデータ処理をさせる
  3. どの View を表示するかの決定と、当該の View に対するモデルの情報の引き渡し

となります。

PoEAA: Model View Controller

poeaa

今日からは、Web Presentation Pattern の章にはいります。 最初が Model View Controller なんですが、おそらく開発者の誰もが聞いたことがあるパターンです。

Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))

Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))

Model View Controller は、以下の 3 つの役割を定義するところから始まります。

  1. Model: ドメインに関する情報を表現するオブジェクト
  2. View: UI 上のモデルの表現
  3. Controller: ユーザの入力を受けて、モデルを操作し、View を適切に更新する役割。

この 3 つの役割により、UI は 2 つの分離が起こります。1 つは「モデル」からの「表現」の分離、もう 1 つは「表現」からの「Controller」の分離です。特に前者の分離の重要性は著しく高く、これは以下のような理由に依ります。

  1. そもそもモデルと表現では、開発者に求められるスキルセットが全く異なる
  2. 同じモデルに対する、複数の表現が必要となるケースが多々ある。リッチクライアントやブラウザ、API や CLI インタフェースなど。
  3. 表現を排除すれば、モデルに対するテストが容易にある

逆に興味深かったのが、公社の「表現」と「Controller」の分離の重要性は低いとされていることです。 例として挙げられているのは、View の Editable/Non-Editable (Readonly) の振舞いをどう実装する場合が多いか、ということですが、これを分離しようと思うと、Editable な Controller と Non-Editable な Controller を配置することになると説明されています(たぶん)。 一方で、実際としてはそんなことはせず、1 つの Controller で Editable/Non-Editable の両方の View の振舞いを実現するはずだし、表現と Controller の分離は必要になったときにすれば良いよって温度感でした。

というわけで、これからようやくおもしろい章に入りそうです (DB あたりは長かったので飽きてきていた)。

PoEAA: Repository

poeaa

パターン名からは DI 用のパターンかな??と思っておりましたが、Repository はドメイン層とデータマッピング層の中間に存在する抽象化レイヤです。

Repository は、言ってみればクエリ生成を一手に引き受け、そのクエリによって抽出されたドメインをクライアントに返却するオブジェクトです。Repository を使用するクライアントは、その背景にあるデータアクセスや、データからドメインへのマッピングを完全に Repository に任せることで、データアクセスをあたかも Collection へのアクセスのようにブラックボックス化させることができます。言い換えれば、クライアントにとっての Repository は、ドメインオブジェクトの Collection クラスと同一視できるものです。 上図は Repository の使用をシーケンスで記載したものになっていますが、クライアントは抽出条件をクライテリアとして Repository に渡すだけで、ドメインオブジェクトが得られるようになっています。その裏では、Repository がそのクライテリアから SQL を構築し、DB からデータを取得し、データからドメインオブジェクトを生成する、といったことを実行することになるでしょう。

PoEAA: Query Object

poeaa

Query Object は、それ自体を SQL に変換できるオブジェクトです。 このオブジェクトによって、SQL も、DB のスキーマ定義も抽象化され、それらの変更が実装とは分離されます。また、そもそもとして SQL に詳しくない開発者が、よりフランクに DB からのデータ抽出を記述できるようになります。

Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))

Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))

構築するのが結構難しそうだなぁとは思ったんですが、以下のようなものも query Object で備えられるものとのこと。

  • 複数の DB の方言を吸収する
  • 一度構築したクエリについては結果をキャッシュしておいて、同一のクエリを構築することになったときはキャッシュから結果を返す

とにかく複雑なパターンなので、PoEAA では以下のように言っています。

Query Objects are a pretty sophisticated pattern to put together, so most projects don’t use them if they have a handbuilt data source layer.

My inclination is that you’re almost always better off buying a tool.

PoEAA: Metadata Mapping

poeaa

Metadata Mapping は、オブジェクトとテーブルデータをマッピングさせるデザインパターンです。 データベース上のテーブルをメモリ上のオブジェクトに変換するコード、また、その逆変換のコードは、テーブル毎に似ていて非なるものなので、同じようなコードが大量生産されがちです。このパターンは、それを解決するためのものになります。

Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))

Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))

方針

Metadata Mapping には大きく分けて 2 つのパターンがあります。

  1. コード生成
  2. リフレクション

1. コード生成

コード生成はその名の通り、メタデータを入力にして、DB 上のテーブルとのマッピングを行うクラスを自動生成する方法です。この方法を採る場合、自動生成はビルドプロセスに組込まれ、かつ、その生成コードの手動編集は禁止されるべきです。 スキーマが変更になった場合、自動生成のやり直しと、生成されたコードの再デプロイが必要になります。

2. リフレクション

リフレクションはその名の通り、リフレクションを使ってマッピングを行う方法ですね。一般にマッピングの定義はファイルに記述され、それを読み込んだ上でリフレクションでマッピングの実装が行われます。 スキーマが変更になった場合は、設定ファイルの置き換えで対応が可能になります。

どのパターンにも言えることですが、Metadata Mapping を使用することにより必ずしも楽になるとは限らないし、性能的なボトルネックを生じることもあります。もちろん、実装が楽になったり、Metadata Mapping を使わないときと比べて性能面で遜色のない場合もあります。 このあたりは、都度計測していくしかないということです。

複雑に関係しあうJWTまわりの仕様を見る: JWS (JSON Web Signature)

technology oauth jwt

最近、JWT JWT 言っているような気がしますが、ぼくはこの単語を OAuth 2.0 の文脈ではじめて知りまして、それから JWT まわりの RFC に目を通し、Auth0 が無料で出している JWT Handbook を読みました。 このエントリは、JWT に関連する仕様について、ぼくなりにまとめたものです。長くなるので、何エントリかに分けて投稿します。JWK と JWA はあまり興味がないので、JWT、JWS、JWE あたりが対象となる予定です。

JWT/JWS/JWE/JWA

JWT まわりの関連仕様は結構密接に関連しあっています。ぼくが理解しているこのあたりの仕様の概観は以下のとおりです。

略称 名称 RFC 概要
JWT JSON Web Token RFC 7519 特定の「主体」に対する情報(JWT の用語で言うと “Claim”)の urf-safe な JSON 表現
JWS JSON Web Signature RFC 7515 電子署名付きメッセージの表現
JWE JSON Web Encryption RFC 7516 暗号化メッセージの表現
JWK JSON Web Key (RFC 7517 暗号鍵の JSON 表現
JWA JSON Web Algorithm RFC 7518 JWS や JWE などで使われる暗号アルゴリズム

分かりやすくいえば JWT は一種の情報のセットでしかなく、そのエンコード形式として JWS や JWE がある、ということになります (この JWS や JWE は組み合わせて使えるのでさらに分かりにくいですが…) JWT の RFC 7519 に記載があるため、よく以下のような例が JWT として出てくるのですが、ぼくの理解が正しいようなら、これは厳密には JWT (の Claim Set) を JWS の “Compact Serialization” で表現したものになります。 ただ、このエンコード結果を「JWT」として呼ぶことも多いようなので、そのあたりはコンテキストを元にして判断するしかないかなと思います。なんか Unicode を UTF-8 と呼んでいるようで、ちょっと違和感があったりもするのですが…。

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ
.
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

というわけで、今日は JWS です。 JWS の意義は、改竄されていないことを保証するメッセージ(電子署名付きメッセージ)を Web で送信するフォーマットが標準化された、ということに尽きるように考えています。今後、そういうセキュリティが要求されるメッセージを送信する機会では、積極的に使っていきたいなと思います。

JWS 概観

JWS は、電子署名付きメッセージを JSON で表現するときのフォーマットを定義しています。 JWS のメッセージは以下の 3 つで構成されます。

  1. JOSE ヘッダ
  2. JWS ペイロード
  3. JWS 署名

また、この 3 つをどのようなフォーマットで表現(エンコード)するかについて、2 パターンが仕様化されています。

  1. JWS Compact Serialization
  2. JWS JSON Serialization

上にも載せていますが、".“ で区切られたメッセージは JWS Compact Serialization の方です。 あまり市民権を獲得しているようには思えない JWS JSON Serialization の方は、pure な JSON として表現されるフォーマットで、Compact Serialization に対し、電子署名を複数持てるといった違いがあります。

JOSE ヘッダ

JOSE ヘッダは、電子署名、MAC に関する情報を保持する JSON オブジェクトです。このヘッダは、後日に書く(であろう)JWE と共通です。 ヘッダの内容は、Registered Header、Public Header、Private Header の 3 種に分けられており、署名に使うアルゴリズムを示す alg や公開鍵の在処を示す jku (JWK Set URL) などは Registered Header に該当し、RFC 上で仕様化されています。 Public Header は「定義していいけど名前の衝突を避けるために IANA に登録しろよ」というもの、Private Header は「衝突するかもしれないから注意しろよ」ってヤツで、アプリケーションの要件によって定義していくタイプのものです。

シンプルかつ JWT の文脈で良く出てくるのは以下のようなヘッダでしょうか。

{"typ":"JWT",
 "alg":"HS256"}

JWS ペイロード

大切にしたいメッセージ本体。なんでも良いです。JWS の目的は、このペイロードの改竄を防止することですね。

JWS 署名

JWS 署名は、JOSE ヘッダ、JWS ペイロードから計算されます。 JOSE ヘッダの alg にて署名を計算するアルゴリズムが規定されますが、アルゴリズムのインプットとなるのは、以下の式になります。まぁ何となく分かりますね。

ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload))

フォーマット

JWS の表現方法として、2 種のシリアライゼーションフォーマットが定義されています。 JWT (JWS) はトークンとして使用されることが多いのですが、このように HTTP のヘッダや URI 上で表現される場合は、JWS Compact Serialization を使用します。実用例では、こちらしか見たことがありません…。 もう 1 つは、JSON で表現するという JWS JSON Serialization です。

JWS Compact Serialization

JWS Compact Serialization では、

  1. JOSE ヘッダ
  2. JWS ペイロード
  3. JWS 署名

のそれぞれをエンコードしたものを “.” で区切って表現します。 RFC からそのまま引っ張ってくると、以下の表現になります。

BASE64URL(UTF8(JWS Protected Header)) || '.' ||
BASE64URL(JWS Payload) || '.' ||
BASE64URL(JWS Signature)

JWS JSON Serialization

こちらは、URL-Safe でもなければコンパクトでもないので、誰が使うのかってかんじが個人的にしてしまいますが、JWS を JSON として表現します。 ぼくの感じたメリットは 2 点。

  1. 署名対象のヘッダと、そうでないヘッダを分けることができる
  2. 1 つの JWS のメッセージの中に、複数の署名を入れることができる。
{
 "payload":"<payload contents>",
 "signatures":[
  {"protected":"<integrity-protected header 1 contents>",
   "header":<non-integrity-protected header 1 contents>,
   "signature":"<signature 1 contents>"},
  ...
  {"protected":"<integrity-protected header N contents>",
   "header":<non-integrity-protected header N contents>,
   "signature":"<signature N contents>"}]
}

じつはこのフォーマットにはもう 1 つ種類があり、署名が 1 つのみの場合は Flattened JWS JSON Serialization を使えます。

{
 "payload":"<payload contents>",
 "protected":"<integrity-protected header contents>",
 "header":<non-integrity-protected header contents>,
 "signature":"<signature contents>"
}