Skip to content

第 3 章: 明白な実装とリファクタリング

3.1 はじめに

この章では FizzBuzz の仕様を cond で明白に実装し、1 から 100 までのリスト生成まで完成させます。最後に、読みやすさを高めるリファクタリングの観点を確認します。

3.2 cond による明白な実装

まずは必要なテストを追加します。

# test/fizz_buzz_test.exs

defmodule FizzBuzzTest do
  use ExUnit.Case

  describe "generate/1" do
    test "5 の倍数を渡すと Buzz を返す" do
      assert FizzBuzz.generate(5) == "Buzz"
    end

    test "15 の倍数を渡すと FizzBuzz を返す" do
      assert FizzBuzz.generate(15) == "FizzBuzz"
    end
  end
end

このテストを通す明白な実装は次のとおりです。

# lib/fizz_buzz.ex

defmodule FizzBuzz do
  def generate(n) do
    cond do
      rem(n, 15) == 0 -> "FizzBuzz"
      rem(n, 3) == 0 -> "Fizz"
      rem(n, 5) == 0 -> "Buzz"
      true -> Integer.to_string(n)
    end
  end
end

15 を先に判定することがポイントです。

3.3 1 から 100 までのリスト生成

続いて、結果一覧を作る関数のテストを書きます。

# test/fizz_buzz_test.exs

defmodule FizzBuzzTest do
  use ExUnit.Case

  describe "generate_list/0" do
    test "1 から 100 までの FizzBuzz リストを返す" do
      result = FizzBuzz.generate_list()

      assert length(result) == 100
      assert Enum.at(result, 0) == "1"
      assert Enum.at(result, 2) == "Fizz"
      assert Enum.at(result, 4) == "Buzz"
      assert Enum.at(result, 14) == "FizzBuzz"
    end
  end
end

実装はパイプライン演算子 |> を使うと読みやすくなります。

# lib/fizz_buzz.ex

defmodule FizzBuzz do
  def generate(n) do
    cond do
      rem(n, 15) == 0 -> "FizzBuzz"
      rem(n, 3) == 0 -> "Fizz"
      rem(n, 5) == 0 -> "Buzz"
      true -> Integer.to_string(n)
    end
  end

  def generate_list do
    1..100
    |> Enum.map(&generate/1)
  end
end

|> は「左の結果を右の関数に渡す」演算子です。データの流れを上から下に読めるため、処理の意図が明確になります。

3.4 リファクタリングのポイント

テストがすべて通る状態を保ちながら、次を確認します。

  • 判定順が明確か(1535
  • 重複した変換処理がないか
  • 関数名が役割を正しく表しているか
  • テストの責務が分離されているか(describe ごとに関心を分ける)

必要なら、テストデータを増やして安全に整理します。TDD では「動くこと」と「読みやすいこと」を両立させます。

3.5 まとめ

この章では、cond を使った明白な実装で BuzzFizzBuzz を追加し、1..100 のリスト生成を完成させました。さらに |> の基本と、テストを守りながら進めるリファクタリングの観点を確認しました。