代碼要想寫得好须教,品位必須提一提嗜闻!

來源:公眾號 作者:程序猿DD
鏈接:https://mp.weixin.qq.com/s/FbISsjNTVQNqmGmWPwYNaQ

要寫出好代碼,首先需要提升品位典勇。

很多軟件工程師寫不好代碼戳晌,在評審他人的代碼時(shí)也看不出問題,就是因?yàn)槿狈么a標(biāo)準(zhǔn)的認(rèn)識痴柔。

現(xiàn)在還有太多的軟件工程師認(rèn)為,代碼只要可以正確執(zhí)行就可以了疫向。這是一種非常低的評價(jià)標(biāo)準(zhǔn)咳蔚,很多重要的方面都被忽視了。

好代碼的特性

好代碼具有以下特性搔驼。

1. 魯棒(Solid and Robust)

代碼不僅要被正確執(zhí)行谈火,我們還要考慮對各種錯誤情況的處理,比如各種系統(tǒng)調(diào)用和函數(shù)調(diào)用的異常情況舌涨,系統(tǒng)相關(guān)組件的異常和錯誤糯耍。

對很多產(chǎn)品級的程序來說,異常和錯誤處理的邏輯占了很大比例囊嘉。

2. 高效(Fast)

程序的運(yùn)行應(yīng)使用盡量少的資源温技。資源不僅僅包括CPU,還可能包括存儲扭粱、I/O等舵鳞。

設(shè)計(jì)高效的程序,會運(yùn)用到數(shù)據(jù)結(jié)構(gòu)和算法方面的知識琢蛤,同時(shí)要考慮到程序運(yùn)行時(shí)的各種約束條件蜓堕。

3. 簡潔(Maintainable and Simple)

代碼的邏輯要盡量簡明易懂抛虏,代碼要具有很好的可維護(hù)性。對于同樣的目標(biāo)套才,能夠使用簡單清楚的方法達(dá)成迂猴,就不要使用復(fù)雜晦澀的方法。

“大道至簡”背伴,能否把復(fù)雜的問題用簡單的方式實(shí)現(xiàn)出來沸毁,這是一種編程水平的體現(xiàn)。

4. 簡短(Small)

在某種意義上挂据,代碼的復(fù)雜度和維護(hù)成本是和代碼的規(guī)模直接相關(guān)的以清。在實(shí)現(xiàn)同樣功能的時(shí)候,要盡量將代碼寫得簡短一些崎逃。

簡潔高于簡短掷倔。這里要注意,某些人為了能把代碼寫得簡短个绍,使用了一些晦澀難懂的描述方式勒葱,降低了代碼的可讀性。這種方式是不可取的巴柿。

5. 可測試(Testable)

代碼的正確性要通過測試來保證凛虽,尤其是在敏捷的場景下,更需要依賴可自動回歸執(zhí)行的測試用例广恢。

在代碼的設(shè)計(jì)中凯旋,要考慮如何使代碼可測、易測钉迷。一個(gè)比較好的實(shí)踐是使用TDD(Test-Driven Development至非,測試驅(qū)動開發(fā))的方法,這樣在編寫測試用例的時(shí)候會很快發(fā)現(xiàn)代碼在可測試性方面的問題糠聪。

6. 共享(Re-Usable)

大量的程序?qū)嶋H上都使用了類似的框架或邏輯荒椭。由于目前開源代碼的大量普及,很多功能并不需要重復(fù)開發(fā)舰蟆,只進(jìn)行引用和使用即可趣惠。

在一個(gè)組織內(nèi)部,應(yīng)鼓勵共享和重用代碼身害,這樣可以有效降低代碼研發(fā)的成本味悄,并提升代碼的質(zhì)量。

實(shí)現(xiàn)代碼的共享塌鸯,不僅需要在意識方面提升傍菇,還需要具有相關(guān)的能力(如編寫?yīng)毩ⅰ⒏哔|(zhì)量的代碼庫)及相關(guān)基礎(chǔ)設(shè)施的支持(如代碼搜索界赔、代碼引用機(jī)制)丢习。

7. 可移植(Portable)

某些程序需要在多種操作系統(tǒng)下運(yùn)行牵触,在這種情況下,代碼的可移植性成為一種必需的能力咐低。

要讓代碼具有可移植性揽思,需要對所運(yùn)行的各種操作系統(tǒng)底層有充分的理解和統(tǒng)一抽象。一般會使用一個(gè)適配層來屏蔽操作系統(tǒng)底層的差異见擦。

