敏捷开发总结DOC.docx

上传人:b****6 文档编号:4271948 上传时间:2022-11-28 格式:DOCX 页数:15 大小:166.96KB
下载 相关 举报
敏捷开发总结DOC.docx_第1页
第1页 / 共15页
敏捷开发总结DOC.docx_第2页
第2页 / 共15页
敏捷开发总结DOC.docx_第3页
第3页 / 共15页
敏捷开发总结DOC.docx_第4页
第4页 / 共15页
敏捷开发总结DOC.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

敏捷开发总结DOC.docx

《敏捷开发总结DOC.docx》由会员分享,可在线阅读,更多相关《敏捷开发总结DOC.docx(15页珍藏版)》请在冰豆网上搜索。

敏捷开发总结DOC.docx

敏捷开发总结DOC

Intro:

简单的说,敏捷开发是一种以人为核心、迭代、循序渐进的开发方法。

在敏捷开发中,软件项目的构建被切分成多个子项目,各个子项目的成果都经过测试,具备集成和可运行的特征。

换言之,就是把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态。

敏捷开发是由一些业界专家针对一些企业现状提出了一些让软件开发团队具有快速工作、响应变化能力的价值观和原则,并于2001初成立了敏捷联盟。

他们正在通过亲身实践以及帮助他人实践,揭示更好的软件开发方法。

  敏捷开发(agiledevelopment)概念从2004年初开始广为流行。

Bailar非常支持这一理论,他采取了"敏捷方式"组建团队:

CapitalOne的"敏捷团队"包括3名业务人员、两名操作人员和5~7名IT人员,其中包括1个业务信息指导(实际上是业务部门和IT部门之间的"翻译者");另外,还有一个由项目经理和至少80名开发人员组成的团队。

这些开发人员都曾被Bailar送去参加过"敏捷开发"的培训,具备相关的技能。

  每个团队都有自己的敏捷指导(Bailar聘用了20个敏捷指导),他的工作是关注流程并提供建议和支持。

最初提出的需求被归纳成一个目标、一堆记录详细需要的卡片及一些供参考的原型和模板。

在整个项目阶段,团队人员密切合作,开发有规律地停顿--在9周开发过程中停顿3~4次,以评估过程及决定需求变更是否必要。

在CapitalOne,大的IT项目会被拆分成多个子项目,安排给各"敏捷团队",这种方式在"敏捷开发"中叫"蜂巢式(swarming)",所有过程由一名项目经理控制。

  为了检验这个系统的效果,Bailar将项目拆分,从旧的"瀑布式"开发转变为"并列式"开发,形成了"敏捷开发"所倡导的精干而灵活的开发团队,并将开发阶段分成30天一个周期,进行"冲刺"--每个冲刺始于一个启动会议,到下个冲刺前结束。

  在Bailar将其与传统的开发方式做了对比后,他感到非常兴奋--"敏捷开发"使开发时间减少了30%~40%,有时甚至接近50%,提高了交付产品的质量。

"不过,有些需求不能用敏捷开发来处理。

"Bailar承认,"敏捷开发"也有局限性,比如对那些不明确、优先权不清楚的需求或处于"较快、较便宜、较优"的三角架构中却不能排列出三者优先级的需求。

此外,他觉得大型项目或有特殊规则的需求的项目,更适宜采用传统的开发方式。

尽管描述需求一直是件困难的事,但经过阵痛之后,需求处理流程会让CIO受益匪浅。

  敏捷开发是由一些业界专家针对一些企业现状提出了一些让软件开发团队具有快速工作、响应变化能力的价值观和原则,并于2001初成立了敏捷联盟。

他们正在通过亲身实践以及帮助他人实践,揭示更好的软件开发方法。

通过这项工作,他们认为:

∙  个体和交互    胜过过程和工具

∙  可以工作的软件胜过面面俱到的文档

∙  客户合作      胜过合同谈判

∙  响应变化      胜过遵循计划

  并提出了以下遵循的原则:

∙  我们最优先要做的是通过尽早的、持续的交付有价值的软件来使客户满意。

∙  即使到了开发的后期,也欢迎改变需求。

敏捷过程利用变化来为客户创造竞争优势。

