YovStudio

article 読むトレ #07:その初期値でいいの?

公開日: 2025-06-21著者: Yov in YovStudio

今回のお題コード

今回のお題コードには非同期処理とよばれる、もしかしたらみなさんがまだあまり見慣れていないかもしれない仕組みが入っています。
先にお伝えしておきますが、非同期処理は今回の本題ではありませんので、Promiseasyncawait といった記述はよくわからなくても問題ありません。

では AI に今回のコードを提示してもらいましょう。

AI 「DBからアイテムリストを取得して表示する処理を書きました!どうですか?」

// アイテムリストを表示する関数
function showItems(currentItems) {
  if (currentItems.length === 0) {
    console.log('データがありません');
  } else {
    console.log('データがあります:', currentItems);
  }
}

// DBからアイテムリストを取得するつもりの関数(1秒後に固定データを取得する)
function fetchItemsFromDB() {
  // 1秒(1000ミリ秒)後に、固定データを返す
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = ['リンゴ', 'バナナ'];
      resolve(data);
    }, 1000);
  });
}

// アイテムリストを読み込んで表示する処理
async function loadAndShowItems() {
  let items = [];

  // DBから取得する前に初期表示
  showItems(items);

  items = await fetchItemsFromDB();
  console.log('✅ データを取得しました');

  // DBから取得したあと(1秒後)に再表示
  showItems(items);
}

loadAndShowItems();

どう動く?

さっそく読んでみましょう。
画面に表示されるデータの状態に注目しながら読んでみてください。

以下のようなサイトで動かしてみてもよいです。

気になる動き

実行すると、こうなります。

実行直後

データがありません

1 秒後

✅ データを取得しました
"データがあります:"
["リンゴ", "バナナ"]

実行直後の「データがありません」の曖昧さに気づきましたか?

「データがありません」だと、DB から取得した結果が 0 件だったのか、まだ DB から取得していないからデータがないのかの判断がつきづらいです。

実際、DBの取得結果を空リストに変えて実行してみると…

// DBからアイテムリストを取得するつもりの関数(1秒後に固定データを取得する)
function fetchItemsFromDB() {
  // 1秒(1000ミリ秒)後に、固定データを返す
  return new Promise((resolve) => {
    setTimeout(() => {
-       const data = ['リンゴ', 'バナナ'];
+       const data = [];
      resolve(data);
    }, 1000);
  });
}

このように、実行直後と 1 秒後どちらも「データがありません」と表示されます。

実行直後

データがありません

1 秒後

データがありません

どちらも「データがない」状態なので、一見「問題ないのでは?」と感じるかもしれません。
しかし実際のアプリケーションにおいては、データを取得しているときにロード画面を表示したりしますよね? こうした一般的な仕組みを考えると、今回のコードもデータ取得中はロード中であることを表示したいという要望が入る可能性を考慮しておいたほうがよいでしょう。

原因は「初期値が状態を考慮していない」

しかし今回のコードでは、items を空リスト [] で初期化してしまっているため、DB からの取得が終わっていないのか、それとも DB からの取得結果が空だったのか判断がつかないため、ロード画面を表示すべきかどうかわかりません。

let items = [];

どう修正する?

最もシンプルでわかりやすい修正方法としては、items の初期値を null にする方法があります。

let items = null;

こうすれば showItems() で、null の場合の処理を追加して「ロード中」などの表示をすることができます。

function showItems(currentItems) {
  if (currentItems === null) {
    console.log('ロード中…');
  } else if (currentItems.length === 0) {
    console.log('データがありません');
  } else {
    console.log('データがあります:', currentItems);
  }
}

補足:実務ではどうする?

今回のお題コードが想定していたデータの状態はたった 2 つしかありませんでした。

  • データが空
  • データが空ではない

修正方法として提示したコードも、上記に「データが null」という状態を追加したシンプルなものでした。
初期値もしっかり考える必要があるとお伝えするのが今回のテーマなので良いのですが、参考までに、実務の話も少し加えたいと思います。

実は、実務においては最低でも次の 5 つの状態が必要になります。

  • まだ取得していない
  • 今まさに取得中
  • 取得した結果が空
  • 取得した結果が空ではない
  • 取得失敗

これを実現するため、状態をオブジェクトで管理する方法がよく用いられます。
他の方法もありますが、あくまで一例としての紹介です。

まだ取得していない

{
  status: "idle",   // アイドル(何もしていない)状態
  data: null,
  error: null
}

今まさに取得中

{
  status: "loading", // ロード中
  data: null,
  error: null
}

取得した結果が空

{
  status: "success",  // 取得成功
  data: [],
  error: null
}

取得した結果が空ではない

{
  status: "success",  // 取得成功
  data: ["リンゴ", "バナナ"],
  error: null
}

取得失敗

{
  status: "error",  // 取得失敗
  data: null,
  error: "Authentication failure."  // 本当はエラー情報の詰まったオブジェクトなど
}

今回の読みどころ

  • 初期値を決めるときは状態を区別できるかも考える
  • 曖昧な初期値は読み手に迷いを与える
  • 初期値の「役割」と「時間的な意味合い」を意識して読む

おまけ:お題コードの修正版

少し長いので折りたたみます。

コードはこちら
// アイテムリストを表示する関数
function showItems(currentItems) {
  if (currentItems === null) {
    console.log('ロード中…');
  } else if (currentItems.length === 0) {
    console.log('データがありません');
  } else {
    console.log('データがあります:', currentItems);
  }
}

// DBからアイテムリストを取得するつもりの関数(1秒後に固定データを取得する)
function fetchItemsFromDB() {
  // 1秒(1000ミリ秒)後に、固定データを返す
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = ['リンゴ', 'バナナ'];
      resolve(data);
    }, 1000);
  });
}

// アイテムリストを読み込んで表示する処理
async function loadAndShowItems() {
  let items = null;

  // DBから取得する前に初期表示
  showItems(items);

  items = await fetchItemsFromDB();
  console.log('✅ データを取得しました');

  // DBから取得したあと(1秒後)に再表示
  showItems(items);
}

loadAndShowItems();