一些編程語言也提供了多操作系統(tǒng)的可移植性钉汗,如很多基于Python語言、Java語言鲤屡、Go語言編寫的程序损痰,都可以跨平臺運(yùn)行。

8. 可觀測(Observable) / 可監(jiān)控(Monitorable)

面對目前大量存在的在線服務(wù)(Online Service)程序酒来,需要具備對程序的運(yùn)行狀態(tài)進(jìn)行細(xì)致而持續(xù)監(jiān)控的能力卢未。

這要求在程序設(shè)計(jì)時(shí)就提供相關(guān)的機(jī)制,包括程序狀態(tài)的收集堰汉、保存和對外輸出辽社。

9. 可運(yùn)維(Operational)

可運(yùn)維已經(jīng)成為軟件研發(fā)活動的重要組成部分,可運(yùn)維重點(diǎn)關(guān)注成本翘鸭、效率和穩(wěn)定性三個(gè)方面滴铅。

程序的可運(yùn)維性和程序的設(shè)計(jì)、編寫緊密相關(guān)就乓,如果在程序設(shè)計(jì)階段就沒有考慮可運(yùn)維性汉匙,那么程序運(yùn)行的運(yùn)維目標(biāo)則難以達(dá)成。

10. 可擴(kuò)展(Scalable and Extensible)

可擴(kuò)展包含“容量可擴(kuò)展”(Scalable)和“功能可擴(kuò)展”(Extensible)兩方面生蚁。

在互聯(lián)網(wǎng)公司的系統(tǒng)設(shè)計(jì)中噩翠,“容量可擴(kuò)展”是重要的設(shè)計(jì)目標(biāo)之一。系統(tǒng)要盡量支持通過增加資源來實(shí)現(xiàn)容量的線性提高守伸。

快速響應(yīng)需求的變化,是互聯(lián)網(wǎng)公司的另外一個(gè)重要挑戰(zhàn)浦妄∧崮。可考慮使用插件式的程序設(shè)計(jì)方式,以容納未來可能新增的功能剂娄,也可考慮使用類似Protocol Buffer 這樣的工具蠢涝,支持對協(xié)議新增字段。

以上十條標(biāo)準(zhǔn)阅懦,如果要記住和二,可能有些困難。我們可以把它們歸納為四個(gè)方面耳胎,見表1惯吕。

表1 對一流代碼特性的匯總分類

壞代碼的例子

關(guān)于好代碼惕它,上面介紹了一些特性,本節(jié)也給出壞代碼(Bad Code)的幾個(gè)例子废登。關(guān)于壞代碼淹魄,本書沒有做系統(tǒng)性總結(jié),只是希望通過以下這些例子的展示讓讀者對壞代碼有直觀的感覺堡距。

1. 不好的函數(shù)名稱(Bad Function Name)

如do()甲锡,這樣的函數(shù)名稱沒有多少信息量;又如myFunc()羽戒,這樣的函數(shù)名稱缤沦,個(gè)人色彩過于強(qiáng)烈,也沒有足夠的信息量易稠。

2. 不好的變量名稱(Bad Variable Name)

如a缸废、b、c缩多、i呆奕、j、k衬吆、temp梁钾,這樣的變量名稱在很多教科書中經(jīng)常出現(xiàn),很多人在上學(xué)期間寫代碼時(shí)也會經(jīng)常這樣用逊抡。如果作為局部變量姆泻,這樣的名稱有時(shí)是可以接受的;但如果作為作用域稍微大的變量冒嫡,這樣的名稱就非常不可取了拇勃。

3. 沒有注釋(No Comments)

有寫注釋習(xí)慣的軟件工程師很少,很多軟件工程師認(rèn)為寫注釋是浪費(fèi)時(shí)間孝凌,是“額外”的工作方咆。但是沒有注釋的代碼,閱讀的成本會比較高蟀架。

4. 函數(shù)不是單一目的(The Function has No Single Purpose)

如LoadFromFileAndCalculate()瓣赂。這個(gè)例子是我編造的,但現(xiàn)實(shí)中這樣的函數(shù)其實(shí)不少片拍。很多函數(shù)在首次寫出來的時(shí)候煌集,就很難表述清楚其用途;還有一些函數(shù)隨著功能的擴(kuò)展捌省,變得越來越龐雜苫纤,也就慢慢地說不清它的目的了。

這方面的問題可能很多人都沒有充分地認(rèn)識到——非單一目的的函數(shù)難以維護(hù),也難以復(fù)用卷拘。

5. 不好的排版(Bad Layout)