∙  经常性地交付可以工作的软件,交付的间隔可以从几个星期到几个月,交付的时间间隔越短越好。

∙  在整个项目开发期间,业务人员和开发人员必须天天都在一起工作。

∙  围绕被激励起来的个体来构建项目。

给他们提供所需的环境和支持,并且信任他们能够完成工作。

∙  在团队内部,最具有效果并富有效率的传递信息的方法,就是面对面的交谈。

∙  工作的软件是首要的进度度量标准。

∙  敏捷过程提倡可持续的开发速度。

责任人、开发者和用户应该能够保持一个长期的、恒定的开发速度。

∙  不断地关注优秀的技能和好的设计会增强敏捷能力。

∙  简单是最根本的。

∙  最好的构架、需求和设计出于自组织团队。

∙  每隔一定时间,团队会在如何才能更有效地工作方面进行反省,然后相应地对自己的行为进行调整。

MatainFlow:

从无到繁重再到敏捷

  多数软件开发仍然是一个显得混乱的活动,即典型的“边写边改”(codeandfix)。

设计过程充斥着短期的,即时的决定,而无完整的规划。

这种模式对小系统开发其实很管用,但是当系统变得越大越复杂时,要想加入新的功能就越来越困难。

同时错误故障越来越多,越来越难于排除。

一个典型的标志就是当系统功能完成后有一个很长的测试阶段,有时甚至有遥遥无期之感,从而对项目的完成产生严重的影响。

我们使用这种开发模式已有很长时间了,不过我们实际上也有另外一种选择,那就是“正规方法”(methodology)。

这些方法对开发过程有着严格而详尽的规定,以期使软件开发更有可预设性并提高效率,这种思路是借鉴了其他工程领域的实践。

  这些正规方法已存在了很长时间了,但是并没有取得令人瞩目的成功,甚至就没怎么引起人们的注意。

对这些方法最常听见的批评就是它们的官僚繁琐,要是按照它的要求来,那有做太多的事情需要做,而延缓整个开发进程。

所以它们通常被认为是“繁琐滞重型”方法,或JimHighSmith所称的“巨型”(monumental)方法。

  作为对这些方法的反叛,在过去几年中出现了一类新方法。

尽管它们还没有正式的名称,但是一般被称为“敏捷型”方法。

对许多人来说,这类方法的吸引之处在于对繁文缛节的官僚过程的反叛。

它们在无过程和过于繁琐的过程中达到了一种平衡,使得能以不多的步骤过程获取较满意的结果。

  敏捷型与滞重型方法有一些显著的区别。

其中一个显而易见的不同反映在文档上。

敏捷型不是很面向文档,对于一项任务,它们通常只要求尽可能少的文档。

从许多方面来看,它们更象是“面向源码”(code-oriented)。

事实上,它们认为最根本的文档应该是源码。

  但是,我并不以为文档方面的特点是敏捷型方法的根本之点。

文档减少仅仅是个表象,它其实反映的是更深层的特点:

  1敏捷型方法是“适配性”而非“预设性”。

重型方法试图对一个软件开发项目在很长的时间跨度内作出详细的计划,然后依计划进行开发。

这类方法在计划制定完成后拒绝变化。

而敏捷型方法则欢迎变化。

其实,它们的目的就是成为适应变化的过程,甚至能允许改变自身来适应变化。

  2敏捷型方法是“面向人”的(people-oriented)而非“面向过程”的(process-oriented)。

它们试图使软件开发工作顺应人的天性而非逆之。

它们强调软件开发应当是一项愉快的活动。

  我认为以上两个特点很好的概括了敏捷开发方法的核心思想:

适应变化和以人为中心

Ation:

 

 这两个圆圈表示不同的视角上的敏捷实践,包括开发者视角和项目管理的视角。

接下来从里向外进行介绍。

 Test-DrivenDevelopment,测试驱动开发,它是敏捷开发的最重要的部分。

在ThoughtWorks,我们实现任何一个功能都是从测试开始,首先对业务需求进行分析,分解为一个一个的Story,记录在StoryCard上。

然后两个人同时坐在电脑前面,一个人依照Story,从业务需求的角度来编写测试代码,另一个人看着他并且进行思考,如果有不同的意见就会提出来进行讨论,直到达成共识,这样写出来的测试代码就真实反映了业务功能需求。

