作者 | 黄东旭,PingCAP 联合创始人&CTO

出品 | CSDN(ID:CSDNnews)

业界一直流传着黄东旭的传说:小学三年级开始写代码,四五年级学习C语言,初中毕业时,已经能够用 Visual Basic 做一些小工具的开发。高中开始用 Linux,还玩摇滚、会画画……编程对他而言,从不是糊口的手艺,而是真正的热爱。对于所热爱的事业,黄东旭在追求完美和极致这条路上越走越远。其设计的开源分布式关系型数据库 TiDB 从2015年创建并在 GitHub 上开源,到成为全球顶级的开源项目,用了不到两年时间。目前,TiDB 在 GitHub 获得了  27.4k 个 star,用黄东旭的话说,“我们诞生在中国,却玩出了世界级技术。”

重点速览:

  • 网络效应对基础软件的意义:基础软件是被“用”出来的,不是“写”出来的;迭代和进化速度是这类软件的核心竞争力。这两点恰恰是网络效应能带来的。

  • 社区的诞生时刻:在 GitHub 上开放你的源代码,甚至使用公开的 Git 工作流,都不是社区诞生的时刻。一个社区真正诞生,是在你和你的代码之外,开始有第三者介入并产生连接的时刻。

  • 社区运营:很多人认为开源社区是竞争壁垒,其实并不是,真正的壁垒是生态,而开源社区是构建生态的一种高效方式。对于社区运营者来说,最关键的任务不是让沉默者更多或更深度地使用,而是让他们和网络中的其他用户建立更多的连接。

  • 社区运营的最高境界:将网络效应从使用者的网络效应转移到基于信仰的网络效应,将社区中心从开源公司内部转移到外部以获得更大的势能。

  • 开源软件的死亡鸿沟:对于一个开源软件,鸿沟的体现可能是经历早期快速增长后,来到长达 1~2 年的静默期,如果熬不过去就是“死亡鸿沟”。

  • 社区和商业化的矛盾:虽然开源软件商业公司的第一目标是客户成功,但这和做好社区并不矛盾。一个常见的误区是在开源软件公司内部,这两个团队形成对立关系。由于社区和商业这两个团队的内部一致性是:好产品和经典场景。所以比较好的做法是,社区团队聚焦于两个关键点:社区用户对于产品的打磨;发现更多的典型场景。

  • 开源软件公司如何规模化变现:传统开源软件公司的商业模式,问题在于规模化中需要人的介入,销售/售前/售后交付等等,而基于人的生意是没法规模化的。在云诞生前这个问题是无解的,开源软件公司需要寻找一个和开源无关的软件商业模式,而云本质上是一个资源租赁生意。

  • 伟大的开源基础软件产品:一个伟大的基础软件产品不仅仅是解决眼下的具体问题,而是开启一片新的天地,一个新的视角,创造新的可能性。

前些天在与友人喝咖啡的时候,正好聊到关于 PingCAP 和 TiDB 的一些历史以及对于开源软件公司核心竞争力的理解,回顾这几年的创业生涯和 TiDB 社区的生长壮大,就像是一场巨大且正在进行中的社会学实验,原本零散的一些想法随着一条主线变得逐渐清晰,就想着写成文章总结一下关于社区对于开源软件以及开源公司到底意味着什么。

无处不在的网络效应

1、两种网络效应

