XP学习笔记

传统软件工程方法的文档辆过重
👇
于是出现了 👉 敏捷开发 👉 “轻量级”方法的软件开发方法
👇
XP是敏捷开发的一种方式

定义:

XP是一种轻量(敏捷)、高效、低风险、柔性、可预测、科学而且充满乐趣的软件开发方式。与其他方法论相比,其最大的不同在于:

  • 在更短的周期内,更早地提供具体、持续的反馈信息。
  • 在迭代的进行计划编制,首先在最开始迅速生成一个总体计划,然后在整个项目开发过程中不断的发展它。
  • 依赖于自动测试程序来监控开发进度,并及早地捕获缺陷。
  • 依赖于口头交流、测试和源程序进行沟通。
  • 倡导持续的演化式设计。
  • 依赖于开发团队内部的紧密协作。
  • 尽可能达到程序员短期利益和项目长期利益的平衡。

内容:

XP由价值观、原则、实践和行为四个部分组成,它们彼此相互依赖、关联, 并通过行为贯穿于整个生命期

一、 四大价值观:沟通、简单、反馈、勇气。

  1. 沟通促进协作;
  • 工作简单化,重复没必要的工作cut掉;提倡对代码进行重构,保持良好结构和可拓展性;
  • 开发内部及时反馈代码问题与进展;向客户与管理层及时反馈可运行版本及时发现问题;
  • XP方法论要求开发人员穿上强大、自动测试的盔甲,勇往直前,在重构、编码规范的支持下,有目的地快速开发
    在这四大价值观之下,隐藏着一个更深刻的东西,那就是尊重。
    因为这一切都建立在团队成员之间的相互关心、相互理解的基础之上。

二、 原则

  1. 快速反馈
    及时地、快速地获取反馈,并将所学到的知识尽快地投入到系统中去;
    (开发人员应该通过较短的反馈循环迅速地了解现在的产品是否满足了客户的需求)
  2. 简单性假设
    要求开发人员将每个问题都看得十分容易解决,也就是说只为本次迭代考虑,不去想未来可能需要什么,相信具有将来必要时增加系统复杂性的能力,也就是号召大家出色地完成今天的任务。
  3. 逐步修改
    微调。不要一次做出很大的改变,那样将会使得可控性变差。
  4. 提倡更改
    尽量为下一次修改做好准备。
  5. 优质工作
    贯彻的是“小步快走”的开发原则,因此工作质量决不可打折扣,通常采用测试先行的编码方式来提供支持。

