privateって書きたくない

まず前提として

  • publicにするべきものはpublicにするべき(公開されたAPIであるもの)
  • privateにするべきものはprivateにするべき(公開すると都合が悪いもの)

である。ところが、残念なことにこの二つの間には、どちらとも言いがたいものがかなりの分量あったりする*1。それをどうするべきなのかというと、簡単に言うと(理論上)二つの戦略を考えることができて*2

  • 良くわからないやつは全部publicにする
  • 良くわからないやつは全部privateにする

それで、僕は前者を選択しがちであるという話。もちろんケースバイケースで、ライブラリを作ってるときはできるだけprivateにするし、例えばattr_accessorattr_readerだったら後者を選ぶし、まあ基準としては曖昧なんだけど。あるいはObjective Cだと、ヘッダファイルを書くのが面倒なのでPrivateにする(宣言しない)という現象が発生するし、NSMutableArrayNSArrayであればNSArrayを選ぶ。


https://github.com/soutaro/unification_assertion/blob/master/lib/unification_assertion.rb

例えば、上のプログラムで言うと、UnificationAssertion#substituteなんかが、僕の言うところの「どちらとも言いがたいもの」である。

これはUnificationAssertionモジュールの外からは呼ばれないメソッドなのでprivateでも良い(公開されたAPIとは言えない)。コメントも書いてないので、実装した人(1年前の僕)もpublicなAPIであるとは認識していないことが推測できる。一方で、この操作はこのプログラムにおいてかなり本質的な操作なので、「実装の詳細なので隠蔽しなくてはいけない」と言うほどの物でもない。その辺を考えた結果「privateにするべきものでもないのでpublicのままにしておこう」となった。

ちなみに、例えば代入に対応するクラスを定義せずにHashをそのまま使っていたりメタ変数のためにシンボルを流用しているように、かなりプログラム全体のサイズを小さくすることにも注目して実装している。この「1ファイルで完結するくらいの小さなプログラム」であるという事実も、privateとpublicのどっちの戦略を採用するかにかなり強く影響している。


アプリケーションを書いているときに、こういう些末なことに頭を使いたくないという感覚も大きい。Webアプリケーションを書いてるときに、上のsubstituteメソッドの可視性について考えることには時間は使いたくない。

こういう、publicなものを好む嗜好というのは、僕の場合にはかなり最近に後天的に獲得された物である。ソフトウェアのモジュールがどのような関係を持っているべきなのか、というのは実際にはけっこう考えるのが楽しいことなので、放っておくと時間を忘れて(しょうもないことを)考え続けてしまう。そういう状況は避けるべきなので、些末なこと、つまり超重要ではないことに悩み始めたら考えるのを止めて、ひとまず最小のタイプ数で制約を満たすものを選ぶような、そういう思考を行うように教育した。ような気がする。

*1:理論上はないというのは理解できるけど、どこまで行ってもどこかに分水嶺があって、さらにその上にかかるものがあってしまうことは、それほど特殊な状況ではないと思う。

*2:別にもっと考えても良いけど。

それは話が逆になっている

種を明かせば簡単で、エンジニアはしょぼいアイディアでも自分で実装できちゃうというだけの話なのですよ、これ。実装を一人でできるので、アイディアの段階で枝刈りされることがなくて、結果として世の中に出てくるものの数で言えば「エンジニアが出したしょぼいアイディア」を実装したものが多くなる。一方で、エンジニアじゃない人はがんばってしょぼくないアイディアを考えて、アイディアがしょぼくないことをエンジニアに説得して頼み込んでやっと実装してもらえるので、明らかにしょぼいアイディアは世に出ないという。

アイディアのしょぼさと当たるかどうかには強い相関性はないというのが現在の常識だと思うので(適当に言ってるけど)、つまり実装できる人が、試行回数を最大化できる分、強いと言うことになる。がんばってしょぼくないアイディアを考えて枝刈りを避けないといけない人は大変ですねーという感じ。がんばってください。


技術的制約がどうのこうのとか、ユーザーベースでサービスを考えるとか、その辺はまあどっちでもいいや。僕も似たようなことを考えるし。

Cross Origin Resource Sharingのプリフライトの背景を理解する

Ajaxで他のホストのデータにアクセスできるようになるやつについてです。

この辺のドキュメントを読んでいても、どうも今ひとつ納得できなかったりすることがないかと思います。

  • シンプルなリクエストとプリフライトリクエストはなにが違うの?
  • まずシンプルなリクエストとプリフライトリクエストをなぜ区別しているの?
  • プリフライトリクエストは「実際のリクエストを送信しても安全かを確かめるために」あると書いてあるが、「安全な」リクエストと「安全でない」リクエストはどう違うの?

