华为云用户手册
-
用户故事地图,既见树木又见森林 由影响地图得到了What部分,也就是我们要做什么,是不是就可以当成用户故事(User Story)排进产品待办事项(Product Backlog)开始开发了呢?答案是还不可以。 用户故事是敏捷开发中普遍使用的实践,但常见的困惑是:产品负责人整理了一大堆的产品Backlog,还编排了优先级,过早地陷入到细节的讨论中,只见树木不见森林。 传统敏捷开发中,扁平的产品待办列表,存在很多问题:它很难解释产品是做什么的。对于一个新的系统,扁平化待办列表无法帮助我们确认是否已经识别出全部故事。同样的,扁平化待办列表也无法帮助制定发布计划,用户故事少则几十,多则上百,详细分析每一个用户故事并且做出是否采纳的决定是非常乏味并且低效的。 用户故事地图是一门在需求拆分过程中保持全景图的技术,目的是既见树木,又见森林,聚焦于故事的整体,而不是过早的纠缠于细节,在看到全景图的同时,逐层进行细节拆分。采用用户故事地图,跳出了扁平化的产品待办列表,看到了产品的全景图,可以真正聚焦于目标用户以及产品最终的形态。产品待办列表只是一维的,而用户故事地图是三维的,这是高维与低维的比较,高维恒胜。 用户故事地图基于简单的网格结构,规则是从左到右讲述故事,即按照叙事主线顺序;自上向下的拆分,即由大到小的细节展现。其中最关键的部分是产品的构思框架,贯穿整个产品的发布地图,可以帮助团队以可视化方式展示依赖关系。此外,更多的背景信息可以摆放在地图的周边,例如产品目标、客户信息等,这几乎就是用户故事的全部了。这也恰好是用户故事地图的魅力所在,好的东西通常都很简单而有效。
-
持续交付 正如Jez Humble对持续交付的定义:“The ability to get changes—features, configuration changes, bug fixes, experiments—into production or into the hands of users safely and quickly in a sustainable way.”持续交付也好,DevOps也罢,最终目标是快速的交付价值。 如果说管理实践的目的是为了鉴别什么是正确的事情,以及正确的做事情。那么工程实践的目的,是除了正确的做事情以外,还能高效的做事。 工程实践就像人体的肌肉,是强调执行力的,是大脑想到然后肌肉能够做到并且快速的做到。每一丝的赘肉都会影响身体执行的速度,所以需要锻炼来消除。如何消除持续交付过程中的赘肉?和肌肉锻炼燃烧脂肪一样,痛苦的事情需要反复做,做十次一百次上千次,反复打磨,持续优化。 工程过程是需要高效、准确并且高度保持幂等性的。也就是说,执行一次的结果,与执行一百次的结果应该是一样的,所以对一致性的要求极高。人工过程是无法满足高频度发布与部署,因此工程实践要求的就是尽可能的自动化。最大化的自动化,越是频繁做的事情越要自动化,越是需要尽快反馈的事情越要自动化。在自动化来保证一致性的同时,我们还要去消除阻塞,发现问题并进行疏通。 自动化与人工审核要有机结合,需要想清楚人工审核的目的是保障质量,而不是管控,更不是官本位的体现屁股所在。每一个存在人工审核的地方,先想一想是否一定需要、是否有自动化的方式、是否可以后移。 质量与速度能否兼得?答案是肯定的。要持续识别并消除开发中的约束点,常见约束点以及相关建议有: 环境搭建的约束点:采用基础设施即代码的实践,应该让环境搭建与配置的过程自动化、版本化,提供自服务平台,使能开发者。 代码部署过程的约束点:采用自动化部署实践,利用容器化与编排技术,让应用部署与运行的过程呈幂等性。 测试准备和执行的约束:采纳自动化测试实践,分层分级的进行测试,针对不同的阶段,建立不同的测试环境、设置不同的测试目标、建立不同的反馈闭环。 紧耦合的架构往往会成为下一个阻塞点,要进行架构解耦,采用松耦合的架构设计,将重构等实践纳入日常的技术债务清理过程,演进式的采用服务化、微服务化的架构。 就像长跑一样,教科书里说道:每一丝肌肉都对跑步成绩造成影响,工程过程也是如此,彼此之间会产生关联并彼此影响。因此我们更应该将持续交付域作为一个整体来看待,而不是分裂的去看编译、构建、静态动态测试、集成、部署、发布等。工程过程更像是一个联动的机器,故而我们称之为持续交付流水线。良好配置的流水线,应该是分层分级,同时又不失整体的。
-
定义和特性说明 定义 敏捷开发方式有很多种,这里我们选择Scrum。Scrum给出了一个具体的工作框架,并且是应用最为广泛、成熟的一种敏捷开发方式,业界已经积累了大量的实践经验。 结合Scrum框架和具体实施项目特点,打造适合的敏捷Scrum团队尤为重要。 Scrum团队是一个完整的团队。Scrum团队是基于功能开发而组成的跨职能、自我管理团队,在组织方式、管理模式和开发过程等方面与传统的开发团队有着重大改革。 Scrum团队与传统团队的简单对比下图: Scrum团队中没有传统意义上的项目经理、产品经理、开发经理,而是引入了产品负责人(Product Owner)、Scrum Master和开发团队(The Team),开发团队中包含了多个职责的成员,例如需求设计人员、开发人员、测试人员等。 传统开发团队通常由项目经理做任务分析(WBS)并下达和分配工作内容,而Scrum团队提倡自我管理、自组织,按兴趣和能力挑选自己喜欢的任务。 传统开发团队通常是接到任务后独立完成,个人英雄主义突出,而Scrum团队需要在工作中相互配合,协作完成任务。 传统开发过程中,通常是经历一个非常大时间段的开发过程才能完成一次产品的发布,中间过程客户不能试用产品成果,不能快速反馈,而Scrum开发过程中,产品是迭代增量发布的,通常是在每个冲刺(Sprint)结束时交付可发布的软件,客户可以试用每个冲刺产品成果和快速反馈。 特性说明 开发团队的大部分时间都花在冲刺执行上。 在冲刺执行期间,开发团队完成设计、构建、测试PBI(Product Backlog Item),生成潜在可发布的产品增量。 开发团队的冲刺执行活动包括:每日检视和调整(站例会)、梳理产品列表(PBI)、冲刺规划(迭代计划会)、检视和调整产品与过程。 下面一起总结团队都有哪些特性。 由5至9人组成 如果开发团队需要一个大型的Scrum团队,比如有43个人,不大可能会组成一个43个人的Scrum团队,而是分成5个或5个以上的Scrum团队,每个团队建议不超过9个人,常用的方法为Scrum of Scrums。 一个整体,跨职能 开发团队必须具备所需的全部技能以构建高质量、可工作的产品增量。 技能单一的专职团队最多只能完成工作的一部分,所以一个专职团队做完自己的工作后,工作产品就被移交给其它团队,例如,开发团队把代码移交给测试团队。移交代表着极有可能产生误解和高成本的错误,拥有跨职能的团队可以减少移交次数,节约成本,开发团队由搭配合理的资深员工和资历浅的员工来实现团队多样化。 开发团队是自组织的 没有人告诉开发团队如何把产品代办事项列表变成潜在可发布的产品增量,开发团队自己确认采用哪种方式来实现产品负责人设定的目标。 自组织是系统自下而上、自发的属性,没有传统的自上而下、命令与控制的管理方式,即便是Scrum Master也不应该冒昧干预,这样的自组织拥有非凡的稳定性和产生惊人的新颖性。 由T型技能的员工组成 T型技能的意思是即要有深度又要有广度。 团队成员拥有适合的技能,覆盖各个专业领域,并且总体上技能有一些重叠,团队有额外的灵活性。有深度的专家型的员工,可以分配到数量合理的产品团队中,但不能让他们成为瓶颈(接力棒掉地)。然而,一开始就能找到想要的团队技能组合,是不太可能的,理想的技能组合需要在开发过程中日益成熟。 具备“人人为我,我为人人”的态度 在开发团队中不会有人说:“我那部分做完了,你那部分没有做完,因此我们失败了。”开发团队的成员必须充分意识到他们必须合作才能冲刺目标承诺,失败是团队中每个人的问题。 广泛沟通 开发团队成员相互之间以及他们和Scrum Master、产品负责人之间需要进行广泛的沟通,快速、高效交换有价值的信息。 广泛的沟通提高了信息分享的频率和质量。信息的经济价值是有时效性的,所以加快信息分享的速度可以快速进行检视和调整,做出更好的决定,同时可以快速识别浪费,避免开发团队在错误的方向上花更多的资源。Scrum团队广泛的沟通,就是用最小的成本快速有效地沟通。 沟通透明 沟通透明使开发团队成员都清楚目标状态,不会意外,另外还可以帮助建立互信。简而言之,开发团队成员需要坦诚、靠谱,才有利于自组织和达到冲刺目标。 目标专注 开发团队成员需要对团队目标保持专注、有责任感。 大量数据表示一个普遍的共识:做多个项目或者跨多个团队会降低生产力,因此建议团队成员尽可能专注于一两个产品。当然专注于一个产品开发工作时,更容易做到专注、有责任感。 持续的工作节奏 开发团队必须以可持续的节奏工作,不在进行死亡行军,这样做可以维持一个健康、有趣的环境。 采用顺序开发时,我们把像测试这样的重要活动放到了最后,此时临近项目交付,通常有大量的问题需要快速解决。结果,在开发后期,工作强度陡然上升,高工作强度会把团队成员压垮。作为组织,我们要问:“为什么必须在晚上和周末工作,哪些地方可以改进?”采用Scrum,每个冲刺我们一直在开发、测试和集成可交付的特性,为了确保团队可以频繁、定期交付价值特性,不至于忙到吐血,每个开发团队成员都应该使用良好的技术实践,比如持续集成和自动化测试等。 人员稳定 开发团队需要人员稳定。开发团队成员的稳定更有利于提高生产力、效率与质量。团队是组织的资产,团队才是敏捷的“价值源泉”。这里并不是说相当长时间内始终应该保持团队稳定。例如,如果有一个团队不像我们想象的那样有凝聚力,或者团队出现功能失调,那么解散团队危害更小而且经济上更合理。再例如,为了在组织内进一步推广Scrum,可以有意识的打散一个高效率Scrum团队,把优秀的团队成员作为“种子”策略的一部分。新的Scrum团队都有一个Scrum经验丰富的种子比保留原来的团队更有价值。
-
案例说明 常见问题 敏捷开发提倡先做市场收益率最高(最高价值)的工作,它容易导致敏捷开发团队过于看重眼前的短期利益,而忽视了产品发展的长远目标。 敏捷项目管理中,对敏捷开发团队成员的素质要求非常高,要求每位团队成员都非常专业并且拥有积极主动的自我管理。而现实中,团队成员的现况往往是水平参差不齐,积极主动的态度因人而异,往往达不到敏捷开发团队成员要求的标准。 解决方法 敏捷团队需要放眼中、远期目标,不能仅仅局限于关注眼前收益率大的目标; 敏捷的价值观提倡谦逊和勇气,团队成员之间互信互助,而不是互相指责批评和推卸。团队成员能够认识到自己的不足,并且主动改进,遇到困难的时候主动寻求团队帮助。团队成员努力做到自我管理和自我驱动,承担多项职能的工作。 主要收益 团队成员的自我管理能力、责任感和主观能动性增强。 团队成员不再各自为战,工作透明,协作和联系更加紧密。 团队成员满意度提高,工作氛围更加和谐。 每个Sprint都将成果(潜在可交付产品增量)与客户做确认,避免了后期较严重的需求变更风险。 团队成员不断地自我反醒、自我激励、能力提升。
-
实践:小步快跑,收支相宜 我们根据在各产品线转型的经验,第一步一定会选一个标杆产品,这个标杆产品一般来说会是一个服务化产品,或者是一个Cloud Native原生的产品。对架构解耦实现云服务化,对工具实现上云,对运维进行云提升。这是我们选取试点服务的方法或者准则、经验。 选好了一个服务后,就需要按部就班地转型。怎么做?实施敏捷的时候,敏捷有很多实践,要小步快跑,不断地见到成效。在进行迁移的时候也面临同样的问题,因为这本身也是一个项目,不可能一蹴而就,不是阶梯状的陡升。通过不断提升每一步的工具能力,来实现整体交付能力的提升。同时把整个转型工作的风险降到最低。 能力转化就如同是一个金字塔,金字塔尖一般来说是非常不容易达到的境界,金字塔的底端是入门团队需要做的事情。金字塔下面是沙子,第一件事情是打破思想,是我要做这件事情,要上云。这里一般是指上公有云,因为私有云的模式很难达到各种应变能力。 一般来说代码上云,就使很多企业避而远之,因为他们要的是代码的安全性。上图中右边每个层级列了两行,描述做这件事情主要的目的是什么、主要涉及到的工具是什么。代码上云主要的目的就是解放思想,把代码放到云端 代码托管服务 上来,把资产,例如软件开发的文档、积累的知识放到这里。 第二是管理上云,让我们的软件开发过程更加开放透明。有很多团队每周会发一个电子版进展表格,从一周的频度来说它是开放的,但是每天而言,它仍然是封闭的系统。把管理放到云端,目的是实现更好的开放协作。需求管理工具要有看板、相应的测试管理人员。 前两步实现之后,必然对效率有了要求,这个时候要构建自己在云端交付的能力,一般来说涉及的是构建、部署、流水线和自动化测试,当这些能力达到之后,这一步追求的提质增效的目标基本达成。 金字塔的顶端是开发上云,把所有的工作迁移到云端,目的是探索创新。此处为什么要把IDE迁移到云端?因为在云端可以得到更好的快速获取环境的能力,可以获得更好的协作能力、试错能力。当这些能力叠加在你面前的时候,你会发现在本地创建一个非常好用,但是搭建起来非常复杂的环境,不再有那么大的吸引力了,你会追求开发上云的境界。 下面给大家介绍几个在云化工具链转化过程中比较好的实践: 第一个实践,DevOps讲究的就是快速迭代、快速交付。它的主要收益不是为了快速的交付价值,而是为了帮助组织不断的纠正错误。产品经理抱怨交付团队交付效率永远达不到要求,就是因为管理过程中会存在各种各样的问题。所以每周一定要有一个迭代回顾,通过迭代回顾把迭代过程中的问题全部列出来,争取在下一个迭代中去改变一些,通过不断的改变,团队的效率得到提升,冗余的行为被去除。这是快速迭代敏捷开发的实践。 第二是微服务解耦。下图中左边部分,所有的服务都耦合在一起,虽然每个服务有自己的泳道,但发布的时候必须携手一起发布。例如一个很简单的服务,只有前台和后台,用于查询数据和刷新数据。经常会有前台升级的时候,要求后台跟着一起升级,后面后台升级了之后,前台工作了。这种情况就是解耦不充分造成的。一般来说,如果做得好会有特性开关、合适的导流、灰度测试等等。右边是一个比较好的例子,每个微服务有自己独立的泳道,同时已经实现了自己独立的交付节奏。 第三是持续交付流水线。这里列了一个流水线的基本流程,下面几点是我们总结出来的比较有意义的实际操作: 流水线一定要体现出管理理念,流水线分广义和狭义,狭义指操作序列,从开始执行到结束,总体来说只执行的是操作序列一些任务的堆积,不是管理理念的构成。还有一种广义的流水线,从需求进入管道之后,整个管理起来,并且可视化,广义流水线决定了你交付价值的真正速度。 任务要自动化执行,还要有质量门禁,这并不是华为的独创,实际上在所有业内的云交付公司都采取了这种方式。华为公司提供的质量门禁是基于Task的输入为大家设定的阈值。实际上质量门禁设置的最高境界是提供一个开放的茬口,在这里一切服务都可以作为门禁,它可以是一个手工的步骤,可以是一个服务请求的数据,也可以是一个测试系统的报告等等。这种开放的质量门禁才能够最大限度的体现出管理理念。 最后一个叫做质量门禁的集中管控,流水线放在个人的手里,执行流水线的同事通常会由于权限过高或者发布压力,把流水线的门禁关掉或者故意设得比较低。一定要从企业或者组织的高度对流水线的门禁有一个较高的要求,这种情况下质量才能得到比较好的保障。 第四个实践叫做生产环境的自动化。出现了比较重大的质量事故后,当我们去追溯时发现,问题往往是由一两个工程师一个多余的操作造成的。怎么杜绝这个事情?只有自动化。只有没有人参与的过程才是不会犯错误的。在生产环境的自动化保证了高质量向用户交付的基本要求。 首先,自动化的变更指的是当你决定向云端发布一个新版本的时候,从版本流出一直到线上功能的上线,直到用户可用的过程、审批必须都是自动化的,而不是说有手工环节在里面,只有这样,交付的前置时间才会缩到最短。 紧接着是灰度发布,任何一个发布对用户都有影响,不一定友好。只有找一部分用户先来试用新的功能,才能降低发布风险。这里有两种,一种是特性,一种是升级的部署。同时还有失败回滚,当部署的新版本发生故障时候,你如何按照精英团队的标准,在一个小时以内把它回滚到健康的版本,保证它的能力。 第五,用户级灰度发布。我们通常会采用很多种技术,一般是采用流量分配的技术,我们一般会控制流量分配,在这个技术过程中,我们会保证一些用户使用到新版本,这个过程仁者见仁,智者见智,概念非常多,不赘述了。 第六是生产在线测试。如果是金融系统,涉及到钱,应该有相应的管理成本配置,否则怎么保障线上的系统是正确的?线上系统势必要做测试,任何系统的模拟数据都无法与真实数据相比,哪怕在真实系统只花一分钱,模拟交易量都不能替代它。应该用管理成本设置一个账户,在里面实际的实现一些线上的支付,只有这样才能保证线上系统是真正可用的。华为线上有非常丰富的测试手段和机制,这里也提到了,告警机制是非常重要的。实现线上测试的目标是什么?第一是保证线上的质量,第二是对用户的承诺,我们交给用户的是一个服务,而不是光盘,这个服务必须是可用的,当它不可用时,要先于用户发现并解决它,这样的服务才是可靠,可信赖的。
-
聚焦:难把工具比仙子 接下来讲一下在企业实行全云化转型过程中面临的问题。下到十人团队,上到千人团队,各种各样的开发模式都有可能存在,怎么去做这样的转型?要先选一个合适的项目类型或者产品类型。这里列了几个基本的工具链的云化水平与其所匹配的软件开发或者项目服务能力的匹配表。 一般来说,我们在最开始只做大规模单体交付时,采用的都是本地化的工具,因为开源、免费,搭建比较方便,运维比较直接。但是当一部分服务已经开始进行混合产品交付的时候,例如华为的消费者云或者一些混合云和开发商混合的产品,里面有一部分是我们自己固定的组件,还有一部分是云端提供的服务接口,这时候就必须要把一些相应的交付能力挪到云端去,这样就实现了部分云化,主要适合混合型的产品。 接下来要把我们的能力全部云化,例如产品研发、测试、部署、构建、发布,都需要云化。 最后,服务变成一种纯Cloud Native,并不是它对本地没有任何要求,而是它所有的能力,包括弹性、各种快速响应,都是依赖云服务商提供的。这样就可以实现移动办公,轻松在家里喝咖啡办公。
-
蔓延:人心所向,大势已成 最后一条是基于组织的。 首先要有一个比较好的文化氛围。当组织对DevOps整个理念有高度认同度的时候,实践这样一种过程的改变会比较方便。 第二是自动化能力。我们可能机械化的去追求某些行为的自动化,但是必须把自动化这件事情刻到骨子里面去,每写一行代码都要思考能否自动化的机制保障它的成功。 第三是共享。在企业内部,很多团队有一些竞争,包括采用不同的理念,例如采用敏捷和采用精益的不同开发方法,分享知识与智慧是企业的宝贵资产。 第四,要有一个度量机制。必须要提到的是统计口径,这非常重要,度量应该是基于结果的度量或者基于事实的正向度量。因为我们现在所处的年代是一个飞速变革,发展非常快速的年代,在最近十年内所产生的技术变化可能抵得上过去一百年所产生的技术总量。 第五,企业内部要有一个好的培训机制和流程的导向。以华为公司为例,内部有一个比较著名的华为大学,华为创建这个大学的目的,就是为了让所有的员工在繁忙的工作交付的同时,能够有学习和深造自己的机会,同时也是为了把企业所赞同的一些核心价值观和方法向一线团队进行传播。所以会有很多培训班,针对DevOps的现场实践课,让一些从来没有机会去实践DevOps的团队,也有机会通过培训实际的方式参与进来,理解DevOps理念,慢慢地一定会在他所处的产品线或者所处的开发方向上发芽生根,以至于整个企业的氛围都是蒸蒸日上。
-
自检:核心实践,成效佳? DevOps是正向价值链,运营反馈是反向价值链,通过不断的度量,实现各方面的提升。在此我们主要关注的是持续交付的交付链。将一个需求变成线上的特性,测试人员在线上测试通过,即完成了正向交付价值。但是实际交付的效果可能并不好,就会造成用户流失,这是非常严重的状况。在正向交付负向反馈的同时,我们要不断地优化自身的能力,重新审视自己交付的能力和流程,是否从一个中等效率团队提升到高效率团队,甚至已经进入到精英团队的范畴,只有这样企业的竞争力才能不断的提升。 如何进行自检? 对于很多产品来说,产品形态还没有达到服务化或者云化的水平,需要用一些理论实践方法去引导他们达到这样一种新的开发能力水平和范围。所以需要有一个基本的引导方式。下图是整个开发的基本过程,列出了正向的交付链,针对每个过程中需要做的事情罗列出它所属的工程领域,例如开发工具或者交付工具、运维、反馈的工具领域,然后规划,以何种方式使用工具。正确的使用可以加快组织流程,用得不对,或者工具存在问题,可能会成为一个阻塞点。下图中红色部分是我们罗列的一部分能力,不是全部的。每个企业有自己软件交付的形式和方式,这里只是举一个例子,抛砖引玉。
-
观察:研发全云,境清奇? 进行企业DevOps能力自检之后,可能发现很多问题。 决定上云本身就是一个创新性的决定,很多企业对上云都是顾虑重重,为什么?首先,它是一个打破思想枷锁的过程,因为云上一切意味着不确定性、不安全性、不可知、风险,同时意味着大量的机会。在这个过程之中,我们首先要知道用全云端的工具意味着什么。 上图中左边有全云端的沙盘,从需求管理开始,紧接着要做实施和交付,开发、测试服务、构建、发布、部署、监控。后续还有一些基础服务,这些基础服务的实现实际上是为了衬托上层服务,如果没有代码托管、资源自动化、仓库服务,实施DevOps也只能是无水之田。右边是云化或者服务化的能力模型,下面三行是重中之重。大多数人做云化软件交付的时候可能不是云化,而是服务化。第一是自动化管理,管理流程不再有那么多人工过程了。第二是弹性扩展,不管是交付的软件也好,或者使用的工具也好,要有一个自动适应弹性扩展的能力,很方便的依托于现在公有云提供的能力,这种弹性扩展的能力并不难实现。第三要有一个足够的资源池,一般来说,公有云的服务商已经为大家打造了这样的平台,金字塔里面都满足了,可以说是云化服务,已经从服务化上升到云化的交付能力了。 然而实际做云化转型的时候是困难重重的。 从资源的角度来说,一般软件云化有三步: 第一是虚拟化,从实体服务器逐步转化成虚拟机。 第二是资源池化,有一个大的资源池可以实现动态的分配 第三步是自助服务,云端自助服务是能够实现快速运转的条件。 此外还有流程。如果线上发布过程和生产环境之间网络不通,应该怎么做呢?答案是工具并不能解决这个问题,因为这是流程问题。众所周知,华为公司有各种各样的安全红线,在做内部的云化服务化工具链落地实施的时候,最大的工作量集中在如何打破枷锁上,怎么把内网的一段代码或者一段测试用例或者二进制的安全文件快速传递到外网仓库,这一问题花了很长时间。举一个简单的例子,有一个流水线,其他步骤执行只需10分钟,最后会在发布审核的环节整整卡七个小时或者一周。我们做到提前审批到事后追查的能力,是做了最大的公关,等于说这是一个关键阻塞点的破除。一定要注意,当你准备做一个流程或者工具实施的时候,阻塞点不一定来自于技术和工具,很有可能是来自于流程。 部署方面,是否具备独立部署的能力,是否能够合理的使用资源组、容器镜像,类似于这种资源池进行管理的能力,都是限制我们服务的能力。经过很长时间的实践,我们发现很多产品线声称他们已经实现微服务架构,已经实现解耦,但是最后的结果是众多的微服务打包部署上线。这实际上还是要回到源头上去看一下整个服务架构是否做到了解耦,是否做到了微服务所要求的九大特征。 后面是编码问题,现在编码工具非常多,但是实现全云化的时候,实际上是要求我们把一种编码的能力移到云端去做。这件事情想起来很简单,做起来很困难。包括要实现后台运行、运维、测试、调试能力的支持,同时还希望和DevOps工具链打通。 再者是安全性,上云本身是一种思想的变革,没有绝对的安全,只要暴露在公众的眼光下,就有泄露的一天,就有被攻击的可能性。很多用户在使用我们的软件服务的时候,最大的问题是:“我们很关注安全性,请问你们有特别好的解决方案吗?”两条路,第一通过特殊化的定制、阉割、裁减一些本来应该很开放的能力来适应安全性,但是后果也显而易见,关在笼子里面的狮子怎么可能是强壮健康的呢?第二是说服用户,看他是否我的菜。举个典型的例子,我们从来没办法说服华为的海思来使用我们的服务,因为海思在华为内部是绝密。
-
用户故事是什么? 很多人认为既然我们使用用户故事来替代传统需求,那么用户故事就是记录需求的方式了。其实不然,用户故事不是用来编写需求的,而是用来讨论和跟踪的。 使用用户故事的目的是让用户可以自然的讲述需求,这样才能确保信息的真实性。因为任何软件产品都是为了帮助用户完成某种任务,也可以说任何的软件产品或者系统都是通过交互来解决问题的,而交互的双方可能是人和系统,可能是系统和系统,也可能是模块和模块。这样理解的话,任何的需求其实都是某个个体(人、系统或者模块)在和其他个体进行交互的过程中,通过我们希望的行为方式,达到我们想要实现的目的。用户故事的3个关键点:人、过程和目的,可以帮助我们将这个行为方式讲清楚。在讲故事这个过程中,我们应该专注于故事主线,而不是如何实现。 一旦用户讲清楚了故事,下一步我们需要产生相应的可开发的功能点,这里我们需要专注于如何实现。一般来说,我们很难通过一个功能点来满足一个用户故事,而必须要不同的功能点配合完成。但是我们仍然必须确保讨论的范围仅仅围绕当前的故事,这时候技术人员非常容易发散,会考虑一些和当前功能点相关,但是和当前故事不相关的内容。例如:这个功能可能以后还要用到的,所以我们还要这样那样等等。这时,用户故事可以起到控制讨论范围的作用。你可能会觉得,技术人员的角度是对的,因为可扩展、可复用等是软件设计的基本原则。但是我们应该从发展的角度来看待这些问题,假设我们可以预见的其他用户故事确实会影响这个功能点,那么这样考虑是可以的,但是应该到讨论那个用户故事的时候再去考虑;如果我们没有其他可以预见的故事会影响这个功能点,那么这些所谓的扩展性复用性设计就是浪费,因为你不知道是否会需要这个功能。 讨论清楚了功能点,进入开发阶段以后,用户故事是控制技术团队开发进度和交付进度的引线,也就是我们应该按照故事一个一个的进行开发测试和交付。这样才能确保我们交付的永远和用户预期一致,所有的开发、测试投入都是可以产生用户认可的价值的。这个时候用户故事起到了跟踪和驱动开发过程的作用。 通过以上分析,我们可以看到用户故事如何编写并不重要,重要的是它所驱动的过程,通过这个过程,我们可以把用户和技术团队紧密结合,并让大家产生对交付内容的统一认识。所以,用户故事是一种沟通工具,而不是编写工具或者需求模板!
-
故事讲给谁? 在真正开始讲故事之前,我们首先要确保正确的人都参与进来。对于规划一款产品来说,你至少需要:最终用户代表、产品经理(或类似Scrum中的PO)、项目经理(或类似Scrum中的ScrumMaster)、团队中的技术骨干(那些对实现的业务很熟悉,对所要使用的技术或者系统很熟悉的技术人员)。技术骨干又可以分成架构、开发和测试三个不同技能的人。这样看来,你至少需要6个人参与这个讲故事的过程(除非有些人可以互相替代)。 故事是讲给这里面每个人听的,同时也希望每个人都能够在讲故事的时候有所输入,而不仅仅是在听故事。 最终用户代表:这些人一般会作为讲故事的主角,因为他们是最了解故事的人。但是最终用户代表只能从用户的角度来描述故事,这里会缺失很多技术细节。当他们开始讲故事的时候,技术人员就需要补充这些细节,将那些从用户角度看上去可能很简单的故事后面所涉及到的复杂度暴露出来。 产品经理和项目经理:这两名成员基本起到协调人的作用,一般产品经理(PO)偏向用户,项目经理(ScrumMaster)偏向团队。我们希望他们的这种倾向性能够在讨论过程中体现出来,将故事的优先级、重要程度、实现难度等问题进行归纳总结,形成我们的项目计划。同时,这个故事讨论的过程一般都是以会议形式进行,这2个人应该作为会议的组织者(主持人)出现,引导团队高效的完成讨论过程。 技术骨干:首先技术人员要明确自己也是主角,而不仅仅是旁听。很多人都有这样的体会,明明很简单的一个功能,为啥做起来会那么慢?这里面有2个原因:第一个是用户自己没有把这个所谓的“简单”功能想明白;第二个是一个对用户“简单”的功能,对于技术来说恐怕没有那么简单,但这个信息一般很难跟用户讲明白,所以很多技术就倾向于不说或者说的很少,结果就是双方对于难度的认知不一致。技术骨干参与这个讲故事的过程的目的,主要就是为了帮助用户从技术实现的角度理解故事,同时自己也能够将技术实现的思路想明白。
-
如何组织需求讨论会? 讲故事的过程一般通过需求讨论会的形式来进行,确保以上应该参与的人员都到场。既然是个会议,我们就必须确保会议的高效,这里可以参考三星高效会议的8点原则: 凡是会议,必有主题。 凡是主题,必有议程。 凡是议程,必有决议。 凡是决议,必有跟踪。 凡是追踪,必有结果。 凡是结果,必有责任。 凡是责任,必有奖罚。 凡是奖罚,必须透明。 针对需求讨论会,我们至少需要有以下安排: 会议主题:XXX产品需求讨论会,目的是在4小时内对XXX产品的XXX内容进行讨论。 会议议程: 组织者:产品经理XXX或者项目经理XXX。 参与者:业务方或最终用户、产品/项目经理、团队技术人员(架构、开发、测试等)。 讨论内容:按照优先级排序的故事列表。 会议分工: 主持人:由产品经理和项目经理轮换组织。 需求记录人:由技术团队内某人承担,负责在讨论过程中将用户故事和所产生的功能点进行详细记录,形成文档或者录入系统。 问题记录人:由技术团队内某人承担,负责在讨论过程中将无法现场确认的问题进行记录,形成文档或者录入管理系统。 会议交付物: 针对议程中的每个用户故事所产生的文档或者管理系统记录。 讨论过程中所记录的问题列表或者管理系统记录。 针对用户故事文档的下一步操作,如:制定开发计划,预算等等。 针对问题的跟踪方式,如:问题列表的状态由谁负责维护,每个问题由谁负责解决跟进,每个问题预计解决的时间。 需求讨论会的过程就是按照以上3个步骤讨论故事和分析故事的过程,我们可以按照以下流程进行: 讨论会前期准备 可以在进行正式的需求讨论会前先进行一次头脑风暴,邀请用户和技术一同参与,在这个过程中大家可以自由讨论,目的是让大家现对产品的大致情况有所了解。 讨论会过程 首先由主持人(产品经理PO/项目经理Scrum Master)向团队列出会议所要讨论的故事列表,这个过程不用讨论细节,目的是让大家知道会议的内容和目标,便于控制进度。 根据所列出的故事列表优先级,从第1个故事开始梳理故事主线,分解功能点,并由专人负责记录。 重复以上过程直到完成列表中所有故事的讨论。 注意事项 一定要按照故事列表逐个讨论,每个讨论都要细化到功能点并完成记录,再进入下一个故事的讨论;不要先讨论所有故事主线,在一并分解功能点。这样做的目的是让团队可以聚焦,避免多条线索交织造成干扰。 在讨论每个故事的时候,不要讨论与当前主线无关的内容,特别是技术团队容易从一个功能点扩散到其他功能点,因为这是技术团队对产品的视角,这种扩散会降低效率。主持人在看到这种情况的时候应该适时制止,告诉团队其他的功能点可以留到其他故事中讨论,只要的产品的一部分,我们在后续的故事中肯定会涉及。 完成每个故事的讨论后可以进行短暂休息,在讨论过程中要确保每个参与成员都集中精力,避免形成小组讨论的形式,建议每个故事的讨论都站立在白板前进行。 主持人可以由PO和Scrum Master按照故事进行轮换,主持人的主要职责是确保过程的顺畅,团队精力的集中。 待确认事项:建议在白板上开辟一片区域,对讨论中出现的团队无法当场确认的问题进行记录,避免在这些问题上纠结太久,影响会议效率。
-
DevOps转型的研发工具链 快速交付的关键是“自动”与“可靠”。自动是一个很宽泛的词汇,在软件交付中代表着测试自动化、交付自动化、运维自动化等,而可靠讲的是每一次交付要保证是当前的交付是稳定的或可回滚到稳定版本的。 为了解决“自动”与“可靠”的问题,敏捷开发鼻祖Martin Fowler提出了持续集成与持续交付的概念,它所描述的软件开发,是从原始需求识别到最终产品部署到生产环境这个过程中,需求以小批量形式在团队的各个角色间顺畅流动,能够以较短的周期完成需求的小粒度频繁交付。频繁的交付周期带来了更迅速的对软件的反馈,并且在这个过程中,需求分析、产品的用户体验和交互设计、开发、测试、运维等角色密切协作,相比于传统的瀑布式软件团队,更少浪费。通过这种小步快跑的方式,将小功能快速迭代、验证、交付,通过自动化的工具,将测试、部署、运维自动化,减少需求在软件生命周期中流动的时间。 华为将自身积累的先进研发能力与优秀实践开放,融合敏捷、精益、DevOps等先进研发理念,打造开放完整的云端开发生态,推出了一站式、全流程、安全可信的DevOps云平台——CodeArts,详情请参见CodeArts产品概述。
-
DevOps概述 DevOps,即Development and Operations,是一组过程、方法与系统的统称,用于促进软件开发、运维和质量保障部门之间的沟通、协作与整合。DevOps的出现是由于软件行业日益清晰的认识到:为了按时交付软件产品和服务,开发和运维工作必须紧密合作。DevOps可看作开发、运维和质量保障(QA)三者的交集。 DevOps运动源自于提高IT服务交付敏捷性的需要,早期出现在许多大型公有云服务提供商中,并被其认可。支撑DevOps的理念基础是敏捷宣言,它强调人(和文化),致力于改善开发和运维团队之间的协作。从生命周期的角度来看,DevOps的实施者也试图更好的利用技术,尤其是自动化工具,来支撑越来越多的可编程的动态的基础设施。
-
DevOps的技术实践 配置管理 软件配置管理的核心功能是版本控制。版本控制系统是一种软件,可以管理代码的所有版本并跟踪代码中的更改。 分布式Git VS 集中式SVN 版本控制系统分为集中式和分布式两种工作模式,Git和SVN是最为广泛被使用的代表,Git由于其诸多特点,更适合DevOps。 安全性——Git是分布式,而SVN是集中式,存在单点故障风险。 分支功能——Git分支功能强大,便于查询和追溯分支间的提交历史,且支持双向合并。 发布控制——Git发布控制相当灵活,而SVN并没有明确的发布控制配置。 开发审核——Git支持团队成员自建分支和版本库,从提交说明、代码规范等方面对提交逐一审核;而SVN则不具备这些功能。 合并支持——Git基于DAG(有向非环图)的设计比SVN的线性提交提供更好的合并追踪,避免不必要的冲突,提高了工作效率。 存储方式——Git把内容按元数据方式存储,而SVN是按文件。 包文件 包文件通常不放在源码库中管理,而是使用专门的包文件仓库(repository)进行存储,并配合包文件依赖管理工具(Maven、npm、Ivy等)进行使用。包文件仓库可以大致分为本地仓库、私服仓库、中央仓库三种。本地仓库是指开发者个人PC中包文件的存储;私服仓库通常是企业为了提升包文件使用性能而搭建的局域网内共用的包文件仓库,通常使用开源的Nexus、artifactory等工具搭建;中央仓库是指开源包文件的共享社区。 开发人员对包文件的使用集中在下载、搜索、发布上传几个操作上。开发和构建时,开发人员通过包依赖管理工具定义好需要使用的私有及开源包文件,在构建或运行时自动从私服仓库或开源中央仓库中下载依赖包文件来提升开发效率。 持续集成(Continuous Integration) 持续集成(CI)是一种软件开发实践,即团队的成员经常集成他们的工作,通常每个成员每天至少集成一次——这导致每天发生多次集成。每次集成都通过自动化的构建(包括测试)来验证,从而尽快的检测出集成错误。 持续集成过程中的角色与职责如下: 角色 职责 开发人员 完成开发任务,并在向版本控制库提交代码之前,先在本地环境完成一次私有构建。 修改反馈回来的代码问题,保持集成构建的绿灯状态。 测试人员 根据项目进展随时更新自动化测试脚本,并保证代码覆盖率达到团队要求。 运维人员 根据开发人员的需要,及时更新维护自动化构建脚本。 维护整个CI流水线的正常运行。 持续交付(Continuous Delivery) 持续交付(CD)是从构建环境到生产环境的构建、测试、配置和部署的过程。 持续交付是一种软件工程手法,让软件产品的产出过程在一个短周期内完成,以保证软件可以稳定、持续的保持在随时可以发布的状况。它的目标在于让软件的构建、测试与发布变得更快以及更频繁。这种方式可以减少软件开发的成本与时间,减少风险。 基础设施即代码(Infrastructure as Code) 作为代码的基础设施(IaC)是描述性模型中的基础设施(网络、虚拟机、负载平衡器和连接拓扑)的管理,使用与DevOps团队用于源代码相同的版本。与同一源代码生成相同二进制文件的原则一样,IaC模型在每次应用时都会生成相同的环境。 IaC是DevOps的关键实践,与持续交付结合使用 。 实施IaC的团队可以快速、大规模的提供稳定的环境。团队通过代码表示环境的期望状态,从而避免手动配置环境并强制实现一致性。使用IaC进行基础架构部署是可重复的,可防止因配置偏差或缺少依赖性而导致的运行时问题。DevOps团队可以与一组统一的实践和工具协同工作。快速,可靠,大规模的交付应用程序及其支持基础架构。
-
快速交付实战演练 流水线的成功和失败都是一种状态,失败也不用怕,可以帮助我们发现问题。 我们的最终目标还是要提升成功率,尽量检查出由于配置出错导致的构建失败,或者个别服务出现问题。我们可以看到历史构建的软件包,选择一个进行回滚。在代码检查时,可以做一个代码质量门禁,例如这个代码检查任务执行完之后,发现原来有100个问题,现在修复完95个,只剩5个,如果预定的门禁是10个,就可以继续向下跑。API测试也是这样,测试门禁里面生产百分之百,如果有20个没有通过,继续执行就会失败,要修复完所有环节才可以继续执行。 此外,任务还有健康度,可以看到哪个任务失败次数多。对已经关联流水线的代码进行修改提交后,可以重新执行流水线。在此过程中,可以看到构建任务在运行中,也可以直接看到日志并下载全量。构建任务执行成功,流水线会流转到下一个环节,直至部署成功,访问对应页面查看效果,代码修改生效。这就是如何修改一行代码,能够保证让用户满意,真正快速地发布到现网。 在代码仓库中可以设置提交后自动触发流水线,例如同一个代码仓拥有两个分支,可以分别设置是否提交后触发流水线,设置后,不需要手动执行流水线,它会在提交代码后自动执行。这是前文提到的两种模式中的一种,叫做随机发生模式。 还有一种模式是定点发车。每天指定时间执行流水线,如果这是一条版本级流水线,或者是一条项目级流水线,我们可以去设置每天什么时候自动执行一遍,无论是否有提交或者合并,到时间都会执行,如果有,则对已有的结果进行质量的测试和监控,并且最终保证流水线交付的应用质量是没有问题的。 在流水线中,失败率最高的Top3任务被面标识出来,按照执行失败的次数排序,我们可以看到哪些环节是健康的,哪些环节阻碍了任务的继续执行,所以这是一个非常好的实践。 对于健康度,失败率Top3的子任务(流水线每个环节中的任务)会在整条流水线中标识出来,并且可以按照执行失败的次数进行排序。由此,可以发现哪些环节是健康的,哪些环节阻碍了任务的继续执行,这是一个非常好的实践。 此外,在CodeArts的需求规划中,可以看到工作项关联的代码提交记录,并直接跳转查看提交的代码的内容,非常方便查看、追踪基于需求的代码运行情况以及应用发布情况,并且还可以关联bug,真正实现了端到端的双向追溯。这就是整个流水线的演示。 此外,CodeArts还支持移动端的移动运维,如果装了CodeArts APP,就可以在家里,或者咖啡馆、高铁上面随时可以查看流水线执行结果,并且可以再次执行它,察看它的错误码、错误日志,以确保随时随地的移动运维,移动交付。
-
DevOps在华为 在华为的研发历程中,IPD(集成产品开发)的影响比较大,从IPD引入华为之后,华为的研发模式才真正做了集团化、正规化的研发模式道路。此后,如测试自动化工厂、DevOps、CI、DevOps大规模敏捷等等,每次研发模式的变更都会带来一部分工具的沉淀,工具本身又会随着模式和技术的变更不断的发展。例如,华为的研发工具部在2003年左右就成立了,最早聚焦在测试自动化工厂方面,包括软件自动化工厂、硬件自动化工厂等等。在CI方面,华为后来引入了持续集成的工具和平台,以及持续交付(CD)的流水线,未来还有随着微服务化、基于无线化的AI流水线,还会继续探索。下图展示了工具和平台发展的过程。
-
不同研发模式下流水线的应用与思考 第二部分重点讲述基于华为的流水线支撑的实践,支持三种主流模式: 第一种模式:大规模开发 华为起家的核心是交换机,交换机本身业务分成多层架构,例如上面的控制层到下面的数据传送层等。在自我分层的基础上,向上对接网管等各种监控工具,再横向和后端的传送网、骨干网对接,进行数据的传递和核心的传递。在这个基础之上,华为做了一个2012实验室——这是一种大平台战略,几乎所有的产品线产品都会用到的公共平台,而且这个平台的能力是重平台薄产品,平台会达到80%的代码量,可能会越来越大。这时候如果产品要用到另外一个BG产品线的平台就是一个非常大的困难了,在产品线内部也会尽量把一些公共特性下沉为小平台,所以一个核心网络产品从各个角度来看,复杂是最核心的特点。 产品的代码量是非常大的。一般来说,一个产品一百万行或者几百万行是非常正常的,需求一千万行也是非常正常的。这么大规模的代码不可能由一个团队开发,CodeArts是由产品线以及各种周边配合,涉及的团队非常复杂。基于时代背景来看,核心网络产品要交付出来,在以前经常需要一年多以上,基本是一年一个版本,半年的时间做线上验证,包括到客户的机房验证,那个时候升级都需要选访问量最低的时候进行半夜断网升级。 怎么保证迭代的速度加快,迭代的质量逐步变得更好呢?后来我们探索了一套模式是分层分级流水线,进行大规模开发的持续交付模式,建立一个合理的结构,我们通常会分成四层。 个人级流水线:团队一般每天提交几次到数十次不等。这时候在本地会先做代码的增量静态检查、增量单元测试,以及功能测试。如果这些检查都没有问题,全部通过,代码会上传到云端配置库。此时触发一个提交构建,就到了项目级流水线。 项目级流水线包括提交构建、滚动构建和全量构建。提交构建通常需要做的是全量的静态检查和冒烟用例。个人级和项目级流水线提交构建,随时提交就能够触发整个构建和流水线的运行和执行,属于随机发生模式。滚动构建和全量构建属于班车模式。班车是定点定时发,无论是坐地铁还是公交车、火车、飞机,时间是固定的,每个人去赶飞机、地铁、公交,如果迟到就需要等待下一趟。对于一个研发团队或者一个产品,一天内代码提交通常有三个峰值,上午10-11点是一个峰值,下午5点左右是一个峰值,晚上8点多有一个属于加班同事的小高峰。所以一般来说,一个项目级流水线会发三个班车,就是中午12点、下午6点、晚上9点半,这三个班车永远是固定的,团队无论有无提交都会发车,定点执行。 这就实现了一个协同,有多个人提交或者每个人提交都会执行,执行的时候会看结果如何。这种时候一般会做基础用例、拉通用例、滚动用例模式。如果定点发车了,会推送到全量构建,解决他们的协同发布。通常是晚上12点会执行一轮,第二天早上整个项目组的同事就收到了流水线测试的结果。如果成功了,大家欢庆一下;如果不成功,就赶快解决问题,因此所有人一早就要解决持续交付流水线的问题。 滚动构建成功之后,还会把这个包归到版本级流水线的构建里面,在版本级流水线里面滚动构建并测试,当这些全部执行成功后,就会再向下游拉通全链条测试。对于版本级流水线,滚动构建也会投入流水线当中,会比项目级构建晚两个小时,如果自动化率足够高,大部分问题都可以解决。 所以,对于一个典型的大规模敏捷产品,我们有四层分级的流水线,里面有随机发车和定点发车的模式,也有实现这样的高速流转的对应解决方案。 在此过程中,流水线在每一个执行阶段都会有一些门禁的判断,任何一个任务跑完了,都有门禁进行把控。只有通过项目组设定的门禁,才能向下走;如果不通过,流水线就终止了,先把基于静态检查的问题解决完,才能继续向下走。这种方式,不像过去有最终的发布评审,到最后的上线环节再搞发布评审,而是在每一个部分就会把所有的门禁做上去,由此来保证在每一个任务的成功和每一个阶段的成功,以保证最终的成功。 此处与传统的交互模式做一下结构比较,传统交付模式越向后的环节越容易出现问题。例如产品级或者解决方案级一集成,越向后,问题会越来越多、越来越大,再返回来到每一个小团队解决问题,实际上这已经比较晚了,解决的成本也很高。使用了分层分级流水线之后,越向前的环节发现越早,就把问题拦截下来了。 从我们的分析和实践结果来看,假设有四层流水线,个人级提交一定最多,因为每天有几次几十次,每个人提交到代码仓的构建在两次左右,除非BUG多一些。再向后就到了班车模式,一般来说,每天进行三次滚动构建。到最后的全量测试,每天执行一次即可。通常越前端的流水线会越早发现问题,原来是最后进行发布评审,现在如果是有了每个任务的质量门禁,每次执行的时候,越在流水线的前端环节,被执行的次数越多,发现问题的概率也越高,符合分层分级流水线的理念结果。 当然,分层分级持续交付的模式下面,会有很多其他构想。包括如何快速搭建第一条流水线,不同层级的流水线如何快速复制,并且搭建自己对应层级的流水线,以及上一级流水线成功后如何自动触发下一级流水线的执行,这些是最基本的思考。 第二种模式:微服务开发 CodeArts团队本是一个微服务化的实践者,有100多个微服务,基本全部微服务化,前端已经全部拆解完。在这个模式下面,首先,架构解耦;其次,结构上最终一定要实现每一个组件足够小,而且尽量没有依赖的。在这个基础上,每一个团队能够比较自由地自我裁决、自我决定。比如发布,以前在传统的模式下,一个团队肯定是要分运维团队、测试团队或者是开发团队、产品团队、QA团队(都是单独的),真正在微服务开发模式下,做成一个全功能团队之后,已经没有非常明显的角色分工,很多功能测试等等都是由开发人员自己去实现的,这个时候对于开发人员来说,既是开发人员也是测试人员、运维人员,会对运维服务的开发、测试、上线、结果,会端到端负责。所以我们针对微服务会做权限的设置,去匹配新的角色模式,一个人可以端到端的执行完整条流水线。上线之前还可以有一个环节,例如和产品经理一起看一下是否满足客户需求等等,如果后续流水线承载的自动化测试的手段都能够完全达到质量发布的条件,届时也不需要评审了。整个过程有40-50%做到不需要人工干预,下一步这个比例还会继续放大。 因为微服务化了,这100多个组件中间还要发一些补丁,一天内都上线是很糟糕的事情,每个微服务中断几分钟,一天下来是几百分钟,整个服务就不可用了。因此微服务模式下一定要实现灰度发布,最基本不能中断业务。 CodeArts团队在最早的时候,每个星期五晚上要12点开放升级,把测试和研发团队、领导都喊起来,整个团队从2点到4点进行测试;测试完成后,4点之前我们决定BUG修复完,再回溯一遍。这个过程每周一次,那时团队成员很痛苦、疲惫,第二天一整天什么也做不了。 后来通过微服务实践和灰度发布实践,才把团队从超级繁忙的、每周一次的超级作战中解放出来,这对团队整体的士气和工作效率的提升都是非常明显的。如果真的发现在灰度测试中出现问题,或者版本有重大的缺陷,要能够触发自动回滚或者手动回滚。这时候运维人员会选前一个包直接启动流水线部署,把灰度测试灰度过的环境全部覆盖掉。 在微服务开发模式下,管理很重要。使用K8S时,如果版本号不增长就不会部署(只要版本不变,就认为是同一个包,因此不会启动部署)。所以版本管理、版本增长等方面都要在流水线上做到位。同时因为这种发布模式时间非常短,我们可以做到小时级、分钟级发布。这种情况下,我们会通过线上A/B、加大测试,在线做各种自动化测试,包括拨号测试、性能测试、压力测试、安全测试等等。在真正大规模灰度之前,就已经把基于真实环境的质量构建好了,其中在线测试、前置测试的比重都要加大。 第三种模式:静态资源部署 静态资源部署不需要重新编译构建出包。通过部署流水线,把静态资源拉包,部署到北京、上海、广州、成都等等各个CDN去。在这个过程中,多地区的并行部署以及跨地域的部署是CodeArts重点支持的方向。
-
流水线关键技术 CodeArts流水线 (CodeArts Pipeline)涉及的关键技术,能够保证用户量增长不会面临宕机。 首先,流水线随时可用、高可用 其次,通过数据云化存储、高隔离、权限控制来保证数据的安全。 执行效率方面,除了并发调度系统,对每个单一任务会做非常多的功能,例如代码预读、分发、增量等等,加速整个流水线的速度。 为了用户的使用成本变得越来越低,尽量将配置简化和维护,提供配置模块以及可集成云化的服务去减少开发工作量。 CodeArts是基于Jenkins的流水线来实现master的调度机制。 CodeArts定义了一种CDDL语言(Continuous Deliver Domain Language),它具备非常好的可扩展性,同时CDDL语言解释器和平台无关,因此可以做到在任何平台上的灵活调度。CDDL的设计参考了UML中的状态机模型,更易于控制。 流水线还涉及到其他的关键技术,支持百万级的并发调度。此外关键技术能力还包括“七个一切”,前四个是一切即代码、版本、服务、数据,在“基础设施即代码”的基础上,引入了这些概念,形成一条可视化流水线。基于以上能力,形成了后三个一切。一切自动化:流水线一旦被调用,可能有几十、几百个步骤,如果全部依靠人工操作,则不可能像自动化流水线一样,有这么高的可靠性和可重复性。CodeArts的流水线是可视化的,可以看到每个环节步骤具体进行的情况。未来产品还将更加智能化。
-
DevOps VS 敏捷 当我们面对敏捷和DevOps的时候,总会不可避免的思考下面这些问题: 敏捷是什么?DevOps是什么?两者有什么区别? 持续集成不是XP里面的么,怎么DevOps也有持续集成? 我们团队之前在做敏捷转型,现在又开始DevOps转型,这两者有什么区别? 其实这些问题并没必要太过纠结,因为敏捷和DevOps两者都在不断演进,两者也的确越来越像。 这个话题注定讨论不清,也注定会有不同的意见。本文也仅从方法论和实践的角度,为开发者简单论述敏捷与DevOps。希望每位读者都会从本文中得到自己的理解与启发 ,帮助大家在敏捷与DevOps这两条路上走的更远。 先说本文的观点: ▪ 敏捷与DevOps初衷、目的是为了解决问题,而不是为了树碑立牌,更不是为了占领地盘。 ▪ 两者并非泾渭分明,也没有一条线能够划出来,说哪边是敏捷,哪边是DevOps。 ▪ 讨论敏捷与DevOps,目的是为了了解两者之间的内在联系,而不是为了划清界限。 ▪ 经常被讨论的,是狭义的敏捷与DevOps概念,而广义的敏捷与DevOps,已经趋同。 ▪ 两者都是试图去解决相同,或相近的问题,只是还没有能一招解决所有问题的办法出现。 接下来, 让我们从狭义的角度看二者的区别。 传统的敏捷是为了解决业务与开发之间的鸿沟。通过敏捷宣言中强调的个体和互动、可工作的软件、客户合作、响应变化,以及12条原则中的尽早的以及连续的高价值交付、自组织团队、小批量交付、团队节奏、可改善可持续的流程、保持沟通等,以及包括Scrum、Kanban、XP在内的众多管理和工程实践,来实现开发与业务之间的频繁沟通,快速响应变化。 而DevOps的出现,是为了解决开发与运维之间的鸿沟。前端的敏捷的确是快了,却发现因为Dev与Ops之间的隔阂,无法真正的将价值持续的交付给客户。 开发侧很快,运维侧太稳,这个就是我们常说的开发与运维之间固有的、根因的冲突,即下图中的混乱之墙。开发(尤其是“敏捷”后),求的是快速响应变化;运维,求的是稳定、安全和可靠的服务。更重要的,两者的KPI度量指标,绩效考核激励机制不同,决定了如果为达成各自的局部目标,势必存在无法调和的根因冲突。 DevOps的出现,就是为了打破开发与运维之间的部门墙,从这点上来说,“DevOps是敏捷在运维侧的延伸”这一说法也不无道理。只是,敏捷与DevOps,都已经不再是原来的那个敏捷和DevOps了;世界变化太快,问题域发生了变化,解决方案域自然也要随之变化。 敏捷的好处是,有一个敏捷宣言,宣告其诞生。敏捷的缺点,也许也是因为有敏捷宣言。敏捷宣言并不应该被拿来约束和限制敏捷的范围,敏捷宣言也说拥抱变化,宣言诞生于2001年,时至今日,也会与时俱进,只是后来再没有这样的一个标志性的事件来做声明。 DevOps的不好之处,是没有一个明确的定义。DevOps的好处,却也正是因为没有一个明确的定义做限制,所以拿来主义,一切好的东西,都可以为我所用。 DevOps是个筐,什么都可以往里装,敏捷又何尝不是呢? 通常人们对DevOps的理解有两方面,即D2O和E2E。D2O,Dev to Ops,即经典、狭义的DevOps概念,解决的是Dev到Ops的鸿沟。E2E,End to End,即端到端、广义的DevOps,是以精益和敏捷为核心的,解决从业务到开发到运维,进而到客户的完整闭环。DevOps的6C概念,即Continuous Planning、Continuous Integration、Continuous Testing、Continuous Deploy、Continuous Release、Continuous Feedback,也是端到端广义的DevOps。 维基百科中总结到,DevOps的出现,有四个关键驱动力: 互联网冲击要求业务的敏捷 虚拟化和云计算基础设施日益普遍 数据中心自动化技术 敏捷开发的普及 从种种概念可以看出,业务敏捷、开发敏捷、运维侧自动化、以及云计算等技术的普及,几乎打穿了从业务到开发到运维(包括测试),所以虽然字面上是Dev到Ops,事实上,已经是BizDevTestOpsSec了,即从狭义的D2O,前后延伸到E2E,端到端广义的DevOps了。 多位DevOps大师曾基于多年DevOps现状报告,汇聚出来了一个DevOps能力成长模型。在DevOps能力模型中,DevOps的最终的目的是组织效能,软件交付和运维效能是敏捷与DevOps共同的目标。 持续交付是狭义DevOps的核心理念,横跨了架构、开发、测试、运维等角色。持续交付的核心开发实践,也涵盖了架构管理、版本管理、分支策略、测试自动化、部署发布、运维监控、信息安全、团队授权、数据库管理等多个维度,其中不乏我们常说的传统的敏捷相关实践,尤其是下图中XP极限编程的很多实践,半数以上在DevOps里都能找到。 能力成长模型,除了持续交付,还包括精益领导力、精益产品开发、精益管理、组织文化与学习氛围。DevOps已远远不是CI/CD那么简单,CALMS原则也横跨了文化、管理、精益与技术。 敏捷宣言的十二条原则、SAFe的九大原则、以及DevOps的CALMS原则,也是彼此相互融合。SAFe有借鉴DevOps的理念和方法,DevOps又采纳敏捷的思想和实践,大家又都以精益为思想核心。那么谁包含谁,谁比谁大,彼此的界限在哪里呢? 由此可见,方法也好,实践也好,其价值应该由客户价值来体现。对客户而言,需要解决的问题,是端到端的,是全局而不是局部优化。 所以,是什么,不重要。能解决什么,要解决什么问题,很重要。 DevOps是集大成者,是各种好的原则和实践的融合,敏捷又何尝不是如此。2001年的17位雪鸟大师,各自在践行着不同的敏捷框架和实践。敏捷宣言和原则,原本就是一次融合。2003年Mary Poppendieck和Tom Poppendieck的精益软件开发方法,即便是已经有敏捷宣言的前提下,也一样纳入敏捷开发的范畴。敏捷也是在不断前行,DevOps与敏捷殊途同归,是同一问题的不同分支,最终汇集到同一个目标。 一个好的方法论,应该是与时俱进,兼容并蓄的;应该是开放的,演进的而不是固化的。 方法论如此,学习和实践方法论的人,更应该如此,以一颗开放的心态,接纳一切合理的存在。 本文参考资料: 《DevOps explained》 Jérôme Kehrli 《Accelerate》 父主题: DevOps概览
-
分支策略 我们都知道分支的意义,也知道它的用法,然而不同的分支管理方法对项目所起到的帮助也是不同的,下面就让我们来看看几种常见的分支策略,以及如何通过CodeArts来管理分支。 Github flow 特点: 令master分支时常保持可以部署的状态。 在新建的本地仓库分支中进行提交。 以合并请求进行交流。 让其他开发者进行审查,合并前的代码要经过测试。 操作步骤: 创建分支 在你创建了一个项目的分支的时候,你也就创建了一个可以尝试你的新想法的环境。 你的分支名称应该具有描述性, 以便其他人通过分支名称就可以知道它到底是干什么用的。 添加提交 每个提交操作都有一个相关的提交信息,用于描述你做出的修改。 通过写清楚的提交信息,你可以让其他人更容易跟上我们的思路并提供反馈。 提出合并请求 合并请求开启了一个关于你的提交内容的讨论。 当你有很少或没有代码但想分享一些截图或一些想法的时候;当你卡住了需要帮助或建议的时候;或者当你准备好了让人来审查你工作的时候,合并请求启动代码审查和有关更改建议的会话。 讨论和评估你的代码 审查你的更改内容的人或团队可以提供一些问题或者意见。 你也可以在大家讨论和给出关于你提交内容的反馈时, 继续Push修改你的分支,来解决问题。 部署验证 合入master代码前的最终部署测试,用真实环境检验版本的正确性。 合并 合并之后,合并请求会保存一份关于你修改代码的历史记录。 通过将某些关键字加入到你的合并请求文本中,你可以将问题与代码关联起来。 Gitlab flow 生产分支 一个反映已部署代码的生产分支。 将master的代码合入production。 可消减Git flow中releasing、tagging、merging的开销。 环境分支 提交仅向下游流动,确保在所有环境中测试所有内容。 如果要做hotfix,在一个功能分支上开发,然后合入master,master通过自动化测试后,将feature分支逐步向下游合并。 发布分支 一个分支就是一个版本。 尽可能在master测试修改完,再开发布分支,减少多分支的bug修复。 声明了发布分支后,该分支只接受严重bug的修复。 bug的修复先合入master,再往发布分支合入,上游优先策略。 每在发布分支接受bug修复,都要使用新标签标示出来。 以上就是当前行业中集中比较流行的分支策略,CodeArts提供了基于Git的版本控制系统,接下来让我们看看如何应用CodeArts帮助团队管理分支。 通过CodeArts我们可以完成分支的创建与管理,对分支进行保护、创建合并请求、对代码的合并进行检视及评分、批准合并请求等一系列操作。 新建分支 可以通过CodeArts提供的代码仓库直接创建分支,也可以通过本地仓库创建分支进行同步。 分支保护 可以设置对某一重要分支进行保护,防止误操作对交付造成影响。 合并请求 开发者提交的合并请求可在CodeArts中进行管理,通过对合并内容的检验,决定是否合并。 代码检视与打分 在CodeArts的版本控制系统中,还提供丰富多样的功能设置,例如IP白名单、子模组、webhook等常用的功能设置。运用版本控制系统,我们同样还可以进一步完善我们开发项目的软件配置、环境配置管理,关于如何进行软件配置管理与环境配置管理就不在此详细说明了。想掌握更多更详细的CodeArts代码仓库使用方法,详见代码托管用户指南。
-
代码提交与分支创建 首先,让我们简单了解一下Git的一些基本概念,方便我们更好的理解代码提交与分支合并之间的逻辑关系。 Git有三种状态,你的文件可能处于其中之一: 已提交(committed):数据已经安全的保存在本地数据库。 已修改(modified):修改了文件,但还没保存到数据库中。 已暂存(staged):对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。 Git仓库、工作目录以及暂存区域 Git仓库目录: Git用来保存项目的元数据和对象数据库的地方。这是Git中最重要的部分,从其它计算机克隆仓库时,拷贝的就是这里的数据。 工作目录:项目的某个版本独立提取出来的内容。 从Git仓库的压缩数据库中提取出来文件,放在磁盘上以供使用或修改。 暂存区域:是一个文件,保存了下次将提交的文件列表信息,有时候也被称作“索引”。 基本的Git工作流程如下: 在工作目录中修改文件。 暂存文件,将文件的快照放入暂存区域。 提交更新,找到暂存区域的文件,将快照永久性存储到Git仓库目录。 从上面的基本概念中我们可以了解到,Git的常用基本操作其实很简单,然而同一个工具,不同的用法产生的效果却是迥然不同的,这就要求我们在使用版本控制系统的时候尽量遵守规范,更能使工具发挥出它应有的价值。下面让我们来看看在代码提交和分支合并的时候应该遵守哪些规范: 分支具有描述性 一个好的分支名称应该具有描述性,以便其他人通过分支名称就可以知道它到底是干什么用的。 提交要做对 “好的文章不是写出来的,而是改出来的。”代码提交也是如此。 一个提交做好一件事情: 保持每个提交的正确性,不要一系列提交都在不停的修改同一个问题,如果是这样,请将它们合一。 每个提交要独立,不要混杂其他的功能。 提交要做小: 如果一个提交,修改了过多的内容,那么对检视者就是个灾难。 尽可能的拆分,让你的逻辑有延续性,并且可读。 清楚的提交信息 通过写清楚的提交信息,你可以让其他人更容易跟上我们的思路并提供反馈。 提交说明要回答如下问题: What——要解决什么问题? When——什么情况下会发生? How——怎么样解决这个问题? Why——为什么这样解决是合理的,比其他解决方法更好? 合并请求的提交要清晰 一个好的合并请求不只是代码的事情,还牵涉到代码审查者对代码的审查,所以开发者不仅要写出好的代码,还需要考虑如何让其他人更清晰的理解自己的想法和思路,这是一个用代码做交流的过程。 进行较小的合并请求。 每个合并请求只做一件事情。 代码行的字数,最好少于80个字。 避免重新格式化代码。 确保提交的代码能够编译通过并能通过所有测试。 详细记录下自己提交的原因。 避免重复修改和混入其他的merge。 了解了如何做好一次规范的提交与合并,接下来让我们看看通过CodeArts中的版本控制系统都能完成哪些具体的实践。 由于CodeArts提供的是基于Git的版本控制系统,因此所有Git的相关操作都可以在CodeArts上实现。 配置秘钥 管理代码仓库 查看提交记录 提交代码并关联工作项 通过CodeArts我们可以将每次提交的代码记录与相应的工作项进行关联。 在提交代码时,备注信息中输入fix #工作项编号即可在工作项的代码提交记录页面,查看到相关联的代码提交记录。
-
构建全功能团队 华为用的是全功能团队,华为对全功能团队有自己的定义。华为有这样的特点:任何一个方法论,在华为有自己的定义,这个定义跟业界的定义可能不完全一样。 总的来说,全功能团队在华为的定义是:能够对特性、部件或者架构完整的实施规划、需求、设计、开发、测试并独立交付、运维的项目型团队。在华为所有产品都在向这个方向发展。从前一个大型产品线所有决策都是一层一层往上升级报告,现在就是往全功能团队发展,产品经理决定全权决定产品做什么,什么时候做,什么时候上线,产品的规划是什么,产品的竞争力在哪里,目标客户群在哪里。团队负责把产品交付出来。 CodeArts共有十个服务,以需求管理服务为例,团队的组织结构有一个产品经理,还有架构师、UED设计师、开发工程师、测试工程师、运营人员,一个服务的规模差不多有10人左右规模。每个服务是不一样的,有的规模大一些十几个人,有的服务规模小,只有几个人,不管规模大小,所有的职能角色都是全的。并不是说团队里的人都是全栈的,比如UED、运营人员并没有配备给团队的全职人员,属于公共资源,只是为某几个服务工作。
-
华为DevOps一体化平台框架 框架并不只是平台本身,既包括理念又包括管理流程,工具只是DevOps的一部分。如果只有工具其实是不够的,最终还是人去工作。 华为的管理流程上应用了Scrum、看板,在内部产品线还用了规模化敏捷,在华为叫产品级敏捷。华为的Scrum和书上的Scrum有区别,华为没有Scrum Master,没有完全复制Scrum。并不是说标准Scrum有什么问题,而是应该结合自身进行取舍。 组织结构上,华为实施的是全功能团队,华为所有的产品线都在做全功能团队,端到端地覆盖全部流程环节,从0到1。团队初期,成员人数少、工作内容全面繁杂,从研发到拜访客户、跟政府洽谈,想办法为产品找到市场,后期规模化后依然保证团队是全功能团队。 在工程实践上,与各个公司相差无几。在平台上,使用华为云CodeArts:DevOps一站式平台。 正如康威定律:系统的架构受制于组织结构的沟通方式。在很多公司里的实际情况是,由于组织结构决定了系统架构,而系统架构又很难改变,所以当试图改变组织结构的时候,发现组织结构又受制于系统架构而很难改变。当尝试DevOps转型的时候,最后总是因为架构的原因很难走到下一步。 以CodeArts团队为例,在达到产品和市场适配之前采取微服务架构恰如其分,因为其不需要建设复杂的组织结构,微服务架构完全能支持组织的规模化。但是对于很多传统企业来说,有很多层次化、职能化分工的组织结构。如果能把架构服务化,就会逐渐发现:很多层次的决策人员、管理人员的价值淡化了。 在华为,这一点很多产品都发现了,华为的很多产品线都采取微服务,至少做架构服务化。原先很多的经理做团队之间的对齐、计划、协调,召集所有的Scrum团队在一起一周开几次会对齐节奏。采取微服务后,这些活动变得并不是那样必要,甚至这些角色的价值也淡化了,因为每个团队都非常独立,不需要再找中间人拉通对齐。现有传统的组织结构,其存在有它必然的历史原因,但并非存在即合理。本质上如果把架构做服务化,那现有的组织结构中的很多层级实际上就慢慢不再需要了。 华为的大部分产品线都以大规模敏捷框架SAFe开展规模化敏捷,华为称为产品级敏捷。因为华为的组织结构和这个框架里的组织结构一层一层匹配,每一层都有管理决策、架构的决策,跟华为正好匹配上,华为当时选SAFe是因为这个框架非常合适做从上到下的大规模转型。这些人的角色保留,工作没有丢,只是换一种方式找到自己的位置,这是愿意接受变革的前提。在做DevOps的过程中发现实际上慢慢不是特别需要这个角色了。CodeArts从来没有用这个大规模敏捷框架,因为团队是从0到1爆发式增长过程走过来的,一开始就不是以这个为基础来做转型的,现在已经百人以上,没有用这种框架,我们做的也很好,所以框架并不是必须的。
-
DevOps转型策略 华为是如何实施规模化的精益DevOps转型呢? 在华为,所有的项目都在尝试着某些能力提升的实践,华为十年前就开始做敏捷,过去十年一直在尝试各种能力提升的实践,到现在全面开展DevOps。之所以要强调“所有的项目”是因为很多公司在尝试任何转型时,总是有大部分项目都说自己没有时间,因为进度紧张、交付压力大,以此为由不做。但在华为所有的项目都做,为什么?没什么原因,就是自上而下要求。为什么会有这样的要求?因为有自上向下传递的危机感,必须要保持自己企业的业界领先地位。一个企业如果不在自己的行业里处于第一、第二位,那么实际上就等于死,只是个时间的问题。遵从这样的观点,就必须持续保持自己的领先地位。怎么去平衡改进和交付的压力呢?既要保证业务交付,也要同时造血,提升自己的研发能力,以CodeArts的经验来说,用70%时间交付产品,30%时间改进,即便已经实施了DevOps仍然还在做改进,架构还在持续重构,产品经理也愿意给团队30%的时间做投资在能力提升上。 变革大师约翰科特写过一本书《领导变革》,里边介绍了变革八步曲,《DevOps Handbook》里有一章专门讲DevOps转型策略,其实就是将约翰科特的变革八步法应用在了DevOps转型领域。变革八步法可以用在任何组织变革,而且这八步是顺序,不能逆序,也不能跳跃。做转型跟八步法有相似之处,但也不完全一样,如果严格一步步实施这八步法就要花很长的周期,这样做变革满足不了时代对我们的要求,所以转型一定要像做敏捷一样小步快跑。 华为的变革策略是: 第一步,把危机感和紧迫感植入组织的血。华为本身就有很强的危机感和紧迫感,需要不断植入,时刻唤醒大家的危机感和紧迫感。每当团队觉得自己做的很好,马上就会有更高的目标要求团队,牵引团队做得更好。 第二步,做大规模转型时,发布红头文件,在产品线试点的时候,产品线的最高领导要签署文件,表态团队要做这个事,全员都要配合。如果想推进变革,第一件事情就是要得到最高领导的认可,在华为基本上这一步走到了,后面就能够顺利开展。 第三步,自上向下设定能力提升目标。做转型一定要有明确的量化目标牵引,如果没有这样目标的牵引,基本上得不到团队成员的支持,在转型的过程中也要时刻监控量化的结果。 剩下的几步需要迭代进行。 产品线领导自上向下沟通、贯彻,产品线领导要决定做一件事,就要全员沟通这个决定,鼓励大家都要去做,没有其他选择。 产品线领导自上向下沟通、贯彻,产品线自己全权负责:怎么做,什么时候做。 然后,产品线决定试点适合哪个部门做,有效果之后马上全部铺开。这个过程不会慢慢地做好几年,试点团队有了初步效果之后马上全面铺开。 接下来,横向传播,横向往另一个产品线传播,其它产品会受试点产品线的影响来转型,受影响的力度更大。 最后一步固化实践形成文化,如果这个过程中间某一步做的不够好马上返回到上一步,可能再去跟产品线领导去沟通,保证领导的支持力度一定要长期存在。这就是我们的转型步骤。
-
管理流程实践 CodeArts现在的管理流程是一周一个迭代。 在做DevOps转型和DevOps微服务之前,产品是三周一个迭代,团队没有采用瀑布,而是采用持续交付。 转型后,发布周期由三周变为一周,一共十个服务,每个服务一周一个迭代,一个迭代发布一次,所有服务不在同一天发布,因此对客户的感知是每天都有新版本上线。每周迭代过程与Scrum类似,但是又不完全一致。因为当一个团队达到持续交付能力的情况下,Scrum的一些流程性工作就变得不是特别重要。产品经理一周之内做两次验收,第一次是在转测环境验收,检查开发内容是否与当时沟通的一样,第二次验收是线上环境验收。另外,关于用户故事点的估算,当团队能达到这样的快速交付的速度后,故事点的故事也不是很必要,因为产品经理很清楚团队吞吐率是多少,比如,团队有十个人,按照历史吞吐率团队一周能做差不多十到十五个story,按照这样的吞吐率做迭代计划就可以了。 介绍一下CodeArts的迭代三重奏实践:指的是产品经理计划两周的需求、UED设计人员设计一周、开发人员开发一周。做迭代三重奏的本质原因是团队在很长的一段时间里受制于一个约束:UED设计。根据约束理论,一个系统的效率受制于这个系统的约束环节,约束环节可能不只一个,约束环节决定整个系统的产出效率。团队的UED设计师属于公共资源,不专属于为一个服务工作。当团队实施了DevOps,交付效率提升之后,但是其它环节没有提升,而没有提升的环节自然就成为约束环节,比如说UED设计师的设计速度不能像开发人员每周上线特性一样快,所以设计人员的效率是没有办法跟上团队的脚步的。在这种情况下,把设计和开发人员的节奏错开。设计师需要专注,设计是一个创造性的过程,尤其是大特性的设计需要给予专注的时间做设计,UED有一周的时间专注设计,设计产出隔一周给开发人员做输入,从而解决了瓶颈,同时没有额外添加设计师。 再介绍一个管理流程实践:全价值流看板。由于每个服务都是全功能团队,不依赖其他团队,每个服务都建立自己的看板,设计、开发、测试、上线,所有流程,到了什么环节所有人都看得非常清楚。产品经理每天就可以盯着看板上的需求流到了什么环节,如果到了转测就到转测环境里验收,如果已经上线了就在线上环境再验收一遍。每个服务都会有自己的看板。做了微服务和全功能团队之后,服务之间偶尔会有依赖,会需要另一个服务提供接口,如果完全没有依赖就不能成为一个产品,这时候只需要点对点沟通就可以了。比如编译构建服务团队需要需求管理服务团队提供接口,不需要把所有服务的人员召集起来开大会,只需要做点对点的对齐即可。 DevOps Handbook整本书其实只有三句话:实施DevOps有三步。 从工程实践来说,刚才介绍的是第一步:从左到右建立价值流。不只是管理流程上建立,还要从技术实践上建立。 实施DevOps的第二步是:从右到左建立快速的持续反馈。由于每个服务都以全功能团队为单位组建,因此每个团队都可以建立自己的持续交付流水线,能够快速获得反馈。 此外,还要建立用户数据反馈。一开始做产品的时候,不需要太多的用户数据,因为客户量非常少,还在验证产品是不是打中客户的刚需,客户离开产品会不会觉得不爽,在很长一段时间之内靠人力就能够获得反馈。比如,几个产品经理一段时间都去客户那办公,坐到客户办公室里,观察客户怎么用产品,有什么问题,白天吐槽,吐槽之后赶紧让团队改。这个阶段不需要数据也是可以的,但是过了这段时间之后,比如产品做大规模的市场拓展,跟很多城市的政府签了合作协议,与很多高校也签了合作协议,同时拓展了大量企业。收到很多吐槽、反馈,这时候没有数据就不行了。 因此,一定在达到这个阶段之前建立用户数据分析系统,从而指导产品决策。如果没有系统指导产品决策,就只能通过客服反馈。如此一来,通过碎片化的反馈,每天需求都像洪水一样涌来,没办法做出高质量的决策。必须通过量化方式指导产品决策,在产品规模化推广之前搭建数据分析系统,如果在之后做会非常痛苦。 DevOps实施的第三步:建立高度信任的持续学习和实验的文化。文化看似虚无缥缈,实则非常重要。实际上文化并不是做DevOps转型就能建立的,文化是这个企业自带的基因,文化是企业创始人个人价值观的放大和延展。每天的工作实际上都在渗透价值观,如果想将文化固化在企业里,必须要在每天工作中得以渗透,否则文化就只能停留在纸面上。 华为有两个重要的关于“长期坚持持续自我批判”的文化的实践。一个是质量回溯:当发现质量问题时马上召开质量回溯会议,团队在一起讨论发生了什么,本质原因是什么,下次怎么避免。第二个实践是事后回顾,回顾这个迭代哪些做的好需要保持,哪些需要改进。这个实践与敏捷无关,只是敏捷提供了一个反馈机制让我们把这个事做得更频繁。从前可能一个版本结束后才做事后回顾,现在迭代结束之后就开始做,两周、一个月,每个产品线不一样。自我批判不只是这样两个实践,一定是深入骨髓的,一定是不断学习实践。
-
CodeArts如何做DevOps转型 华为云CodeArts是一个DevOps一站式平台,它是典型的云化互联网产品。CodeArts是从公司内部孵化出来的创业产品,和创业公司很像,生存过程也很艰难:创业团队一开始只有部长和他手下的一个人,共计两人,没有资源和团队,只有证明商业价值才能得到资源和团队;经历两年多的时间,才发展成为百人以上的团队,这个发展历程非常像创业公司。 作为一个互联网创业团队,什么时候开始引入DevOps做工程能力的建设?不要从第一天就开始。任何一个创业产品都会经历这样几个阶段:一开始,目标客户还不明确,需要寻找目标客户,处于问题和解决方案适配的阶段,那时候只有创始人和他的合伙人,这个阶段不需要做工程实践,只需定位目标客户,寻找目标客户的痛点。之后设计一系列的最小可行化产品去验证产品是否打中了目标客户的痛点,是否达到了产品与市场适配,只有达到了适配之后才会大规模招聘员工组建团队。接下来就是寻找渠道做营销,达到产品与营销渠道匹配之后,规模化复制,最后到达成熟期。 整个创业历程非常的艰辛,一定要一步一步来。很多创业公司的死亡都是在错误的阶段做错误的事情,导致现金断裂而死亡,CodeArts也是按照这些步骤来的。一开始只有领导和他手底的一个人,去抓资源,抓一个小团队做产品。 CodeArts是从内部孵化出对外的,是有基础的,不是从0开始的,华为内部本身就有DevOps平台。但是内部和对外产品不一样,内部的业务场景非常复杂,因为内部的产品线都是500人到1000人甚至更多的规模,而外部所面临的目标客户群体都是小公司或者是中型企业,一个项目只有几个人最多几十个人,所以对内部的平台不能直接拿出来对外,一定要把它简化,适应目标客户群,然后再组建一个20多人的小团队,设计了一系列MVP,达到产品与市场匹配。而百人以上规模的团队是达到这个点之后建立的。 什么时候开始做DevOps?过早投资DevOps会造成很大的浪费,因为产品和市场还不匹配,还需要探索商业模式,但也不能过晚,如果达到这个产品与适配点之后很长时间还没有投资DevOps,就没有办法规模化扩张团队,如果没有办法规模化团队的话,就没有办法满足正在爆发的市场。所以,CodeArts在达到产品和市场适配点之前,投入了微服务的建设,投入了DevOps建设。这个决定是当时做的很正确的一个决定,尽管那段时间非常痛苦,因为团队既要交付特性,压力很大,加班很多,同时还要做工程能力的建设。CodeArts先从一个团队做试点开始,有效果之后再铺开,不久之后所有团队都开始做DevOps。
-
敏捷测试有何不同 在传统项目中,我们往往更习惯于去严格定义软件开发生命周期中的各个阶段。例如从制定发布计划和需求定义开始,最终以测试和延迟的发布结尾。对于测试来说,在传统项目中往往被迫担任门卫的角色。 对于团队的领导,或者大部分项目干系人来说,测试往往被寄予期望承担项目质量控制的职责。然而在传统项目中这点很难做到,因为测试既不能控制代码如何编写,也不能控制开发人员测试他们的代码,但所有的质量把控却都被希望能压缩在开发之后的测试阶段圆满完成。 在敏捷项目中,测试人员不再坐在那里等待工作的降临,而是主动寻找在整个开发周期中都贡献价值的方式:与用户一起编写需求的测试用例,与开发人员一起寻找程序中的漏洞,聚焦使用覆盖面更广、更灵活的测试方法。在敏捷中,开发人员从来不超前于测试人员,因为一个功能在被测试之前处于“未完成”状态。 敏捷测试 传统测试 适应性 计划性 阶段性 持续性 强调协作 注重记录 关注产品 关注bug 全功能团队 智能独立 我们可以简单的总结出敏捷测试的几个特点: 强调从客户的角度,即从使用系统的用户角度来测试系统。 重点关注持续迭代地测试新开发的功能,而不再强调传统测试过程中严格的测试阶段。 建议尽早开始测试,一旦系统某个层面可测,比如提供了模块功能,就要开始模块层面的单元测试。同时随着测试深入,持续进行回归测试保证之前测试过内容的正确性。
-
组织挑战 接下来让我们看看,在敏捷转型的过程中,传统的测试团队,测试人员,甚至整个项目团队,会遇到哪些挑战。 文化挑战 组织文化可以影响敏捷团队的成功。在我们开始实行敏捷转型的过程中,变化是无处不在的,这其中必然包括组织文化的冲突。组织文化的形成需要时间,并且一旦建立就很难改变。在这个过程中,团队的成员都会或多或少的抵触变化,遇到失败会很自然地产生怀疑。 这就要求团队要学会引入并接受变化,在应对变化时,要认识到其负面影响,要能预见和接受混乱,并采取措施走出混乱。敏捷看似拥有很快的速度,但变化可以是循序渐进的,采用敏捷的新团队可以较慢的去实现一些新的实践,例如测试驱动开发等。 From:《敏捷软件测试:测试人员与敏捷团队的实践指南》 团队构成 敏捷项目团队是跨职能的,敏捷团队与传统的跨职能团队的区别就是敏捷是向整体团队运作的方向努力,但是不可避免的是每个成员都有出于他自己的背景,尤其是团队组建初期。不同背景的成员给团队带来的既有不好的地方也有好处,例如对自身角色的定位不清楚、成员之间沟通不顺畅。好处是不同背景的成员往往有着互补的思维,尤其对于测试人员来说,在敏捷团队的测试人员会感觉到自身拥有很明显的代表客户的特性,并会将自己在质量思想方面的影响带给团队的其他成员。 很多团队都提过一个敏捷团队中测试与开发人员比例的问题。与其关注比例,团队应该更关心他们需要什么样的测试技能。每个团队的需求是不同的,尤其对于敏捷项目团队而言,敏捷和DevOps的运作方式,会让团队中的专业人员突破他们的技术领域,投入到其他活动中,因此对于测试人员和开发人员来说,需要考虑更多的角色之外的问题。这点可以从扩张团队时对人员的要求上来体现,同时也要注重对团队内部成员多方位技能的培养。 From:《敏捷软件测试:测试人员与敏捷团队的实践指南》 迁移过程 在敏捷转型的过程中,有很多内容不能很好的迁移到敏捷的模式中,在此我们主要来看看有哪些和测试有关的内容是我们需要迁移且容易出现问题的。 首先是度量标准,这是一个存在争议的话题。不同的度量指标,所产生的价值是千差万别的,有可能我们浪费精力跟踪得来的指标最终只代表了一些数字,除了评估之外不会产生其他附加的价值,对团队的进步也起不到一定的帮助。因此,选择合适的度量指标,获得较高的度量投资回报率对团队起到的帮助的很大的。 缺陷跟踪也是敏捷团队在项目转型过程中一个比较矛盾的地方,许多敏捷实践者认为,在敏捷项目开发的过程中发现和修补缺陷是开发人员的必要工作,发现了缺陷后立刻就会被修补,因此对于缺陷的跟踪和记录是没有必要的。对于测试人员而言,他们往往使用缺陷跟踪系统对缺陷进行跟踪管理,而缺陷跟踪系统不仅仅用于缺陷跟踪,还可以记录更多相关的信息,例如优先级,严重性,状态,负责人,关联的用例、需求,以及缺陷的描述和复现方式等。我们可以通过工具来简化传统项目中繁杂的管理工作,且可以实现更多更丰富的管理目标。 华为云CodeArts提供专业的用例管理与缺陷跟踪管理工具。 通过测试计划服务的测试管理功能,可以清晰的查看需求树中每一个需求所关联的测试用例。 测试用例中提供用例的基本信息编辑与查询,用例执行结果、缺陷列表、操作历史等内容的查询。 可直接在用例执行后,在用例界面新建缺陷或关联缺陷,实现缺陷与用例、用例与需求、需求与缺陷的闭环跟踪。
-
测试自动化 在敏捷和DevOps中,测试的自动化是必需的。我们需要用自动化的手段去管理关键的测试活动,并为开发提供必要的反馈。下面就让我们来看看测试自动化都包含哪些内容,以及如何做好测试自动化。 测试金字塔 在开始测试自动化的内容之前,我们先来看一个经典的测试自动化的模型—测试金字塔。 测试金字塔模型的目的是,指导团队从测试自动化中尽量以最低的投入获得最大的价值。金字塔展示了3个不同的自动化测试层次。 最低的一层是基础,主要有单元测试、组建测试等面向技术的测试所构成,这一层也代表了大多数的自动化测试。在这一层中,测试用例的单元隔离性最好,定位分析问题最容易,使用的代价也最低。 金字塔的中间一层包含了大多数用来支持团队的自动化业务测试。这些功能测试只在验证我们在做正确的事。 金字塔的顶层很少使用自动化,因为他的运行效率最低,开发复杂度最高,测试ROI最低。 什么是测试自动化 上文提到了很多自动化测试的手段,例如单元测试、API测试等等。这些是测试的执行部分,也就是把一些测试执行的人工测试手段通过工具做成自动化的测试过程。但是测试自动化不仅仅是只是执行部分,还包括了从环境的获取到生成测试数据、执行自动化测试、最终生成结果并提供反馈。如果测试结果有问题,系统会自动推给相关的人。最终自动生成测试报告,测试人员可以直接拿到测试结果。这整个闭环的过程才是测试自动化的最终组成。 接下来让我们看看在CodeArts中,提供了哪些帮助我们完成测试自动化实践的工具: 在测试管理上提供了包括上文提到的整体测试流程管理、测试的用例和需求、虚线能够双向可追溯。 在自动化方面,提供了 移动应用测试 、API测试和性能测试。 移动应用测试提供了对应用软件包进行系统化的兼容性测试,检测软件包是否有兼容性的问题,能够涵概多少用户。 接口测试提供自动化的API测试工具,通过编写测试用例实现对API的自动化测试。 性能测试可为用户模拟一些大并发的场景、提供多种加压策略,能够在测试过程中对于用户的吞吐量、响应时间、负载能力,整体进行结构分析。在测试完成后还提供多维度可视化的看板,能够详细了解测试执行的情况。
共100000条
- 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
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400
- 401
- 402
- 403
- 404
- 405
- 406
- 407
- 408
- 409
- 410
- 411
- 412
- 413
- 414
- 415
- 416
- 417
- 418
- 419
- 420
- 421
- 422
- 423
- 424
- 425
- 426
- 427
- 428
- 429
- 430
- 431
- 432
- 433
- 434
- 435
- 436
- 437
- 438
- 439
- 440
- 441
- 442
- 443
- 444
- 445
- 446
- 447
- 448
- 449
- 450
- 451
- 452
- 453
- 454
- 455
- 456
- 457
- 458
- 459
- 460
- 461
- 462
- 463
- 464
- 465
- 466
- 467
- 468
- 469
- 470
- 471
- 472
- 473
- 474
- 475
- 476
- 477
- 478
- 479
- 480
- 481
- 482
- 483
- 484
- 485
- 486
- 487
- 488
- 489
- 490
- 491
- 492
- 493
- 494
- 495
- 496
- 497
- 498
- 499
- 500
- 501
- 502
- 503
- 504
- 505
- 506
- 507
- 508
- 509
- 510
- 511
- 512
- 513
- 514
- 515
- 516
- 517
- 518
- 519
- 520
- 521
- 522
- 523
- 524
- 525
- 526
- 527
- 528
- 529
- 530
- 531
- 532
- 533
- 534
- 535
- 536
- 537
- 538
- 539
- 540
- 541
- 542
- 543
- 544
- 545
- 546
- 547
- 548
- 549
- 550
- 551
- 552
- 553
- 554
- 555
- 556
- 557
- 558
- 559
- 560
- 561
- 562
- 563
- 564
- 565
- 566
- 567
- 568
- 569
- 570
- 571
- 572
- 573
- 574
- 575
- 576
- 577
- 578
- 579
- 580
- 581
- 582
- 583
- 584
- 585
- 586
- 587
- 588
- 589
- 590
- 591
- 592
- 593
- 594
- 595
- 596
- 597
- 598
- 599
- 600
- 601
- 602
- 603
- 604
- 605
- 606
- 607
- 608
- 609
- 610
- 611
- 612
- 613
- 614
- 615
- 616
- 617
- 618
- 619
- 620
- 621
- 622
- 623
- 624
- 625
- 626
- 627
- 628
- 629
- 630
- 631
- 632
- 633
- 634
- 635
- 636
- 637
- 638
- 639
- 640
- 641
- 642
- 643
- 644
- 645
- 646
- 647
- 648
- 649
- 650
- 651
- 652
- 653
- 654
- 655
- 656
- 657
- 658
- 659
- 660
- 661
- 662
- 663
- 664
- 665
- 666
- 667
- 668
- 669
- 670
- 671
- 672
- 673
- 674
- 675
- 676
- 677
- 678
- 679
- 680
- 681
- 682
- 683
- 684
- 685
- 686
- 687
- 688
- 689
- 690
- 691
- 692
- 693
- 694
- 695
- 696
- 697
- 698
- 699
- 700
- 701
- 702
- 703
- 704
- 705
- 706
- 707
- 708
- 709
- 710
- 711
- 712
- 713
- 714
- 715
- 716
- 717
- 718
- 719
- 720
- 721
- 722
- 723
- 724
- 725
- 726
- 727
- 728
- 729
- 730
- 731
- 732
- 733
- 734
- 735
- 736
- 737
- 738
- 739
- 740
- 741
- 742
- 743
- 744
- 745
- 746
- 747
- 748
- 749
- 750
- 751
- 752
- 753
- 754
- 755
- 756
- 757
- 758
- 759
- 760
- 761
- 762
- 763
- 764
- 765
- 766
- 767
- 768
- 769
- 770
- 771
- 772
- 773
- 774
- 775
- 776
- 777
- 778
- 779
- 780
- 781
- 782
- 783
- 784
- 785
- 786
- 787
- 788
- 789
- 790
- 791
- 792
- 793
- 794
- 795
- 796
- 797
- 798
- 799
- 800
- 801
- 802
- 803
- 804
- 805
- 806
- 807
- 808
- 809
- 810
- 811
- 812
- 813
- 814
- 815
- 816
- 817
- 818
- 819
- 820
- 821
- 822
- 823
- 824
- 825
- 826
- 827
- 828
- 829
- 830
- 831
- 832
- 833
- 834
- 835
- 836
- 837
- 838
- 839
- 840
- 841
- 842
- 843
- 844
- 845
- 846
- 847
- 848
- 849
- 850
- 851
- 852
- 853
- 854
- 855
- 856
- 857
- 858
- 859
- 860
- 861
- 862
- 863
- 864
- 865
- 866
- 867
- 868
- 869
- 870
- 871
- 872
- 873
- 874
- 875
- 876
- 877
- 878
- 879
- 880
- 881
- 882
- 883
- 884
- 885
- 886
- 887
- 888
- 889
- 890
- 891
- 892
- 893
- 894
- 895
- 896
- 897
- 898
- 899
- 900
- 901
- 902
- 903
- 904
- 905
- 906
- 907
- 908
- 909
- 910
- 911
- 912
- 913
- 914
- 915
- 916
- 917
- 918
- 919
- 920
- 921
- 922
- 923
- 924
- 925
- 926
- 927
- 928
- 929
- 930
- 931
- 932
- 933
- 934
- 935
- 936
- 937
- 938
- 939
- 940
- 941
- 942
- 943
- 944
- 945
- 946
- 947
- 948
- 949
- 950
- 951
- 952
- 953
- 954
- 955
- 956
- 957
- 958
- 959
- 960
- 961
- 962
- 963
- 964
- 965
- 966
- 967
- 968
- 969
- 970
- 971
- 972
- 973
- 974
- 975
- 976
- 977
- 978
- 979
- 980
- 981
- 982
- 983
- 984
- 985
- 986
- 987
- 988
- 989
- 990
- 991
- 992
- 993
- 994
- 995
- 996
- 997
- 998
- 999
- 1000
- 1001
- 1002
- 1003
- 1004
- 1005
- 1006
- 1007
- 1008
- 1009
- 1010
- 1011
- 1012
- 1013
- 1014
- 1015
- 1016
- 1017
- 1018
- 1019
- 1020
- 1021
- 1022
- 1023
- 1024
- 1025
- 1026
- 1027
- 1028
- 1029
- 1030
- 1031
- 1032
- 1033
- 1034
- 1035
- 1036
- 1037
- 1038
- 1039
- 1040
- 1041
- 1042
- 1043
- 1044
- 1045
- 1046
- 1047
- 1048
- 1049
- 1050
- 1051
- 1052
- 1053
- 1054
- 1055
- 1056
- 1057
- 1058
- 1059
- 1060
- 1061
- 1062
- 1063
- 1064
- 1065
- 1066
- 1067
- 1068
- 1069
- 1070
- 1071
- 1072
- 1073
- 1074
- 1075
- 1076
- 1077
- 1078
- 1079
- 1080
- 1081
- 1082
- 1083
- 1084
- 1085
- 1086
- 1087
- 1088
- 1089
- 1090
- 1091
- 1092
- 1093
- 1094
- 1095
- 1096
- 1097
- 1098
- 1099
- 1100
- 1101
- 1102
- 1103
- 1104
- 1105
- 1106
- 1107
- 1108
- 1109
- 1110
- 1111
- 1112
- 1113
- 1114
- 1115
- 1116
- 1117
- 1118
- 1119
- 1120
- 1121
- 1122
- 1123
- 1124
- 1125
- 1126
- 1127
- 1128
- 1129
- 1130
- 1131
- 1132
- 1133
- 1134
- 1135
- 1136
- 1137
- 1138
- 1139
- 1140
- 1141
- 1142
- 1143
- 1144
- 1145
- 1146
- 1147
- 1148
- 1149
- 1150
- 1151
- 1152
- 1153
- 1154
- 1155
- 1156
- 1157
- 1158
- 1159
- 1160
- 1161
- 1162
- 1163
- 1164
- 1165
- 1166
- 1167
- 1168
- 1169
- 1170
- 1171
- 1172
- 1173
- 1174
- 1175
- 1176
- 1177
- 1178
- 1179
- 1180
- 1181
- 1182
- 1183
- 1184
- 1185
- 1186
- 1187
- 1188
- 1189
- 1190
- 1191
- 1192
- 1193
- 1194
- 1195
- 1196
- 1197
- 1198
- 1199
- 1200
- 1201
- 1202
- 1203
- 1204
- 1205
- 1206
- 1207
- 1208
- 1209
- 1210
- 1211
- 1212
- 1213
- 1214
- 1215
- 1216
- 1217
- 1218
- 1219
- 1220
- 1221
- 1222
- 1223
- 1224
- 1225
- 1226
- 1227
- 1228
- 1229
- 1230
- 1231
- 1232
- 1233
- 1234
- 1235
- 1236
- 1237
- 1238
- 1239
- 1240
- 1241
- 1242
- 1243
- 1244
- 1245
- 1246
- 1247
- 1248
- 1249
- 1250
- 1251
- 1252
- 1253
- 1254
- 1255
- 1256
- 1257
- 1258
- 1259
- 1260
- ...
- 1261
- 1262
- 1263
- 1264
- 1265
- 1266
- 1267
- 1268
- 1269
- 1270
- 1271
- 1272
- 1273
- 1274
- 1275
- 1276
- 1277
- 1278
- 1279
- 1280
- 1281
- 1282
- 1283
- 1284
- 1285
- 1286
- 1287
- 1288
- 1289
- 1290
- 1291
- 1292
- 1293
- 1294
- 1295
- 1296
- 1297
- 1298
- 1299
- 1300
- 1301
- 1302
- 1303
- 1304
- 1305
- 1306
- 1307
- 1308
- 1309
- 1310
- 1311
- 1312
- 1313
- 1314
- 1315
- 1316
- 1317
- 1318
- 1319
- 1320
- 1321
- 1322
- 1323
- 1324
- 1325
- 1326
- 1327
- 1328
- 1329
- 1330
- 1331
- 1332
- 1333
- 1334
- 1335
- 1336
- 1337
- 1338
- 1339
- 1340
- 1341
- 1342
- 1343
- 1344
- 1345
- 1346
- 1347
- 1348
- 1349
- 1350
- 1351
- 1352
- 1353
- 1354
- 1355
- 1356
- 1357
- 1358
- 1359
- 1360
- 1361
- 1362
- 1363
- 1364
- 1365
- 1366
- 1367
- 1368
- 1369
- 1370
- 1371
- 1372
- 1373
- 1374
- 1375
- 1376
- 1377
- 1378
- 1379
- 1380
- 1381
- 1382
- 1383
- 1384
- 1385
- 1386
- 1387
- 1388
- 1389
- 1390
- 1391
- 1392
- 1393
- 1394
- 1395
- 1396
- 1397
- 1398
- 1399
- 1400
- 1401
- 1402
- 1403
- 1404
- 1405
- 1406
- 1407
- 1408
- 1409
- 1410
- 1411
- 1412
- 1413
- 1414
- 1415
- 1416
- 1417
- 1418
- 1419
- 1420
- 1421
- 1422
- 1423
- 1424
- 1425
- 1426
- 1427
- 1428
- 1429
- 1430
- 1431
- 1432
- 1433
- 1434
- 1435
- 1436
- 1437
- 1438
- 1439
- 1440
- 1441
- 1442
- 1443
- 1444
- 1445
- 1446
- 1447
- 1448
- 1449
- 1450
- 1451
- 1452
- 1453
- 1454
- 1455
- 1456
- 1457
- 1458
- 1459
- 1460
- 1461
- 1462
- 1463
- 1464
- 1465
- 1466
- 1467
- 1468
- 1469
- 1470
- 1471
- 1472
- 1473
- 1474
- 1475
- 1476
- 1477
- 1478
- 1479
- 1480
- 1481
- 1482
- 1483
- 1484
- 1485
- 1486
- 1487
- 1488
- 1489
- 1490
- 1491
- 1492
- 1493
- 1494
- 1495
- 1496
- 1497
- 1498
- 1499
- 1500
- 1501
- 1502
- 1503
- 1504
- 1505
- 1506
- 1507
- 1508
- 1509
- 1510
- 1511
- 1512
- 1513
- 1514
- 1515
- 1516
- 1517
- 1518
- 1519
- 1520
- 1521
- 1522
- 1523
- 1524
- 1525
- 1526
- 1527
- 1528
- 1529
- 1530
- 1531
- 1532
- 1533
- 1534
- 1535
- 1536
- 1537
- 1538
- 1539
- 1540
- 1541
- 1542
- 1543
- 1544
- 1545
- 1546
- 1547
- 1548
- 1549
- 1550
- 1551
- 1552
- 1553
- 1554
- 1555
- 1556
- 1557
- 1558
- 1559
- 1560
- 1561
- 1562
- 1563
- 1564
- 1565
- 1566
- 1567
- 1568
- 1569
- 1570
- 1571
- 1572
- 1573
- 1574
- 1575
- 1576
- 1577
- 1578
- 1579
- 1580
- 1581
- 1582
- 1583
- 1584
- 1585
- 1586
- 1587
- 1588
- 1589
- 1590
- 1591
- 1592
- 1593
- 1594
- 1595
- 1596
- 1597
- 1598
- 1599
- 1600
- 1601
- 1602
- 1603
- 1604
- 1605
- 1606
- 1607
- 1608
- 1609
- 1610
- 1611
- 1612
- 1613
- 1614
- 1615
- 1616
- 1617
- 1618
- 1619
- 1620
- 1621
- 1622
- 1623
- 1624
- 1625
- 1626
- 1627
- 1628
- 1629
- 1630
- 1631
- 1632
- 1633
- 1634
- 1635
- 1636
- 1637
- 1638
- 1639
- 1640
- 1641
- 1642
- 1643
- 1644
- 1645
- 1646
- 1647
- 1648
- 1649
- 1650
- 1651
- 1652
- 1653
- 1654
- 1655
- 1656
- 1657
- 1658
- 1659
- 1660
- 1661
- 1662
- 1663
- 1664
- 1665
- 1666
- 1667
- 1668
- 1669
- 1670
- 1671
- 1672
- 1673
- 1674
- 1675
- 1676
- 1677
- 1678
- 1679
- 1680
- 1681
- 1682
- 1683
- 1684
- 1685
- 1686
- 1687
- 1688
- 1689
- 1690
- 1691
- 1692
- 1693
- 1694
- 1695
- 1696
- 1697
- 1698
- 1699
- 1700
- 1701
- 1702
- 1703
- 1704
- 1705
- 1706
- 1707
- 1708
- 1709
- 1710
- 1711
- 1712
- 1713
- 1714
- 1715
- 1716
- 1717
- 1718
- 1719
- 1720
- 1721
- 1722
- 1723
- 1724
- 1725
- 1726
- 1727
- 1728
- 1729
- 1730
- 1731
- 1732
- 1733
- 1734
- 1735
- 1736
- 1737
- 1738
- 1739
- 1740
- 1741
- 1742
- 1743
- 1744
- 1745
- 1746
- 1747
- 1748
- 1749
- 1750
- 1751
- 1752
- 1753
- 1754
- 1755
- 1756
- 1757
- 1758
- 1759
- 1760
- 1761
- 1762
- 1763
- 1764
- 1765
- 1766
- 1767
- 1768
- 1769
- 1770
- 1771
- 1772
- 1773
- 1774
- 1775
- 1776
- 1777
- 1778
- 1779
- 1780
- 1781
- 1782
- 1783
- 1784
- 1785
- 1786
- 1787
- 1788
- 1789
- 1790
- 1791
- 1792
- 1793
- 1794
- 1795
- 1796
- 1797
- 1798
- 1799
- 1800
- 1801
- 1802
- 1803
- 1804
- 1805
- 1806
- 1807
- 1808
- 1809
- 1810
- 1811
- 1812
- 1813
- 1814
- 1815
- 1816
- 1817
- 1818
- 1819
- 1820
- 1821
- 1822
- 1823
- 1824
- 1825
- 1826
- 1827
- 1828
- 1829
- 1830
- 1831
- 1832
- 1833
- 1834
- 1835
- 1836
- 1837
- 1838
- 1839
- 1840
- 1841
- 1842
- 1843
- 1844
- 1845
- 1846
- 1847
- 1848
- 1849
- 1850
- 1851
- 1852
- 1853
- 1854
- 1855
- 1856
- 1857
- 1858
- 1859
- 1860
- 1861
- 1862
- 1863
- 1864
- 1865
- 1866
- 1867
- 1868
- 1869
- 1870
- 1871
- 1872
- 1873
- 1874
- 1875
- 1876
- 1877
- 1878
- 1879
- 1880
- 1881
- 1882
- 1883
- 1884
- 1885
- 1886
- 1887
- 1888
- 1889
- 1890
- 1891
- 1892
- 1893
- 1894
- 1895
- 1896
- 1897
- 1898
- 1899
- 1900
- 1901
- 1902
- 1903
- 1904
- 1905
- 1906
- 1907
- 1908
- 1909
- 1910
- 1911
- 1912
- 1913
- 1914
- 1915
- 1916
- 1917
- 1918
- 1919
- 1920
- 1921
- 1922
- 1923
- 1924
- 1925
- 1926
- 1927
- 1928
- 1929
- 1930
- 1931
- 1932
- 1933
- 1934
- 1935
- 1936
- 1937
- 1938
- 1939
- 1940
- 1941
- 1942
- 1943
- 1944
- 1945
- 1946
- 1947
- 1948
- 1949
- 1950
- 1951
- 1952
- 1953
- 1954
- 1955
- 1956
- 1957
- 1958
- 1959
- 1960
- 1961
- 1962
- 1963
- 1964
- 1965
- 1966
- 1967
- 1968
- 1969
- 1970
- 1971
- 1972
- 1973
- 1974
- 1975
- 1976
- 1977
- 1978
- 1979
- 1980
- 1981
- 1982
- 1983
- 1984
- 1985
- 1986
- 1987
- 1988
- 1989
- 1990
- 1991
- 1992
- 1993
- 1994
- 1995
- 1996
- 1997
- 1998
- 1999
- 2000
- 2001
- 2002
- 2003
- 2004
- 2005
- 2006
- 2007
- 2008
- 2009
- 2010
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2017
- 2018
- 2019
- 2020
- 2021
- 2022
- 2023
- 2024
- 2025
- 2026
- 2027
- 2028
- 2029
- 2030
- 2031
- 2032
- 2033
- 2034
- 2035
- 2036
- 2037
- 2038
- 2039
- 2040
- 2041
- 2042
- 2043
- 2044
- 2045
- 2046
- 2047
- 2048
- 2049
- 2050
- 2051
- 2052
- 2053
- 2054
- 2055
- 2056
- 2057
- 2058
- 2059
- 2060
- 2061
- 2062
- 2063
- 2064
- 2065
- 2066
- 2067
- 2068
- 2069
- 2070
- 2071
- 2072
- 2073
- 2074
- 2075
- 2076
- 2077
- 2078
- 2079
- 2080
- 2081
- 2082
- 2083
- 2084
- 2085
- 2086
- 2087
- 2088
- 2089
- 2090
- 2091
- 2092
- 2093
- 2094
- 2095
- 2096
- 2097
- 2098
- 2099
- 2100
- 2101
- 2102
- 2103
- 2104
- 2105
- 2106
- 2107
- 2108
- 2109
- 2110
- 2111
- 2112
- 2113
- 2114
- 2115
- 2116
- 2117
- 2118
- 2119
- 2120
- 2121
- 2122
- 2123
- 2124
- 2125
- 2126
- 2127
- 2128
- 2129
- 2130
- 2131
- 2132
- 2133
- 2134
- 2135
- 2136
- 2137
- 2138
- 2139
- 2140
- 2141
- 2142
- 2143
- 2144
- 2145
- 2146
- 2147
- 2148
- 2149
- 2150
- 2151
- 2152
- 2153
- 2154
- 2155
- 2156
- 2157
- 2158
- 2159
- 2160
- 2161
- 2162
- 2163
- 2164
- 2165
- 2166
- 2167
- 2168
- 2169
- 2170
- 2171
- 2172
- 2173
- 2174
- 2175
- 2176
- 2177
- 2178
- 2179
- 2180
- 2181
- 2182
- 2183
- 2184
- 2185
- 2186
- 2187
- 2188
- 2189
- 2190
- 2191
- 2192
- 2193
- 2194
- 2195
- 2196
- 2197
- 2198
- 2199
- 2200
- 2201
- 2202
- 2203
- 2204
- 2205
- 2206
- 2207
- 2208
- 2209
- 2210
- 2211
- 2212
- 2213
- 2214
- 2215
- 2216
- 2217
- 2218
- 2219
- 2220
- 2221
- 2222
- 2223
- 2224
- 2225
- 2226
- 2227
- 2228
- 2229
- 2230
- 2231
- 2232
- 2233
- 2234
- 2235
- 2236
- 2237
- 2238
- 2239
- 2240
- 2241
- 2242
- 2243
- 2244
- 2245
- 2246
- 2247
- 2248
- 2249
- 2250
- 2251
- 2252
- 2253
- 2254
- 2255
- 2256
- 2257
- 2258
- 2259
- 2260
- 2261
- 2262
- 2263
- 2264
- 2265
- 2266
- 2267
- 2268
- 2269
- 2270
- 2271
- 2272
- 2273
- 2274
- 2275
- 2276
- 2277
- 2278
- 2279
- 2280
- 2281
- 2282
- 2283
- 2284
- 2285
- 2286
- 2287
- 2288
- 2289
- 2290
- 2291
- 2292
- 2293
- 2294
- 2295
- 2296
- 2297
- 2298
- 2299
- 2300
- 2301
- 2302
- 2303
- 2304
- 2305
- 2306
- 2307
- 2308
- 2309
- 2310
- 2311
- 2312
- 2313
- 2314
- 2315
- 2316
- 2317
- 2318
- 2319
- 2320
- 2321
- 2322
- 2323
- 2324
- 2325
- 2326
- 2327
- 2328
- 2329
- 2330
- 2331
- 2332
- 2333
- 2334
- 2335
- 2336
- 2337
- 2338
- 2339
- 2340
- 2341
- 2342
- 2343
- 2344
- 2345
- 2346
- 2347
- 2348
- 2349
- 2350
- 2351
- 2352
- 2353
- 2354
- 2355
- 2356
- 2357
- 2358
- 2359
- 2360
- 2361
- 2362
- 2363
- 2364
- 2365
- 2366
- 2367
- 2368
- 2369
- 2370
- 2371
- 2372
- 2373
- 2374
- 2375
- 2376
- 2377
- 2378
- 2379
- 2380
- 2381
- 2382
- 2383
- 2384
- 2385
- 2386
- 2387
- 2388
- 2389
- 2390
- 2391
- 2392
- 2393
- 2394
- 2395
- 2396
- 2397
- 2398
- 2399
- 2400
- 2401
- 2402
- 2403
- 2404
- 2405
- 2406
- 2407
- 2408
- 2409
- 2410
- 2411
- 2412
- 2413
- 2414
- 2415
- 2416
- 2417
- 2418
- 2419
- 2420
- 2421
- 2422
- 2423
- 2424
- 2425
- 2426
- 2427
- 2428
- 2429
- 2430
- 2431
- 2432
- 2433
- 2434
- 2435
- 2436
- 2437
- 2438
- 2439
- 2440
- 2441
- 2442
- 2443
- 2444
- 2445
- 2446
- 2447
- 2448
- 2449
- 2450
- 2451
- 2452
- 2453
- 2454
- 2455
- 2456
- 2457
- 2458
- 2459
- 2460
- 2461
- 2462
- 2463
- 2464
- 2465
- 2466
- 2467
- 2468
- 2469
- 2470
- 2471
- 2472
- 2473
- 2474
- 2475
- 2476
- 2477
- 2478
- 2479
- 2480
- 2481
- 2482
- 2483
- 2484
- 2485
- 2486
- 2487
- 2488
- 2489
- 2490
- 2491
- 2492
- 2493
- 2494
- 2495
- 2496
- 2497
- 2498
- 2499
- 2500
- 2501
- 2502
- 2503
- 2504
- 2505
- 2506
- 2507
- 2508
- 2509
- 2510
- 2511
- 2512
- 2513
- 2514
- 2515
- 2516
- 2517
- 2518
- 2519
- 2520
- 2521
- 2522
- 2523
- 2524
- 2525
- 2526
- 2527
- 2528
- 2529
- 2530
- 2531
- 2532
- 2533
- 2534
- 2535
- 2536
- 2537
- 2538
- 2539
- 2540
- 2541
- 2542
- 2543
- 2544
- 2545
- 2546
- 2547
- 2548
- 2549
- 2550
- 2551
- 2552
- 2553
- 2554
- 2555
- 2556
- 2557
- 2558
- 2559
- 2560
- 2561
- 2562
- 2563
- 2564
- 2565
- 2566
- 2567
- 2568
- 2569
- 2570
- 2571
- 2572
- 2573
- 2574
- 2575
- 2576
- 2577
- 2578
- 2579
- 2580
- 2581
- 2582
- 2583
- 2584
- 2585
- 2586
- 2587
- 2588
- 2589
- 2590
- 2591
- 2592
- 2593
- 2594
- 2595
- 2596
- 2597
- 2598
- 2599
- 2600
- 2601
- 2602
- 2603
- 2604
- 2605
- 2606
- 2607
- 2608
- 2609
- 2610
- 2611
- 2612
- 2613
- 2614
- 2615
- 2616
- 2617
- 2618
- 2619
- 2620
- 2621
- 2622
- 2623
- 2624
- 2625
- 2626
- 2627
- 2628
- 2629
- 2630
- 2631
- 2632
- 2633
- 2634
- 2635
- 2636
- 2637
- 2638
- 2639
- 2640
- 2641
- 2642
- 2643
- 2644
- 2645
- 2646
- 2647
- 2648
- 2649
- 2650
- 2651
- 2652
- 2653
- 2654
- 2655
- 2656
- 2657
- 2658
- 2659
- 2660
- 2661
- 2662
- 2663
- 2664
- 2665
- 2666
- 2667
- 2668
- 2669
- 2670
- 2671
- 2672
- 2673
- 2674
- 2675
- 2676
- 2677
- 2678
- 2679
- 2680
- 2681
- 2682
- 2683
- 2684
- 2685
- 2686
- 2687
- 2688
- 2689
- 2690
- 2691
- 2692
- 2693
- 2694
- 2695
- 2696
- 2697
- 2698
- 2699
- 2700
- 2701
- 2702
- 2703
- 2704
- 2705
- 2706
- 2707
- 2708
- 2709
- 2710
- 2711
- 2712
- 2713
- 2714
- 2715
- 2716
- 2717
- 2718
- 2719
- 2720
- 2721
- 2722
- 2723
- 2724
- 2725
- 2726
- 2727
- 2728
- 2729
- 2730
- 2731
- 2732
- 2733
- 2734
- 2735
- 2736
- 2737
- 2738
- 2739
- 2740
- 2741
- 2742
- 2743
- 2744
- 2745
- 2746
- 2747
- 2748
- 2749
- 2750
- 2751
- 2752
- 2753
- 2754
- 2755
- 2756
- 2757
- 2758
- 2759
- 2760
- 2761
- 2762
- 2763
- 2764
- 2765
- 2766
- 2767
- 2768
- 2769
- 2770
- 2771
- 2772
- 2773
- 2774
- 2775
- 2776
- 2777
- 2778
- 2779
- 2780
- 2781
- 2782
- 2783
- 2784
- 2785
- 2786
- 2787
- 2788
- 2789
- 2790
- 2791
- 2792
- 2793
- 2794
- 2795
- 2796
- 2797
- 2798
- 2799
- 2800
- 2801
- 2802
- 2803
- 2804
- 2805
- 2806
- 2807
- 2808
- 2809
- 2810
- 2811
- 2812
- 2813
- 2814
- 2815
- 2816
- 2817
- 2818
- 2819
- 2820
- 2821
- 2822
- 2823
- 2824
- 2825
- 2826
- 2827
- 2828
- 2829
- 2830
- 2831
- 2832
- 2833
- 2834
- 2835
- 2836
- 2837
- 2838
- 2839
- 2840
- 2841
- 2842
- 2843
- 2844
- 2845
- 2846
- 2847
- 2848
- 2849
- 2850
- 2851
- 2852
- 2853
- 2854
- 2855
- 2856
- 2857
- 2858
- 2859
- 2860
- 2861
- 2862
- 2863
- 2864
- 2865
- 2866
- 2867
- 2868
- 2869
- 2870
- 2871
- 2872
- 2873
- 2874
- 2875
- 2876
- 2877
- 2878
- 2879
- 2880
- 2881
- 2882
- 2883
- 2884
- 2885
- 2886
- 2887
- 2888
- 2889
- 2890
- 2891
- 2892
- 2893
- 2894
- 2895
- 2896
- 2897
- 2898
- 2899
- 2900
- 2901
- 2902
- 2903
- 2904
- 2905
- 2906
- 2907
- 2908
- 2909
- 2910
- 2911
- 2912
- 2913
- 2914
- 2915
- 2916
- 2917
- 2918
- 2919
- 2920
- 2921
- 2922
- 2923
- 2924
- 2925
- 2926
- 2927
- 2928
- 2929
- 2930
- 2931
- 2932
- 2933
- 2934
- 2935
- 2936
- 2937
- 2938
- 2939
- 2940
- 2941
- 2942
- 2943
- 2944
- 2945
- 2946
- 2947
- 2948
- 2949
- 2950
- 2951
- 2952
- 2953
- 2954
- 2955
- 2956
- 2957
- 2958
- 2959
- 2960
- 2961
- 2962
- 2963
- 2964
- 2965
- 2966
- 2967
- 2968
- 2969
- 2970
- 2971
- 2972
- 2973
- 2974
- 2975
- 2976
- 2977
- 2978
- 2979
- 2980
- 2981
- 2982
- 2983
- 2984
- 2985
- 2986
- 2987
- 2988
- 2989
- 2990
- 2991
- 2992
- 2993
- 2994
- 2995
- 2996
- 2997
- 2998
- 2999
- 3000
- 3001
- 3002
- 3003
- 3004
- 3005
- 3006
- 3007
- 3008
- 3009
- 3010
- 3011
- 3012
- 3013
- 3014
- 3015
- 3016
- 3017
- 3018
- 3019
- 3020
- 3021
- 3022
- 3023
- 3024
- 3025
- 3026
- 3027
- 3028
- 3029
- 3030
- 3031
- 3032
- 3033
- 3034
- 3035
- 3036
- 3037
- 3038
- 3039
- 3040
- 3041
- 3042
- 3043
- 3044
- 3045
- 3046
- 3047
- 3048
- 3049
- 3050
- 3051
- 3052
- 3053
- 3054
- 3055
- 3056
- 3057
- 3058
- 3059
- 3060
- 3061
- 3062
- 3063
- 3064
- 3065
- 3066
- 3067
- 3068
- 3069
- 3070
- 3071
- 3072
- 3073
- 3074
- 3075
- 3076
- 3077
- 3078
- 3079
- 3080
- 3081
- 3082
- 3083
- 3084
- 3085
- 3086
- 3087
- 3088
- 3089
- 3090
- 3091
- 3092
- 3093
- 3094
- 3095
- 3096
- 3097
- 3098
- 3099
- 3100
- 3101
- 3102
- 3103
- 3104
- 3105
- 3106
- 3107
- 3108
- 3109
- 3110
- 3111
- 3112
- 3113
- 3114
- 3115
- 3116
- 3117
- 3118
- 3119
- 3120
- 3121
- 3122
- 3123
- 3124
- 3125
- 3126
- 3127
- 3128
- 3129
- 3130
- 3131
- 3132
- 3133
- 3134
- 3135
- 3136
- 3137
- 3138
- 3139
- 3140
- 3141
- 3142
- 3143
- 3144
- 3145
- 3146
- 3147
- 3148
- 3149
- 3150
- 3151
- 3152
- 3153
- 3154
- 3155
- 3156
- 3157
- 3158
- 3159
- 3160
- 3161
- 3162
- 3163
- 3164
- 3165
- 3166
- 3167
- 3168
- 3169
- 3170
- 3171
- 3172
- 3173
- 3174
- 3175
- 3176
- 3177
- 3178
- 3179
- 3180
- 3181
- 3182
- 3183
- 3184
- 3185
- 3186
- 3187
- 3188
- 3189
- 3190
- 3191
- 3192
- 3193
- 3194
- 3195
- 3196
- 3197
- 3198
- 3199
- 3200
- 3201
- 3202
- 3203
- 3204
- 3205
- 3206
- 3207
- 3208
- 3209
- 3210
- 3211
- 3212
- 3213
- 3214
- 3215
- 3216
- 3217
- 3218
- 3219
- 3220
- 3221
- 3222
- 3223
- 3224
- 3225
- 3226
- 3227
- 3228
- 3229
- 3230
- 3231
- 3232
- 3233
- 3234
- 3235
- 3236
- 3237
- 3238
- 3239
- 3240
- 3241
- 3242
- 3243
- 3244
- 3245
- 3246
- 3247
- 3248
- 3249
- 3250
- 3251
- 3252
- 3253
- 3254
- 3255
- 3256
- 3257
- 3258
- 3259
- 3260
- 3261
- 3262
- 3263
- 3264
- 3265
- 3266
- 3267
- 3268
- 3269
- 3270
- 3271
- 3272
- 3273
- 3274
- 3275
- 3276
- 3277
- 3278
- 3279
- 3280
- 3281
- 3282
- 3283
- 3284
- 3285
- 3286
- 3287
- 3288
- 3289
- 3290
- 3291
- 3292
- 3293
- 3294
- 3295
- 3296
- 3297
- 3298
- 3299
- 3300
- 3301
- 3302
- 3303
- 3304
- 3305
- 3306
- 3307
- 3308
- 3309
- 3310
- 3311
- 3312
- 3313
- 3314
- 3315
- 3316
- 3317
- 3318
- 3319
- 3320
- 3321
- 3322
- 3323
- 3324
- 3325
- 3326
- 3327
- 3328
- 3329
- 3330
- 3331
- 3332
- 3333
- 3333
推荐文章