安装shadowsocks的v2ray插件

服务端部署 部署环境:CentOS 7.6 x64 安装Shadowsocks-libev 这个之前博文说过,就不重复了。 安装v2ray-plugin 我懒得编译,直接下载已经编译好的了,解压到/usr/local/bin/下。 获取SSL证书 我使用的是Let’s Encrypt的免费证书(这里建议使用CloudFlare的免费证书),执行命令之前记得先将域名的A记录解析到服务器IP上,并且开放80和443端口。 wget https://dl.eff.org/certbot-auto chmod a+x certbot-auto ./certbot-auto certonly 成功之后会有/etc/letsencrypt/live/域名/fullchain.pem和/etc/letsencrypt/live/域名/privkey.pem两个文件。 修改配置文件 默认配置文件在/etc/shadowsocks-libev/config.json,如下文所示,在最后加上plugin和plugin_opts,把域名换成自己的就行。这里采用的是Shadowsocks over websocket (HTTPS),其它的可以自己参考GitHub上的介绍。 { "server":"0.0.0.0", "server_port":443, "local_port":1080, "password":"password", "timeout":300, "method":"aes-256-gcm", "plugin":"v2ray-plugin", "plugin_opts":"server;tls;cert=/etc/letsencrypt/live/域名/fullchain.pem;key=/etc/letsencrypt/live/域名/privkey.pem;host=域名;loglevel=none" } 最后执行ss-server -c /etc/shadowsocks-libev/config.json -f /run/shadowsocks.pid即可。 客户端设置 先安装对应平台的Shadowsocks客户端。 Windows 直接下载已经编译好的v2ray-plugin的windows版,解压后命名为v2ray-plugin.exe和Shadowsocks.exe放在同一文件夹下。 在Shadowsocks的服务器设置中,插件程序填v2ray-plugin,插件选项填tls;host=域名。域名要和服务端设置的一致。 Android 安装v2ray-plugin-android,打开Shadowsocks编辑服务器,在最下面的插件中选择v2ray,配置Transport mode为websocket-tls,Hostname为服务端设置的域名即可。 Ubuntu 直接下载已经编译好的v2ray-plugin,解压到/usr/local/bin/下。 编辑配置文件/etc/shadowsocks-libev/config.json,如下文所示,在最后加上plugin和plugin_opts,域名要和服务端设置的一致。 { "server":"域名", "server_port":443, "local_port":1080, "password":"password", "timeout":300, "method":"aes-256-gcm", "plugin":"v2ray-plugin", "plugin_opts":"tls;host=域名;loglevel=none" } 最后执行ss-local -c /etc/shadowsocks-libev/config.json即可。 优势 你甚至可以把SS服务器放在CDN后面,免费的CDN有Cloudflare。 然后,最重要的,让你的服务器屏蔽所有除了CloudFlare和你自己的IP之外的所有IP。 基本上很长一段时间内,G#F#W就拿你没办法了。 原文: https://blog.m3chd09.com/2019/02/01/v2ray-plugin-for-shadowsocks.html

June 4, 2019

我们都拿到了4个6.5,总分7

其实这个分数,我在去年9月份的时候就拿到了,但是因为就差一点点达到4个7,所以很不服气又考了3次,但依然没有拿到理想分数,幸运的是爱人也拿到了这个分数。目前来看,只能抢489和491了,如果抢不到就考虑新西兰。 我心里觉得如果坚持下去,应该能拿到4个7,但是现在这个分数也无法189和190,特别是最近澳洲出了新的政策,砍掉大量的配额,并且出了新的491签证,所以不打算考了。 回过头了,从2017年5月起,到2018年12月,一年半的时间,虽然没有达到理想的分数,但是想想对于口语那么烂的我,也许这个结果已经很不错了。 这近两年过来关于migaration的问题,我们讨论、争论、研究、分析,期间还去了一趟澳新,最终达成一致,定了目标,就看后面这几个月了。 希望有志者事竟成,我真的很希望能拿我们喜欢的地方,I love Melbourne! 写在五月的最后一天。

May 31, 2019

.NET Core 3.0 Preview 5发布

今天我们非常高兴发布 .NET Core 3.0 Preview 5,它包含了新的Json serializer,支持发布单执行文件,并且更新到新的runtime roll-forward,BCL也做了一些改动。 目前可以下载.NET Core 3.0 Preview 5安装到Windows, macOS and Linux.另外,ASP.NET Core和EF Core也发布了。 具体英文地址:https://devblogs.microsoft.com/dotnet/announcing-net-core-3-0-preview-5/