接着由另一个人控制键盘,编写该测试代码的实现。

如果没有测试代码,就不能编写功能的实现代码。

先写测试代码,能够让开发人员明确目标,就是让测试通过。

 ContinuousIntegration,持续集成。

在以往的软件开发过程中,集成是一件很痛苦的事情,通常很长时间才会做一次集成,这样的话,会引发很多问题,比如build未通过或者单元测试失败。

敏捷开发中提倡持续集成,一天之内集成十几次甚至几十次,如此频繁的集成能尽量减少冲突,由于集成很频繁,每一次集成的改变也很少,即使集成失败也容易定位错误。

一次集成要做哪些事情呢?

它至少包括:

获得所有源代码;编译源代码;运行所有测试,包括单元测试、功能测试等;确认编译和测试是否通过,最后发送报告。

当然也会做一些其它的任务,比如说代码分析、测试覆盖率分析等等。

在我们公司里,开发人员的桌上有一个火山灯用来标志集成的状态,如果是黄灯,表示正在集成;如果是绿灯,表示上一次集成通过,开发人员在这时候获得的代码是可用而可靠的;如果显示为红灯,就要小心了,上一次集成未通过,需要尽快定位失败原因从而让灯变绿。

在持续集成上,我们公司使用的是自己开发的产品CruiseControl

 Refactoring,重构。

相信大家对它都很熟悉了,有很多很多的书用来介绍重构,最著名的是Martin的《重构》,Joshua的《从重构到模式》等。

重构是在不改变系统外部行为下,对内部结构进行整理优化,使得代码尽量简单、优美、可扩展。

在以往开发中,通常是在有需求过来,现在的系统架构不容易实现,从而对原有系统进行重构;或者在开发过程中有剩余时间了,对现在代码进行重构整理。

但是在敏捷开发中,重构贯穿于整个开发流程,每一次开发者checkin代码之前,都要对所写代码进行重构,让代码达到cleancodethatworks。

值得注意的是,在重构时,每一次改变要尽可能小,用单元测试来保证重构是否引起冲突,并且不只是对实现代码进行重构,如果测试代码中有重复,也要对它进行重构。

 Pair-Programming,结对编程。

在敏捷开发中,做任何事情都是Pair的,包括分析、写测试、写实现代码或者重构。

Pair做事有很多好处,两个人在一起探讨很容易产生思想的火花,也不容易走上偏路。

在我们公司,还有很多事都是Pair来做,比如Pair学习,Pair翻译,Pair做PPT,关于这个话题,钱钱同学有一篇很有名的文章对它进行介绍,名为PairProgramming(结对编程)。

 Standup,站立会议。

每天早上,项目组的所有成员都会站立进行一次会议,由于是站立的,所以时间不会很长,一般来说是15-20分钟。

会议的内容并不是需求分析、任务分配等,而是每个人都回答三个问题:

1.你昨天做了什么?

2.你今天要做什么?

3.你遇到了哪些困难?

站立会议让团队进行交流,彼此相互熟悉工作内容,如果有人曾经遇到过和你类似的问题,那么在站立会议后,他就会和你进行讨论。

 FrequentReleases,小版本发布。

在敏捷开发中,不会出现这种情况,拿到需求以后就闭门造车,直到最后才将产品交付给客户,而是尽量多的产品发布,一般以周、月为单位。

这样,客户每隔一段时间就会拿到发布的产品进行试用,而我们可以从客户那得到更多的反馈来改进产品。

正因为发布频繁,每一个版本新增的功能简单,不需要复杂的设计,这样文档和设计就在很大程度上简化了。

又因为简单设计,没有复杂的架构,所以客户有新的需求或者需求进行变动,也能很快的适应。

MinimalDocumentation,较少的文档。

其实敏捷开发中并不是没有文档,而是有大量的文档,即测试。

这些测试代码真实的反应了客户的需求以及系统API的用法,如果有新人加入团队,最快的熟悉项目的方法就是给他看测试代码,而比一边看着文档一边进行debug要高效。

如果用书面文档或者注释,某天代码变化了,需要对这些文档进行更新。

一旦忘记更新文档,就会出现代码和文档不匹配的情况,这更加会让人迷惑。

