My Browser Profile Chooser 3.0 released!

My Browser Profile Chooserが3.0になった

1.x, 2.xではZshスクリプトだったが、Rubyスクリプトに変更され、プロファイル設定は2.xのZsh関数として定義する形からYAMLで書く形になった。

3.xでの非互換変更を行った理由だが、設定を書くのが面倒だったからである。 互換性のため、2.x系も別のブランチとして残っている。

コード的にも簡単すぎてあまり見るべきところがないので、今回はリリース報告だけ。

webUIデザイン考

私はかなり前からデザインの仕事もしているし、評判も上々。 日頃デザインの勉強もしているし、自分でも悪くないと思っている。

けれど、デザインに一家言あるみたいなタイプの人からは評判が悪いし、そもそも私のウェブデザインはウェブデザインの常識に則っていない。

とはいえ、私のほうが正しいと主張できるだけの根拠はちゃんとある。 なにより、「本当に正しくデータを取ったか?」である。

なお、ここで出てくる様々な実験データは、なにかから引用しているわけではなく、 私が自分で実験・聴取しているものである。

ほんとかよ、それ

直感的であるよりも経験的である

「ひと目見てわかることよりも、慣例に則っていることのほうが大事」 という主張なのだけど。

絶対ウソだ。

デザインする側は全く分かっていないけれど、 ハンバーガーメニューってみんな知らないよ

ハンバーガーメニューを理解できるのはそれなりにコンピュータに通じている人であって、 私が話している限りだとスマホネイティブな世代の人を含め、ハンバーガーメニューは無視する人のほうが圧倒的に多く、 「ハンバーガーメニュー」という言葉はまず知らないし、それがメニューボタンだという認識もない。

実際、私が手がけたサイトのログをみる限り、

  • 他のナビゲーション手段があるかどうかに関わらず、ハンバーガーメニューはほぼ押されていない
  • ハンバーガーメニュー経由でしかアクセスできないようになっているものには人がこない
  • 常にハンバーガーメニュー経由でナビゲーションするようになっていると離脱率がものすごく上がる

なので、ハンバーガーメニューはごく一部のわかっている人だけのものだという認識で良いはずだ。

動的表示

HTML5だ、動的表示だ、JQueryだみたいな話は当たり前のようにされるけど。

ユーザーは望んでないぞ、それ。

これに関しては明確な不満が聞かれることは稀だが、「重い」という形での不満になったり、あるいはちゃんと説明すると(容量が大きいことによってどのような影響になるのかといった話)「それはいや」という回答が返ってくる。

ごてごてと重くして、CDNで速くするくらいなら、最初から軽くしておくべきだ。

アニメーションで取られる時間も明確にUXを悪化させており、実際にその仕様が異なるページを体験してもらう実験では、非常に速いアニメーションが最も好まれ、アニメーションを認識できる程度のアニメーションがあるくらいならば一瞬で実行されるほうがずっと良い、ということがわかる。

遅延表示

記事の全文を表示せず、ユーザーアクション、スクロールに従って読み込むのは必須要求であるように言われるのだが、聴取してみると コンピュータの熟達度によらず極めて評判は悪い。

これは、スクロールの判定の問題による。

まずPCではEndキーを押してのスクロールに対応できない。そもそもEndが末尾にならない。 実装方法によっては、PgUp/PgDnのスクロールの判定をしないから、私のようにキーボードでナビゲーションしている人をはじくことになる。

さらにスマートフォンのナビゲーションでも、弾いたり反射させる場合に対応できない。

そもそも、大抵の遅延ロードが、私が普通に読んでいても途中でなんども読むのを止めさせられることになる。 「続きを読む」も何の節約にもならないので大嫌いだ。

この話は人にすると多くの場合強い共感を得られる。 極めて劣悪な体験である。

ちなみに、私は遅延表示するサイトはよほどがない限り、読むのをやめる。

実験と聴取と経験

ハンバーガーメニューは誰も使わない

前述のようにハンバーガーメニューは誰も押さない。

ちゃんと「アイコン+ “メニュー”の文字」になっていると押してもらえる。

英語だと使わない

“MENU”とかいう英語ですらも、英語で書くと使ってもらえなくなる。 ところが、なぜか“HOME”だけは英語で書いても全く影響がない。

back to HOMEに関しては、「トップページ」と書くよりも「HOME」と書いたほうが理解されやすい。

「HOME」と「ホーム」は誤差の範囲。

最近のソシャゲのUIはこのあたりよくわかってる。

アイコンだけだとやはり使わない

UX面で見ればラベルは絶対必要。デザイン的にはイヤ。

アイコンだけでがんばる場合は、それを押す必然性がないといけない。 これはハンバーガーメニューでも同じだし、ハンバーガーメニューはアイコンのデザイン自体が直感的じゃないので、よりハードルは高い。

SEOより情報価値

最近はGoogleがSEOに屈した感があるが、結局情報価値がある内容を書いているとその情報を必要とする人はその情報を頼るしかないので、あまりSEOスペシャルみたいなものは必要ないと考えている。

内容さえあれば、変なことするよりも、人間的にも機械的にも意味がきちんと伝わるように書くのが長期的に見て色々と得だ。

内容が重複する場合は基本的に情報価値はないとみなされるが、もちろんより適切にまとまっているなど情報の扱い方によってもその価値は変わってくる。

結局、SEOのことを気にする時間があるならば、少しでも良い記事を書くために心を砕くことに時間を使うべきだと思う。

明朝体とウェブフォント

「長文には明朝体が良い」というのは、ウェブには全然浸透していない、出版関係の常識だけれど、これに関しては私は特別には同意しない。ゴシック体だから長文が辛い、ということもない、というのが私の意見だし、むしろウェブではみんなゴシック体を見慣れてるからゴシック体のほうがいいんじゃないかとすら思う。

ただ、文章に対する没入という観点からいうと明朝体のほうが良いようだ。

実際に、難しい長文を読むにあたって、どのような書体が好ましいかという実験をしたところ、最も良いのはUDアポロであり、アポロでもフォークでもタイポスでもスキップでもいいからアンチックでしょ、ということになる。 ちなみに、ロゴたいぷゴシックは長文だとやや読みにくい。フリーフォントなら源暎ラテミンの評判が良い。

私はアポロの製品版をまだ持っていないので、今のところこの文章を書くのにはフォークを使っている(でも、ライセンス期限が近づいている…)が、フォークは実はそんなに読みやすくない(アンチックの中では)。とにかくアポロが読みやすい。次いで源暎ラテミン、あるいはラテゴ。元陽逆アンチックも読みやすいと評判。

こうしたゴシック体と明朝体の中間のフォントが最も読みやすく感じられる、というのは、まんま「明朝体のほうが読みやすいと言われればそうだし、ゴシック体が読みづらいと言われてもそうでもない」という感覚に直結しているのだと思う。

より漫画的なアンチック体(例えば源暎アンチック)もかなり読みやすい。そういうものなんだな、と思ったりする。

だから、可能ならウェブだってアンチック体で表示したい。 だが、現実には難しい。

そもそも汎用の指定がserif, sans-serif, monospace, fantasy, cursiveの5つしかない。 せめて丸ゴシックを指定できるようにしてほしいし、アンチック体を指定するなんて夢のまた夢だ。

システムフォントを指定することがどれだけバカバカしいかという話は、多分Chienomi読者なら耳タコだろうし、そんなことは絶対しないと私は信じている。

しかし日本語ウェブフォントなんていうのは死すべしである。大きくても100kBもない欧文フォントなら、まぁちょっと大きい画像1枚くらいか、許そうとなるが、源暎ラテミンなんて9MBもある。問答無用で動画ねじ込まれるようなもんである。通信容量は有料のものだし、人の通信容量を貪るんじゃない、となる。

だから制作者がコントロールできる部分ではないが、どちらかといえば長文読みの場合は明朝体のほうが良いのではないだろうか。 Androidでは明朝体が出ないということも踏まえた上で。

リーダービュー

リーディングという意味ではリーダービューはかなり理想的な状態であるように思われる。

ウェブデザイナたちがこれがユーザービリティだとごてごてしたデザインを押し付けた結果、CSSを除去し、本文だけを抽出する機能がブラウザに搭載されたというのは本当に笑える話だが。

しかし、リーダービューは私が聞き取った限りで使用しているという人を見つけることはできなかった。 「知っている」という人は3割強。恐らくこの値は全体比からすればかなり高い。

リーダービューを前提にすることができれば、ウェブデザインは可読性よりもナビゲーションのしやすさに寄せることができるが、そうではないのでリーダービューのような可読性を目指すことになるだろう。

ちなみに、私のサイト(PureBuilder Simplyで書かれているもの)はいずれも綺麗に書いてあるのでリーダービューが効く場合は非常に読みやすくなるが、「はるかのおはなしのおはなし」を除けば元がリーダービューに近い見た目をしているため、効果はあまりない。 一方、このChienomiはWordPressなので、リーダービューを使うとだいぶゴミを感じるが、余計なものが消えて読みやすくなる。

my designs

Mimir Yokohama

Mimir Yokohamaのデザイン自体は、もともとがWordPressページであり、なおかつWordPressのデザインを維持することからスタートしているため、基本的な形式はWordPressのデザインに準じている。

中央寄せコンテンツコンテナのレスポンシブ2カラムというのは、典型的なブログデザインといっていいだろう。

ただし、現在はしっかりと私のウェブサイトとしての工夫も盛り込まれたものだ。

Mimir Yokohamaのウェブサイトは、リテラシーが低い人が読む、という前提があるため、ユーザーに何かをさせるということは回避する方向である。知識がなく受動的であっても使えるようにという工夫だ。

基本的なところでは、Mimir Yokohamaは「経験則によってナビゲーションできるようにすべき」という主張を受け入れたものになっている。 だが、構造的スマートさよりもアクセシビリティを優先し、同じナビゲーションが複数配置される構造だ。

ハンバーガーメニューの中身はメニューとTOCだが、これはサイドカラムにも搭載されている。重複させることでその人の直感がどちらに属してもカバーできるようにしている。 では重複は2箇所かというと、実は3箇所である。TOCは記事よりも手前にも存在し、ナローモードでは下に行くサイドカラムではなく、記事手前に表示されるようになっている。

ロゴクリックでのback to homeや、破線アンダーラインでの辞書機能、lightboxなどは経験則的機能だ。 その人のブラウジング経験によってはより便利に使えるわけである。

その他、本文を含めてとても説明的。 どんなに丁寧に書いても読まない人は読まないのだが、デザイン的にはちゃんと説明されるべきだ。 そういえば都営地下鉄の駅の表示に情報が欠落していて、結局わざわざ説明書きの張り紙をした、なんて話もあった。

はるかのおはなしのおはなし

はるかのおはなしのおはなしはウェブ縦書きのサイトである。 世間的には、ほぼエロゲーの話をするサイトとして扱われている。

これはいくつかの実験を含んでおり、縦書きはその一部である。

もうひとつ大きいのはスケーラブルフォントサイズだろう。 文字サイズがウィンドウサイズに依存しており、ウィンドウを大きくすることで大きな表示で読めるようになっている。

ただ、ブラウザの縦書き実装が相当にあまりて、ウィンドウリサイズにちゃんと対応しておらず、リサイズ時はリロードする必要があるとか、場合によってはカラム境界がおかしいなどの問題がある。 Android版Firefoxに至っては、以前はちゃんと表示できていたのに、今は完全に崩壊してしまっている

正直なところ、私はあまり読みやすいとは思っていない。多分、JavaScriptでスクロールディレクションを変換し、行方向を20emなり30emなりに制限するほうが読みやすい。そして縦書きが別に読みやすくはないというのも感じてしまう。 これはそもそもブラウザの縦書きエクスペリエンスがだいぶ悪いということに起因している。

リーダービューにすると横書きにできるのですごく読みやすくなる。

