← Systems Foundations

TOOLING FOUNDATION · 80

Configuration / Environments:Code 不該靠 Hard-code 才知道自己在哪裡

Dev、test、staging、production 常使用不同 API URL、database、log level、credentials。好的設計把「會隨環境改變的值」明確放在 configuration boundary,而不是散落在 source code。

Learning outcomes

1. Hard-code 的問題

const apiUrl =
  "https://prod.example.com";

如果 test 也使用這段,就可能誤打 production。Environment difference 應有明確注入點。

2. Node environment input

const apiUrl =
  process.env.API_URL;

if (!apiUrl) {
  throw new Error(
    "API_URL is required"
  );
}

Environment variable 只是 config transport mechanism;敏感性仍依 value privilege 判斷。

3. Startup validation

function loadConfig(env) {
  const port =
    Number(env.PORT);

  if (!Number.isInteger(port)) {
    throw new Error(
      "Invalid PORT"
    );
  }

  return { port };
}

Fail fast 比等到第一個 request 才因 undefined config 崩潰更容易定位。

4. Environment matrix

dev:
  local API
  verbose logs

test:
  isolated DB
  deterministic config

prod:
  production API
  restricted secrets
  observability

重點不是每個 environment 都完全不同,而是差異要可追蹤、可驗證。

5. Build-time vs Runtime

前端 bundler 可能在 build 時把 public config 寫進 bundle;server process 則可能在 runtime 讀 env。不要把兩種 timing 混為一談。

Project checkpoint:Environment Contract

config schema:
  API_URL
  PORT
  LOG_LEVEL

startup:
  read
  validate
  normalize
  expose typed config

建立 dev/test/prod 範例,但不把 real secret commit。

Debug evidence:Production 連到測試 API

  1. Config 是 build-time 還是 runtime?
  2. Actual deployed artifact 裡寫了什麼?
  3. Process environment 是什麼?
  4. Deployment workflow 注入了哪個 scope 的 value?

Knowledge check

  1. Config 和 secret 是否同義?
  2. Startup validation 解決什麼問題?
  3. 前端 build-time config 為何會進 bundle?
  4. 設計 Course Workspace 的 dev/test/prod config matrix。