架构设计50-架构师技术01-怎么画架构图

架构设计系列文章,请参见连接。

0. 前言

0.1 业界现状

在软件业界有一个说法:PPT架构师。PPT架构师的由来肯定是因为架构师有很大一部分工作在做PPT或者在讲PPT。一方面“画图”在架构师的工作占比中已经非常大了。另外一方面也代表着架构师画图能力代表着成为架构师所必要的能力。

0.2 架构师必不可缺

软件研发最简单的理解是:使用技术解决业务问题。而对于技术的使用过程是怎样的过程是需要架构师进行管理的,并在软件系统发展过程中对于技术治理工作还是需要架构师处理的。架构师公司发展过程中还需要将公司的发展纳入到技术演进过程中。所以说架构师在公司发展过程中是必不可缺的。

0.3 本文概要

鉴于此架构师用“图”来描述系统工程规范、技术规范、业务转换架构过程、架构、流程等等内容,并将“图”交付给团队进行实施。在”架构设计“过程中这么大的画图工作量,架构师肯定要明确的知道:

  • 为什么要画图?
    说明画图是为了解决什么问题的。
  • 什么是架构图?
    说明什么样的图是架构图。
  • 怎么画架构图?
    说明以什么样的过程,什么样的规则可以画出好的图。
  • 用什么画架构图?
    说明用什么工具什么样的图比较合适。
  • 总结一下
    最后讨论一下:画图是一种技能吗?

1. 为什么画架构图?

很多研发人员对于软件的认知:软件开发就是在处理细节。处理各种各样的细节,在软件研发的各个阶段。靠人把所有的细节全部记住?还是靠某种机制将细节记录下来?这只是为什么要画架构图中的一个最简单的原因,其他原因可以看下面。

1.1 为什么要画图

画图其实是承载了设计中的信息,以图的形式进行传递。那为什么很多团队还是不进行设计呢?

1.1.1 为什么不设计?

  • 设计是反人类的。
    就像学习是反人类的一样。很多人理不清到底要做什么,只有在实现过程遇到了才能知道有这个问题,并解决这个问题。
  • 容易被人挑战
    没有设计方法、不体系化、遗漏等问题使提出的解决方案有很多点都会被挑战。
  • 意识到问题是问题
    没有设计大家也过的挺好的,为啥要设计?所以意识到没有设计是个问题是很很重要的问题。没意识问题的存在就永远解决不了问题。

1.1.2 为什么要设计?

战术编程的结果
  • 战术编程的问题
    FaceBook 是一个鼓励战术编程的公司。原公司座右铭:"快速行动,打破常规",后来意识到问题改成了"以坚实的基础设施快速发展"。

    战术编程的问题在于它是短视的。-《软件设计哲学 3.1 战术编程》

  • 识别风险,理清计划
    前面的文章中有讨论为什么要设计,这里也是参照02.终极问题--为什么要架构设计?

    一个公司可以用任何一种方法取得成功。然而,在一家关心软件设计并拥有干净代码库的公司工作要有趣得多。-《软甲设计哲学 3.4 创业与投资》

1.2 系统复杂度从哪里而来?怎么解决?

1.2.1 系统复杂度从哪里而来?

软件开发就是在处理细节?
  • 业务本身复杂度
    为了创建真正能耐为用户活动所用的软件,开发团队必须运用一整套与这些活动有关的知识体系。所需知识的广度可能令人望而生畏,庞大而复杂的信息也可能超乎想象。那怎么才能让实现过程中一直都能记清之前的想法是什么样的?
  • 演化过程中的复杂度
    在软件系统的发展过程中,在新增或修改业务时未进行良好的设计的业务进入到系统后就会带来混乱。这种混乱会不断的在技术组件间传播扩散,甚至可能传播到系统之外。

1.2.2 怎么解决?

cynefin问题认知框架就是用来解决复杂问题的。主要的方式就是将复杂问题使用各自对应的方法将问题变为简单问题,然后再解决简单问题。


cynefin认知框架

在通过对微服务大泥球的整理与处理之后,可以看到与之前的大泥球有很大的不同。

设计后的结果

1.3 细节重要还是整体重要?

上一节已经讨论到了软件中有很多很多的细节,细节导致了复杂度指数级的提升。那么解决问题的时候就需要关注并解决所有的细节吗?

1.3.1 还原论vs整体论=系统论

系统论

解决复杂领域的问题,就不能单纯靠还原论的解题思路。一个复杂的动态系统整体远大与构成该系统的各个部分之和,同理一个动态系统的问题也不能单纯通过分而析之的方式来解决。