三、 实践(13个)
在XP中,集成了13个最佳实践。有趣的是,它们没有一个是创新的概念,大多数概念和编程一样老。其主要创新点在于提供一种良好的思路,将这些最佳实践结合在一起,并且确保尽可能彻底地执行它们,使得它们能够在最大程度上相互支持。

  1. 计划游戏
  • 主要思想:先快速地制定一份概要的计划,然后随着项目细节的不断清晰,再逐步完善这份计划。
  • 产生的结果:一套用户故事及后续的一两次迭代的概要计划。
  • 计划游戏获得成功的前提条件:客户负责业务决策,开发团队负责技术决策。(系统的范围、下一次迭代的发布时间、用户故事的优先级应该由客户决定;而每个用户故事所需的开发时间、不同技术的成本、如何组建团队、每个用户故事的风险,以及具体的开发顺序由开发团队决定。)
  • 流程
    • 首先客户和开发人员坐在同一间屋子里,每个人都准备一支笔、一些用于记录用户故事的纸片,最好再准备一个白板
    • 客户编写故事:由客户谈论系统应该完成什么功能,然后用通俗的自然语言,使用自己的语汇,将其写在卡片上
    • 开发人员进行估算:首先客户按优先级将用户故事分成必须要有、希望有、如果有更好三类,然后开发人员对每个用户故事进行估算,先从高优先级开始估算。如果在估算的时候,感到有一些故事太大,不容易进行估算,或者是估算的结果超过2人/周,那么就应该对其进行分解,拆成2个或者多个小故事
    • 确定迭代的周期:接下来就是确定本次迭代的时间周期,这可以根据实际的情况进行确定,不过最佳的迭代周期是2~3周。有了迭代的时间之后,再结合参与的开发人数,算出可以完成的工作量总数。然后根据估算的结果,与客户协商,挑出时间上够、优先级合适的用户故事组合,形成计划
  1. 小型发布
    每一次发布的版本应该尽可能的小,秉承“持续集成,小步快走”的哲学。前提条件:每个版本有足够的商业价值,值得发布。
    由于小型发布可以使得集成更频繁,客户获得的中间结果也越频繁,反馈也就越频繁,客户就能够实时地了解项目的进展情况,从而提出更多的意见,以便在下一次迭代中计划进去。以实现更高的客户满意度
  2. 隐喻
    相对而言,隐喻这一个最佳实践是最令人费解的。根据词典,隐喻的定义是:一种语言的表达手段,它用来暗示字面意义不相似的事物之间的相似之处。(当然,如果能够找到合适的隐喻是十分快乐的,但并不是每种情况都可以找到恰当的隐喻,也没有必要强求)
  • 隐喻的作用:
    • 寻求共识:也就是鼓励开发人员在寻求问题共识时,可以借用一些沟通双方都比较熟悉的事物来做类比,从而帮助大家更好地理解解决方案的关键结构,也就是更好地理解系统是什么、能做什么。
    • 发明共享词汇:通过隐喻,有助于提出一个用来表示对象、对象间的关系通用名称。例如,策略模式(用来表示可以实现多种不同策略的设计模式)、工厂模式(用来表示可以按需“生产”出所需类得设计模式)等。
    • 创新的武器:有的时候,可以借助其他东西来找到解决问题的新途径。例如:“我们可以将工作流看做一个生产线”。
      描述体系结构:体系结构是比较抽象的,引入隐喻能够大大减轻理解的复杂度。例如管道体系结构就是指两个构件之间通过一条传递消息的“管道”进行通信。
  1. 简单设计
    强调简单设计的价值观,引出了简单性假设原则,落到实处就是“简单设计”实践。这个实践看上去似乎很容易理解,但却又经常被误解,许多批评者就指责XP忽略设计是不正确的。其实,XP的简单设计实践并不是要忽略设计,而且认为设计不应该在编码之前一次性完成,因为那样只能建立在“情况不会发生变化”或者“我们可以预见所有的变化”之类的谎言的基础上的。

Kent Beck概念中简单设计是这样的:
>能够通过所有的测试程序。
没有包括任何重复的代码。
清楚地表现了程序员赋予的所有意图。
包括尽可能少的类和方法

他认为要想保持设计简单的系统,需要具备简单思考的能力,拥有理解代码和修改的勇气,以及为了消除代码的“坏味道”而定期重构的习惯。

流程
(1)首先写测试代码:具体将在后面详细描述。
(2)保持每个类只负责一件事:SRP(单一职责原则)是面向对象设计的基础原则之一。
(3)使用Demeter(迪米特)法则:迪米特法则,也称为LoD法则、最少知识原则。也就是指一个对象应当对其他对象尽可能少地了解。用隐喻的方法来解释的话就是“只与你直接的朋友通信”、“不要和陌生人说话”。
(4)使用CRC卡片进行探索。

  1. 测试先行/测试驱动开发
    打个比方:
    工匠一:先拉上一根水平线,砌每一块砖时,都与这跟水平线进行比较,使得每一块砖都保持水平。
    工匠二:先将一排砖都砌完,然后再拉上一根水平线,看看哪些砖有问题,对有问题的砖进行适当的调整。
    显然,工匠二的做法浪费时间。然而平时在编写程序的时候又是怎么做的呢?我们就是按工匠二的方法在工作呀!甚至有时候比工匠二还笨,是整面墙都砌完了,直接进行“集成测试”,经常让整面的墙倒塌。

不仅我们没有采用工匠一的工作方法,甚至有的时候程序员会以“开发工作太紧张”为理由,而忽略测试工作。但这样却导致了一个恶性循环,越是没有空编写测试程序,代码的效率与质量越差,花在找Bug、解决Bug的时间也越来越多,实际产能大打降低。由于产能降低了,因此时间更紧张,压力更大。你想想,为什么不拉上一根水平线呢?难道,我们不能够将后面浪费的时间花在单元测试上,使得我们的程序一开始就更健壮,更加易于修改吗?不过,编写测试程序当然要比拉一条水平线难道多,所以我们需要引入“自动化测试工具”,免费的xUnit测试框架就是你最佳的选择。
为了鼓励程序员原意甚至喜欢在编写程序之前编写测试代码,XP方法论还提供了许多有说服力的理由。
如果你已经保持了简单的设计,那么编写测试代码根本不难。
如果你在结对编程,那么如果你想出一个好的测试代码,那么你的伙伴一定行。
当所有的测试都通过的时候,你再也不会担心所写的代码今后会“暗箭伤人”,那种感觉是相当棒的。
当你的客户看到所有的测试都通过的时候,会对程序充满前所未有的信心。
当你需要进行重构时,测试代码会给你带来更大的勇气,因为你要测试是否重构成功只需要一个按钮。

