架构师日记-软件工程里的组织文化 | 京东云技术团队

一 引言

本文是京东到家自动化测试体系建设过程中的一些回顾和总结,删减了部分系统设计与实践的章节,保留了组织与文化相关的内容,整理成文,以飨读者。

下面就以QA(Quality Assurance)的视角来探讨工作中经常面临的问题与挑战。

关于软件质量,不知道你有没有以下困惑:

西医中“头疼医头,脚疼医脚”的思路在研发团队中往往不能奏效。中医的整体辩证论治往往是解决问题的良方。其根本还是思考维度和观察视角的不同。举个例子来说,改变人类出行方式的,并没有按照培育更加优良健壮的马匹来演进,而是自行车,汽车的发明;还有被大众经常戏说的例子,抢占方便面市场的不是因为某一款方便面,可能是外卖的兴起。这都告诉我们,从更高维度视角去审视问题,问题往往更容易被定位解决。我们先来看一下研发体系需求交付流程,涉及到的人员合作及各个交互阶段,如下图:

举个例子,拿软件漏测率高,导致线上事故频发的现象来说。先从整个需求交付流程来看,整个产品迭代的节奏如下图:

那么导致漏测率高的原因是什么呢?

可能是产品设计问题,可能是研发实施问题,可能是用例验证问题,可能信息不对称的流程问题,可能是团队协作节奏出现了问题,也有可能是技术储备的问题,总结起来可以归纳为:组织支持,技术实践,文化共识几个维度。下面我们聚焦于组织支持和文化共识两个方向。

二 康威定律

2.1 定律解读

亚马逊CEO贝索斯对于如何提高开会效率这个问题有自己的解决办法。他称之为“两个披萨原则”,即与会人数不能多到两个披萨饼还不够他们吃的地步。

谈到组织架构就绕不开号称软件架构设计中的第一定律,康威定律:“设计系统的架构受制于产生这些设计的组织的沟通结构”;

它们都体现了横向沟通成本是非常高的现实。技术层面,系统各个模块间的接口也反映了它们之间的信息流动与合作方式,也是同样道理。

为了直观理解,我们借用一张流传甚广的图来理解一下组织结构:

其实根据原文中康威定律,又有人将其拆解为以下四个定律:

第一定律 组织沟通方式会通过系统设计表达出来。

组织的沟通和系统的设计之间紧密相连,特别是复杂系统,解决好人与人的沟通才能有一个更好的系统设计。

第二定律 时间再多一件事情也不可能做的完美,但总有时间做完一件事情。

“敏捷开发”模式很好的诠释了这条定律,做到不断迭代、持续交付、快速验证和反馈,并持续改进。一句话:完成比完美更重要!

在系统真正地投入生产使用之前,再好的架构都只是假设,产品越晚被使用者使用,失败的成本和风险就越高,而小步行进,通过MVP快速实验,获取客户反馈,迭代演化产品,能有效地减少失败的成本和风险。避免过度设计问题的出现。

第三定律 线型系统和线型组织架构间有潜在的异质同态特性。

你想要什么样的系统设计,就架构什么样的团队,能扁平化就扁平化。最好按业务来划分团队,这样能让团队自然的自治内聚,明确的业务边界会减少和外部的沟通成本,每个小团队都对自己的模块的整个生命周期负责。这是对第一定律的场景具象化;

组织和系统架构之间有一个映射关系(1 ~ 1 mapping),两者不对齐就会出各种各样的问题,一方面,如果你的组织结构和文化结构(民主合作式,集权式,丛林法则式,人才密度)不支持,你也无法成功建立高效的系统架构,例如集中式和严格职能(业务, 开发, 测试, 部署, 运维)的企业,很难推行微服务和DevOps,推行Docker/PaaS平台也会比较困难,这样的组织职能之间都倾向于局部优化,无法形成有效的合作和闭环。

反过来也是成立的,如果你的系统设计或者架构不支持,那么你就无法成功建立一个有效的组织;

第四定律 大的系统组织总是比小系统更倾向于分解。

系统越复杂,越需要增加人手,人手越多,沟通成本也呈指数增长。分而治之便是大多数公司选择的解决方案。分不同的层级,分不同的小团队,让团队内部完成自治理,然后统一对外沟通。