而在敏捷中并不会出现,因为只有测试变化了,代码才会变化,测试是真实反应代码的。

这时有人会问:

代码不写注释行吗?

一般来说好的代码不是需要大量的注释吗?

其实简单可读的代码才是好的代码,既然简单可读了,别人一看就能够看懂,这时候根本不需要对代码进行任何注释。

若你觉得这段代码不加注释的话别人可能看不懂,就表示设计还不够简单,需要对它进行重构。

 CollaborativeFocus,以合作为中心,表现为代码共享。

在敏捷开发中,代码是归团队所有而不是哪些模块的代码属于哪些人,每个人都有权利获得系统任何一部分的代码然后修改它,如果有人看到某些代码不爽的话,那他能够对这部分代码重构而不需要征求代码作者的同意,很可能也不知道是谁写的这部分代码。

这样每个人都能熟悉系统的代码,即使团队的人员变动,也没有风险。

CustomerEngagement,现场客户。

敏捷开发中,客户是与开发团队一起工作的,团队到客户现场进行开发或者邀请客户到团队公司里来开发。

如果开发过程中有什么问题或者产品经过一个迭代后,能够以最快速度得到客户的反馈。

AutomatedTesting,自动化测试。

为了减小人力或者重复劳动,所有的测试包括单元测试、功能测试或集成测试等都是自动化的,这对QA人员提出了更高的要求。

他们要熟悉开发语言、自动化测试工具,能够编写自动化测试脚本或者用工具录制。

我们公司在自动化测试上做了大量的工作,包括Selenium开源项目。

AdaptivePlanning,可调整计划。

敏捷开发中计划是可调整的,并不是像以往的开发过程中,需求分析->概要设计->详细设计->开发->测试->交付,每一个阶段都是有计划的进行,一个阶段结束便开始下一个阶段。

而敏捷开发中只有一次一次的迭代,小版本的发布,根据客户反馈随时作出相应的调整和变化。

敏捷开发过程与传统的开发过程有很大不同,在这过程中,团队是有激情有活力的,能够适应更大的变化,做出更高质量的软件。

TDD:

背景

一个高效的软件开发过程对软件开发人员来说是至关重要的,决定着开发是痛苦的挣扎,还是不断进步的喜悦。

国人对软件蓝领的不屑,对繁琐冗长的传统开发过程的不耐,使大多数开发人员无所适从。

最近兴起的一些软件开发过程相关的技术,提供一些比较高效、实用的软件过程开发方法。

其中比较基础、关键的一个技术就是测试驱动开发(Test-DrivenDevelopment)。

虽然TDD光大于极限编程,但测试驱动开发完全可以单独应用。

下面就从开发人员使用的角度进行介绍,使开发人员用最少的代价尽快理解、掌握、应用这种技术。

下面分优势,原理,过程,原则,测试技术,Tips等方面进行讨论。

1.优势

TDD的基本思路就是通过测试来推动整个开发的进行。

而测试驱动开发技术并不只是单纯的测试工作。

需求向来就是软件开发过程中感觉最不好明确描述、易变的东西。

这里说的需求不只是指用户的需求,还包括对代码的使用需求。

很多开发人员最害怕的就是后期还要修改某个类或者函数的接口进行修改或者扩展,为什么会发生这样的事情就是因为这部分代码的使用需求没有很好的描述。

测试驱动开发就是通过编写测试用例,先考虑代码的使用需求(包括功能、过程、接口等),而且这个描述是无二义的,可执行验证的。

通过编写这部分代码的测试用例,对其功能的分解、使用过程、接口都进行了设计。

而且这种从使用角度对代码的设计通常更符合后期开发的需求。

可测试的要求,对代码的内聚性的提高和复用都非常有益。

因此测试驱动开发也是一种代码设计的过程。

开发人员通常对编写文档非常厌烦,但要使用、理解别人的代码时通常又希望能有文档进行指导。

而测试驱动开发过程中产生的测试用例代码就是对代码的最好的解释。

快乐工作的基础就是对自己有信心,对自己的工作成果有信心。

当前很多开发人员却经常在担心:

“代码是否正确?

”“辛苦编写的代码还有没有严重bug?

”“修改的新代码对其他部分有没有影响?

”。