なるべく色々がんばろうとはしていて、例えば

  • 小説のように読ませたいというのがあるので、ナビゲーションは意識に入らないようになっている。逆にナビゲーションしたいときに困るかもしれないが
  • 電子書籍のような「めくり」に対応
  • 日本語縦書きプロポーショナルメトリクスを採用

と、技術的にものすごくアグレッシヴ。商用サイトでは絶対できない。

実は「はるかのおはなしのおはなし」は布石であり、実験であった。

Harukamy’s Memoranda

Harukamy’s MemorandaはもともとJournal de Akiだったものである。 その後、ここと分離してReason Essembleになって、リニューアルで一部分を残して新規サイトになった。

レイアウト自体はいまさら驚くものではない。構造的には4カラム構成であり、これは現代的というよりは、古のフレームレイアウトに近い。 ナローウィンドウにおいては直列になる。

今さら見たことはないという人も多いかもしれない。

画面レイアウト上は昔っぽいが、中身としてはモダンに普通である。 フッターをfixedにして、コンテンツコンテナを全幅にするだけである。

しかし、その配置に関してはちょっと特殊だ。

サイドカラムはあくまでメニューナビゲーションに過ぎない。 現代的にはこれは上部に持ってくるものである。だが、上部に持ってきてしまうと実際には幅に対する制限がより厳しくなるので、サイドに持ってきた。

“Mimir Yokohama”はナビゲーションをサイドカラムとモーダルウィンドウから選択でき、「はるかのおはなしのおはなし」は常にモーダルウィンドウでナビゲーションを行うことで画面上からナビゲーションを追い出したが、“Harukamy’s Memoranda”では逆にモーダルウィンドウを持っていない。ナビゲーションはメインカラム上に存在し、ナビゲーションボタンとしてそれらへのリンクがある。

内部リンクは元位置に戻るのが戻るボタンで処理できるので非常にユーザビリティが高い。

見た目はちょっと不格好だが、恐らくこれが最善。 むしろ情報をみるために任意位置までスクロールしなければならないサイドカラムへの記載のユーザビリティが低すぎる。

本文に関してはほぼ「なり」であり、コンテンツ幅が狭いほうがよければウィンドウをタイルすれば良いじゃない、という考え方になっている。ユーザーの意思に関係なく、ディスプレイの空間を無駄に使って一部分だけに目を集中ざて読ませるようなものは嫌いだ。 ただ、ちょっとこだわりがあって欧文ウェブフォントになっている。これは、タイトルロゴにもサイドカラムにも画像は使っていないし、特にサイドカラムはかなりコンデンスドなフォントである必要があるといった都合による。 このサイトは割とデザインコンシャスなので、本文フォントの欧文はGildaでウェブフォント。

ただ、ちょっと思ったのがChromium系だと内部リンクをクリックしたときにウェブフォントを取りに行っちゃう。 これはちょっとおかしい。

また、フォントに関してはある程度のリテラシーを期待して「serifにしてあるから自分のブラウザを設定してよ」という形。 設定しないままだと少し困ってしまう等幅フォントだけは軽く指定してある。

長文読みに適するようにserif指定であり、赤めの低コントラストになっている。 このあたりは長年長文読みを研究してきた成果をぶちこんだ感じ。

デザインの話はAboutのページ内で解説している

Reasonset

コンテンツはまだないが、ついにリニューアルされたReasonset

Reasonsetとしては第三世代となり、私のメインウェブサイトとしては9代目になる。

これは、私が考える参照性がない長文読みのための、現在のベストだ。 そして、それは「はるかのおはなしのおはなし」と“Harukamy’s Memoranda”を組み合わせたものになっている。

コンテンツレイアウトはウィンドウ幅によらず直列である。 ナビゲーションも含めてすべて直列なセクション上にあり、“Harukamy’s Memonranda”からさらに1つ減った2つの内部リンクナビゲーションボタンがアクセスを提供する。

これは“Harukamy’s Memoranda”を発展させたものだが、フォントサイズの指定は「はるかのおはなしのおはなし」同様、ウィンドウサイズに基づくスケーラブルである。 こちらもさらに発展させており、最小16pxでシームレスにスケールする。

基本的には縦長にしたときのほうが情報量は増えるので、表示を絞りたい人は横長、ざっと読みたい人は縦長と使い分けられる。 もちろん、ブラウザウィンドウの空間は余すことなく使える。

内容に参照性がある場合は、一覧性が重要になってくるのでこのような表示は好ましいものではないが、Reasonsetの場合は先頭からじっくり読むタイプの記事に限られるため、この形式にした。 このようなデザインを採用するとしたら、コラム程度では甘く、かなりじっくり読める小説サイトのようなものに限られるだろう。

フォント指定も完全にgenericなものに限られ、WINGでホストしているので“Harukamy’s Memoranda”以上に軽く、速い。 フォントは全面的にSerif指定で明朝体。

要はリーダービューに近い、それ以上に「読む」ことを求めたものだ。軽めに読めるブログと違い、じっくりしっかり読むことを求めるスタイルでもある。 コントラストは青系でやや低めになっており、任意にダークテーマも選択可能。ダークテーマになるとコントラストはさらに下がる。

mpv * Linux でハードウェアビデオアクセラレーション

この話は

  • 各ビデオカードにはビデオエンコード/デコード支援チップが載っている
  • QSVとかUVDとかVCEとかNVENCとかNVDECとか名前がついてる
  • Linux的にはVDPAUとVA-APIというAPIがある
  • Nvidiaの場合はNVENC直 (NVDEC直も可)
  • CUDAを使ったCUVIDってのもある
  • mpvで再生支援するのが便利

っていうのは理解しているという前提で始まる。

それは、「結局渡すべきパラメータはなに?」って話である。 なお、VDPAU及びVA-APIは有効である前提で話す。それがわからない人はArchwikiへGo

はじめに

mpvを使うと非常に便利で、

$ mpv video.mp4

みたいな話なんだけれども、mpvには--hwdec--voというオプションがあり、ハードウェアビデオアクセラレーションを行う場合はこれらを指定する。

で、--hwdecは話としては簡単だ。ハードウェアデコーダを使うという話。つまりはコーデック的な話。

じゃ--voは? という話になるのだが、これは「ビデオ出力ドライバ」の指定。 なんじゃそら…という感じなのだけれど、「エンコードと描画レイヤーは別の話」みたいなことらしい。 だからSDLとか、Direct3Dとか出てくる。 YUVビデオとかそのまま書くんじゃないの?とかいう気持ちになったけれど、そんなことはないようで、「ハードウェアでデコードしたらハードウェアで書くところまでしないと効果なし」みたいな話になるようだ。

とはいえ、--vox11なんてすると凄まじくCPU負荷が増えてしまうし、xvを使う理由も全くない。 だから現実的な選択肢としては、vdpau, vaapi, gpuの3つだ。

試してみる

vdpau + vdpau

VDPAUでデコードしてVDPAUで出力する、というのは悪くないようだ。

ただし、この場合ポストプロセスはVDPAUでやることになる。 VDPAUはポストプロセスに対応しているからできるのだけど、一部使えなくなるものもある。例えば、ズームは効かなくなる。

vdpau + gpu

VDPAUで出力するよりも軽い。

そしてフィルタ等はすべて使える。

vaapi + vaapi

ちゃんとアクセラレーションが効いて軽くなるけれど、エフェクト、フィルタなどは一切使えなくなる。 マニュアルにも、だめなシステム向けだと書いてある。

vaapi + gpu

VA-APIだと--vogpu指定にすべきなようだ。

ちなみに、VDPAUだと--voを書かなくても十分アクセラレーションが効くのだけど、VA-APIの場合は--vo必須。

NVDEC / CUVID

--vogpu一択。ほかはそもそも使えない。

結局…?

Intel

alias mpv='mpv --hwdec=vaapi --vo=gpu,vaapi'

AMD, Nvidia (nvドライバ)

alias mpv='mpv --hwdec=vdpau --vo=gpu,vdpau'

Intel同様にVA-APIを使っても構わない。 ただ、再生だけを考えるならVDPAUのほうが少し良い感じがする。

nvドライバ環境でハードウェアビデオアクセラレーションすべきかどうか自体が疑問。

Nvidia (nvidiaドライバ)

alias mpv='mpv --hwdec=nvdec --vo=gpu --profile=gpu-hq'

NVDEC直のほうが速い。

gpu-hq

通常の--vo=gpuはフェイルセーフで、--profile=gpu-hqすると品質優先、とのことなのだけど、 試してみた限りでは、特にgpu-hqして問題になるケースは見つからなかったので、--profile=gpu-hqつけても良いかもしれない。

その場合はfallback用に指定しているvaapivdpauvoは必要ないというか、つけないほうが良い。

私の設定

alias mpvpau="mpv --loop-playlist=yes --hwdec=vdpau --vo=gpu --profile=gpu-hq --prefetch-playlist=yes --video-latency-hacks=yes --osd-font='Fira Sans' --osd-font-size=23 --sub-font='MotoyaLCedar' --sub-font-size=32 --sub-blur=3.5 --script=playlistmanager --script-opts=playlistmanager-loadfiles_on_start=yes"
alias mpvva="mpv --loop-playlist=yes --hwdec=vaapi --vo=gpu --profile=gpu-hq --prefetch-playlist=yes --video-latency-hacks=yes --osd-font='Fira Sans' --osd-font-size=23 --sub-font='MotoyaLCedar' --sub-font-size=32 --sub-blur=3.5 --script=playlistmanager --script-opts=playlistmanager-loadfiles_on_start=yes"
alias mpvnv="mpv --loop-playlist=yes --hwdec=nvdec --vo=gpu --profile=gpu-hq --prefetch-playlist=yes --video-latency-hacks=yes --osd-font='Fira Sans' --osd-font-size=23 --sub-font='MotoyaLCedar' --sub-font-size=32 --sub-blur=3.5 --script=playlistmanager --script-opts=playlistmanager-loadfiles_on_start=yes"
alias mpvcud="mpv --loop-playlist=yes --hwdec=cuda --vo=gpu --profile=gpu-hq --prefetch-playlist=yes --video-latency-hacks=yes --osd-font='Fira Sans' --osd-font-size=23 --sub-font='MotoyaLCedar' --sub-font-size=32 --sub-blur=3.5 --script=playlistmanager --script-opts=playlistmanager-loadfiles_on_start=yes"
alias mpv="mpv --hwdec=auto --vo=gpu --sub-font='MotoyaLCedar' --sub-font-size=32 --sub-blur=3.5"

playlistmanagerスクリプトを使っている。 単独のmpvコマンドだけが単一ファイル用。

Vivaldi Androidがついにきた!

Vivaldiが誕生し、それが良好であることが認められてから随分たち、スマートフォンバージョンは長く待望されていた。

そして、「今αより前のバージョンを試しているところだ」という報告があってから2年だか3年だか。 ついにAndroidバージョンが登場した。

デスクトップアプリとして最適化され、非常に高機能になっているVivaldi。 それをスマートフォンでどこまで活かせるかがポイントだった。

長所・特徴

扱いやすいブックマーク

ナビゲーションボタンにブックマークボタンがあり、動作も非常に早く、アクセスしやすい。

「スマートフォンにブックマークは不要」という考え方が主流で、まともなブックマーク機能をもったブラウザがない中、これはとても嬉しい。 下方へスクロールしている最中はナビゲーションボタン、アドレスバーともに見えなくなる構造。 非常に読みやすい。

なお、全画面表示設定はなく、オンスクリーンナビゲーションが原則として表示される端末の場合、デバイスナビゲーションを非表示にすることはできない。

文字サイズ

私にとっては待望と言えるのが「文字サイズの変更」である。

一般的にモバイルアプリのウェブブラウザでは文字サイズを変更したり、フォントファミリを変更したりすることはできない。 「ズームできるんだからいいじゃないか」という考え方なのだが、ズームだとUI全体が拡大され、デバイスから表示がはみ出すことになり、可読性が著しく低下する。 この問題はコンテンツ幅を指定していない、つまり「なり」で表示している場合でも適用され、「レンダリングしたものを拡大しているだけ」であるため、問題としてほぼ解決にならない。

