🌊
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