1.3.2 道法术势器

不同层次的软件组成

我们提供的软件产品在不同的层面为不同的人提供用户不同的解决方案。在提升软件交付效率的领域中,我们如果只是提供CI/CD工具是可以解决用户的问题,但如果提供解决问题的方法论才能让用户更好的使用应用我们的工具。

1.3.3 重要的是?

需要以系统化的方法认知细节和整体。这样才能在不同的层面上同时获取成功。

1.4 “设计”的理解一致吗?

1.4.1 认知过程

邓宁-克鲁格心理效应

根据邓宁-克鲁格心理效应:对于同一件事情,人的认知也是经过这个过程的。从愚昧山峰到大师级别看到的内容做的内容都是一样的,但是对于同一件事情的背后认知是不一致的。例如:敏捷的形式中有每日晨会,对于刚接触和有深度认知的人对于晨会的认知是不一样的。

1.4.2 智慧形成过程

数据->信息->知识->智慧

认知过程中将数据变为智慧的方式不同导致每个人的对同一件事的认知不同。这可以很好的解释不同的人对同一件事的不同侧面的认知深度都是不同的。

1.4.3 理解一致吗?

在不同的邓宁-克鲁格阶段,不同的智慧形成过程。再加上一个人的精力是有限的,并且每个人的兴趣内容也不相同。所以会形成虽然大家都是Java后端软件研发,有些对Java线程比较懂,有些对数据库原理比较懂。更不用说对于业务的理解是不可能达成一致的。就需要以某种形式让软件研发需求,实现形成某种统一的认知。

1.5 业务到实现之间的转换怎么才是好的?

从软件需求到软件实现之间有多种转换方式,那种方式是最好的?那种方式可以尽量的提升效率,降低成本都是需要在设计阶段确认的。

  • 管理复杂性,效率最大化
    需求->技术

    在业务需求和系统实现之间做权衡,从而来应对未来变化的不确定性。无论是何种变化,在我看来架构都是在不断的判断和取舍。而变化和不确定性导致权衡取舍,再不进行说明的情况下很难让人理解为什么这样做?
  • 架构是系统实现的蓝图
    设计

    仅凭程序员自己脑子里的模糊设想,也许你可以像传统手艺人一样独自创造出一些美好有用的小东西(比如 Linux 0.01 版本),但不太可能以工程的方式协同一个团队共同建造起一个与摩天大楼规模类似的复杂软件系统(比如现代的 Linux 系统)。

1.6 结论:

解决系统复杂度最好的方式是简化,拥有从全局的整体到局部的细节的上下统一观点,并理解团队中的成员对业务的、技术的理解都是不一致的。才能比较好的理解架构的作用是管理复杂度,系统蓝图的作用。

1.6.1 控制复杂度

软件开发本质上是复杂的,所以首要任务就是管理复杂度!《人月神话》

当复杂性失去控制时,开发人员就无法很好的理解软件,因此无法轻易、安全地更改和扩展它。而好的设计可以为开发复杂特性创造更多机会。《领域驱动设计:软件核心复杂性应对之道》

架构设计的目的是为了解决软件系统的复杂度带来的问题,对系统的高可用、高性能、可扩展、安全、伸缩性、简洁等做系统级的把握。《架构即未来》

成为一名优秀的软件设计师的第一步是认识到仅仅为了完成工作编写代码是不够的。为了更快地完成当前的任务而引入不必要的复杂性是不可接受的。最重要的是这个系统的长期结构。《软件设计哲学》- 3.2 战略规划

设计和编码混合在一起的风险就是可能没设计就编码了——一旦出现这种情况,演进式设计就可能脱轨并失败。《设计已死》

如果你在开发小组,那么你可以通过代码来判断是不是有设计。如果代码越来越复杂,越来越难搞,那么就是设计没有做足。但杯具的是这个观点比较主观。我们没有一个可靠的标尺来给我们一个客观的衡量设计好坏的方法。《设计已死》

1.6.2 形式是什么?

一图胜千言

一图胜千言,用图来传递信息是最快的方式。并且可以传递更多的信息。但在此过程中很多时候都会想到MDD(模型驱动开发),MDD是被生成代码所耽误的一种开发方法。在后面会讨论各种画图方法论来说明并不是只有UML一种画图方式。使用图的方式进行大部分信息的展示,但还是需要配合图进行一些文字描述来说明图的意图。

2. 什么是架构图?