其实康威定义的核心要义就是如何提高组织的协作效率。想更加具象化的去理解,我们可以从大自然中寻找智慧,最典型的就是树的组织结构,树根->树干->树枝->树叶,树根通过树皮向上提供水分和养分到树叶,树叶光合作用将碳水化合物通过树心从上向下传导,这种生命有机体的分工协作方式就是符合康威定律的。另外树状结构在数据结构方面的效率表现也是最为均衡的。所以运用好树状架构,对于组织沟通协作乃至系统架构都是大有裨益的。重新审视一下我们的组织架构吧,这可能是繁杂问题现象后的罪魁祸首之一。

2.2 实践案例

京东到家优惠券系统进行过一次大的改版重构。当时的业务背景是O2O业务模式经过一段时间的摸索,我们最终将超市生鲜定为业务的着力点,紧接着针对于超市生鲜业务门类的促销便接踵而至,仅仅在新人资格上面就有:平台新人,商家新人,首单新人等若干维度,然后在叠加渠道,城市,商家,门店,品牌,商品等各个维度的组合限制,玩法灵活,多变,需求池里面挤压了大量的促销需求。

当时团队有3个人在支持当前优惠券系统的业务迭代, 运作模式可以用竖烟囱的方式来形容。架构体系处于失控的状态。其运转逻辑是:为了快速支撑业务需求,减少对原有服务逻辑的影响,就只能另起炉灶,重新设计,而越是这样,从底层的数据结构到中间的基础服务,以及上层的业务聚合,在组件数量和结构上无法做到必要的内聚和收敛,导致部分业务很难支撑,同时线上漏洞明显增多,最终到了难以为继的地步。于是我们进行了系统重构,当然我们的测试人员由一个人从头到尾全程支持,支撑起了整个重构工作的测试任务。当时的组织架构如下图:

随着业务的快速发展,大量的拉新促活需求接踵而至,最重要的是促销的玩法多变,各个业务团队都有自己的要求,比如对于用户留存业务团队要求有下单返券/分享领券/砍价券等场景,而对于用户增长团队可能想要的是定向推送优惠券/地推扫码领券/新人红包等玩法。业务方是多线的,而我们的研发团队以及系统却是单线的,这就导致了项目沟通和协调的成本巨大,由于研发资源的问题,很多需求长期处于需求池里面得不到及时响应,即使我们试着将研发人员提高了一倍,但结果还是不能根本解决这个问题,需求交付效率成了业务痛点。

接下来我们在组织架构上做了很大的调整,首先业务架构层面,我们将用户增长部门和用户留存部门的业务和研发分别进行了闭环,即两个业务部门都成立自己独立的研发团队内部进行领域闭环;其次我们在技术架构层面,将现有的优惠券服务进行了系统拆分,将处于优惠券核心生命周期的功能进行了中台化,为各个部门提供基础服务的能力,而非核心生命周期里的比如优惠券发放门槛,触达方式等促销业务玩法,交由各个业务团队内部消化就可以了。这样就消除了业务和技术的多对一的组织协作模式,在团队的沟通和协作效率上取得了明显的效果。

从业务到技术研发都做到了组织和系统的拆分映射,但我们的测试团队并没有在第一时间及时的进行人员调整,展现出来的结果就是测试质量有所下降,同时测试效率明显降低。因为随着组织和系统架构的重塑,业务和研发做到了沟通协作的内部闭环,但对于测试同学来说却并没有做到,接下来我们将测试团队再次与研发团队的组织进行对应,完成了整个需求交付链路的架构调整。

三 组织文化

3.1 团队认知

成员克服个体差异性,默契配合,彼此信任,形成真正有凝聚力的团队,是需要一些时间的,可能需要6个月,甚至1年。凝聚力一旦真正形成,团队的成员会一起做计划,一起面对问题,一起搞定一切。一旦团队有了凝聚力,但却因为项目结束了便将这样的团队解散,则是极为荒谬的。最好的做法是不拆散团队,让他们继续合作,只要不断地把新项目分派给他们就行。

一些新创立的软件外包公司试图围绕项目来构建团队。这是一种不明智的做法。按照这种做法,团队永远都不可能形成凝聚力。每个人都只在项目中短期停留,只有一部分时间是在为项目工作,因此他们永远都学不会如何默契配合。