测试先行是XP方法论中一个十分重要的最佳实践,并且其中所蕴含的知识与方法也十分丰富。

  1. 重构
    重构时一种对代码进行改进而不影响功能实现的技术,XP需要开发人员在闻到代码的坏味道时,有重构代码的勇气。
    重构的目的是降低变化引发的风险,使得代码优化更加容易。通常重构发生在两种情况之下。
    实现某个特性之前:尝试改变现有的代码结构,以使得实现新的特性更加容易。
    实现某个特性之后:检查刚刚写完的代码后,认真检查一下,看是否能够进行简化。

在《重构》一书中,作者Martin Fowler提示我们:在考虑重构时,应该要养成编写并经常运行测试代码的习惯;要先编写代码,再进行重构;把每一次增加功能都当做一次重构的好时机;将每一个纠正错误当做一次重构的重要时机。同时,该书中也列出大量需要重构的情况和重构方法。
最后类似地,给还没有足够勇气进行重构的程序员打几剂强心针:
XP提倡集体代码所有制,因此你可以大胆地在任何需要修改的地方做改动。
由于在XP项目组中有完整的编码标准,因此在重构前无须重新定义格式。
在重构中遇到困难,和你结对编程的伙伴能够为你提供有效的帮助。
简单的设计,会给重构带来很大的帮助。
测试先行让你拥有了一个有效的检验器,随时运行一下就知道你重构的工作是否带来了影响。
由于XP在持续集成,因此你重构所带来的破坏很快就能够暴露,并且得以解决。

重构技术是对简单性设计的一个良好的补充,也是XP中重视“优质工作”的体现,这也是优秀的程序员必备的一项技能。

  1. 结对编程
    “什么!两个人坐在一起写程序?那岂不是对人力的巨大浪费吗?而且我在工作时可不喜欢有一个人坐在边上当检察官。”是的,正如这里列举出来的问题一样,结对编程技术还是被很多人质疑的。
    但是长期研究得出:结对编程的效率反而比单独编程更高。一开始虽然会牺牲一些速度,但慢慢的,开发速度会逐渐加快。
    究其原因,主要是结对编程大打降低了沟通的成本,提供了工作的质量,具体表现在:
  • 所有的设计决策确保不是由一个人做出的。
  • 系统的任何一个部分都肯定至少有2个人以上熟悉。
  • 几乎不可能有2个人都忽略的测试项或者其他任务。
  • 结对组合的动态性,是一个企业知识管理的好途径。
  • 代码总是能够保证被评审过。
  • 而且XP方法论集成的其他最佳实践也能够使得结对编程更加容易进行:
    • 编码标准可以消除一些无谓的分歧。
    • 隐喻可以帮助结对伙伴更好地沟通。
    • 简单设计可以使得结对伙伴更了解他们所从事的工作。

结对编程技术被誉为XP保持工作质量、强调人文主义的一个典型的实践,应用得当还能够使得开发团队之前的协作更加流畅、知识交流与共享更加频繁,团队的稳定性也会更加稳固。

  1. 集体代码所有制
    团队中的每个成员都拥有对代码进行改进的权利,每个人都拥有全部代码,也都需要对全部代码负责。同时,XP强调代码是谁破坏的(也就是修改后发生问题),就应该由谁来修复。
    由于在XP中,有一些与之匹配的最佳实践,因此你并无须担心采用集体代码所有制会让你的代码变得越来越乱。
    由于在XP项目中,集成工作是一件经常性得工作,因此当有人修改代码而带来了集成的问题,会在很快的时间内被发现。
    由于每一个类都会有一个测试代码,因此不论谁修改了代码,都需要运行这个测试代码,这样偶然性的破坏发生的概率将很小。
    由于每一个代码的修改就是通过了结对的两个程序员共同思考,因此通常做出的修改都是对系统有益的。
    由于大家都坚持了相同的编码标准,因此代码的可读性、可修改性都会比较好,而且还能够避免由于命名法、缩进等小问题引发经常性得代码修改。