実は昔はPCでのブラウザの拡大がそのような扱いであり、ユーザーによってUIを調整することが難しかった。 現在はPCブラウザでの拡大はスケーリング扱いになるため、レスポンシブデザインになっていればなんの問題もなく表示できる。 それがモバイルでは同じ過ちを繰り返している状態だ。

Vivaldi Androidは文字サイズを独立して変更することができる。 拡大縮小が簡単なVivaldiブラウザの特徴を引き継いでいるということだろうか。

PC表示

ほとんどのブラウザの「PC版表示」はdevice widthを無視する動作である。つまり、問答無用ではみ出す動作をする。

Vivaldi Androidではdevice widthをdot by dotにする。つまり、スケール1にする。 例えばFHDの端末であればdevice widthは実際には1080pxなのだが、スケール2になっていれば540pxしかない扱いになる。その分2倍に拡大される。 それをやめて、スケール1として扱うのでdevice widthが1080pxであるとする。結果的に「表示自体は小さいが、ちゃんと幅が収まる」状態になる。

どのみちズームはできるわけだから、これは望ましい挙動であるはずだ。 2層目のボタン一発なのも嬉しい。

カラーテーマ

デスクトップ版のように自由自在というわけではないが、ライトモードとダークモードが選択可能。

ただし、 自動ではダークモードがバッテリーセイバー有効時に有効になるという仕様には若干問題があるかもしれない

OLED(有機EL)の場合、黒は消費電力に有効である。 ところが、TN液晶だと黒は最も消費電力が大きい。まぁ、イマドキTN液晶なスマートフォンはないと思うが、VA/IPS液晶でも黒は気持ち省エネなだけである。

「ダークモードは省電力」という誤った認識を招くかもしれない。

リーダーモード

全く使われていないが、リーダーモードを搭載しているし、その扱いもちょっと特徴的だ。

他のブラウザはアドレスバーのわかりづらいところにアイコンを出すようになっている。 常にリーダーモードが使えるわけではないため、これはほとんどの人が気づかない。

Vivaldi Androidでは、設定で有効にするとリーダーモードにできるページでは「リーダーで表示するか?」と聞いてくる。 「常に使えるわけではないから、そもそも使えるかどうか気づきにくい」「使う人は望むが、使わない人は全く使わない」という点から考えると非常に合理的。

また、リーダーモードに3種類のページカラーテーマがあり、フォントもSans Serif, Serif, Monospaceで選択可能。 ただし、日本語Serifの載っている端末は非常に稀だろうけれども。

文字エンコーディング

PC版ブラウザからも消えつつある文字エンコーディング設定。

Vivaldiのデスクトップ版にも存在していないのだが、Androidには存在する。 日本語の古いページが読めなくなりつつあるので、とても嬉しい。

ダウンロードマネージャ

Androidでは割と省略されがちなダウンロードマネージャ搭載。

タブ機能

タブスタッキングやタイリングができるVivaldiだが、そのような機能は搭載されていない。

ただし、タブマネジメントそのものは他のブラウザと比べてやりやすい。 ブックマークだけでなく閉じたタブの復元などデスクトップVivaldiユーザーであれば「わかっている」であろう様々な機能はうまく移植されている。

ページ内検索

まともにページ内検索が載ってなくて困るブラウザが多いので、これは嬉しい。

ページキャプチャ

Vivaldiらしい機能として搭載される、Webページ全体のスクリーンキャプチャ機能。 スマートフォンだとこれは非常に便利。

なお、他のブラウザ同様にページを保存する機能はない。

検索エンジン

デフォルトはBingで、ほとんどのブラウザがGoogle固定である中、選択可能になっている。 アドレスバーから簡単に都度選択できるのもデスクトップ版同様。

ただし、追加はできないし、編集もできない。 Googleはgoogle.comになっているので、google.co.jpでの検索ができない。

ログインと補完

Vivaldiアカウントによる同期に対応。

パスワード、住所、クレジットカードの補完が可能で、それなりに柔軟にできるようになっているが、これらはそもそも精度がいまひとつであることから実用性はいまひとつ。 有効無効は設定できる。

問題点

プライバシーの設定には問題があるように感じる。

デフォルトの検索エンジンがBingなのだが、プライバシーや権限に関する設定が、Bingを例外として許可するようになっており、一部は変更できない。 これはBingをデフォルト検索エンジンから外すことで解除できるが、やや問題があるように感じる。

それ以外にもプライバシーに関するデフォルト設定が甘く、まるでWindowsのデフォルト設定のように「たくさんの項目を防衛的に変更する必要がある」状態である。 これは嬉しくない。

デフォルトで入っているスピードダイヤルのブックマーク数が多すぎるというのも問題であるように感じる。 もちろん、Vivaldiがスポンサーによって成り立っているという点を考えればスピードダイアルくらいは我慢して当然なのかもしれないが。

また、Vivladiユーザーであれば期待するであろう、デスクトップに最適化された様々な機能と、拡張機能いらずのカスタマイズ性は搭載されていない。 「Vivaldiらしさ」をそこに見出しているのであれば、Vivaldi Androidは肩透かしかもしれない。

総括

まず、ようやくVivaldiがAndroidにきたこと、「信頼できる、デフォルトにできるブラウザ」が誕生したことを歓びたいと思う。 「Chromeが最適だがChromeは使いたくない」という私にとっては吉報だ。現在はFirefox Focus/Firefoxを使っているが、Vivaldiがあるのであれば今後はメインで使っていくことになるだろう。

また、モバイルアプリにありがちな、ナビゲーションの劣悪さや機能の致命的不足がなく、サクサク使えるようになっている点は好ましい。

ただ、差別化という点ではやや厳しくも感じた。 特徴に乏しく、こだわりがない人がChromeから乗り換えようというモチベーションには恐らくならない。 結局一番欲しかったユーザープロファイル機能も搭載されなかった。

だが、この方向性が間違っているとも思わないので、ぜひがんばって欲しい。

お勧めできる!! Telegramの現在 2019

Telegram

TelegramはLINEのようなメッセンジャーアプリの一種。

本拠になっているのはドイツの非営利企業Telegram Messanger LLP。 創設者はロシア最大のSNS “VK” を立ち上げたニコライ・ドゥーロフ/パーヴェル兄妹。 VKとの直接の関係はない。

セキュリティをウリにしており、オープンセキュリティコンテストにより、脆弱性を発見したユーザーに報奨金を送る制度を持っている。 (ただし、これは実際にはセキュリティ上の根拠がないという指摘もある) EFFの審査でも安全性は高評価である。

すべてのメッセージはMTProtoによって暗号化される。 また、公式クライアントはオープンソース化されており、将来的にはサーバーもオープンソース化するつもりであるとしている。

基本的にはWhatsappのような電話拡張型だ。というか、Whatsapp対抗だ。 つまり、

  • 通話ができるよ。無料だよ
  • SMSより便利だよ。無料だよ

ということである。 基本的には電話機能に組み込もうとするし、電話帳とのリンクは行うのが原則である。

アカウントも電話番号を前提としたもので電話番号に紐づく。

日本ではWhatsappが流行っていないことから、火を見るより明らかに日本では流行らない。 日本語がない、というのもそれに拍車をかけている。Slackも日本語に対応していなかった頃は嫌がられたからね。

Telegramのウリはセキュアであることで、頻繁に「こんなのセキュアじゃない」と叩かれたりするけれど、 それもちゃんとオープンだからこその話で、相対的に見ればセキュア。

Telegramの今

電話番号

さてさて、あなたは

「電話番号でアカウントを作ります。電話番号と名前で相手を検索します。電話番号は相手に公開されます」

といったらどう思うだろうか。

世界的に言えば「え、普通でしょ」なのだが、日本では絶対受け入れられないやつである。私も嫌だ。

これがTelegram最大のネックだったのだが、いつの間にやら “Privacy and Securiry” の設定項目で 見せなくできるようになっている

これを使うと、「電話ベース…」というげんなり感が解消される。 素晴らしい。

ユーザーは、Usernameを設定している場合、@で始めることでユーザー名で検索できるようになった。 正確に一致していなくても検索候補には出るので、スパムや勧誘を気にする必要がある。 ユーザー名を消してしまえば部分一致には出なくなるようだ。

ユーザー名を公開するか、電話番号で扱うかの2択、ということになる。 電話番号の場合は完全一致が必要で、検索結果の候補には出てこない。

ちなみに、登録時に戸惑う人がいるかもしれないが、Telegramの電話番号はローカルという概念がないので、国別コードが必要。 これは例えば090で始まる番号は+81 90 ...になるということなのだが(0で始まる電話番号は「この国のローカルの」である)、これを知らない人は多いと思うので戸惑うかもしれない。

チャット

とても良い。

設定が細かくできることと、通知が優秀なことが大きいが、チャット自体の使いやすさもLINEよりだいぶ上。 LINEよりコンパクトに表示されるし、フォントサイズも設定可能なのが大きい。

通知に

  • REPLY TO … (返信する)
  • MARK AS READ (既読をつける)

の選択肢があるのもまた良い。

通知がすごく優秀で、ずっと優秀だったLINEも最近はあんまり通知してくれず気づかないことが多いが、 Telegramは完璧である。端末がディープスリープ下でもしっかり通知してくれる。Discordより良い。

メッセージ送達は数秒から十数秒程度でかなり速い部類に入る。

Stickers(スタンプ)は非常に「洋物」という感じだが、自作してしまえば良い。

LINEも最近は「音声メッセージを送る」ということができるようになっている。 みんなあまりつかってないけど、私は結構活用してる。

Telegramにも同様の機能があり、それだけでなく動画で送信することもできる。

ただし、音声同様、その場で録画して送るだけの機能だ。 この手の機能、インスタなのか、若い子が使っているのを割と見るので、需要あるのでは。

通話

通話品質は私が知るすべてのアプリの中でもっとも良い。

P2P通話にするかどうかは別に選べるのだが、 P2P通話の場合、エンドツーエンドで暗号化され、盗聴できなくなる。

非常に安定していて、ポイントが高いのは、Linuxデスクトップ版でも安定していることだ。

Linuxでの通話はいくらか不安定に感じられることが多い。LINEに至っては通話自体できない。 だが、Linux上での通話品質ならTelegramは圧倒的に優れている。

Linux上でということだと恐らく最も良いのはGoogle Hangoutsだと思う。 だが、Hangoutsでも「音声が突如聞こえなくなる」というようなことがままある。 その症状はSkypeだとより出る。

Discordは非常に音質が良いが、環境によっては音声が切れ切れに聴こえるということがあるようだ。 だから1:1での通話にはあまり向いていない。

LINEに関してはそもそも通話の音質自体がよくない。 そして、安定性も低く、音が切れたり、通話が切れたりよくする。

こうした点でTelegramは最も安定しており、最もではないが音質も良い。

ただ、ビデオ通話はできない。 とはいえ、これもちょっとおもしろいトリックがある。

通話は実は暗号化されたデータストリームであり、暗号化はエンドツーエンドで行われる。 そして、Telegramの仕様はオープンになっている。 このことから、データストリームにビデオを載せてしまうテクニックがあり、非公式のクライアント同士であればビデオ通話できたりする。

シークレットチャットの使いどころ

シークレットチャットに関しては、基本的に「エンドツーエンド暗号化されているから、覗かれる心配がなく、他端末からは見えない」というのが特徴である。

私だと、「PCはデモで画面を見せるから、プライベートなチャットは見せたくないな」という考えでシークレットチャットにするようなこともできるけれど、実際そのようなケースはあまりないと思う。 もちろん、「Telegram運営から隠す」という意図は成立するだろうけれども。例えば住所みたいなプライベートな情報を送るときとか。

ただ、シークレットチャットは基本的には「自爆タイマー」をオンにして使うものだと思う。これは、1-15秒の1秒刻みと、30秒、1分、1時間、1日、1週間で設定できるようになっている。 自爆タイマーの起動タイミングは「送信者が既読マークを受け取ってから」なので、実際は1秒にしてもがんばれば読めるくらいの時間はある。 また、相手が見ないうちに消えてしまうということはない。

