蒼時弦也
蒼時弦也
資深軟體工程師
發表於

更新購物車 - Clean Architecture in TypeScript

這篇文章是 Clean Architecture in TypeScript 系列的一部分,你可以透過 Leanpub 提前閱讀內容。

可以查詢商品後,我們就可以透過對話得到能購買的商品,那麼就可以加入更新購物車商品的設計。基於前面我們已經有很多基礎,加入新功能的速度會快上不少。

撰寫本文時 Claude Code 變得非常熱門,後續的文章會使用 Claude Code 作為範例。

新增工具

這次我們要增加一個 updateCart 的工具,基本上會接受商品名稱、數量以及對應的購物車編號(對話編號)即可,跟前面 Aider 範例不太一樣的地方是 Claude Code 會自動尋找檔案,不需要特別限定檔案範圍。

給出以下提示,讓 Claude Code 根據要求加入對應的實作

We are working on @src/service/LlmAssistantService.ts to add new tool `updateCart`

To allow our assistant to update the cart, we need to complete following components:

# Update Cart Use Case

- Locate at `src/usecase/updateCart.ts`
- Accepts `id`, `name`, `quantity`
- Checking product by name to get price using product repository
- Save the cart using cart repository

# Cart Repository

- Add `save` method to `src/repository/KvCartRepository.ts`:
- Accept the `Cart` entity, map data to storage backend schema
- Save the cart data to the storage backend

# Product Repository

No need to change, we will use `ListAll` to get all products and find the price by name.

# Cart Entity

No need to change, we already have `updateItem` method in `Cart` entity to update the item.

# Llm Assistant Service

- Register the new tool in `src/service/LlmAssistantService.ts`
- Use `ToolCartPresenter` to return updated cart

我個人是主張使用不同 AI 工具的提示不會非常大的類型,畢竟我們不能一直配合模型改版修正,因此撰寫提示的方式跟之前差異不會太大,以清楚描述要修改的範圍為主。

Claude Code 的設計不太適合過長的內容,因此官方文件會建議另外存成一個檔案使用 @ 引用,可以考慮放到像是 docs/20251017-update-cart-tool.md 之類的目錄。

提示的內容並不複雜,因為我們在前面已經逐步完善整個開發跟設計,因此只需要在文件中描述要修改的檔案,以及調整的範圍即可,Claude Code 是有設計思考跟計劃能力的,因此要避免過多的修改可以利用提示「不用調整」讓他更專注在我們想修改的範圍(類似 Aider 的限定檔案)

調整提示

之前為了讓 LlmAssistantService 可以很簡單運作起來,我們給了非常粗糙的系統提示,在更新購物車時會需要更細節的描述。

這是因為我們不會在對話紀錄儲存工具呼叫的內容,這可能造成我們使用「商品名稱」更新的問題,以 「Power Bank」作為例子,我可能會用「行動電源」描述這個商品,如果沒有特別告知怎麼判斷,那可能就會發生錯誤。

因此我們需要將更新商品的流程寫進去,至少確保現階段的功能正常。

You are a helpful assistant that can answer questions and provide information about the shopping cart. You can also retrieve the current contents of the cart when requested.

## Update Cart

When update the cart, you MUST checked the product use "getProduts" tool is available in the store.
User may use different language to refer to the same product, so you SHOULD use the database name to refer to the product.
To give correct quantity, you MUST use the "getCart" tool to get the current cart contents.
Finally, you MUST use the "updateCart" tool to update the cart with the specified quantity.

更新後的提示我們加入了 Update Cart 段落,簡單描述應該先使用 getProducts 工具查詢到相應的項目後,再使用 getCart 確認數量,最後才用 updateCart 填入正確的品名和數量。

這段提示會取決於能使用的工具,假設有可以針對個別商品查詢的工具,以及 updateCart 使採用「增加、減少」的設計,那就不需要這樣的機制,如果資料量不大的話,直接印出所有資訊對目前大部分模型都是能輕鬆處理的程度。

細部調整

完成提示調整後,就可以測試功能。有時候 AI 產生的實作可能會漏掉一些細節,這些細節也可能是因為我們在提示時沒有特別告知,所以就自然被遺漏的資訊。

src/usecase/updateCart.ts 中,漏掉了「商品為 0 是移除」的處理,但是 Claude Code 在設計時,卻在 src/service/LlmAssistantService.ts 的工具描述這樣寫,考慮到這個設計還在預期範圍內,我們可以直接加入簡單的修正。

1const isRemove = quantity === 0;
2if(isRemove) {
3	cart.removeItem(productName);
4} else {
5	cart.updateItem(productName, product.price, quantity);
6}

原本應該只會呼叫 cart.updateItem() 對商品數量進行更新,我們在這邊加入一條判斷額外進行處理要呼叫的動作。

也可以選擇在 Cart entity 處理,這取決於對於 quantity == 0 的限制條件是否寬鬆來決定

在測試過程中,也發現之前 AI 實作時並沒有處理對話訊息超出畫面時,自動捲動到最下方的機制,而且購物車更新後,也不會在右邊的側邊欄顯示新的狀態。

我們可以用下面這段提示,告知 AI 需要修改畫面呈現並且更新購物車。

Let's update @src/view/Chat.tsx to improve the UI.

When user sent message and received response:

- Get cart items again from API
- Scroll to bottom of chat view

Claude Code 基本上很快就可以處理完這個修改,因為原本就有取得購物車的 API 可以使用,預期會使用相同的方式快速的把功能實現。

那麼,我們現階段就可以透過對話的方式調整購物車的商品,後續就是要細修許多先前沒有仔細處理的細節。