ChatGPT開始威脅程序員的核心能力了!
?ChatGPT是程序員的好幫手?還是要干掉程序員?
我覺得不僅要看它生成代碼的能力,更關鍵的是要看它是否具備強大的設計能力。
設計能力有兩個層面,一個是高層的,例如架構設計,系統設計。
一個是相對低層的設計能力,主要設計具體的類和接口。
今天我們看看它在這兩個方面分別表現如何。
由于ChatGPT的回答特別啰嗦,我會刪除一些細節,只保留重要部分。
出于公司保密的原因,沒法用真實項目,只能用書籍中公開的案例來考考它。
一、架構設計
這里我使用的案例是客服工單系統,是從一本書《從程序員到架構師》中提取出來的,這本書有很多實戰案例,順便向大家推薦一下。
客服工單系統的大概需求是這樣:
有個客服系統,用的MySQL數據庫,每年產生的工單有3000多萬條,每個工單會有5~6次操作,這些操作也要記錄下來,這樣每年就會有超過1.5億條操作記錄。
現在客服打開系統查看工單的時候,速度非常慢,10秒才能打開, 現在對SQL語句,索引等已經優化到了極致,無法再繼續提升。
現在系統性能已經嚴重影響了客服的處理效率,客戶要求一周之內解決這個問題,時間很短。
經過分析業務流程發現,工單如果處理完成,就會增加一個狀態“關閉”,這樣的工單,一年都打開不了幾次。
團隊沒有用過數據庫分區,一周內沒有任何把握搞定,就放棄了數據庫分區的方案。
對于這個問題,書中的解決方案是“冷熱分離”,日常操作“熱數據庫”,把“關閉”的工單移入新的“冷數據庫”,但是在數據冷熱分離過程中,需要處理數據一致性問題。
把這個需求拋給GPT-4,看它如何回答。
GPT-4:在這種情況下,我建議采用以下兩種方法來解決性能問題:
1.數據庫歸檔:由于大部分已關閉的工單基本上不再需要訪問,可以將這些工單數據從主數據庫中移動到一個歸檔數據庫中。這樣,主數據庫的大小將大大減小,從而提高查詢速度。歸檔數據庫可以定期(如每月或每季度)更新,將已關閉的工單移動到歸檔數據庫中......
具體操作步驟如下:
a. 創建一個新的MySQL數據庫,用于存儲歸檔數據。
b. 編寫一個腳本,定期將已關閉的工單及其相關操作記錄從主數據 庫移動到歸檔數據庫,并確保數據一致性。
c. 修改客服系統,使其默認僅查詢主數據庫中的未歸檔數據。
d. 提供一個單獨的界面或工具,供客服人員在需要時查詢歸檔數據 庫中的數據。
- 緩存:...略...
不錯,它一下子就抓住了重點,給出了數據庫歸檔的方案,還有具體的操作步驟。
不過,需求中有一定的提示,這個方案也容易想到。
劉欣:在你的操作步驟中,如何保證數據一致性,這里需要操作兩個數據庫啊
GPT-4 :確保數據一致性是非常重要的。在操作兩個數據庫時,可以采用以下方法來保證數據一致性:
- 使用事務:事務可以確保一組操作要么全部成功,要么全部失敗。.....略....
劉欣:你在使用事務的時候,怎么能開啟一個跨越兩個數據庫的事務?
GPT-4: 抱歉,我在之前的回答中確實犯了一個錯誤。在MySQL中,我們無法直接在兩個不同的數據庫之間使用單個事務。在這種情況下,可以考慮使用其他策略來確保數據一致性。一個可行的方法是使用“兩階段提交協議”(Two-Phase Commit, 2PC)。....略....
劉欣:兩階段提交協議很脆弱,有別的安全的辦法來實現數據從主數據庫移動到歸檔數據庫嗎?
GPT-4: 抱歉之前的方案沒有完全滿足您的需求。這里我提供一個新的方案,使用消息隊列(例如RabbitMQ、Kafka或Amazon SQS)來確保數據遷移過程的一致性。這種方法可以將數據遷移過程分為兩個獨立的步驟,確保在出錯時可以方便地回滾。.....略.....
劉欣:如果不使用MQ,完全自己寫代碼實現,如何保證數據遷移過程中的一致性?
GPT-4: 如果您不想使用消息隊列,您可以使用以下方法自行編寫代碼來確保數據遷移過程中的一致性:
- 使用鎖和標記字段:
a. 為工單表和操作記錄表分別添加一個名為“is_migrated”的布爾字段,用于標記記錄是否已遷移。
b. 編寫一個腳本或程序,從主數據庫中查詢滿足遷移條件(例如,已關閉的工單且“is_migrated”為false)的記錄。
......略......
嗯,到此為之,它終于找到了一個方案,和書中有點類似,就是用一個字段來標記“是否已遷移”。
但是,無論我怎么提示,它也不會提出如何做冪等性的方案,我就放棄了。
劉欣:歸檔數據庫數據量很大,查詢非常慢,但查詢基本上都是"根據客戶ID查出工單,然后根據工單ID查出該工單所有的處理記錄",這有什么辦法來解決?
GPT-4 :針對這種查詢模式,可以采取以下策略來優化歸檔數據庫的查詢性能:
- 為客戶ID和工單ID創建索引:......略......
- 數據庫表分區:......略......
- 數據庫視圖:......略......
- 結果緩存:......略......
- 拆分讀寫負載:......略......
- 優化硬件和配置:......略......
這些方案都無法有效解決不了問題,正確的方案是用HBase這樣的NoSQL數據庫,它是想不到了。
二、詳細設計
我使用的案例依然是薪水支付,這是從經典書《敏捷軟件開發:原則,模式和實踐》中提取出來的。
這個案例的需求是這樣的:
該系統由一個公司數據庫以及和員工相關的數據組成,系統需要準時地按照規則給員工支付薪水
員工有三種類型
1.鐘點工,每個小時有固定報酬,他們每天提交工作時間卡,其中記錄了日期以及工作小時數,如果每天工作超過8小時,按1.5倍進行支付。每周五對他們進行支付。
2.月薪員工,工資固定,每個月的最后一個工作日對他們進行支付
3.銷售人員,有固定工資,但會根據他們的銷售情況,支付給他們一定數量的傭金,他們會提交銷售憑條,其中記錄了銷售的日期和數量。每隔一周的周五對他們進行支付。
員工可以選擇支付方式,可以把支票郵寄到他們指定的郵政地址,也可以保存在財務那里隨時支取,或者要求直接存入他們指定的銀行賬戶。
看了這個需求以后,一般的設計是這樣的:
Employee 作為基類,不同類型的雇員類來繼承。
但是這個需求會有變更,客戶要求員工類型可以變更,例如從鐘點工變成月薪雇員,這樣上面的設計就不行了。
這個時候應該做個抽象,,用一個類PaymentClassification來表達支付分類,然后讓Employee類持有這個實例,簡單說就是用組合代替繼承。
這是一個陷阱,也是給ChatGPT挖的一個坑,看看它是如何處理的。
正式開始,我把需求告訴它,讓它設計。
沒想到,它一上來就給我寫Python代碼,這太多細節了,我馬上讓它停止輸出。
劉欣:不用展示代碼,把類描述出來就可以。
GPT-4 : 好的,根據您的需求,我們可以設計以下類和相關的屬性和方法:
- 基類 Employee: ......略......
- HourlyEmployee 類,繼承自 Employee 類:......略......
- SalariedEmployee 類,繼承自 Employee 類:......略......
- SalesEmployee 類,繼承自 SalariedEmployee 類:......略......
- PaymentMethod 類:略
還真是不錯,它“理解”了需求,從中抽取出了名詞進行類的設計,它設計出來的Employee,HourlyEmployee,SalariedEmployee,SalesEmployee和第一個UML圖幾乎是一樣的。
已經達到了面向對象設計的初級水平。
接下來開始挖坑:
劉欣:上面的類設計得很好,但是如果一個人剛開始是鐘點工,后來變成了月薪員工,上面的設計就無法支持這種變更了,這該怎么辦呢?
GPT-4 :為了解決您提到的問題,我們可以將員工的薪水計算策略從 Employee 類中分離出來,使用策略模式進行設計。這樣,我們可以在不修改 Employee 類的情況下,為其動態更改薪水計算策略。
在這種設計下,我們需要對原來的類結構進行一些調整:
- 保留基類 Employee:
新增方法:set_salary_strategy,用于設置員工的薪水計算策略
- 移除原來的子類 HourlyEmployee、SalariedEmployee 和 SalesEmployee,因為我們將薪水計算策略從 Employee 類中分離出來。
- 新增抽象類 SalaryStrategy,作為薪水計算策略的基類
- 新增具體策略類:
HourlySalary 類,繼承自 SalaryStrategy 類
SalariedSalary 類,繼承自 SalaryStrategy 類
SalesSalary 類,繼承自 SalaryStrategy 類
通過以上調整,現在可以在不修改 Employee 類的情況下為其動態更改薪水計算策略。當員工從鐘點工變為月薪員工時,只需為其設置新的薪水計算策略即可。
不得不說,GPT-4非常厲害!
它用上了策略模式,把薪水計算策略SalaryStrategy給抽象了出來。
和第二個UML圖相比,除了名稱不同,基本上一樣了。
可以說,能做到這一步,就可以超越很多程序員了。
我注意到,它一直沒有處理支付周期的問題。我開始繼續發問:
劉欣:原來的需求中還有支付的時間,例如鐘點工每周五支付,這個該怎么設計?
GPT-4: 為了處理不同類型員工的支付時間,我們可以在 SalaryStrategy 基類中引入一個抽象方法 should_pay_today,該方法根據當前日期判斷是否應該支付薪水。接著,在具體的策略類中實現這個方法。
......略......
這里它犯了一個錯誤,把支付周期放到了薪水計算策略中,還美名其曰“易于維護和擴展”。
劉欣:支付時間和薪水計算策略是兩個概念,放在一起不太好,怎么才能達到最大的靈活性呢?
GPT-4 :您是對的,支付時間和薪水計算策略是兩個不同的概念。為了使設計更具靈活性,我們可以將支付時間從薪水計算策略中分離出來,創建一個新的抽象類 PaymentSchedule,用于處理支付時間的邏輯。這樣,我們可以為每個員工分別設置薪水計算策略和支付時間策略。
以下是調整后的類結構:
保留基類 Employee:
- 屬性:姓名、ID、地址
方法:set_payment_method,用于設置員工的支付方式
方法:set_salary_strategy,用于設置員工的薪水計算策略
新增方法:set_payment_schedule,用于設置員工的支付時間策略
- 保留抽象類 SalaryStrategy 及其具體策略類,不做改動。
- 新增抽象類 PaymentSchedule,作為支付時間策略的基類:...略...
- 新增具體支付時間策略類,繼承PaymentSchedule:
WeeklyPayment 類 ...略...
MonthlyPayment 類 ...略...
BiweeklyPayment 類 ...略...
- 保留 PaymentMethod 類及其子類,不做改動。
非常驚艷! 它似乎知道我腦海中所想,PaymentSchedule 和 SalaryStrategy 給分開了!
到目前為止,它已經實現了書中最終的,也可能是最好的設計:
三、小結
在詳細設計層面上,GPT-4的表現遠遠強于架構設計。
碼農翻身的老讀者知道,我在去年用薪水支付案例測試過GPT-3.5, 當時它就是在背誦答案,甚至會給出超出需求之外的設計。
但是GPT-4不同了,它的設計能力更進了一步,在程序員的提示下,他已經學會了分離關注點。
在架構設計上,感覺GPT-4掌握了很多知識,但是無法有效地應用到復雜問題上,出的解決方案很混亂,離我們想要的還比較遠。
更關鍵的問題是如何識別它的回答是正確的,我現在手頭有標準答案,可以對它做考核。而在實際項目中,面對的都是未知數,如果沒有經驗,如何知道GPT-4給出的設計是有效的?是能解決問題的??