<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          TDD已死?如何進(jìn)行有效的TDD實(shí)踐 | IDCF

          共 7112字,需瀏覽 15分鐘

           ·

          2021-03-13 03:23


          c924eadffe58f52f81676a87e370966a.webp

          來源:ThoughtWorks洞見、劉冉的思辨悟

          作者:劉冉


          一、TDD已死?

          94600aee5955780afee8f5d8c8f01548.webp



          最近幾年“TDD 已死”的聲音不斷出現(xiàn),特別是 David Heinemeier Hansson 那篇文章——《TDD is dead. Long live testing. (DHH)》 ( http://david.heinemeierhansson.com/2014/tdd-is-dead-long-live-testing.html )引發(fā)了大量的討論。其中最引人注目的是 Kent Beck、Martin Fowler、David 三人就這個舉行的系列對話(辯論)——Is TDD Dead??( https://martinfowler.com/articles/is-tdd-dead/ )
          當(dāng)前國內(nèi)對 TDD 的理解十分模糊,大部分人也沒有明確和有意識的去實(shí)施 TDD,因此許多人對此都有著不同的理解。其中最經(jīng)典的理解就是基于代碼的某個單元,使用 Mock 等技術(shù)編寫單元測試,然后用這個單元測試來驅(qū)動開發(fā),抑或是幫助在重構(gòu)、修改以后進(jìn)行回歸測試。而現(xiàn)在大部分反對 TDD 的聲音就是基于這個理解,比如:
          • 工期緊,時間短,寫 TDD 太浪費(fèi)時間;
          • 業(yè)務(wù)需求變化太快,修改功能都來不及,根本沒有時間來寫 TDD;
          • 寫 TDD 對開發(fā)人員的素質(zhì)要求非常高,普通的開發(fā)人員不會寫;
          • TDD 推行的最大問題在于大多數(shù)程序員還不會「寫測試用例」和「重構(gòu)」;
          • 由于大量使用 Mock 和 Stub 技術(shù),導(dǎo)致 UT 沒有辦法測試集成后的功能,對于測試業(yè)務(wù)價值作用不大;
          • ......
          總結(jié)一下,技術(shù)人員拒絕 TDD 的主要原因在于難度大、工作量大、Mock 的大量使用導(dǎo)致很難測試業(yè)務(wù)價值等。這些理解主要是建立在片面的理解和實(shí)踐之上,而在我的認(rèn)知中,TDD 的核心是:先寫測試,并使用它幫助開發(fā)人員t來驅(qū)動軟件開發(fā)。
          • 首先是先寫測試,這里的測試并不只是單元測試,也不是說一定要使用 mock 和 stub 來做測試。這里的測試就是指軟件測試本身,可以是基于代碼單元的單元測試,可以是基于業(yè)務(wù)需求的功能測試,也可以是基于特定驗(yàn)收條件的驗(yàn)收測試。
          • 其次是幫助開發(fā)人員,主要是幫助開發(fā)人員理解軟件的功能需求和驗(yàn)收條件,幫助其思考和設(shè)計代碼,從而達(dá)到驅(qū)動開發(fā)的目的。
          所以 TDD 是包含兩部分:ATDD 與 UTDD。( http://www.agiledata.org/essays/tdd.html )2a0a9674beff8c6355800d21a2f4052c.webp
          • ATDD(Acceptance Test Driven Development):驗(yàn)收驅(qū)動測試開發(fā),首先 BA 或者 QA 編寫驗(yàn)收測試用例,然后 Dev 通過驗(yàn)收測試來理解需求和驗(yàn)收條件,并編寫實(shí)現(xiàn)代碼直到驗(yàn)收測試用例通過。
          由于驗(yàn)收方法和類型也是多種多樣的,所以根據(jù)驗(yàn)收方法和類型的不同,ATDD 其實(shí)是包含 BDD(Behavior Driven Development)、EDD(Example Driven Development),F(xiàn)DD(Feature Driven Development)、CDCD(Consumer Driven Contract Development)等各種的實(shí)踐方法。比如以軟件的行為為驗(yàn)收標(biāo)準(zhǔn),這個是 BDD;如果以特定的實(shí)例數(shù)據(jù)為驗(yàn)收標(biāo)準(zhǔn),這個是 EDD;如果以 Web Service API 消費(fèi)者提出 API 契約來驅(qū)動 API 提供者開發(fā) API,這個是 CDCD 等。所以 ATDD 的具體實(shí)現(xiàn)需要結(jié)合項(xiàng)目的實(shí)際情況來選用適合的驗(yàn)收測試方法與類型。
          • UTDD(Unit Test Driven Development):單元驅(qū)動測試開發(fā),首先 Dev 編寫單元測試用例,然后編寫實(shí)現(xiàn)代碼直到單元測試通過。這個就是現(xiàn)在很多人所謂的 TDD、實(shí)踐的 TDD、喜歡的 TDD、抱怨的 TDD,但是它卻只是真正意義上 TDD 的一部分而已。
          c6640307772c67288f83de69059ddc2c.webpTDD 金字塔

          二、TDD的實(shí)施和分層

          94600aee5955780afee8f5d8c8f01548.webp



          現(xiàn)在還有非常多軟件工程師在質(zhì)疑 TDD 的可行性,比如太難不會、成本太高無法推動、意義不是很大等,但是他們卻一直都在做著 TDD,只不過沒有意識到而已,這便是“不識廬山真面目,只緣身在此山中”。
          TDD 的實(shí)施一般分為思維層面和技術(shù)層面。一般來說,思維層面上的實(shí)施成本較低、容易接受,但是缺點(diǎn)很多,比如難以傳遞、難以持續(xù)獲得快速反饋等;而技術(shù)層面上的實(shí)施一般成本較高、不容易被人接受,但是優(yōu)點(diǎn)更多,比如可以獲得快速反饋、更容易傳遞和協(xié)作等。而現(xiàn)實(shí)世界中 TDD 的實(shí)施一般分為三個階段,即無意識的 TDD、被動通過技術(shù)實(shí)現(xiàn)的 TDD、以及有意識和主動通過技術(shù)實(shí)現(xiàn)的 TDD。第一階段:無意識的 TDD對于軟件開發(fā)人員,當(dāng)他們拿到一個新的軟件需求時,首先會思考如何實(shí)現(xiàn),其中包括當(dāng)前軟件架構(gòu)、業(yè)務(wù)分解、實(shí)現(xiàn)設(shè)計、代碼分層、代碼實(shí)現(xiàn)等。然后通過思考和設(shè)計所得到的產(chǎn)出物來驅(qū)動代碼實(shí)現(xiàn),進(jìn)而在代碼實(shí)現(xiàn)中會思考如何通過一個或多個函數(shù)或者算法來實(shí)現(xiàn)業(yè)務(wù)邏輯。所以軟件系統(tǒng)的實(shí)現(xiàn)要先通過意識層面的思考,再進(jìn)行技術(shù)層面的工作。eadb436f4a145e7304f2175801eab7c2.webp當(dāng)開發(fā)人員思考和設(shè)計這些函數(shù)或者方法的時候,一般都會思考它們有哪些參數(shù),然后想象將這些參數(shù)換成真實(shí)的數(shù)據(jù)后傳遞進(jìn)去,會得到怎樣的返回值。好一點(diǎn)的開發(fā)人員會思考如何處理異常輸入和異常返回值。這類思考其實(shí)已經(jīng)是意識思維上的 TDD,它幫助開發(fā)人員先在大腦里面設(shè)計并驗(yàn)證代碼實(shí)現(xiàn),甚至幫助其重構(gòu)代碼。所以很多開發(fā)人員都在無意識的情況下做著 TDD。比如在一個銀行系統(tǒng)里面,開發(fā)人員拿到一個需求,需要開發(fā)一個通過手機(jī) APP 轉(zhuǎn)賬的功能。
          1. 首先開發(fā)人員會基于當(dāng)前的軟件架構(gòu)思考:是開發(fā)一個全新的模塊來處理這個業(yè)務(wù)?還是基于當(dāng)前架構(gòu)中的某個模塊來添加代碼進(jìn)行處理?
          2. 當(dāng)確定架構(gòu)和設(shè)計之后,就開始思考具體的代碼實(shí)現(xiàn),比如類的設(shè)計、方法的設(shè)計或者函數(shù)的設(shè)計等。當(dāng)開發(fā)“將錢從原帳號轉(zhuǎn)出”這個功能前,開發(fā)人員會思考:這個功能需要支持當(dāng)錢從原帳號中轉(zhuǎn)出成功后,原帳號中的余額等于原始余額減去轉(zhuǎn)出金額。進(jìn)一步有些程序員還會設(shè)計一些用來驗(yàn)證功能的實(shí)例,比如帳號中的原始余額是 999.99,轉(zhuǎn)出 111.11,那么剩余的金額就應(yīng)該是 888.88。
          3. 在這樣思考之后,開發(fā)人員便開始根據(jù)自己大腦中的測試邏輯和用例來驅(qū)動和輔助開發(fā)過程。在代碼開發(fā)完畢之后還會想一些辦法來驗(yàn)證一下所實(shí)現(xiàn)的功能是否符合預(yù)期,比如人工使用之前的或者新的測試用例再測試一下。如果驗(yàn)證正確,就會認(rèn)為自己開發(fā)的功能正確了,并交給測試人員進(jìn)行測試。
          其實(shí)開發(fā)人員在開發(fā)前思考測試邏輯和用例的過程就是在做 TDD 了。很多做業(yè)務(wù)分析的 BA 和測試分析前移的 QA 也同樣在無意識的做著 TDD,比如分析驗(yàn)收條件、寫出驗(yàn)收文檔等。只不過這些 AC 和驗(yàn)收文檔可能寫得不是很明確或者不是很好,比如不是實(shí)例化需求等,但是本質(zhì)上已經(jīng)是 TDD 了。只不過是初級的無意識的 TDD,可能有的人做得好,有的人做得不好,而且沒有明確的產(chǎn)出來協(xié)助和規(guī)范這個測試驅(qū)動開發(fā)方式,也缺乏快速反饋、度量、傳遞和協(xié)作等。因此從無意識到有意識將是做好 TDD 的一個重要過渡。第二階段:被動通過技術(shù)實(shí)現(xiàn) TDD當(dāng)有一部分軟件工程師意識到了 TDD 的意義和普遍存在性之后,就開始準(zhǔn)備解決思維上的 TDD 的缺點(diǎn)。而解決這些問題的方法就是在技術(shù)層面上用代碼來實(shí)現(xiàn) TDD,用明確的代碼來協(xié)助和規(guī)范開發(fā)人員的測試驅(qū)動開發(fā)行為,來度量他對業(yè)務(wù)邏輯以及代碼實(shí)現(xiàn)的理解度。通過將他的理解傳遞給以后的維護(hù)人員,讓他的理解能重復(fù)被使用,以及和其他人協(xié)作開發(fā)。但是現(xiàn)實(shí)中很多開發(fā)人員的認(rèn)識不足以及技術(shù)能力不夠,就算管理層支持并且主動推動 TDD,最終由于開發(fā)人員設(shè)計和選取的測試用例合理性很差,導(dǎo)致驅(qū)動出來的代碼有效性差,測試用例無法體現(xiàn)出 SBE(Specification by example)導(dǎo)致易讀性差,對于自動化測試框架和測試編寫不熟悉導(dǎo)致開發(fā)速度很慢等,往往是被動的在技術(shù)層面上去實(shí)現(xiàn) TDD,所以出現(xiàn)了各種怨言,各種抵觸,進(jìn)而導(dǎo)致技術(shù)層面上的 TDD 很難以大規(guī)模實(shí)施。由于意識層面上的難易程度和工作量都比技術(shù)層面上相對較小,所以前者實(shí)施起來相對容易一些,而后者則相對較難,所以如果通過了各種手段強(qiáng)行實(shí)施 TDD,而沒有主動去擺正做 TDD 的意識,甚至沒有足夠的技術(shù)能力,那么這樣的 TDD 就是一個倒三角,非常容易倒塌。27b6fbb26ccab71bb4497f3a001983bb.webpTDD 倒三角所以,如果不希望技術(shù)層面上的 TDD 隨時倒塌,就需要把這個倒三角補(bǔ)全,才能更好的、長久的實(shí)施 TDD。第三階段:有意識和主動通過技術(shù)實(shí)現(xiàn) TDD為了大規(guī)模以及有效的實(shí)施 TDD,首先要突破思維意識的局限,認(rèn)識到 TDD 的普遍存在性和適用性,不要害怕和排斥 TDD 這種思維和開發(fā)模式。其次要主動學(xué)習(xí),并刻意練習(xí) TDD 的技術(shù)實(shí)現(xiàn),提升自己的技術(shù)能力,從而在技術(shù)層面能更容易的實(shí)現(xiàn) TDD,擺脫被動 TDD 的困境。其中學(xué)習(xí)的方法包括閱讀 TDD 相關(guān)的書籍和文章,書籍包括《測試驅(qū)動開發(fā)》、《重構(gòu)》、《BDD In Action》以及《系統(tǒng)思考》等,從而充分理解 TDD 優(yōu)點(diǎn)和局限。對于刻意練習(xí),一定要長時間堅持去做,讓其成為一種習(xí)慣。如果在項(xiàng)目中沒有合適的環(huán)境去練習(xí),還可以通過一些第三方的 TDD 練習(xí)系統(tǒng)去做刻意練習(xí),比如 Cyber-dojo( http://www.cyber-dojo.org/ )。只有大量的刻意練習(xí)才能讓你在真實(shí)的代碼編寫過程中去思考和理解 TDD,去運(yùn)用你通過學(xué)習(xí)得到的知識,最終才能做到有意識和主動的通過技術(shù)去實(shí)現(xiàn) TDD,TDD 的倒三角才能變成一個穩(wěn)定的磚塊,然后哪里需要往哪里搬。4f6c0810a5f94eced7f6ca3083d0f96f.webpTDD 磚塊

          三、TDD實(shí)踐

          94600aee5955780afee8f5d8c8f01548.webp



          最近TDD相關(guān)的培訓(xùn)和討論也越來越多,比如:
          • 學(xué)好TDD靠多多練習(xí)就可以了,不用學(xué)習(xí)其理論知識;
          • 開發(fā)應(yīng)該自己理解業(yè)務(wù),并提煉測試(需求)點(diǎn)來實(shí)施TDD;
          • 開發(fā)只要做好TDD,就不需要其他人測試了;
          • 軟件沒有做好就是因?yàn)門DD沒有做好;
          • 等等。
          而我對于這些片面的說法都是不贊同的。
          • 首先,TDD不是銀彈,所以軟件沒有做好的原因是很多的,也不是靠TDD做好了就一定能做好。
          • 其次,學(xué)習(xí)TDD的理論是非常重要的,而僅僅靠不斷練習(xí)并自悟的方法,對于大部分普通人來說是難以成功的。
          • 最后,一般開發(fā)能做的較好的TDD,一般是UTDD,而對于ATDD,則需要相應(yīng)的業(yè)務(wù)分析,測試分析與設(shè)計的相關(guān)方法和技術(shù)。如果要求開發(fā)做好ATDD,則需要開發(fā)學(xué)習(xí)并掌握相應(yīng)的業(yè)務(wù)分析,測試分析與設(shè)計的相關(guān)方法和技術(shù)。而這對于開發(fā)也是非常大的挑戰(zhàn)。所以在真正的TDD實(shí)踐中,如果想大規(guī)模實(shí)施TDD,仍然需要相應(yīng)的分工才更可行,更容易實(shí)施。而提前充分學(xué)習(xí)并了解TDD實(shí)踐的相關(guān)理論,也是可以幫助實(shí)施人員更好的去實(shí)踐,少踩坑,從而正其思規(guī)其行。
          3.1 TDD需要的能力在真實(shí)工作中要較好的實(shí)施TDD需要具備以下能力:
          • 測試前移(左移)的思維能力
          • 軟件設(shè)計能力
          • 業(yè)務(wù)和技術(shù)需求分析和任務(wù)拆分能力
          • 測試用例分析和設(shè)計能力
          • 自動化測試開發(fā)能力
          • 代碼重構(gòu)和持續(xù)改進(jìn)能力
          首先是測試前移(左移)的思維能力是TDD實(shí)施的前提條件。如果沒有這個思維能力,或者不認(rèn)可這個測試前移(左移)的價值,這樣的開發(fā)人員則很難認(rèn)可TDD的開發(fā)方式,從而可能會想盡各種辦法抵制TDD,或者陽奉陰違,從而導(dǎo)致TDD實(shí)施艱難,并顯得困難重重。所以一定要擁有這個能力作為前提才容易真正實(shí)施好TDD。要實(shí)施TDD,第一步就是業(yè)務(wù)需要分析能力,其次根據(jù)需求點(diǎn)設(shè)計測試用例的能力。這里面包含了一個業(yè)務(wù)需求人員和測試人員的基本能力。其中業(yè)務(wù)需求分析能力需要能很好的分析業(yè)務(wù)需求,并能總結(jié)出業(yè)務(wù)需求點(diǎn)或者業(yè)務(wù)驗(yàn)收點(diǎn)。其次測試用例設(shè)計能力需要能根據(jù)業(yè)務(wù)的需求點(diǎn)或者業(yè)務(wù)驗(yàn)收點(diǎn)設(shè)計出有效的正確的測試用例,從而才能驅(qū)動出功能正確的業(yè)務(wù)代碼。實(shí)施TDD最為核心的兩個能力則是自動化測試開發(fā)能力和代碼重構(gòu)能力。其中自動化測試開發(fā)能力是指熟練使用相應(yīng)的自動化測試框架和編程語言,將前面設(shè)計出來的測試用例自動化起來。對于UTDD常用的自動化測試框架有JUnit,Jasmine等,而對于ATDD常用的自動化測試框架則有Cucumber,RobotFramework等。只有將測試用例自動化之后,才能快速的進(jìn)行回歸測試,從而幫助代碼重構(gòu)。而良好的代碼重構(gòu)能力,則是代碼質(zhì)量內(nèi)建,防止代碼腐化以及保障代碼易于維護(hù)的主要手段之一。如果沒有能力或者不愿對代碼進(jìn)行重構(gòu),那么就不能算一個完整的TDD。最后要實(shí)施一套完整的好的TDD,還需要一個持續(xù)改進(jìn)的能力。不僅需要對代碼進(jìn)行持續(xù)改進(jìn),即代碼重構(gòu);還需要對自動化測試的代碼,測試用例設(shè)計和業(yè)務(wù)分析進(jìn)行持續(xù)改進(jìn)。只有這樣對TDD的各個步驟和環(huán)節(jié)都進(jìn)行持續(xù)改進(jìn),才能越來越好的實(shí)施TDD。3.2 UTDD和ATDD的步驟在實(shí)際工作中,實(shí)踐TDD第一步就是轉(zhuǎn)變思維-測試前移(及測試左移),將測試用例分析,設(shè)計和實(shí)現(xiàn)前移到編寫代碼之前。這里的測試并不只是單元測試,也不是說一定要使用mock和stub來做測試。這里的測試就是指軟件測試本身,可以是基于代碼單元的單元測試,也可以是基于業(yè)務(wù)需求的功能測試,也可以是基于特定驗(yàn)收條件的驗(yàn)收測試。其次是幫助開發(fā)人員,主要是幫助開發(fā)人員理解軟件的功能需求和驗(yàn)收條件,幫助其思考和設(shè)計代碼,從而達(dá)到驅(qū)動開發(fā)的目的。所以TDD可以被分為UTDD(Unit TDD)和ATDD(Acceptance TDD),其中UTDD是指代碼單元級別的驅(qū)動開發(fā),而ATDD是指功能驗(yàn)收級別的驅(qū)動開發(fā)。所以TDD可以幫助開發(fā)人員梳理和理解需求 ,幫助開發(fā)人員獲得更好的代碼設(shè)計 ,并且有效的減少過度設(shè)計,獲得大量有效的測試用例(手動/自動), 以及可以獲得快速反饋,從而有效的減少返工,提高代碼的內(nèi)在質(zhì)量。對于UTDD(單元驅(qū)動測試開發(fā)),首先由開發(fā)人員自己或者開發(fā)人員結(jié)對業(yè)務(wù)或者測試人員一起分析并梳理需求點(diǎn),然后開發(fā)人員針對每個需求點(diǎn)編寫自動化單元測試用例,并實(shí)現(xiàn)代碼直到單元測試通過。UTDD中的測試主要針對函數(shù)(方法)或者業(yè)務(wù)單元代碼的測試,而且一定要自動化,這樣才能在開發(fā)的過程中快速的反復(fù)的執(zhí)行它們,從而達(dá)到驅(qū)動開發(fā)的目的。最后也可以在持續(xù)集成流水線快速反復(fù)的執(zhí)行他們,從而幫助持續(xù)集成獲得單元測試層面上的快速反饋。UTDD的特點(diǎn)如下:
          • 關(guān)注單元級別的代碼設(shè)計
          • 測試用例需要明確的實(shí)例
          • 清晰的單元完成標(biāo)志
          • 最快的feedback周期
          • 有效的減少開發(fā)過程中side effect引起的返工
          • 可以幫助開發(fā)減少調(diào)式的成本
          • 可以作為單元接口的使用文檔
          而對于ATDD(驗(yàn)收驅(qū)動測試開發(fā)),首先BA或者QA編寫驗(yàn)收測試用例,然后Dev通過驗(yàn)收測試來理解需求和驗(yàn)收條件,并編寫實(shí)現(xiàn)代碼直到驗(yàn)收測試用例通過。由于驗(yàn)收方法和類型也是多種多樣的,所以根據(jù)驗(yàn)收方法和類型的不同ATDD又可以分為BDD(Behavior Driven Development),EDD(Example Driven Development),F(xiàn)DD(Feature Driven Development),CDCD(Consumer Driven Contact Development)等具體的實(shí)踐方法。比如以用戶使用軟件時軟件的行為為驗(yàn)收標(biāo)準(zhǔn),這個是BDD;如果以特定的實(shí)例數(shù)據(jù)為驗(yàn)收標(biāo)準(zhǔn),這個是EDD;如果以Web Service API消費(fèi)者提出API契約來驅(qū)動API提供者開發(fā)API,這個是CDCD等。所以ATDD的具體實(shí)現(xiàn)需要結(jié)合項(xiàng)目的實(shí)際情況,選用適合的驗(yàn)收測試方法與類型。ATDD的特點(diǎn)如下:
          • 關(guān)注業(yè)務(wù)價值,測試與需求一體化
          • 明確的測試實(shí)例(SBE)而不是復(fù)雜的描述
          • 清晰的功能完成標(biāo)志
          • 更快的feedback周期,提早并頻繁溝通
          • 消除誤解,減少返工
          • 可視化的驗(yàn)收回歸測試
          • 可以作為描述功能的活文檔
          測試驅(qū)動開發(fā)的實(shí)施有一個經(jīng)典三步曲,不論是UTDD還是ATDD都可以按照這個三步來實(shí)施:?
          1. 變紅:寫一個不通過的測試 (紅)?
          2. 變綠:寫實(shí)現(xiàn)代碼,使其剛好通過測試 (綠)
          3. 重構(gòu)
          但是要實(shí)施好TDD,不能只靠這三個核心步驟,還需要相應(yīng)的其他輔助步驟以及多方協(xié)作,下面兩個圖分別展示了TDD的步驟和協(xié)作的基本全貌。TDD實(shí)施-步驟9477e3dff10252543934bb054366d55b.webpTDD實(shí)施-步驟1b8aa13eda5b93d6eb11345aaf5fa03f.webp

          四、最后

          94600aee5955780afee8f5d8c8f01548.webp



          業(yè)界元老Robert C. Martin 也提出過他總結(jié)的TDD三原則:
          • 不允許編寫任何產(chǎn)品代碼,除非目的是為了讓失敗的測試通過;
          • 不允許編寫多于一個的失敗測試,編譯錯誤也是失敗;
          • 不允許編寫多于恰好能讓測試通過的產(chǎn)品代碼,有效的減少返工。
          這三個原則很好的總結(jié)了TDD實(shí)踐的關(guān)鍵步驟。此三原則雖然是正確的,但是嚴(yán)格按照此三個原則去做卻是不易的,并且在現(xiàn)實(shí)的開發(fā)工作中并不是很多人能嚴(yán)格按照此三原則去編寫代碼,因?yàn)檗D(zhuǎn)變思維是一件很困難的事情,而且如果在時間短交付壓力大的情況下就更為困難了。但是在我經(jīng)歷的項(xiàng)目中,我們一般以ATDD結(jié)合UTDD的模式進(jìn)行工作,并根據(jù)資源的多少決定其比例,從而全方位保證代碼的內(nèi)在質(zhì)量和業(yè)務(wù)正確性。55a422f3021e3479665c70e11e3af055.webp想要提升敏捷DevOps技能,來場DevOps黑客馬拉松!想要尋找第二增長曲線實(shí)現(xiàn)創(chuàng)新增速,來場DevOps黑客馬拉松!2021年4月24-25日,IDCF DevOps黑客馬拉松走進(jìn)天府之國-成都趕緊報名參加吧~可自己報名,也可公司組團(tuán)參加哦!

          32e1fdf32622618700caebd1d8067bc1.webp

          瀏覽 206
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码免费视频观看 | 四虎影院最新地址 | 国产欧美黄色一级片 | 久久夜色国产精品噜噜AVAV | 麻豆成人传媒网,一区二区三区四区 |