xiyuan技术圈

溪源的技术博客,技术的不断进取之路


  • Home

  • 技术

  • 随笔

  • 读书

  • 管理

  • 归档

《程序员的三门课》读书随想

Posted on 2019-12-15 | Edited on 2021-04-25 | In 读书

一 回顾我的职场体会

我的职场生涯开始于十年前,一直在中小企业发展,未曾有幸到沿海那些高速发展的互联网公司工作,也就错过了互联网的大时代。

但这不影响我的正常工作生活,事实上无论你身在何处,或在哪家公司,以各种title生存,我们都是在属于自己的职场道路上奋力拼搏,为了实现自己的人生梦想,我们需要付出的代价和努力,或许并不亚于我们的父辈。

我们的父辈大部分都生于50后,60后,70后,成长于七零年代,八零年代,九零年代。他们的时代,是举国体制逐渐退潮,市场经济开始唱主角的时代,他们往往没那么多的学问,有时候得靠自己的勇气和双手才能改变自己的命运。而我们的时代,更多的得依靠自己的学问和知识领域来直面社会发展。互联网的大时代,汹涌澎湃如斯,浪花卷卷,看似卑微的小人物,同样也能在时代扮演不平凡的角色。

事实上过去十年正是中国互联网产业飞速发展最为波澜壮阔的十年,哪怕从世界层面来说,也同样如此。中国的互联网本身就比美国晚了将近十年,但是凭借过去的十年,我们取得的飞速发展让我们得以跟美国看起来不相上下。

当然,大时代的发展看似与我们大多数人关系不大,我们只是时代的见证者和受益人,而还有一些人,他们都积极的参与到其中,并为这个时代的发展起到了看似简单但也至关重要的作用。

二 价值或没价值,其实不用争执

我一贯认为围绕价值的争执毫无意义,毕竟每个人的评判标准截然不同,但不同的人大概目标是一致的,追求创造属于自己的价值,实现自己的梦想。当然,在时代的裹挟之下,大多数人都难以真正拥有自己的梦想。往往都是在本能的驱使下,选择工作,家庭,按部就班的工作,陪伴家庭逐渐的向未来前进。

但这不影响我们可以设想一下我们应该拥有的一些共识,例如使命,价值观和文化。我觉得这三者是非常重要的东西,使命驱使我们前进,价值观促使我们拥有自己的原则,而文化是我们过去受到的家庭教育,学校教育和社会教育在灵魂上的投影。这些东西某种意义来说决定了我们的货币价值。

为了提高货币价值,我们往往都得超越自我,去做一些在现在知识层面下难以实现的东西。

一个人的知识领域,往往是知道得越多,越会感觉到自己的欠缺,在刚开始的时候或许是一个小圆圈,但是随着逐渐的学习,这个圆圈也越来越大。

未知越多,潜力越大。每个人都是独一无二的个体,并在自己的舞台上努力表演,我们虽然难免需要妥协于生活,但是我们其实并不必莫名其妙的取悦于任何人。

而社会中的每个个体都看似不一样,但往往也能够互相协作,互相支撑,每个人都有自己的职业分工,但总有工作交集的存在。这就意味着看似不一样的生活或工作,总能找到一些值得复用和思考的知识领域,这就需要我们放开心胸与其他人交流,从而使自己的精神更加饱满。

三 写书和读书,是一种灵魂对话

而写博客,写书或读书大概是最好的一种方式,作者把自己的成长故事和所思所感记下来,再借助书这种载体输出,既实现了自己知识的沉淀,又能将自己的知识领域向外播撒;

读者可以花并不高的代价购买到来自于作者一手的知识分享,又能在书中寻找自己的存在,达到与作者的共鸣,这样的学习一定会让人获益非浅。

在软件研发领域的许多知识,不像我们受到的教育一般,有些东西是有明显的对错之分的,像程序员成长,架构思维或管理模式,无论是哪种方式,总能实现我们的目标。

我们中的大部分人的成长都大体一样,来源于某份工作或多份工作的自我学习,而不是靠真正的书本或教育,在社会中学习,大概如此。但是这样的东西难免有失节奏,不够系统,甚至要走特别多的弯路,吃很多亏。

有时候我们会想知道,哪里可以获得系统的学习方法呢?

四 这本书值得读的点

一本《程序员的三门课》,或许能够给你带来思考。

这本书没有试图像那些能够给我们带来直接收入的【21天学会xx技术】的书一样,能够迅速让我们迅速的学会新技术,他甚至有点像啰嗦的前辈一样,说了一些让人摸不着边际的东西。

事实上书的作者恰好是亲历了互联网大时代的一波人,有阿里巴巴的技术大佬右军老师,李伟山老师,还有彭首长老师和刘朋老师,也有年轻如张洪亮的青年才俊,他们都致力于学习和为企业创造价值,他们事实上也颇有成就。他们都经历了职场的历练,无论是996甚至007,他们都是第一批冲杀在前线的斗士。他们不仅做事雷厉风行,他们更是喜欢思考人生的意义。

他们都并非像这篇文章一样喜欢说啰嗦的话,他们把自己过去若干年的思考汇集在这本书中,目标是渴望给读者带来真正的收获。

当你刚参加工作时,需要快速入门的书给你带来顿悟,但一旦稍微稳定下来,一定得站在更高的视角来规划一下自己的未来。编程技术,你可以快速的提升,而掌握这本书中的某些部分,你将有希望看破迷雾,不至于在职场面前过于迷茫。这些从工作中出发,提取自技术、思维模式和管理方法不同层面的知识,每一种都很有思考的意义。

当然,看完这本书你甚至需要看更多的书,因为这本书他虽然凝淬了许多书的精华,但也是来源于本书作者对于知识的提炼,或许与原作者的原意稍有差别。在读完这本书之后,你或许将拥有一把去开启更多知识领域的钥匙。

一本经典,往往能让你产生无尽思考;而一本好书,则会让你看破一些道理,甚至会觉得,原来这些其实就是这么回事啊。

越是看起来简单的道理,越是需要花心思去揣摩才能体会。就像许多看似简单的技术实现,没有亲身经历的,都是“二手知识”。网上有许多的学习资料,尤其是当我们打开某些信息流app时,其实那是你的“信息茧房”,每天阅读这些内容,你会以为技术的获得是多么的轻易,但只有手把手写过一波,才能真正获得价值。而阿里巴巴和众多互联网公司们,花了十年时间做了那么多东西,一定是走了弯路,踩了许多坑才最终获得了最佳实践,而这些在这本书里都有所介绍。

例如,如果你想在组织中建设一套质量管理体系,书中花了不少章节介绍了代码审查的方式和工具,以及代码审查清单的五个大方向和十六个小方向,这些能够从代码层面建立第一道防线;接着可以从架构体系做好第二层防线,例如分析架构质量的问题来源和解决策略,以及实现流程。这些几乎都是拿来就能应用的良好策略。

对于程序员的快速成长,作者们都深有体会,例如积极主动的应对困难,以空杯的形态去看待学习,以及别怕犯错,这些都是良好的习惯,尤其要掌握学习方法,打破舒适区和终身成长,能够让我们更快的成长。

如果初涉管理,作者们也介绍了他们的许多感受,包括做好准备,抓住机会,构建领导力,和高效的时间管理。尤其是时间管理,为什么同样都是996,作者们却不仅把代码写得很完美,还能有时间写那么多博客呢。团队培养,看起来简单却不简单,书里面也提到了许多措施。

五 总结

一本好书,能够给你带来一点思考,就已经足够了,如果让你获得了超过一点思考,那就是赚大了。

冷静的阅读一下,你会有不一样的收获。这些都是你自己的收获,更是属于你自己的无穷财富。

李文强先生的《容器入门教程》推荐序

Posted on 2019-12-11 | Edited on 2021-04-25 | In 随笔

推荐序

容器技术,大概是最近几年最为流行的一种技术。这种技术打破了原来用虚拟机部署软件对硬件环境和条件的限制,让软件的逻辑边界获得了更大程度的扩展。只要是一台能够安装Linux的个人PC机、服务器、甚至是小巧玲珑的树莓派,都可以非常轻松的安装容器,实现了硬件资源的最大化利用。这也让微服务技术得以更好的落地,更加便捷、高效的实现企业生产效率的提升。

然而,虽然容器技术越来越流行、虽然网上的资料很多,但是往往多而杂乱,让人看得眼花缭乱。而且许多资料看起来能够有用,实际上大部分资料都是重复而错误的,许多文章都是从其他网站上生搬硬套、拷贝或者甚至直接抄过来的。这也导致了许多开发者虽然想真正学习容器技术,却还得自己一点点摸着石子过河,踩很多的坑。事实上借助于搜索引擎往往看似会给我们带来许多便利,也会让人产生摸不着头脑。缺乏靠谱的资料支持,缺乏系统的学习方法,缺乏深入浅出的过程描述,这大概是面向搜索引擎学习的开发者们最大的困扰。

在这个背景下,这本书应运而生。作者李文强是我们长沙互联网社区的一位开发者,而且也是一位创业者,平时工作很繁忙,但是却依然对技术充满了持续的学习精神。他从容器刚刚兴起就跟进技术,并灵活的将容器技术和kubernetes(k8s)技术运用到企业的实际项目中,获得了非常不错的效果。基于容器技术和k8s技术的完美结合,让公司的产品开发流程实现了足够细粒度的服务划分,然后再配上一键发布、所见即所得的持续交付流程,让他的企业能够快速适应客户需求和市场的变化,为企业的业绩腾飞带来了不少助力。

这本书的每个案例都是作者悉心收集整理、书中的每个步骤作者都认真的尝试了好几遍,与步骤有关的每个截图都力求真实,可以是说精心打磨的上佳作品。他平时观察也很仔细,把在工作中踩过的每个坑都认真的记下来,并以博客的形式发布,获得了大家的一致好评。这几年来他在博客和公众号发表相关主题的帖子已经不下百篇,惠及数万开发者,事实上我也正是通过他的博客认识了他。这本书也是李文强先生在实践过程中的所思所感的汇聚,通过这本书,我们也还可以学习到如何科学有效的掌握新技术的方法。

总之这是一本非常适合初学者入门容器和k8s的书,不管你是在校大学生、还是对容器和运维技术感兴趣的从业者,您都应该拥有这本书。它不仅能手把手指引你的学习,更能让你赢在起跑线上,为你的幸福生活添砖加瓦。

某软件技术有限公司研发总监-邹锭

复盘2019年,我花了3个月时间备考PMP

Posted on 2019-12-09 | Edited on 2021-04-25 | In 随笔

引子​

​ 经过几个月的准备,终于在2019年12月7日完成了PMP的考试,并于今天查到了成绩,总结这次考试的具体情况:涉及题型虽然都没有超出大纲的范围,但是原题出现的概率似乎不高,还有一些原来未曾见过的题目,例如矩阵型组织或弱矩阵型组织等,以及造一个能够能飞三米的纸飞机,存在5%的废品,该如何处理,这样的题目让人有点摸不着头脑,还有一些原题,虽然是模拟题上的题目,但是。。我居然到了考试的时候居然忘记答案了,这有点过于尴尬。

为什么考PMP

