过去几年,通天塔一直处于快速的业务能力建设和架构完善的阶段,以应对不断增长的业务需求和容量、高可用等技术需求,现在通天塔平台已经能满足集团主站的大部分活动、频道搭建和运营能力,主流程的新需求越来越少,个性化需求和非标准化流程的数据源和服务接入的需求越来越多,有些甚至是京东零售体系外的,同时通天塔技术和产品也在积极主动寻求变化和创新,这些因素结合在一起驱动通天塔孵化出了一个以技术为导向的项目:通天塔积木,旨在构建一个基于完全开放的前端 SDK 和后端数据源&服务、高度灵活和强大的积木画布、能够快速移植和部署到任何第三方 IT 环境的活动搭建解决方案,这套方案的初衷和设计理念也契合了京东国际化赋能和 PaaS 化的战略。

目前通天塔积木已经取得阶段性成果,已开始赋能京东国内和国际站,但如何应对异常复杂的积木业务逻辑和不可预知的业务变化,构建业务和底层技术基础实施的完全解耦的系统,一直是我们面对的巨大挑战。也是时候从更高视角来看清问题和源头,思考 一种能应对和控制业务复杂度、具备强扩展性和弹性的解决方案 。纵观我们的目标,DDD 这个词不知不觉映入了我的眼帘。

2004 年著名建模专家 Eric Evans 发表了他最具影响力的书籍《Domain-Driven Design –Tackling Complexity in the Heart of Software》(领域驱动设计—软件核心复杂性应对之道),书中反复强调领域通用语言(Ubiquitous Language)的重要性,全面阐述了 DDD 战略设计到战术设计的方法论和实践。让软件研发所有参与者围绕着一个统一和一致的领域模型建模和设计,分析模型和设计模型不再割裂,并引出了以领域为核心的分层架构,有效地分离业务和技术复杂度,使得领域层的代码和领域模型保持高度一致。在战术上提供了诸多元模式帮助构建职责清晰、内聚和高维护性和可扩展性的代码 。

领域驱动设计不是新鲜的概念,至今已有十六年时间,一直来不曾大行其道,直到 IT 行业内掀起微服务的狂潮,技术界才重新审视和意识到领域驱动设计的价值。不能说微服务拯救了领域驱动设计,但确实是微服务,让领域驱动设计又重新焕发了青春。DDD 是一个非常庞大的建模和设计体系,这篇文章只在理论和概念上阐述 DDD 的价值、方法和架构,欢迎任何的问题指正和补充。

DDD 价值

应对复杂业务

引起软件系统复杂度的主要因素是需求,软件系统需求又可以分两个方面:业务需求和技术需求 。我们分析系统的复杂度时就可以从业务复杂度和技术复杂度这两个维度出发。

业务复杂度跟系统的业务需求规模和需求之间的关系层级有直接关系,需求的数量和关系的层级决定代码的规模和逻辑循环或递归的层级,系统的需求数量越大,需求之间的关系越复杂,系统的业务复杂度就越大。John Ousterhout 的著作《A Philosophy of Software Design》从认知的负担和开发工作量的角度来定义软件系统的复杂度,并给出了一个复杂度公式:

子模块的复杂度(cp)乘以该模块对应的开发时间权重值(tp),累加后得到系统的整体复杂度(C)。可以看到系统整体的复杂度并不简单等于所有子模块复杂度的累加,还要考虑该模块的开发维护所花费的时间在整体时间中的权重占比(tp),这个权重比就跟模块划分是否内聚、设计是否优雅有直接关系。

技术复杂度则来自于对软件系统运行的质量需求,包括安全、高性能、高并发、高可用和高扩展性。系统安全性要求对访问进行控制,无论是加密还是认证和授权,都需要为整个系统架构添加额外的间接层。不仅对访问的低延迟产生影响,还极大提升了系统代码复杂度;为了让后端系统能具备高扩展性和弹性,要求所有系统的设计必须是无状态的;为了提升用户端访问体验,后端需要增添离线任务对数据加工、异构、预热、预缓存,以实现用空间换时间,降低实时接口的逻辑复杂度来降低请求的延迟。然而最让开发者更抓狂的是这些技术需求彼此又是相互影响甚至相互矛盾,在一些复杂流程并要求高响应的业务场景,如下单、秒杀等,会将一个同步的访问请求拆分为多级步骤的异步请求,再通过引入消息中间件对这些请求进行整合和分散处理,这种分离一方面增加了系统架构的复杂性,另一方面也因为引入了更多的资源,使得系统的高可用面临挑战,并增加了维护数据一致性的难度。而且技术复杂度与业务复杂度并非孤立,二者复杂度因子混合在一起产生的负作用更让系统的复杂度变得不可预期,难以掌控,就好比氢气和氯气混合在一起遇到光亮发生爆炸一样。

