L44:JavaScript応用(状態遷移表=State Machine)+非同期(擬似API)+リトライ/キャンセル+ログ設計(TRAINING ONLY/流用禁止)
【重要:本レッスンは訓練専用】
- このレッスンで作る「サンプルHTML/CSS/JS」「状態遷移表」「擬似API」「リトライ/キャンセル実装」「ログ(イベント記録)」等は訓練専用です。通常業務でそのまま使用することは禁止します(コピペ流用禁止)。
- 実サイト更新・実公開・実リポジトリ反映は禁止:本番環境/実CMS/実タグ/実URLには触れません(ローカルファイル・ダミーのみ)。
- 実データ・個人情報・未公開情報は禁止(実案件名、実ページID、実在のSKU/取引先/条件などは書かない)。
- 本番で必要になった場合は、訓練成果物を流用せず、情報を取り直し、別途レビュー/承認を経て新規作成してください。
L43で学んだ state → render → event → guard の最小構造を、非同期(擬似通信)でも破綻しない形に拡張します。
ポイントは「クリックイベント」ではなく、状態遷移(State Machine)を先に固定し、成功/失敗/空/キャンセル/タイムアウトを“仕様として再現可能”にすることです。
このページの使い方
1レッスン=1LP(1ページ)です。上から順に当日の時間割に沿って進めてください。
各項目の冒頭に EC事業部/文房具カフェ事業部・準備室 の実施時間を併記しています。
※本レッスンはダミーのみで行います(実データ・個人情報・未公開情報は入力しない)。
このレッスンの狙い(到達状態)
- 非同期UIを「イベントの寄せ集め」ではなく、状態遷移(state machine)として説明できる
- loading/error/empty/canceled/timeout を、再現条件付きで実装できる(ランダム禁止推奨)
- 二重実行・競合(古いレスポンスで上書き)を、requestId等のガードで止められる
- リトライ(手動/自動)と復帰導線を持たせ、壊れても戻れるUIにできる
- イベントログ(いつ何が起きたか)を残し、デバッグ/検収に耐える形にできる
受講ルール(共通)
- 実データ禁止:実URL、実ページID、実アカウント、実顧客情報、未公開企画などは禁止
- 訓練成果物の流用禁止:訓練で作ったコード/要件/テンプレを通常業務へコピペしない
- 通常業務をしない:訓練日は講義・演習・レビュー・理解度確認に専念する
- 命令系統の具体化をしない:役割は「作成担当」「レビュー担当」「承認担当」など抽象ロール
- 相互レビュー2件以上:前日までの他者成果物に2件以上コメント(本ページの観点を使用)
今日の目標(できた範囲でOK)
受講者のレベル差があるため、強制の提出物は設けません。今日の目標を選び、できた範囲を「今日進めたこと」に記録してください。
- (A)TRN-JS44 Specヘッダ(v0.1):状態/例外/再現条件/完了条件を固定
- (B)状態遷移表(v0.1):状態×イベント×ガード×副作用(Side Effect)を表にする
- (C)擬似API+requestIdガード:競合(古い結果の上書き)を防ぐ
- (D)復帰導線:retry/cancel/入力修正の動線を作る(error/timeout/empty)
- (E)イベントログ(v0.1):時系列で追えるログ(再現→原因仮説→修正確認)を残す
結論:非同期UIは「状態遷移表」がないと壊れる
ありがちな事故(非同期で一気に増える)
- 二重実行:loading中の連打で同じ処理が2回走る
- 競合:Aの結果が遅れて返ってきて、Bの結果を上書きする(順序問題)
- 復帰できない:error/timeout/empty から戻るボタンがない
- 原因不明:ログがなく、いつ何が起きたか追えない
今日の最小ルール(これで壊れにくい)
- 状態は列挙する(idle/loading/success/empty/error/canceled/timeout)
- 状態遷移表で「起きうる遷移だけ」を許可する
- requestId(世代)で古い結果を捨てる(競合ガード)
- 復帰導線を必ず置く(retry / 条件変更 / close)
- ログを残す(デバッグと検収の共通言語)
標準テンプレ(TRAINING ONLY)
A) TRN-JS44 Specヘッダ(v0.1)
【TRN-JS44 Specヘッダ(v0.1:訓練専用・流用禁止)】
Spec-ID:TRN-JS44
版:v0.1
状態:DRAFT / REVIEW / FINAL(訓練内)
UI対象(ダミー):
* 例:リスト取得(擬似API)+フィルタ+再試行
目的(1行):
* 例:非同期UIを「状態遷移表」で固定し、競合・二重実行・復帰不能を防ぐ練習
範囲(やる/やらない):
* やる:state machine設計/擬似API/retry/cancel/ログ(ダミー)
* やらない:実API接続、実サイト更新、実公開、実運用データ反映
状態(この中から使う):
* idle / loading / success / empty / error / canceled / timeout
再現条件(必須:ランダム禁止推奨):
* success:条件A(例:カテゴリ=all)
* empty:条件B(例:カテゴリ=empty)
* error:条件C(例:失敗スイッチON)
* timeout:条件D(例:遅延スイッチON+タイムアウト短)
* canceled:条件E(例:loading中にCancel押下)
例外(最低3つ):
* 二重実行(loading中の連打)
* 競合(古いレスポンスの上書き)
* 復帰不能(error/timeout/emptyから戻れない)
ログ(残すもの):
* 時刻(相対でOK)
* イベント名(FETCH_START / FETCH_OK / FETCH_FAIL 等)
* requestId
* 状態(from→to)
* 入力条件(ダミー)
* エラーメッセージ(あれば)
完了条件(採点可能):
* 状態遷移表があり、実装がそれに従っている
* requestId等で競合が防げる
* retry/cancelが機能し、復帰できる
* ログで再現→原因→確認が追える
* 実データ混入がない(訓練専用の明記あり)
B) 状態遷移表(State Machine:最小形)
※「イベントが来たら何が起きるか」を表に固定します。
| From(状態) | Event(入力) | Guard(許可条件) | To(状態) | Side Effect(副作用) | ログ |
|---|---|---|---|---|---|
| idle | FETCH_CLICK | 常にOK | loading | requestId++ / 擬似API開始 | FETCH_START |
| loading | FETCH_OK | requestId一致 | success / empty | データ反映 | FETCH_OK |
| loading | FETCH_FAIL | requestId一致 | error / timeout | エラー表示 | FETCH_FAIL |
| loading | CANCEL_CLICK | 常にOK | canceled | 以後の結果を無視(requestId更新) | FETCH_CANCEL |
| error/timeout/empty | RETRY_CLICK | 常にOK | loading | 再試行 | FETCH_RETRY |
| success/empty/error/timeout/canceled | RESET_CLICK | 常にOK | idle | 初期化 | RESET |
ダミー課題(どれか1つでOK)
JS-44A(易):リスト取得+empty+retry(競合は扱わない)
状況(ダミー):
- 「読み込み」ボタンで擬似データを表示
- empty条件がある(カテゴリ=empty)
要求:
* 状態:idle/loading/success/empty/error
* error/emptyの復帰導線(retry or reset)
* ランダム禁止(再現条件を固定)
JS-44B(中):競合ガード(requestId)+cancel
状況(ダミー):
- フィルタを切り替えて連続で読み込み
- 先に押した方の結果が遅れて返ってくる場合がある
要求:
* requestIdで古い結果を捨てる(上書き防止)
* cancelでloadingを止める(以後の結果を無視)
JS-44C(難):timeout(擬似)+復帰(retry)+ログ強化
状況(ダミー):
- 「遅延スイッチON」で擬似応答が遅くなる
- 「タイムアウト短」でtimeoutにする
要求:
* timeout状態を持つ(message/復帰導線)
* ログに requestId / 状態遷移 / 条件 を残す
サンプル(訓練用:JS-44B/C相当)
※このサンプルは訓練用の型です。実務に流用しないでください。
1) HTML(index.html想定:抜粋)
<!-- TRAINING ONLY: TRN-JS44(流用禁止) -->
<div class="trn">
<h2>TRN-JS44:非同期UI(擬似API)+状態遷移+ログ(ダミー)</h2>
※実データ禁止。実API接続禁止。これは訓練用ダミーです。
“` <label><input id=”failSwitch” type=”checkbox”> 失敗にする(error)</label> <label><input id=”slowSwitch” type=”checkbox”> 遅延にする(timeout再現用)</label> <button id=”fetchBtn” type=”button”>読み込み(ダミー)</button> <button id=”cancelBtn” type=”button”>Cancel</button> <button id=”retryBtn” type=”button”>Retry</button> <button id=”resetBtn” type=”button”>Reset</button> “`
イベントログ(訓練用)
2) JS(script.js想定:抜粋)
/* TRAINING ONLY: TRN-JS44(流用禁止) */
const $ = (sel) => document.querySelector(sel);
const els = {
category: $("#category"),
failSwitch: $("#failSwitch"),
slowSwitch: $("#slowSwitch"),
fetchBtn: $("#fetchBtn"),
cancelBtn: $("#cancelBtn"),
retryBtn: $("#retryBtn"),
resetBtn: $("#resetBtn"),
statusBar: $("#statusBar"),
statusLive: $("#statusLive"),
errorBox: $("#errorBox"),
list: $("#list"),
logBox: $("#logBox"),
};
const state = {
status: "idle", // idle | loading | success | empty | error | canceled | timeout
data: [],
errorMessage: "",
requestId: 0, // 送信した世代
activeRequestId: 0, // 画面が受理する世代(競合ガード)
lastQuery: { category: "all", fail: false, slow: false },
log: [],
t0: Date.now(),
};
function nowMs() {
return Date.now() - state.t0;
}
function addLog(type, meta = {}) {
const item = {
t: `${nowMs()}ms`,
type,
requestId: state.activeRequestId,
status: state.status,
meta,
};
state.log.push(item);
// 長くなりすぎ防止(訓練用)
if (state.log.length > 80) state.log.shift();
}
function setLive(text) {
els.statusLive.textContent = text;
}
function render() {
const isLoading = state.status === "loading";
els.fetchBtn.disabled = isLoading;
els.cancelBtn.disabled = !isLoading;
els.retryBtn.disabled = isLoading || !(state.status === "error" || state.status === "timeout" || state.status === "empty");
els.resetBtn.disabled = isLoading;
// ステータス文言
const s = state.status;
let msg = "";
if (s === "idle") msg = "待機中(ダミー)";
if (s === "loading") msg = "読み込み中…(ダミー)";
if (s === "success") msg = `表示中(${state.data.length}件:ダミー)`;
if (s === "empty") msg = "該当なし(empty:ダミー)";
if (s === "error") msg = "失敗(error:ダミー)";
if (s === "timeout") msg = "タイムアウト(ダミー)";
if (s === "canceled") msg = "キャンセル済み(ダミー)";
els.statusBar.textContent = msg;
// エラー表示
if (s === "error" || s === "timeout") {
els.errorBox.hidden = false;
els.errorBox.textContent = state.errorMessage || "エラー(ダミー)";
setLive(`エラー:${state.errorMessage || "ダミー"}`);
} else {
els.errorBox.hidden = true;
els.errorBox.textContent = "";
}
// リスト表示
els.list.innerHTML = "";
if (s === "success") {
for (const x of state.data) {
const li = document.createElement("li");
li.textContent = x;
els.list.appendChild(li);
}
}
// emptyは説明文だけ(リスト空のまま)
if (s === "empty") {
// 何もしない(statusBarが表示される)
setLive("該当なし(ダミー)");
}
if (s === "loading") setLive("読み込み中(ダミー)");
// ログ表示
els.logBox.textContent = state.log
.map((r) => `${r.t}\t${r.type}\t(id=${r.requestId})\tstatus=${r.status}\t${JSON.stringify(r.meta)}`)
.join("\n");
}
// 擬似API(外部通信禁止:setTimeoutのみ)
function fakeApi(query) {
return new Promise((resolve, reject) => {
const baseDelay = query.slow ? 1800 : 500; // 遅延スイッチでtimeout再現しやすく
setTimeout(() => {
if (query.fail) {
reject(new Error("擬似失敗(failSwitch=ON)"));
return;
}
if (query.category === "empty") {
resolve([]);
return;
}
if (query.category === "few") {
resolve(["Dummy Item A", "Dummy Item B"]);
return;
}
resolve(["Dummy Item 01", "Dummy Item 02", "Dummy Item 03"]);
}, baseDelay);
});
}
// タイムアウト(擬似):一定msで失敗にする(Promise.race)
function withTimeout(promise, timeoutMs) {
return Promise.race([
promise,
new Promise((_, reject) => {
setTimeout(() => reject(new Error(`擬似タイムアウト(${timeoutMs}ms)`)), timeoutMs);
}),
]);
}
function getQuery() {
return {
category: els.category.value,
fail: !!els.failSwitch.checked,
slow: !!els.slowSwitch.checked,
};
}
async function startFetch(isRetry = false) {
// Guard:二重実行防止
if (state.status === "loading") return;
const query = state.lastQuery = getQuery();
state.status = "loading";
state.errorMessage = "";
state.data = [];
state.requestId += 1;
state.activeRequestId = state.requestId;
addLog(isRetry ? "FETCH_RETRY" : "FETCH_START", { query });
render();
const myId = state.activeRequestId;
try {
// timeoutは固定値(訓練):slow ONのときtimeoutしやすく
const timeoutMs = query.slow ? 800 : 2000;
```
const data = await withTimeout(fakeApi(query), timeoutMs);
// 競合ガード:古い結果は捨てる
if (myId !== state.activeRequestId) {
addLog("FETCH_IGNORED", { reason: "stale-response", myId });
return;
}
state.data = data;
state.status = data.length ? "success" : "empty";
addLog("FETCH_OK", { count: data.length });
render();
```
} catch (e) {
if (myId !== state.activeRequestId) {
addLog("FETCH_IGNORED", { reason: "stale-error", myId });
return;
}
const m = (e && e.message) ? e.message : "不明なエラー(ダミー)";
state.errorMessage = m;
state.status = m.includes("タイムアウト") ? "timeout" : "error";
addLog("FETCH_FAIL", { message: m });
render();
```
// エラー時の最小復帰:フォーカスをretryへ(訓練)
els.retryBtn.focus();
```
}
}
function cancelFetch() {
if (state.status !== "loading") return;
// 「以後の結果を無視」するためにactiveRequestIdを進める
state.activeRequestId = state.requestId + 1;
state.requestId = state.activeRequestId;
state.status = "canceled";
addLog("FETCH_CANCEL", {});
render();
els.fetchBtn.focus();
}
function retryFetch() {
if (!(state.status === "error" || state.status === "timeout" || state.status === "empty")) return;
startFetch(true);
}
function resetAll() {
if (state.status === "loading") return;
state.status = "idle";
state.data = [];
state.errorMessage = "";
state.lastQuery = { category: "all", fail: false, slow: false };
addLog("RESET", {});
render();
els.fetchBtn.focus();
}
els.fetchBtn.addEventListener("click", () => startFetch(false));
els.cancelBtn.addEventListener("click", cancelFetch);
els.retryBtn.addEventListener("click", retryFetch);
els.resetBtn.addEventListener("click", resetAll);
// Enterでも読み込み(訓練:操作性)
document.addEventListener("keydown", (ev) => {
if (ev.key === "Enter" && document.activeElement === els.fetchBtn) {
ev.preventDefault();
startFetch(false);
}
});
render();
品質ゲート(OK/差戻し/要相談:v1.0)
| 判定 | 基準 | 次アクション | 記録 |
|---|---|---|---|
| OK | 状態遷移表があり、loading/error/empty/canceled/timeoutが再現条件付きで動く。requestIdで競合が止まり、retry/resetで復帰できる。ログで追える。 | 次工程(検収観点/要件整合)へ | 結果=OK、根拠(再現条件とログ) |
| 差戻し | 状態が増えたのに表がない/競合が止まらない/復帰導線がない/再現条件がランダムで検収不能/ログがない | v+0.1で修正(不足を埋める) | 差戻し理由(どこ/なぜ/完了条件) |
| 要相談(停止) | 実データ混入、実API/実サイト更新を誘導、通常業務に流用する意図がある、権利/法務/安全に触れる断定がある | 作業停止→相談(抽象ルート) | 停止理由、混入箇所、再開条件 |
ChatGPTに投げるプロンプト(コピペ用)
1) 状態遷移表(State Machine)を作る
【L44 プロンプト①:状態遷移表(訓練用)】
前提(安全):
* 教育訓練用ダミー。実データ・実URL・未公開情報は禁止。
* 訓練成果物は流用禁止。実API接続はしない(setTimeout等の擬似のみ)。
入力:
* L42で作ったUI要件(State表+例外表+A11y要件)
* 選んだ課題(JS-44A/B/C)
出力形式(必須):
* 状態一覧(enum)
* イベント一覧
* 状態遷移表(From/Event/Guard/To/SideEffect/Log)
* 再現条件(success/empty/error/timeout/canceled)
2) requestIdガード+擬似APIの骨格を作る
【L44 プロンプト②:非同期の骨格(訓練用)】
前提:
* 外部通信禁止(fetchしない)。擬似APIはPromise+setTimeoutのみ。
* stateとrenderを分け、状態遷移表どおりに実装する。
* 競合防止:requestId(世代)で古いレスポンスを無視する。
入力:
* あなたの状態遷移表
* UI要件(抜粋)
出力形式:
* HTML(ボタン/フィルタ/メッセージ/ログ領域)
* JS(state/render/event/guard/requestId/擬似API)
* TRAINING ONLY/流用禁止の明記
3) 復帰導線(retry/cancel/timeout)とログを強化する
【L44 プロンプト③:復帰+ログ(訓練用)】
入力:
* あなたのHTML/JS
* L44の品質ゲート
出力:
* 足りない状態(timeout/canceled等)があれば追加案
* 復帰導線(retry/reset/cancel)を仕様→実装で揃える修正
* ログ項目(時刻/イベント/requestId/状態/条件/結果)を満たす実装案
* 自己判定(OK/差戻し/要相談)と理由
相互レビュー観点(L44専用)
- 訓練専用の担保:流用禁止が明記され、実在情報が混入していないか
- 状態遷移表:表があり、実装が表どおりに見えるか(増えた状態を放置していないか)
- 競合・二重実行:requestId等で競合が止まり、loading中の連打が止まるか
- 復帰導線:error/timeout/empty/canceled から戻れるか
- 再現性:success/empty/error/timeout が再現条件付きで検収できるか(ランダム禁止推奨)
- ログ:何が起きたか追えるログになっているか(時刻・id・状態・条件)
レビューコメントテンプレ(コピペ用)
【L44 相互レビューコメント】
対象(TRN-JS44):
版:
1. 良い点(1つ):
*
2. 状態遷移表はある?実装は従ってる?
* OK / 要改善
不足(1つ):
*
3. 競合/二重実行は止められる?
* OK / 要改善
再現手順(問題が出るなら):
*
4. 復帰導線(retry/cancel/timeout)はある?
* OK / 要改善
不足(1つ):
*
5. ログで追える?(時刻/イベント/requestId/状態/条件)
* OK / 要改善
不足(1つ):
*
6. 次の一手(v+0.1で直すなら):
*
本日の流れ(タイムライン)
目次(クリックで移動)
- 出席・当日選択カリキュラムの内容確認
- 時間差相互評価(2件以上コメント)
- 休憩
- 自分への受領レビュー確認・改善方針メモ
- L44 レクチャー本編(講師説明・質疑込み)
- 昼休憩
- 個人演習①:Spec→状態遷移表→骨格実装
- 休憩
- 個人演習②:競合/復帰/ログ強化→v+0.1改善
- 休憩
- 復習:共有できる形に整形(できた範囲でOK)
- 質問・コメント・感想の提出(指定スレッド)
1) 出席・当日選択カリキュラムの内容確認
【実施時間】
| 対象 | 時間 |
|---|---|
| EC事業部 | 08:30–09:10 |
| 文房具カフェ事業部/準備室 | 10:00–10:40 |
この時間にやること
- 今日の目標(A〜E)を選ぶ(できた範囲でOK)
- ダミー課題(JS-44A/B/C)を1つ選ぶ
- 注意点を1行で書く(例:状態遷移表から書く/競合を止める/流用禁止)
セルフ棚卸し(コピペ用)
【L44 セルフ棚卸し】
1) 今日選ぶダミー課題:
- JS-44A / JS-44B / JS-44C
2. 自分が弱い点(1つ):
* (例:状態の洗い出し/競合ガード/復帰導線/ログ設計)
3. 今日の目標(1行):
*
2) 時間差相互評価(前日までの他者成果物に2件以上コメント)
【実施時間】
| 対象 | 時間 |
|---|---|
| EC事業部 | 09:10–10:00 |
| 文房具カフェ事業部/準備室 | 10:40–11:30 |
この時間にやること
- 前日までの他者成果物を2件選び、L44レビュー観点でコメントする
- 「動いてる」より、状態遷移表・再現条件・復帰・ログを見る
3) 休憩
【実施時間】
| 対象 | 時間 |
|---|---|
| EC事業部 | 10:00–10:15 |
| 文房具カフェ事業部/準備室 | 11:30–11:45 |
休憩:学習作業なし
4) 自分への受領レビュー確認・改善方針メモ(講師レビュー含む)
【実施時間】
| 対象 | 時間 |
|---|---|
| EC事業部 | 10:15–10:45 |
| 文房具カフェ事業部/準備室 | 11:45–12:15 |
改善方針メモ(コピペ用)
【L44 改善方針メモ】
受領した指摘の要点(最大3つ):
1)
2)
3)
## 直す理由(状態遷移が曖昧/競合が止まらない/復帰導線不足/ログ不足 等):
直し方(どこを改善する?):
* Spec(再現条件/完了条件):
* 状態遷移表:
* 競合/二重実行ガード:
* 復帰導線(retry/cancel/reset):
* ログ(項目/粒度):
今日の最優先ルール(1行):
*
5) 当日選択カリキュラム実施:L44レクチャー本編(講師説明・質疑込み)
【実施時間】
| 対象 | 時間 |
|---|---|
| EC事業部 | 10:45–12:00 |
| 文房具カフェ事業部/準備室 | 12:15–13:30 |
ここからが「読む/聞く」パート
非同期UIは「頑張って書く」ほど事故ります。
先に状態遷移表で“起きうること”を固定し、実装は表に従って作ります。
午後は、ダミー課題を選び、競合/復帰/ログまで揃えます。
6) 昼休憩
【実施時間】
| 対象 | 時間 |
|---|---|
| EC事業部 | 12:00–13:00 |
| 文房具カフェ事業部/準備室 | 13:30–14:30 |
昼休憩:学習作業なし
7) 個人演習①:Spec→状態遷移表→骨格実装
【実施時間】
| 対象 | 時間 |
|---|---|
| EC事業部 | 13:00–14:30 |
| 文房具カフェ事業部/準備室 | 14:30–16:00 |
演習①のやり方(必須)
- TRN-JS44 Specヘッダ(v0.1)を埋める(再現条件・完了条件まで)
- 状態遷移表(v0.1)を作る(From/Event/Guard/To/SideEffect/Log)
- 骨格実装:state/render/event/guard を作る
- 擬似API(Promise+setTimeout)を入れる(外部通信禁止)
提出用フォーマット(演習①:コピペ用/できた範囲でOK)
【L44 演習① 提出(できた範囲でOK)】
Spec-ID:TRN-JS44
ダミー課題:
## (1) Specヘッダ(v0.1):
## (2) 状態遷移表(v0.1):
(3) 骨格実装メモ(state/render/event/guard):
*
8) 休憩
【実施時間】
| 対象 | 時間 |
|---|---|
| EC事業部 | 14:30–14:45 |
| 文房具カフェ事業部/準備室 | 16:00–16:15 |
休憩:学習作業なし
9) 個人演習②:競合/復帰/ログ強化→v+0.1改善
【実施時間】
| 対象 | 時間 |
|---|---|
| EC事業部 | 14:45–15:45 |
| 文房具カフェ事業部/準備室 | 16:15–17:15 |
演習②のやり方(必須)
- 競合を再現し、requestId等で止める(古い結果を捨てる)
- error/timeout/empty/canceled から復帰できる導線(retry/reset)を揃える
- ログ(時刻/イベント/requestId/状態/条件/結果)を満たす
- 品質ゲートで自己判定(OK/差戻し/要相談)し、差戻しならv+0.1で直す
提出用フォーマット(演習②:コピペ用/できた範囲でOK)
【L44 演習② 提出(できた範囲でOK)】
Spec-ID:TRN-JS44
## (1) 競合/二重実行の再現手順:
## (2) ガード実装(requestId等):
## (3) 復帰導線(retry/cancel/reset):
## (4) ログ(抜粋:3〜8行):
(5) 品質ゲート判定:
* 判定(OK/差戻し/要相談):
* 根拠(1行):
(6) 任意:v+0.1の改善ログ(何を/なぜ/どう直す):
*
10) 休憩
【実施時間】
| 対象 | 時間 |
|---|---|
| EC事業部 | 15:45–16:00 |
| 文房具カフェ事業部/準備室 | 17:15–17:30 |
休憩:学習作業なし
11) 復習:共有できる形に整形(できた範囲でOK)
【実施時間】
| 対象 | 時間 |
|---|---|
| EC事業部 | 16:00–16:30 |
| 文房具カフェ事業部/準備室 | 17:30–18:00 |
最終チェック(コピペ用)
【L44 最終チェック】
- 訓練専用(流用禁止)が明記されている
- 実データ/実URL/実APIが混入していない
- 状態遷移表があり、実装が従っている
- success/empty/error/timeout/canceled が再現条件付き
- requestId等で競合が止まる
- retry/reset/cancelで復帰できる
- ログで追える(時刻/イベント/requestId/状態/条件/結果)
12) 講師への質問・コメント・感想の提出(指定スレッド)
【実施時間】
| 対象 | 時間 |
|---|---|
| EC事業部 | 16:30–17:00 |
| 文房具カフェ事業部/準備室 | 18:00–18:30 |
提出先(参考)
EC事業部・文房具カフェ事業部:ChatWork の指定スレッド/準備室:Slack の指定スレッド
提出テンプレ(コピペ用)
【L44 提出(本人レポート)】
1. 今日の学習内容(要約:3行)
*
*
*
2. 今日進めたこと(TRAINING ONLY:流用禁止)
* 選んだ課題(JS-44A/B/C):
* Specヘッダ:
* 状態遷移表:
* 競合ガード(requestId):
* 復帰導線(retry/cancel/reset):
* ログ(満たした項目):
* 品質ゲート判定:
3. 一番工夫した点(1つ)
-(例:状態遷移表から書いた/競合再現→requestIdで止めた/timeout復帰を作った 等)
理由:
*
4. 次に改善したい点(1つ)
*
## 理由:
5. 質問(最低1つ)
*