这种担心甚至导致某些代码应该修改却不敢修改的地步。

测试驱动开发提供的测试集就可以作为你信心的来源。

当然测试驱动开发最重要的功能还在于保障代码的正确性,能够迅速发现、定位bug。

而迅速发现、定位bug是很多开发人员的梦想。

针对关键代码的测试集,以及不断完善的测试用例,为迅速发现、定位bug提供了条件。

我的一段功能非常复杂的代码使用TDD开发完成,真实环境应用中只发现几个bug,而且很快被定位解决。

您在应用后,也一定会为那种自信的开发过程,功能不断增加、完善的感觉,迅速发现、定位bug的能力所感染,喜欢这个技术的。

那么是什么样的原理、方法提供上面说的这些好处哪?

下面我们就看看TDD的原理。

2.原理

测试驱动开发的基本思想就是在开发功能代码之前,先编写测试代码。

也就是说在明确要开发某个功能后,首先思考如何对这个功能进行测试,并完成测试代码的编写,然后编写相关的代码满足这些测试用例。

然后循环进行添加其他功能,直到完全部功能的开发。

我们这里把这个技术的应用领域从代码编写扩展到整个开发过程。

应该对整个开发过程的各个阶段进行测试驱动,首先思考如何对这个阶段进行测试、验证、考核,并编写相关的测试文档,然后开始下一步工作,最后再验证相关的工作。

下图是一个比较流行的测试模型:

V测试模型。

【图V测试模型】

 

在开发的各个阶段,包括需求分析、概要设计、详细设计、编码过程中都应该考虑相对应的测试工作,完成相关的测试用例的设计、测试方案、测试计划的编写。

这里提到的开发阶段只是举例,根据实际的开发活动进行调整。

相关的测试文档也不一定是非常详细复杂的文档,或者什么形式,但应该养成测试驱动的习惯。

关于测试模型,还有X测试模型。

这个测试模型,我认为,是对详细阶段和编码阶段进行建模,应该说更详细的描述了详细设计和编码阶段的开发行为。

及针对某个功能进行对应的测试驱动开发。

【图X测试模型】

 

基本原理应该说非常简单,那么如何进行实际操作哪,下面对开发过程进行详细的介绍。

3.过程

软件开发其他阶段的测试驱动开发,根据测试驱动开发的思想完成对应的测试文档即可。

下面针对详细设计和编码阶段进行介绍。

测试驱动开发的基本过程如下:

1)明确当前要完成的功能。

可以记录成一个TODO列表。

2)快速完成针对此功能的测试用例编写。

3)测试代码编译不通过。

4)编写对应的功能代码。

5)测试通过。

6)对代码进行重构,并保证测试通过。

7)循环完成所有功能的开发。

为了保证整个测试过程比较快捷、方便,通常可以使用测试框架组织所有的测试用例。

一个免费的、优秀的测试框架是Xunit系列,几乎所有的语言都有对应的测试框架。

我曾经写过一篇文章介绍CppUnit的文章。

开发过程中,通常把测试代码和功能代码分开存放,这里提供一个简单的测试框架使用例子,您可以通过它了解测试框架的使用。

下面是文件列表。

project/项目主目录

project/test测试项目主目录

project/test/testSeq.cpp测试seq_t的测试文件,对其他功能文件的测试文件复制后修改即可

project/test/testSeq.h

project/test/Makefile测试项目的Makefile

project/test/main.cpp测试项目的主文件,不需要修改

project/main.cpp项目的主文件

project/seq_t.h功能代码,被测试文件

project/Makefile项目的Makefile

主要流程基本如此,但要让你的代码很容易的进行测试,全面又不繁琐的进行测试,还是有很多测试原则和技术需要考虑。

4.原则

测试隔离。

  不同代码的测试应该相互隔离。

对一块代码的测试只考虑此代码的测试,不要考虑其实现细节(比如它使用了其他类的边界条件)。

一顶帽子。

   开发人员开发过程中要做不同的工作,比如:

编写测试代码、开发功能代码、对代码重构等。

做不同的事,承担不同的角色。

开发人员完成对应的工作时应该保持注意力集中在当前工作上,而不要过多的考虑其他方面的细节,保证头上只有一顶帽子。

避免考虑无关细节过多,无谓地增加复杂度。