自爆タイマーは両者共有される。

あとはちょっと見せるだけの写真を送るときとか。

コンタクト検索には注意

Usernameを設定しているとグローバルに検索されてしまうし、Telegramに位置情報を使わせていると近くの人にコンタクト追加されてしまったりする。 こういう設定は(Skypeとかでもそうだけど)ナンパ被害にあいやすいので注意が必要。

コンタクトに追加されたときは追加、ブロックが選べるのだが、 グループへの追加をEverybodyにしてるといきなりグループに追加されてしまうし、 通話をEverybodyにしてるといきなり通話をかけられてしまうので要注意。 ちゃんと設定はしましょう。

モダンなセキュリティ設計

電話番号ベース、SMS認証というのは非常にモダンなセキュリティ。

パスワードを廃止するテクニックのひとつで、端末を操作可能であることを条件とする。 この使い心地はなかなかで、アカウントには電話番号を使うのでアカウント名もない。

パスワードを伴うことを強制することもできる。

…英語で!!

言語機能はあるが、日本語がない。

英語でがんばろう。

Telegramの機能・設定

通知

超優秀な通知設定は、

  • 個人間のチャット
  • グループ
  • チャンネル
  • コンタクトに追加されたとき
  • メッセージがピン留めされたとき

の5種類の有効無効が設定可能。

通話呼び出し時に関してはバイブとサウンドは別々に設定でき、サウンドは任意に選べる。

アプリ内通知に関しても

  • 音声
  • バイブ
  • プレビュー (メッセージ内容の表示)

の3つが設定でき、またチャット中の相手から受け取ったときに音を鳴らすかどうかも選べる。

通知の優先度が高いimportanceも設定可能。

グループ、チャンネル、ユーザー個別のミュートも可能。 これはLINEのグループで悩まされている人にはとても嬉しいだろう。

そして、LINEのグループで悩まされている人にはもっと嬉しいであろう、 「未読数バッジの設定」がある。これについて「ミュートしているチャットは除外する」というのがあるのだ。

既読

「送達済み」と「既読」の2つのマークがつくというXMPPと同じ仕様。 既読がつかないようにはできない。

ブロック

ブロックは簡単で、ブロックの解除も可能。

電話番号の可視性

基本的にはWhatapp同様、電話番号ベース、電話拡張アプリになっている。

通常、コンタクトに登録した相手には電話番号が見えるが、 見せないようにもできるようになった

個別にも設定できる。

ただ、既にプロフィールで電話番号を確認した相手からは設定を変更しても消えない模様。

オンラインステータス

スマートフォン向けのメッセンジャーアプリにはなく、PCのメッセンジャーソフト(例えばICQやMSNメッセンジャー)には伝統的にあるオンライン表示機能。 といっても、DiscordやXMPPアプリ、Slackなんかにはあるし、Whatsappにもある。「LINEにない」のが大きいだろうか。 ちなみに、LINEだけじゃなく、カカオトークにもないし、Commにもなかった。

Telegramにはオンラインステータス、及びLast seen(最後に使用したとき)が表示される。 範囲を限定することも、個別に指定することもできる。

アイコン

アイコンは自由に設定可能。可視範囲も設定できる。

メッセージの転送

別の人にメッセージを転送する機能がある。

この転送は禁止することもできる。 転送禁止はスクショに対しても効く。つまり、スクショで晒すこともできなくなる。

通話

通話機能があり、非常に安定している。

通話の許可/拒否は範囲も、個別にも設定可能。 ビデオチャットはない。

また、通話でデータ量の削減を行うことも可能。

グループチャット

グループチャットは普通に使える。

許可/拒否設定があるが、“Everybody”, “My Contacts”だけで、(個別設定はできるが)一切拒否というのはできない。 もっとも、グループへの追加の完全な拒否ができないのは珍しくもないが。

ちなみに、追加は問答無用で行われ、拒否もできない。

グループ人数の上限はなんと 200,000 であり、単なるグループにとどまらず、コミュニティとしても利用できる。

チャンネル

チャンネルは配信用で、LINEでいうとLINE@やLINE公式アカウントと似たもの。 グループと同じ感覚で作れる。

ただし、チャンネルとLINE@の違いとして「配信専用」であるということが挙げられる。 つまり、告知に使える、メールマガジンと同じような位置づけのものであり、ユーザーからの問い合わせには使えない。そもそもユーザーがメッセージを送信することができないから、個別応答もできない。

それではLINE@のように使えないと思うかもしれないが、恐らくその心配はあまりない。 ほぼ単純に事業用の電話番号でTelegramアカウントを取れば良い。 LINEと違い、単一の端末で複数のアカウントを扱うことができるし、通常のTelegramアカウントでAPIを使ってbotを動作させることができるため、LINE@でしたいことは通常のTelegramアカウントでできるはずだ。

困るのは、ひとつの電話番号しか持っていない人がLINE@アカウントを作りたい場合だろうが、そのようなケースはあまり一般的ではなさそうだ。

メッセージの削除

なんと、相手のメッセージも削除可能。ローカルに消すことも、相手からも消すこともできる。

シークレットチャット

  • エンドツーエンドで暗号化される
  • Telegramのサーバーから見えなくなる
  • 自動消去タイマーが利用可能
  • 転送できない。 スクショもできなくなる

盗聴できないだけでなく、端末間で暗号化されているから端末をまたいで見ることもできない。 PC版からは使えない。

メッセージ消去は常に両者で共有される。

データコントロール

自動メディアダウンロードに関しては、「モバイル通信時」「WiFi時」「ローミング時」それぞれに指定でき、アニメーションGIF, ビデオは自動再生も設定可能。

クイック応答

電話に応答できないときに4種類、ワンタップでメッセージを返すことができるようになっている。

音声トークがあるため、留守電機能はない。

プロキシ

Socks5とMTProtoによるプロキシが利用可能。

まず見かけない設定だが、非常に強力。 ただ、通信自体が制限されている場合を除けば必要性は微妙。

テーマデザイン

色のパターンは選択できるだけでなく、独自に編集することも可能。

背景に画像を設定することもでき、器用にも「画像をぼかす」こともできる。

コンタクトごとに変える、ということはできない。

フォントサイズが自由に変えられる というのは嬉しい人も多いのではないだろうか。

あと、デスクトップ版は絵文字デザインが

  • Mac
  • Android
  • Twitter
  • EmojiOne

から選べたりする。

このあたりの設定は非常に細かくできる。

in app browser

LINEの内蔵ブラウザはセキュリティ上 すごく重大な 問題があるのだけど、内蔵ブラウザで開くかどうかというのはリンクアドレスそのもので指定するしかなく、任意には選べない。

Telegramではそもそもin app browserで開くかどうかを設定で選択可能。

スタンプ

英語で言うとStickers。

すごく簡単に自作できる。共有することになるけれど、アドレスを公開しなければまぁ見られることは多分ない。

その手順はbotに話しかけながら画像を送信するというお手軽さ。ただし、英語ができないとキツイかも。

言語

  • English
  • Arabic
  • Catalan
  • Dutch
  • French
  • German
  • Indonesian
  • Italian
  • Korean
  • Malay
  • Persian
  • Portuguese (Brazil)
  • Russian
  • Spanish
  • Turkish
  • Ukrainian

はい、日本語はない。

あと、韓国語があるのに中国語はない。珍しい。

パスコードロック

パスコードは4桁固定。 指紋認証も使うことができる。

ロックは「ロックボタンを押してからアプリを離れたら」かかるようになっている。 また、自動ロックをオンにしていると、その時間離れていると自動的にかかる。

なお、LINEのように完璧にブロックするわけではなく、コンタクトリストは短時間だが見えてしまうので、 浮気を隠す目的には使えない。

2段階認証

通常、新しいデバイスでログインするときはSMSで送られてくるパスコードを入力することになるのだが、 そのパスコードに加えて別途パスワードを入力するようにもできる。

コンタクトの共有

LINEはアカウントを作った瞬間に電話帳をアップロードしようとするやつだが、 Telegramの場合、電話帳の利用を許可したとしてもサーバーと共有するかは別に設定できる。

アカウントの自動削除

一定期間利用がないとアカウントを消すようにできる。

「もし私がいなくなったら…」の機能である。

望まれることが多い機能だが、どちらかというとSNSで欲しいんじゃないだろうかと思ったりする。

お気に入り

Saved Messageという専用チャンネルがあり、そこにメッセージを転送するとそのメッセージがクラウド上に保存される。

ちなみに、転送メッセージはワンタップで転送元のメッセージに移動できる親切設計。

マルチアカウント

LINEは「かならずモバイルは1端末である」という制約を課しているが、Telegramの場合特にそのような制約はなく、1つのアカウントを任意のデバイスで共有できる。

それだけでなく、1つの端末で複数アカウントを切り替えることもできる。 電話番号が必要なので無軌道にアカウントを増やせるわけではないが、DSDSのようなSIMカードが複数使える端末を使っている人には嬉しい仕様だろう。

Finally

問題点を挙げるとすれば

  • 英語
  • かわいいスタンプがない
  • かわいいテーマデザインがない

というところだと思うのだけど、いずれも基本的には努力と手間でなんとかなる。

テーマデザインはLINEのようなデザイン性はないけど、そもそもUIが不要なものを表示しない合理的なものなので、そういうデザインをねじ込む場所自体ない。

とにかく使い勝手が良いし、LINEよりもずっとずっと安心して使えるので、多分今最もお勧めできるメッセンジャーアプリだと思う。

ただ、唯一ビデオ通話ができないことだけがいかんともしがたい問題。通話をP2Pで処理できるようになっているのだからビデオ通話を追加することはそれほど難しくないと思うのだけど、ビデオ通話を追加する意思はなさそうだ。 ビデオ通話に適したアプリというのはとてもむずかしくて、私としても困っている。

Skypeもすっかりデスクトップの使い心地を捨て去った中、デスクトップアプリの使い勝手が良いのもポイント。 モバイル版にはない点として、メディアを一覧する機能があり、特にSaves Messagesではギャラリーのように使える。

多分、私がここでこんなことを言ったところでLINEから乗り換えようという人はほぼいないと思うのだけど、すごく正当なメッセンジャーという感じでいいと思う。 ぜひこういうのこそ主流になってほしい。LINEは最近余計なことをしまくっているし、見たくもない芸能ニュースを強制してくるし。

しかしちょっと思うのは、LINEって余計なものだらけですごく使いにくいUIをしているのに、慣れのせいなのか割と愛嬌のあるUIだと感じるし、Telegramは味気なさを感じてしまう。 もしかしたらこういうのは大事な要素なのかもしれない。

とはいえ、使い勝手は比べ物にならないほどTelegramが良いので、LINEの使いにくさや鬱陶しさに困っている人、 LINEを信用できないという人は使ってみたらどうだろうか。

「事前生成戦略」の原点、チャットスクリプト (コードつき)

チャットの開発、そして事前生成戦略に到達する下りはなんども書いているが、それが非常に革命的で、「極めてシンプルにすることができた」という話はそれだけではピンとこないのが普通だろうから、コードを添えて解決することにする。

事前生成戦略

PureBuilder Simplyで採用されている「事前生成戦略」は、私にとってはウェブアプリケーション開発におけるウリのひとつになっている。

その内容は、基本的に「ユーザーが要求するものは静的HTMLであるようにする」ということである。

キッカケはNginxだった。 2005年にはもう取り組み始めていたのだから、かなり感度は高かったといえるだろう。

当時、私のwebサーバーはApache 1.3だったが、結局はこのあとLighttpdへの移行することになる。 そしてその後はまさかのDeleGateへと先祖返りする。

だが、Nginxを検討したのは「静的ファイルの応答速度を重視している」という設計のためだ。

