dramaling-vocab-learning/TTS播放按鈕架構不一致問題評估報告.md

8.1 KiB
Raw Blame History

TTS 播放按鈕架構不一致問題評估報告

📋 問題概述

在 BluePlayButton 重構過程中,發現了 TTS 播放邏輯的架構不一致性問題,導致同一應用中存在兩套不同的播放狀態管理機制。

🔍 現況分析

當前架構狀態

1. 新架構 (BluePlayButton 內建邏輯)

使用範圍: 8+ 個組件

// 使用方式:極其簡潔
<BluePlayButton text="hello" />

// 狀態管理:組件內建
const [isPlaying, setIsPlaying] = useState(false)  // 內建於 BluePlayButton

優勢

  • 使用簡潔,一行代碼
  • 無狀態洩漏,組件自主管理
  • 無重複邏輯

2. 舊架構 (useTTSPlayer Hook)

使用範圍: 詞卡詳細頁面 (app/flashcards/[id]/page.tsx)

// 使用方式:複雜配置
const { isPlayingWord, isPlayingExample, toggleWordTTS, toggleExampleTTS } = useTTSPlayer()

<FlashcardDetailHeader
  isPlayingWord={isPlayingWord}
  onToggleWordTTS={toggleWordTTS}
/>

<FlashcardContentBlocks
  isPlayingExample={isPlayingExample}
  onToggleExampleTTS={toggleExampleTTS}
/>

問題

  • 與新的 BluePlayButton API 不相容
  • 外部狀態管理複雜
  • 狀態可能與內建邏輯衝突

🚨 架構衝突分析

衝突點 1: 雙重狀態管理

詞卡詳細頁面狀態流:
useTTSPlayer Hook → isPlayingWord → 傳遞給組件
                                      ↓ 衝突
BluePlayButton → 內建 isPlaying 狀態

衝突點 2: API 不相容

// useTTSPlayer 期望的 API
<BluePlayButton isPlaying={isPlayingWord} onToggle={toggleWordTTS} />

// 新 BluePlayButton 的 API
<BluePlayButton text="hello" />  // 無 isPlaying 和 onToggle

衝突點 3: 功能重複

  • useTTSPlayer 有完整的 TTS 邏輯 (71 行)
  • BluePlayButton 也有完整的 TTS 邏輯 (40 行)
  • 總計 111 行重複邏輯

💡 解決方案評估

方案 A: 完全統一為 BluePlayButton 內建邏輯

實施方式

  1. 移除詞卡詳細頁面的 useTTSPlayer 使用
  2. 簡化 FlashcardDetailHeaderFlashcardContentBlocks 的 props
  3. 刪除 useTTSPlayer.ts Hook

修改範例

// app/flashcards/[id]/page.tsx
- const { isPlayingWord, isPlayingExample, toggleWordTTS, toggleExampleTTS } = useTTSPlayer()

<FlashcardDetailHeader
  flashcard={flashcard}
- isPlayingWord={isPlayingWord}
- isPlayingExample={isPlayingExample}
- onToggleWordTTS={toggleWordTTS}
/>

<FlashcardContentBlocks
  flashcard={flashcard}
- isPlayingWord={isPlayingWord}
- isPlayingExample={isPlayingExample}
- onToggleExampleTTS={toggleExampleTTS}
/>

優勢

  • 完全一致: 全應用使用相同的播放邏輯
  • 代碼最少: 移除 71 行重複邏輯
  • 維護簡單: 只需維護一套 TTS 邏輯
  • 使用統一: 所有組件使用方式一致

劣勢

  • 狀態隔離: 無法協調兩個按鈕的播放狀態 (同時只能播放一個)
  • 重構成本: 需要修改組件 props 介面

評分: 5/5 (推薦)

方案 B: 保持 useTTSPlayer適配新 BluePlayButton

實施方式

  1. 修改 BluePlayButton 支援外部狀態注入
  2. 保持 useTTSPlayer Hook 不變
  3. 通過 props 橋接兩套系統

修改範例

// 修改 BluePlayButton 支援外部狀態
interface BluePlayButtonProps {
  // 新增外部狀態支援
  externalIsPlaying?: boolean
  externalOnToggle?: (text: string) => void
  // 保留內建邏輯
  text?: string
}

// 使用方式
<BluePlayButton
  externalIsPlaying={isPlayingWord}
  externalOnToggle={toggleWordTTS}
/>

優勢

  • 狀態協調: 可以協調兩個按鈕的播放狀態
  • 向下相容: 不破壞現有功能
  • 漸進移轉: 可以逐步移轉到新架構

