アクセシビリティに興味を持ち始めたきっかけ

アクセシビリティの琴線に触れるいくつかのアプローチ の記事を読んで、自分がアクセシビリティに興味を持ち始めたきっかけについて書き残しておきたくなったので書く。

自分の場合はアンチャーテッドというゲームのメイキングインタビュー動画をみたのが、アクセシビリティを意識するようになったきっかけになっている。

5分程度の動画なのでまずみてほしいのだけど、一部暴力的なゲーム内シーンもあるのでこういうのが大丈夫な人は再生ボタンを押してほしい。

www.youtube.com

内容を要約すると以下のような動画になっている。

  • アンチャーテッド4というゲームは多くの人にゲームを楽しんでもらえるようにアクセシビリティに取り組んでいる
  • これまでのシリーズではボタンを連打するなどの複雑な操作が必要な場面で健常者の助けなしではクリアできなかったが、障がいを抱えたゲーマーの話をきっかけにアクセシビリティに取り組んだ
  • 過去作からのアクセシビリティ機能を拡大してボタン連打が必要なものを長押しに出来るようにしたり、色覚によって区別できない色を使っている部分を変更したりした

自分はこの動画をみて、かなり気づかされることが多いなと思った。

自分が出来ることが出来ない人がいること、出来ないことを出来るようにする実現の仕方、ゲームの操作が出来ないことはもうそのゲームを楽しめないということ。

出来ない人がいるなんてちょっと考えてみれば当然だったけれど、全然意識したことがなかった。

特に冒頭のインタビューが強く印象に残っている*1

開発者に気づいてほしい ぼくらにはゲームが単なる娯楽以上のものだと 障がいをかかえているとう憂うつさを忘れさせてくれるんだ 交流の機会も与えてくれる 外見で判断されるんじゃなく ゲーム内での行動やその結果だけで判断される機会だ

印象に残ったのは当時の自分の立場ともリンクしていたからもあると思う。

自分は当時*2Web小説サイトの開発に関わっていて、ここではユーザーさんが小説を書いて自分の考えた物語を表現したり、読んでその世界に浸ったり、感想を述べて交流したりしている。 これはインタビューで言われていた ゲーム内での行動やその結果だけで判断される機会 と同じだし、サイトが使えないことはこの機会がないことになってしまい、すごく残念な気持ちになった。

このように自分に置き換えてみると、アクセシビリティに対して「あ、これって大事なことだ」と素直に思い、以来アクセシビリティについて興味を持ち始めた。

琴線に触れるいくつかのアプローチでいう「人権」や「福祉」に近いきっかけだったと思う。

もちろんこれはゲームの販促動画なので、エモい発言や見せ方になっていると思う。 動画内では語られていないけど、法律などの要請もあった可能性もある。 けれどもおかしなことは言っていないし、タイミングもあっただろうけど自分が意識するきっかけになってくれた。その意味でとてもいいインタビュー動画だと思う。

これまで普段WebサービスのUIを実装する時はブラウザなどのユーザーの環境の違いを考えて動くように実装することはあっても、そもそもそのUIを使えない人がいるところまでは正直想像できていなかった*3。 やっぱりアプリケーションエンジニアとして多くの人が使えるサービスを作っていきたいなと思うし、アクセシビリティは良いサービスを作る技術的な意味でも自然に受け入れられた考えだったし、面白いとも感じた。

恐らくこの先どんなものを作る場面でも、それこそWeb/Appアクセシビリティに限らず全ての人が利用できることを意識だろうから、この気づき方はよかったと感じている。何をするにしてもこの考えはもっていたいと思う。

最後に、アンチャーテッドと同じスタジオが制作したThe Last of Us Part IIを全盲の人がクリアした記事を貼っておく。 このゲームも自分もプレイしていたゲームで、目が見える自分でもちょっとやっかいだなと感じる敵がいたのに、それを目が見えなくてもクリアできるのかと驚いたことが強い印象だった。

automaton-media.com

*1:この人はDAGERSystemというゲームのアクセシビリティ関するメディアの編集長で、アンチャーテッドを開発している会社のノーティドッグアクセシビリティについて話した人。

*2:2021年現在も