​ 回顾职场,我是在参加工作的第二年成为项目经理的,当时还是啥都不同的毛头小伙,就被公司指派担任一个十几万小项目的项目经理,并和两位老鸟一起共同参与项目的研发,每天都出入XX勘测设计院的大门之中,基本上都认识了这些勘测院的机关工作人员,还好这个项目本身技术并不复杂,加上有足够的资源和不急的时间需求,做出的成果也符合了甲方的需求,所以这个项目总体上处理的还算不错;

​ 随后又参加了另外一个几十万的小项目,并在其中担任项目经理和技术负责人,由于有了一位资深工程师、一位资深从业者(虽然对编程技术不够了解,但是沟通能力很强)所以这个项目也能如鱼得水。

​ 再后来同时带了两个项目,一个是XXX规划局的XX信息平台,一个是地下管线系统,同时带两个项目的压力确实很大,而且公司的技术水平其实并不好,这两个都是研发型项目,作为一个开发出生的我,难免很难同时兼顾两个项目,加上地下管线系统其实是有老鸟参与研发设计,而我基本上只用跟需求,而空间信息平台则是我带一些没有工作经验的新手,所以我对于管线系统也就没太放在心上,精力也就全部放在空间信息平台上,所以当项目结项时,虽然两个项目都完成了,但是差别却特别大,空间信息平台广受赞誉,为后来接下数百万的合同奠定了基础,而地下管线系统(其实合同额更高)中的老程序员们却由于被过度放权,反而疏于管理,虽然软件做出来了,但是却没能派上用场,到后来被尘封,只能成为一个经费项目。

​ 再后来,公司内部组织结构发生了变更,我也进入了一个的高光时期,被选为部门的项目主管,同时兼顾多个项目,负责管理了超过20位项目团队成员,管了3个项目经理。当时的我一度以为是自己的优秀打动了领导,其实是因为公司确实是没人了,才让我临时暂代,然而我还以此为骄傲,最终什么事情都没搞好。

​ 后来就从这家公司离职,开始了新的职场过程,前前后后也陆陆续续带了不少项目,有大有小,成功或失败,也或多或少有一些。总体上来评价,差强人意,虽然试图做好项目,但是却总感觉阻塞颇多,无论是人员上的,还是技术上,或者沟通上的,总觉得没有特别完美。尤其是做互联网项目时,花了许多时间去打磨产品,却依然没能做出令人眼前一亮的东西,固然与产品有一定的关系,其实也与未能管理领导的预期有更大的关系。

​ 确实如此,一个成功的项目,首先要管好客户的预期,其次得做好资源的调配。真正好的项目经理,一定是那些看起来很闲的项目经理,因为他们把什么事情都能很好的规划,只是做好任务分配、任务审查、和任务总结以及汇报就够了,而像过去的我那样的渣项目经理,不仅事无巨细、连代码要管,衣食住行要管,还让大家累死累活下来也根本没赚到多少钱。

​ 在IT领域,不仅软件开发有德雷福斯的能力成熟度模型,连项目经理也同样具备,同样必须经过一万小时,经过从新手到高级新手,到胜任者,精通者,到专家的蜕变,而这个过程,要么必须吃了很多亏(意味着要花费公司大量的人力物力财力来培养),要么就是能够真正自发成为专业的项目管理者。

​ 事实上专业的项目管理者比开发者或许更困难,在我从业的这十年中,也遇到了个别优秀的项目经理,他们善于运用领导力的强大魄力,在项目各方间游刃有余,而更多的项目经理,都像我一样,运用程序员的沟通技巧,与各方沟通,往往会吃尽苦头。

​ 技术出生的管理者,往往都具备类似的毛病:例如过度在意过程和实现;忽略沟通的力量;渴望全局掌控;缺乏领导艺术;缺乏政治敏感度;藐视人情世故等。好吧,在后来的项目过程中,我已经逐步掌握了沟通、政治敏感度和人情世故这样的法宝,并通过这种手段获得过各方的认同,但是还是或多或少在乎细节、在乎流程的完备性,反而忽略了对于客户预期的把控,最终依然造出了几个不太成果的项目。

​ 一个人的成长,大概就是得经历从失败的挫折、吸取教训、逐渐成长的过程,无论是哪个岗位都大体类似。优秀的项目管理能力一定是开发者的必备基础技能,唯有灵活的掌握项目管理技能的多个方面,才能让软件项目能够高效、快速的契合各方的需求,实现组织从一种状态到另外一种状态。

​ 如果说以前带的项目,基本上已经到了胜任者的层级,那么大概这种层级,其实是自封的,如何来真正证明自己具备\胜任相关岗位呢,我觉得大概需要一个纸质证明了。这就是我打算考PMP的原因。

为什么选择培训班

​ 不过考PMP有很多种方式,而且PMP本身也不是一种特别困难的资格证,在我的身边已经有许多人考了PMP,并获得了证书,甚至有许多人拿到了5A证书,例如我参加的培训班,5A率已经超过70%了。

​ 而在国内,每种证书最常见的质疑是,考这个有用么?我倒是觉得,有没有用先不管,至少学到知识的过程就一定值得花这点钱。知识的价值,也并非那些可以用直接卖多少钱来衡量,他其实是一点一滴深入你的骨肉,并最终构成你的灵魂,并且在需要体现价值的时候,一点一点的凸显出来。

​ 除此之外,我也感觉虽然考试范围就是在PMBOOK这本书,而且只考前538页,但是书本上有太多内容了,每一个点都能够写出许多许多的故事出来,甚至而言,把五大过程,四十九过程组中,任意抽出一个过程组出来专精,都可以成为一个称职的专家,所以纯粹看书其实并不能提高自己对于项目管理技能的领悟力,而那些能够给我们提供培训的老师,他们往往首先是真正优秀的项目经理。其次不仅对项目管理这一本砖头书要烂熟于心,也需要能够用自己的语言把枯燥无味、干涩的知识讲出花来,这更需要本事。

​ 再加上项目管理这种管理体系,其实更是一种团队技能,靠自己看书,往往找不到重点,而借助于培训机构,反而能够跟其他具有相同爱好的人一起学习,也算是一段不错的过程。

​ 选择现代卓越面授班对我来说确实是个非常明智的决定,因为面授班确实是这样的好地方,大家一起讨论项目管理方面的问题,着实是一种不错的体验。

通过培训获得的收获

​ 近年来随着离软件公司越来越远,离各种行业软件越来越近,觉得自己的项目管理能力的某些方面诸如沟通表达能力和领导力有所提升,但是对于项目管理过层中的计划管理能力反而已经越来越差了。毕竟原来一直从事IT技术研发+项目管理,对于时间的计划安排,无外乎就是按照自己的经验去套、或者借助于模仿,这是初学者的典型惯例。

​ 除此之外,在项目中,虽然用到了瀑布模型这种预测性生命周期来管理项目,但是又接触到许多敏捷的项目管理方法,所以技能点反而不纯粹了,总结就是,什么都懂一点,却什么都只懂一点,所以专业级项目经理是如何做项目的?这确实是一个值得仔细讨论的问题。而这也是参加培训最大的收获。

​ 总结一下可以为我未来做项目提供指导的一些点:

1、需求的重要-紧急矩阵:评估需求时,先把重要紧急矩阵画好,然后再来指导工作。以前难道不知道么,确实没这么系统的学习这套理论吧。

2、权力-利益方格、相关方认知模型、相关方参与度评估矩阵:

3、能力-欲望矩阵:有能力有欲望、有能力没欲望、没能力有欲望、没能力没欲望,你在哪个象限?值得深思。

4、成本管理:老板的钱来之不易,成本管理得做好。

6、三大管理学原理:彼得原理、帕金森定律和墨菲定律,大概可以好好讲一天。

7、如何做好团队激励和团队建设:哪些是保健因素,哪些是激励因素,如何打造一支优秀的团队?知易行难啊。

9、风险责任矩阵RBS:提前做好风险评估和责任人分配,让风险防范于未然很有必要。

10、问题日志、经验教训登记册、风险登记册和营造积极分享的氛围。

11、会议管理:罗伯特议事规则。开会太长确实需要规则。

12、关键链法:盲目的设定项目工作包或活动其实没什么意义,倒不如先做好关键链,然后再逐步的实现里程碑,只要关键链做好了,往往也离项目做完不远了。毕竟一个项目是花有限的资源做有限的事,而不是无穷尽的盲目的投入。

13、挣值分析技术:虽然挣值分析技术是一种数学评估方法,看起来有点不太精准,但是将这种技术高效的运用到项目中,也许会给项目管理带来不少便利。

14、责任分解矩阵:做好工作分解和责任分解固然重要,更要给责任人指派明确的责任,而不是口头上的任命,做到有根有据,有考核指标和评价依据非常重要。

15、塔克曼团队发展阶段理论:一个团队的成长早期,往往是相互独立、甚至互相提防的,只有互相磨合,经历开诚布公,才能打造成熟稳定的团队。

16、TEAM团队理论:Today Everyone Achive More。没有完美的个人,只有完美的团队。团队并非一个人、而是大家彼此拿出自己最擅长的方面,共同打造一个完美的群体。

17、冲突管理:团队中适度的沟通反而能够促进团队关系的更加融洽。而没有冲突的团队往往是一滩死水,有了冲突,各方才能更好的理解对方的思维模式和思考方式,进而促进团队的进一步完善。

18、沟通的漏斗效应:是沟通就一定会衰减,但是如何让衰减尽可能的减小、控制在一定的范围呢。这大概需要更加重视沟通相关方的影响力。

​ 当然,实际上还有更多内容,只是以上几点特别熟悉,整个PMP的考试过程确实给我带来了不少启发,我也希望以后能够逐步的把pmp中学到的一些知识应用到项目和团队管理中,并渴望能够带来效率上的提升。

总结

​ 好吧, 说那么多,我尽力了,是真的尽力了么,我完全还可以更努力啊。

​ 当然,深受帕金森定律的影响,能够提前学的东西,到最后一天才学,不过庆幸自己的努力没有白费,相信一份付出,总有一份回报。

浅议gRPC的数据传输机制和WCF中的回调如何迁移到gRPC

Posted on 2019-12-01 | Edited on 2021-04-25 | In 技术

浅议Grpc的双向流和WCF中的回调机制

一、引子

如您所知,gRPC是目前比较常见的rpc框架,可以方便的作为服务与服务之间的通信基础设施,为构建微服务体系提供非常强有力的支持。

而基于.NET Core的gRPC.NET 组件截至2019年11月30日的最新版本为2.25.0,该版本基于.netstrandard2.1进行,能够在.NET Core3.0上非常方便的实现,而且还能方便的迁移到基于.NET Core的windows桌面端开发体系。

在本文中参考微软官方文档的示例,实现了一个从WCF 服务回调机制迁移到gRPC的过程,由于时间仓促,如有疏漏,还望批评指正。第一篇主要从技术层面来分析迁移流程,第二篇打算从业务和代码整洁性角度来思考这个问题。

1.1、一些新东西:

1)、使用客户端工厂组件 Grpc.Net.ClientFactory :

在新版本中,可以使用 Grpc.Net.ClientFactory 支持以依赖注入的形式AddGrpcClient,将grpc客户端引入中,而无需每一次方法调用都使用 New 关键词进行创建。 这对客户端调用来说是极大的方便,毕竟随着.NET Core的普及,对于许多开发者来说,看到 New 关键词其实是很难受的啊。

