bubbletea-code-review
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBubbleTea Code Review
BubbleTea 代码评审
Quick Reference
快速参考
| Issue Type | Reference |
|---|---|
| Elm architecture, tea.Cmd as data | references/elm-architecture.md |
| Model state, message handling | 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 |
| 问题类型 | 参考文档 |
|---|---|
| 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)
非问题项(请勿标记)
| Pattern | Why It's Correct |
|---|---|
| |
Value receiver on | Standard BubbleTea pattern; model returned by value |
Nested | Normal component composition |
Helper functions returning | Creates command descriptor, no I/O in Update |
| Commands execute concurrently by runtime |
| 模式 | 正确原因 |
|---|---|
| |
| BubbleTea的标准模式;模型通过值返回 |
嵌套 | 正常的组件组合方式 |
返回 | 仅创建命令描述符,Update中无I/O操作 |
| 运行时会并发执行命令 |
ACTUAL Issues (DO Flag These)
真正的问题项(需要标记)
| Pattern | Why It's Wrong |
|---|---|
| Blocks UI thread |
| Network I/O blocks |
| Freezes UI |
| May block indefinitely |
| Blocking call |
| 模式 | 错误原因 |
|---|---|
| 会阻塞UI线程 |
| 网络I/O会造成阻塞 |
| 会冻结UI |
Update中使用 | 可能会无限期阻塞 |
| 阻塞式调用 |
Review Checklist
评审检查清单
Architecture
架构
- No blocking I/O in Update() (file, network, sleep)
- Helper functions returning are NOT flagged as blocking
tea.Cmd - 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 BubbleTea → elm-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
评审问题
- 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?
- Update()中是否无阻塞I/O?(注意:不是“辅助命令函数是否阻塞?”)
- Update中模型是否是不可变的?
- Lipgloss样式是否仅定义一次,而非在View中重复定义?
- 是否处理了WindowSizeMsg以支持窗口调整?
- 按键绑定是否使用help.KeyMap进行了文档化?
- Bubbles组件是否设置了正确的尺寸?