DDD 的核心思想就是要避免业务逻辑的复杂度与技术实现的复杂度混淆在一起,确定业务逻辑与技术实现的边界,从而隔离各自的复杂度,业务逻辑并不关心技术是如何实现的。无论采用何种技术,只要业务需求不变,业务规则就不会变化。理想状态下,应该保证业务逻辑与技术实现是正交的。

DDD 通过分层架构与六边形架构确保业务逻辑与技术实现的隔离。

DDD 战略设计指导我们面对客户的业务需求,由领域专家与开发团队展开充分的交流,经过需求分析与知识提炼,获得清晰的问题域,在引入限界上下文和上下文映射对问题域进行合理的分解,识别出核心领域与子领域,并确定领域的边界以及它们之间的关系,从而把一个大的复杂系统问题拆分成多个细粒度、独立和内聚的业务子问题,从而很好地分解和控制业务复杂度,各个小组聚焦各自的子领域中。

在架构方面,通过分层架构来隔离关注点,将领域实现独立出来,利于领域模型的单一性与稳定性;

引入六边形架构清晰地界定领域与技术基础设施的边界;CQRS 模式则分离了查询场景和命令场景,针对不同场景选择使用同步或异步操作,提高架构的低延迟性与高并发能力。

分层架构

“分层架构”遵循了“关注点分离”原则,将属于业务逻辑的关注点放到领域层(Domain Layer)中,而将支撑业务逻辑的技术实现放到基础设施层(Infrastructure Layer)中。同时,领域驱动设计又颇具创见的引入了应用层(Application Layer)。应用层扮演了双重角色。一方面它作为业务逻辑的外观(Facade),暴露了能够体现业务用例的应用服务接口;另一方面它又是业务逻辑与技术实现的粘合剂,实现二者之间的协作。下图展现的就是一个典型的领域驱动设计分层架构。蓝色区域的内容与业务逻辑有关,灰色区域的内容与技术实现有关,二者泾渭分明,然后汇合在应用层。应用层确定了业务逻辑与技术实现的边界,通过直接依赖或者依赖注入(DI,Dependency Injection)的方式将二者结合起来。

六边形架构

由 Cockburn 提出的六边形架构则以“内外分离”的方式,更加清晰地勾勒出业务逻辑与技术实现的边界,且将业务逻辑放在了架构的核心位置。这种架构模式改变了我们观察系统架构的视角。体现业务逻辑的应用层与领域层处于六边形架构的内核,并通过内部的六边形边界与基础设施的模块隔离开。当我们在进行软件开发时,只要恪守架构上的六边形边界,就不会让技术实现的复杂度污染到业务逻辑,保证了领域的整洁。边界还隔离了变化产生的影响。如果我们在领域层或应用层抽象了技术实现的接口,再通过依赖注入将控制的方向倒转,业务内核就会变得更加的稳定,不会因为技术选型或其他决策的变化而导致领域代码的修改。

快速响应业务变化

不确定性和变化是这个时代的主旋律,业务需要快速上线,并根据用户的反馈不停地调整和升级,有生命力的业务主动寻求变化,不变则亡是很多行业目前的共识,企业应对变化的响应力成了成败的关键。同时一个长期困扰软件研发的问题是,需求总是在变化,无论预先设计如何“精确”,总是发现下一个坑就在不远处。相信很多技术人员都有这样的经历,架构和响应能力越来越糟糕,也就是我们常说的架构腐化了,最后大家不得不接受重写。软件架构设计的另一个关键方面是让系统能够更快地响应外界业务的变化,并且使得系统能够持续演进。在遇到变化时不需要从头开始,保证实现成本得到有效控制。

DDD 的核心是从业务出发、面向业务变化构建软件架构,实质是保证面对业务变化时我们能够有足够快的响应能力。面向业务变化而架构就要求首先理解业务的核心问题,即有针对性地进行关注点分离来找到相对内聚的业务活动形成子问题域。让每个字问题的划分尽可能靠近变化的原点,子问题域内部是相对稳定的,未来的变化频率不会很高,是符合深模块特性的,而子问题边界是很容易变化的。DDD 最后在实现层面利用成熟的技术模式屏蔽掉技术细节的复杂度。