不少人認(rèn)為喊废,程序可以正常執(zhí)行就行了,所以一些軟件工程師不重視對代碼的排版恭金,認(rèn)為這僅僅是一種“形式”操禀。

沒有排好版的程序,在閱讀效率方面會帶來嚴(yán)重問題横腿。這里舉一個(gè)極端的例子:對于C語言來說颓屑,“;”可作為語句的分割符,而“縮進(jìn)”和“換行”對于編譯器來說是無用的耿焊,所以完全可以把一段C語言程序都“壓縮”在一行內(nèi)揪惦。這樣的程序是可以運(yùn)行的,但是對人來說罗侯,可讀性非常差器腋。這樣的程序肯定是我們非常不希望看到的。

6. 無法測試(None Testable)

程序的正確性要依賴測試來保證(雖然測試并不能保證程序完全無錯)钩杰。無法或不好為之編寫測試用例的程序纫塌,是很難有質(zhì)量保證的。

好代碼從哪里來

上一節(jié)說明了好代碼的特性讲弄,本節(jié)來分析好代碼是如何產(chǎn)出的措左。

好代碼不止于編碼

好代碼從哪里來?

對于這個(gè)問題避除,很多讀者肯定會說:“好代碼肯定是寫出來的呀怎披。”

我曾做過多次調(diào)研瓶摆,發(fā)現(xiàn)很多軟件工程師日常所讀的書確實(shí)是和“寫代碼”緊密相關(guān)的凉逛。

但是,這里要告訴讀者的是群井,代碼不只是“寫”出來的状飞。在很多年前,我所讀的軟件工程方面的教科書就告訴我书斜,編碼的時(shí)間一般只占一個(gè)項(xiàng)目所花時(shí)間的 10%诬辈。我曾說過一句比較有趣的話:

“如果一個(gè)從業(yè)者告訴你,他的大部分時(shí)間都在寫代碼菩佑,那么他大概率不是一個(gè)高級軟件工程師自晰∧”

那么稍坯,軟件工程師的時(shí)間都花到哪里去了呢?軟件工程師的時(shí)間應(yīng)該花在哪里呢?

好的代碼是多個(gè)工作環(huán)節(jié)的綜合結(jié)果瞧哟。

(1)在編碼前混巧,需要做好需求分析和系統(tǒng)設(shè)計(jì)。而這兩項(xiàng)工作是經(jīng)常被大量軟件工程師忽略或輕視的環(huán)節(jié)勤揩。

(2)在編碼時(shí)咧党,需要編寫代碼和編寫單元測試。對于“編寫代碼”陨亡,讀者都了解傍衡;而對于“編寫單元測試”,有些軟件工程師就不認(rèn)同了负蠕,甚至還有人誤以為單元測試是由測試工程師來編寫的蛙埂。

(3)在編碼后,要做集成測試遮糖、上線绣的,以及持續(xù)運(yùn)營/迭代改進(jìn)。這幾件事情都是要花費(fèi)不少精力的欲账,比如上線屡江,不僅僅要做程序部署,而且要考慮程序是如何被監(jiān)控的赛不。有時(shí)惩嘉,為了一段程序的上線,設(shè)計(jì)和實(shí)施監(jiān)控的方案要花費(fèi)好幾天才能完成俄删。

因此宏怔,一個(gè)好的系統(tǒng)或產(chǎn)品是以上這些環(huán)節(jié)持續(xù)循環(huán)執(zhí)行的結(jié)果。

需求分析和系統(tǒng)設(shè)計(jì)

1. 幾種常見的錯誤現(xiàn)象

相對于編碼工作畴椰,需求分析和系統(tǒng)設(shè)計(jì)是兩個(gè)經(jīng)常被忽視的環(huán)節(jié)臊诊。在現(xiàn)實(shí)工作中,我們經(jīng)常會看到以下這些現(xiàn)象斜脂。

(1)很多人錯誤地認(rèn)為抓艳,寫代碼才是最重要的事情。不少軟件工程師如果一天沒有寫出幾行代碼帚戳,就會認(rèn)為工作沒有進(jìn)展玷或;很多管理者也會以代碼的產(chǎn)出量作為衡量工作結(jié)果的主要標(biāo)準(zhǔn),催促軟件工程師盡早開始寫代碼片任。

(2)有太多的從業(yè)者偏友,在沒有搞清楚項(xiàng)目目標(biāo)之前就已經(jīng)開始編碼了。在很多時(shí)候对供,項(xiàng)目目標(biāo)都是通過并不準(zhǔn)確的口頭溝通來確定的位他。例如:

“需要做什么氛濒?”

“就按照×××網(wǎng)站的做一個(gè)吧《焖瑁”

(3)有太多的從業(yè)者舞竿,在代碼編寫基本完成后,才發(fā)現(xiàn)設(shè)計(jì)思路是有問題的窿冯。他們在很多項(xiàng)目上花費(fèi)很少(甚至沒有花費(fèi))時(shí)間進(jìn)行系統(tǒng)設(shè)計(jì)骗奖,對于在設(shè)計(jì)中所隱藏的問題并沒有仔細(xì)思考和求證⌒汛基于這樣的設(shè)計(jì)投入和設(shè)計(jì)質(zhì)量执桌,項(xiàng)目出現(xiàn)設(shè)計(jì)失誤也是很難避免的。而面對一個(gè)已經(jīng)完成了基本編碼的項(xiàng)目芜赌,如果要“動大手術(shù)”來修改它鼻吮,相信每個(gè)有過類似經(jīng)歷的人都一定深知那種感受——越改越亂,越改越著急较鼓。

以上這幾種情況椎木,很多讀者是不是都有過類似經(jīng)歷?

2. 研發(fā)前期多投入博烂,收益更大

關(guān)于軟件研發(fā)香椎,首先我們需要建立一個(gè)非常重要的觀念。

在研發(fā)前期(需求分析和系統(tǒng)設(shè)計(jì))多投入資源禽篱,相對于把資源都投入在研發(fā)后期(編碼畜伐、測試等),其收益更大躺率。

這是為什么呢玛界?

要回答這個(gè)問題,需要從軟件研發(fā)全生命周期的角度來考量軟件研發(fā)的成本悼吱。除編碼外慎框,軟件測試、上線后添、調(diào)試等都需要很高成本笨枯。如果我們把需求搞錯了,那么與錯誤需求有關(guān)的設(shè)計(jì)遇西、編碼馅精、測試、上線等成本就都浪費(fèi)了粱檀;如果我們把設(shè)計(jì)搞錯了洲敢,那么與錯誤設(shè)計(jì)相關(guān)的編碼、測試茄蚯、上線的成本也就浪費(fèi)了压彭。

如果仔細(xì)考量那些低效的項(xiàng)目称近,會發(fā)現(xiàn)有非常多的類似于上面提到的“浪費(fèi)”的地方。軟件工程師似乎都很忙哮塞,但是在錯誤方向上所做的所有努力并不會產(chǎn)生任何價(jià)值,而大部分的加班實(shí)際上是在做錯誤的事情凳谦,或者是為了補(bǔ)救錯誤而努力忆畅。在這種情況下,將更多的資源和注意力向研發(fā)前期傾斜會立刻收到良好的效果尸执。

3. 修改代碼和修改文檔家凯,哪個(gè)成本更高

很多軟件工程師不愿意做需求分析和系統(tǒng)設(shè)計(jì),是因?yàn)閷Α皩懳臋n”有著根深蒂固的偏見如失。這里問大家一個(gè)問題绊诲,如果大家對這個(gè)問題能給出正確的回答,那么在“寫文檔”的意識方面褪贵,一定會有很大的轉(zhuǎn)變掂之。

任何人都不是神仙,無法一次就把所有事情做對脆丁。對于一段程序來說世舰,它一定要經(jīng)過一定周期的修改和迭代。這時(shí)有兩種選擇:

選擇一:修改文檔槽卫。在設(shè)計(jì)文檔時(shí)完成迭代調(diào)整跟压,待沒有大問題后再開始編碼。

選擇二:修改代碼歼培。只有粗略的設(shè)計(jì)文檔震蒋,或者沒有設(shè)計(jì)文檔,直接開始編碼躲庄,所有的迭代調(diào)整都在代碼上完成查剖。

請大家判斷,修改代碼和修改文檔噪窘,哪個(gè)成本更高梗搅?

在之前的一些分享交流會上,對于這個(gè)問題效览,有人會說无切,修改文檔的成本更高。因?yàn)樵谛薷奈臋n后還要修改代碼丐枉,多了一道手續(xù)哆键。而直接修改代碼,只需要做一次瘦锹,這樣更直接籍嘹。

這個(gè)回答說明了回答者沒有充分理解“先寫文檔闪盔,后寫代碼”的設(shè)計(jì)方法。如果沒有充分重視設(shè)計(jì)文檔的工作辱士,在輸出的設(shè)計(jì)文檔質(zhì)量不高的情況下就開始編碼泪掀,確實(shí)會出現(xiàn)以上提到的問題。但是颂碘,如果在設(shè)計(jì)文檔階段就已經(jīng)做了充分考慮异赫,會減少對代碼的迭代和反復(fù)。