专业的开发组织会把项目分配给已形成凝聚力的团队,而不会围绕着项目来组建团队。一个有凝聚力的团队能够同时承接多个项目,根据成员各自的意愿、技能和能力来分配工作,会顺利完成项目。

团队比项目更难构建。因此,组建稳健的团队,让团队在一个又一个项目中整体移动共同工作是较好的做法。并且,团队也可以同时承接多个项目。在组建团队时,要给予团队充足的时间,让他们形成擬聚力,一直共同工作,成为不断交付项目的强大引擎。

团队的向心力如何打造?一定是结合业务场景,设定合适的价值导向。从普通的研发团队来看,有以下几方面可能是需要投入精力来保障的:

  1. 识别团队瓶颈,优化木桶短板,提高资源利用率;

  2. 缩短交付周期,提高吞吐率;

  3. 周期预估准确,精准把控节奏;

如果我们的团队产出达不到预期,那就要识别出问题出现的原因,是因为目标没对齐,流程不规范,还是技术储备少,基础设施薄弱,最关键的是我们要有良好的洞察力和执行力。发现问题,问题就解决了一半。

  1. 目标不对齐:让信息透明,明确度量指标;

  2. 流程不规范:对流程进行治理,比如采用敏捷开发模式;

  3. 技术储备少:解构->观测->对标->学习->重构

  4. 基础设施薄弱:善用工具(CI/CD)/自研

最困难的是做决策和执行。在执行的时候也要考虑现实的环境和团队文化,这是自上而下快速推进制度落地的准绳和依据。比如我们应该如何去进行需求立项,如何将项目落地?

这就需要找出我们做决策的依据和贯彻执行的方法:

  1. 做正确的事情(价值驱动-决策依据):关注ROI/优先级;

  2. 正确的做事情(规则驱动-执行方法):关注规则/方法/质量效率体系建设;

3.2 问题认知

我想提高软件交付质量,就需要抓住问题的本质。如何定位问题的本质呢?核心就是多问几个为什么。参照六度分隔(Six Degrees of Separation)理论,“你和任何一个陌生人之间所间隔的人不会超六个,也就是说,最多通过六个人你就能够认识任何一个陌生人。”

什么样的状态才算是高质量的软件交付?

回答可能是:问题少,交付效率高。

进一步拆解,问题少,交付效率是通过什么来衡量的?

千行bug数,单位周期上线的故事点数量。

如何统计千行bug数,单位周期上线的故事点数量?

可以借助Bug跟踪管理软件,比如Jira。

第三方软件不能很好的支持我的诉求,我想要的更多,怎么办?

可以研发自有的CI/CD工具…

那么问题问到什么时候才能结束呢?

将问题被拆解到至少可以被度量的粒度。拿软件交付质量来讲,问题可能会被拆解到下面几个维度:

结合PDCA工具,我们可以将整个度量体系抽象为以下流程:

拆解完成的可以被执行的任务,如下:

1. 提升代码质量:指标度量(千行bug率,圈复杂度)/工具辅助(扫描)/服务拆分/流程保障(技术评审);

2. 加强流程把控:提测流程线上化/上线流程(质量门禁,灰度等)/指标度量(提测通过率);提高测试覆盖率:指标度量(接口覆盖率/代码覆盖率/自动化覆盖率/缺陷分析)等;

最终按照软件交付流程,将产研测运等核心节点如法炮制,最终形成体系化的解决方案,如下图:

3.3 知识赋能

在一个拥有战斗力的团队中,默契和共识是基础。而要形成某些共识,就需要拥有一套良好的问题反馈和解决机制,借事练人。可以借用如何进行单元测试和如何进行预估排期两个工作当中常见的问题,来审视一下团队的共识情况吧。

3.3.1 如何单元测试?

软件可测性和研发过程息息相关的,但是现实场景是软件开发人员很不愿意编写单元测试用例,原因有很多,比如:方法和分支太多,单元测试用例的编写甚至要比业务代码还要多,时间根本不够用;好多方法依赖于上下文,需要做模拟(mock),只有这样才能跑起来;推行单元测试似乎就困难重重。