很多人听说过网络效应(梅特卡夫效应:网络的价值与联网用户的平方数成正比),许多伟大的产品和公司通过网络效应构建起了强大的护城河。提到网络效应,经典例子在通信领域,例如手机,每多一个用户,对于所有用户的价值就越大,虽然大家也无意为他人创造价值,但是一旦开始使用,该行为就会帮助这个网络创造价值。很多我们熟知的 to C公司,尤其是社交网络和IM(即时通信软件) ,通过这个效应构建了极高的壁垒。NfX Venture 在他们的一篇博客(https://www.nfx.com/post/network-effects-manual/)中详细描述了很多种网络效应,在介绍社区之前,我想着重介绍下其中和开源软件相关的两种网络效应。

  • 基于从众心理的网络效应

这类网络效应通常是从一些意见领袖开始,可能是行业大咖,可能是社交潮人,常常出现在一个新产品要去进攻一个老产品的市场时。尽管这个新产品相比市场的统治者来说不一定成熟,但它通常会带着一些鲜明的特色或者更加前沿的理念,吸引那些对「主流」不满或者希望突显自身前沿视野的意见领袖的支持,造成一种「很酷的人都在用,你不用你就要被淘汰了」的感觉。

这种感觉会在新用户纷纷加入时,形成从众心理的网络效应,但是这类网络效应的持续时间不会太长。细想一下就能知道:如果早期意见领袖只是因为突显「不同」而加入,那么在这个社区成为主流后,这些意见领袖就没有理由留下,追随这些人的粉丝可能会随之而去。另外,对于这个新产品来说,完善程度通常不如老产品,美誉和差评会在早期同时到来。此时,如果不快速通过网络效应打磨产品,获得更好的迭代速度,那么,这个网络效应是根基不牢的。一个好处在于,该效应在早期是事半功倍的。

回想 TiDB 早期的社区建设,也是因为几个创始人在 Codis 的工作以及在国内基础软件圈中积累的名声,和一些互联网技术圈中朋友的支持,形成最早的背书。

  • 基于信仰的网络效应

所谓「信仰」,就是基于对一个理念的认可而加入,从而形成网络效应。这点在软件领域也不少见,自由软件运动和开源运动都是很好的例子。人嘛,总是要相信点什么。这类网络效应的护城河是极深的,而且对于产品缺陷的容忍度极高。因为信念是一个长期的念想,对于 TiDB 来说,这个念想形如:相信分布式是未来,相信云时代的业务需要像 TiDB 这样的数据库。但是这个目标又是足够有挑战的,值得长期为之努力。

基于信仰的网络效应可能在最早期和从众心理网络效应有点类似,其中的关键是社区核心人群对于产品背后的理念是否有坚定信仰。反之,如果只是简单地秀优越感,是不会长久的,随着兴趣衰减,网络效应也会崩塌。

2、网络效应对于基础软件的意义

对于基础软件来说,我一直坚持两个观点:

  • 基础软件是被“用”出来的,不是“写”出来的

  • 迭代和进化速度是这类软件的核心竞争力

这两点恰恰是网络效应能带来的,虽然价值链条不像IM那样明显,但是,网络效应存在的基础是新用户给老用户带来的额外价值。而基础软件的价值,体现为以下几点:

  • 可控的风险(稳定性)

  • 更多的场景适应性(发现新的适用场景和持续提升性能)

  • 良好的易用性

对于风险控制来说,越多人用意味着风险被越多人均摊,其中的一个假设是:我不特别,我遇到的问题别人应该也遇到过,一定有人能比我早发现并修复它。这个假设在一个成熟且活跃的基础软件社区是成立的,因为基础软件的场景边界相对清晰,在适用范围内的路径大致相同,同一条路径走多了,坑自然就少了。只要有一个人踩到坑,反馈回社区,不管最后是谁修好的,这个行为对于其他用户都是受益的。

同样的逻辑,对于场景适应性来说也成立。个体的认知总是带有局限性,即使是项目的创始团队,也不见得对于某个具体的应用场景有深刻理解。社区用户的创造力是无穷的,一些设计外的使用路径可能会出奇地好用,从而发展出新的优势场景。同样地,只要有一个成功案例,那么对于其他具有相似场景的用户来说,软件的价值就增加了, TiDB 和 Flink 组合成的实时 HTAP 数据处理方案,就是一个很好的例子。

对于易用性改进的逻辑和稳定性类似,我就不赘述了。利用网络效应带来的飞轮效应改进软件,这个思路我在《大教堂终将倒下,但集市永存》一文中也提到过。

社区的成熟度曲线和必经阶段

1、社区的诞生

在 GitHub 上开放你的源代码,甚至使用公开的 Git 工作流,都不是社区诞生的时刻。一个社区真正诞生,是在你和你的代码之外,开始有第三者介入并产生连接的时刻,可能是收到第一个外部 PR,可能是收到第一个外部 issue,这些才是社区的开端。社区始于连接,也成就于连接。开放源代码并不等同于开源,很多团队和项目在开放源代码方面花费了很多时间,却忽略了代码及背后团队的社区化,这是很可惜的。

2、死亡鸿沟和希望之坡

就像《跨越鸿沟》这本书中提到的,开源软件也有自己的生命周期曲线,这是和社区息息相关的。

图中断层出现的原因是产品成熟度迟迟没有跟上,用户过来以后发现都是坑,随之而来的各种差评会让早期支持者和创始人疲于奔命甚至而失去兴趣。

对于一个开源软件,断层的体现可能是经历早期快速增长后,来到长达 1~2 年的静默期,增长几乎停滞。对于社区来说,几乎所有的精力都用在给早期用户填坑,期间会有用户自然增长但流失率也非常高。这个阶段对于资源的消耗非常大,社区的核心贡献者也会非常累,如果熬不过去就死了,所以说是“死亡鸿沟”。

好消息是,这个阶段终将会过去,bug 这种东西嘛,改掉一个就少一个,产品也会在这个阶段逐渐摸索到自己的定位和最佳实践,而在最佳实践这个路径上,产品会变得越来越稳定和聚焦。如果定位是市场刚需,那么就会迎来一个高速增长阶段(成熟期),而社区的生态也会随着产品的普及开始加速度发展。这个从上图的 Kubernetes 和 TiDB 的搜索指数里面能看到这个鸿沟的一个侧写。

3、社区的终局

一个好的开源软件社区的终局会是什么样子?对于这个问题,其实我们有很多能参考的例子,例如 GNU Linux、Hadoop、Spark、MySQL 等等。我认为,不管一个开源软件及社区是由商业公司发起还是其他方式发起、壮大,到最后一定会出现独立于某公司之外的中立组织来接管这个社区,这也是最自然合理的方式。

尤其是公司主导的开源项目,在后期会面临中立性的问题。因为对于公司而言,最重要的是客户成功,对商业化的诉求一定会影响开源软件功能设置和开发优先级。而且优先级往往是会变的(可能更紧急且更具体),变化也许会和社区的开发节奏冲突,但我不认为这两者的矛盾不可调和,我会在下文展开来讲。

中后期的开源软件已经支撑着太多用户的场景成功和商业利益,由一个中立的委员会来平衡各方的利益及监督各方的责任是目前看来比较成功的实践,而且开始有这样的组织,也从侧面说明这个项目已经成熟,已经有良好的生态。还没有到达这个阶段的开源软件大多是由项目背后的公司主导社区,在项目成熟阶段,重点是不断地通过优化客户和场景的成功让整个飞轮转动起来,当主导公司之外有越来越多的成员在思考和实践 governance rule,这就是一个积极的信号。

社区和商业化如何共存

1、种地和做菜 & 河与岸上的人

前文留下一个问题,就是开源与商业化的矛盾,不管我如何解释,本质上开源和传统的软件售卖模式一定是冲突的。

我举一个比较好理解的例子:如果将开源比作种菜,开源软件源代码相当于种子,业务成功相当于长出来的菜,传统的软件商业模式类似于卖种子,但是种地施肥(hosting)都是客户自己的工作。开源软件的种子是免费的,地是客户的,种地的人也是客户的人,所以开源厂商大概只能提供种地指导服务,尤其在一些种子不是太好种的情况下,指导服务是有意义的。但仔细想想,随着种子不断改良(性能、稳定性、易用性等),随便撒到地里就能开花结果,那么专业的种菜服务就没什么必要性了。于是厂商只好卖一些额外的价值,比如保险服务,万一种子生长遇到极端天气,至少有专家团在背后帮忙解决。但是这种商业模式仍然比较别扭,因为价值链条大部分都在客户自己这边。所以,如果厂商看待社区只停留在潜在客户视角,很难做出好产品,因为没有内在动力去持续优化软件。

一个更好的视角是往后退一步,我再举个好理解的例子:将社区当成一条河流,不属于任何人,大家共同保持河水的清澈和流动性,谁都不要过度捞鱼,不同的组织和个人都可以在河流周边构建自己的生态,至于岸上的人靠什么挣钱,那是另外一个问题,后文再讲。

2、客户成功和用户体验:内在的一致性

虽然开源软件商业公司的第一目标是客户成功,但这和做好社区并不矛盾。一个常见的误区是在开源软件公司内部,这两个团队形成对立关系。商业团队认为社区就是给商业化养鱼的,养肥了就要收割,极端点就动不动要闭源;社区团队认为商业化会减慢生态传播的速度,使用门槛上升,极端做法是产生反商业化的倾向。如果都只在自己的位置上思考问题,当然双方都没错,那到底是哪里有问题呢?

问题出在了“阶段”和“客户选择”,社区用户和商业用户使用开源软件的生命周期可能完全不同,一般的开源软件公司会有两个漏斗,我称之为社区漏斗和商业漏斗。有些说法认为社区漏斗是商业漏斗的上层,我之前也深以为然,但经过几年的实践,我渐渐发现其实并不是那样。这两者是独立的,如果只是简单地作为一个漏斗,那么就会有很多问题,比如经典问题:不会流到商业漏斗的社区用户,其价值到底是什么?所以,肯定不是一个漏斗,而是有很深的内部联系。

什么联系?为方便理解,还是用种菜举例说明。开源社区孵化出来的东西,例如用户成功案例、社区贡献对产品的打磨、探索出来的适用场景等,就像一个个生的菜和食材,而客户想要一盘鱼香肉丝,并不关心盘子中的肉和菜是怎么来的,所以看到关键点了吗?商业化团队的角色就像是厨师,社区运营团队就像农民,二者的关注点并不一样,厨师关注点是如何做好菜,农民的关注点是如何种好地,产生更好的食材。从食材到一道菜,还要经历很长的过程,但没有好食材,能力再强的厨师也难做出一盘好菜。

对于开源软件公司来说,社区和商业这两个团队的内部一致性是:好产品和制胜场景。根据我们的实践经验,比较好的做法是,社区团队聚焦于两个关键点:

  • 社区用户对于产品的打磨(在制胜场景下)

  • 发现更多的制胜场景

这两个关键点会形成闭环,社区团队持续产生食材(制胜场景以及持续进化的产品),商业团队聚焦于制胜场景的进一步加工和客户旅程优化,两个团队互相配合拉动整个公司和项目的大循环。例如TiDB商业用户的场景和解决方案,大多是从社区用户中诞生并打磨成熟,尽管可能两个用户群体完全不一样,但是通过 TiDB 形成了一个大的生态——商业化的循环,而PingCAP 就是中间的桥梁。另外,社区和商业化团队会有一个共同的北极星指标:用户体验。

3、可规模化变现的唯一出路:云

一个好的生意应该是可以规模化的,传统开源软件公司的商业模式,问题在于规模化中需要人的介入,销售/售前/售后交付等等,而基于人的生意是没法规模化的。在云诞生前这个问题是无解的,所以开源软件公司需要寻找一个和开源无关的软件商业模式(听起来有点别扭,但是仔细想想确实如此),而云本质上是一个资源租赁生意。

还是以种菜的例子来说,过去传统的商业模式中,因为土地和种菜人都是客户自己的,所以开源软件公司的位置就比较尴尬,但是在云上,基础软件商业模式本质上是一个hosting服务,让原来价值链条中最重要的一部分“土地”( hosting资源和基础设施)掌握在了厂商手上,这对于用户来说也是好的,毕竟管理“土地”也是一件费心费力的事情,而且很难做到按需购买。问题在于用户想要的只是一道好菜而已,注意这和开源(种菜)并没有什么关系,因为不管开不开源,用户支付的都是管理和租赁费用,相当于即使种子和食材免费,顾客去饭店吃饭,也需要为菜品买单,因为顾客购买的是好菜和服务体验。

另外,很多人认为开源社区是竞争壁垒,其实并不是,真正的壁垒是生态,而开源社区是构建生态的一种高效方式,如果一个产品不用开源也构建起了生态,那么效果是一样的。一个很好的例子就是 Snowflake,尽管 Snowflake 没有开源,但是2012年诞生伊始,它在云数据仓库这个市场内几乎没有任何竞争对手,留给 Snowflake 足够的时间通过差异化定位和极佳的用户体验构建自己的生态,依托云的崛起和规模化效应取得了巨大成功。

如何做好社区

上文形而上地讨论了很多关于哲学的内容,接下来聊聊落地实践。想要做好开源社区其实是有方法论的,但前提是有正确的思考方式和思考角度,否则在实践环节你就会发现有无数事情可以做,却不知道哪件或哪些事情是更重要的,更难受的是你发现没法衡量对与错。以下是我的一些思考角度以及思考时考虑的重点指标,可作为社区运营者的参考。

1、你是谁?你解决了什么问题?为什么是你?

好社区的根基一定是好产品,要回答“你是谁”这个问题,一定是通过回答“你解决了什么问题”而得出的,这点和 to C 产品的运营很不一样。一些社区运营者会将注意力转移到各种活动或者宣传拉新,同时夸大产品能力,导致与现实不符,这是最常见的误区。

很多做社区运营的朋友经常来找我:我也做了很多活动,写了很多文章,为什么看起来没有效果?通常这个时候我会问他:你能一句话说明白你的产品是做什么的吗?到底解决了什么问题?这个问题是普遍问题吗?非你这个产品不可吗?这个时候他就明白:完美的产品是不存在的,好的产品一定是跟随它的优势场景出现的,比如 Redis 显然不能用来做核心金融交易场景,但谁都不会否认Redis在缓存场景下是当之无愧的事实标准。同样的例子还有很多,例如 Spark、ClickHouse 等等。所以对于运营团队,在做任何动作之前要想清楚上面的四个问题。

2、好用决定了漏斗的转化率

找到制胜场景就够了吗?当然不是,如果把整个用户旅程当成一个漏斗,找到制胜场景充其量是找到正确的入口而已,进入漏斗以后,重要的事情就变成了提升各阶段的转化率,决定转化率的一个关键指标是产品的易用性,这点和做 to C 产品很像,很多做 to B 的团队会下意识忽略这一点,通常可能是两种原因:

  • 不太重视社区用户 Self-service ,项目官方甚至鼓励用户联系官方团队,因为早期知道有人在用这个信息是很重要的,而商业客户基本服务和支持都是官方的,客户无感,对公司而言没有动力优化。

  • 很多产品在诞生初期是救命型的产品,用户没有别的选择。例如早期的 TiDB ,在 MySQL 扩展需求迫在眉睫的时候,用户更关心如何立即把问题解决掉,内核能力更重要,其他的可以先缓缓,忍着就好。

这两种原因导致的结果就是,对易用性和用户体验关注不足,这个错误在市场竞争初期是很隐蔽的。一方面因为流进漏斗的 leads 数量不够大,人肉支持尚可,且市场的竞争还不激烈,用户没有其他选择。试想一下,当这个市场终有一天变得成熟,大量客户被充分教育后流入漏斗,团队的支持带宽肯定是不足的;另一方面,因为市场已经被教育成熟,一定会有竞争对手能做类似的事情,这时,当你不是市场中唯一的救命选择,用户一定会选择用着顺手且省心的一方,这不难理解。这就是为什么在开源软件竞争的中后期,易用性和用户体验要放在至高位置的原因。对于“用着省心”,假设已经通过成熟的生态和案例背书解决了,而在“用着顺手”这一点上,中国诞生的开源软件团队相比世界先进水平而言,差距很大,毕竟海外的开源软件竞争比国内更加激烈,因为国外开源市场诞生时间长,而且业务场景对于基础软件的需求也没有国内极端,通常好几个产品都能搞定同一个场景,那么这时当然就要比拼易用性(省心)和生态(放心)。

有几个问题,作为开源项目的产品负责人可以问问自己,在你的产品领域里,如何定义好用?最佳实践是什么?世界上最好用的同类水平是怎么样的?我相信思考这些问题对产品发展会有帮助。一个反映易用性的好视角是:用户能够 Self-servicing 的程度,其指标体系较多:比如在云上自助完整整个产品生命周期的比例,在开源社区从接触到使用过程中不用提问的比例,开源社区活跃贡献者数量等等。

3、二次传播是达成网络效应的关键

上文提到过,网络效应产生的前提是,任何一个新用户的使用对于老用户是有价值加成的,所以试想:如果一个社区用户默默地使用了软件,默默地看了文档和最佳实践文章,甚至出了 bug 自己默默地修好(不贡献回来),这对这个社区和产品是有价值的吗?

我认为是没有的。

尽管我知道一定会有这样的用户存在,就像沉默的大多数人一样。对于社区运营者来说,最关键的任务不是让沉默者更多或更深度地使用,而是让他们和网络中的其他用户建立更多的连接,例如分享经验(写案例文章)、培养贡献者、积极向社区反馈使用中的问题等等,而且一定要将这些内容传递到网络的其他节点,确保产生价值。例如:一个用户的使用场景帮到了另一个用户选型,一个用户反馈帮助产品发现了一个 bug 并修复,这些都是产生价值的例子。切忌让用户变成一个个孤岛,社区运营者如果看不清这个关键点,可能会陷入为了数字(使用量)而追求数字的情况,做了很多工作,但从全局看不到进步。

4、网络效应的转移

社区运营的最高境界是将网络效应从使用者的网络效应转移到基于信仰的网络效应,将社区中心从开源公司内部转移到外部以获得更大的势能。这两者都不容易,对于前者可能更多的是抽象和总结提炼理念以及持续保持长远而正确的 insight(洞察),加之寻找合适的布道者群体,这点并不容易。对于后者来说,只要在以公司为中心的阶段积累足够多的成功案例和优势场景,并且投入资源教育市场,剩下的交给时间就好,这个阶段关注的指标是品牌力。开源软件社区运营是一个指数曲线的游戏,要抱着长期主义的心态去耕耘。

最后作为结尾,我想谈谈,一个伟大的开源基础软件产品应该是什么样的?

我眼中一个伟大的基础软件产品不仅仅是解决眼下的具体问题,而是开启一片新的天地,一个新的视角,创造新的可能性。就像智能手机的发明,它作为平台催生出了微信这样的伟大应用,开启了一个全新的世界。就像云、S3 和 EBS 的发明,给开发者提供了新的设计方式,催生出了Snowflake这类的新物种,彻底改变了人们使用分析数据的方式。而开源社区正是这类伟大基础软件诞生的最合适的土壤,就像鱼和水一样。

我不知道社区会带来什么,我也不敢高估自己能力,毕竟在群体智慧面前,个人的力量永远是渺小的。

开源深度思考 - In Community We Trust的更多相关文章

  1. GitHub 上 57 款最流行的开源深度学习项目

    转载:https://www.oschina.net/news/79500/57-most-popular-deep-learning-project-at-github GitHub 上 57 款最 ...

  2. 快速傅里叶(FFT)的快速深度思考

    关于按时间抽取快速傅里叶(FFT)的快速理论深度思考 对于FFT基本理论参考维基百科或百度百科. 首先谈谈FFT的快速何来?大家都知道FFT是对DFT的改进变换而来,那么它究竟怎样改进,它改进的思想在 ...

  3. Spark Streaming源码解读之JobScheduler内幕实现和深度思考

    本期内容 : JobScheduler内幕实现 JobScheduler深度思考 JobScheduler 是整个Spark Streaming调度的核心,需要设置多线程,一条用于接收数据不断的循环, ...

  4. Spark Streaming源码解读之Job动态生成和深度思考

    本期内容 : Spark Streaming Job生成深度思考 Spark Streaming Job生成源码解析 Spark Core中的Job就是一个运行的作业,就是具体做的某一件事,这里的JO ...

  5. 推荐GitHub上10 个开源深度学习框架

    推荐GitHub上10 个开源深度学习框架   日前,Google 开源了 TensorFlow(GitHub),此举在深度学习领域影响巨大,因为 Google 在人工智能领域的研发成绩斐然,有着雄厚 ...

  6. Computational Network Toolkit (CNTK) 是微软出品的开源深度学习工具包

    Computational Network Toolkit (CNTK) 是微软出品的开源深度学习工具包 用 CNTK 搞深度学习 (一) 入门 Computational Network Toolk ...

  7. 开源深度学习架构Caffe

    Caffe 全称为 Convolutional Architecture for Fast Feature Embedding,是一个被广泛使用的开源深度学习框架(在 TensorFlow 出现之前一 ...

  8. MySQL 5.7 优化SQL提升100倍执行效率的深度思考(GO)

    系统环境:微软云Linux DS12系列.Centos6.5 .MySQL 5.7.10.生产环境,step1,step2是案例,精彩的剖析部分在step3,step4. 1.慢sql语句大概需要13 ...

  9. 3星|《深度思考:不断逼近问题的本质》:香奈儿前CEO自传

    深度思考:不断逼近问题的本质 作者是前香奈儿CEO,主要内容是作者的自传,从家庭说起,一直到卸任香奈儿CEO. 作者出生于上世纪六七十年代的一个美国中西部的犹太家庭,崇尚自由,讨厌标签.高中的一个暑假 ...

随机推荐

  1. Java 对象实现 Serializable 的原因

    java.io.Serializable 是 Java 中的一种标记接口(marker interface).标记接口是一种特殊的接口,java.io.Serializable 接口没有任何方法,也没 ...

  2. drools动态增加、修改、删除规则

    目录 1.背景 2.前置知识 1.如何动态构建出一个kmodule.xml文件 2.kmodule.xml应该被谁加载 3.我们drl规则内容如何加载 4.动态构建KieContainer 3.需求 ...

  3. CF1580E Railway Construction

    CF1580E Railway Construction 铁路系统中有 \(n\) 个车站和 \(m\) 条双向边,有边权,无重边.这些双向边使得任意两个车站互相可达. 你现在要加一些单向边 \((u ...

  4. CSS元素的几种显示模式

    元素的显示模式 元素的显示模式就是元素以生么方式进行显示,比如<div>自己占一行,比如一行可以放多个<span>. HTML元素一般分为块元素和行内元素. 块元素 常见的块元 ...

  5. 如何在Uniapp中访问CabloyJS后端API管理系统

    介绍 CabloyJS是一款免费开源的NodeJS全栈开发框架,采用前后端分离设计,具备开箱即用的后台管理系统 Cabloy-SDK是专门为Uniapp应用量身定制的前端SDK,用于便捷的访问Cabl ...

  6. 【Redis】事件驱动框架源码分析

    aeEventLoop初始化 在server.c文件的initServer函数中,对aeEventLoop进行了初始化: 调用aeCreateEventLoop函数创建aeEventLoop结构体,对 ...

  7. 利用XtraDiagram.DiagramControl进行流程图形的绘制和控制

    DevExpress提供了一个比较强大的图形绘制工具,可以用于绘制各种图形,如流程图.组织机构图等等,本篇随笔介绍XtraDiagram.DiagramControl的使用,以及利用代码对其属性进行控 ...

  8. c++(qt)播放wav文件的四种方式

    //方法一(要符合RIFF规范) 1 QSound::play("E:/Projects/报警声1-1.wav"); //方法二(要符合RIFF规范) 1 QSoundEffect ...

  9. 搭建uipath

    我对windows也不太熟,也是第一次安装Uipath Orchestrator,希望有问题指出一起交流,可以留言,Uipath中文qq交流群:4656303241. 下载镜像 windows ser ...

  10. MOEAD实现、基于分解的多目标进化、 切比雪夫方法-(python完整代码)

    确定某点附近的点 答:每个解对应的是一组权重,即子问题,红点附近的四个点,也就是它的邻居怎么确定呢?由权重来确定,算法初始化阶段就确定了每个权重对应的邻居,也就是每个子问题的邻居子问题.权重的邻居通过 ...