May 28, 2019

留美幼童观后感

“他们是中国历史上最早的官派留学生。公元1872年到1875年间,清政府先后派出四批共一百二十名学生赴美国留学。这批学生出洋时的平均年龄只有十二岁,因此 他们有一个共同的名字——留美幼童。这批饱受欧风美雨熏陶的学子是中国矿业、铁路业、电报业的先驱。他们中出现了今天清华大学、天津大学最早的校长,出现了中国最早的一批外交官,出现了中华民国的第一任总理。回国后的这批西学所造之子历经中国晚清政坛的跌宕起伏,目睹了近代中国的荣辱兴衰。 留美幼童的命运,离奇曲折;他们的故事,美丽而忧伤。 他们有一个永远的名字:留美幼童。” 最近翻出央视的一部纪录片《留美幼童》,居然眼前一亮,原来央视也出过这么优秀的纪录片。眼看现在中美贸易战打得火热,不知道有多少人认真去看这部纪录片。如果认真想想中国近代化和现代话过程中,哪个国家对中国最慷慨和友好,我觉得一定是美国,美国没有侵略过中国,并且100多年来一直在帮助中国。历史上美国对中国伤害最大的估计也就是1882的排华法案,但要知道这只是限制华人在美的权利。 留美幼童是中国与美国的第一次接触,但清政府却因为排华法案从日后第一强国撤回留学生。从此以后,美国对中国的帮助就一直延续:庚子赔款退还用于建设清华园、为中国培养大批人才;协和医院救助大量中国人、并且培养大量医学人才;二战期间无私地帮助中国进行反法西斯战争、并确认战后五个大国之一的地位;中美建交成功阻止了苏联对中国的威胁;新世纪帮助加入世贸、彻底改变中国的经济状况…

May 28, 2019

领域驱动设计实现之路