与微服务相得益彰

Martin Fowler 和 James Lewis 提出微服务时,提出了微服务的 9 大架构特质,指导组织围绕业务组建团队,把业务拆分为一个个业务上高度内聚、技术上松散耦合、运行在独立进程中的小型服务,微服务架构赋予了每个服务业务上的敏捷性和技术上的自主性,因此可以针对每个服务进行独立地迭代、更新、部署和弹性扩展,从而缩短需求交付周期并加速创新。

在面对复杂业务和快速变化需求时,DDD 从业务视角进行关注点分离和应对复杂度,让业务具备更高的响应力。DDD 战略设计阶段,引入限界上下文(Bounded Context)和上下文映射(Context Map)对问题域进行合理的分解,确定领域的边界以及它们之间的关系,维持模型的完整性。

限界上下文不仅限于对领域模型的控制,而在于分离关注点之后,使得整个上下文可以成为独立部署的设计单元,这就是“微服务”的概念,上下文映射的诸多模式则对应了微服务之间的协作。因此在战略设计阶段,微服务扩展了领域驱动设计的内容,反过来领域驱动设计又能够保证良好的微服务设计。

边界给了实现限界上下文内部的最大自由度。这也是战略设计在分治上起到的效用,我们可以在不同的限界上下文选择不同的架构模式和技术实现,这也正好映照了微服务的特点:在技术架构上,系统模块之间充分解耦,可以自由地选择合适的技术架构,去中心化地治理技术和数据。

ThoughtWorks 公司技术专家编写的《微服务设计》书中,专门有一章节“限界上下文”,充分说明微服务的落地需要 DDD 来辅助的,起码在建模阶段是需要借助 DDD 强大的战略模式来支撑的。微服务不是简单的指将服务尽可能的拆小,然后一个 RPC 框架搞定了,这太粗糙了,无法落地。

辅助中台战略落地

领域驱动设计让参与者基于统一语言沟通和协作,围绕一个统一和一致的领域模型工作,传统的分析模型和设计模型不再割裂;显式地把业务领域和设计放到了软件开发的核心,软件人员和业务人员合作来构建领域模型,使得软件的交付质量更高且维护成本更低;利用限界上下文来分解问题域,识别核心领域,有效分解和控制了业务的复杂度;

利用 DDD 提倡的分层、六边形等架构,分离了业务复杂度和技术复杂度,使得系统具备更强的扩展性和弹性;战术层面提供了元模型(聚合,实体,值对象,服务,工厂,仓储)帮助构建清晰、稳定,能快速响应变化和新需求能力的应用;

DDD 构建的应用能快速方便地切到微服务;领域驱动设计给企业应用带来的稳定性、灵活性、扩展性和应对变化的响应力对于建立灵活前台、稳固中台能带来巨大的帮助作用。

DDD 过程

领域驱动设计是一套面对复杂业务进行建模和设计的方法论和实践,建立了以领域为核心驱动力的设计体系。领域驱动设计分为 2 个主要过程:战略设计、战术设计 。

在战略设计阶段 ,面对纷繁复杂的业务需求,领域专家和研发团队进行紧密合作、充分沟通,进行事件风暴或场景驱动设计,分析需求并提炼知识,得到比较清晰的问题域,输出由领域专家和研发团队达成共识的统一语言(UL,Ubiquitous Language),基于统一语言对问题域进行分析和建模,识别业务边界,确定限界上下文,根据限界上下文划分独立的领域,建立限界上下文彼此之间的关系,接着引入系统上下文(System Context)确定系统的边界,并确定它的外部环境,包括与其集成的第三方系统与基础设施。利用 DDD 分层架构或六边形架构界定业务领域和技术实现的边界,让稳定的核心领域模型处于架构的最内部,避免技术实现和架构变动带来的影响。

接着进入战术设计阶段 ,一个大的业务问题被分解为多个限界上下文(问题域),团队视野和专注就可以聚焦到每一个内聚的限界上下文,进行战术设计。战术设计的重点是利用领域驱动设计的元模型对领域的复杂性进行分解和建模。

领域驱动设计强调和突出了领域模型的重要性,通过整个领域驱动设计过程,绑定领域模型和技术模型,以保证领域模型和技术模型在贯穿整个软件开发的生命周期中(需求分析、建模、架构、设计、编码、测试与持续重构)的强一致性。领域模型指导着软件设计以及技术编码实现,接着通过重构实践来挖掘隐式概念,完善统一语言和模型,运用设计模式改进设计与开发质量。以下是领域驱动设计的粗略过程:

战略设计

提炼问题域

回顾我们往日的分析和解决问题过程, 面对复杂问题,很多同学还没完全理解问题的全貌就已经在提出解决办法,这些解决办法只是针对问题的局部,经典图书《第五项修炼》把这种行为称为“反应式”的,碰到一个问题给出一个回应办法,而从这些问题整体来看这种方式会阻碍团队找出最佳解决方案。

DDD 作为一种建模和架构方法,最大的突破是着重明确了区分了问题域和解决方案域,对业务问题的认知不是技术人员最擅长的,很多研发在碰到需求时,脑子本能就闪现表、类、服务、架构,把解决方案当终极问题来追求,而 DDD 要求研发进行痛苦的蜕变,在业务分析和领域建模阶段忘记技术解决方案。同时 DDD 要求领域专家和技术人员坐在一起通力合作、密切沟通来分析和建模,领域专家对业务有着深刻的理解,技术人员擅长技术实现和架构设计,而领域专家和技术人员由于工种的差异导致交流产生障碍,开发人员满脑子是技术语言,领域专家脑子也都是业务概念,如果按照本能基于自己的专业背景进行沟通,效率太低了,即使有翻译的角色也会产生理解偏差, DDD 的一个核心原则是所有人员包括领域专家和技术的进行任何沟通都使用一种基于模型的通用语言(UL,Ubiquitous Language),在代码中也是这样。

DDD 帮助技术人员对需求进行本质思考和理解,关注点不在是聚焦在功能上,而是理解需求的真正意图和愿景,而非开发一个 feature,更深层次地理解隐含的愿景才能开发出真正地解决问题和创造价值的系统来。在提炼问题域过程中,领域专家和技术专家通过充分交流,进行需求分析和知识提炼,获得清晰的问题子域,识别出核心域、通用域、支撑域。通用域是开发该软件系统根本竞争力所在,也是领域建模的重心,建议分配最精锐的研发;

通用域 是指多个子域依赖的通用功能子域,比如权限、邮件、日志系统等;支撑域 是指系统中非核心域和通用域的业务域。

需求分析时从用例开始,列出达成业务目标需要的步骤,切忌跳转到解决方案上,识别出用于构建模型的知识,通过 UML 表示分析模型和业务模型,形成业务和技术人员达成共识的通用语言。

该阶段领域专家只专注于问题域而不是解决方案,业务和技术人员基于 UL 沟通,并且考虑投入产出比,团队只为核心业务进行领域驱动设计并创建 UL,订单系统为下单模块进行 DDD,订单监控模块用普通的事务脚本方式来即可,我们通天塔的活动模板和积木业务非常复杂和核心,非常适合使用 DDD 来建模和架构设计,而通天塔后端的 Man 系统是面向开发者进行后端和线上业务监控的,进行 DDD 就是小题大做。

识别限界上下文(Bounded Context)

Eric Evans 说:“对一个大型系统,领域模型的完全统一将是不可行的或者不划算的。”。DDD 的构建块不能盲目地应用在一个无限大的领域模型上,一个无限大的领域模型也无助于我们开发出优质的软件,限界上下文是分解领域模型的关键。限界上下文是一种“分而治之”的思维,也是一种高层的抽象机制,让人们对领域进行本质思考,简化问题和应对复杂性。

限界上下文如同细胞,细胞是上下文,细胞壁是边界,细胞内的信息负责对代谢和遗传进行调控,细胞壁对细胞起着支持和保护防御的作用,控制物质进出,让对细胞有用的物质不能出来,有害的物质也不能进入细胞。而领域驱动设计中的限界上下文保证领域模型的一致性和完整性,清晰边界的控制力保证了领域的安全和稳定。

如何识别限界上下文?

明确了系统的问题域和业务期望后,梳理出主要的业务流程,这些业务流程体现了各种参与者在这个过程中通过业务活动共同协作,最终完成具有业务价值的领域功能。业务流程结合了参与角色(Who)、业务活动(What)和业务价值(Why)。在业务流程的基础上,我们就可以抽象出不同的业务场景,这些业务场景又由多个业务活动组成,可以利用领域场景分析方法剖析场景,以帮助我们识别业务活动,例如采用用例对场景进行分析,此时,一个业务活动实则就是一个用例。业务流程是一个由多个用户角色参与的动态过程,而业务场景则是这些用户角色执行业务活动的静态上下文。