测试列表。

  需要测试的功能点很多。

应该在任何阶段想添加功能需求问题时,把相关功能点加到测试列表中,然后继续手头工作。

然后不断的完成对应的测试用例、功能代码、重构。

一是避免疏漏,也避免干扰当前进行的工作。

测试驱动。

  这个比较核心。

完成某个功能,某个类,首先编写测试代码,考虑其如何使用、如何测试。

然后在对其进行设计、编码。

先写断言。

测试代码编写时,应该首先编写对功能代码的判断用的断言语句,然后编写相应的辅助语句。

可测试性。

功能代码设计、开发时应该具有较强的可测试性。

其实遵循比较好的设计原则的代码都具备较好的测试性。

比如比较高的内聚性,尽量依赖于接口等。

及时重构。

  无论是功能代码还是测试代码,对结构不合理,重复的代码等情况,在测试通过后,及时进行重构。

关于重构,我会另撰文详细分析。

小步前进。

   软件开发是个复杂性非常高的工作,开发过程中要考虑很多东西,包括代码的正确性、可扩展性、性能等等,很多问题都是因为复杂性太大导致的。

极限编程提出了一个非常好的思路就是小步前进。

把所有的规模大、复杂性高的工作,分解成小的任务来完成。

对于一个类来说,一个功能一个功能的完成,如果太困难就再分解。

每个功能的完成就走测试代码-功能代码-测试-重构的循环。

通过分解降低整个系统开发的复杂性。

这样的效果非常明显。

几个小的功能代码完成后,大的功能代码几乎是不用调试就可以通过。

一个个类方法的实现,很快就看到整个类很快就完成啦。

本来感觉很多特性需要增加,很快就会看到没有几个啦。

你甚至会为这个速度感到震惊。

(我理解,是大幅度减少调试、出错的时间产生的这种速度感)

5.测试技术

5.1.测试范围、粒度

对哪些功能进行测试?

会不会太繁琐?

什么时候可以停止测试?

这些问题比较常见。

按大师KentBenk的话,对那些你认为应该测试的代码进行测试。

就是说,要相信自己的感觉,自己的经验。

那些重要的功能、核心的代码就应该重点测试。

感到疲劳就应该停下来休息一下。

感觉没有必要更详细的测试,就停止本轮测试。

测试驱动开发强调测试并不应该是负担,而应该是帮助我们减轻工作量的方法。

而对于何时停止编写测试用例,也是应该根据你的经验,功能复杂、核心功能的代码就应该编写更全面、细致的测试用例,否则测试流程即可。

测试范围没有静态的标准,同时也应该可以随着时间改变。

对于开始没有编写足够的测试的功能代码,随着bug的出现,根据bug补齐相关的测试用例即可。

小步前进的原则,要求我们对大的功能块测试时,应该先分拆成更小的功能块进行测试,比如一个类A使用了类B、C,就应该编写到A使用B、C功能的测试代码前,完成对B、C的测试和开发。

那么是不是每个小类或者小函数都应该测试哪?

我认为没有必要。

你应该运用你的经验,对那些可能出问题的地方重点测试,感觉不可能出问题的地方就等它真正出问题的时候再补测试吧。

5.2.怎么编写测试用例

测试用例的编写就用上了传统的测试技术。

∙操作过程尽量模拟正常使用的过程。

∙全面的测试用例应该尽量做到分支覆盖,核心代码尽量做到路径覆盖。

∙测试数据尽量包括:

真实数据、边界数据。

∙测试语句和测试数据应该尽量简单,容易理解。

∙为了避免对其他代码过多的依赖,可以实现简单的桩函数或桩类(MockObject)。

∙如果内部状态非常复杂或者应该判断流程而不是状态,可以通过记录日志字符串的方式进行验证。

6.Tips

很多朋友有疑问,“测试代码的正确性如何保障?

是写测试代码还是写测试文档?

”这样是不是会陷入“鸡生蛋,蛋生鸡”的循环。

其实是不会的。

通常测试代码通常是非常简单的,通常围绕着某个情况的正确性判断的几个语句,如果太复杂,就应该继续分解啦。

而传统的开发过程通常强调测试文档。

但随着开发节奏的加快,用

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 理化生

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1