集成代码所有制是XP与其他敏捷方法的一个较大不同,也是从另一个侧面体现了XP中蕴含的很深厚的编码情节。

  1. 持续集成
    在前面谈到小型发布、重构、结对编程、集体代码所有制等最佳实践的时候,我们多次看到“持续集成”的身影,可以说持续集成是对这些最佳实践的基本支撑条件。
    可能大家会对持续集成与小型发布代表的意思混淆不清,其实小型发布是指在开发周期经常发布中间版本,而持续集成的含义则是要求XP团队每天尽可能多次地做代码集成,每次都在确保系统运行的单元测试通过之后进行。
    这样,就可以及早地暴露、消除由于重构、集体代码所有制所引入的错误,从而减少解决问题的痛苦。
    要在开发过程中做到持续集成并不容易,首先需要养成这个习惯。而且集成工作往往是十分枯燥、烦琐的,因此适当地引入每日集成工具是十分必要的。XP建议大家首先使用配置管理服务器将代码管理起来,然后使用Ant或Nant等XP工具,编写集成脚本,调用xUint等测试框架,这样就可以实现每当程序员将代码Check in到配置服务器上时,Ant就会自动完成编译和集成,并调用测试代码完成相应的测试工作。
  2. 每周工作40小时/可持续的速度
    XP方法论认为,加班最终会扼杀团队的积极性,最终导致项目失败。充分体现了XP方法关注人的因素比关注过程的因素更多一些。
    Kent Beck认为开发人员即使能够工作更长的时间,他们也不该这样做,因为这样做会使他们更容易厌倦编程工作,从而产生一些影响他们效能的其他问题。因此,每周工作40小时是一种顺势行为,是一种规律。其实对于开发人员和管理者来说,违反这种规律是不值得的。
    开发人员:如果不懂得休息,那么就无法将自己的节奏调整到最佳状态,那么就会带来很大的负面影响。而且在精神不集中的状态下,开发质量也得不到保证。
    管理者:也许这可以称得上“第二种人月神话”,那就是你不得不通过延长每天的工作时间来获得更多的人月。这是因为,每个开发人员的工作精力是有限的,不可能无限增长,在精力不足的时候,不仅写出来的代码质量没有保障,而且还可能为项目带来退步的效果。因此采用加班的方式并不是一个理性的方式,是得不偿失的。

不过有一点是需要解释的,“每周工作40小时”中的40不是一个绝对数,它所代表的意思是团队应该保证按照“正常的时间”进行工作。那么如何做到这一点呢?
首先,定义符合你团队情况的“正常工作时间”。
其次,逐步将工作时间调整到“正常工作时间”。
再次,除非你的时间计划一团糟,否则不应该在时间妥协。
最后,鼓起勇气,制定一个合情合理的时间表。
正如米卢说过的“享受足球”一样,同样地,每一个开发人员应该做到“享受编程”,那么“每周工作40小时”就是你的起点。
团队只有持久才有获胜的希望。他们以能够长期维持的速度努力工作,他们保存精力,他们把项目看作是马拉松长跑,而不是全速短跑。

  1. 现场客户
    为了保证开发出来的结果与客户的预想接近,XP方法论认为最重要的需要将客户请到开发现场。就像计划游戏中提到过的,在XP项目中,应该时刻保证客户负责业务决策,开发团队负责技术决策。因此,在项目中有客户在现场明确用户故事,并做出相应的业务决策,对于XP项目而言有着十分重要的意义。
    也许有人会问,客户提交了用户故事之后不就完成工作了吗?其实很多尝试过用户故事的团队都会发现其太过简单,包含的信息量极少,XP方法论不会不了解,因此,不会把用户故事当做开发人员交付代码的唯一指示。用户故事只是一个起点,后面的细节还需要开发人员与客户之间建立起来的良好沟通来补充。
    作为一名有经验的开发人员,绝对不会对现场客户的价值产生任何怀疑,但是都会觉得想要实现现场客户十分困难。要实现这一点,需要对客户进行沟通,让其明白,想对于开发团队,项目成功对于客户而言更为重要。而现场客户则是保障项目成功的一个重要措施,想想在你装修房子的时候,你是不是常常在充当现场客户的角色呢?其实这隐喻就是让客户理解现场客户重要性最好的突破口。
    其实现场客户在具体实施时,也不是一定需要客户一直和开发团队在一起,而是在开发团队应该和客户能够随时沟通,可以是面谈,可以是在线聊天,可以是电话,当然面谈是必不可少的。其中的关键是当开发人员需要客户做出业务决策是,需要进一步了解业务细节时能够随时找到相应的客户。
    不过,也有一些项目是可以不要现场客户参与的:
    当开发组织中已经有相关的领域专家时。
    当做一些探索性工作,而且客户也不知道他想要什么时(例如新产品、新解决方案的研究与开发)。

