bubbletea-code-review

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

BubbleTea Code Review

BubbleTea 代码评审

Quick Reference

快速参考

Issue TypeReference
Elm architecture, tea.Cmd as datareferences/elm-architecture.md
Model state, message handlingreferences/model-update.md
View rendering, Lipgloss stylingreferences/view-styling.md
Component composition, Huh formsreferences/composition.md
Bubbles components (list, table, etc.)references/bubbles-components.md
问题类型参考文档
Elm架构、tea.Cmd作为数据传递references/elm-architecture.md
模型状态、消息处理references/model-update.md
视图渲染、Lipgloss样式references/view-styling.md
组件组合、Huh表单references/composition.md
Bubbles组件(列表、表格等)references/bubbles-components.md

CRITICAL: Avoid False Positives

⚠️ 重要提示:避免误判

Read elm-architecture.md first! The most common review mistake is flagging correct patterns as bugs.
请先阅读elm-architecture.md 评审中最常见的错误是将正确的模式标记为问题。

NOT Issues (Do NOT Flag These)

非问题项(请勿标记)

PatternWhy It's Correct
return m, m.loadData()
tea.Cmd
is returned immediately; runtime executes async
Value receiver on
Update()
Standard BubbleTea pattern; model returned by value
Nested
m.child, cmd = m.child.Update(msg)
Normal component composition
Helper functions returning
tea.Cmd
Creates command descriptor, no I/O in Update
tea.Batch(cmd1, cmd2)
Commands execute concurrently by runtime
模式正确原因
return m, m.loadData()
tea.Cmd
会被立即返回;运行时会执行异步操作
Update()
使用值接收器
BubbleTea的标准模式;模型通过值返回
嵌套
m.child, cmd = m.child.Update(msg)
正常的组件组合方式
返回
tea.Cmd
的辅助函数
仅创建命令描述符,Update中无I/O操作
tea.Batch(cmd1, cmd2)
运行时会并发执行命令

ACTUAL Issues (DO Flag These)

真正的问题项(需要标记)

PatternWhy It's Wrong
os.ReadFile()
in Update
Blocks UI thread
http.Get()
in Update
Network I/O blocks
time.Sleep()
in Update
Freezes UI
<-channel
in Update (blocking)
May block indefinitely
huh.Form.Run()
in Update
Blocking call
模式错误原因
os.ReadFile()
在Update中
会阻塞UI线程
http.Get()
在Update中
网络I/O会造成阻塞
time.Sleep()
在Update中
会冻结UI
Update中使用
<-channel
(阻塞式)
可能会无限期阻塞
huh.Form.Run()
在Update中
阻塞式调用

Review Checklist

评审检查清单

Architecture

架构

  • No blocking I/O in Update() (file, network, sleep)
  • Helper functions returning
    tea.Cmd
    are NOT flagged as blocking
  • Commands used for all async operations
  • Update()中无阻塞I/O(文件、网络、休眠)
  • 返回
    tea.Cmd
    的辅助函数不会被标记为阻塞
  • 所有异步操作均使用命令实现

Model & Update

模型与更新

  • Model is immutable (Update returns new model, not mutates)
  • Init returns proper initial command (or nil)
  • Update handles all expected message types
  • WindowSizeMsg handled for responsive layout
  • tea.Batch used for multiple commands
  • tea.Quit used correctly for exit
  • 模型是不可变的(Update返回新模型,而非修改原有模型)
  • Init返回正确的初始命令(或nil)
  • Update处理所有预期的消息类型
  • 处理WindowSizeMsg以实现响应式布局
  • 使用tea.Batch执行多个命令
  • 正确使用tea.Quit实现退出

View & Styling

视图与样式

  • View is a pure function (no side effects)
  • Lipgloss styles defined once, not in View
  • Key bindings use key.Matches with help.KeyMap
  • View是纯函数(无副作用)
  • Lipgloss样式仅定义一次,而非在View中重复定义
  • 按键绑定使用key.Matches与help.KeyMap

Components