*3:環境の違いを想像し切れていなかったという話ではある

Webブラウザセキュリティ読んだ

年始に話題になったWebブラウザセキュリティの本をようやく読んだ。

Webブラウザセキュリティ ― Webアプリケーションの安全性を支える仕組みを整理するwww.lambdanote.com

なんとなく知っているつもり・名前は聞いたことあるのような概念や仕様を、それが作られた背景から丁寧に説明されていてとてもわかりやすかった。 特にOriginやCSPの章では「そもそもどういう攻撃から守ろうとしているのか」「その攻撃に関する基本的な知識は何か」から説明しているので、頭にすっと入ってくる。

デモ環境を Docker 上で試せるのもよくて、サクっと立ち上げてブラウザで動作を確かめられるのはこれまでの手元で試す系のものよりも体験がよかった。

著者とレビュアーの対談記事も出ているので、そちらも合せて読んでみると良さそう。読みながら感じていた、Webセキュリティの過渡期感と攻撃を受けないように制約をかけていきつつも後方互換性を保つ努力について語られていてよかった。

本の内容とは関係ないけど、紙の本とPDFを行き来するのは便利だった。ラムダノートのサイトで買うと紙書籍と一緒にPDFもダウンロードできて、それをiPadに入れて気分によって行ったり来たりしながら読み進めていた。

技術書の類は基本紙で読みたいのだけど、シュッとこの単語をググりたいとか、デモ試すときにページを保ちながらやるのややこしいなとなったときに電子で読めるのはとても便利だった。

以下箇条書き感想

  • CSP改めてムズいなと思った
    • 既存の挙動を実現できつつ制約はかけたいのはわかりつつも、制約の掛け方色々ありすぎて笑ってしまった
  • というかセキュリティ対策をちゃんとやるというのがそもそもムズい
  • セキュリティの問題があるWebの機能を塞ごうと思っても、それを塞ぐことによってこれまでのWebが壊れるので困るというのがよくわかる
  • 引用元の論文やブログの数が多くてすごい

Emacsのlsp-modeが遅いときはlsp-doctorを見てみるといい

emacs-lsp.github.io

タイトルと↑のリンクでFAなのだけれど、EmacsのLSPクライアントであるlsp-modeで補完などの動作が遅いなと感じたときは M-x lsp-doctor とやると遅い原因を列挙してくれる。

Emacsのデフォルト設定値ではlsp-modeの利用に最適ではない場合があるのは、言われてみればその通りなのだけど完全に失念していた。 lsp-mode側でよしなに書き換えてしまってもいいのに……と思ったけど、それをやるのは流石に思想の違いがありそう。

自分の場合はGCが発生するメモリの閾値gc-cons-threshold と、一度の読み取り操作でサブプロセスから何バイト読み取るかの read-process-output-max の値を調節すると、補完候補が出る速度が体感でわかるほど早くなった。 元々候補が出るのに一瞬ひっかかるなと感じる程だったので、明らかに体験が良くなった。

lsp-mode 遅いなと感じている時は試してみるとよさそう。

※ 追記 v7.0 までは lsp-diagnose って名前だったらしい

github.com

ページのコンテンツから離れたタイミングのブラウザイベントの選び方

これは はてなエンジニアAdvent Calendar 2020 1日目のエントリーです。

ブラウザに何か表示させるアプリケーションを作っている人は、ブラウザのAPIやイベントの発火タイミングについて調べる機会が年に何度かあると思います。今回はそんな調査の一つを紹介です。

知りたいこと

ユーザーがページから離れたタイミングを取れるイベントが知りたい。

  • ユーザーがページから離れたら際に行いたい処理があったので、契機となるイベントがほしい
  • ここでは「ページから離れた = ページのコンテンツを見ていないと想定される」とする。具体的には以下のようなタイミング
    • ページ遷移
    • タブ移動
    • ページ破棄 (タブ/ブラウザを閉じる)
    • 画面がロックされる
    • 別のアプリケーションに切り替える (PCなら画面の最小化/モバイルならアプリ切り替え)
  • beforeunloadイベントでタブやブラウザ自体を閉じる際に処理を挟めるのは知っていたが、タブの切り替えやPC/モバイルの画面がロックされた場合にも処理を行いたいので、何を使えばいいのか知りたい