很多公司程序代码正确性的验证就交由软件测试人员来完成,工作的转移必定产生了更多的沟通与协作成本,如果软件不经常迭代,问题还不大,如果软件是按照周期迭代的,每个周期都要进行全量测试,那么这个测试团队的人员必将会非常之大,这个问题就比较突出了,测试阶段极有可能成为需求交付的瓶颈,损害软件产品的发布,影响业务的增长。

为了提升测试效率,很多测试过程可以进行自动化,比如回归测试,性能测试等。当然还有另一种提升测试效率的办法,就是让单元测试回归到开发人员的职责范围内,当然单元测试也属于自动化测试的范畴。

举个我们日常web开发中经常遇到的一种场景,比如说我想根据给定的筛选条件,获取相应的数据信息:

示例中这个方法的测试有容器的依赖HttpServletRequest,需要模拟出来才可以测试,否则就只有把服务器启动才能够运行这段代码,这就不属于单元测试了,而属于集成测试了。仅模拟容器还不够,还需要模拟底层的数据库才能跑起来,于是模拟就会变得越来越复杂。测试代码明明不复杂,单元测试的成本确非常之高,如何解决呢?

要知道我们真正要测试的是代码逻辑,代码执行所依赖的环境不是单元测试的目的,它只会让测试变得困难。所以我们要写可进行单元测试的代码,就是要测试代码的参数开发人员可以自由模拟,不需要依赖于环境。比如,上述示例我们就以拆分改造一下:

我们拆分出来的子方法是不需要依赖于容器环境的,这样我们的单元测试就可以顺利进行了。可能还会有人提出疑问,拆分后难道原方法里的代码就不需要测试了吗?答案其实是肯定的,因为原方法里的代码都是顺序执行的,并没有逻辑,如果代码里没有逻辑,是不需要进行测试的。同样的还有底层的数据库操作也是如此,我们进行单元测试的时候也不需要真正的做落库操作,落库动作对于验证业务逻辑本身也没有太大意义。

单元测试交给软件开发人员来编写,本身是没有问题的,有问题的其实是软件开发人员对单元测试的认知,以及开发出来的代码本身。测试驱动开发模式就是规范我们进行单元测试用例编写的一种实践方式。

3.3.2 如何预估排期?

研发人员应该懂得如何为业务人员提供可信的预估结果,以便做出计划。一旦做了承诺.就要提供确定的数字,按时兑现。但是大多数情况下,精确数字这很难做到。专业的做法是提供概率预估,来描述期望的完成时间及可能的变数。对预估结果,研发人员会与团队的其他人协商,以取得共识。

1957年,为支持美国海军的潜艇极地航行计划,计划评审技术(PERT, Program Evaluation and Review Technique )诞生了。PERT 的一部分内容就是对预估的计算方法。这种技术包含了一个非常简单而有效的办法,把预估变成概率分布,让主管们看懂。

你可以根据3个数字预估某项任务。这就是三元分析法。

O**:乐观预估。这是非常乐观的数字。如果一切都异常顺利,你可以在这个时间内完成。实际上,为了保证乐观预估有意义,这个数字对应的发生概率应当小于1%。举例:假如是1天。**

N**:标称预估。这是概率最大的数字。如果画一张柱状图,标称预估就是最高的那个。举例:假如3天。**

P**:悲观预估。这是最糟糕的数字。它应当考虑到各种意外,比如飓风、核战争、黑洞、其他灾难等。为保证悲观预估有意义,这个数字对应的发生概率也应当小于1%。举例:假如12天。**

有了以上三个预估,我们可以这样描述概率分布:μ=(O+4N+P)/6

针对于例子,我们可以的出预估值(1+4*3+12)/6=4.2天

通常这个数字都有点水分,因为分布图的右边部分比左边部分长。所以我们用任务的概率分布的标准差来衡量不确定性:σ=(P-O)/6

σ是这个任务的概率分布的标准差,如果这个数字很大, 就表示非常不确定。对上文举例来说,它等于(12-1)/6,也就是大概1.8天。

现在我们预估结果是4.2天/1.8(标准差),给人传递的信息是,实际可能5天完成,但也可能要6天甚至9天。

实际情况可能会更复杂一些,有时候我们会多项任务并行,这时候的预估模型也会进行调整,总任务统计分布:μseq=μtask,总标准差就是标准差平方和的平方根。

