BubbleTea Code Review
Quick Reference
references/model-update.md |
| View rendering, Lipgloss styling |
references/view-styling.md |
| Component composition, Huh forms |
references/composition.md |
| Bubbles components (list, table, etc.) |
references/bubbles-components.md |
CRITICAL: Avoid False Positives
Read elm-architecture.md first! The most common review mistake is flagging correct patterns as bugs.
NOT Issues (Do NOT Flag These)
| Pattern | Why It's Correct |
|---|
| INLINECODE0 | INLINECODE1 is returned immediately; runtime executes async |
| Value receiver on INLINECODE2 |
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 |
ACTUAL Issues (DO Flag These)
| Pattern | Why It's Wrong |
|---|
| INLINECODE6 in Update | Blocks UI thread |
| INLINECODE7 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 |
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
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
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
Components
- - [ ] Sub-component updates propagated correctly
- [ ] Bubbles components initialized with dimensions
- [ ] Huh forms embedded via Update loop (not Run())
Critical Patterns
Model Must Be Immutable
CODEBLOCK0
Commands for Async/IO
CODEBLOCK1
Styles Defined Once
CODEBLOCK2
When to Load References
Review Questions
- 1. Is Update() free of blocking I/O? (NOT: "is the cmd helper blocking?")
- Is the model immutable in Update?
- Are Lipgloss styles defined once, not in View?
- Is WindowSizeMsg handled for resizing?
- Are key bindings documented with help.KeyMap?
- Are Bubbles components sized correctly?
BubbleTea 代码审查
快速参考
references/model-update.md |
| 视图渲染,Lipgloss样式 |
references/view-styling.md |
| 组件组合,Huh表单 |
references/composition.md |
| Bubbles组件(列表、表格等) |
references/bubbles-components.md |
关键:避免误报
请先阅读 elm-architecture.md! 最常见的审查错误是将正确模式标记为错误。
非问题(不要标记这些)
| 模式 | 正确原因 |
|---|
| return m, m.loadData() | tea.Cmd 立即返回;运行时异步执行 |
| Update() 使用值接收者 |
标准BubbleTea模式;模型按值返回 |
| 嵌套 m.child, cmd = m.child.Update(msg) | 正常的组件组合 |
| 辅助函数返回 tea.Cmd | 创建命令描述符,Update中无I/O操作 |
| tea.Batch(cmd1, cmd2) | 命令由运行时并发执行 |
实际问题(需要标记这些)
| 模式 | 错误原因 |
|---|
| Update中的 os.ReadFile() | 阻塞UI线程 |
| Update中的 http.Get() |
网络I/O阻塞 |
| Update中的 time.Sleep() | 冻结UI |
| Update中的 <-channel(阻塞) | 可能无限期阻塞 |
| Update中的 huh.Form.Run() | 阻塞调用 |
审查清单
架构
- - [ ] Update()中无阻塞I/O(文件、网络、休眠)
- [ ] 返回 tea.Cmd 的辅助函数不被标记为阻塞
- [ ] 所有异步操作使用命令
模型与更新
- - [ ] 模型不可变(Update返回新模型,不修改原模型)
- [ ] Init返回正确的初始命令(或nil)
- [ ] Update处理所有预期的消息类型
- [ ] 处理WindowSizeMsg以实现响应式布局
- [ ] 多个命令使用tea.Batch
- [ ] 正确使用tea.Quit退出
视图与样式
- - [ ] View是纯函数(无副作用)
- [ ] Lipgloss样式定义一次,不在View中定义
- [ ] 按键绑定使用key.Matches配合help.KeyMap
组件
- - [ ] 子组件更新正确传播
- [ ] Bubbles组件使用尺寸初始化
- [ ] Huh表单通过Update循环嵌入(不使用Run())
关键模式
模型必须不可变
go
// 错误 - 修改模型
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.items = append(m.items, newItem) // 修改!
return m, nil
}
// 正确 - 返回新模型
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
}
异步/IO的命令
go
// 错误 - 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
}
// 正确 - 使用命令
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
// 错误 - 每次渲染创建新样式
func (m Model) View() string {
style := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color(205))
return style.Render(Hello)
}
// 正确 - 在包级别或模型中定义样式
var titleStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color(205))
func (m Model) View() string {
return titleStyle.Render(Hello)
}
何时加载参考文档
审查问题
- 1. Update()是否没有阻塞I/O?(注意:不是cmd辅助函数是否阻塞?)
- Update中的模型是否不可变?
- Lipgloss样式是否定义一次,不在View中定义?
- 是否处理了WindowSizeMsg以实现调整大小?
- 按键绑定是否使用help.KeyMap记录?
- Bubbles组件尺寸是否正确?