結論

  • visibilitychangeイベントで「ページから離れた」のユースケース全てを満せるので、このイベントを契機に処理を行う
  • Safariではバグがあるので、一部pagehideイベントと合せて実現する
  • (未検証)IEではページ遷移時の処理が途中で打ち切られているような挙動をしているので、IEをサポートするのならbeforeunloadも合せて実現する

以下この結論に至った過程を紹介。

調査と検討過程

基本方針

改めて対応したいことは「ページから離れた = ページのコンテンツを見ていないと想定される」タイミングで発火されるイベントが何かということ。

このケースは全てPage Visibility APIで対応できる。

developer.mozilla.org

visibilitychangeイベントが発火し、 visibilityState === 'hidden' であれば「ページから離れた」と判断できるので、このタイミングで処理を行えば良い。 Can I Useを見る限り主要ブラウザではサポートされているので、気にせず使っていけば良さそう。

ただしSafariにバグがある。

Safari向け対応

Can I UseのSafariの注釈[3]を読むと、こう書いてある。

https://caniuse.com/mdn-api_document_visibilitychange_event

Doesn't fire the visibilitychange event when navigating away from a document, so also include code to check for the pagehide event (which does fire for that case in all current browsers)

(意訳) visibilitychangeがページ遷移時に発火しないので、このタイミングではpagehideを利用する必要がある

そんな……。

ページ遷移時だけを考えるならpagehideのみを使えばよいが、今回はページから離れた時全般なので、visibilitychangeとpagehideのそれぞれで処理を行う必要がある。

このときvisibilitychangeとpagehideの両方に処理を登録すると、ページ遷移時に2回処理が実行されてしまうので、Safariのみpagehideイベントに行いたい処理を登録する必要がある*1

このSafariのバグについて、WebKit Bugzilla見てみると 2020/09/25 時点で更新がある。もしかしたら近いリリースでの修正が期待できるかもしれない。

IEの挙動について

IEではページ遷移時にvisibilitychangeやpagehideのイベントが発火はしているものの、処理が終わり切らず途中で終わっているような挙動をしているように見えるため、代替手段が必要になる。挙動は深く追ってはいないものの、beforeunloadなら処理を最後まで終了させているようなので、IEをサポートする必要があるならこれを利用する必要もあるだろう*2

以上をまとめると以下のようなコードになる。

const doSomething = () => { /* ページのコンテンツから離れた際の処理 */ };

document.addEventLisnter('visibilitychange', () => {
  const state = document.visibilityState;
  if (state === 'hidden') {
    doSomething();
  }
});

if (isSafari()) {
  window.addEventListener('pagehide', () => {
    doSomething();
  });
}

if (isIE()) {
  window.addEventListener('beforeunload', () => {
    doSomething();
  });
}

調査過程で得た情報

調査の過程で得た、他にも応用できそうな情報を上げておく。

Page Lifecycle API

developers.google.com

ページが開かれてから閉じるまでの状態やイベントの遷移をまとめたもの。

これを読んでおけばページの状態にまつわる処理を書きたくなった時にサッと参照出来てお得。ただしPage Lifecycle API自体はChromeでしか実装されていなさそうなので、あくまで参考程度に止めた方がよさそう。

ライフサイクルをまとめた図を見ると、モバイルのネイティブアプリのライフサイクルと似たイメージなのかなとも思ったりする。

またbeforeunloadで何か処理を行うのは、ページ離脱時のユーザー体験を損ねる可能性があるので、保存前の変更を警告するため だけ に使うべきなど、Legacy Lifecycle APIの節で言及されており、勉強になる。

デバッグ便利情報

event-logger.glitch.me

WebKit BugzillaのIssueコメントにあった、動作確認用のglitch。visibilitychangeやpageshow/hideの発火毎にログを表示してくれるもので、今回のAPIの挙動理解の助けになった。

また実装がデバッグの手段の一つの参考になる。素朴なイベントの動作確認方法だと、イベント発火時にconsole.debugでコンソールに出力させるのがあるけど、今回は発火のタイミングがタブやブラウザを閉じるまで含まれるのでコンソールから消えてしまう。このglitchではローカルストレージにイベント発火のログを残しており、タブやブラウザを閉じても消えないようにしている。