2004年,Eric Evans出版《领域驱动设计——软件核心复杂性应对之道》(简称《领域驱动设计》),10年之后,我们有了《实现领域驱动设计》。DDD将一个软件系统的核心业务功能集中在一个核心域里面,其中包含了实体、值对象、领域服务、资源库和聚合等概念。在此基础上,DDD提出了一套完整的支撑这样的核心领域的基础设施。此时,DDD已经不再是“面向对象进阶”那么简单了,而是演变成了一个系统工程。 领域,即是一个组织的业务开展方式,业务价值便体现在其中。长久以来,我们程序员都是很好的技术型思考者,我们总是擅长从技术的角度来解决项目问题。但是,一个软件系统是否真正可用是通过它所提供的业务价值体现出来的。因此,与其每天钻在那些永远也学不完的技术中,何不将我们的关注点向软件系统所提供的业务价值方向思考思考,这也正是DDD所试图解决的问题。在DDD中,代码就是设计本身,你不再需要那些繁文缛节的并且永远也无法得到实时更新的设计文档。编码者与领域专家再也不需要翻译才能理解对方所表达的意思。DDD有战略设计和战术设计之分。战略设计主要从高层“俯视”我们的软件系统,帮助我们精准地划分领域以及处理各个领域之间的关系;而战术设计则从技术实现的层面教会我们如何具体地实施DDD。 DDD之战略设计 DDD的战略设计主要包括领域/子域、通用语言、限界上下文和架构风格等概念。 1、领域和子域(Domain/Subdomain) 领域驱动设计关注点应该放在如何设计领域模型上,以及对领域模型的划分。 领域的概念:一个电商网站的领域包含了产品名录、订单、发票、库存和物流的概念。领域的划分是将一个大的领域划分成若干个子域。通常会将一个大型的软件系统拆分成若干个子系统。这种划分有可能是基于架构方面的考虑,也有可能是基于基础设施的。DDD对系统的划分是基于领域的,即基于业务。第一个问题,哪些概念应该建模在哪些子系统里面?第二个问题是,各个子系统之间的应该如何集成?如何解决?答案是:限界上下文和上下文映射图。 2、限界上下文(Bounded Context) 在一个领域/子域中,我们会创建一个概念上的领域边界,在这个边界中,任何领域对象都只表示特定于该边界内部的确切含义。这样边界便称为限界上下文。限界上下文和领域具有一对一的关系。将一个限界上下文中的所有概念,包括名词、动词和形容词全部集中在一起,我们便为该限界上下文创建了一套通用语言。通用语言是一个团队所有成员交流时所使用的语言,业务分析人员、编码人员和测试人员都应该直接通过通用语言进行交流。 上文中的各个子域之间的集成问题,是限界上下文之间的集成问题。防腐层负责与外部服务提供方打交道,还负责将外部概念翻译成自己的核心领域能够理解的概念。当然,防腐层只是限界上下文之间众多集成方式的一种,另外还有共享内核、开放主机服务等,具体细节请参考 《实现领域驱动设计》原书。限界上下文之间的集成关系也可以理解为是领域概念在不同上下文之间的映射关系,因此,限界上下文之间的集成也称为上下文映射图。 3、架构风格(Architecture) DDD并不要求采用特定的架构风格,因为它是对架构中立的。可以采用传统的三层式架构,也可以采用REST架构和事件驱动架构等。但是在《实现领域驱动设计》中,作者比较推崇事件驱动架构和六边形(Hexagonal)架构。在六边形架构中,已经不存在分层的概念,所有组件都是平等的。这主要得益于软件抽象的好处,即各个组件的之间的交互完全通过接口完成,而不是具体的实现细节。Robert C. Martin:抽象不应该依赖于细节,细节应该依赖于抽象。 采用六边形架构的系统中存在着很多端口和适配器的组合。端口表示的是一个软件系统的输入和输出,而适配器则是对每一个端口的访问方式。 DDD之战术设计 战略设计为我们提供一种高层视野来审视我们的软件系统,而战术设计则将战略设计进行具体化和细节化,它主要关注的是技术层面的实施,也是对我们程序员来得最实在的地方。 1、领域对象 领域对象能够准确地表达出业务意图,但多数时候却是充满getter和setter的领域对象,此时的领域对象已经不是领域对象了,而是Martin Fowler所称之为的贫血对象。.NET里面很好地支持非贫血对象。 2、实体vs值对象(Entity vs Value Object) 软件系统中实体表示那些具有生命周期并且会在其生命周期中发生改变的东西;而值对象则表示起描述性作用的并且可以相互替换的概念。同一个概念,在一个软件系统中被建模成了实体,但是在另一个系统中则有可能是值对象。 3、聚合(Aggregate) 聚合是DDD中最难理解的概念 ,聚合中所包含的对象之间具有密不可分的联系,他们是内聚在一起的。比如一辆汽车(Car)包含了引擎(Engine)、车轮 (Wheel)和油箱(Tank)等组件,缺一不可。一个聚合中可以包含多个实体和值对象,因此聚合也被称为根实体。聚合是持久化的基本单位,它和资源库具有一一对应的关系。 4、领域服务(Domain Service) 领域概念放在实体上不合适,放在值对象上也不合适,领域服务本来就是来处理这种场景的。比如对密码进行加密,可以创建一个 PasswordEncryptService来专门负责此事。 5、资源库(Repository) 资源库用于保存和获取聚合对象,资源库与DAO相似。但资源库和DAO存在显著区别。DAO只是对数据库的一层很薄的封装,而资源库则更加具有领域特征。另外,所有的实体都可以有相应的DAO,但并不是所有的实体都有资源库,只有聚合才有相应的资源库。资源库分为两种,一种是基于集合的,一种是基于持久化的。顾名思义,基于集合的资源库具有编程语言中集合的特征。 6、领域事件(Domain Event) 《领域驱动设计》中并没有提到领域事件,领域事件是最近几年才加入DDD生态系统的。微服务(Micro Service)的架构中,整个系统被分成了很多个轻量的程序模块,他们之间的数据一致性并不容易通过事务一致性完成,领域事件便可以用于处理上述问题,此时最终一致性取代了事务一致性,通过领域事件的方式达到各个组件之间的数据一致性。

May 20, 2019

澳新之行

