-- Views
June 01, 26
スライド概要
https://zenn.dev/yukiko_sapporo/articles/59e67faa3a509c
何卒よろしくお願い申し上げます。 一流のIT研修講師を目指し、日々研鑽を続けております。 本資料は外部公開用としてご提供するものです。
エンジニア勉強会 ジェネレーターツールの実装解説 新人向け(1行ずつ)+ 中堅向け(設計・UML) 題材:最小版ジェネレーター mini-gen(入力 → 生成 → 出力 + セルフテスト) WHY → WHAT → HOW / 人ではなく仕組み
全体像 ツールは「4つの役割」でできている ① ② ③ ④ 入力 INPUT 生成 GENERATE 出力 OUTPUT セルフテスト ユーザーが値を入れる(<input>) 入力から文字列を組み立てる 作った文字列を画面に出す 起動時に壊れていないか確認 うさうさラーメン店のたとえ:①注文を聞く → ②作る → ③ 出す → ④ 味見。当たり前の流れをコードに分けただけ。
第1部 新人向け:1行ずつ読む 役割で小さく分ける/外の入力は疑う/作ると出すを分ける/起動時に味見
新人向け|① 入力を読む val():入力欄の値を安全に読む function val(id){ var el = document.getElementById(id); // idで部品を取り出す return el ? el.value : ""; // 無ければ空文字(落ちない) } getElementById:idで部品を1つ探す 三項演算子 el ? A : B は「あればA、無ければB」 見つからなくてもエラーで止まらない。これが「落ちないコード」の第一歩。
新人向け|② 入力を疑う
esc():危険な文字を無害化(XSS対策)
function esc(s){
return String(s).replace(/[<>&]/g, function(c){
return {"<":"<", ">":">", "&":"&"}[c];
});
}
< > & を表示用の安全な表記に置き換える
合言葉:外から来た文字は、まず疑う。
例)<script> をそのまま画面に出すと危険 → <script> にして無害化
新人向け|③ 生成(心臓)
generate():入力から文章を組み立てる
function generate(inp){
var course = inp.course || "(コース名なし)"; // 未入力でも落ちない
var who = inp.audience ? inp.audience+"向け" : "受講者向け";
var md = "";
md += "# " + esc(course) + " 設計メモ\n\n"; // 見出し
md += "- 対象:" + esc(who) + "\n";
// 箇条書き
return md;
// 作るだけ。画面には触らない
}
大事:この関数は「作る」だけ。「出す」のは別の係(render)。役割を分けるとテストしやすい。
新人向け|④ 出力と流れ render() と doGenerate():出して、つなぐ function render(md){ document.getElementById("out").textContent = md; // 安全に表示 } function doGenerate(){ var inp = collectInput(); // ①集める if(!inp.course){ alert("..."); return; } // ②検証(早期リターン) render(generate(inp)); // ③生成 → ④表示 } 流れが「集める→検証 →生成 →表示」と一直線。読めば分かるのが良いコード。
新人向け|セルフテスト
起動時に「味見」を自動化する
T("生成に見出しが入る", function(){
return generate({course:"テスト"}).indexOf("# テスト") >= 0;
});
✓ PASS
generate() を実際に呼び、結果に見出し
が含まれるか確認。含まれれば合格。
人が毎回手で確認しなくて済む = 「人ではなく仕組み」。壊れたら起動時に赤く分かる。
第2部 中堅向け:設計の意図とUML 副作用を1か所に閉じ込める/純粋ロジックでテスト容易に/追加は「分岐+テスト」をセットで
中堅向け|関心の分離(SoC) 単方向の流れ:副作用は1か所に DOM入力 collectInput generate generate() は純粋関数に近い → 同じ入力なら同じ出力/DOMに副作用なし → テストが容易 render() だけが DOM に触れる → 副作用の出口を1か所に閉じ込めるのが保守性の肝 実物:generate() → generateMarkdown() の switch ルーター(16成果物へ振り分け) render DOM出力
中堅向け|クラス図(UML相当) 責務の地図:UI / Controller / Service / View / Test <<UI>> InputForm <<Model>> InputData reads #course / #audience #genBtn course: string audience: string click <<Controller>> doGenerate collectInput() 検証(早期return) <<Service>> Generator generate(inp): md esc(s): string <<Test>> SelfTest runSelfTests() T(name, fn) MVC+Service+Test。役割が一方向に流れ、依存が循環しない。 <<View>> render DOMに出力 textContentで安全表示
中堅向け|シーケンス(UML相当) 実行時の流れ:click から表示まで User → InputForm : click InputForm → doGenerate() doGenerate → collectInput() : 入力を集める collectInput → doGenerate : inp doGenerate : course空? ⇒ alert して return(早期リターン) doGenerate → generate(inp) : 文章を組み立て generate → doGenerate : md(Markdown) doGenerate → render(md) : 出力 render → DOM(out) : textContent をセット(表示) 生成(純粋)と表示(副作用)が分かれているので、各ステップを単体で検証できる。
中堅向け|テスト容易性 なぜこの分け方? → テストが書けるから 内蔵セルフテスト 起動時に自動実行。生成・反映・エスケープを関数で確認 商用テスト(jsdom) ブラウザ相当で検証:出力・CSV・XSS・DL・ページエラー0 出荷条件 5回連続オール緑(再現性のある安定) mini-gen の runSelfTests() は、その最小サンプル。観点を関数で持つ形は実物と同じ。
中堅向け|拡張の型 新機能を足す手順(破綻させない) 1 generate() に分岐を足す(実物:genXxx()+switchに1行) 2 入力UIを足す(collectInput に1項目) 3 セルフテストを1〜2個追加(生成される・反映される) 4 商用テストに観点追加 → 5回連続緑を確認 「分岐+テストをセットで足す」習慣が、16成果物まで破綻なく育てられた理由。
まとめ 新人 • • • • 役割で小さく分ける 外の入力は疑う(esc) 作ると出すを分ける 起動時に味見(テスト) 中堅 • • • • 副作用を1か所に閉じ込める 純粋ロジックでテスト容易に 追加は「分岐+テスト」をセットで 5回連続緑を出荷条件に 小さく理解して、実物で確認。mini-gen が読めれば実物(16成果物)は同じ型の拡大版。 面白きこともなき世を面白く