ローカルストレージに残す発想は考えてみたら当たり前ではあるが、使ったことの無い手法なので参考になる。

まとめ

ページのコンテンツから離れたタイミングのイベントの選び方とその検討過程について紹介した。Page Visibility APIやライフサイクルの図は覚えておくと便利なタイミングがありそう。

ほしいブラウザのAPIを調べるのが最初だったけれど、ページのライフサイクルだったりデバッグテクニックまで知れてお得な題材だった。

明日は id:nabeop さんです!

*1:ブラウザによる条件分岐を避けたいのなら、行いたい処理をべき等にしたり、処理が実行されたらフラグを立て1度しか実行されないようにするなども考えられる。

*2:同僚の id:koudenpa さんが挙動回りを確認してくれた。

IntelliJ を使って Pull Request をレビューする

言いたいことはタイトルが全て。

IntelliJ には GitHub と連携して Issue や Pull Request を見れる機能があり、しっかりコードレビューする際は GitHub のサイト上ではなく IntelliJ 上で行うようにしている。この IntelliJ でレビューを行うことはサイト上で行うよりも体験が良く、便利に思っていた。使い始めた頃は Pull Request の一覧やコメントを書く程度だったが、先日のバージョン2020.2のアップデートでついにレビュー関連の機能が完全にサポートされたので、これを機に IntelliJ 上でレビューを行う体験の何が良いかについて紹介したい。

blog.jetbrains.com

便利だと感じている点は4つ。以下説明していく。

  • 手元に Checkout せずに済むこと
  • 定義/参照ジャンプなどの IntelliJ の機能が使えること
  • IntelliJ の 差分表示が見やすい
  • IntelliJ上でレビュー作業の全てが完結すること

手元に Checkout せずに済むこと

Checkout せずに済むことは言葉の通りで、GitHub 上で見える差分以上に見たくなった時に手元に Checkout する場面はあると思う。この時始めから IntelliJ で Pull Request を見ていれば Checkout のコマンドを打つひと手間無く差分の周辺コードを見に行ける。

最近は GitHub CLI で簡単に Checkout できるようになっているので、この点はあまり推す点でもなくなってきているのかもしれない*1

定義/参照ジャンプなどの IntelliJ の機能が使えること

一押しはこれ。IntelliJ 上で差分を見れることで、エディタ上で未使用変数・スペルミスのハイライト、コードジャンプといった機能を使いコードを見ていけるのが便利に感じている。 GitHub 上だけでレビューしていると未使用変数やスペルミスは見落としがちで、この点は非常に助かっている。コードジャンプも GitHub 上だとブラウザの検索でメソッド名を探すといった頑張りをしなければいけなかったことが、普段のコードを読むのと同じ体験で見ていけるのは大きなメリットだと思う。

ここに書いたメリットを GitHub 上でも得られるようになってきている*2*3が、普段仕事で書いている Perl はこれらのメリットが得られにくい。この点 IntelliJPerl プラグインは優秀で、ここで書いた機能は全て提供されている。詳しくは以前書いたエントリを参照してもらいたい。

benevolent0505.hatenablog.com

差分表示が見やすい

機能の話ではあるが差分表示の見やすさは特に紹介したい。個人的に GitHub の差分表示はもっとも見やすいとは言いづらく、もっと良くなってほしいと思う点だった。 IntelliJ の差分表示は見やすく、どこに何が追加・削除されたのか、差分の周辺はどうなっているのかが見やすいと感じている。文章で伝えにくい点なので、ヘルプは画像検索の結果を見てもらいたい。

IntelliJ上でレビュー作業の全てが完結すること

Checkout の話にも通じるが、ブラウザとエディタの行き来が無くなり IntelliJ だけでレビュー作業の全てが完結できるのは、開発の効率化という面で大きなメリットだと思う。 この話は単に手間が減ることだけでなく IntelliJ (IDE) が開発の起点になるということ だと思う。別に IntelliJ が無くてもレビューや他の開発は出来るが、IntelliJ にまとめ上げることで作業を集中させ、開発を行いやすくできるのではないかと思う。

