- ブラウザURL入力
- DNS名前→IP
- ルータ経路選択
- ロードバランサ振り分け
- Nginx受け口
- アプリ処理今ここ
- DB保存
第14期はアプリの内側に引かれる線を扱います。1本目はその線が機械として何かを定義します。
まず結論
「分ける」の実体は、名前を実体に結び付ける表を分けることです。線を引いた側は名前だけを持ち、実体は向こう側にあります。
分け方の違いは、表引きが失敗する時期に現れます。実行前に失敗する線と走り出してから失敗する線があり、この差が境界の硬さです。
1行目が console.log、2行目で存在しない名前を import したファイルを Node で実行すると、1行目は印字されるでしょうか。
当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。
この期でいう「境界」を先に切っておく
第14期は「分ける」を扱います。ただし境界という語は、この研修で既に3つの意味で使われています。文字列を安全に埋め込む境界、資源を隔離する境界、特権が切り替わる境界です。
本期が扱うのはそのどれでもありません。片方を変えたとき、もう片方が影響を受けるかどうかを決める線です。以後これを変更の境界と呼びます。
この線の実体は抽象的ではありません。第7期『モジュール — import は何をしているか』で見たとおり、import { render } from "./view.js" と書いたとき render は自分のファイルには無く、別のファイルにある実体を指すだけの名前でした。名前だけを持ち、実体を向こう側に置く。これが線を引くということです。
だから「分けた」かどうかは図では判定できません。判定できるのは名前を実体に結び付ける表が分かれているかです。
失敗が評価の前に起きる線
既習レッスンが実測つきで示すとおり、import の表引きはコードが1行も走る前に終わっています。仕様は2つの段を定めています。
Link が依存を辿って解決する段、Evaluate が走らせる段で、Link の完了が Evaluate の前提です。名前がずれたファイルは起動しません。
// main.mjs の1行目は console.log("LINE 1 RAN")file:///w/m/main.mjs:2import { absent } from "./lib.mjs";^^^^^^SyntaxError: The requested module './lib.mjs' does not provide an export named 'absent'at #asyncInstantiate (node:internal/modules/esm/module_job:455:21)(以下略)exit=1
LINE 1 RAN が印字されていません。 名前を存在するものに変えただけの版は LINE 1 RAN まで出して exit=0 で走りきりました。差は1語で、片方は1行も走っていません。
存在しない名前を import したファイルで、1行目の console.log が印字されないのはなぜですか。
失敗の時期が、線の性質を決める
ここまでは既習の読み直しです。本回が足すのは、表引きが失敗する時期は線ごとに違うという点です。
表引きの結果は、どの線でも解決できるかできないかの2つです。違うのはいつそれが分かるかです。
- ・硬い・柔らかいは良し悪しではなく、失敗が分かる時期の呼び分けです
- ・同じ名前解決でも、DNS・仮想アドレス変換・URL の照合は別の時期に起きます
硬い線では、名前を変えた側が向こう側を巻き込んで止めます。止まるのは困りますが、ずれは誰の目にも明らかです。 柔らかい線では名前がずれていても全体は動き続け、かわりにずれは特定の経路を通った人にしか見えません。
失敗が走り出してから起きる線
URL も名前です。/orders/42 に対応する処理は、書いた側のファイルの中にはありません。では、対応が無かったときは何が起きるか。
SERVER: listening### 既知のパス /knownSERVER: handler entered for /knownHTTP/1.1 200 OKok### 存在しないパス /no-such-thingSERVER: handler entered for /no-such-thingSERVER: no route matched /no-such-thing -> 404HTTP/1.1 404 Not Foundwget: server returned error: HTTP/1.1 404 Not Found
肝心なのは SERVER: handler entered for /no-such-thing が印字されていることです。存在しない名前を渡されても、サーバのコードは走り出しています。 走った結果として照合が外れ、404 を組み立てました。import の側では1行も走っていませんでした。
なお、どのハンドラを選ぶかの規則は HTTP の規格が定めておらず実装ごとに違います(第7期『1リクエストは1本のバイト列 — パースしてから「ルーティング」する』)。上の「照合して落ちた」はこのサーバの実装の挙動であって規格の要求ではありません。比べているのは規格の厳しさではなく、失敗が判明する時期です。
存在しない URL を取りに行くと、サーバ側で「ハンドラに入った」というログが出てから404が返りました。何を示していますか。
import の名前(硬い線)
存在しない名前を取り出そうとすると、依存を解決する段で失敗します。この段は評価より前にあるため、1行目にすら到達しません。名前を1語変えるだけで、走るか走らないかが切り替わります。
import した名前 1行目の印字 終了コードpresent(存在する) 出る 0absent(存在しない) 出ない 1
URL の名前(柔らかい線)
存在しない URL を取りに行くと、サーバのコードは走り出してから照合に失敗します。ハンドラに入ったログが先に出て、その後で不一致が判明します。名前がずれていても、サーバ自体は動き続けます。
渡したパス ハンドラに入る 応答/known 入る 200/no-such-thing 入る 404
片方は1行も走らず、片方は走り出してから失敗しました。2つに共通する構造は何でしょうか。
「名前」と「実体」がどちら側にあるかを、両方で並べて考えてみてください。違うのは1点だけです。
この章のまとめ
- 本期でいう変更の境界は、名前を実体に結び付ける表を分けた場所。エスケープ・隔離・特権の「境界」とは別の意味。
- 線を引くとは名前だけを手元に置き、実体を向こう側に置くこと。分けたかは図ではなく、表が分かれているかで決まる。
importは表引きがEvaluateより前のLink段にあるので、名前がずれたファイルは1行も走らない。- URL は照合が実行中にあるので、存在しない名前でもサーバのコードは走り出してから404 を組み立てる。
- 同じ「名前が解決できない」でも失敗が判明する時期が違う。この差が線の硬さで、良し悪しの尺度ではない。
- 「分けたので疎になった」は、名前を変えたときに失敗がいつ分かるかに言い直して検証する。
自分の現場で確かめる
読んだだけでは身につきません。手元の環境で実際に見てみてください。
理解度チェック
読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。
このレッスンでいう「境界」を機械の言葉で言い換えるとどうなりますか。
用語集(4語)
- 変更の境界
- 本教材が第14期で使う語。名前を実体に結び付ける表を分けた場所。片側を変えたとき、もう片側が影響を受けるかがこの線で決まる。エスケープ・隔離・特権の文脈の「境界」とは別の意味。
- 名前解決(表引き)
- 書かれた名前を実体に結び付ける操作。import、URL とハンドラの対応、DNS、仮想アドレスの変換など、層は違っても同じ形をしている。
- Link / Evaluate
- ECMAScript がモジュール処理に定める2つの段。Link が依存を解決する段、Evaluate が走らせる段。仕様は Link の完了を Evaluate の前提としている。
- 硬い線 / 柔らかい線
- 本教材の呼び分け。名前のずれが評価の前に判明するものを硬い線、走り出してから判明するものを柔らかい線と呼ぶ。良し悪しではなく時期の違いを指す。