接下来,我们利用领域场景分析的用例分析方法剖析这些场景。通过参与者(Actor)来驱动对用例的识别,这些参与者恰好就是参与到场景业务活动的角色。根据用例描述出来的业务活动应该与统一语言一致,最好直接从统一语言中撷取。一旦准确地用统一语言描述出这些业务活动,我们就可以从语义相关性和功能相关性两个方面识别业务边界,进而提炼出初步的限界上下文。

从不同角度看待限界上下文,限界上下文会呈现出对不同对象的控制力。

  • 领域逻辑层面:限界上下文确定了领域模型的业务边界,维护了模型的完整性与一致性,从而降低系统的业务复杂度。

  • 团队合作层面:限界上下文确定了团队的工作边界,建立了团队之间的合作模式,提升了团队间的协作效率,“康威定律”告诉我们,系统设计(产品结构)等同组织形式,每个设计系统的组织,其产生的设计等同于组织之间的沟通结构,限界上下文指导产生的团队结构的工作模式是最高效的。

  • 技术架构层面:限界上下文确定了系统架构的应用边界,保证了系统层和上下文领域层各自的一致性,建立了上下文之间的集成方式。微服务中,限界上下文指导技术人员划分微服务的边界,通常一个限界上下文作为一个在独立进程中运行的微服务。

DDD 驱动我们把每一个限界上下文设计成一个个“自治”的单元,自治要满足四个特点:

  • 最小完备 是实现自治的基本条件,指的是自治单元履行的职责是根据业务价值的完整性和最小功能集进行设计的,这让自治单元无需求助其他自治单元获得信息,避免了不必要的依赖关系,同时也避免了不必要和不合适的职责添加到该自治单元上。

  • 自我履行意味着由自治单元自身决定要做什么。是否应该履行某职责,由限界上下文拥有的信息来决定。站在自治单元的角度去思考:“如果我拥有了这些信息,我究竟应该履行哪些职责?”这些职责属于当前上下文的活动范围,一旦超出,就该毫不犹豫地将不属于该范围的请求转交给别的上下文。自我履行其实意味着对知识的掌握,为避免风险,你要履行的职责一定是你掌握的知识范畴之内。

  • 稳定空间 指的是减少外界变化对限界上下文内部的影响。稳定空间符合开放封闭原则(OCP),即对修改是封闭的,对扩展是开放的,该原则其实体现了一个单元的封闭空间与开放空间。封闭空间体现为对细节的封装与隐藏,开放空间体现为对共性特征的抽象与统一,二者共同确保了整个空间的稳定。

  • 独立进化 指的是减少限界上下文的变化对外界的影响。用限界上下文的上下游关系来阐释,则稳定空间寓意下游限界上下文,无论上游怎么变,我自岿然不动。要做到独立进化,就必须保证对外公开接口的稳定性,因为这些接口被众多消费者依赖和调用,一旦发生变更,就会牵一发而动全身。一个独立进化的限界上下文,需要一个稳定、设计良好的接口设计,并在版本上考虑了兼容与演化。

最小完备是基础,只有赋予了限界上下文足够的信息,才能保证它的自我履行。稳定空间与独立进化则一个对内一个对外,是对变化的有效应对,而它们又是通过最小完备和自我履行来保障限界上下文受到变化的影响最小。