IDE とはなんなのかという話については別の方がまとめており、なるほどなと思ったのでそちらを紹介しておく。

irof.hateblo.jp

まとめ

IntelliJ で Pull Request をコードレビューするのが便利だと思う点について書いた。普段使っているツール上でレビューできる良さはやってみないとイメージしづらいものも多いと思うので、既に IntelliJ を使っている人は試してみると良いと思う *4。 また IDE が開発の起点になることに軽く触れた。元々 IntelliJ をデフォルトでコーディング支援の整ったエディタ程度にしか思っていなかったが、レビュー関連の機能を使ってからは IntelliJIDE であるということを意識するようになった。IDE は開発を行いやすくするツールであることは今後も意識していきたいと思う。

cspell でレポジトリの typo 判定一覧を出力する

Pull Request のレビューなどで typo を指摘することがあるだろうが、typo の指摘をしてもマイナスをゼロにするレビューコメントが一つ増えるだけであまり嬉しくない。

こういった無用なレビューを避けるために手元のエディタでスペルチェッカーが動かしている場合も多いと思う。最近なら多くのチームメンバーが VSCode を使っていて、レポジトリに .vscode を追加するだけで推奨拡張機能を皆のエディタに入れられるようになったので大変便利*1

Code Spell Checker - Visual Studio Marketplace

しかしこういったスペルチェッカーは造語や辞書に登録されていない単語を検知してしまうので、我々にとって誤検知であることが多い。 Code Spell Checker は設定ファイルに allowlist を記述でき、typo 判定してほしくないキーワードを登録できる。 「よし、これで導入だ」といきたいところだが、せっかくならキーワードの登録も同時に行ってしまいたい。その時に試したやり方を残しておく。

cspell を使う

Code Spell Checker は内部で cspell というライブラリを使っていて、npm でコマンドラインツールとしても配布されている。元々この拡張のために作ったツールをコマンドラインでも使えるように提供しているらしい。

www.npmjs.com

使い方は素朴でディレクトリを指定したりファイル名を直接指定すれば OK 。今回は一度単語リストが出せれば良いので npx 経由で使ってみた。

$ npx cspell <filename>

あとはお好みに合せてファイル名を指定すれば完了。 git レポジトリだったら git ls-files とかで拡張子を指定しつつファイル一覧を取得すると楽だと思う。例えば Perl だったらこんな感じになる。

#!/bin/sh

files=$(git ls-files '*.pm' '*.pl' '*.t')
exec npx --quiet cspell --wordsOnly --unique --no-summary $files

単語の一覧だけ出したいので --wordsOnly--no-summary, --unique を指定した。このままだと npx の出力も出てしまうので、 --quiet を付けると良い。

「よしよし、これで」と思ったが、普段触っているレポジトリで試してみると結構な数の語が検出されてしまい、全部 allowlist に載せるのは厳しい。もちろん typo がたくさんあるわけではなくて、 subtest などのライブラリ特有のキーワードが typo 判定されてしまったため。頻出するキーワードが typo 判定されてたらイライラしてコードの質が下がることになりかねないと思う()。

そこで作戦を変えて、頻出語順に出力し上位20件程度をリストに加えるやり方にした。

#!/bin/sh

files=$(git ls-files '*.pm' '*.pl' '*.t')
exec npx --quiet cspell --wordsOnly --no-summary $files | sort | uniq -c | sort -nr

--unique を指定するのは止め、昔ながらの UNIX コマンドの組み合わせで頻出語を出すようにした。これで allowlist に登録すると良いキーワードを判別しやすく、理由を持って追加できるようになった。

実例

試しにインターン課題のサンプルアプリケーション go-Intern-Bookmark でリストを出してみる。

~/repos/src/github.com/hatena/go-Intern-Bookmark
$ ./spellcheck.sh
  43 hatena
  13 graphql
  12 sqlx
   7 stretchr
   7 signup
   6 signin
   6 csrf
   4 tmpl
   4 jmoiron
   4 bcrypt
   4 Tmpl
   3 nosurf
   3 graphiql
   3 Signup
   3 Signin
   3 Queryx
   3 Graphql
   2 entrys
   2 attatch
   1 unmatching
   1 justinas
   1 fmsec
   1 dimfeld
   1 UUID
   1 CSRF