这趟旅行我们酝酿了将近一年时间。今年正好是我们结婚七周年,而从去年开始,澳新这两个国家就一直在我们家里反复被提起讨论,连宝宝都是不是冒出阿德莱德、奥克兰、悉尼、墨尔本了。想想如果不先出去看看,对于我们都没有出过国的人来说,讨论migration貌似真的有点夸张。正好从网上、电视上看,这两个国家的景色和环境都非常棒,所以我们就打算作为旅行地。 从北京出发,穿过中国的大江南北,穿过黄河、长江、南海,穿过马来西亚,来到新加坡,休息一晚上,从新加坡穿过南太平洋,来到澳大利亚的上空,穿过帕斯、穿过阿德莱德,来到墨尔本。 一、墨尔本 墨尔本气候宜人,人文氛围好。这是皇家植物园,确实名不虚传。 二、悉尼 悉尼确实很繁华,她的繁华体现在几乎每个地方都很发达。这是悉尼歌剧院和海港大桥。 三、奥克兰 奥克兰是新西兰的首都,但因为准备举办帆船世界杯,到处都在施工,而且山地多,所以整体的感觉没有澳洲方便。当然,伊甸山还是很棒的。 四、皇后镇(格林诺奇、剑镇和瓦纳卡湖) 新西兰的自然环境无可挑剔,真的是100%纯净的新西兰。皇后镇很美,格林诺奇是一个来了就不想走的地方,秋天的剑镇更是让人心醉。 这是箭镇,而文章最开始那张是格林诺奇,爱人和女儿的合影。 这是瓦纳卡湖,没有什么比这个湖更美的了。 五、惠灵顿 惠灵顿是首都,所以更让人舒适,而且这里居住的人,很多是英国人的后裔,感觉他们依然秉承英伦gentle之风。

May 10, 2019

.NET Core 3.0-preview3 发布

.NET Core 3.0 Preview 3已经发布,框架和ASP.NET Core有许多有趣的更新。这是最重要的更新列表。 下载地址 :https://aka.ms/netcore3download 。 .NET Core 3.0的更新: C#中对索引和范围的更多支持 支持.NET Standard 2.1。以.NET Standard项目文件为目标,并将netstandard2.1指定为目标框架。完整的.NET Framework不支持.NET Standard 2.1。 F#4.6和dotnet fsi命令。可以使用F#4.6和dotnet fsi命令的预览。FSI代表F#互动。 AssemblyDependencyResolver和resolver事件。从给定路径加载依赖程序集(之前不可能),解析程序事件可帮助我们更好地处理动态加载的本机依赖项。 Windows Forms应用程序的高DPI。最后,微软将Windows Forms应用程序推向了当今时代。96DPI不再适用,并且可以构建高DP Windows窗体应用程序。 ​ ASP.NET Core 3.0的更新: Razor组件的改进。现在2个项目合并成单个项目模板,Razor组件支持端点路由和预渲染,Razor组件可以托管在Razor类库中。还改进了事件处理和表单和验证支持。 运行时编译。它在ASP.NET Core 3.0模板中被禁用,但现在可以通过向项目添加特殊的NuGet包来打开它。 Worker Service 模板。需要编写Windows服务还是Linux守护进程?现在我们有了Worker Service 模板。 gRPC模板。与谷歌一起构建的gRPC是一种流行的远程过程调用(RPC)框架。此版本的ASP.NET Core在ASP.NET Core上引入了第一等的gRPC支持。 Angular模板使用Angular 7. Angular SPA模板现在使用Angular 7,在第一次稳定释放之前,它将被Angular 8替换。 SPA-s的身份验证。Microsoft通过此预览为单页应用程序添加了现成的身份验证支持。 SignalR与端点路由集成。小变化 - 现在使用端点路由定义SingalR路由。 SignalR Java客户端支持长轮询。即使在不支持或不允许WebSocket的环境中,SignalR Java客户端现在也可以使用。

March 6, 2019

【转】浅谈我对DDD领域驱动设计的理解

遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决。 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品。所以,自然而然就想到要做一个普通电商系统,用于实现在线销售自己企业产品的目的。 再比如,我是一家互联网公司,公司有很多系统对外提供服务,面向很多客户端设备。但是最近由于各种原因,导致服务经常出故障。所以,我们希望通过各种措施提高服务的质量和稳定性。其中的一个措施就是希望能做一个灰度发布的平台,这个平台可以提供灰度发布的服务。然后,当某个业务系统做了一些修改并需要发布时,可以使用我们的灰度发布平台来非常方便的实现灰度发布的功能。比如在灰度发布平台上方便的定制允许哪些特定的客户端才会访问新服务,哪些客户端继续使用老服务。灰度发布平台可以提供各种灰度的策略。有了这样的灰度发布机制,那即便系统的新逻辑有什么问题,受影响的面也不会很大,在可控范围内。所以,如果公司里的所有对外提供服务的系统都接入了灰度平台,那这些系统的发布环节就可以更加有保障了。 总之,我们做任何一个软件系统,都是有原因的,否则就没必要做这个系统,而这个原因就是我们遇到的问题。所以,通过问题,我们就知道了我们需要一个什么样的系统,这个系统解决什么样的问题。最后,我们就很自然的得出了一个目标,即知道了自己要什么。比如我要做一个论坛、一个博客系统、一个电商平台、一个灰度发布系统、一个IDE、一个分布式消息队列、一个通信框架,等等。 DDD切入点1 - 理解概念 DDD的全称为Domain-driven Design,即领域驱动设计。下面我从领域、问题域、领域模型、设计、驱动这几个词语的含义和联系的角度去阐述DDD是如何融入到我们平时的软件开发初期阶段的。要理解什么是领域驱动设计,首先要理解什么是领域,什么是设计,还有驱动是什么意思,什么驱动什么。 一、什么是领域(Domain)? 前面我们已经清楚的知道我们现在要做一个什么样的系统,这个系统需要解决什么问题。我认为任何一个系统都会属于某个特定的领域,比如论坛是一个领域,只要你想做一个论坛,那这个论坛的核心业务是确定的,比如都有用户发帖、回帖等核心基本功能。比如电商平台、普通电商系统,这种都属于网上电商领域,只要是这个领域的系统,那都有商品浏览、购物车、下单、减库存、付款交易等核心环节。所以,同一个领域的系统都具有相同的核心业务,因为他们要解决的问题的本质是类似的。 因此,我们可以推断出,一个领域本质上可以理解为就是一个问题域,只要是同一个领域,那问题域就相同。所以,只要我们确定了系统所属的领域,那这个系统的核心业务,即要解决的关键问题、问题的范围边界就基本确定了。通常我们说,要成为一个领域的专家,必须要在这个领域深入研究很多年才行。因为只有你研究了很多年,你才会遇到非常多的该领域的问题,同时你解决这个领域中的问题的经验也非常丰富。很多时候,领域专家比技术专家更加吃香,比如金融领域的专家。 二、什么是设计(Design)? DDD中的设计主要指领域模型的设计。为什么是领域模型的设计而不是架构设计或其他的什么设计呢?因为DDD是一种基于模型驱动开发的软件开发思想,强调领域模型是整个系统的核心,领域模型也是整个系统的核心价值所在。每一个领域,都有一个对应的领域模型,领域模型能够很好的帮我们解决复杂的业务问题。 从领域和代码实现的角度来理解,领域模型绑定了领域和代码实现,确保了最终的代码实现就一定是解决了领域中的核心问题的。因为:1)领域驱动领域模型设计;2)领域模型驱动代码实现。我们只要保证领域模型的设计是正确的,就能确定领域模型可以解决领域中的核心问题;同理,我们只要保证代码实现是严格按照领域模型的意图来落地的,那就能保证最后出来的代码能够解决领域的核心问题的。这个思路,和传统的分析、设计、编码这几个阶段被割裂(并且每个阶段的产物也不同)的软件开发方法学形成鲜明的对比。 三、什么是驱动(Driven)? 上面其实已经提到了,就是:1)领域驱动领域模型设计;2)领域模型驱动代码实现。这个就和我们传统的数据库驱动开发的思路形成对比了。DDD中,我们总是以领域为边界,分析领域中的核心问题(核心关注点),然后设计对应的领域模型,再通过领域模型驱动代码实现。而像数据库设计、持久化技术等这些都不是DDD的核心,而是外围的东西。 领域驱动设计(DDD)告诉我们的最大价值我觉得是:当我们要开发一个系统时,应该尽量先把领域模型想清楚,然后再开始动手编码,这样的系统后期才会很好维护。但是,很多项目(尤其是互联网项目,为了赶工)都是一开始模型没想清楚,一上来就开始建表写代码,代码写的非常冗余,完全是过程是的思考方式,最后导致系统非常难以维护。而且更糟糕的是,出来混总是要还的,前期的领域模型设计的不好,不够抽象,如果你的系统会长期需要维护和适应业务变化,那后面你一定会遇到各种问题维护上的困难,比如数据结构设计不合理,代码到处冗余,改BUG到处引入新的BUG,新人对这种代码上手困难,等。而那时如果你再想重构模型,那要付出的代价会比一开始重新开发还要大,因为你还要考虑兼容历史的数据,数据迁移,如何平滑发布等各种头疼的问题。所以,就导致我们最后天天加班。 虽然,我们都知道这个道理,但是我也明白,人的习惯很难改变的,大部分人都很难从面向过程式的想到哪里写到哪里的思想转变为基于系统化的模型驱动的思维。我想,这或许是DDD很难在中国或国外流行起来的原因吧。但是,我想这不应该成为我们放弃学习DDD的原因,对吧! 概念总结: 领域就是问题域,有边界,领域中有很多问题; 任何一个系统要解决的那个大问题都对应一个领域; 通过建立领域模型来解决领域中的核心问题,模型驱动的思想; 领域建模的目标针对我们在领域中所关心的问题,即只针对核心关注点,而不是整个领域中的所有问题; 领域模型在设计时应考虑一定的抽象性、通用性,以及复用价值; 通过领域模型驱动代码的实现,确保代码让领域模型落地,代码最终能解决问题; 领域模型是系统的核心,是领域内的业务的直接沉淀,具有非常大的业务价值; 技术架构设计或数据存储等是在领域模型的外围,帮助领域模型进行落地。 DDD切入点2 - 理解领域、拆分领域、细化领域 一、理解领域知识是基础 上面我们通过第一步,虽然我们明确了要做一个什么样的系统,该系统主要解决什么问题,但是就这样我们还无法开始进行实际的需求分析和模型设计,我们还必须将我们的问题进行拆分,需求进行细化。有些时候,需求方,即提出问题的人,很可能自己不清楚具体想要什么。他只知道一个概念,一个大的目标。比如他只知道要做一个股票交易系统,一个灰度发布系统,一个电商平台,一个开发工具,等。但是他不清楚这些系统应该具体做成什么样子。这个时候,我认为领域专家就非常重要了,DDD也非常强调领域专家的重要性。因为领域专家对这个领域非常了解,对领域内的各种业务场景和各种业务规则也非常清楚,总之,对这个领域内的一切业务相关的知识都非常了解。所以,他们自然就有能力表达出系统该做成什么样子。所以,要知道一个系统到底该做成什么样子,到底哪些是核心业务关注点,只能靠沉淀领域内的各种知识,别无他法。因此,假设你现在打算做一个电商平台,但是你对这个领域没什么了解,那你一定得先去了解下该领域内主流的电商平台,比如淘宝、天猫、京东、亚马逊等。这个了解的过程就是你沉淀领域知识的过程。如果你不了解,就算你领域建模的能力再强,各种技术架构能力再强也是使不上力。领域专家不是某个固定的角色,而是某一类人,这类人对这个领域非常了解。比如,一个开发人员也可以是一个领域专家。假设你在一个公司开发和维护一个系统已经好几年了,但是这个系统的产品经理(PD)可能已经换过好几任了,这种情况下,我相信这几任产品经理都没有比你更熟悉这个领域。 二、拆分领域 上面我们明白了,领域建模的基础是要先理解领域,让自己成为领域专家。如果做到了这点,我们就打好了坚实的基础了。但是,有时一个领域往往太复杂,涉及到的领域概念、业务规则、交互流程太多,导致我们没办法直接针对这个大的领域进行领域建模。所以,我们需要将领域进行拆分,本质上就是把大问题拆分为小问题,然后各个击破的思路。然后既然把一个大的领域划分为了多个小的领域(子域),那最关键的就是要理清每个子域的边界;然后要搞清楚哪些子域是核心子域,哪些是非核心子域,哪些是公共支撑子域;然后,还要思考子域之间的联系是什么。那么,我们该如何划分子域呢?我的个人看法是从业务相关性的角度去思考,也就是我们平时说的按业务功能为出发点进行划分。还是拿经典的电商系统来分析,通常一个电商系统都会包含好几个大块,比如: 会员中心:负责用户账号登录、用户信息的管理; 商品中心:负责商品的展示、导航、维护; 订单中心:负责订单的生成和生命周期管理; 交易中心:负责交易相关的业务; 库存中心:负责维护商品的库存; 促销中心:负责各种促销活动的支持; 上面这些中心看起来很自然,因为大家对电子商务的这个领域都已经非常熟悉了,所以都没什么疑问,好像很自然的样子。所以,领域划分是不是就是没什么挑战了呢?显然不是。之所以我们觉得子域划分很简单,是因为我们对整个大领域非常了解了。如果我们遇到一个冷门的领域,就没办法这么容易的去划分子域了。这就需要我们先去努力理解领域内的知识。所以,我个人从来不相信什么子域划分的技巧什么的东西,因为我觉得这个工作没有任何诀窍可以使用。当我们不了解一个东西的时候,如何去拆解它?当我们对整个领域有一定的熟悉了,了解了领域内的相关业务的本质和关系,我们就自然而然的能划分出合理的子域了。不过并不是所有的系统都需要划分子域的,有些系统只是解决一个小问题,这个问题不复杂,可能只有一两个核心概念。所以,这种系统完全不需要再划分子域。但不是绝对的,当一个领域,我们的关注点越来越多,每个关注点我们关注的信息越来越多的时候,我们会不由自主的去进一步的划分子域。比如,也许我们一开始将商品和商品的库存都放在商品中心里,但是后来由于库存的维护越来越复杂,导致揉在一起对我们的系统维护带来一定的困难时,我们就会考虑将两者进行拆分,这个就是所谓的业务垂直分割。 三、细化子域 通过上面的两步,我们了解了领域里的知识,也对领域进行了子域划分。但这样还不够,凭这些我们还无法进行后续的领域模型设计。我们还必须再进一步细化每个子域,进一步明确每个子域的核心关注点,即需求细化。我觉得我们需要细化的方面有以下几点: 梳理领域概念:梳理出领域内我们关注的概念、概念的关系,并统一交流词汇,形成统一语言; 梳理业务规则:梳理出领域内我们关注的各种业务规则,DDD中叫不变性(invariants),比如唯一性规则,余额不能小于零等; 梳理业务场景:梳理出领域内的核心业务场景,比如电商平台中的加入购物车、提交订单、发起付款等核心业务场景; 梳理业务流程:梳理出领域内的关键业务流程,比如订单处理流程,退款流程等; 从上面这4个方面,我们从领域概念、业务规则、交互场景、业务流程等维度梳理了我们到底要什么,整理了整个系统应该具备的功能。这个工作我觉得是一个非常具有创造性和有难度的工作。我们一方面会主观的定义我们想要什么;另一方面,我们还会思考我们要的东西的合理性。我认为这个就是产品经理的工作,产品经理必须要负起职责,把他的产品充分设计好,从各个方面去考虑,如何设计一个产品,才能更好的解决用户的核心诉求,即领域内的核心问题。如果对领域不够了解,如果想不清楚用户到底要什么,如果思考问题不够全面,谈何设计出一个合理的产品呢? 关于领域概念的梳理,我觉得可以采用四色原型分析法,这个分析法通过系统的方法,将概念划分为不同的种类,为不同种类的概念标注不同的颜色。然后将这些概念有机的组合起来,从而让我们可以清晰的分析出概念和概念之间的关系。有兴趣的同学可以在网上搜索下四色原型。 注意:上面我说的这四点,重点是梳理出我们要什么功能,而不是思考如何实现这些功能,如何实现是软件设计人员的职责。 DDD切入点3 - 领域模型设计 这部分内容,我想学习DDD的人都很熟悉了。DDD原著中提出了很多实用的建模工具:聚合、实体、值对象、工厂、仓储、领域服务、领域事件。我们可以使用这些工具,来设计每一个子域的领域模型。最终通过领域模型图将设计沉淀下来。要使用这些工具,首先就要理解每个工具的含义和使用场景。不要以为很简单哦,比如聚合的划分就是一个非常具有艺术的活。同一个系统,不同的人设计出来的聚合是完全不同的。而且很有可能高手之间的最后设计出来的差别反而更大,实际上我认为是世界观的相互碰撞,呵呵。所以,要领域建模,我觉得每个人都应该去学学哲学知识,这有助于我们更好的认识世界,更好的理解事物的本质。 关于这些建模工具的概念和如何运用我就不多展开了,我博客里也有很多这方面的介绍。下面我再讲一下我认为比较重要的东西,比如到底该如何领域建模?步骤应该是怎么样的? 一、领域建模的方法 通过上面我介绍的细化子域的内容,现在再来谈该如何领域建模,我觉得就方便很多了。我的主要方法是: 划分好边界上下文,通常每个子域(sub domain)对应一个边界上下文(bounded context),同一个边界上下文中的概念是明确的,没有任何歧义; 在每个边界上下文中设计领域模型,具体的领域模型设计方法有很多种,如以场景为出发点的四色原型分析法,或者我早期写的这篇文章;这个步骤最核心的就是找出聚合根,并找出每个聚合根包含的信息;关于如何设计聚合,可以看一下我写的这篇文章; 画出领域模型图,圈出每个模型中的聚合边界; 设计领域模型时,要考虑该领域模型是否满足业务规则,同时还要综合考虑技术实现等问题,比如并发问题;领域模型不是概念模型,概念模型不关注技术实现,领域模型关心;所以领域模型才能直接指导编码实现; 思考领域模型是如何在业务场景中发挥作用的,以及是如何参与到业务流程的每个环节的; 场景走查,确认领域模型是否能满足领域中的业务场景和业务流程; 模型持续重构、完善、精炼; 二、领域模型的核心作用: 抽象了领域内的核心概念,并建立概念之间的关系; 领域模型承担了领域内的状态的维护; 领域模型维护了领域内的数据之间的业务规则,数据一致性; 需要特别注意的是,领域模型设计只是整个软件设计中的很小一部分。除了领域模型设计之外,要落地一个系统,我们还有非常多的其他设计要做,比如: ...