對于同樣的設(shè)計(jì)修改头岔,“修改代碼”的成本遠(yuǎn)高于“修改文檔”塔拳。這是因?yàn)椋谠O(shè)計(jì)文檔中只會涉及主要的邏輯峡竣,那些細(xì)小的靠抑、顯而易見的邏輯不會在設(shè)計(jì)文檔中出現(xiàn)。在修改設(shè)計(jì)文檔時(shí)适掰,也只會影響到這些主要邏輯颂碧。而如果在代碼中做修改,不僅會涉及這些主要邏輯类浪,而且會涉及那些在文檔中不會出現(xiàn)的細(xì)小邏輯稚伍。對于一段程序來說,任何一個(gè)邏輯出現(xiàn)問題戚宦,程序都是無法正常運(yùn)行的个曙。

4. 需求分析和系統(tǒng)設(shè)計(jì)之間的差別

很多讀者無法清楚地區(qū)分“需求分析”和“系統(tǒng)設(shè)計(jì)”之間的差別,于是會發(fā)現(xiàn)受楼,在寫出的文檔中垦搬,有些需求分析文檔里出現(xiàn)了系統(tǒng)設(shè)計(jì)的內(nèi)容,而有些系統(tǒng)設(shè)計(jì)文檔里又混雜了需求分析的內(nèi)容艳汽。

我們用幾句話可以非常明確地給出二者的差異猴贰。

(1)需求分析:定義系統(tǒng)/軟件的黑盒的行為,它是從外部(External)看到的河狐,在說明“是什么”(What)米绕。

(2)系統(tǒng)設(shè)計(jì):設(shè)計(jì)系統(tǒng)/軟件的白盒的機(jī)制,它是從內(nèi)部(Internal)看到的馋艺,要說明“怎么做”(How)和“為什么”(Why)栅干。

比如,對一輛汽車來說捐祠,首先使用者從外部可以看到車廂碱鳞、車輪,坐在車?yán)锟梢钥吹椒较虮P踱蛀、剎車踏板窿给、油門踏板等贵白;操作方向盤可以改變汽車的行駛方向,腳踩剎車踏板崩泡、油門踏板可用于減速和加速禁荒。以上這些是對汽車的“需求分析”。

然后角撞,我們想象汽車外殼和內(nèi)部變成了透明的呛伴,可以看到汽車內(nèi)部的發(fā)動機(jī)、變速箱靴寂、傳動桿、與剎車相關(guān)的內(nèi)部裝置等召耘。而這些對駕駛者來說是不可見的百炬,它們是對汽車的“系統(tǒng)設(shè)計(jì)”。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末污它,一起剝皮案震驚了整個(gè)濱河市剖踊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌衫贬,老刑警劉巖德澈,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異固惯,居然都是意外死亡梆造,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進(jìn)店門葬毫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镇辉,“玉大人,你說我怎么就攤上這事贴捡『龈兀” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵烂斋,是天一觀的道長屹逛。 經(jīng)常有香客問我,道長汛骂,這世上最難降的妖魔是什么罕模? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮帘瞭,結(jié)果婚禮上手销,老公的妹妹穿的比我還像新娘。我一直安慰自己图张,他們只是感情好锋拖,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布诈悍。 她就那樣靜靜地躺著,像睡著了一般兽埃。 火紅的嫁衣襯著肌膚如雪侥钳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天柄错,我揣著相機(jī)與錄音舷夺,去河邊找鬼。 笑死售貌,一個(gè)胖子當(dāng)著我的面吹牛给猾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播颂跨,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼敢伸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了恒削?” 一聲冷哼從身側(cè)響起池颈,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钓丰,沒想到半個(gè)月后躯砰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡携丁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年琢歇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梦鉴。...
    茶點(diǎn)故事閱讀 40,561評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡矿微,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尚揣,到底是詐尸還是另有隱情涌矢,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布快骗,位于F島的核電站娜庇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏方篮。R本人自食惡果不足惜名秀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望藕溅。 院中可真熱鬧匕得,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至考阱,卻和暖如春翠忠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背乞榨。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工秽之, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吃既。 一個(gè)月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓考榨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鹦倚。 傳聞我的和親對象是個(gè)殘疾皇子河质,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評論 2 359

推薦閱讀更多精彩內(nèi)容