架构设计有多种方法论,而撑起这些方法论的就是其下各种各样的图。这些图描述方法论中所特有的内容,那么这些架构设计方法论中会将软件所有细节都落到图上吗?基于这么多的架构设计方法论,我们最后的架构图有应该是什么?

2.1 有哪些图可以表示架构?

2.1.1 现有的图分类

图分类

上图中是简单的分类,因为每种图都不是在一个过程中会使用到。而且还有很多图未分类进入软件工程中:

2.2.2 (标准)架构描述

在标准组织ISO/IEC/IEEE 42010:2011 A Conceptual Model of Architecture Description中描述了架构所组成的元素。在架构图中也需要包含这些元素。

The Core of Architecture Description

2.2 方法论

架构一大目标就是为了让开发团队快速达成共识。而这个目标就需要有具体的方法才可以达成。
例如架构设计的Togaf中的adm进行设计,C4的设计方法,DDD中实践方法DCI,还有面面俱到的RUP,还有4+1视图法,所以要具体选择那种呢?

架构方法论分类

每种方法论都有优点,而且都有它所适用的场景。在阿里的从方法到思维:什么是应用逻辑架构的正确姿势?(上)中描述了从需求到代码实现的整个过程。TOGAF的典型EA的方法论,RUP+”4+1视图“发的面向对象分析和设计方法。也有从架构的方面考虑的:结构+架构决策+设计原则+架构特征。还有其他各种各样的架构过程,也伴随着不同的方法。例如:1.3.3. Refined Architecture阶段:落地的5视图方法

2.2.1 设计方法对应的图

先将方法论进行归类,方面在后面的文章中进行细节的分享。并从方法论的层面上了解架构设计方法论有多少种:


方法论

另外还有:ADL、SysML、AADL、BPMN等

2.2.2 RUP

统一软件开发过程和4+1视图出现在差不多的时间段。所以在初期的时候就有uml和4+1视图的结合,这里将图转换一下形成下图:


uml和4+1视图

让4+1视图和UML结合才能形成比较完善的架构图的原因是UML都在细节,对于架构设计的上层结构的描述力不足所以需要结合4+1视图的视角来描述上册。这样才可以形成比较完善的架构描述方法。

2.2.2.1 UML的问题

Martin Fowler在一篇文章中说明UML的三种用法:草图、蓝图与编程。那我们分析一下这三个角度:

  • 草图
    草图是用来大概描述系统结构、设计结构的。来传递概要性的概念,但是现在UML发展的越来越复杂越来越细化的情况下很难描述一个概要性的信息。
  • 蓝图
    蓝图描述整体最终的架构、架构的愿景。而UML的发展是1.0是9中图到2.5的时候已经变成了12中23个了。UML发展成描述更多的细节,捕捉更多的细节。失去了对于整体的描述方法。
  • 编程
    现在的变成要不用MVC要不用代码从生成器,使用设计模式的时候都很少。所以说对于快速变化的业务与系统来说花大力气画出来的UML图在三天后可能都不适用了,这种大投入小回报的方式是违反了敏捷背后的原则的。

并不是反驳Martin Fowler,只不过想说UML点错了技能树没有办法很好的反应现在软件研发过程了。有一些大神通过各种方式也说明了UML的问题例如《UML 怎么就真“挂”了? 2021 年 5 月 09 日》,《UML三大硬伤-程序员杂志2002年第5期》中描述了UML的问题:上不着天、下不着地、一盘散沙。还有知乎上的大神对于UML的讨伐,我这里整理一下:

  • 过于复杂:图形化是为了传达信息,复杂之后就很难有效的传达信息
    所有的图都是针对某一个方面的细节的。没有一张图可以表示架构所要的全局。
  • UML试图去捕捉软件中的每一个细节。
    1. 但是根据人的认知过程来说的现在认为的正确细节在过不了多长时间之后就会变的错误。
    2. 并且不能适应现在敏解式“拥抱变化”的情况。
  • 图形的意义不明确导致画出来的图会有各种歧义,需要不断的解释与说明才可以完成业务。
    1. 主要是因为图形太多,符号太多。导致符号体系中有重复覆盖相同功能的问题

2.2.3 C4

C4

C4补充图

C4 模型是一种“抽象优先”(abstraction-first)的架构制图方法,它也是受前面的 UML 和“4+1”视图模型所启发,但相对而言要更加简单和轻量,只包含少量的一组抽象和图表,很易于学习和使用。

2.3 DDD