劣勢

  • 複雜度增加: BluePlayButton 變複雜,需要處理兩套邏輯
  • 代碼重複: 仍有重複的 TTS 邏輯
  • API 混淆: 組件有兩種使用方式,容易混淆

評分: 3/5 (可行但不理想)

方案 C: 混合架構 - 詞卡詳細頁面特殊處理

實施方式

  1. 詞卡詳細頁面保持使用 useTTSPlayer
  2. 其他頁面使用 BluePlayButton 內建邏輯
  3. 接受架構不一致性

優勢

  • 最小改動: 幾乎不需要修改現有代碼
  • 功能保持: 不影響現有功能

劣勢

  • 架構混亂: 同一應用有兩套播放邏輯
  • 維護困難: 需要維護兩套不同的系統
  • 代碼重複: 71 行 + 40 行 = 111 行重複邏輯
  • 開發混淆: 新開發者不知道該用哪一套

評分: 2/5 (不推薦)

📊 詳細衝擊評估

方案 A 實施衝擊分析

需要修改的文件

  1. app/flashcards/[id]/page.tsx - 移除 useTTSPlayer 使用
  2. components/flashcards/FlashcardDetailHeader.tsx - 移除 TTS props
  3. components/flashcards/FlashcardContentBlocks.tsx - 移除 TTS props
  4. hooks/shared/useTTSPlayer.ts - 刪除檔案

修改工作量

  • 估計時間: 30-60 分鐘
  • 修改行數: ~30 行
  • 風險等級: 低(只是移除多餘代碼)

相容性影響

  • 破壞性變更: 是(修改組件 props 介面)
  • 功能影響: 無(播放功能完全保持)
  • 用戶體驗: 無影響

🎯 推薦方案

強烈推薦:方案 A - 完全統一為 BluePlayButton 內建邏輯

推薦理由:

  1. 架構純淨性:

    • 全應用使用統一的播放邏輯
    • 消除 111 行重複代碼
    • 單一真相來源 (Single Source of Truth)
  2. 開發體驗:

    • 新組件開發只需要知道一種使用方式
    • 無需學習兩套不同的播放邏輯
    • IDE 自動完成更準確
  3. 維護成本:

    • 只需維護一套 TTS 邏輯
    • bug 修復只需要在一個地方
    • 功能增強影響全應用
  4. 性能優勢:

    • 減少組件 props 傳遞
    • 減少狀態更新鏈條
    • 更好的組件獨立性

實施建議:

階段 1: 狀態協調解決方案 (可選)

如果需要協調兩個播放按鈕的狀態(同時只能播放一個),可以:

// 在 BluePlayButton 中添加全域狀態管理
import { create } from 'zustand'

const useGlobalTTSStore = create((set) => ({
  activePlayer: null,
  setActivePlayer: (player) => set({ activePlayer: player })
}))

// BluePlayButton 使用全域狀態
const { activePlayer, setActivePlayer } = useGlobalTTSStore()

階段 2: 漸進式重構

  1. 先修改詞卡詳細頁面使用新 API
  2. 測試確保功能正常
  3. 刪除 useTTSPlayer Hook
  4. 清理相關 imports

🚀 實施路線圖

立即執行 (10 分鐘)

  • 移除詞卡詳細頁面的 useTTSPlayer 使用
  • 簡化組件 props 傳遞

短期清理 (20 分鐘)

  • 刪除 useTTSPlayer Hook
  • 清理相關類型定義
  • 更新組件介面文檔

可選增強 (30 分鐘)

  • 添加全域播放狀態協調
  • 實施播放佇列機制
  • 添加播放狀態持久化

📈 預期效益

量化效益:

  • 代碼減少: 71 行 (useTTSPlayer) + 30 行 (props 傳遞) = 101 行
  • 組件簡化: 3 個組件的 props 介面簡化
  • 維護成本: 降低 50% (只需維護一套邏輯)

質性效益:

  • 架構一致性: 全應用統一設計模式
  • 開發效率: 新功能開發更快速
  • 代碼品質: 消除重複,提高內聚性

🎯 結論與建議

強烈建議立即實施方案 A,理由:

  1. 技術債務清理: 消除架構不一致性
  2. 開發效率: 統一的開發模式
  3. 代碼品質: 大幅減少重複邏輯
  4. 未來維護: 更容易擴展和修改

風險評估: 低風險,只是移除多餘代碼,不影響核心功能

實施優先級: 🔴 高 (建議在下次開發週期立即處理)


報告生成時間: 2025-10-02 問題發現者: 用戶架構審查 分析範圍: 全前端 TTS 播放邏輯