示例:

以下代码以注册了 GreetClient ,并在发送 http 请求前,对请求头信息进行修改,添加 jwt 标识,以便发送带鉴权标识的请求。

serviceCollection.AddGrpcClient<GreeterClient>(
    o =>
    {
    o.Address = new Uri(configuration["address"]);
    })
    .AddHttpMessageHandler<JwtTokenHeader>();
1
2
3
4
5
6
7
8
9
public class GreetImpl
{

private readonly GreetClient _greetClient;
public GreetImpl(GreetClient greetClient)
{

}
}

JwtTokenHeader中的代码段:

1
2
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "");
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

(以上示例代码仅供参考,不支持直接运行,且不支持.NET Framework。。)

所以到此为止,我们在使用gRPC开发时,需要(能)使用的组件包括以下几种:

  • Grpc.AspNETCore包:这个包用于在asp.net core中提供grpc服务支持,在asp.netcore的服务端项目中以nuget安装grpc组件时,需要安装这个包。
    • Google.Protobuf组件:Protobuf协议的实现。
    • Grpc.AspNetCore.Server :gRPC Asp.NET Core服务端核心库
    • Grpc.Core.Api :gRPC Core API核心库
  • Grpc.Tools 包:内部封装了从proto文件生成gRPC服务端/客户端方法存根的流程。
  • Grpc.Core:gRPC核心包。
  • Grpc.Net.Client:gRPC 客户端实现核心库。
    • Grpc.Core.Api :gRPC Core API核心库
    • Grpc.Net.Common:gRPC 常用方法。
  • Grpc.Net.ClientFactory: gRPC客户端工厂方法。仅用于标准库2.1。
2)、其他特性:
  1. 支持 SerializationContext.GetBufferWriter 。
  2. 性能优化。 Optimize server’s gRPC message serialization
  3. 验证协议降级。 Validate gRPC response protocol is not downgraded
  4. New Grpc.AspNetCore.Server.Reflection package
  5. Log unsupported request content-type and protocol
  6. Major client performance improvement
  7. 修bug等。

( 当然,由于各种原因,未能亲测。)

1.2、存在的缺陷

  • 目前的grpc的定位仅仅是一种数据传输机制,因此本身不包含负载均衡和服务管理的功能,一般会引入consul/etcd/zk等框架来实现服务治理。

  • 由于最新版本基于标准库2.1进行构建,因此该最新版本无法在.net fx上使用(因为.netframework最高仅支持到标准库2.0),不过只是新版本不支持,依然可以使用2.23.2的版本来实现。当然,以后也不会支持.netfx了。。

二、gRPC通信方式

gRPC提供了以下四种传输方式:

查看

2.1、Simple RPC

简单RPC 传输。一般的rpc方法调用,一次请求返回一个对象。适用于类似于以前的webapi请求调用的形式。

1
rpc Hello (HelloRequest) returns (HelloReply);

2.1、Server-side streaming RPC

一种单向流,服务端流式RPC,客户端向服务端请求后,由服务端以流的形式返回多个结果。例如可以用于客户端需要从服务端获取流媒体文件。

1
rpc Subscribe (SubscribeRequest) returns (stream StockTickerUpdate);

2.3、Client-Side streaming RPC

一种单向流,客户端单向流,客户端以流的形式传输多个请求,服务端返回一个响应结果。例如可以用于客户端需要向服务端推流的场景。

1
rpc Subscribe (stream SubscribeRequest) returns (StockTickerUpdate);

2.4、 Bidirectional streaming RPC

双向流式rpc。客户端和服务端均可以传输多个请求。例如可以用于游戏中的双向传输。

1
rpc Subscribe (stream SubscribeRequest) returns (stream StockTickerUpdate);

总之,看起来gRPC能够实现目前所能设想的大部分场景,因此也被视为是古老的rpc框架 wcf ( Windows Communication Foundation )的替代者,官方专门编写了一本电子书,用来给需要从 wcf 转 gRPC的开发者提供指引。

具体地址为: https://docs.microsoft.com/zh-cn/dotnet/architecture/grpc-for-wcf-developers/

除此之外,本人还看到了一些外网作者使用grpc 来移植 wcf的一些博客。

1、 https://www.seeleycoder.com/blog/migrating-wcf-to-grpc-netcore/

2、https://www.seeleycoder.com/blog/using-wcf-with-dotnetcore/

这两篇博客的作者在.NET Core中使用了WCF,根据作者的说法,在.NET Core2.0中还能使用,但是随着3.0的发布,他已经不再使用WCF了,而是改用了gRPC。

三、WCF的通信方式

3.1、简述

WCF 是.NET框架中非常常用的一种组件,在.NET Framework 3.0时被引入,它整合了一些历史悠久的技术框架或通信机制,诸如 soap、remoting等。

由于WCF技术体系庞大,学习路线也比较陡峭,能够驾驭的往往都是拥有多年工作经验的资深开发者,开发者们有时需针对各个阶段的内涵做深入的了解,才能开发对应的应用。

由于本人使用WCF的经验尚浅(以前的项目用得少,充其量就用过Remoting),所以以下文字均来自网上现有资料的演绎,如有疏漏,敬请批评指正。

WCF中,需要定义合约作为通信过程中的沟通方式。通信双方所遵循的通信方式,有合约绑定来制定;通信期间的安全性,有双方约定的安全性层级来定义。

3.2、合约(Contract)

合约( Contract) 是WCF中最重要的基本概念,合约的使用分成两个部分,一部分是以接口形式体现的合约,一部分是基于合约派生出的实现类。

合约分成四种类型:

数据合约 (Data Contract) :订定双方沟通时的数据格式。

服务合约 (Service Contract) :订定服务的定义。

操作合约 (Operation Contract) :订定服务提供的方法。在维基百科中翻译为营运合约。

消息合约 (Message Contract) :订定在通信期间改写消息内容的规范。

在维基百科中,提供了一个如下的代码示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using System.ServiceModel;
namespace Microsoft.ServiceModel.Samples
{
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")] // 服务合约
public interface ICalculator
{
[OperationContract] // 操作合约
double Add(double n1, double n2);
[OperationContract] // 操作合约
double Subtract(double n1, double n2);
[OperationContract] // 操作合约
double Multiply(double n1, double n2);
[OperationContract] // 操作合约
double Divide(double n1, double n2);
}
}

3.3、协议绑定

WCF支持HTTP\TCP\命名管道( Named Pipe )、MSMQ( MSMQ )、点对点TCP Peer-To-Peer TCP 等协议。其中对HTTP协议的支持分为:基本HTTP支持\WS-HTTP支持;对TCP的协议也支NetTcpBinding\NetPeerTcpBinding等通信方式。

从这里可以看出,能够驾驭WCF技术的,基本上都是.NET开发领域的大牛,涉及到如此多的技术栈,实在是令人钦佩。

由于WCF支持的协议很多,所以在进行WCF的客户端和服务端开发时,需要使用统一通信的协议,并且在编码以及格式上也要一致。

维基百科提供了一个设置通信绑定的示例配置文件,当然,有时候无需通过配置文件来配置wcf的服务信息,通过代码创建也同样可行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<configuration>
<system.serviceModel>
<!-- 接口协议 -->
<services>
<service name=" CalculatorService" >
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding1"
contract="ICalculator" />
</service>
</services>
<!-- 通信机制 -->
<bindings>
<wsHttpBinding>
<binding name="Binding1">
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
</configuration>

4、代码迁移

4.1 迁移WCF的单工通信

在WCF中,一般默认的契约形式为点对点的请求-响应方式。即客户端发出请求后,一直阻塞方法,指导服务端响应后,才能执行后面的代码。

这种模式类似于gRPC中的简单传输机制,所以如果从WCF服务迁移到gRPC服务时,比较简单纯粹,只需根据对应的数据方法来订定我们的服务协议文件 proto 文件。

例如,大概是这样的:

1
2
3
4
5
6
[ServiceContract]
public interface ISimpleStockTickerCallback
{
[OperationContract]
void HelloWorld(string msg);
}

迁移到 gRpc中之后,就是这样的实现:

1
2
3
4
5
6
7
rpc Hello (HelloRequest) returns (google.protobuf.Empty);
message HelloReply{
string msg=1;
}
message HelloRequest{
string msg=1;
}

然后再在两端代码中实现方法即可。(由于代码过于简单,此处省略若干字)在引文3中,提供了非常完善的Wcf迁移到gRPC的代码流程,需要请自取。

4.2 迁移WCF的双工通信

1、WCF中的双工通信示例

在WCF中,双工(Duplex)通信很常用,在通信过程中,双方都可以向对方发送消息,使得很容易的就实现了服务端回调客户端。

在这种模式下,客户端向服务端调用一个方法,然后在服务端回调客户端方法,可以理解为双方的位置发生了改变,此时的服务端变成了客户端,而客户端变成了服务端。

如图所示。

  • image-20191130140814321

代码如下:

  1. 服务端:

    • 订定契约HelloCallback,用于处理回调的逻辑。
    • 订定契约UserService 和 UserServiceImpl,并定义了一个 GetUser 方法。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    /// <summary>
    /// 用于回调的Hello方法
    /// </summary>
    [ServiceContract]
    public interface HelloCallback
    {
    [OperationContract(IsOneWay = true)]
    void SayHelloworld(string msg);
    }
    /// <summary>
    /// 用户服务,并回调客户端到HelloCallback
    /// </summary>
    [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(HelloCallback))]
    public interface UserService
    {
    [OperationContract(IsOneWay = true)]
    void GetUser(string userName);
    }
    /// <summary>
    /// 用户服务
    /// </summary>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class UserServiceImpl : UserService
    {
    HelloCallback callback;
    public void GetUser(string userName)
    {
    Console.Write(userName);
    OperationContext context = OperationContext.Current;
    callback = context.GetCallbackChannel<HelloCallback>();
    callback.SayHelloworld($"{userName}:hello");
    }
    }

    启动服务端程序时,需要创建服务端的Host主机信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     private static ServiceHost StartUserService()
    {
    var host = new ServiceHost(typeof(UserServiceImpl));
    var binding = new NetTcpBinding(SecurityMode.None);
    host.AddServiceEndpoint(typeof(UserService), binding,
    "net.tcp://localhost:12384/userservice");

    host.Open();
    return host;
    }
  2. 客户端:

    • 订定契约HelloCallback 和客户端的契约实现 HelloCallbackImpl 。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      /// <summary>
      /// 回调Hello方法
      /// </summary>
      [ServiceContract]
      public interface HelloCallback
      {
      [OperationContract(IsOneWay = true)]
      void SayHelloworld(string msg);
      }
      public class HelloCallbackImpl : HelloCallback
      {
      public void SayHelloworld(string msg)
      {
      Console.Write(msg);
      }
      }
  • 订定契约UserService,用以保持和服务端的契约保持一致。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    /// <summary>
    /// 用户服务
    /// </summary>
    [ServiceContract(CallbackContract = typeof(HelloCallback))]
    public interface UserService
    {
    [OperationContract(IsOneWay = true)]
    void GetUser(string userName);
    }

    客户端启动时,连接到服务端。并发送GetUser方法。