经典DDD中没有说明领域模型应该怎么画图,但是它是一个不可忽视的架构设计方法论。在其他的DDD的文档中也有很多方式进行领域驱动的描述。

2.3.1 DDD原模型

战术设计+战略设计

领域分层

2.3.2 DDD建模过程

经典DDD中更多的是说明概念,对于它应该怎样实施,怎样完成这个过程。DDD很难学习也是基于此,只有概念没有动手的方法。其实DDD的实施过程也是需要画图的。

ddd starter modelling process

上图是从DDD入门建模过程拉过来的。

DDD 建模工作坊指南

上图是从DDD 建模工作坊指南拉过来的

2.4 面向过程

面向过程

这里想说明的是DFD是一种分层图,在不同的层次中有不同的细节内容。鱼骨图很多时候用来做根因分析,软件故障的分析可以用鱼骨图来完成。

2.5 EA

企业架构从上到下描述了软件的整体过程。他不止描述实体的生命周期,它还会表述系统、平台的生命周期管理。


TOGAF ADM
MEAF

2.5.1 EA-TOGAF ArchiMate

TOGAF图例

上图是从ArchiMate教程ArchiMate示例中抓取过来的。

2.6 总结

在图形分类、标准定义两个侧面说明了架构设计和画图是有很多中方法论的,然后讨论了五种体系化的方法论。那么我们看过了这么多定义和方法论之后再进行分析(回归本源)得出结论(元元模型)。

2.6.1 回归本源

2.6.1.1 系统之美

有一本书叫做《系统之美》讨论了系统的定义:

系统 = 结构 + 关系 + 目标/功能

2.6.1.2 ISO/IEC 42010:20072

标准化组织也定义了类似的内容:


2.6.1.3 架构蓝图--软件架构 "4+1" 视图模型


从几个方面抽象出架构图到底应该有哪些内容组成,必须包括哪些内容。上图是从4+1视图的第一篇论文中翻译过来的内容:Architectural Blueprints—The “4+1” View Model of Software Architecture

2.6.2 元元模型


组成视角分层这几个角度可以描述一个架构,然后再加上”时间“这个维度形成4维空间来描述架构可以以一种比较完备的方式描述清晰一个可靠的架构。

2.7 结论

最后说明一下各种各样的方法论存在并不代表着混乱,而恰恰代表着架构设计方法论的繁荣发展。但每个方法论都代表着一个方法论的应用场景。所以需要进行权衡,选择合适的。

2.7.1 权衡

合适的是最好的,不是最新的是最好的。很多研发人员因为各种原因喜欢新的技术,新的工具,新的方法论。在我看来这么做就代表着决策方式就看那个新就用那个,而不是进行实际的分析之后再进行决策。这样的决策过程肯定是有问题的。所以才有了权衡。

2.7.2 副作用

工程化、系统、严谨、完整、标准。只要有图就很好,有了图就可以更好的与团队进行沟通。就可以说明系统的规范、计划、评审等等内容。

2.7.3 架构图特点

从各种方法论就总结出架构描述的方法:组成元素、多视角、分层次、辅以文字描述。

3 怎么画架构图?

有架构图的组成元素、视角、分层就可以画出架构图吗?

3.1 怎么画图?


画图是不是一种技术?前面那么多方法论都有规范的图的意义,图的画法规范等等。那么画图是一种技术吗?是不是学过这些方法就可以有实际的实践意义?并不是,还是需要有自己的一些做事规范来规范化自己的输出,提要自己的职业化能力。
这里画图的方式以:流程+规则->图即代码

3.2 流程

架构设计流程用来说明在不同的阶段应该画什么样的图,设计阶段说明主要进行设计阶段。

3.2.1 设计流程


3.2.2 设计阶段


ArchiMate,DDD设计都包含了从概要到详细的设计过程,所以这里只是区分了uml+”4+1视图“的方式。

3.3 规则

画图从哪里画?图要覆盖哪些内容?

3.3.1 从上到下

金字塔模型中以上统下的方式进行设计开始。


3.3.2 逐层分解

分层、分块的对整个系统进行描述,力求将信息清晰的传递过去。


清晰架构分块表示

3.4 图即代码

一切即代码

3.4.1 架构即代码

使用编写代码的方式进行架构设计。

分两个层次:组件以及组件之间的关系。对于组件的描述,表示组件内容。对于组件之间关系

3.5 结论

