🌊

Fragment #7 – アプリの生成ロジックとデータ構造をリファクタした話

に公開

はじめに

Fragment は、「色」「言葉」「音」の 3 つのピースを選んで、その人だけのオリジナルな「偶然」を作るシンプルなアプリです。

今回は、この Fragment 生成ロジックの基盤を、分かりやすく、拡張性のある形にリファクタした過程を整理します。


なぜリファクタが必要だったのか

最初の実装では、生成ロジックが画面コンポーネントと密結合しており、以下のような課題がありました:

  • 生成ロジックのテストが困難
  • 新しい生成ルールの追加が複雑
  • コードの見通しが悪い

これらの課題を解決するため、生成ロジックを独立したモジュールとして分離することにしました。


技術的な実装ポイント

Fragment 生成ロジックの分離

ユーザーが選んだ「色」「言葉」「音」が指す意味(たとえば "静けさ" や "希望")に基づいて、意味的に一貫性のある Fragment を一部システム側で補完しています。

この補完処理は generateFragment 関数で行っており、内部では SemanticRule をもとに候補を絞り込み、関連性のあるピースを再構成しています。

SemanticRule の実装

interface SemanticRule {
  tags: string[]; // 全体的な意味を表すタグ
  wordTags: string[]; // 言葉に関連するタグ
  soundTags: string[]; // 音に関連するタグ
}

// 使用例
const rules: SemanticRule[] = [
  {
    tags: ["静けさ", "気配", "風"],
    wordTags: ["平穏"],
    soundTags: ["風", "空間"],
  },
  // 他のルール...
];

生成ロジックの実装

function matchRule(input: FragmentInput): SemanticRule | undefined {
  return semanticRules.find((rule) =>
    rule.tags.some((tag) =>
      [input.color.tag, input.word.tag, input.sound.tag].includes(tag)
    )
  );
}

function getRandom<T>(items: T[]): T {
  return items[Math.floor(Math.random() * items.length)];
}

export function generateFragment(input: FragmentInput): FragmentResult {
  const matchedRule = matchRule(input);

  const chosenWord = matchedRule
    ? getRandom(
        wordPieces.filter((w: WordPiece) =>
          matchedRule.wordTags.includes(w.tag)
        )
      )
    : getRandom(wordPieces);

  const chosenSound = matchedRule
    ? getRandom(
        soundPieces.filter((s: SoundPiece) =>
          matchedRule.soundTags.includes(s.tag)
        )
      )
    : getRandom(soundPieces);

  return {
    color: input.color,
    word: chosenWord as WordPiece,
    sound: chosenSound as SoundPiece,
  };
}

リファクタリングの効果

1. テスト容易性の向上

  • 生成ロジックを独立したモジュールとして分離したことで、単体テストが書きやすくなりました
  • モックデータを使ったテストケースの作成が容易になりました

2. 拡張性の向上

  • 新しい生成ルールの追加が容易になりました
  • 意味解析のロジックを変更する際の影響範囲が限定されました

3. コードの可読性向上

  • 責務が明確に分離され、コードの見通しが良くなりました
  • 各関数の役割が明確になり、メンテナンスが容易になりました

苦労した点・工夫した点

  • リファクタリングを通じて、コードの品質と保守性が大きく向上した
  • 特に、生成ロジックの分離により、新しい機能の追加や変更が容易になり、開発の効率が上がった

次にやること

  • より静かな演出へ向けて、音との統合(環境音の再生など)
  • 選んだピースからユーザーの感情を抽出し Complete 画面の演出を感情によって変化させる
  • Fragment #8 – Fragment の emotion 表現

Discussion