2005年には、ADSLの普及により回線速度がだいぶ向上していた。結果的に、従来では考えられないくらいチャットに対するリクエストが増大するという問題が発生していた。 ちなみに、当時のHTMLチャットといえば、「みんなでアクセスするとエラーになるもの」であり、ログ表示がおかしかったり、発言が消えたり、ページが取得できなかったりということは日常的にあった。

だが、そもそもwebサーバーは静的なページを配信するのが最も基本であり、静的なページにすることで多くの問題が解決するものと思われた。 そもそも、静的なページを取得するのであれば、CGIスクリプトは起動されず、負荷はとても少ない。 また、セキュリティ上のリスクなども(webサーバーが自分の責任で保守しているのではないなら)考えなくて良い。

少なくとも、静的ページを配信することはセキュリティ上もパフォーマンス上も良いことであるのは確かだ。

チャットで事前生成戦略

そもそも、チャットで問題が起きる理由は、「新しい発言を取得しようとしてリロードボタンを連打するから」であり、一種のF5アタックを仕掛けることになるからだ。

仮にF5アタックがさけられないとするならば、更新されるものが静的HTMLであればスクリプトが呼ばれることはなく、随分軽くなる。

私はそもそも、チャットスクリプトは随分長く開発に取り組んでいた。 その目的は既存のフリースクリプトを利用していた状況からの脱却であり、私がプログラミングを再開したときにまず行ったのは、チャットスクリプトを改造すること、そして学習の一環としてそれら(特にPerl4で書かれているもの)をモダンに書き換えることだった。

私のサイトでメインで使われてきたチャットスクリプトは「ゆいちゃっと2000」のち「TeaChat」であるが、サイト全体では非常に多くのチャットスクリプトを動作させていた。 フリースクリプトを比較すると同時に、私の開発テストでもあった。 舞台となったのはfreeweb、そしてロリポップ!である。

プログラミング言語を学習する過程でも、「その言語に適した形でチャットスクリプトを再実装する」という目標があり、 制作した「TeaChatのクローンスクリプト」は、Perl5(オブジェクト指向版), Ruby 1.8, PHP5, Python 2.4となかなか多い。

TeaChatのクローンスクリプトを書く中で感じたのは、 「チャットスクリプトは結局のところ、発言があったときはログを更新するという操作があるが、そうでないときはログを読んでHTMLをビルドしているだけである」ということだ。

この気持ちがより強くなったのは、eRubyを学んだときだった。 チャットのページは、eRubyエンジン、eRubyテンプレート、ログファイルがあれば生成可能であり、Rubyスクリプトは必要としない。 だが、TeaChatに準じると、わざわざRubyスクリプトであれやこれやしてからeRubyエンジンを呼び出すことになる。

そして、何度も何度もリロードによってHTMLをビルドすることになるのだが、更新するのは発言するときだけであり、ビルドする頻度に対して更新する頻度は極めて低い。 更新されていなければ、全く同じ内容のページをビルドしているわけである。これは、この上ないほど無駄だ。

だったら、更新があったときだけHTMLを更新して、ユーザーはHTMLを読めばよいではないか。

結果的には、フレームだけでなく、発言用ページも、チャットページも全て静的HTMLという設計ができあがった。 唯一、発言フォームのsubmit先がCGIであり、これは当初は静的HTMLそのものを編集する、というものだった。 のちに、eRubyを使ってログから生成する設計に変更される。

具体なコード

当時のコードは残っていないが、GitHubにその概要を実装したものを上げた

TeaChatほど高機能なわけではないが、当時のHTMLチャットとして基本的な機能は備えている。 PerlのチャットCGIは小さなものでも300行程度はあったことを考えると、39行というのは驚異的な小ささである。 しかも、このスクリプトはWebrickサーブレットになっており、サーバー機能すら自分で賄う。

本質部分はわずか8行で、

cgi = req.query
chat.unshift({name: esc(cgi["name"]), timestamp: Time.now.strftime("%y-%m-%d %T"), chat: esc(cgi["chat"])&.[](0, 1024)})
chat = chat[0,30]
File.open("chat.log", "w") do |f|
  Marshal.dump chat, f
end
chat_content = ERB.new(CHAT_HTML).result(binding)
File.open("chat.html", "w") {|f| f.puts chat_content}

となっている。ここでは

  • パラメータを読み込み
  • パラメータをオブジェクト化してチャットログに追加し
  • ログを保存して
  • HTMLにビルドして
  • HTMLファイルとして保存する

という手順である。

リロード間隔は5秒と短いが、手動で連打されるよりははるかにマシなので、手動ではやりにくい仕様になっている。

事前生成戦略をとることでコードが短くなり、バグの余地も減った。 そして、設計自体が単純になり見通しもよくなった。基本的に、良いことづくめである。

事前生成戦略の応用

では、このような事前生成戦略が有効なケースを考えてみる。

掲示板システムなどは、より読むことが多く、より適している。 そのように考えていくと非常に多くのケースに使えるということがわかる。

なによりもすごいのが、ブログのような発信型のコンテンツだ。

このようなものは当時、ページマスタリングシステムと呼ばれていた。 その要点としては、テンプレートがあることでページヘッダなど共通の部分を一箇所にまとめ、コンテンツ部分だけが異なるものを書こう、というようなことだ。

しかし、ブログシステムでこれを使うのは明らかに過剰である。 現在でいえば、Pandocですらそれは叶えられるのだ。

このことから、「テンプレート機能のサポート」「PODのようなより簡単にコンテンツを記述できる言語のサポート」の2点がテーマになった。 前者はPureBuilderとして、後者はPureDocとして実装されることになる。これに「記事の前後関係をもたせる」ことを目標としたのがACCSだ。

これらの大きなメリットとして、事前生成戦略ならではの「軽さ」だけでなく、実装が容易であり、なおかつ安全であるということがいえる。

まず、ログイン機能、管理機能などを実装する必要がない。 単純にファイルとして生成するものなので、「ファイルの編集」という概念に吸収される。 これで実装がとても楽になる。

さらに、webに対する攻撃というのはほとんどが定番webアプリケーションの機能を起動しようとしたり、ログインを試みるものであるから、単なる静的HTMLファイルでは攻撃の起点がない。 非常にセキュアである。

「事前生成戦略」という考え方からすれば、そもそも手元で静的ファイルに変換してしまうPureDoc/PureBuilderはより発展的な考え方であった。 これとは別に、検索ページのようなオンデマンドで提供される必要があるものはこの考え方が通用しない。むしろ、負担になる場合すらある。 そのために、「遅延生成戦略」というものも編み出された。これは、「例えページが更新される状況が起きたとしても、最初にアクセスされるまではページを実際には更新しない」というものである。 ただ、これ自体はほとんど「コンテンツキャッシュ機能」と変わりがなく、それほど独特なものではない。生成するべきかどうかを判断するために、リクエストはスクリプトが受け付けなくてはならないからだ。 実際に遅延生成戦略を取ったアプリとしてはMongrelを用いたサーブレットとして実装されたものがいくつかあるが、キャッシュとして以上の効果は発揮できず、この話を大いにすることはなくなった。

郷愁, 探求, 求道

今にしてみれば意外に思われるかもしれないけれど、私は当初から「変わったコード」「きわどいコード」を書いていたわけではない。 そもそも私は完璧主義者だったし、ものすごくきっちりしたコード、学習時に使用したものを正しく踏まえたコードを書いていた。

だが、当時から好奇心は強かったし、真理の探求という傾向も強かった。チャットスクリプトの再実装を繰り返す中で、「これは本当に必要か?」「こう書いたほうが本質的で端的なのでは」という疑問が次々湧き上がり、 1年くらいは耐えていたが、結局は徐々にアレンジを加えるようになっていった。

「別にアプリケーションで応答する必要はないじゃないか」というところに至るのがその流れだ。 サンプルでは本質部分だけを書くことをテーマにしているが、実際にはTeaChatに存在する機能は全て網羅するものを制作した。 TeaChatには電報機能があり、これはprivate messageである。つまり、「ユーザー固有のチャットを事前生成する」という戦略に成功していたことを意味する。

これは2バージョンあり、最初のバージョンではユーザーごとに固有のHTMLファイルを開くようになっていた。 こちらはやや複雑で、

  • フレームページとしてディスパッチャが呼ばれる
  • ディスパッチャはUIDを生成し、UIDのディレクトリを作成してベースとなるHTMLファイルを出力する
  • フォームにはUID値を覚えておく
  • 当該チャンネル上で一定時間内に発言のあったUIDを覚えておき、そのUIDを更新対象にする

可能な限り漏れがない仕様ではあるのだが、見てわかるとおり完全ではない。 電報リストのためにF5しなければならないというのが最も大きい問題だろうか。

後発の仕様はAjax仕様であり、XMLHttpRequestを使う。 HTML内にメッセージIDが埋め込まれており、そのメッセージIDが未知のものであれば、XMLHttpRequestによって追加で取得する。取得したメッセージはJavaScriptによってタイムスタンプでソートし、チャットに混ぜ込まれる。 HeartComではこれを発展した形式になっており、PM用(というよりuser relem用)のアプリケーションが独立して存在する。そしてXMLHttpRequestによってポーリングを行い、メッセージが受信できるようになっている。

結局このチャットにおける事前生成戦略採用が転機になった。 このスクリプトは、常識や、正しいとされていることとは全く異なる。だが、完全に正しく動作し、意図を達成できる。

至って本質的だ。この事実は「本質は端的に表せる」ということを意味しており、その正誤自体は結果1によって証明できる。 また、正しく動作する限りいずれも正しいのであり、世の中で正しいとされている手法や常識はどちらかといえばそれに依存している。つまり、「正しいが、最適であるかどうかは別」である。

以降、私は端的なコードを目指すことになる。 本質がなにかを見極めることができればコードは劇的に短くなる。もちろん、場合によっては泥臭くても今思いつく方法で解決したほうが良い場合もある。 だが、それだけでは成長がない。とにかくタンテ的なコードを目指す。それも、できるだけ短時間で、だ。 私の向上が、求道が始まった。

この求道はなにも「事前生成戦略」というテクニックにとどまらず万事に及んだ。 途方もなく困難に思われたことも、今ならできる。


  1. 結果は現象であり、この「結果」を「売上」や「人気」で測ろうとすると真実にはたどり着けない。↩︎

LINEオープンチャットに先を越されたか オープンチャットコミュニティへの想い

この話は今後を見据えた今の思考をまとめたものに過ぎない。

チャットについて

チャットにかける思い

チャット。

今の人にはあまり馴染みがないかもしれないが、インターネット黎明期のメインコンテンツがチャットだった。 ちなみに、もう少し前から見ると「掲示板」のほうがメインであり、ネットニューズを含めてポスト型のコミュニケーションから、パソコン通信時代を経てチャットのほうが追い越していく形だった。

私がはじめて経験した「画面の向こうの世界」は、the Internet上でのチャットだった。 1992年のことである。

私はあまり人と接さない子供だった。 幼少期は比較的コミュニティの濃い空間にいたが、「なじまない」という気持ちはとても強かった。

1992年に私が呼ばれたとき、私の扱いは「子供」ではなかった。ひとりのハッカーとして呼ばれたのだ。 技術的には未熟もいいところであったから、実際に対等なものであったのか、正直なところ今や私は覚えていない。10年くらい前までは結構はっきりと記憶していたと思うのだが、今や仲間たちの顔も名前も思い出せない。 そもそも、私の脳はそうしたことを思い出せるようにできていない。

そして、そのときのことは私にとって「衝撃な体験ではあった」のだが、あまり私を私たらしめる要素ではない。 それは、幼い頃のプログラミング体験が今の私には何も活きていないということと同じだ。

どちらかといえば、2000年に自宅でインターネットができるようになったとき――そしてチャット全盛期でもある――ようやく私の言葉が受け止められるという歓びに打ち震えたことこそが原体験となっている。 やがては結局、想いを共有できる者などいないという事実にぶち当たるわけだけども、少なくともそれまでのように言葉を尽くす意味もないということはなくなった。