シンプルなリクエストとプリフライトリクエストの二つがあることはわかるけど、なぜ二つに分けないといけないのか良くわからないし、その定義もなんか無駄に複雑に見えて良く理解できない。なぜ application/x-www-form-urlencodedが特別扱いされているのか。そもそも、プリフライトリクエストとはなんのためのものなのかは、全然具体的に説明されていない。プリフライトリクエストではなにをすれば良いのだろう。何も考えずに200を返すだけで良いのだろうか。何らかの認証を行うのは、プリフライトリクエストのなかでやって良いのだろうか?キャッシュの時間はどの程度の長さにして良いのだろう?

まあ、こんな感じ。


さて、適当にぐぐってみると、Stack Overflowの記事が見つかります。

おお。これっぽい。

プリフライトリクエストの背景

簡単に言うと、

  • シンプルなリクエストは、元々Webブラウザで発行可能だったクロスドメインなリクエスト
    • これまでもできていたことなので、これからもできないといけない
    • Webアプリケーションの責任として、このようなリクエストはきちんと処理できなくてはいけない
  • プリフライトリクエストは、CORSによって発行可能になったリクエスト
    • この種類のリクエストが発行されたときにきちんと動作しないのは、Webアプリケーションの責任ではない
    • Webブラウザの側で、リクエストを発行して大丈夫であることを確認しないといけない

ということです。

シンプルなリクエストを良く見てみると、

  • カスタムヘッダなしのGETはこれまでもWebブラウザから発行できていたリクエストなので、特別な対応は必要ない → シンプルなリクエスト
  • 普通のformを通して他のドメインにPOSTできていたようなもの(カスタムヘッダがないとか、content-typeがapplication/x-www-form-urlencodedとか)は、これまでも普通にWebブラウザから発行できていたので、普通のWebアプリケーションは処理できるはず → シンプルなリクエスト

ということです。

一方でプリフライトリクエストはと言うと、それ以外のもので、つまりXHRとかを使わないとブラウザ内からは発行できないものです。CORSで初めて発行可能になったリクエストなので、Webサーバが対応しているかどうかを、確実に検査する必要があるわけですね。

サーバがCORSに対応しているかどうかって……Access-Control-Allow-Originと何が違うの?

一瞬混乱するかもしれませんが、違います。

Access-Control-Allow-Originは、リクエストが処理されて、ブラウザに返ってきたときに見えるやつなので、POSTみたいな冪等でないリクエストの場合にはやくにたちません。ブラウザに返事が返ってきた時点では、すでにPOSTが処理されてしまっていて、サーバのデータが変更されてしまっているわけです。

まとめ

  • プリフライトリクエストはWebアプリケーションがCORSに対応しているかどうかを確認するためのもの
  • 対応してるなら、深く考えずに200返しちゃって問題ない(多分)
  • キャッシュの時間も「やっぱりCORS止めます!」みたいなことがないなら、適当に決めれば良い(多分)

MacからDELLのディスプレイにきれいに画面を出力させる方法

MacでMini DisplayportからDELLのディスプレイに画面を出すと、とても汚いことがあります。これを直す方法。僕はU2713Hで気づきましたが、U2713HMとかU2711とかでも同じ問題が発生しているはずだし、他のディスプレイでも同じことが起きているかもしれない。

tl;dr

上のURLから、patch-edid.rbをダウンロードして実行すると、DisplayVendorID-10acみたいなディレクトリがすぐ下にできるので、それを/System/Library/Displays/Overridesにコピーして再起動する。再起動すると、DELLのディスプレイがちゃんと良い感じに表示されるようになっている。

私になにがおきたのか

DELLのU2713Hというディスプレイを買って、昨日無事に届いて、Macに接続したらすごい汚い表示で愕然とした、というのが発生した現象。シャープネスを強くするフィルタをかけたような表示。ディスプレイにはシャープネスを設定する機能があるので、それを初期値50を0にすると、まあなんとなくまともになった。

とりあえず、社内のMac何台かで試したけど、同じ表示だったので、初期不良を疑って、DELLに電話して、交換品を届けてもらったのが今朝。

Macにつないでみると、やっぱり汚い。念のため、Windowsにつないでみると普通にきれいに表示されている。これはおかしい。

というわけで、上のURLを見て、良い感じになったという話でした。DELLのディスプレイでも、U2713HMとU2711は、そこまで汚くなかったので、気づいていなかった。同じ問題は発生しているはずなので、試しにU2711のもRGBにしてみたけど、これできれいになったのかというとよくわからない……