コード量が少ないためかおびただしい件数が検出されることはなかった。 GraphQL みたいな技術用語を検出するのは結構予想通りだが Hatena はなるほどという気持ちになった。 Go だとレポジトリ名がモジュール名に含められるので、だいたいこうなってしまいそう。

まとめ

cspell でレポジトリの typo 判定一覧を出す方法を書いた。 cspell 意外に便利そうで、 README にあるように Git の commit-hook や CI でチェックするようにしても効果的だと思う。

参考

*1:ただ僕はIntelliJEmacsを使っている

君はあのコンマ演算子を知っているか?

僕は知らなかったです。

Perlで遭遇

次のようなPerlのコードを読んでいるときに思ってなかった挙動をした。

my $x = ('a', 'b');
$x  # => ??

始め以下のような想定をして $x には 'a' が入るのだと思っていた。

  1. 左辺がスカラコンテキストなので、右辺もスカラコンテキストになる
  2. 配列の区切りの最初の値が入り $x には 'a' が入る
  3. 'b' はどの変数にも入らず捨てられる

しかし実行してみると $x には 'b' が入る。

my $x = ('a', 'b');
$x  # => 'b'

これはどういうことかと思い調べてみると、どうやらコンマ演算子というものがあるらしい。perldocを引いてみると

perldoc.jp

二項演算子の "," はコンマ演算子です。 スカラコンテキストではその左引数を評価し、その値を捨てて、 それから右引数を評価し、その値を返します。 これはちょうど、C のコンマ演算子と同じです。 リストコンテキストでは、これは単にリスト引数の区切り文字で、 双方の引数をそのリストに挿入する働きがあります。 これらの引数も左から右に評価されます。

そんなのあるの……。つまりさっきのコードは以下のような流れで 'b' が入る。

  1. 左辺がスカラコンテキストなので、右辺もスカラコンテキストになる
  2. 'a', 'b',二項演算子コンマ演算子として働く
  3. そのため 'a' を評価し値を捨て、 'b' を評価し値を返す
  4. そして $x には 'b' が入る

という流れ。

恥ずかしながら2年弱Perlを書いててコンマ演算子のことは初めて知った……。あまりこういうコードを書く機会は無いだろうけどミスってこのようなコードを書いてしまった時は意図しないハマりポイントになりそうだなと思った。

ちょっと待てよ……

Perlのハマりポイントを知ったところで、さっきのperldocの文を思い出してみると……。

これはちょうど、C のコンマ演算子と同じです。

ということはC言語やそれ以外の言語にもあるということではないだろうか?そう思って雑にググってみるとWikipediaがヒットした。

コンマ演算子 - Wikipedia

CやC++をめきめき書いたことは無いのでなるほど〜といった感想程度だったけど、次のコード例はちょっと面白い。

int a=1, b=2, c=3, i;   // このコンマは演算子としてではなくセパレータとして作用する
i = (a += 2, a + b);    // aに2を加算した後、a+b = 3+2 をiへ代入する                                    ... a=3, b=2, c=3, i=5

ちょっとしたコード短縮テクニックなのかなと思ったけど、Twitterで調べてみたら定期的にツイートがある。CやC++ということは競技プログラミングの界隈だと普通に知られたテクニックだったりするのだろうか?

コンマ演算子 - Twitter Search

お前もか〜〜

見つけてしまった瞬間「マジかよ……」と思ってしまったのだけれ、JavaScriptにもコンマ演算子は存在していた。雰囲気は同じ感じで詳細はMDNを見ればよさそう。

developer.mozilla.org

Minifierとかでコードが圧縮された後だとこんな感じのコードが生成されているのかもしれないなと思った。

終わりに

知らない演算子を発見するの結構新鮮な気分だった。PerlJavaScriptも仕事で書いているけど、言語の仕様を上から下までさらって覚えるということはしたことないので他にもこういった発見は今後もあるんだろうなと思った。 (あとJavaScriptオチ担当として優秀な気がする)