結果、私はチャットにのめり込んだ。 real worldでの生活においては価値観を共有可能なコミュニティに巡り合わなかったということもあって、チャットは同時に私にとって貴重な出会いの場でもあった。 今私は誰とも触れ合わず暮らしているが、チャットがなければ昔もあまり変わらなかっただろう。そして、そうであればそれは今とは意味が全く異なる。

そのチャットも、コモディティ化によって崩壊する。 残されたのは、極めて限られた層だけが利己的に振る舞う場所としてのチャットだ。

復権はないのか、ずっと模索してきた

観測を続けていれば、インターネットの変化はよくわかる。 そして、人々が――特に若い人が――ネットに対して既知のコミュニティ以外を求めなくなってゆくこと、そして一方的なコミュニケーションのドッヂボールと化していくことは、痛いほど感じられた。

疑問はつきない。

人は本質的にコミュニケーションを求めるものなのではないのか

誰もが自分が暮らす狭い世界であてがわれる関係性だけで満足しているのか

――世の中誰もがリア充なのか?

もっともっと多くの人とめぐりあい、気の合う者、分かち合える者をみつけ、たくさんの言葉を交わしたいとは思わないのか?

少なくとも私は真のマイノリティだから、インターネットがなければ分かち合える言葉を持つことはない。 例えば、「持てる技術の限りを弄ぶ求道者」も、「知識と関心で世界の観測を望む者」も、「自己属性の有利ではなく均衡を望む者」も、普通に暮らしていては出会うことができない。 そう多く浮かぶわけではないが、今の知己の面々は実際、かけがえのないものだと私は認識している。

人は会話を望まないのか、チャットは人にとって夢のようなツールではないのか。 その想いはずっとあった。

現実は厳しい

チャットに限らないのだが、コミュニケーション系のコンテンツというのは非常に難しい。

一番の理由は「参加者の量に依存するから」である。 開始時は0にならざるを得ないので、コンテンツ価値がない状態からしかスタートできない。 そして、人の集め方を間違うと取り返しがつかない。 TwitterとLINEがどれほど腐っていても容易にはやめられない理由でもある。

技術的にも結構難しい。幅がひろすぎる上に、マッシヴコンテンツの対策というのは、経験しないことにはわからない。 Twitterは秒間25000ほどのツイートをさばくという。今では減少しているそうだが、携帯電話キャリアのあけおめメールのさばき方も並大抵ではないだろう。 IIJは甲子園野球の中継をホストしているが、550Gbpsを配信しているという。

Twitter以上の活発さを目指すのであれば技術的ハードルも高いなんてもんじゃない。

普通のHTMLチャットソフトの再実装(元ソフトウェアはTeaChat)からはじまり、このPerl5(オブジェクト指向), PHP5, Ruby 1.8, MySQLバージョン、sqliteバージョン、GDBMバージョン、ファイルシステムツリーバージョンと幅を広げ、 さらに独自実装ではNode.jsバージョン、Ruby emバージョン、事前静的生成バージョン(リードは静的HTMLで、送信によってHTMLを更新してしまう)が誕生し、EventMachine以外にもZeroMQを使ったもの、Rindaを使ったものなどとにかく色々と試した。 ZeroMQバージョンとRindaバージョンはウェブではないバージョンも登場した。

今に至るまで納得できる実装は登場していない。 作っている間に世の中の要件が変わりすぎるからだ。 「始めればついてくる」という確信があればとりあえず動くものを作っただろうが、そちらに関しては全くのノーアイディアだったから、それすらもしなかった。

例えば、成瀬さんは「チャットにログインがあるべきではない」と考えている。 一方私は「チャットに対してアクティブな状態にすることで「会話しよう」という明確な意思を形成できる」と考えている。 最高のチャット体験とはなにか、追い求めるほどに難しい。

いや、チャットコンテンツの主体は人だから、そのあたりはどうでもいいとも言える。 だが、「使ってもらえるチャット」である必要があるのだ。 だから「使い始める動機」を与える必要がある。

究極のUXを求めて

現状の仕様

RindaとZeroMQを中心とした複合的な技術になっている。フロントエンドはWebSocket+EventMachine(em-websocket)である。 繋ぎっぱなしなので、恐らくあまり大きな負荷には耐えられない。

データは極力クライアントサイドによって処理するという仕様であり、クライアントサイドJavaScriptに大いに依存している。

概念としてはログインがなく、「チャンネルの購読」という方式になっている。 channel subscribeするとチャンネルに対する更新を受け取ることができる。 チャンネルは無軌道に作成できるわけではない。

表示はoverall timelineとchannelの2種類。 過去ログ機能はなく、あくまでアクティブ中のメッセージが読めるだけ。

この表示はクライアントサイドのフィルタになっていて、channelを選択すると当該チャンネル以外のメッセージが非表示になる。

発言を行う場合、表示がchannelであれば単純にメッセージウィンドウを出して発言するだけ。 overall timelineの場合はメッセージウィンドウを開くときにチャンネルを選択する。

アカウントとログインは、アカウント認証時にeメールを必須とし、以降はログインのたびにeメールに書かれたPINを入力する。 パスワードはなく、eメールアカウントで管理することになる。

これとは別にトラディショナルなHTMLウェブチャットもある。 トラディショナルと言いながら実装は普通ではなく、

  • CGIによって動作するRubyスクリプト
  • 表示はiframe上の静的なウェブページ
  • チャットページはmetaタグによる自動リロード
  • チャットポップアップキー、またはチャットウィンドウアイコンによって発言用のウィンドウをポップアップする。これは親フレーム側(静的HTML)に属している
  • 同ウィンドウの送信先はチャットCGI
  • チャットCGIはデータベース(GDBM)を更新すると共にHTMLを書き換える

という仕様である。

実はあんまりよくない

Twitterとチャットの中間というか、まぁマストドンに近い感覚になっているのだけど、もっと単純なほうが使いやすい、と感じてしまう。

チャットUIのベストのあり方、というのは難しいが、PCではテーブル型(発言者と発言の横並び)、スマホでは定義リスト型(発言者の下にインデントして発言)が見やすいように思う。 さらにいえば、定義リスト型で長さによって横に並べるか下に置くかを動的にするのがベスト、かもしれない。

UIデザインに関しては色々と検討しているが、少なくともLINEのものは「悪くはないが、最善ではない」というところにある。 大人数の場合は追いにくくなるので、もっとエレメントを詰めて表示したい。

恐らくデザイン的にはDiscordのチャットが素晴らしい。

しかし、いずれにしても単純な連続的会話ストリームであるほうがよく、つまりはDiscordやSlack、あるいはIRCのような会話が望ましい。 結局のところ、TwitterのようなSNS形式が会話の環境として望ましいわけではない。それは、TwitterのDMがTwitterのUIとは別の形式を持っていることからも明らかだろう。

もうひとつの問題が、「ライフの長いチャンネルは淀む」ということだ。 チャンネルに支配的な発言者がいるとそのチャンネルは腐敗していく。これはYouTubeのチャット欄などでも発生する事情で、常連が支配的に振る舞うと、結局チャット全体が支配されてしまう。 だから、チャットチャンネルのライフはある程度短いほうが良い。だから、固定的なチャンネルというのは良いものでもない。

結果的には、Twitterがチャットの進化系であるという意見を元にTwitter的なやり方を取り入れて(もっと言えば、IRCや2ちゃんねるなどの「流行った手法」の踏襲)みたものの、結果としては「昔のチャットのほうがよかった」という結論に至ってしまう。

それはある意味当然で、昔のチャットというのは、他のことが手がつかないとしても会話に集中できる環境づくりが意識されていた。 対して、近年のLINEのようなコミュニケーションツールは昔のケータイメールの延長線上、つまり「メッセージを残す」性質のものになっている。 だからチャットでは通常あまり重要ではないタイムスタンプや既読マークが重要になるし、会話のフローを一覧しやすいようにもなっていない。

結局のところチャットとして望ましい仕様というのは非常に古典的なものだという結論に到達してしまうのだ。

UI部分

実は1:1とパーティチャットにおける望ましいUIというのは全然違う。

1:1だとDiscordのUIは相当に理想に近いところにある。 PC版だと他のサーバーや他のダイレクトメッセージを開いたり、通話をかけたりといった操作系がわかりやすく配置されている。 改行が可能であることは良いこととは言い難いが、そのためにMarkdownを用いた修飾が可能であることは利用の幅を広げてくれる。ただ、純粋に「チャット」であるならばそのあたりは抑制的なほうがいいだろう。

スマホ版だとメッセージ表示の余地が大きく、LINEと比べてすっきりしていて見やすい。 欲をいえば上部にあるアイコンやメニューなどは左右スワイプで出したい。

横長でもメッセージ幅を広げてくれるため見やすい。アイコン表示も見やすく、アイコンの存在がメッセージ表示領域を圧迫していない。 PC版ではページ外に、モバイル版ではチャットウィンドウ上にタイピング中のインジケータを出す。 これはSkypeあたりがやり始めたことだったような気がする。

スマートフォンならXabberも悪くないと思うのだが、これだとLINEやTelegramとほぼ一緒。

DiscordのUIは洗練された良いものだが、古典的なメッセンジャーUIであるPidginを見ても別に悪くないと感じる。 会話が盛り上がってくれば表示に改善できる余地がある点も気にならない。

それどころか、古典的なHTMLチャットですら割とアリだ。 現代のコンピュータと回線だと速度的にも速くなって非常に実用的。

パーティチャットの場合は大量のメッセージが流れることになるため、より一覧性が高く、スクロール時に見失いにくいデザインが望まれる。 インスタントメッセンジャーアプリの中ではKopeteが非常に不満な安定性ではある(よく落ちるし、接続もなかなか確立できず、メッセージの受動的受け取りができない。さらにいえば、コンタクトリストがどんどん増える)のだが、UIは最高に望ましい。 邪魔にならないアイコンと、コンパクトな表示が優れている。ただ、名前とメッセージの間が空きすぎていて、Discordよりも間延びしているのが残念。とはいえ、PC向けのパーティチャットの基本的な最も良いUIがこの方向であることは間違いない。

加えていうなら、「色分けしたい」というのはある。 ここでは「自分とそれ以外」でヘッダー部分の色が変わるのだが、メッセージ色なり、名前色なりといった部分がユーザーごとに違うようにして、アイコンや名前を確認しなくても誰が発言したかわかるようにすることと、自身の発言だけ背景色をつけることで明確にすることだ。

スマホ版でも基本的な方向性には変わりないが、チャットウィンドウ以外の「なにも表示しない」のがいいのではないだろうか。 1:1では常に自分は発言する状態にあるが、パーティチャットの場合その瞬間に発言しようとしていない人というのが多い。 だから発言用のウィンドウも非表示。チャットウィンドウだけ。参加者一覧とメニューアイコンを左から右へのスワイプで、発言を右から左へのスワイプで出す、というのはどうだろうか。 もしくは小さな発言用アイコンをフロートさせてもいいのだけど。

スマホで発言ウィンドウ(というよりもソフトウェアキーボード)を出した状態での表示領域の小ささはいかんともしがたい。 発言ウィンドウ表示は1行に抑えるとして、それでもチャットの表示は少ないので、発言ウィンドウを開いている間は表示更新はしないのがよかろう。

チャット体験部分

チャットの体験としては、「ライフの短く、固定性のないチャンネルだが、匿名ではない」が良さそうだ。

現存するものとしてはランダムマッチングのものがあるが、さすがにこれはライフが短すぎる。 また、よりライフの短い人と非常にマッチングしやすくS/N比が実際以上に悪化してしまう。

このことを考えると、

  • チャンネルは自由に立てられるが
  • チャンネルのカテゴリは大枠で制限されており
  • 検索によって発見する
  • チャンネルは接続が0になるか、一定時間以上誰も発言しないとクローズする

あたりが良いのではないかと思う。

ただし、これだと部屋の作成がまともにできないので、作成後一定時間はライフを維持できるようにするか、作成後joinされるまではある程度の時間待ち受け状態であり続けられる(検索対象になる)という形で良いかと思う。

