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