March 6, 2019

讲给女儿的故事

白雪公主和白马王子的故事 在很久很久以前,有一位美丽的白雪公主,她有一头乌黑的长发、圆圆的脸蛋、明亮的眼睛、弯弯的眉毛和苗条的身体。白雪公主住在城堡里面,过着幸福快乐的生活。白雪公主有七个好朋友,他们是七个小矮人,小矮人住在城堡附近的小森林里面,过着无忧无虑的生活。小森林里面有各种各样的动物和植物,有小松鼠、小考拉、小袋鼠、小熊猫、小鼹鼠、小河马、小企鹅等等等,还有松树、柳树、银杏树、橡树、枫树和果树。白雪公主经常和小矮人一起到小森林里面玩耍,他们在小森林里能看见美丽的草地、潺潺的小溪、美丽的彩虹,还可以看日出和日落,他们玩得非常开心。 有一天,城堡里面来了一个可怕的巫师,他把白雪公主的爸爸妈妈抓起来了,并且还给白雪公主施了一个魔咒:让白雪公主永远地睡着醒不过来,除非有一天白雪公主遇到一个真正爱着她的王子,她才能醒过来。七个小矮人把白雪公主偷偷带出了城堡,来到了小森林。那个巫师追赶着他们来到小森林,不过巫师不敢靠近小森林,因为小森林里也有小矮人的魔法,邪恶的巫师不能进入小森林。于是,这个巫师在小森林的周边也施了魔咒,让小森林看起来很可怕,这样就没有人敢靠近小森林,他要永远困住白雪公主。 小矮人们在小森林给白雪公主建了一个别墅,并且精心地照顾白雪公主,他们希望有一天白雪公主能够遇到爱着她的王子,这样她就可以醒过来了。终于有一天,有一位来着东方的英俊王子,他骑着白色的骏马来到了小森林,他叫白马王子。他很久以前就听说这里有一座美丽的小森林,所以他决定要冒一次险,去探索这个小森林。经过一番努力,白马王子进入了森林,他被小森林迷住了,这是他见过的最美丽的森林。他来到了小别墅,看见里面睡着以为美丽的姑娘,他说这是我遇到的最美丽的一位姑娘。 白马王子爱上了白雪公主,七个小矮人把白雪公主的遭遇告诉了白马王子,于是白马王子在白雪公主的额头轻轻地亲了一个吻,白雪公主醒过来了。白马王子带着白雪公主和七个小矮人回到了城堡,打败了巫师,救出了白雪公主的爸爸和妈妈。从此以后,白雪公主和白马王子过上了幸福快乐的生活。

September 20, 2018

终于考过了总分6.5

去年给自己定了一个目标,一年时间考过4个7,但到现在分数只有:听7,说5.5,读6,写7,总分6.5。这个分数还不能达到澳洲最低要求,但幸运的是,过了新西兰的最低要求,而且我们的打分足够新西兰的分数了。 爱人不想考虑新西兰,但她也不完全反对,毕竟如果真的走移民这条路,新西兰是保底选择。而我会继续考,努力达到7,最少要达到4个6.5,总分7。 这段时间,爱人通过了职业评估,而我打算在努力到年底,争取过了这个考试再做职业评估,不过在这之前找了三家公司开了推荐信和工作证明,我们的移民之剑发出去了。

August 25, 2018