原则
  • 准确(accurate):错的图比没有图还糟糕;即使一开始是准确的,后面也需要定期更新校对;
  • 完整(complete):需要覆盖架构的核心要素和关键信息,为受众呈现一个没有残缺的完整架构设计;
  • 清晰(clear):制图时最好带上图例(形状、颜色、线型、箭头);用图描述不清的地方,还可以加上文字标注做补充;
  • 一致(consistent):比如同一类型的图,最好使用相同的记号风格,以降低受众的理解成本;不一致往往还会带来混淆;
  • 简洁(consise):在满足以上 4 点基础之上,还需要让图更加简洁,一方面是更容易被人接受(没人读 = 没写),另一方面更新维护成本也更低。

图表必须是自我描述的、一致的、足够准确的并且与代码相关联。 这就是为什么每个架构师或软件工程师在创建架构图时都依赖几个指导方针很重要的原因,因为它们是随着时间的推移(例如结构、元素、关系、属性、原则)和不同利益相关者之间交流应用程序架构的共同基础各种技术背景和关注点。

4. 用什么画图?

4.1 工具发展

从刚毕业的时候用VisioAstah UMLStarUML这样的UML工具。原来从Visio到PPT,再从PPT再到ProcessOn再到draw.io。工具也在不断的发展,从原先的客户端模式到比较流行的在线版,再到以代码画图的的现在。工具在不断的发展,现在看代码画图有不宜用,不完善的点待到大家认识到图即代码的优点的时候图即代码工具肯定会有更好的发展。

4.2 实践过程

4.2.1 ADL(架构描述语言)分类

  • 使用解释型文件: 所有的配置信息都被定义于可执行的配置解释文件中,比如说shell脚本,ansible的playbooks,Chef的recipes,或者Puppet的manifests。人们无需登入服务器,就可以做出实时的动态调整。开发时,这些代码可以作为持续的定义,来减少任何生成雪花服务器(SnowflakeServer)的风险。这也意味着更新代码的频率要快。幸运的是,计算机可以快速执行程序,并可以准备数百个服务器,速度比任何人类都快。
  • 自归档的系统和过程: 相比于人们使用文档中的指示来执行操作(人工级别的可靠性),代码更加清晰准确并且可以不断的被执行。而且如果有必要的话,根据这些代码也可以生成一些更具有可读性的文档。
  • 给所有代码做版本控制: 要让所有的代码都处于版本控制之中。这样每次配置以及每个修改都会有记录可以查询的到,而且还可以利用可重用的构建(ReproducibleBuild)来诊断问题。
  • 持续地测试系统和过程: 测试可以帮助计算机快速地找到基础设施配置中的诸多错误。在现代软件系统中,你可以搭建用于基础设施代码的“部署流水线”,这能够让你实践针对基础设施变化的持续交付流程。

4.2.2 工具

还有很多工具可以进行图即代码的画图过程:Graphviz,Mermaid,OmniGraffle,code2flow,Lucidchart。

5. 总结

软件的设计应该是为了便于阅读,而不是便于书写。--《软件设计的哲学》

攻技者,短之;理论者,长之;践行者,胜之。
云原生体系下的技海浮沉与理论探索-王银利(芸峥) 阿里巴巴云原生

即使学了很多软件架构画图方法,但是要描述一个完成的架构做到哪一步才可以还是需要实践才能知道。

5.1 什么时候画图?

都可以,只要你认为用语言表示困难的时候都可以画图来解释。

5.2 画图要画到那种细节程度?

都可以,只要你认为图可以在评审和实现过程中表示清楚即可。

6. 参考:

第一节

架构制图:工具与方法论
如何画好一张架构图?
制作架构图的艺术
为什么说我们需要软件架构图?
软件设计的哲学:第三章 编程的战术和战略
浮现式设计
软件设计的哲学:第三章 编程的战术和战略
【万字长文】探讨可信构架之道
Is Design Dead?

什么是Cynefin框架?
什么是Cynefin框架
应用 Cynefin 框架,您的团队可以识别好的问题
Cynefin框架

第二节

软件工程用图
A Conceptual Model of Architecture Description
企业架构、TOGAF与 ArchiMate 概览
浅谈架构设计(上)
架构制图:工具与方法论

第三节

The Art of Crafting Architectural Diagrams
用于软件架构的 C4 模型

InfrastructureAsCode(中文版:基础设施即代码)
OmniGraffle中文网站
软件开发过程
軟體架構分析方法
软件架构
graphviz
Text to UML tools – Fastest way to create your models
code2flow
Lucidchart
Mermaid,一个生成结构图的工具
mermaid

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

推荐阅读更多精彩内容