去尝试吧,现场客户不仅可以争取得到,而且还能使得团队焕然一新,与客户建立起良好的合作与信任。

  1. 编码标准
    编码标准是一个“雅俗共享”的最佳实践,不管是代表重型方法论的RUP,PSP,还是代表敏捷方法论的XP,都认为开发团队应该拥有一个编码标准。XP方法论认为拥有编码标准可以避免团队在一些与开发进度无关的细节问题上发生争论,而且会给重构、结对编程带来很大麻烦。试想如果有人将你上次写的代码的变量命名法做了修改,下次你需要再改这部分代码时,会是一种什么感觉呢?
    不过,XP方法论的编码标准的目的不是创建一个事无巨细的规则表,而是只要能够提供一个确保代码清晰,便于交流的指导方针。
    如果你的团队已经拥有编码标准,就可以直接使用它,并在过程中进行完善。如果还没有,那么大家可以先进行编码,然后在过程中逐步总结出编码规则,边做边形成。当然除了这种文字规范以外,还可以采用一些如自动格式化代码工具之类的方法进行代码规范。,事实上,你只需要很好地贯彻执行其他的实践并且进行沟通,编码标准会很容易地浮现出来。
  2. 配合是关键
    有句经典名言“1+1>2”最适合表达XP的观点,Kent Beck认为XP方法论的最大价值在于在项目中融会贯通地运用12个最佳实践,而非单独地使用。你当然可以使用其中的一些实践,但这并不意味着你就运用了XP方法论。XP方法论真正能够发挥其效能,就必须完整地运用12个实践。

适用范围

XP适合规模小、进度紧、需求变化大、质量要求严的项目。它希望以最高的效率和质量来解决用户目前的问题,以最大的灵活性和最小的 代价来满足用户未来的需求,XP在平衡短期和长期利益之间做了巧妙的选择。


敏捷开发中XP与SCRUM的区别

  • 区别之一: 迭代长度的不同
    XP的一个Sprint的迭代长度大致为1~2周();
    Scrum的迭代长度一般为 2~ 4周(较长)。
  • 区别之二: 在迭代中, 是否允许修改需求
    XP在一个迭代中,如果一个需求还没有实现, 则可以考虑用另外的需求将其替换,替换的原则是需求实现的时间量是相等的(允许);
    Scrum是不允许这样做的,一旦迭代开工会完毕, 任何需求都不允许添加进来,并有Scrum Master严格把关,不允许开发团队受到干扰(不允许)。
  • 区别之三: 在迭代中,User Story是否严格按照优先级别来实现
    • XP是务必要遵守优先级别的。
    • Scrum在这点做得很灵活, 可以不按照优先级别来做,Scrum这样处理的理由是:如果优先问题的解决者,由于其它事情耽搁,不能认领任务,那么整个进度就耽误了。 另外一个原因是,如果按优先级排序的User Story #6和#10,虽然#6优先级高,但是如果#6的实现要依赖于#10,则不得不优先做#10.
  • 区别之四:软件的实施过程中,是否采用严格的工程方法,保证进度或者质量
    • Scrum没有对软件的整个实施过程开出工程实践的处方。要求开发者自觉保证;
    • XP对整个流程方法定义非常严格,规定需要采用TDD, 自动测试, 结对编程,简单设计,重构等约束团队的行为。因此,原作者认为,这点上,XP的做法值得认同的,但是却把敏捷带入了一个让人困惑的矛盾, 因为xp的理念,结合敏捷模式,表达给团队的信息是“你是一个完全自我管理的组织, 但你必须要实现TDD, 结对编程, ...等等”

不难发现,这四个区别显见的是: Scrum非常突出Self-Orgnization,** XP注重强有力的工程实践约束**
建议: 在管理模式上启用Scrum;而在实践中创造一个适合项目组的XP


参考资料
【1】http://blog.csdn.net/fw0124/article/details/48713959
【2】强大的百度,等等等等

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容