これにroom limitを加え(固定値でもいいし、5から20などの範囲で設定できても良い)、limitを迎えたチャンネルは検索対象にならないようにする。joinできなくするかは要検討。恐らくjoinできなくする必要はない。

これで交流はある程度流動的になるし、どうしても固まる人たちはむしろ固まってくれたほうが良い。

kickは与えず、チャンネルマスターも設定しない。 それをすると「開設者がチャンネルマスターとして支配的に振る舞う」という事態が発生するからだ。

ユーザー関連機能は厳し目にしないとひどいことになってしまう。

厳格なユーザー認証(恐らくSMSが良い)を必要とし、ユーザーに対してはプロフィール機能を用意する。 このプロフィール機能は記入は任意であり、主にはチャットユーザーがそのチャッターに関する情報を確認するためのものである。 実は、「はとこみ」設計時はこの機能を中核として考えており、「ユーザーがあり、コミュニケーションを取る」ような形であったが、それと比べると抑制的である。

チャンネルに関してカテゴリ違いや禁止事項への抵触に対する対応はかなり厳しく行う。 一方、「通報」に関する対応は、「通報件数が多いから」のような対応はしない。

どちらかというと「ブロック」を上手に使う方向で考えている。 このあたりはYouTubeチャットと同じか。

運営リソースはかなり必要になりそうだ。

そして、これはLINEオープンチャットのように、無数の人が最初からいる前提である。

LINEオープンチャットがユートピアとなりえない理由

時代を変革するかと思われたLINEオープンチャットだが、致命的な問題が見つかったので、そこまでのことではないと判断することができた。

その致命的な問題が、「過剰な連絡先交換の拒絶」である。

現在、社会的な理由でリスクを避けるためにも、また制度的(法的)な理由でもそのようにしたいということはわからないではない。 だが、これは致命的なミスである。

このような扱いは、結局のところ「匿名で荒れる」という状況を作り出すことになる。 その場での発言が全てなので「別に何言ったってこの場のことだし」となるし、結果2ちゃんねるやニコニコ動画のコメントのように非常に品位の低い一方的な言葉の投げつけが行われることになる。 そんな環境ではまともな会話が成り立つことは極めて少なくなるし、生産的な場になりようがない。

交流の場たらしめるには匿名にしてはならないのだ。 それは、ずっとチャットを含めコミュニケーションをずっと眺めてきて強く感じることだ。

そして、匿名にすること、ここが「他のコミュニケーションとは違う」という扱いをすることによって「画面の向こうに人がいる」という基本的なことを意識しなくなる。 だから何をしてもいいという理屈を振り回すようになり、人を傷つけることに対して抵抗をなくしてしまう。 必要なことは匿名化ではなく、「on your risk」を明確にすることだ。

連絡先を交換することも、あなたのリスクにおいて、それが結果どうなったとしても他者に責任を求めることはできないし、してはならないということを承知の上で自身で選択すればよい。 自身の振る舞いには常に責任があるということを明確にしないと、ただただ悪意と攻撃ばかりが増幅していく。

LINEオープンチャットは実際に蓋をあけてみれば、あらゆる点に対して思慮が足りなかった。 チャットの運営はとても大変なものであり、それは文化足り得るからこそ慎重さも必要となる。

確かに、LINEでチャットをはじめれば多くの人が利用するだろう。 だが、それが意味するところ、それをすることで実現できることを十分に測らなかった、そう感じる。

もちろん、これはある種イデオロギーの対立である。 私が正しいと信じるものに賛成はすまい。 でもだからこそ、それは私が求めるユートピアではないと、そう感じるのだ。

正規表現マスターの「コツ」

「正規表現がわからない」という人は結構多い。

私としては、正規表現(Perl regexp)の習得は特に苦もなく、長大な正規表現もすんなり書けるようになったのであまり実感はないのだが、どうも正規表現の記述に関しては得手不得手がはっきり出る部分であるようだ。

私が正規表現を教えてきた感覚で言うと、正規表現はむしろプログラミングに関してある程度知識がある人のほうがハマりやすい。 プログラミングが関数型言語を除けば手続き的であるのに対し、正規表現は宣言的であるため、その切り替えができず、概念がごっちゃになる部分が大きいようだ。

正規表現を理解するには、正規表現が宣言的であり、どのような概念の集合なのかということを理解するのが重要だ。 そして、それだけを理解すれば単純な要素の複合であるため、全く難しくはない。

ここではMimir Yokohamaのクラス2授業であるプログラミング系科目で教えている正規表現の内容から、特に肝となる部分のエッセンスを抽出し、紹介したいと思う。 察しのいい、定義によって明らかにされれば論理的導出で理解できる人にとってはこの内容が十分助けになるだろう。

より具体的な説明や、詳細な大切、具体例などが欲しい人は、ぜひMimir Yokohamaを頼って欲しい。

正規表現の要素

基本

正規表現の要素はBREの場合

  • 文字
  • グループ
  • 文字列
  • 位置

が存在する。

EREの場合は「文字列」がない。

Perl RegexやOniguruma/Onigmoの場合、「パターン」が追加される。 まぁ、さらに「条件」や「実行」や「演算」が追加されたりもするのだけど、そこは置いておく。 正規表現わからないと言っている人の話題はそこではないだろうから。

文字

文字は正規表現の基本要素であり、正規表現の考え方としては文字が並ぶことで構文となる、と考えられている。

正規表現は文法の条件の記述であり、文字というのは固定の文字ということではなく、条件に合致する文字を示すものである。

通常の文字、例えばaは、aという文字だけが条件に合致する文字があることを示す。

[abc]a, b, cのいずれかが条件に合致する文字であるということだ。

これは例えば文字クラスやUnicodeスクリプトにおいても、どのような文字が条件に合致するかということを示しているだけであり、文字には変わりない。

グループ

グループは文字条件を1文字以外に拡張するものである。

文字はあくまで文字として定義されたものが1文字に一致するのだが、グループ化されるのは正規表現であるために、 0文字以上の 任意の文字列が条件に当てはまることになる。

量は文字, 文字列, グループ(パターン)の反復を示す。

単純に「〜がn回あって」という話だと考えていい。もちろん、場合によっては「n回またはm回」であったり、「n回以上」であったり、「n回以下」であったり、「n回からm回」であったりする。

文字列

文字列はキャプチャによって得られる既知の文字列である。

例えばBREにおいて

\(ab\)\1

というと、ababということになる。

文字列はパターンでなく、あくまで文字列なので、

\(a[ab]\)\1

というと、ababaaaaにはマッチするが、aaabにはマッチしない。

多くの人が理解していない部分として、文字列は量指定子の対象である。だから

% print ababababbbabab | grep -o '\(a[ab]\)\1*'
abababab
abab

という結果になる。

位置

位置は「ここがこういう場所である」ということを条件とするものである。

普通のBREの場合、「行頭」(^)と「行末」($)の2種類しかない。 GNU grepだと「単語協会」(\b)もあったりする。

Perlの正規表現にあるのは位置をパターンで表すことができる幅ゼロアサーションだ。 幅ゼロアサーションはパターンであるために混乱を招くかもしれないが、「…という場所」ということを述べていると理解すれば難しくない。

パターン (強敵)

さて、最大の強敵がパターンだ。Perlだと5.14から追加され、Onigurumaにも目玉機能として入っている。

正規表現そのものがパターンだから、パターンの中にパターンを表現するということは、「再利用」や「再帰」ができるということである。

再帰だと混乱する人が多いので再利用について述べると、例えば

nnn-ACnnn-Xnnn-n

という文法が存在するとしよう。(nは数字)。もちろんこれは、

\d{3}-AC\d{3}-X\d{3}-\d

で表現できるものである。

パターンを正規表現中で利用すること自体は、「グループの量指定」によって可能である。 ところが、これはあくまで「グループで示されるパターンが連続する」場合であり、「グループで示されるパターンが断続する」場合や、「グループで示されるパターンが内包される」場合には利用できない。

これを可能にするのが部分式呼び出しである。 これを使うとOnigmoでは

(\d{3})-AC\g<1>-X\g<1>-\d

と書くことができる。 \g<1>というところが1番目にキャプチャされたパターン(\d{3})を意味する。

ここでは\d{3}なんていうものすごく単純なパターンであり、別に嬉しくないように思うが、これはものすごく複雑なパターンが繰り返す場合には相当タイピングを節約できる。

Onigmoでは名前付き捕獲式を使うことができる。

(?<num>\d{3})-AC\g<num>-X\g<num>-\d

\g\kで悩む人もいるが、\kは単純に捕獲された文字列である。 これは既にあったものだ。だから、

% ruby -e 'ARGV.first =~ /([ab])\k<1>/ and puts $&' abaaa
aa

である。([ab]\k<1>)([ab])\1に等しい。

そして、部分式呼び出しはパターンであるから、

ruby -e 'ARGV.first =~ /([ab])\g<1>/ and puts $&' abaaa
ab

であり、これは結果的には([ab]){2}と書いても同じである。もちろん、その場合は間に何かをはさむことはできないが。

つまり、パターンが利用できる正規表現エンジンにおいては、「文字列の再利用」だけでなく「パターンの再利用」が可能になっている。 だから結果的にグループが「パターンの宣言的定義」にもなっているのだ。

正規表現の考え方

正規表現は文法を示すものである、ということを忘れてはいけない。 「Xはこのような文法を持っている」ということを記述するものである。

正直なところ、BNFなんかよりは遥かにわかりやすく、簡単だと思う。

例えばウェブアドレスの場合、httpまたはhttpsスキームを持つわけだが、そのあとはあまり変わらない。だから

https?://(?:\g<user>:\g<password>@)?\g<domain>/\g<path>(?:\g<param>(?:\g<param>)*)?

のように書くことができる。

「一致する文字列」というふうに考え出すとドツボにハマる。 正規表現はその概念を定義するものだ。

プログラミング上では、値よりもクラスの定義のほうが近いと思えば良いだろう。 クラスの定義は「Xというクラスは以下のようなものである。メソッドa、メソッドb、インスタンス変数xをもち…」というように行うものだが、 正規表現もまた「re1は以下のように正規表現によって表すことができるものである」と述べているわけだから。

ちなみに、この場合では各捕獲式がこの正規表現中で定義されていないため、正規表現のコンパイルエラーになる。 だが、パターンに名前をつけられるのであれば、事前に部分的文法を定義しておきたいものだ。 Perl6のRulesはそのようになっており、「部分式呼び出し」を中核に据えたものになっている。なので、よりわかりやすく宣言的だ。

ただし、Perl6のRulesは正規表現とは記法に互換性が 全くない ので注意してほしい。

Git/Mercurial/分散バージョン管理システムの基礎

Gitに関する話をするとき、「ん???」となることがまぁまぁある。

で、多くの場合よく考えれば「GitHubの概念に引きずられている」ものが多いように感じる。

今回は、Git、そしてMercurialを含めて分散バージョン管理システムに関する概念と用語を、簡潔・明瞭に説明したいと思う。 なお、Bazzrその他に関しては私は使ったことがないので、分散バージョン管理システムの説明といいながら、GitとMercurialだけで進めさせていただきたい。

概念に関するもの

リポジトリ

恐らく、用語としてはこれが最も難しい。

「リポジトリとは歴史である」などといったりするのだが、どうも各々の定義にぶれがある。

であるから、Gitの場合は、.gitディレクトリ、あるいは*.gitディレクトリ(ベアリポジトリ)のことを指していると思えば良い。 また、.gitがあるディレクトリは「ワーキングツリー」である。

Mercurialの場合は.hgディレクトリを指す。

これは単にファイルであるだけではなく、ファイルの変更などを管理するための情報をもち、実際に管理することができる。

ローカルリポジトリ

ローカルリポジトリは、ワーキングツリーから見て、そのワーキングツリーが所属するリポジトリ(つまりは、ワーキングツリー先頭の.gitあるいは.hg)を指す。