组件

  • Sub-component updates propagated correctly
  • Bubbles components initialized with dimensions
  • Huh forms embedded via Update loop (not Run())
  • 子组件的更新被正确传播
  • Bubbles组件使用维度参数初始化
  • Huh表单通过Update循环嵌入(而非使用Run())

Critical Patterns

关键模式

Model Must Be Immutable

模型必须是不可变的

go
// BAD - mutates model
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    m.items = append(m.items, newItem)  // mutation!
    return m, nil
}

// GOOD - returns new model
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    newItems := make([]Item, len(m.items)+1)
    copy(newItems, m.items)
    newItems[len(m.items)] = newItem
    m.items = newItems
    return m, nil
}
go
// BAD - 修改原有模型
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    m.items = append(m.items, newItem)  // 直接修改!
    return m, nil
}

// GOOD - 返回新模型
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    newItems := make([]Item, len(m.items)+1)
    copy(newItems, m.items)
    newItems[len(m.items)] = newItem
    m.items = newItems
    return m, nil
}

Commands for Async/IO

使用命令处理异步/I/O操作

go
// BAD - blocking in Update
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    data, _ := os.ReadFile("config.json")  // blocks UI!
    m.config = parse(data)
    return m, nil
}

// GOOD - use commands
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    return m, loadConfigCmd()
}

func loadConfigCmd() tea.Cmd {
    return func() tea.Msg {
        data, err := os.ReadFile("config.json")
        if err != nil {
            return errMsg{err}
        }
        return configLoadedMsg{parse(data)}
    }
}
go
// BAD - Update中存在阻塞操作
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    data, _ := os.ReadFile("config.json")  // 阻塞UI!
    m.config = parse(data)
    return m, nil
}

// GOOD - 使用命令
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    return m, loadConfigCmd()
}

func loadConfigCmd() tea.Cmd {
    return func() tea.Msg {
        data, err := os.ReadFile("config.json")
        if err != nil {
            return errMsg{err}
        }
        return configLoadedMsg{parse(data)}
    }
}

Styles Defined Once

样式仅定义一次

go
// BAD - creates new style each render
func (m Model) View() string {
    style := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("205"))
    return style.Render("Hello")
}

// GOOD - define styles at package level or in model
var titleStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("205"))

func (m Model) View() string {
    return titleStyle.Render("Hello")
}
go
// BAD - 每次渲染都创建新样式
func (m Model) View() string {
    style := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("205"))
    return style.Render("Hello")
}

// GOOD - 在包级别或模型中定义样式
var titleStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("205"))

func (m Model) View() string {
    return titleStyle.Render("Hello")
}

When to Load References

何时查阅参考文档

  • First time reviewing BubbleTeaelm-architecture.md (prevents false positives)
  • Reviewing Update function logic → model-update.md
  • Reviewing View function, styling → view-styling.md
  • Reviewing component hierarchy → composition.md
  • Using Bubbles components → bubbles-components.md
  • 首次评审BubbleTea代码elm-architecture.md(避免误判)
  • 评审Update函数逻辑 → model-update.md
  • 评审View函数、样式 → view-styling.md
  • 评审组件层级 → composition.md
  • 使用Bubbles组件 → bubbles-components.md

Review Questions

评审问题

  1. Is Update() free of blocking I/O? (NOT: "is the cmd helper blocking?")
  2. Is the model immutable in Update?
  3. Are Lipgloss styles defined once, not in View?
  4. Is WindowSizeMsg handled for resizing?
  5. Are key bindings documented with help.KeyMap?
  6. Are Bubbles components sized correctly?
  1. Update()中是否无阻塞I/O?(注意:不是“辅助命令函数是否阻塞?”)
  2. Update中模型是否是不可变的?
  3. Lipgloss样式是否仅定义一次,而非在View中重复定义?
  4. 是否处理了WindowSizeMsg以支持窗口调整?
  5. 按键绑定是否使用help.KeyMap进行了文档化?
  6. Bubbles组件是否设置了正确的尺寸?