掌握一些基本的时间预估模型的知识,对于项目规划和实施节奏的把控,是非常必要的,毕竟依据经验甚至是拍脑袋给出的排期往往是不能让人满意和信服的。

四 总结

本文介绍了软件与组织架构的关系-康威定律,并结合实际案例进行了解读。又从组织文化层面,描述了团队规模对软件交付的影响,给出应该围绕团队来承接项目,而不是依据项目来组建团队的观点。接下来又借助六度分隔(Six Degrees of Separation)理论,给出了分析问题,解决问题的方法和思路。最后介绍了团队应该共同成长,将工作中常见的问题(比如:如何预估排期),给出科学的指导和训练,从而打造出一支能战能胜的“特种部队”。

注:本文部分图片来自互联网

作者:京东零售 刘慧卿

来源:京东云开发者社区 转载请注明来源

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/94721.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Git分支机制

一、分支机制简述 要想真正理解Git的分支机制,我们要首先回过头来看一下Git是如何存储数据的。 Git并没有采用多个变更集( changeset )或是差异的方式存储数据,而是采用一系列快照的方式。当你发起提交时,Git存储的是提交对象( commi…

fastadmin iis伪静态应用入口文件index.php

<?xml version"1.0" encoding"UTF-8"?> <configuration><system.webServer><rewrite><rules><rule name"OrgPage" stopProcessing"true"><match url"^(.*)$" /><conditions…

开始MySQL之路——外键关联和多表联合查询详细概述

多表查询和外键关联 实际开发中&#xff0c;一个项目通常需要很多张表才能完成。例如&#xff0c;一个商城项目就需要分类表&#xff0c;商品表&#xff0c;订单表等多张表。且这些表的数据之间存在一定的关系&#xff0c;接下来我们将在单表的基础上&#xff0c;一起学习多表…

抖音seo矩阵系统源代码开发部署分享

一、 开发步骤分享 抖音SEO矩阵系统源代码开发部署分享&#xff0c;需要经验丰富的开发人员和服务器管理人员&#xff0c;以下是大致的步骤&#xff1a; 确定你需要的功能和设计&#xff0c;确定开发人员和设计师的角色和任务分配&#xff0c;以及开发进度和计划。 确定服务器…

java+ssm+mysql农场信息管理系统

项目介绍&#xff1a; 本系统为基于jspssmmysql的农场信息管理系统&#xff0c;功能如下&#xff1a; 用户&#xff1a;注册登录系统&#xff0c;菜地信息管理&#xff0c;农作物信息管理&#xff0c;种植信息管理&#xff0c;客户信息管理&#xff0c;商家信息管理&#xff…

《Flink学习笔记》——第四章 Flink运行时架构

4.1 系统架构 Flink运行时架构 Flink 运行时由两种类型的进程组成&#xff1a;一个 JobManager 和一个或者多个 TaskManager。 1、作业管理器&#xff08;JobManager&#xff09; JobManager是一个Flink集群中任务管理和调度的核心&#xff0c;是控制应用执行的主进程。也就…

花5分钟判断,你的Jmeter技能是大佬还是小白!

jmeter 这个工具既可以做接口的功能测试&#xff0c;也可以做自动化测试&#xff0c;还可以做性能测试&#xff0c;其主要用途就是用于性能测试。但是&#xff0c;有些公司和个人&#xff0c;就想用 jmeter 来做接口自动化测试。 你有没有想过呢&#xff1f; 下面我就给大家讲…

Redis之集群模式

一、Redis集群 一个节点就是一个运行在集群模式下的Redis服务器&#xff0c;Redis服务器在启动时会根据cluster-enabled配置选项是否为yes来决定是否开启服务器的集群模式。 Redis节点不会互相发现&#xff0c;连接各个节点的工作需要使用cluster meet命令来完成 CLUSTER MEE…

代码随想录算法训练营day42 | 01背包问题,416. 分割等和子集

目录 01背包问题 416. 分割等和子集 01背包问题 416. 分割等和子集 类型&#xff1a;动态规划&#xff0c;01背包 难度&#xff1a;medium 思路: 经典的01背包问题&#xff0c;背包容量为sum/2, 每个物品的重量为nums[i],其价值也为nums[i]。 需要注意的是&#xff0c;如果…

【PLSQL】PLSQL基础

文章目录 一&#xff1a;记录类型1.语法2.代码实例 二&#xff1a;字符转换三&#xff1a;%TYPE和%ROWTYPE1.%TYPE2.%ROWTYPE 四&#xff1a;循环1.LOOP2.WHILE&#xff08;推荐&#xff09;3.数字式循环 五&#xff1a;游标1.游标定义及读取2.游标属性3.NO_DATA_FOUND和%NOTFO…

基于SSM的旅游管理系统jsp房源信息java源代码Mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 基于SSM的旅游管理系统 系统有2权限&#xff1a;管理…

【Axure教程】调用日期选择器并筛选中继器表格

今天教大家在Axure里怎么调用代码调用浏览器的日期选择器并对对中继器表格进行日期区间的筛选。调用浏览器日期选择器的好处是&#xff0c;可以选择真实的日期&#xff0c;包括某年某月某日是星期几&#xff0c;哪个二月是29天……都是真实的&#xff0c;那不同的浏览器日期选择…

Linux内核学习(十二)—— 页高速缓存和页回写(基于Linux 2.6内核)

目录 一、缓存手段 二、Linux 页高速缓存 三、flusher 线程 Linux 内核实现了一个被叫做页高速缓存&#xff08;page cache&#xff09;的磁盘缓存&#xff0c;它主要用来减少对磁盘的 I/O 操作。它是通过把磁盘中的数据缓存到内存中&#xff0c;把对磁盘的访问变为对物理内…

Markdown 扩展语法练习

风无痕 August 26, 2023 Markdown 指南中文版 Markdown 入门指南Markdown 基本语法Markdown 扩展语法Markdown 基本语法练习Markdown 扩展语法练习 代码 <h3 id"table">表格</h3>| Syntax | Description | | --- | --- | | Header | Title | | Paragrap…

抖店商品怎么让达人带货?说下找达人技巧和寄样后的操作,可收藏

我是王路飞。 找达人带货的玩法是公认出单快、易爆单、长久稳定的出单方式。 虽然新手可能感觉要给达人佣金&#xff0c;自己利润会降低&#xff0c;但是这种玩法可以让你快速入门&#xff0c;且能长久玩下去。 尤其是现在抖音直播间的产品全都是来自抖音小店的&#xff0c;…

多线程基础篇

我们平常说的一个程序&#xff0c;一个程序中有声音&#xff0c;图片&#xff0c;字幕 实际上是一个进程中有多个线程 main线程是主线程。 多核&#xff0c;多个cpu&#xff0c;多个线程&#xff0c;切换的很快 单核的话是一个cpu,某一时间只能是一个线程&#xff0c;但是因为…

抢先体验|乐鑫推出 ESP32-S3-BOX-3 新一代开源 AIoT 开发套件

乐鑫科技 (688018.SH) 非常高兴地宣布其开发套件阵容的最新成员 ESP32-S3-BOX-3。这款完全开源的 AIoT 应用开发套件搭载乐鑫高性能 ESP32-S3 AI SoC&#xff0c;旨在突破传统开发板&#xff0c;成为新一代开发工具的引领者。 【乐鑫新品抢先体验】ESP32-S3-BOX-3 新一代开源 A…

WPF基础入门-Class3-WPF数据模板

WPF基础入门 Class3&#xff1a;WPF数据模板 1、先在cs文件中定义一些数据 public partial class Class_4 : Window{public Class_4(){InitializeComponent();List<Color> test new List<Color>();test.Add(new Color() { Code "Yellow", Name &qu…

数据库中的条件索引使用

数据库条件索引 在逻辑删除相关的表中&#xff0c;设置普通唯一索引在多个逻辑上已删除的元组中可能发生唯一性冲突&#xff0c;即不允许存在两个相同的已删除元组&#xff0c;同时在存在已删除元组时也不允许插入相同值的新元组。此时可以通过设置条件索引&#xff0c;使唯一…

PlantUML文本绘制类图

记录下文本绘制类图的语法 参考 https://juejin.cn/post/6844903731293585421 类的UML表示 使用UML表示一个类&#xff0c;主要由三部分组成。类名、属性、方法。其中属性和方法的访问修饰符用 - 、# 、 表示 private、protected、public。 如图所示&#xff0c;表示A类有一个…