ローカルリポジトリという語が出てくるのはリモートリポジトリに対する対比である。 なぜならば、リポジトリの操作はローカルリポジトリ(ワーキングツリー)上で行うため、「手元側」を意味することになるからだ。

リモートリポジトリ

リモートリポジトリは、ワーキングツリー、あるいはリポジトリから見て、自身ではないリポジトリを指す。

リモートリポジトリは一般的にはローカルリポジトリに対して何らかの関係性を持つ。ただし、持たない場合もある。 何らかの関係性とは、ローカルリポジトリがリモートリポジトリのことを登録しているか、リモートリポジトリがローカルリポジトリのことを登録しているかを指す。

「リモート」といっても、あくまでも「このリポジトリの外」の意味であり、ネットワーク越しであることを意味するわけではない。 むしろ、最も基本的なGitやMercurialの運用においてはリモートリポジトリはファイルシステム上にあるほうが普通であり、ネットワークにおけるリモートを指してはいない。

また、場合によってはそもそもローカルリポジトリ上で登録されたリポジトリのことだけを指してリモートリポジトリと呼ぶ場合もある。

コミット

リポジトリによって管理されるファイルのある状態の記録である。 GitやMercurialの変更は連続的に記録されるわけではなく、コミットした瞬間ごとが記録される。

コミットは本質的にリポジトリへの書き込みである。 このことから、最終的な修正が反映される権威リポジトリが存在する場合、その権威リポジトリに対するpush、あるいは権威リポジトリ上でのコミットを「コミット」と呼ぶ場合がある。 この場合、「そのリポジトリを更新する行為」を指すのであり、その行為をしうる者を「コミッタ」と呼ぶ。

ステージング

Mercurialにはない、「コミット候補」。

基本的にはGitの場合、ステージされたものはステージされた状態で保たれ、コミットされる。 ステージされてからコミットされるまでに変更は加えられないので、「コミットする前に考える」段階があると考えて良い。

実際のところ、ほとんどの場合ステージングは省略されている。

HEADはGit独自の概念である。

HEADは コミットを指している訳ではない 。 HEADはあくまで位置である。

リポジトリがリモートリポジトリと同期される関係にある場合、リモートリポジトリと同期した位置というものが記録されている。 HEADは全体で一番最後にコミットされた位置である。

コミットを取り込む場合、取り込む側(つまり、それによって変更される側)のほうがHEADの位置が前にあってはいけない。

フォーク

フォークは分散バージョン管理システムにおける用語ではない。

フォークは(由来は置いておくとして)ソフトウェアを複製し、複製元とは異なる未来を歩むことを意味する。

分散バージョン管理システムにおいては、行為としてはcloneすることがまさにforkすることを指す。 ただし、cloneした後に異なる未来を歩み、それを元のリポジトリに反映する場合や、恒常的に元のリポジトリの変更を反映する場合はforkしたとは言えない。

先割れしたフォークの先端が交わることはない。forkは決別なのである。

ブランチ

ブランチの概念はソフトウェアによって随分違う。

Gitの場合はあくまで歴史の分岐である。 ブランチを作ることでブランチ作成の起点になるコミットから、他のブランチに影響されることなくコミットを作っていける。

Mercurialの場合は、ブランチは位置情報になっている。 枝分かれしているというよりは、同じように時間が流れる平行世界みたいな状態である。

両者の大きな違いとして、Gitはブランチを作ったらそのまま完全に違う未来を歩んでもいいので、最初のブランチであるmasterブランチにそこまで特別な意味がない。 対してMercurialの場合は一種のコミットのような扱いになり、ブランチは最終的には取り込まれるか、クローズして捨てられるかすることを想定している。 だから、Mercurialの場合はdefaultブランチが本命である。

なお、Gitのmasterブランチは基本的に進んだHEADを持っているので、masterブランチをリリースブランチにするのはちょっとまずい。 リリースブランチは別に切るべきだ。 対して、Mercurialは一番進んだコミットを持つdefaultに合流するようになっており、あんまりリリースのことは考えてない感じになっている。

また、ブランチの大きな違いとして、Gitはブランチは削除できるが、Mercurialは閉鎖できるだけで削除はできない。 どうしても削除したい場合は方法がなくもないが、それはそれでMercurialでは本来禁止されている歴史操作を使ってそのブランチの世界線にあるコミットを全て消滅させるというすごいことをすることになる。

さらにもうひとつ大きな違いとして、Gitの場合ブランチは個々のリポジトリに属している。明示して送りつけない限りはpushあるいはpullするのはブランチ単位である。 対してMercurialは全てのブランチが共有される。だから、Mercurialでのpushあるいはpullするのはリポジトリ全体である。

競合 (conflict)

バージョン管理システムにおいて最も重要なのは、「同じファイルを同時に変更することに対して保護する」である。 古代のバージョン管理システムであるRCSでは、「変更可能な状態で持ち出せるのは1ユーザーだけ」という方法で管理していた。

GitもMercurialも、基本的には同一ファイルに対する変更を競合とみなす。

ただし、Gitの場合は変更点が重複していなければ競合にはならない。 Mercurialの場合は変更点が重複していなくても同一ファイルに対して変更していれば競合になる。

ただし、Mercurialの競合はそもそも歴史が割り込まれた時点で発生するため、こっちも向こうもそれぞれにコミットしたんだよね、という状態になったら確実に競合が発生する。 この変更が統合可能なのであれば、mergingという扱いにはなるものの、実際にはmergeは必要なく、単に「歴史を統合したコミット」を作れば良いようになっている。

ここらへんはGitのほうがきっちりしていて、Mercurialの場合はそれぞれが無軌道に変更を加えているとえらいことになる。 Gitではそもそもpush可能なのはベアリポジトリだけなのに対し、Mercurialではベアリポジトリという概念がなく、リポジトリは須らくワーキングツリーを持っているという考え方になっている。 でも、複数人で作業するような場合はワーキングツリーに対する変更を加えない、つまり自分でコミットを作成しないリポジトリを作ってそこにpushするようにしておかないと混乱を招くことになる。

pull request

pull request (通称プルリク)は、GitでもMercurialでもなく、 GitHubの機能である。 ちなみに、GitLabでは “Merge Request”という名前で同種の機能がある。

リポジトリに対してpushするためには、当該リポジトリに対する書き込み権限が必要である。 読み取り権限があればcloneできるため、cloneされるリポジトリは所有者が異なる可能性があり、元のリポジトリに対する書き込み権限がないことも少なくはない。

もちろん、書き込み権限があるのであれば当該リポジトリに対してpushすれば良いのだが、ない場合は当該リポジトリの書き込み権限を持つ者にpullしてもらうことになる。 しかし、その場合「pullしてほしい」と伝えなくてはならない。これを、「pullして欲しいと伝えて、変更点を明確にして、ついでにボタン一発でpullできるようにしたもの」がPull Requestである。

これに関しては誤解が深く、GitHubでGitを触り始めた人がだいたい混乱している。

アクション

init

リポジトリを作成すること、だが、どちらかといえば「今いるこの場所をリポジトリにする」のほうが実態を指している。

ただし、Gitにおいてはgit init --bareがあるためそうとも限らない。 この場合はベアリポジトリを単純に作成する。

このアクションはローカルリポジトリが存在しない状態で行う。

clone

リモートリポジトリの複製を作成する。

このアクションはローカルリポジトリが存在しない状態で行う。

push

ローカルリポジトリのコミットをリモートリポジトリに書き込む。 リモートリポジトリの書き込み権限が必要である。

pull

リモートリポジトリのコミットをローカルリポジトリに書き込む。 リモートリポジトリの読み取り権限が必要である。

add

基本的にはワーキングツリー以下のファイルをリポジトリの管理下に加えるアクション。

Gitの場合はステージングの際にも使用する。

Mercurialの場合、ワーキングツリー以下で明に除外されていないのに管理外にファイルがあることは望ましい状態ではないと考えるため、addの手順はまぁまぁ省略される。 Gitでは省略はできない。

merge

Gitにおいては異なるブランチを取り込むこと。

Mercurialにおいては、割り込みの発生した歴史を一本にまとめたコミットを作ること。

reset / rollback

resetはGitにおけるアクションで、ステージされたファイル、あるいは最新のコミットを取り消す。

Mercurialでは最新のコミットを取り消すrollbackがあり、Mercurialではコミットの歴史を操作するアクションはこれが唯一。 ステージして慎重にコミットするGitと違い、Mercurialは一発でコミットをキメてしまうため、rollbackは結構よく使うし、実際に簡単に使えるようになっている。

revert / backout

revertはGitとMercurialで全く意味が違う。

Gitにおいてはコミットを取り消す。この場合、そのコミットにおいて行われた変更そのものを元に戻す。 Mercurialは歴史を変更することはできないので、あるコミットで行われた変更を元の状態に戻す変更を加えたというコミットを作成する。それ用にbackoutというアクションがある。

Mercurialのrevertはワーキングツリーのファイルをコミットの状態に戻すことを指す。 これはGitであればgit checkout <commit> <file>に相当する操作である。 Gitのcheckoutはこれとは全く異なる「ブランチの切り替え」という機能も兼ねており、少々わかりにくい。

Gitには他にも歴史操作に関するアクションがあり、特にrebaseはまさに歴史修正主義者のためのコマンドである。

あんまり知られていないが、Gitにはblameという大変便利な歴史チェックコマンドがあったりする。 そして、実はMercurialにも似た感じのことができるannotateというコマンドがあり、hg annotate --user --numberとやればblame相当になる。

「revertするぞ」と言われたら、「お前のコミットは問題があるからなかったことにする」という意味になる。 例え実際にはMercurialを使っている場合でも「backoutするぞ」じゃなく「revertするぞ」と言う場合が多い。

diff

何か(コミット, タグ, ブックマーク, e.t.c.)の間でファイルの変更を比較するアクションである。

実はGitのdiffはGitリポジトリ外でも使うことができる。

diff -uと同じだろ?何が嬉しいんだよ」と思うかもしれないが、実はGit diffはインラインで変更を表示することができるのだ。 これがすごく便利。

stash

ワーキングツリーに対する変更を保留にするGitのアクション。Mercurialには全く存在しない。 ほとんどの場合、「作業すべきブランチを間違えた」という場合に別のブランチに変更を持っていくために行う。

すごく便利である。 そもそも、ブランチに関する操作はMercurialよりGitのほうがずっとやりやすい。

Manjaro Linux, Arch Linux共にDiscordがCommunityパッケージに

AURからなくなったDiscordの行方

先日の記事でDiscordがAURから削除され、Snappyを利用するように変更されたということを記事にしたが、2018-08-13 MANJAROのstable updateでcommunityパッケージに追加された

もう少し解説

ManjaroのリポジトリはArchとは独立しており、そのパッケージングポリシーも少し違う。 一方でArchのユーザー投稿リポジトリであるAURのパッケージのほとんどが利用できる程度には互換性がある。

原則として、AURにはArchの公式パッケージとして存在するものは投稿できないし、AURのパッケージがArchのパッケージになる場合、AURから削除される。 一方、Manjaroにおいてはもっと広く、「多くの一般ユーザーが欲しがるパッケージ」が公式パッケージに加わっているため、AURと重複するパッケージというのが存在している。これは時々トラブルの元になる。 例えば公式パッケージから削除されたときにAURパッケージがインストールされてしまうなどだ。

今回のAURからの削除は、重複するパッケージを設置しないというArchのポリシーに基づき、Snappyによってインストールすることを推奨するものかと推察された。 これに対しManjaroがAURから削除されたパッケージを「必要としている」と判断して独自にDiscordをパッケージングしたという理解だ。 だが、実際にはArchのほうもcommunityパッケージとしてDiscordが追加された

extraではなく、サポートの手厚いcommunityパッケージというのは驚きだが、これは「LinuxerにとってコミュニケーションツールはDiscordが標準となっている」ということでもあるのだろう。

やはりSnappy版よりもフォントレンダリングをはじめ全体的に良いので、よかったと思う。 ちなみに、Discord自体、最近debパッケージだけでなくバイナリパッケージも配布している。