DDD(领域驱动设计)系列主题:领域驱动设计(DDD)实践相关推荐

  1. IP网络设计系列之-局域网设计

    [导读]这是ip网络设计系列讲座的最后一部分,讨论园区局域网设计中遇到的一些问题.以太网交换机优越于传统的集线器环境的好处将首先介绍一下.应用虚拟局域网的动机已经同规划和配置虚拟局域网遇到的问题一起进 ...

  2. iv+css大作业:主题旅游网站设计——蓝色主题旅游网页设计(6页) HTML+CSS+JavaScript 主题出行

    div+css作业:主题旅游网站设计--蓝色主题旅游网页设计(6页) HTML+CSS+JavaScript 主题出行 常见网页设计作业题材有 个人. 美食. 公司. 学校. 旅游. 电商. 宠物. ...

  3. HTML5期末大作业:主题旅游网站设计——蓝色主题旅游网页设计(6页) HTML+CSS+JavaScript 主题出行

    HTML5期末大作业:主题旅游网站设计--蓝色主题旅游网页设计(6页) HTML+CSS+JavaScript 主题出行 常见网页设计作业题材有 个人. 美食. 公司. 学校. 旅游. 电商. 宠物. ...

  4. linux v4l2 示例程序,linux驱动由浅入深系列:camera驱动之二(基于高通平台的V4L2结构及代码分析)...

    在上一篇文章中介绍了camera的基础知识和相关概念,我们一起来了解一下驱动相关的代码结构.本文以高通+android平台为示例,首先看一下整体框图: 这张图是从整体上来看的 1,图中最下面的是ker ...

  5. linux驱动由浅入深系列:camera驱动之二(基于高通平台的V4L2结构及代码分析)

    在上一篇文章中介绍了camera的基础知识和相关概念,我们一起来了解一下驱动相关的代码结构.本文以高通+android平台为示例,首先看一下整体框图: 这张图是从整体上来看的 1,图中最下面的是ker ...

  6. linux驱动由浅入深系列:camera驱动之二(基于高通平台的V4L2结构及代码分析

    点击打开链接 在上一篇文章中介绍了camera的基础知识和相关概念,我们一起来了解一下驱动相关的代码结构.本文以高通+android平台为示例,首先看一下整体框图: 这张图是从整体上来看的 1,图中最 ...

  7. 【游戏设计系列】关于游戏设计文档

    如何编写设计文档 设计文档的分类 迷你型设计(mini design) 定义:一周左右完成的设计,一个完整却简单的游戏描述 要求 任何一团队成员能够摘录与阅读 读者能够了解游戏设计者的设计意图 读者能 ...

  8. 驰骋工作流引擎设计系列05 启动流程设计

    2019独角兽企业重金招聘Python工程师标准>>> 启动流程设计 第1节. 关键字 驰骋工作流引擎 流程快速开发平台 workflow ccflow jflow 第1节. 启动流 ...

  9. UML设计系列(8):数据库关联关系图

    传送门 UML设计系列(1):状态机图 UML设计系列(2):类图 UML设计系列(3):时序图 UML设计系列(4):用例图 UML设计系列(5):系统依赖图 UML设计系列(6):活动图 UML设 ...

  10. 幼儿园网络图怎么绘制_如何设计幼儿园主题网络图.doc

    如何设计幼儿园主题网络图 如何设计幼儿园主题网络图????????????????????????????? 赵春莉 幼儿园主题活动以一定教育主题为核心,以幼儿生活为基础,以游戏和活动为基本形式,以幼 ...

最新文章

  1. AI:百度飞桨EasyDL多门视频课程,手把手教你如何定制高精度AI模型
  2. kdj值应用口诀_KDJ买卖绝学!记住这些操作 精准判断quot;顶部和底部quot; 让你远离亏损...
  3. DEDE文章列表加上序号效果
  4. 4个数字,如何最快找到最小的2个数
  5. python安装pymssql等包时出现microsoft visual c++ 14.0 is required问题无需下载visualcppbuildtools的解决办法...
  6. WP7基础学习---第一讲
  7. 关于sybase数据库的连接
  8. VUE框架应用包---------微信二维码应用
  9. 【数据集收集】可用于深度学习模型的遥感数据集(持续更新,最后更新时间2020-06)
  10. Tableau 中国最美八条骑行线路(三)天数与预算
  11. 负数与二进制之间的转换
  12. HP笔记本装XP,‘基本系统设备’驱动的安装
  13. 分布式锁的一些细节问题,值得收藏
  14. “靠天吃饭”坐拥百万资产客户,富途摆脱被动局面难?
  15. 如何通过YouTube实现财富自由?
  16. 【微信小程序】-- WXML 模板语法 - 数据绑定(九)
  17. QT 带 进度条 解压缩文件方法 - QuaZip
  18. 2022中国中医药产业展,山东医药保健展,济南药交会9月举办
  19. 操作系统的启动过程详解
  20. 中国知网html阅读说明什么区别,知网研学和中国知网的区别

热门文章

  1. 新手编程 编写一个方法,输出大于某个正整数n的最小的质数。
  2. 日语在线翻译和日语在线词典网站
  3. MFC简单自学图形绘制1
  4. 七彩虹技术服务论坛硬件驱动更新指南(添加Vista支持)
  5. 华为USG系列防火墙配置-带宽管理
  6. QQ找茬辅助工具 C#
  7. 2020年焊工(高级)模拟试题及焊工(高级)模拟考试
  8. python用户手册是什么_Wind量化平台-用户手册(Python).pdf
  9. 【工业互联网】康鹏举:工业互联网平台的技术内核与创新应用
  10. 最好用的Python网页抓取工具包!