1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

業務の自動化診断アプリを素のJavaScriptで作る|判定は純粋関数、集計は6項目だけ、広告は別ファイル、テスト19万件

1
Last updated at Posted at 2026-10-19

はじめに

小さな会社・お店向けに、「どの業務を、どの方法で自動化すると良いか」を出す無料の診断アプリを作りました。業種と業務、頻度と時間、パソコンの環境を選ぶと、次の3つが出ます。

  • 年間で減らせる時間の目安
  • 方法の比較(Excelの関数・GAS・Power Automate・定型文など)
  • 進める順のチェックリスト(推進プラン)

日本版は40業種・86業務、英語版(米・英・加・豪など)は40業種・59業務です。フレームワークは使わず、素のJavaScript・GitHub Pages・Node.jsのテストだけで作っています。

この記事では、作るときに決めた4つの設計を紹介します。

  1. 判定ロジックを「画面から切り離した純粋関数」にする
  2. 匿名の集計は「送る項目を関数で固定」する
  3. 広告は「おすすめに影響しない」ことをコードで分ける
  4. データ全体をテストで総当たりする

※この記事とアプリは、AI(Claude)を活用して作成し、動作とテストを確認しています。

構成

dx/
  index.html      … CSPで外部への通信先を限定
  js/data.js      … 業種・業務・方法のデータ
  js/logic.js     … 判定ロジック(DOMを触らない)
  js/app.js       … 画面の組み立て
  js/ads.js       … 広告タグの取り込み
  js/config.js    … 集計の送信先
  test/test.js    … Node.jsで実行するテスト

1. 判定ロジックは純粋関数にする

logic.js はDOMに一切触れず、入力(選んだ業務・頻度・環境)を受け取って結果を返すだけにしました。たとえば年間時間の目安は、次のような関数です。

function round1(x) { return Math.round(x * 10) / 10; }
function annualHours(freq, min, rate) {
  var n = FREQ[freq] ? FREQ[freq].n : 0;
  return round1(n * min * rate / 60);
}

画面には「回数/年 × 1回の分数 × 削減率 ÷ 60」という式もそのまま表示します。目安の数字だけを出すより、どう計算したかが見えるほうが信用されると考えたからです。

ブラウザでもNodeでも読めるように、最後はこう書いています。

if (typeof module !== 'undefined') module.exports = API; else root.DX = API;

2. 匿名の集計は「送る項目」を関数で固定する

どの業種でどの業務に困っているかが分かると、次に何を作るべきかが分かります。そこで、選んだ内容だけを匿名で集計しています。

気をつけたのは、送る項目を1つの関数に閉じ込めることです。

function buildPayload(answers, diag, now) {
  var env = normalizeEnv(answers && answers.env);
  var d = diag || diagnose(answers);
  var tasks = d.items.map(function (it) { return it.task.id + ':' + it.freq + ':' + it.min; }).sort();
  var methods = d.items.map(function (it) { return it.task.id + ':' + it.rec.id; }).sort();
  return {
    industry: d.industry,
    tasks: tasks.join(','),
    env: ['sheet=' + env.sheet, 'pc=' + env.pc, 'm365=' + env.m365, 'code=' + env.code, 'budget=' + env.budget].join(';'),
    methods: methods.join(','),
    date: dayString(now instanceof Date ? now : new Date()),
    version: APP_VERSION
  };
}

業種・業務のID・環境・おすすめの方法・日付・バージョンの6項目だけで、自由記入の文章や名前・連絡先は入りません。日付は時刻を含めず日単位にしています。テストでは「この6項目以外のキーが無いこと」を確認しています。

送信はGoogle Apps Scriptのウェブアプリに fetch で投げています。

window.fetch(CFG.submitUrl.trim(), {
  method: 'POST', mode: 'no-cors', credentials: 'omit', cache: 'no-store',
  keepalive: true, referrerPolicy: 'no-referrer',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: DX.encodeForm(payload, CFG.fields)
}).catch(function () { /* 送れなくても画面はそのまま */ });
  • credentials: 'omit' でCookieを送らない
  • referrerPolicy: 'no-referrer' でどのページから来たかを送らない
  • 同じ内容は同じタブで二度送らない(内容のハッシュを sessionStorage に記録)
  • ?demo=1 のときは送らない

CSPの connect-src も、自サイトとApps Scriptのドメインだけにしています。仮にコードに誤りがあっても、それ以外の場所には通信できません。

3. 広告は「おすすめ」と別のファイルにする

結果画面には、会計ソフトなどのアフィリエイト広告を出しています。ここで大事なのは、広告が診断結果に影響しないことです。

  • logic.js は広告の設定ファイル(ads.json)も ads.js も読みません
  • 広告は、結果が出たあとに画面の別の枠へ入れるだけ
  • 広告タグは、a8.net の <a> <img> <br> だけを取り込み、それ以外は捨てる
var A8 = /^https:\/\/([a-z0-9-]+\.)*a8\.net\//i;
function okUrl(u) { u = String(u || '').trim(); return A8.test(u) ? u : null; }

タグ文字列を innerHTML で入れるのではなく、DOMParserで読んでから、許可した要素だけを作り直しています。リンクには rel="noopener sponsored" を付けます。

開いたときの全画面広告は1日1回だけ、×・Esc・外側のクリックで閉じられるようにしました。

4. データ全体をテストで総当たりする

業種・業務・方法のデータは手で書いているので、抜けや矛盾が入りやすい部分です。そこで、Node.jsだけで動く小さなテストを書きました(テストフレームワークは使っていません)。

function ok(cond, msg) { if (cond) pass++; else { fail++; console.log('FAIL: ' + msg); } }

確認している例です。

  • 業務IDと方法IDが重複していない
  • どの業務にも方法が2つ以上ある
  • 「はじめの一歩」は3〜5個
  • 削減率は 0〜90% の範囲
  • 販売中の商品を紹介する方法は、商品データが存在する
  • 環境(スプレッドシート・PC・Microsoft 365・コードを書けるか・予算)の全組み合わせで、どの業務にもおすすめが1つ以上出る

最後の「全組み合わせ」があるので、テストの件数は日本版で76,788件、英語版で191,412件になりました。件数が多くても、すべて純粋関数なので数秒で終わります。

公開は、テストが全部通ったときだけにしています。

node test/test.js | grep -q " 0 failed" && git push

(一度、テストが1件落ちたままpushしてしまったことがあり、それ以来この形にしています。)

まとめ

  • 判定は純粋関数にして、画面・広告・送信から切り離す
  • 集計で送る項目は1つの関数に固定し、テストで確認する
  • 広告はおすすめのロジックが読まないファイルに分ける
  • データは全組み合わせでテストし、通ったときだけ公開する

小さなアプリでも、この4つを決めておくと、あとから業種や業務を増やしても安心して直せました。よければ診断を試してみてください。

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?