さっきのURLの話の要約

  1. なんかわからんけど、DELLのディスプレイをMacでMini Displayportでつなぐとすごい汚い
  2. これはYCbCrというモードになってるからで、これをRGBにするべきである
  3. RGBにするには、なんか設定ファイルをアレすると良い
  4. U2713Hのやつはこれだぜー
  5. (ちょっと後で)このRubyスクリプトを実行すると、接続されてるディスプレイのパッチを作るようにしたよ!

開発のスループットを犠牲にしてレイテンシを向上させる

アジャイルな見積りと計画づくり ~価値あるソフトウェアを育てる概念と技法~

アジャイルな見積りと計画づくり ~価値あるソフトウェアを育てる概念と技法~

ソフトウェア製品の一部をまず完成させる。次に、別の一部を完成させる。もう一つ、別の一部を完成させる。こういうやり方を続けていくと、最初のほうに作った部分と最近になって作った部分のコードは、かなり違ったものになってしまう。最近になって必要になったモデルの機能は、最初のほうに書いたコードのデザインとうまく一体化していない。そこで、全体を直す作業が必要になる。これをリファクタリングと言う。一つ機能を追加するたびにリファクタリングする必要があるので、当然、開発のスループットは落ちる。それでも、一部ずつソフトウェアができあがっていくので、進捗を開発者以外とも共有しやすいし、できてから初めて気づいた問題にも素早く対処できる。実は必要がなかった機能を実装してしまう可能性は、少なくなる。スループットが落ちる代わりに、ソフトウェアの価値が発生し始めるまでのレイテンシは短い。

最初に全部を見渡して完璧な設計を導出できるなら、リファクタリングは必要がない。リファクタリングに必要な時間がいらなくなるので、スループットは向上する。一方で、完璧な設計にたどり着くまで、ソフトウェアの設計はなかなか進まない。レイテンシは悪化する。


もちろんビジネスの種類にはよるんだけど、ものすごいざっくりと言えば、原則としてスループットを捨ててレイテンシを取るほうが賢い戦略だと思う。少なくとも僕が生きている自分で適当なWebサービスを開発するような世界では、レイテンシ向上をデフォルトの戦略にするのが良いと思う。

ただし、当然だけど例外があって、レイテンシの向上でもたらせる利益によって帳消しにできないくらいにスループットの低下が激しい場合には、後者の戦略のほうが正しい。

レイテンシの向上が利益をもたらさないのはどういう場合かというと、スコープと期間があらかじめ厳密に定められていて、変更ができない場合である。スループットの低下が無視できないくらい大きいのはどういう場合かというと、リファクタリング(に相当する作業)のコストが大きい場合である。例えば、よく知らないけどハードウェアの開発とかそれに関するものとかだときっと大変でしょうね。

僕の感想だけど、どっちの条件についても緩和される方向に、人類が進化するのが正しいと思う。

inputでエンターキーを押しても、formのsubmitイベントが発生しないのはどうすれば良いの?

いつも忘れて混乱するので書いておく。細かいルールを解説したページを前見たんだけど見つけられない……

formの中にinput[type=submit]なinput要素がないと、テキストフィールドでエンターを押してもsubmitイベントが発生しない。見えないようにしたsubmitボタンを、

<input type="submit" style="float:left; opacity:0; height:1px; width:1px; margin:0" value="to fire submit event on enter">

とでも書いて、設置しておく。display:noneだと、やっぱりsubmitイベントが発生しない。


でこの辺に悩んだ結果「Enterキーが押されたらsubmit」とかやると、日本語変換の確定とかの思わぬタイミングでsubmitされて悲しい思いをすることになる。まあ日本人ならちょっと触った時点で気づくだろうから、ここに書いてもしょうがないだろうけど。アメリカ人は最後まで気づかないんだと思う。例:Pivotal TrackerのTask欄。

テキストフィールドの値の変更の監視にはkeyupイベントではなくてinputイベントを使おう

漢字が読めないがいこくじんやようちえんじにもひらがなならよめるね!アクセシブル!

という話ではなくて、keyupイベントを使ってテキストフィールドの変更を監視するとiOSでこんなことになります(多分、変換の確定がキーイベントじゃない)。左上の「かんじ」は本当は「漢字」になっててほしかった。(ちなみにコピペしたときも更新されずに問題が起きます。)

inputイベントを使うとこういう問題は発生しません。

先ほど指摘されましたので、ユビレジのkeyupはすべてinputに置き換わりました。漏れはないはず。