• 万物流变:从辩证法看互联网架构和人生


    辩证法

    这两天在学习辩证法,发现辩证法的思想非常有意思。辩证法简单的说就是事物都是运动、变化和发展的,事物的对立面在某些情况下是可以互相转换的,而且正是这种矛盾推动着事物向前发展。

    辩证法的思想自古有之,也是系统化思维和思辨思维的重要方法论,我们先简单看下其历史和脉络。

    中国古代朴素辩证法

    • “祸兮福所倚,福兮祸所伏”
    • “物极必反”, “否极泰来”
    • “天下大势,分久必合,合久必分”。

    希腊古代辩证法

    "在我们身上,生与死,醒与梦,少与老,都始终是同一的东西。后者变化了,就成为前者,前者再变化,又成为后者。“赫拉克利特的这些话表达了对立面是互相转化的思想。赫拉克利特还明白表述了"一切皆流,无物常住”,“一个人不能两次踏入同一条河流”的发展变化的思想。

    客观唯心主义辩证法

    以黑格尔为代表的客观唯心主义辩证法主要表现为“正题-反题-合题”,应该理解成“某种我们认为的普遍概念或原理-—对普遍概念或原理的反对——新的普遍概念或原理”,这里的普遍概念或原理只是相对意义的,而不是演绎派所说的绝对意义的。至于绝对意义的普遍概念或原理本应该是只能通过无限步骤的辩证发展才能够达到。

    dialectic.png

    唯物主义辩证法

    马克思唯物辩证法的三个基本规律是对立统一规律、质量互变规律、否定之否定规律。

    • 对立统一规律揭示了事物内部对立双方的统一和斗争是事物普遍联系的根本内容,是事物变化发展的源泉和动力(比如白天和黑夜是对立的,可是相对于地球来说,它们却是统一的)
    • 质量互变规律揭示了一切事物运动、变化、发展的两种基本状态,即量变和质变以及它们之间的内在联系和规律性;
    • 否定之否定规律揭示了事物由矛盾引起的发展,即由肯定──否定──否定之否定的螺旋式的前进运动。

    互联网架构辩证发展

    单体架构

    早起的互联网应用,因为流量少,功能简单,基本上如下图所示,单体(Monolithic)就能支撑。

    undefined

    分布式架构

    随着流量和功能的增加,单体应用不再能支撑,水平扩展性和服务化拆分成为互联网的标配。

    undefined

    中台架构

    虽然SOA(Service Oriented Architecture,面向服务的架构)和微服务有一统天下之势。但是并不代表单体架构就会退出历史舞台,特别是在中台概念提出来以后,中台要求通过集中式的中台管控,来提升软件系统的复用,避免趋同的业务重复造轮子现象。其目的就是要通过中台能力,赋能前线业务,提升对前线业务的支撑效率。其架构思想如下图所示。
    image.png

    可以看到,中台架构虽然也是集中式的代码管控,但并不是对Monolithic的简单回归,而是综合了分布式理念之后的、升级版的“超级单体”。正是这种不教条,这种辩证的发展,才推动着互联网架构不断的往前发展演进。

    正所谓“天下大势,分久必合,合久必分”,这句话用在互联网架构的演进上也是合适的。

    辩证的世界观

    对立的存在

    很多道理不是一边说了就算的,这个世界几乎没有绝对的存在。有无数种对立的价值,在我们人生中都会起作用,都是对的。

    • 就像我们的价值观当中同时会追求自由派和保守派
    • 就像我们天性中就要追求舒适又要追求刺激
    • 就像我们既要诺守诚信又要拥抱变化
    • 就像我们既要自由又要自律
    • 就像我们既要有敏感力也要有钝感力

    豁达的心态

    辩证法告诉我们基本上任何事情都是两面的,从一个方面看是“坏”的事情,从另一个角度看可能就是“好”的。而且“坏”和“好”随着时间的推移,情景的不一样,可以互相转换。看问题不能只看一面。

    这无疑教会了我们另外一个更加豁达的看待世界的方法,如果对待任何事情,我们都有能力发现其“善”的一面,我们就会充满慈爱,心怀感恩,也就没有那么多抱怨和纠结。

    比如,即使是遭遇突如其来的疾病,我们也可以感受疾病带来的“好处”。因为疾病给了我们独处和自省的机会,让我们可以更加深刻的感受生命和自己。很多人在生完一场大病之后,对生命有完全不一样的认识,把财富和省外之外看的都很轻,更加豁达和开明,生活的更轻松愉快。

    最后贴一段《西部世界》中我非常喜欢的话:

    “Some people choose to see the ugliness in this world, the disarray. i choose to see the beauty. To believe there is an order to our days, A purpose.” -Dolores

    image.png

    SOFA企业应用框架

    前言

    从业这么多年,接触过银行的应用,Apple的应用,eBay的应用和现在阿里的应用,虽然分属于不同的公司,使用了不同的架构,但有一个共同点就是都很复杂。导致复杂性的原因有很多,如果从架构的层面看,主要有两点,一个是架构设计过于复杂,层次太多能把人绕晕。另一个是根本就没架构,ServiceImpl作为上帝类包揽一切,一杆捅到DAO(就简单场景而言,这种Transaction Script也还凑合,至少实现上手都快),这种人为的复杂性导致系统越来越臃肿,越来越难维护,酱缸的老代码发出一阵阵恶臭,新来的同学,往往要捂着鼻子抠几天甚至几个月,才能理清系统和业务脉络,然后又一头扎进各种bug fix,业务修补的恶性循环中,暗无天日!
    image.png
    CRM作为阿里最老的应用系统,自然也逃不过这样的宿命。不甘如此的我们开始反思到底是什么造成了系统复杂性? 我们到底能不能通过架构来治理这种复杂性?基于这个出发点,我们团队开始了一段非常有意义的架构重构之旅(Redefine the Arch),期间我们参考了SalesForce,TMF2.0,汇金和盒马的架构,从他们那里汲取了很多有价值的输入,再结合我们自己的思考最终形成了我们自己现在的基于扩展点+元数据+CQRS+DDD的应用架构。该架构的特点是可扩展性好,很好的贯彻了OO思想,有一套完整的规范标准,并采用了CQRS和领域建模技术,在很大程度上可以降低应用的复杂度。本文主要阐述了我们的思考过程和架构实现,希望能对在路上的你有所帮助。

    复杂性来自哪里

    经过我们分析、讨论,发现造成现在系统异常复杂的罪魁祸首主要来自以下四个方面:

    可扩展性差

    对于只有一个业务的简单场景,并不需要扩展,问题也不突出,这也是为什么这个点经常被忽略的原因,因为我们大部分的系统都是从单一业务开始的。但是随着支持的业务越来越多,代码里面开始出现大量的if-else逻辑,这个时候代码开始有坏味道,没闻到的同学就这么继续往上堆,闻到的同学会重构一下,但因为系统没有统一的可扩展架构,重构的技法也各不相同,这种代码的不一致性也是一种理解上的复杂度。久而久之,系统就变得复杂难维护。像我们CRM应用,有N个业务方,每个业务方又有N个租户,如果都要用if-else判断业务差异,那简直就是惨绝人寰。其实这种扩展点(Extension Point),或者叫插件(Plug-in)的设计在架构设计中是非常普遍的。比较成功的案例有eclipse的plug-in机制,集团的TMF2.0架构。还有一个扩展性需求就是字段扩展,这一点对SaaS应用尤为重要,因为有很多客户定制化需求,但是我们很多系统也没有统一的字段扩展方案。

    面向过程

    是的,不管你承认与否,很多时候,我们都是操着面向对象的语言干着面向过程的勾当。面向对象不仅是一个语言,更是一种思维方式。在我们追逐云计算、深度学习、区块链这些技术热点的时候,静下心来问问自己我们是不是真的掌握了OOD;在我们强调工程师要具备业务Sense,产品Sense,数据Sense,算法Sense,XXSense的时候,是不是忽略了对工程能力的要求。据我观察大部分工程师(包括我自己)的OO能力还远没有达到精通的程度,这种OO思想的缺乏主要体现在两个方面,一个是很多同学不了解SOLID原则,不懂设计模式,不会画UML图,或者只是知道,但从来不会运用到实践中;另一个是不会进行领域建模,关于领域建模争论已经很多了,我的观点是DDD很好,但不是银弹,用和不用取决于场景。但不管怎样,请你抛开偏见,好好的研读一下Eric Evans的《领域驱动设计》,如果有认知升级的感悟,恭喜你,你进阶了。我个人认为DDD最大的好处是将业务语义显现化,把原先晦涩难懂的业务算法逻辑,通过领域对象(Domain Object),统一语言(Ubiquitous Language)将领域概念清晰的显性化表达出来。相信我,这种表达带来的代码可读性的提升,会让接手你代码的人对你心怀感恩的。借用Abelson的一句话是

    Programs must be written for people to read, and only incidentally for machines to execute

    所以强烈谴责那些不顾他人感受的编码行为。

    分层不合理

    俗话说的好,All problems in computer science can be solved by another level of indirection(计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决),怎样? 是不是感受到间接层的强大了。分层最大的好处就是分离关注点,让每一层只解决该层关注的问题,从而将复杂的问题简化,起到分而治之的作用。我们平时看到的MVC,pipeline,以及各种valve的模式,都是这个道理。好吧,那是不是层次越多越好,越灵活呢。当然不是,就像我开篇说的,过多的层次不仅不能带来好处,反而会增加系统的复杂性和降低系统性能。就拿ISO的网络七层协议来说,你这个七层分的很清楚,很好,但也很繁琐,四层就够了嘛。再比如我前面提到的过度设计的例子,如果没记错的话应该是Apple的Directory Service应用,整个系统有7层之多,把什么validator,assembler都当成一个层次来对待,能不复杂么。所以分层太多和没有分层都会导致系统复杂度的上升,因此我们的原则是不可以没有分层,但是只分有必要的层。

    随心所欲

    随心所欲是因为缺少规范和约束。这个规范非常非常非常的重要(重要事情说三遍),但也是最容易被无视的点,其结果就是架构的consistency被严重破坏,代码的可维护性将急剧下降,国将不国,架构将形同虚设。有同学会说不就是个naming的问题么,不就是个分包的问题么,不就是2个module还是3个module的问题么,只要功能能跑起来,这些问题都是小问题。是的,对于这些同学,我再丢给你一句名言“Just because you can, doesn't mean you should"。就拿package来说,它不仅仅是一个放一堆类的地方,更是一种表达机制,当你将一些类放到Package中时,相当于告诉下一位看到你设计的开发人员要把这些类放在一起考虑。理想很丰满,现实很骨感,规范的执行是个大问题,最好能在架构层面进行约束,例如在我们架构中,扩展点必须以ExtPt结尾,扩展实现必须以Ext结尾,你不这么写就会给你抛异常。但是架构的约束毕竟有限,更多的还是要靠Code Review,暂时没想到什么更好的办法。这种对架构约束的近似严苛follow,确保了系统的consistency,最终形成了一个规整的收纳箱(如下图所示),就像我和团队说的,我们在评估代码改动点时,应该可以像Hash查找一样,直接定位到对应的module,对应的package里面对应的class。而不是到“一锅粥”里去慢慢抠。
    image.png
    本章节最后,上一张我们老系统中比较典型的代码,也许你可以从中看到你自己应用的影子。
    sample.png

    复杂性应对之道

    知道了问题所在,接下来看下我们是如何一个个解决这些问题的。回头站在山顶再看这些解决方案时,每个都不足为奇,但当你还“身在此山中”的时候,这个拨开层层迷雾,看到山的全貌的过程,并不是想象的那么容易。庆幸的是我团队在艰难跋涉之后,终有所收获。

    扩展点设计

    扩展点的设计思想主要得益于TMF2.0的启发,其实这种设计思想也一直在用,但都是在局部的代码重构和优化,比如基于Strategy Pattern的扩展,但是一直没有找到一个很好的固化到框架中的方法。直到毗卢到团队分享,给了我们两个关键的提示,一个是业务身份识别,用他的话说,如果当时TMF1.0如果有身份识别的话,就没有TMF2.0什么事了;另一个是抽象的扩展点机制。

    身份识别

    业务身份识别在我们的应用中非常重要,因为我们的CRM系统要服务不同的业务方,而且每个业务方又有多个租户。比如中供销售,中供拍档,中供商家都是不同的业务方,而拍档下的每个公司,中供商家下的每个供应商又是不同的租户。所以传统的基于多租户(TenantId)的业务身份识别还不能满足我们的要求,于是在此基础上我们又引入了业务码(BizCode)来标识业务。所以我们的业务身份实际上是(BizCode,TenantId)二元组。在每一个业务身份下面,又可以有多个扩展点(ExtensionPoint),所以一个扩展点实现(Extension)实际上是一个三维空间中的向量。借鉴Maven Coordinate的概念我给它起了个名字叫扩展坐标(Extension Coordinate),这个坐标可以用(ExtensionPoint,BizCode,TenantId)来唯一标识。
    image.png

    扩展点

    扩展点的设计是这样的,所有的扩展点(ExtensionPoint)必须通过接口申明,扩展实现(Extension)是通过Annotation的方式标注的,Extension里面使用BizCode和TenantId两个属性用来标识身份,框架的Bootstrap类会在Spring启动的时候做类扫描,进行Extension注册,在Runtime的时候,通过TenantContext来选择要使用的Extension。TenantContext是通过Interceptor在调用业务逻辑之前进行初始化的。整个过程如下图所示:
    image.png

    面向对象

    面向对象不仅是一种编程语言,更是一种思维模式。所以看到很多简历里面写“精通Java”,没写“精通OO”,也算是中肯,因为会Java语言并不代表你就掌握了面向对象思维(当然,精通Java也不是件易事),要想做到精通,必须要对OO设计原则,模式,方法论有很深入的理解,同时要具备非常好的业务理解力和抽象能力,才能说是精通,这种思维的训练是一个长期不断累积的过程,我也在路上,下面是我对面向对象设计的两点体会:

    SOLID

    SOLID是单一职责原则(SRP),开闭原则(OCP),里氏替换原则(LSP),接口隔离原则(ISP)和依赖倒置原则(DIP)的缩写,原则是要比模式(Design Pattern)更基础更重要的指导准则,是面向对象设计的Bible。深入理解后,会极大的提升我们的OOD能力和代码质量。比如我在开篇提到的ServiceImpl上帝类的例子,很明显就是违背了单一职责,你一个类把所有事情都做了,把不是你的功能也往自己身上揽,所以你的内聚性就会很差,内聚性差将导致代码很难被复用,不能复用,只能复制(Repeat Yourself),其结果就是一团乱麻。
    image.png
    再比如在java应用中使用logger框架有很多选择,什么log4j,logback,common logging等,每个logger的API和用法都稍有不同,有的需要用isLoggable()来进行预判断以便提高性能,有的则不需要。对于要切换不同的logger框架的情形,就更是头疼了,有可能要改动很多地方。产生这些不便的原因是我们直接依赖了logger框架,应用和框架的耦合性很高。怎么破? 遵循下依赖倒置原则就能很容易解决,依赖倒置就是你不要直接依赖我,你和我都同时依赖一个接口(所以有时候也叫面向接口的编程),这样我们之间就解耦了,依赖和被依赖方都可以自由改动了。
    image.png
    在我们的框架设计中,这种对SOLID的遵循也是随处可见,Service Facade设计思想来自于单一职责SRP;扩展点设计符合关闭原则OCP;日志设计,以及Repository和Tunnel的交互就用到了依赖倒置DIP原则,这样的点还有很多,就不一一枚举了。当然了,SOLID不是OO的全部。抽象能力,设计模式,架构模式,UML,以及阅读优秀框架源码(我们的Command设计就是参考了Activiti的Command)也都很重要。只是SOLID更基础,更重要,所以我在这里重点拿出来讲一下,希望能得到大家的重视。

    领域建模

    准确的说DDD不是一个架构,而是思想和方法论。所以在架构层面我们并没有强制约束要使用DDD,但对于像我们这样的复杂业务场景,我们强烈建议使用DDD代替事务脚本(TS: Transaction Script)。因为TS的贫血模式,里面只有数据结构,完全没有对象(数据+行为)的概念,这也是为什么我们叫它是面向过程的原因。然而DDD是面向对象的,是一种知识丰富的设计(Knowledge Rich Design),怎么理解?,就是通过领域对象(Domain Object),领域语言(Ubiquitous Language)将核心的领域概念通过代码的形式表达出来,从而增加代码的可理解性。这里的领域核心不仅仅是业务里的“名词”,所有的业务活动和规则如同实体一样,都需要明确的表达出来。例如前面典型代码图中所展示的,分配策略(DistributionPolicy)你把它隐藏在一堆业务逻辑中,没有人知道它是干什么的,也不会把它当成一个重要的领域概念去重视。但是你把它抽出来,凸显出来,给它一个合理的命名叫DistributionPolicy,后面的人一看就明白了,哦,这是一个分配策略,这样理解和使用起来就容易的多了,添加新的策略也更方便,不需要改原来的代码了。所以说好的代码不仅要让程序员能读懂,还要能让领域专家也能读懂。
    再比如在CRM领域中,公海和私海是非常重要领域概念,是用来做领地(Territory)划分的,每个销售人员只能销售私海(自己领地)内的客户,不能越界。但是在我们的代码中却没有这两个实体(Entity),也没有相应的语言和其对应,这就导致了领域专家描述的,和我们日常沟通的,以及我们模型和代码呈现的都是相互割裂的,没有关联性。这就给后面系统维护的同学造成了极大的困扰,因为所有关于公海私海的操作,都是散落着各处的repeat itself的逻辑代码,导致看不懂也没办法维护。所以当尚学把这两个领域概念抽象成实体之后,整个模型和代码都一下子变清晰很多。在加上上面介绍的把业务规则显现化,极大的提升了代码的可读性和可扩展性。用尚学的话说,用DDD写代码,他找到了创作的感觉,而不仅仅是码农式Coding。下图是销售域的简要领域模型,但基本上能表达出销售域的核心领域概念。
    image.png
    关于CQRS简要说一下,我们只使用了Command,Query分离的概念,并没有使用Event Sourcing,原因很简单---不需要。关于Command的实现我们使用了命令模式,因此以前的ServiceImpl的职责就只是一个Facade,所有的处理逻辑都在CommandExecutor里面。

    分层设计

    这一块的设计比较直观,整个应用层划分为三个大的层次,分别是App层,Domain层和Repostiory层。

    • App层主要负责获取输入,组装context,做输入校验,发送消息给领域层做业务处理,监听确认消息,如果需要的话使用MetaQ进行消息通知;
    • Domain层主要是通过领域服务(Domain Service),领域对象(Domain Object)的交互,对上层提供业务逻辑的处理,然后调用下层Repository做持久化处理;
    • Infrastructure层主要包含Repository,Config和Common,Repository负责数据的CRUD操作,这里我们借用了盒马的数据通道(Tunnel)的概念,通过Tunnel的抽象概念来屏蔽具体的数据来源,来源可以是MySQL,NoSql,Search,甚至是HSF等;Config负责应用的配置;Common是一写工具类;负责message通信的也应该放在这一层。 image.png这里需要注意的是从其他系统获取的数据是有界上下文(Bounded Context)下的数据,为了弥合Bounded Context下的语义Gap,通常有两种方式,一个是用大领域(Big Domain)把两边的差异都合起来,另一个是增加防腐层(Anticorruption Layer)做转换。什么是Bounded Context? 简单阐述一下,就是我们的领域概念是有作用范围的(Context)的,例如摇头这个动作,在中国的Context下表示NO,但是在印度的Context下却是YES。

    规范设计

    我们规范设计主要是要满足收纳原则的两个约束:

    放对位置

    东西不要乱放,我们的每一个组件(Module),每一个包(Package)都有明确的职责定义和范围,不可以放错,例如extension包就只是用来放扩展实现的,不允许放其他东西,而Interceptor包就只是放拦截器的,validator包就只是放校验器的。我们的主要组件如下图:
    image.png
    组件里面的Package如下图:
    image.png

    贴好标签

    东西放在合适位置后还要贴上合适的标签,也就是要按照规范合理命名,例如我们架构里面和数据有关的Object,主要有Client Object,Domain Object和Data Object,Client Object是放在二方库中和外部交互使用的DTO,其命名必须以CO结尾,相应的Data Object主要是持久层使用的,命名必须以DO结尾。这个类名应该是自明的(self-evident),也就是看到类名就知道里面是干了什么事,这也就反向要求我们的类也必须是单一职责的(Single Responsibility)的,如果你做的事情不单纯,自然也就很难自明了。如果我们Class Name是自明的,Package Name是自明的,Module Name也是自明的,那么我们整个应用系统就会很容易被理解,看起来就会很舒服,维护效率会提高很多。我们的命名规则如下图所示:
    image.png

    SOFA应用架构

    经过上面的长篇大论,我希望我把我们的架构理念阐述清楚了,最后再从整体上看下我们的架构吧。我讲这个架构命名为SOFA,全称是Simple Object-oriented and Flexible Architecture,是一个轻量级的面向对象的,可扩展的应用架构,可以帮助降低复杂应用场景的系统熵值,提升系统开发和运维效率。
    image.png
    目前框架也准备开源,贡献个社区,让更多的开发者使用,帮助解决他们各自的业务复杂度。
    关于框架源码和介绍,请移步:https://github.com/alibaba/SOFA/

    整体架构

    我们的架构原则很简单,即在高内聚,低耦合,可扩展,易理解大的指导思想下,尽可能的贯彻OO的设计思想和原则。我们最终形成的架构是集成了扩展点+元数据+CQRS+DDD的思想,关于元数据前面没怎么提到,这里稍微说一下,对于字段扩展,简单一点的解决方案就是预留扩展字段,复杂一点的就是使用元数据引擎。使用元数据的好处是不仅能支持字段扩展,还提供了丰富的字段描述,等于是为以后的SaaS化配置提供了可能性,所以我们选择了使用元数据引擎。和DDD一样,元数据也是可选的,如果对没有字段扩展的需求,就不要用。最后的整体架构图如下:
    image.png

    提效工具

    Archetype

    因为框架包含了5个Module,20+的Package,如果手动创建的话很费时,而且很容易出错,所以创建了这个Archetype,可以一键构建框架的所有Artifacts,使用时,只需要将下面的命令中的demo替换成自己应用的名字即可:

    mvn archetype:generate  -DgroupId=com.alibaba.crm -DartifactId=demo -Dversion=1.0.0-SNAPSHOT -Dpackage=com.alibaba.crm.demo -DarchetypeArtifactId=sofa-framework-archetype -DarchetypeGroupId=com.alibaba.sofa -DarchetypeVersion=1.0.0-SNAPSHOT
    

    测试容器

    不管你是不是TDD吧,写几行代码,然后本地跑下测试验证一下总是个不错的习惯。因为代码还是热的,出错也容易定位。但是本地启动PandoraBoot可不是个省心的事,我这台2.3G双核平均也要4分钟,严重的影响了效率。所以开发了这个工具,就是等PandoraBoot启动后,将线程Hold住,然后通过Console控制台输入要测试的方法或者类。使用这个工具很简单。
    首先依赖crm-test:

    1.  
      <dependency>
    2.  
      <groupId>com.alibaba.crm</groupId>
    3.  
      <artifactId>crm-test</artifactId>
    4.  
      <version>1.0.0-SNAPSHOT</version>
    5.  
      <scope>test</scope>
    6.  
      </dependency>

    然后将TestApplication修改如下即可:

      1.  
        public class TestApplication {
      2.  
        public static void main(String[] args) {
      3.  
        PandoraBootstrap.run(args);
      4.  
        SpringApplication.run(Application.class, args);
      5.  
        TestsContainer.start();//启动测试容器,避免重复启动PandoraBoot
      6.  
        }
      7.  
        }

    统一语言

    正在阅读《发现你的优势》,感觉其内容平平,无外乎就是一种积极心理学,强调注重强化自身优势,而不是一味的克服弱点... 正在觉得乏善可陈的时候,看到了一个亮点,即发现优势的第三个革命工具- 用来描述你自身才干的统一语言。

    也就是书中对优势进行描述的34个标签,积极(Positivity),包容(Inclusiveness),完美(Maximizer)等等

    那么为什么统一语言显得这么重要?

    语言是我们了解事物,获取知识的重要途径,任何一个概念,任何一项技能,无不是通过语言或语言的文本形式(文字)来进行传授和获取的。 一套统一的词汇表,对于沟通来说非常重要,用统一的词汇使得沟通变得高效,使得沟通的过程变得轻松愉快。为什么中国人说英语外国人不容易理解? 因为你用的词汇和别人惯用的词汇不一样,所以沟通起来就有困难,憋屈。

    对于程序员来说,在职场上,用统一的技术词汇沟同样通至关重要,记得当时在看程序员必读的《设计模式》时,里面就有提到《设计模式》的一个重要价值就是提供了工程师之间对常见设计模式进行沟通的统一词汇表,比如A君说这个地方我们应该用观察者去监听通知,又或是B君说我们一个用适配器去解决新老接口不一致情况,作为一个有专业素养的猿,你应该很快就能体会到对方所要表达的意思,而不用A花时间去解释什么是观察者,这样的沟通无疑是高效的,在凸显你的专业性的同时,也增加了沟通的愉快性,为什么呢?因为每个人都有被理解的需要,古人也说“他乡遇故知” 是人生最美妙的事情,你理解他说的话,满足了他被理解的需求,变成了他的故知,还有什么比这个更惬意,更让人愉快的事呢?所以说 “ 士为知己者死 ”嘛

    还有就是最近去阿里面试的经历,与其说是面试,不如说是愉快的聊天,之后阿里也非常爽快的给了我一个较高的offer,之所以有这样的结果,我想可能和我一直在eBay工作从事的也是电商的工作有关系吧,因为都是电商,大家有了彼此都通的听得懂的词汇表,所以沟通起来自然轻松愉快。

    “我们之间没有共同语言” ,说的也是大家缺少一套能够沟通的统一语言,统一词汇,也就是大家在精神上没有交集。通常被追求者拒绝追求者的时候喜欢以此为借口,所以说如果你要追求你心目中的女神或男神的时候,记住要尽量向TA的语言靠拢,什么意思呢? 就是好君子之所好,用他所熟悉和舒服的语言沟通,比如TA喜欢篮球,你就跟他聊两双,聊控卫,聊勒布朗詹姆斯,保证事半功倍。

    由此可见,无论是在生活上,职场上,情场上,统一的语言,大家都能理解的词汇表都是高效沟通的重要基石。如果你想让你的沟通对象愉快,就用他能理解的词汇去说话吧, talking in their shoes, a relax and harmony climate will be automatically created.

    如果你发现你的字典里,缺少这些沟通必备的词汇表,请通过学习来补充吧,当然我们也可以主动创造属于自己的词汇,从而影响身边的人

    from:

    https://blog.csdn.net/significantfrank/article/details/91974397

    https://blog.csdn.net/significantfrank/article/details/79286947

    https://blog.csdn.net/significantfrank/article/details/35274599

  • 相关阅读:
    数据导入和导出
    用户登陆案例
    SQLHelper
    把连接数据库的字符串放在配置文件中
    访问数据库
    SQL语句
    Django Tornado Flask
    Python 的协程
    面试 Better Call Soul
    mklink 解决VScode 扩展...Google迁移到 windows D盘
  • 原文地址:https://www.cnblogs.com/Chary/p/13523582.html
Copyright © 2020-2023  润新知