1
2
3
4
5
6
7
8
9
10
11
private static void GetUser(NetTcpBinding binding)
{
var address = new EndpointAddress("net.tcp://localhost:12384/userservice");
var factory =
new DuplexChannelFactory<UserService>(typeof(HelloCallbackImpl), binding,
address);
var context = new InstanceContext(new HelloCallbackImpl());
var server = factory.CreateChannel(context);

server.GetUser("zhangssan");
}

实现效果如下:

image-20191130144237825

这是一个典型的WCF双工通信的示例,在传统的.NET Framework开发中可能非常常见,但是该如何才能迁移到gRPC服务中呢?

2、gRPC中的代码实现

  • 流程说明

gRPC中实现此双工通信,需要使用来自服务端的单向流来实现,但在gRPC中不能直接回调对应的方法,而是在服务端将流返回后,触发对应客户端代码中的方法来实现这个回调的流程。

如图所示:

image-20191130214340416

  • 代码实现流程:

    1、定义 proto 协议文件

    请求方法为getUser,并返回流。首先定义服务协议文件,命名为 userService.proto 文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    syntax = "proto3";

    option csharp_namespace = "DulpexGrpcDemo";

    package DulpexGrpcDemo;

    service userService {
    rpc GetUser (HelloRequest) returns (stream HelloReply);
    rpc GetTest (HelloRequest) returns (HelloReply);
    }
    message HelloReply{
    string msg=1;
    }
    message HelloRequest{
    string msg=1;
    }

    2、服务端实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class UserServiceImpl : userService.userServiceBase
{
public override async Task GetUser(HelloRequest request, IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
{
await DoSomeThing(request.Msg, (msg) => { responseStream.WriteAsync(new HelloReply { Msg = $"{msg}:hello" }); });

}
//处理回调逻辑
private async Task DoSomeThing(string msg, Action<string> action)
{
Console.WriteLine(msg);
action?.Invoke(msg);
}
public override Task<HelloReply> GetTest(HelloRequest request, ServerCallContext context)
{
Console.WriteLine(request.Msg);
return Task.FromResult(new HelloReply { Msg = $"{request.Msg}:hello" });
}
}
3、客户端实现(需要被调用的方法)
1
2
3
4
5
6
7
8
9
10
11
public interface HelloCallback
{
void SayHelloworld(string msg);
}
public class HelloCallbackImpl : HelloCallback
{
public void SayHelloworld(string msg)
{
Console.Write(msg);
}
}

4、用户服务方法的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class UserServiceImpl
{
private userService.userServiceClient userServiceClient;
private readonly HelloCallback _helloCallback;

public UserServiceImpl(userService.userServiceClient serviceClient, HelloCallback helloCallback)
{
userServiceClient = serviceClient;
_helloCallback = helloCallback;
}
public async Task GetUser()
{
AsyncServerStreamingCall<HelloReply> stream = userServiceClient.GetUser(new HelloRequest { Msg = "张三" });
await Helloworld(stream.ResponseStream);
}
async Task Helloworld(IAsyncStreamReader<HelloReply> stream)
{
await foreach (var update in stream.ReadAllAsync())
{
_helloCallback.SayHelloworld(update.Msg);
}
}
}

5、客户端程序的入口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Program
{
static async Task Main(string[] args)
{
IServiceCollection servicesCollection = new ServiceCollection();
IConfiguration configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json", true, false).Build();

servicesCollection.AddGrpcClient<userService.userServiceClient>(
o =>
{
o.Address = new Uri("https://localhost:5001");
});
servicesCollection.AddSingleton<UserServiceImpl>();
servicesCollection.AddSingleton<HelloCallback, HelloCallbackImpl>();
var userServiceImpl = servicesCollection.BuildServiceProvider().GetService<UserServiceImpl>();
await userServiceImpl.GetUser();
Console.ReadLine();
}

}

当然,从这个示例中,可能会觉得有点奇怪,明明可以使用请求-响应的简单RPC模式,为什么要使用服务端的单向流来实现了?

这种单向流中,客户端无需等待服务端执行方法执行完,而是由服务端完成后续流程后,再回调客户端的方法,使得流程变得简单清晰。

在微软的官方文档(参考文献1)更适合介绍这个迁移过程的单向流的实现,通过实现服务端向客户端推流的形式来介绍,只是方法相对而言实现的逻辑比较多,而鄙人这个示例则剥离了与让我们理解服务端单向流流程无关的部分,使得流程看起来更简单。

参考文献

[1] 官方文档: https://docs.microsoft.com/zh-cn/dotnet/architecture/grpc-for-wcf-developers/migrate-duplex-services

[2] Jon Seeley的官方博客,如何迁移将wcf服务迁移到grpc:https://www.seeleycoder.com/blog/migrating-wcf-to-grpc-netcore/

[3] Jon Seeley的官方博客,如何在.netcore中使用wcf:https://www.seeleycoder.com/blog/using-wcf-with-dotnetcore/

在.NET Core/Framework中使用依赖注入框架

Posted on 2019-12-01 | Edited on 2021-04-25 | In 技术

在.NET Core/Framework中使用依赖注入框架

综述

在传统的.NET Framework中通常会使用 new 关键词和静态对象或静态方法作为对象创建的形式,但是由于这两种方式存在以下缺陷:

使用New的方式创建对象的缺陷:

1、使用New的方式创建的对象,需要在由GC在不同的位置分别管理生命周期。
2、如果在不同的方法中需要创建相同的对象,往往需要用很多个new来进行管理。
3、当一个对象有多个子类时,创建的过程更加麻烦。

使用静态变量的缺陷。

1、静态变量的内存空间是应用程序启动时创建、并在程序消亡时统一释放。
2、在高并发场景下,静态变量容易被不同的线程频繁读写,从而成为系统的主要性能瓶颈。

为啥要使用依赖注入

在.NET Core或.NET FX中目前已经倾向于使用依赖注入框架来对对象的创建过程进行统一管理,这样的好处:
1、封装了对象的创建过程,可以实现对象创建过程和内存管理过程的一致性,
2、如果一个对象有多个实现,也容易使用依赖注入对象对其进行拆分。
3、提供统一的对象生命周期管理。

依赖注入的生命周期

目前在.NET Core(.NET FX也有)中提供了3种依赖注入的生命周期,分别是:
1、单例的生命周期SingleTon。每次从同根容器中(同根 IServiceProvider)获取的时候都是同一个实例,类似于静态变量。主要用来存储系统中需要保持唯一一份的对象
2、瞬时的生命周期Transient。每次从容器 (IServiceProvider)中获取的时候都是一个新的实例,可以用于 控制台程序。
3、作用域的生命周期Scoped。每次从同一个容器中获取的实例是相同的。往往用于ASP.NET Core 网站。
使用依赖注入的方式实现对象的创建虽然会给程序带来一点不便利,但是容易实现程序的耦合度降低,更有利于程序未来的横向扩展,也逐渐成为ASP.NET开发(不仅仅是.NET Core)的的一种最佳实践。

依赖注入的使用

目前.NET中的依赖注入组件是基于.NET Strandard(标准库)进行开发的无其他依赖项的组件,能够被基于标准库的各种.NET技术方案所实现。
主要分为两个步骤,
1:初始化时,将对象注册到依赖注入组件中;例如:

1
serviceCollection.AddScoped<DBContext>();

2:对象使用时,从依赖注入组件中取出对象。

1
var dbContext = MyServiceProvider.GetService<DBContext>();

从依赖注入组件中取出对象的过程,往往会伴随着对象创建的过程,即在依赖注入框架内部,封装了原来与 New 一致的流程。

如果一个对象如果需要引用的对象已经被注册到依赖注入组件中,则无需使用 GetService 方法从依赖注入组件中取出对象,依赖注入框架在创建对象时,也会连带着将其他与之相关的对象一起创建。

示例

例如:
1、在示例代码中,设置 DBContext 为 Scoped

1
serviceCollection.AddScoped<DBContext>();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
static ServiceProvider MyServiceProvider;
static void Main(string[] args)
{
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.UseDBContext();
serviceCollection.UseDBService();
serviceCollection.UseAppService();
MyServiceProvider = serviceCollection.BuildServiceProvider();
var dbContext = MyServiceProvider.GetService<DBContext>();
dbContext.DBConfig = "127.0.0.1";
TestSingleTon();
TestTransient();
Console.ReadKey();
}
static void TestSingleTon()
{
for (int i = 0; i < 5; i++)
{
var task = new Task(() =>
{
var dbService = MyServiceProvider.GetService<UserDbService>();
Console.WriteLine(dbService.GetDBConfig());
Console.WriteLine("设置用户名为张三");
dbService.UserName = "张三" + i;
});
task.Wait(100);
task.Start();
}
}
static void TestTransient()
{

for (int i = 0; i < 5; i++)
{
var task = new Task(() =>
{
var userAppService = MyServiceProvider.GetService<UserAppService>();
Console.WriteLine($"获取数据库中的用户名:{userAppService.GetDBUserName()}");
});
task.Wait(200);
task.Start();
}
}

那么在创建 UserDbService 对象时,依赖注入框架会自动创建dbContext对象,并将其注入到 UserDbService中。

1
public UserDbService(DBContext dBContext)

这样就封装了原来的

1
IUserDBService dbService=new UserDBService(new DBContext());

的代码过程,弥补了调用者需要与UserDBService 高度耦合的缺陷。

值得注意的是:

1、在.NET Core(.NET Framework) 控制台中,需要手动创建对象IServiceCollection,并创建一个静态的 ServiceProvider 对象,由这个对象来实现对象的加载。
2、在.NET Core 网站项目中,由WebHost管理的生命周期,会创建一个统一的 IServiceCollection和 ServiceProvider 对象,无需再单独创建这个ServiceProvider.

示例代码

在示例代码中,提供了一个DIExtension的静态类,并定义了三个注册对象的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static IServiceCollection UseDBContext(this IServiceCollection serviceCollection)
{
serviceCollection.AddScoped<DBContext>();
return serviceCollection;
}
public static IServiceCollection UseDBService(this IServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<UserDbService>();
return serviceCollection;
}
public static IServiceCollection UseAppService(this IServiceCollection serviceCollection)
{
serviceCollection.AddTransient<UserAppService>();
return serviceCollection;
}

网易事件,芸芸众生,相煎何急

Posted on 2019-12-01 | Edited on 2021-04-25 | In 随笔

十一月初拖家带口去了上海,到了著名的城隍庙参观,无意中看到了一个仅出现在历史书上的古老物件“西洋镜”,仿佛跨越百年,来到那个如裹脚布般冗长而乏味的古老年代,看到了一群有一群卑微的小民在生活的裹挟之下,对外界充满兴趣,并透过一个西洋镜来看看外面的世界。对于古老时代的他们而言,西洋镜里的一切都充满稀奇。

图片

有时候,今天的互联网就像西洋镜。

今天,制度的优越性让我们取得了经济上的飞速成长,互联网技术拉近了彼此的距离,也容易打破隔阂,原来或许发生在与自己无关世界的事情,总是很容易的就让我们产生同理心。

图片

《前网不易员工发文称患病后遭遇公司“暴力裁员”》引起了轩然大波,随着网不易拿出了更多的论点,也让事件掀起了小高潮,我想换一个角度来考虑一下问题,分析一下在事件中那些出现了的,或没出现的人群。

主角:

主角J是一位90后,拥有上海交大的学历,是职场上最走俏的优秀资源。而且业余运营了自己的公众号,文笔朴实简练流畅自然。如此年轻的他,也是企业最受欢迎的优秀成员,假以时日,如果能够善终,一定能谱写一篇非常不错的故事,让大家看到90后是如何快速成长为企业的栋梁人才,为公司创造无穷价值。然而,由于一场身体上的变故,让他的职场之路遇到了困境,而且扩展性心肌炎病症非常严重,最终必须面临换心的痛苦。

人生之痛,莫过于让白发人送黑发人,难道要让他的父母成为失独老人么。扼腕叹息。

主管和人事:

在这个事件中,作为第一当事人的主管自然而然会成为焦点,甚至“网红”,即便他不想如此。

当然,我们都知道,他的谈话是代表公司谈话的,所以他以为他的立场也同样代表了公司立场,嗯,那一刻他一定以为他是三石附体,公司要裁员,是裁掉那些劳动生产力低或者如大东子说的“性价比低”的员工,哪怕他生病了,也应该毫不犹豫的挥起屠刀,不能放过任何一个不能跟公司共同奋斗的人。于是他这么做了,并且他成功了。

而人力资源部门显然是这件事情背后的幕后真凶,公司说要裁减人员,而作为裁员的直接被考核部门,自然而然要冲在最前面。

在职场中,许多人都信奉这样的哲学:大家都是成年人,人性是什么重要么?难道还有什么比KPI更重要的么?

图片

三石兄:

说实话,网不易的发展历史对于80后的我来说一度是一个非常古老的故事,就像昔日《硅谷之火》一般,指引着我走上了IT这条道路,并成为一位普通码农。但是吃到了互联网时代的红利,却在移动互联网时代开始逐渐走下坡路了。

而且网不易和微软中国、金山一样被成为中国互联网的黄埔军校,从网不易毕业的许多创业者,他们创造出许多优秀的产品,也深深的影响着我们。

当然,黄埔军校其实对于公司本身来说,并非是个非常好听的名词,因为他代表着公司能够培养人,但是却不能留住人。用《浪潮之巅》中的一句话来说,要看一家公司是好还是坏,就看是优秀的人才流入还是流出。每一个优秀的人员流失,对一家大公司来说看起来没什么,但是往往意味着公司的吸引力在逐渐下降。

经济学中有一个“劣币驱逐良币”的现象,对于一家无法维持积极发展的企业,也往往会面临这样的现象。优秀的人才流失之后,往往留下来的是最能体会企业文化精神、并能在肉体上跟公司在一起的人。

嗯,肉体上跟公司在一起的人似乎更能理解企业管理的规则,并愿意花时间熬工时。年初马云说996是福报时,大家都在吐槽说资本家的本质彰显无疑,但是实际上还有更多IT公司其实是维持着更长的小时,每天只上9个小时,确实是一种福报啊。好吧,对于大部分公司而言,加班,其实是为了靠苦劳来弥补管理层甚至老板吹过的牛或能力上的不足吧。

三石兄似乎已经退居二线了,这也意味着,企业文化精神已经在逐渐衰微,公司已经在“大公司病”这条路上越病越深。

在互联网寒冬的今天,许多中小企业都面临着裁员的艰难抉择,也许他们没办法经营,但为了给员工多一条生路,往往也会想办法给他们一些补偿。当然有一些企业确实拿不出钱,但是他们也会给出承诺。

但网不易的吃相会不会太难看了?连网不易这样的大公司都不给补偿,而是以这么难看的吃相挥舞屠刀,肆意驱赶那些为公司发展做出巨大贡献的优秀员工?那其他的公司还有没有更加恶劣的手段来赶人呢?招人的时候不惜一切代价,赶人的时候,也同样不惜一切代价?企业的商誉难道如此廉价?

出生90后的主角身患需要换心的重病,而大概同样90后的网不易,也需要三石兄出面,给公司来一场换心手术吧。

工会

在我的同学群讨论这个事情时,突然有人抛出了一个问题:工会去哪里了。大概大家都会觉得莫名其妙。虽然在有一部法律《工会法》明确了工会的职能是维系党和人民群众的关系、并维护广大工人阶级的基本利益,而且大部分公司似乎都设立了所谓的工会,但是真的有工会么?

并非如此,工会代表老板的利益,或者说是管理层的利益,其目前的主要职能大概仅仅停留在“收会费、搞茶话会”。工会究竟还有什么用?

期待全国总工会发声。

劳动部门

对于大部分普通群众来说,跟劳动部门似乎没有一丁点关系。

虽然跟公司签署了劳动合同,看似应该受到劳动法的保护,但是当发生劳动纠纷,去劳动仲裁大队申请仲裁时,政府部门的工作方式往往会让人望而生畏。于是宁可自己吃点亏,也不愿意走那么冗长的劳动仲裁流程,毕竟搞不好就需要花大半年的时间,不定期就会接到劳动部门的电话让当事人去仲裁庭处理案子,对于个人来说确实是有点吃不消。

期待劳动部门发声。

我还记得多少年前,农民工的问题引起了政府部门的多次关注,连续好几年的中央一号文件都是关注农民工问题。IT民工呢?毕竟IT产业工人也算是个人所得税的主要纳税群体,难道就不应该引起更多关注?有关部门不要只想着GDP、招商引资、课税,而不想着如何维护劳动者的利益啊。

结语

城隍庙的西洋镜,看透百年,看透世间百态。

网不易裁员事件,透过这个事件,我们看到了来自互联网时代的独特魅力,国民早已不再停留在鲁迅书中说过的矇昧和无知的区区看客,而是掌握了更多的方法,足以产生更加深远的影响力。

使其生、使其亡。摧枯拉朽,谁能阻挡?

时代在进步,那些该破灭的就让他破灭吧。

由于时间仓促,胡言乱语,还请诸君一笑。

2019.NET Conf China(中国.NET开发者峰会),.NET技术之崛起,已势不可挡

Posted on 2019-11-12 | Edited on 2021-04-25 | In 随笔

一、微软走向开放与.NET Core的诞生

当今时代,气象更新,技术飞速发展。

当今时代,开发者大概是最优秀的群体。每一位开发者,无不奋勇向前,努力追寻时代的步伐,以大无畏的精神迎接挑战,紧跟大时代成就企业发展的宏伟蓝图的同时,也在实现自己的个人梦想。

微软,无疑便是最善于应对时代变化的英雄,从比尔盖茨选择从哈佛大学创业开始,历经四十年时间,经过了三个变革的时期。每个时代都以其独特的方式深深地鼓舞人心,哪怕历经千辛万苦,哪怕一度前途充满阴霾,也能实现自我价值的刷新,并重回巅峰。

当代的微软,已经从一家技术驱动型公司,变革为一家文化驱动型公司,在纳德拉的领导下,云战略,开放,分享,自我刷新的企业文化精神已经让人们深深的意识到,那个沉睡的巨象一旦觉醒,该有着多么大的魄力和影响力。

大环境已经在悄然改变,在隔壁Java走下坡路时,这边的.NET,也迎来了新的发展机遇。微软不再靠自己一家企业来控制这种优秀的技术,而是成立了一个.NET基金会,他扮演着技术公司于开发者之间的窗口,旨在加强和扩大以.NET技术为核心的技术生态系统。并随着.NET技术交给了社区由基金会来管理,基于.NET的开源生态已经如星火燎然之势蓬勃开展起来。到目前为止该基金会的参与者已经包括谷歌,红帽等知名互联网公司,这么多优秀的企业都参与其中。众人拾柴火焰高,有了这么多企业的积极参与,.NET技术生态已经迎来了前所未有的战略机遇期。

2019年的9月份,在2019年的.NET Conf上已经发布了.NET技术体系下、面向开源和跨平台的技术组件.NET Core3.0,该技术包含了一系列组件和新特性,能够让无论是Web开发者,还是ML.NET开发者,或者是游戏开发者都能直接感受到.NET Core跨平台技术的魅力和价值。

二、开发者峰会的诞生

2019年对于广大.NET开发者来说算是不平凡的一年。在这一年里,在微软云技术社区的支持下、在.NET社区领袖张善友老师、衣明志老师、叶伟民老师、陈作老师、潘淳老师等行业翘楚的摇旗呐喊之下,各地的.NET技术社区(微软.NET俱乐部)如雨后春笋般蓬勃开展起来。

首先是胶东开发者部落的诞生、广州微软.NET俱乐部的复活。

接着是苏州微软.NET俱乐部的诞生。

随后是长沙.NET技术社区、沈阳、东莞、厦门、北京等地区.NET社区的诞生 。

以及随后各地都相继成立了主题为.NET技术或互联网技术的各类线上或线下的技术交流组织,可以说无论你目前身处祖国的哪一个角落,总是能在最近的地域找到一个活跃的技术社区,通过社区能够跟当地的技术大佬们进行充满高质量的技术交流,这对于每一位开发者来说都是非常难能可贵的体验。

除了这些.NET技术社区外,还有数十位.NET开发者们自发运营起主打.NET方向的技术公众号来,通过这些公众号,能够让开发者从全方位多维度了解和学习面向互联网大时代的.NET技术,能够让爱学习的开发者们的技术每时每刻都做好积累。

而且在.NET开发者的主阵地,博客园每天发表的新内容中,与.NET技术相关的话题也越来越多;而且越来越多的优秀的.NET技术书籍也已经付梓,并被出版社相继出版,成为畅销书,还有许多开发者们都相继把他们的写的新书交给了出版社,预计在明年年初将迎来一波.NET技术类书籍的小高潮。

这些都是.NET开发者们迎来的良好机遇,借着行业互联网的逐渐深化、以及.NET技术的进一步推广、技术社区的繁荣昌盛、.NET学习资源的源源不绝,相信开发者们一定能借此良机成就个人的美好梦想。

在这样的大背景之下,为了让.NET开发者们能够更加直观的感受到.NET技术的强大魅力,微软云(Azure)、.NET技术社区的行业翘楚、企业代表、活跃在.NET技术圈的优秀开发者们、以及各地.NET技术社区们,打算干一件大事,这就是本次2019年的.NET Conf,中国.NET 开发者峰会。

图片

有别于一般都是由大型企业组织、或者甚至有微软包办的其他类型技术峰会,这次峰会完全来自.NET技术圈开发者们的无偿付出,我们可以看到,张善友老师经常在他的公众号里发布与Conf有关的资讯,而这些文章的撰写都是来源于社区;我们也可以看到许多精美的海报,这些也是来源于开发者,甚至也许就是我们身边的某位不知名的开发者。还有在活动现场的许多志愿者、主持人,这些都是对.NET 技术充满大爱的优秀开发者;尤其是那些为大家带来精彩内容的老师们,他们有时候为了PPT上的每一页内容,需要花费大量的业余时间;除了这些之外,我们还能看到许多细节,如那些设计精美的PPT、那些设计精良的文化衫、甚至还有那些小巧玲珑的贴纸图案、海报,无一不是来源于社区志愿者的精心奉献。

图片

这么多开发者、志愿者、老师们的专注认真、精心设计、严密组织, 从宣传、活动安排、布置、会场组织的每一个细节出发,我们看到的,正是一个充满生机和活力、专业的技术社区,这样的社区,让我们对.NET技术充满了激情,也让我们对未来充满了无限期待。

图片

三、精彩纷呈的内容

图片

这次.NET Conf的主题是《开源,共享,创新》,既可以称为社区的主题,也可以拥抱新时代的.net开发者们的共同心声。

图片

开源:随着.Net技术推出的新版技术框架.net core已经发布3.0版本,开源社区建设正如同雨后春笋一般蓬勃发展。

共享:.net开发者们,不再选择敝帚自珍,而是以更加开放的心态参与到社区建设之中,共享知识,也是在分享财富。

创新:开发者们拥有的最优秀的品质,在时代的浪潮下,唯有不断刷新,创新,才能始终如一的创造价值。

而围绕主题出发的各种主题也同样贴合了行业发展的大趋势,许多.NET开发者虽然目前从事的领域也许是某些行业应用的开发,但是都说想了解新兴技术是如何运用到其中的,那么这次盛会给了大家机会。在本次峰会上,不仅有开发者职业发展规划的内容,也有.NET Core新的特性介绍,更有许多新兴技术,例如人工智能、实时计算、混沌工程、服务网格、RPA等新潮技术,还有PowerBI、Unity Bot、 ABP等备受期待的传统技术,能够各个让对技术充满兴趣的开发者都能学到自己想学的东西。

我们可以跟随.NET Core项目负责人Scott Hunter一起,看看在.NET Core3.0中,哪些新的特性能够获得怎样的好处。

也可以跟着来自澳大利亚的微软MVPJustin Yoo一起,听听他讲的故事,看看他的职业发展;

图片

还可以跟着来自校宝在线的肖伟宇老师一起,看看如何在.NET Core中将检测组件集成到高可用的.NET Core微服务中。

图片

我们还可以听卢建辉老师谈谈ML.NET 和SciSharp项目以及TensorFlow.NET项目,而这个TensorFlow.NET项目尤其值得大家关注,因为他的主要开发团队,许多成员都是我们身边的、来自中国内地的.NET开发者们,这个项目不仅仅是中国.NET开发者们的小圈子自嗨,更是成为微软人工智能框架ML.NET的基础平台框架,通过这款框架,能够让全世界范围内超过六百二十万.NET开发者们无需转语音,便可畅想人工智能的美妙。

图片

而刘腾飞Jesse这位英俊帅气不凡的开发者,也把他们公司踩坑K8s的全过程搬上讲台,用血和汗的教训告诉大家,其实.NET Core什么都能干好,而且不比隔壁家的技术差。

图片

本次大会与某些大厂组织的自称科技未来的技术峰会、喜欢吹假大空技术不同,这次大会完全是面向开发者的毫无套路的技术大会,内容都是来源于身边那些热衷于技术的开发者们平时工作的点滴积累。

例如,我们可以看到博客园常年排名第一的蒋金楠大大,从多个角度出发,向开发者介绍在过去、现在,如何使用.NET/.NET Core的技术实现跨平台应用的开发;

图片

以及来自特来电的周国庆老师,把特来电如何构建一个覆盖全国二十万个充电站的过程讲述给大家听,混沌工程,从未离大家如此贴近。

图片

除此之外,还有目前在日本从事聚合支付的桂素伟老师也分享了他们使用.NET Core+K8s的开发实践过程,让开发者能够更加深入的了解.NET技术是如何更好的融入到云原生之中。

图片

还有来自中通快递的黄国石老师,把中通基于.NET技术构建实时计算框架的过程也搬上舞台,让大家看到了这双十一一亿订单背后,.NET技术也做出了如此巨大的贡献。

图片

还有来自刘钰老师分享的PowerBI,如何无需编程就能掌握大数据分析的技能,只要使用PowerBI,谁都可以办到。图片

除了一对多式的讲座,活动还提供了面对面的workshop讲座,在张善友老师、陈计节老师、刘腾飞老师等几位老师花了半天时间向参加工作坊的开发者们介绍如何在azure云中使用k8s的全过程,让大家在互动中学习,产生了非常不错的效果。

图片

四、结语

从11月8日的.NET 之夜,到11月9日,11月10日的.NET Conf,我在上海呆了不足三天,有幸作为观众参与到这场活动之中,让我获益匪浅。我不仅仅学到了许多在现有工作经历中无法获取的机会,认识了许多在原来圈子中无法认识的优秀开发者,更让我深刻明白,自身离他们的巨大差距,这将激励我进一步努力。

时光流逝如白驹,短暂而稍纵即逝,如同黄浦江,时而平静流淌,时而泛起波澜,正如我们所亲历的这个时代。

人类从未有过如此般壮阔的变革。无时无刻不在变革,是因为历史的车轮滚滚向,历史眷顾的是坚定者、奋斗者、搏击者。

我相信,我们每个人都将迎来同样更加壮阔的明天,因为我们正赶上了行业互联网大发展的时代、以及.NET发展的大时代。

图片

开发者的不断进取,源自对技术的点滴追求

Posted on 2019-11-05 | Edited on 2021-04-25 | In 随笔

身边的优秀开发者,【DotNET骚操作】周杰

一,社区的小圈子

今年3月的一次技术交流活动上,那是我们.NET技术社区第一次组织线下活动,由于没什么经验,所以活动组织得比较仓促,内容也比较一般,效果还是有点欠缺。当然,活动本身是必要的,这次活动上有幸认识了许多长沙的优秀开发者,这让我非常的高兴。

事实上搞技术活动,与其说是交流技术,倒不如说是扩大圈子,交流感情,认识更多的朋友。毕竟每个职场人往往圈子都是固定的,哪怕是在大公司,真正经常来往的朋友其实也不过三两人而已。但是在北上广深的大城市,往往有时候刚刚认识几个朋友,对方可能就离开了,这也是一种遗憾。相对而言,在小城市或许也相对容易形成更加稳定的精准小圈子,这也是我认为一个社区存在的最大价值。

小城市的职业发展方向大概都是一样的,从入门级小程序员出发,然后到高级程序员,再到项目经理,然后逐渐脱离技术的主航道,直到被技术抛弃。有朋友戏谑道,长沙的程序员大概率都是一样的,靠经验的简单复制、依靠人际关系技巧或者靠资历,而真正钻研技术的非常少。

哪怕有许多开发者得以突破转到了项目管理或其他方向,也很难能够在专业领域能够进一步的发展。毕竟首先企业大环境决定了个人的职业选择,其次就是很少有开发者能够明白的看清自己的职业发展规划,为了钱而生存无可厚非,然后整个职业生涯都迷迷茫茫,只能导致最终到了一定的年纪,就开始原地踏步了。

别瞎迷茫了

二、周杰的成长历程

而公众号DotNet骚操作的作者周杰则是小城市中少有的对技术始终保持热心的优秀开发者。周杰也是参加了我们第一次活动的三十位开发者中的一位。

事实上很多年前(三年前)我就对他的名字有所耳闻,我的好几个朋友都说他的生活除了工作,家庭,剩下的就都是技术,是一个不折不扣的.NET技术狂。

不过由于当时我主要是沉浸于小行业应用的泥坑之中,还不能体会.NET技术作为基础技术的巨大价值,自然而然相对来说比较无感。直到从泥坑中出来才能深深体会到技术的无穷魅力,也才真正理解在长沙这座城市,能够踏踏实实的以.NET技术作为自己的核心竞争力的开发者是何其的珍贵。

当时的他的公众号【DotNet骚操作】还没开,以前他经常做开源项目。与许多内地城市的开源项目参与者热衷于刷开源项目,以fork了哪些项目贡献了多少文档的形式相比,他更倾向于自己造轮子。在他的github仓库(https://github.com/sdcb)中还有许多各种各样的开源项目,这些都是他一点一滴的积累,几乎每个方法都会认真考虑代码背后的实现逻辑和性能优化,这些小巧玲珑、性能完美、代码整洁的小轮子,既让他在技能方面得到了积累,更是让其他人能从中获益。

当时他还很少写博客,我就撺掇他写博客,他也说干就干,很快就写完一篇,那篇文章的具体内容我不太记得了,我只记得他对于技术问题的专注和专业,令我非常钦佩。

这个时候就体现了他过去那么多年积累的价值,一旦开始写博客,就产量特别高。到现在短短五个月时间已经写了二十篇,而且素材越写越多,质量也越来越好,几乎每一篇都会成为博客园的推荐文章。他立下了一个flag,要写五十篇精品博客,让大家看到DotNet技术的美妙与精彩。

我们偶尔会讨论.NET开发者的焦虑,许多.NET开发者都以自己选择了.NET为耻,总觉得是这个技术让自己的路越走越窄,经常在各种技术群里吐槽,说自己人生最大的错误就是选择了.Net。

我们都对这种人觉得惋惜。他说,程序员只有因为自己没能努力学习而感到焦虑,真正掌握了一种开发技术,一定也能适应其他语言和技术。优秀开发者根本没时间焦虑,毕竟要学习的技能点随着年龄的增长越来越多,恨不能每天有48个小时来学习技术,哪里还有其他闲心去思考工作,家庭,技术之外的其他事情?只要自己技术过硬,哪里还需要担心什么未来前途不保?

我们也经常讨论招人难的问题。尤其是对于基于.NET技术栈的企业来说,都遇到了这样的问题。一方面,确实越来越少的开发者使用.NET技术栈,一方面许多使用.NET技术栈的开发者都在从事边缘业务的开发者,很难触及底层技术或核心的技术。这并非企业行为,而是兴趣爱好驱动的。

也必须承认,过去十年借助于互联网取得财富自由的.NET开发者几乎非常罕见,许多以前致力于研究.NET技术的开发者的出路都只能选择出国。这样的前提让功利的中国社会,越来越少人选择.NET技术。但是这也是.NET开发者最大的机会,好好学习技术、努力跳出自己的圈子,看看世界,选择将让你成长。

我深以为然。程序员,不仅仅是.NET程序员或java程序员,能够用心学好技术,努力提高自己的技能,并时刻保持学习的精神,才是程序员的最大的价值。

周杰正是按照这样的节奏在坚持自己的方向,他深刻的明白贪多嚼不烂的道理、没有追求一蹴而就,而是一步一个脚印,每一步都踏得严严实实。这种严于律己的优秀开发者的自我进取,也正是开发者所应该具备的自我刷新的精神。

他使我明白,无论是什么岗位,在什么环境下,都应该清楚自己的职业发展方向,并努力提高自己的硬技能和软实力,这是开发者得以利足于时代永不淘汰的光辉色彩。

才华照

(ps,大概需要减肥了。。)

三、环境造人才

在互联网技术飞速发展的今天,越是优秀的企业也往往最能凝聚最优秀的人才,正是这种人才间相互吸引的魅力,让企业更加优秀,也让人才得以借助企业提供的平台取得了更好的发展。

他所在的公司是我一直神往的优秀互联网企业,也是长沙地区.NET开发者最多的企业。公司基于.NET方向的开发者超过一百人,福利好,制度好,充满了积极的分享氛围,正是这样的氛围才得以造就出周杰这样的优秀开发者。

企业良好氛围的形成,并非个人或某几个人所能影响,而是一种从企业基因出发,到企业各个维度精神的集中体现,是集体智慧和创始人基因以及管理层管理能力的最好表达。

互联网时代许多企业盲目追求眼前的快速扩展,总是恨不能招待机时间最长的二十几岁开发者完成原始积累之后再把资源甩开。而这家优秀的公司则并非如此,更在乎团队能力的整体提升。

我仍然记得曾经问过他们的人事同学为何改成现在这个名字时,她说是总经理说的。不由得让我想起那个历经互联网大时代的优秀企业家,他曾经以一己之力,撑起了星城IT产业的繁荣。

曾经,那些从这家公司毕业的优秀开发者都能成为其他公司最核心的开发者。而每年还有更多优秀开发者,正在这里跟随企业一起成长,正在成为企业和社会的顶梁支柱。

生死看淡,不服来干的企业精神,让企业得以常盛不衰。积极分享、勇于进取、不断挑战,携手并进、共创辉煌的集体意识,让企业的人才队伍源远流长。

人才、人才、人才,这正是在互联网大时代最宝贵的财富。

(请大C小姐姐看到这篇文章后考虑一下广告赞助的形式)

结语

欢迎大家关注他的公众号,【DotNet骚操作】。也请大家记住他,一位年轻而充满激情的开发者。

DotNET骚操作公众号二维码

让我们一起跟随他的步伐,看看DotNet的一系列骚操作将如何给我们的生活带来更多精彩。

你或许以为你不需要领域驱动设计

Posted on 2019-11-05 | Edited on 2021-04-25 | In 技术

一、易于腐化的软件设计

犹记得刚刚参加工作时,是地图厂商四维图新集团旗下的一家子公司,主要从事规划测绘相关软件研发的公司。当时我的项目是为勘测设计院提供相对应的应用软件,对地理信息和规划相关的图纸信息,几乎已经专业水平。事实上,规划设计大概和软件设计类似,有规划的设计、或无规划的设计,造成的结果几乎是天壤之别。

我们或许很容易就能设想到一个毫无规划设计的城市,纵横交错的路网、杂乱无章式的建筑布局、各种凌乱的棚户区设计,恰好象征着软件设计的无序性,也恰好体现了软件企业在经费不足、组织缺乏管理、开发者能力不足、软件随时随地想改就改时的行业现状,只能说这样的软件是最能符合当时实际劳动生产力水平的产品。

巴西棚户区

如图一所示,巴西棚户区,层层叠叠、风格迥异、密密麻麻,如果作为一个外人贸然来到这样的地方,大概很容易迷失期间、更不用说充斥在棚户区的各类毒品和黑社会。杂乱无章的建筑和街区,就像代码中错综复杂的调用链;而借助贫民区搞事的黑社会就像是代码中的异味或者bug,表面上看起来如此平静、与世无争、但是你永远也不知道啥时候会来一冷枪。

不要以为离我们很远,我们其实轻易就能写出这样的软件工程项目。不一定是“大泥球”系统,也有可能只是一些看似简单的业务系统,但内部代码逻辑,可能会复杂到令人窒息的程度。也许那个时候有个别开发者也许会试图靠自己的能力来改变局面,但是往往也会碍于屎山太大,难以下咽。

大概只有最顶级的规划设计师、耗费足够多的资源,才能将这样的软件系统进行整改。然而,即便如此,如果以后没有持续维护的手段、更好的设计、仅靠老程序员或个别架构师、盲目相信将单体服务拆分成微服务,几乎不太可能实现软件未来的可持续发展。

一个良好的软件产品的一生、或许其实是一家企业一生的真实写照。

在特定组织架构下,缺乏技术基因的组织有时候期待技术变革,却会开启新的泥坑。而那些渴望靠技术改变一切的技术专家,虽然拥有某些大厂微服务式架构、以及架构改造的经验,他们也试图通过自己的努力,为企业业务腾飞助力。而在他们过去的经验中,往往相信组织遇到的问题,用微服务一定能解决问题。然后大肆扩招,一年内从几个人的规模、扩招到数百人的规模,将原来的系统从单体服务、改良成为微服务。但是靠单枪匹马根本无力拯救大势,没有更好的业务拆分策略,就只能按照数据库的表名关系实现了最简单的拆分。架构改造并非每次都会百试百灵,有时甚至连原来的需求都包不住,毕竟只能看到用户界面层外观上的表面逻辑,而隐藏在业务中的那数十万行代码,哪怕包含了企业最有价值的经验财富,也由于代码过于混乱,最终抛弃在源代码管理器中,堪称化神奇为腐朽。

# 二、易于腐化的面向过程开发

老系统改造也好、新系统开发也好,毫无疑问,我们最容易相信的其实是老程序员经验,而程序员们掌控系统的方式,就是靠数据库建模来驱动软件开发的古老模式,而且几乎都是面向过程式的代码,这些代码的流程几乎一模一样,只需简单的按照步骤,一步步套模式,轻易就能学会。

1、查看用户界面,定义需要绑定到界面的模型和层级结构。

2、设计数据库,不管什么类型的项目,先根据客户提供的业务表单、将其转化成实体关系(ER图)、然后建立对应的代码模型。有可能使用专业软件设计ER图,也有可能会使用Navicat软件设计ER图。

3、设计接口,然后把数据拼凑成用户界面层所需的对象。

4、代码层次结构为传统的三层架构,严格按照用户界面层、业务逻辑层、数据访问层进行设计,有时候会引入依赖注入框架,实现不同层次间的解耦。

但是有时候程序员不会严格区分需要编写的代码,究竟是属于哪个层次应该囊括的内容。于是毫无疑问,如果代码是为了实现用户界面上某些数据绑定操作,代码就往用户界面层写;或者代码是为了实现从数据库中抽取某些复杂数据、并构造成满足用户表现层逻辑的查询对象,那么就可以看到数据访问层代码中那些臃肿的SQL语句或查询方法。

正如“罗马不是一天建成的”,屎山也同样如此。这样的写法在代码刚刚编写之初并没有问题,只是随着业务变化、时间的积累、程序员的水平、方法重构、新技术新组件的引入,代码将成为屎山。

这时,高级程序员们的价值,就在于他如何能够在屎山中快速找到bug、并解决问题的能力,这大概是一种不能复用、不可再生的能力,因为永远有让人看不懂的垃圾代码,而且每家企业都有自己的特点,不同企业间往往不能循环利用。我一位朋友经常吐槽,他感觉自己的价值就是守住公司那份拥有8年历史的古老代码,以便其他程序员在进行代码修改时,不会引发莫名其妙的bug让系统无法运转。

三、过程式开发和事务脚本模式

在现代软件工程学的教科书中,都会指出面向对象是解决软件复杂性的方法,但实际上掌握这种方法的开发者并不多。由于开发者普遍缺乏抽象化思维,所以面向数据库、面向过程式的编程习惯能够成为业界主流,并非时代的倒退,而仅仅只是在短期效率和长期维护性上,被迫做出的艰难选择。

假设我们设计出的符合三层架构的系统结构图简化后,如下图所示:

简单结构

我们来看看这种数据库建模的开发流程中的输出成果:

1、会定义两种对象,分别是是面向UI层的模型(DTO)和数据实体(Entity)。在领域驱动设计中,将这两种称为所谓贫血模型,贫血模型,只有赋值器Set和取值器Get,(在Java里面会使用POJO 这个名词来定义)。贫血模型是为了作为保存状态或传递对象而存在,他并非按照实际用例场景对某类具体事务的抽象、也没有与对象相关的行为。

2、定义数据访问层来实现数据的持久化、或者从持久层实现数据的创建过程。数据访问层存在的目的是为了构建上述贫血模型对象,这种访问机制被成为“事务脚本”。事务脚本与对象行为割裂,而且容易导致异味产生。

3、与用户行为相关的操作割裂的存放在不同层。有的可能放在用户界面层、有的可能放在数据访问层、有的可能放在业务逻辑层,造成了领域知识的丢失。

4、用户界面层使用接口作为外观或者一种行为、开发者会使用自己独立的风格习惯来定义这种行为,就容易造成术语和规则不统一,也会为后期产品的维护迭代造成问题。

5、现在的软件设计,往往要求输出一份高保真的原型图、也会按照敏捷项目管理的流程对这份原型图建立持续更新的机制,确保原型图是需求的具体表达,但是产品语言并非统一语言,也许产品语言具有业务含义,但是由于不能指导开发者进行接口、类、持久层的设计,造成了代码与需求的割裂。在张逸老师的《领域驱动战术实践》提到他曾经使用dimension和metric两种不同的对象来定义一个维度对象,为代码造成了不必要的麻烦。我也曾经在一个项目,遇到过产品术语未能澄清,导致开发中使用style和theme两种截然不同的定义来定义与“风格”相关术语,为代码引入了不必要的纠结。

四、领域驱动设计是什么?

领域驱动设计引入了以下概念,但是我们无需在这篇文章中深刻理解这些概念的具体含义,我们只需知道,有这个东西。当我们开始按照领域驱动设计的方法设计一个系统时,按照前人整理的领域驱动的sample,往往就会将概念融汇贯通,达到更好的理解效果。

1、统一语言:定义好产品原型,需要建立统一语言。这是一种在内部和外部都能使用的规范化用语,包括UML、适当的图、一致性的描述、以及专业术语和术语对应的英文描述。

2、实体:在领域中可以通过标识进行唯一值定位的对象。

3、值对象:在领域中,从其他领域或某个实体中分离出只包含某些特定属性的对象。由于不具备唯一性特征,往往无需用于数据持久化。

4、聚合、聚合根:将具有相关性的对象聚合在一起,并以聚合根的形式统一对外提供访问方法和属性字段成员。

5、限界上下文:领域包含核心领域、子域和通用子域,而限界上下文则是一个具体业务的流程。每个限界上下文独立于其他限界上下文而存在,独立演进、功能完备。限界上下文的识别充满技术含量。

6、领域服务:包括仓储服务和工厂服务,前者负责实现对象与数据库的操作过程、封装了一系列数据库操作的方法;后者则侧重于对象的创建过程。个人认为从三层架构演进到领域驱动架构过程中,仓储服务是最接近于数据访问层的逻辑,也是让大部分领域驱动架构最终又回归到三层架构的一种通病。从对数据访问层中抽出对象、行为、数据访问,是战术设计的关键步骤。

领域驱动设计引入了一堆新的架构形式,包括经典的四层架构、EDA(事件驱动架构)、CQRS架构(命令查询职责分离)。而由于Evans的原书没有过分讨论如何识别领域,后来又有许多大佬在他的基础上进行了完善,提出了许多方法,包括名词、形容词、动词建模法、事件风暴、四色建模等方法,限于篇幅,且听下回分解。

领域驱动的结构

五、思维的转变,才是最大的困难

领域驱动设计,或许是解决这些问题的一剂良方,但也或许是开启了暗黑世界的大门。

概念晦涩难懂、程序员们不愿意开始思维变革、技术上可能存在不预期的坑、都可能让新方法的实践陷入一滩烂泥。还有许多人以为自己看懂了领域驱动设计(包括笔者),在往项目中运用时,总是有意无意的会被过程式代码的思维定式控制,让架构回退到三层架构。

由于微服务架构的兴起,让复杂系统的开发维护成为大家普遍关心的问题,使得Eric Evans于十五年前提出的这套理论,在今天绽放出了新的光芒。当然领域驱动设计仅仅只是众多面向对象编程的一种实践,通过领域驱动设计将UML等方法灵活的运用其中,通过打破原有数据库关系建模给代码造成的桎梏,让开发者能够真正的实现面向对象编程。

然而思维模式的转换并非易事,从过程式代码中,抽离出与对象有关的行为,远比理解这几个概念要复杂,这需要大量经验的积累。

领域的复杂性

毋庸置疑,数据库建模驱动软件开发具有速度快、学习成本低的显著特点,在许多项目中,能在短期内可以给开发者带来许多便利;而应用领域驱动设计,则可以在更长的维护周期内,给软件维护带来实质性好处。

两种不同类型的开发模式,根据企业实际出发进行选择,还只是开始,但能真正运用好领域驱动设计或者UML、面向对象设计这种软件工程的美学思维来改造我们的系统,让系统绽放出更加璀璨的光芒,这才是软件设计的乐趣所在。

如何画马

2019.Net Conf,我们的共同期待

Posted on 2019-11-04 | Edited on 2021-04-25 | In 随笔

(一)回顾一个小社区红过的五分钟

不知不觉,距离中国.net社区组织的.net conf只有不到一周的时间,还记得年初在叶伟民老师,潘淳老师和张善友老师的号召下,我们长沙的十几位开发者自发组织起来,拉了一个技术社区,并在腾讯云加社区、微软Azure云技术社区的大力支持,在华邦互联、百师通教育、校管家、心莱科技、长沙冉星信息、深圳纵网长沙分公司、北大青鸟海纳学院等优秀企业的赞助下,在四月组织了一次技术大会,上午场邀请到了张善友老师、梁桐铭老师和汪鹏老师,下午场邀请到了腾讯云的胡李伟老师和卓伟老师,一天的分享安排的满满当当,在小城长沙的.net技术圈掀起了一波小浪潮。

不过大概我们几个996程序员们和几位创业者们的业余时间着实有点匮乏,许下了不少宏伟蓝图,转眼间就把自己的flag吞掉,让组织者之一我感觉到颇为尴尬。一个优秀的社区,一定得持续的把活动拉起来,让更多优秀开发者能够在这里传递更多正能量,让技术的星星之火点燃,推向更加广阔的人群。只有更多的人参与进来,社区之水能够源远流长的持续不断的流下去,才能真正获得长效的发展。

不过显然,虽然企业和开发者都对一个积极优秀的社区充满兴趣,但是却缺少真正能够站出来积极拉动社区的开发者,由于社区初成立、大部分参与者都只是以看热闹的态度,这也让那些对原本充满热情的早期参与者的热情熄灭,很快就偃旗息鼓,然后社区就看起来名存实亡了。

无论是作为组织者的我们,或者是做为观众的开发者们,对社区期许过高。总是高估了自己的计划能力,组织者们太想更早的出成绩、有时候又心态不纯,想借此机会获得一些虚名,但是一旦遇到挫折就会浇灭火苗,然后曾经的豪言壮语都将成为泡影。而作为参与者,确实苦于没有社区这样一个集体,于是总想着更早的看到成绩,然后发现这个社区其实有点名不副实之后,就失去兴趣了。

无论作为组织者,还是参与者都是或许一样的三分钟热度。在技术这条路上,追求三天打鱼、两天晒网、恨不能一口吃成大胖子的心态数见不鲜。每个人都能在这个波澜壮阔的大时代成为网红,但只有少数人真正能成为明星,大部分人都将在红完他那五分钟后,瞬间谢幕。

也就像许多年轻的开发者们总是能很快的成长,在技术的甘泉中以飞快的速度汲取到足够的养分,但是却只有区区百分之五的掌握了优秀学习方法的、最优秀、能够一步一个脚印的开发者最终能够一直长期的走下去。他们既有长远规划、也有短期计划,不过分在乎眼前得失、不汲汲于名利、不戚戚于自我,他们的每一天都在坚持,让他们靠自己的努力创造了不菲的业绩。

(二)大环境下、市场选择和人生际遇

有人说,大环境不好,再努力都是徒劳。对于.NET开发者来说,9012年的今天,大环境似乎没那么好了。在过去十年,正是互联网产业大爆发、中国经济飞速增长的十年。

在这十年的前五年里,执掌微软的Steve Ballmeerr犯了许多错误,首先是错过了移动互联网的爆发,失去了手机阵地、买了诺基亚,然后却将其埋葬。错过了从软件到硬件转型的大时代,他自称为最大的遗憾。

其次在云端战略中,失去了先机,在阿里云开始大规模铺云端战略时,微软和中国互联网三巨头中的两家,百度和腾讯一样,并没有在第一时间看到企业级市场对于云的巨大需求,还好后期继任者纳德拉及时按下了刷新键,才得以转型成功。毕竟是一家有着四十多年历史的公司,基因决定了企业的思维模式,能够实现自我变革,确实是一家伟大的企业。

而对于广大.NET开发者来说,则错过了跟随中国互联网发展的最佳时期,由于.NET技术与微软windows平台的深度绑定、windows平台本身较高的授权费用,让对互联网基础平台需求非常旺盛、而对成本效益最为在意的互联网公司最终纷纷抛弃了.NET平台,转移到了开源和授权费用相对较低的Linux平台,并开始逐步使用Java、Go、Python等作为主力开发语言。

说来也有点遗憾,在20世纪末时,微软也曾是Java主要推动者的Sun公司最大的竞争对手,C#之父Anders Hejlsberg,在他的职业生涯的早期,开发出了Delphi,是大杀器;而职业生涯的中期,基于开源的Java开发出的J#和在Windows上使用的虚拟机,甚至比Sun公司自己开发的虚拟机都好用,最终让Sun不得不通过法律手段来寻求庇佑。然后Anders Hejlsberg大神将主要精力投入到.NET和C#这种优秀的语言中,并大杀四方,获得了非常广泛的用户。

然而,三十年河东,三十年河西。本世纪前几年Windows平台的火爆,确实有力的推动了中国信息产业的繁荣昌盛和发展、微软甚至被称为互联网的黄埔军校,号称撑起了中国互联网的半边天,许多大型互联网公司的CTO或高管(包括阿里云的王坚博士),都是从微软出来的。但是由于后来微软自身的战略原因和中国互联网产业的独特性,让Windows开始失宠,而.NET技术开始走向下滑。以至于今日,许多培训机构也不再开设这门技术。

有人说:大环境不好,所以开发者找工作都很困难。但是也得承认,在环境下的个人,其实不过是此起彼伏翻转、甚至被拍打在沙滩上的浮萍,被人生裹挟着,难免会失去目标,当然也得承认,适应环境的能力非常重要。就像许多开发者都转型到其他语言,这就是在环境下的自然选择,这或许会让大家会有点遗憾。不过我觉得,逐利是人性自然的需求,能够在一门语言上一直走下去固然重要,但是选择变化也无可厚非。毕竟真正掌握了像.NET这种优秀的技术、以及C#这门优秀的语言,不仅在windows下能够做出优秀的产品,也同样能够驾驭包括像Java这样优秀的技术。我们都是程序员,而不仅仅是某个专门领域的程序员,始终抱有开放的心态,能够让我们的职场更加顺畅、也让我们的人生更加圆满。

(三)优秀开发者们的持续守候

而一个人的成长,其实与某种语言本身无关、取决于对待技术的认真态度、和孜孜不倦的求索精神。就像我们对社区充满了殷切期待,却不能指望他一天就成为巨人,这需要一次又一次的设计、测试、调试和优化、甚至还需要进行大规模的重构,才足以成为更加完美的软件。这需要许多人一起努力,有共同的目标和执着的信念,每个人或许是不同的角色、职位、岗位、或技能特色,但是大家的心在一起,这就是一个完整的生态。

我还记得我刚刚参加工作的2009年,恰好是Java最低迷的一个时期,优秀的技术先锋Sun公司被迫以白菜价被Oracle收购,一度让.NET带来了机遇。(这也是我选择.NET的一个大环境原因)。时至今日,这门技术我已经用了十年,虽然技术不好,但是我很庆幸见到了几位对技术执着追求的优秀开发者。对于他们,我们或许认识,或许不认识,或许他们出名、也或许他们低调,但是他们都是我们值得学习的优秀榜样。

当博客园的创始人dudu把博客园搭起来时,他为了实现个人技术理想使用了.NET技术来构建博客站、而且这个小站是在扬州这样一个小城市成立的,当时的类似的轻博客竞争对手也很多,所以许多人都不看好他。但是十五年的成长,博客园已经成为许多程序员的心灵港湾,在这里各种不同技术的开发者在这里交流,打造了一个和谐宁静的技术圣地。

有一个或许有人熟悉的论坛,叫做苏飞论坛,是一个历史悠久的小论坛,站长苏飞不仅是一位老程序员、目前也是一位创业者,他的论坛非常活跃,技术氛围浓烈,许多开发者在这里获得了大量有用的知识,包括我就是获益者之一。

从CSkin开始,到DSkin,小红帽和乔克斯他们几位开发者,他们基于.NET构建了一套完整的界面库、效果优美,性能优异,打造了一个不错的小圈子。

张善友老师运营.NET社区、公众号和博客,虽然同期有数十位开发者与他一起开始经营公众号,但是他一直坚持下来,目前公众号已经拥有数万粉丝,堪称.NET领域的KOL。

苏盛巍老师把他的全部精力都投入到基于微信的SDK开发过程中,到目前已经拥有数十万用户基于这套SDK组件,开发出大量优秀的应用,极大的促进了微信应用市场的繁荣。

刘怡、谢炀、刘浩杨、何镇汐、娄宇等五位老师,他们不仅自己学习技术,还积极分享技术,组成一个社区,邀请了许多优秀开发者一起来贡献更加优秀的.NET Core技术,让中国的.NET Core开源社区越发的强大。

这些都是我恰好认识并曾经熟悉的优秀开发者,而在我们身边还有更多知名或不知名的优秀开发者,他们用他们的实际行动,一点点的点亮了黑暗时代,并迎来了新的黎明—–脱离Windows平台、开源的.NET Core技术。

时至今日.NET Core已经发布了3.0的版本,惠及数十万开发者。

(四)生态、社区、你我共同见证

使用.NET、.NET Core技术的开发者,这就是一个完整的生态。

而.NET Core技术,将成为我们的武器,带领我们开启新的征程。曾经.NET技术的发展只能依靠微软,而今,要依靠的不仅仅是微软、更是真正的社区力量,更好的生态、将在我们的手中塑造。 互联网的大时代,或许一波波浪潮将不再滚滚,但是产业互联网的大势已经即将拉开,这是我们的.NET开发者们的主场。

云原生、多平台、以及开放、创新的.NET 新时代,已经到来。

2019年11月9日,我们在上海等你,不见不散。这是一次完全有社区力量倾力打造的技术盛会,组织者们力求完美,只为给你献上一道力求优秀的技术盛宴,数十位.NET圈子的技术大牛,他们无偿付出,就是想让大家知道,.NET 技术什么都能干,什么都能干得最好。

我们期待大家一起来关注,也请大家相信,.NET社区,从来不是一个人在战斗,齐心协力,生态将更加美好。

1…6789

溪源

81 posts
4 categories
4 tags
博客园 CSDN
© 2021 溪源
Powered by Hexo v3.9.0
|
Theme – NexT.Pisces v7.1.2
#
ICP备案号:湘ICP备19001531号-2