如果你想成為一名專業的軟件工程師

      網友投稿 755 2022-05-29

      “噢,笑吧,科廷,老伙計。這是上帝,或者也可以說是命運或自然,跟我們開的一個玩笑。不過,不管這家伙是誰或是什么,他真幽默!哈哈!”

      ——霍華德,《碧血***》

      哦,你點進來了,這么說,你確實是想成為專業的軟件工程師,對吧?你希望能昂首挺胸向世界宣告“我是專業人士”,希望人們滿懷尊重地看著你,充滿敬意地對待你。希望母親們會指著你告訴自己的孩子要成為像你這樣的人。這些都是你想要的,對吧?

      1 清楚你要什么

      “專業主義”有很深的含義,它不但象征著榮譽與驕傲,而且明確意味著責任與義務。這兩者密切相關,因為你不可能從你無法負責的事情上獲得榮譽與驕傲。

      做個非專業人士可輕松多了。非專業人士不需要為自己所做的工作負責,他們大可把責任推給雇主。如果非專業人士把事情搞砸了,收拾攤子的往往是雇主;而專業人士如果犯了錯,只好自己收拾殘局。

      如果你不小心放過了某個模塊里的一個bug,以致公司損失了1萬美元,結果將會怎樣呢?非專業人士會聳聳肩說:“難免要出點兒狀況嘛。”然后像沒事兒人一樣繼續寫其他模塊。而專業人士會自己為公司的那1萬美元買單!

      哇,自掏腰包?那可真讓人心疼唉!但專業人士就必須這么做。實際上,專業主義的精髓就在于將公司利益視同個人利益。看到了吧,“專業主義”就意味著擔當責任。

      2 擔當責任

      我曾因不負責任嘗盡了苦頭,所以明白盡職盡責的重要意義。

      那是1979年,當時我是一家叫Teradyne的公司的“負責工程師”,所負責的軟件控制著一個測量電話線路質量的小型機系統和微機系統,該系統的中央小型機通過帶寬為300波特的撥號電話線與幾十臺控制測量硬件的外圍微機連接在一起,程序是用匯編語言編寫的。

      我們的客戶是各大電話公司的客服經理,他們每個人都負責10萬條甚至更多的電話線路。我的系統負責幫助這些服務區經理搶在客戶之前發現各種線路故障并及時修復。這可以減少客戶投訴率,以免對此做監測的公共設施委員會相應下調電話公司收取的服務費。總之,這些系統極其重要。

      每天晚上,這些系統都會運行“夜間例行程序”,即中央小型機會通知外圍微機對所控制的電話線路進行檢測;每天早上,中央計算機就能獲取故障線路清單及其故障特征。根據這些報告,各服務區經理會安排人員修復故障,這樣就不會有客戶投訴了。

      一次,我對幾十個客戶推出了一版新發布。“推出”這詞可真是形象啊。我把軟件寫在磁帶上,就把這些帶子“推出”給客戶了。客戶載入這些磁帶,然后重啟系統。

      這一新發布修復了幾個小故障,還增加了客戶要求的一項新功能。之前我們曾承諾會在截止日期之前提供那項新功能。我連夜趕工,總算在約定日期前交付了磁帶。

      兩天后,我接到現場服務經理Tom的電話,他告訴我已經有好幾個客戶投訴“夜間例行程序”沒能執行完成,他們沒收到任何報告。我不由心頭一沉:為了按時交付軟件,我沒測試例行程序。我測試了系統的其他大部分功能,但測試例行程序要費好幾個小時,而當時我又必須交付軟件。因為故障修復部分都不涉及例行程序部分的編碼,所以我也沒擔心會有什么不妥。

      收不到夜間報告,問題可就大了。修理工們會一時無事可忙但隨后又要超負荷工作,而且,有些電話客戶也可能會在這期間發現故障并投訴。要是弄丟一晚的數據,某一服務區經理肯定會打電話臭罵Tom。

      我啟動實驗室系統,加載新軟件,然后開始對“夜間例行程序”進行測試。幾小時后,運行中斷。例行程序運行失敗!如果我在匆忙交付軟件前對此進行測試,就不會發生服務區丟失數據的事了,服務區經理們這時也不會炮轟Tom了。

      我打電話給Tom,說我能重現問題了。Tom告訴我其他大部分客戶也已經打電話抱怨了,并問我什么時候能解決問題。我說我也沒把握,但正在努力。同時我告訴他應該建議客戶倒回去使用舊版軟件。Tom發火了,說那對客戶來說無疑是個雙重打擊,因為客戶不僅為此丟失了一整個晚上的數據,而且還無法使用事先承諾的新功能。

      故障排查非常困難,每次測試就要好幾個小時。第一次修復失敗了。第二次也沒能成功。我試了好幾次,等我發現問題所在時,好幾天已過去了。這期間,Tom每隔幾小時就打電話問我問題什么時候能解決,他還把那些服務區經理喋喋不休的抱怨如數傳達給我,并一再告訴我讓那些客戶重新起用舊軟件令他多么尷尬。

      最后,我終于找出了缺陷所在,重新交付修復了問題的新程序,一切恢復正常。Tom也平靜下來,不再提這段插曲,畢竟,他不是我的上司。事后,我的老板過來對我說:“你最好別再犯同樣的錯誤。”我只能默默地點點頭。

      經過反省,我意識到沒有對例行程序進行測試就交付軟件是不負責任的。為了如期交付產品,我忽略了測試環節,整個過程中只考慮要如何保全自己的顏面,卻沒顧及客戶和雇主的聲譽。我本該早點兒擔起責任,告訴Tom測試還未完成、自己不能按時交付產品。那么做絕非易事,Tom一定會不高興,但客戶不會丟失數據,客服經理也不會打電話來轟炸。

      3 首先,不行損害之事

      那么,我們該如何承擔責任呢?的確有一些原則可供參考。援引“希波克拉底誓言”或許顯得有點夸張,但沒有比這更好的引據了。的確,作為一名有追求有抱負的專業人士,他的首要職責與目標難道不正是盡其所能行有益之事嗎?

      軟件開發人員能做出什么壞事呢?從純軟件角度看,他可以破壞軟件的功能與架構。我們會探討如何避免帶來這些破壞。

      3.1 不要破壞軟件功能

      如果你想成為一名專業的軟件工程師

      顯然,我們希望軟件可以運行。沒錯,我們中的大部分人今天之所以是程序員,是因為我們曾開發出可用的軟件,而且希望能再度體驗那種成功創作的喜悅。但希望軟件有用的不單單是我們,客戶和雇主也希望它們能用。是啊,他們出錢,讓我們去開發那些能按照他們意愿運行的軟件。

      開發的軟件有bug會損害軟件的功能。因此,要做得專業,就不能留下bug。

      “等等!”你肯定會說,“可是那是不可能的呀。軟件開發太復雜了,怎么可能會沒bug呢!”

      當然,你說的沒錯。軟件開發太復雜了,不可能沒什么bug。但很不幸,這并不能為你開脫。人體太復雜了,不可能盡知其全部,但醫生仍要發誓不傷害病人。如果他們都不拿“人體的復雜性”作托辭,我們又怎么能開脫自己的責任呢?

      “你的意思是我們要追求完美嘍?”你可能會這樣抬杠吧?

      不,我其實是想告訴你,要對自己的不完美負責。代碼中難免會出現bug,但這并不意味著你不用對它們負責;沒人能寫出完美的軟件,但這并不表示你不用對不完美負責。

      所謂專業人士,就是能對自己犯下的錯誤負責的人,哪怕那些錯誤實際上在所難免。所以,雄心勃勃的專業人士們,你們要練習的第一件事就是“道歉”。道歉是必要的,但還不夠。你不能一而再、再而三地犯相同的錯誤。職業經驗多了之后,你的失誤率應該快速減少,甚至漸近于零。失誤率永遠不可能等于零,但你有責任讓它無限接近零。

      因此,發布軟件時,你應該確保QA找不出任何問題。故意發送明知有缺陷的代碼,這種做法是極其不專業的。什么樣的代碼是有缺陷的呢?那些你沒把握的代碼都是!

      有些家伙會把QA當作啄木鳥看待。他們把自己沒有全盤檢查過的代碼發送過去,想等QA找出bug再反饋回來。沒錯,有些公司確實按照所發現的bug數來獎勵測試人員,揪出的bug越多,獎金越多。

      且不說這么做是否會大幅增加公司成本,嚴重損害軟件,是否會破壞計劃并讓企業對開發小組的信心打折扣,也不去評判這么做是否等同于懶惰失職,把自己沒把握的代碼發送給QA這么做本身就是不專業的。這違背了“不行損害之事”的原則。

      QA會發現bug嗎?可能會吧,所以,準備好道歉吧,然后反思那些bug是怎么逃過你的注意的,想辦法防止它再次出現。

      每次QA找出問題時,更糟糕的是用戶找出問題時,你都該震驚羞愧,并決心以此為戒。

      你怎么知道代碼能否常運行呢?很簡單,測試!一遍遍地測,翻來覆去、顛來倒去地測,使出渾身解數來測!

      你或許會擔心這么狂測代碼會占用很多時間,畢竟,你還要趕進度,要在截止日期前完工。如果不停地花時間做測試,你就沒時間寫別的代碼了。言之有理!所以要實行自動化測試。寫一些隨時都能運行的單元測試,然后盡可能多地執行這些測試。

      要用這些自動化單元測試去測多少代碼呢?還要說嗎?全部!全部都要測!

      我是在建議進行百分百測試覆蓋嗎?不,我不是在建議,我是在要求!你寫的每一行代碼都要測試。完畢!

      這是不是不切實際?當然不是。你寫代碼是因為想執行它,如果你希望代碼可以執行,那你就該知道它是否可行。而要知道它是否可行,就一定要對它進行測試。

      我是開源項目FitNesse的主要貢獻者和代碼提交者。在寫作本書的時候,FitNesse的代碼有6萬多行。在這6萬行代碼中有2000多個單元測試,超過2.6萬行。Emma的報告顯示,這2000多個測試對代碼的覆蓋率約為90%。

      為什么只有90%呢?因為Emma會忽略一些執行的代碼。我確信實際的覆蓋率會比90%高許多。能達到100%嗎?不,達不到,100%只是個理想值。

      但是有些代碼不是很難測試嗎?是的,但之所以很難測試,是因為設計時就沒考慮如何測試。唯一的解決辦法就是要設計易于測試的代碼,最好是先寫測試,再寫要測的代碼。

      這一方法叫做測試驅動開發(TDD),我們在隨后的章節里會繼續談到。

      FitNesse的整個QA流程即是執行單元測試和驗收測試。如果這些測試通過了,我就會發布軟件。這意味著我的QA流程大概需要3分鐘,只要我想要,可以隨時執行完整的測試流程。

      沒錯,FitNesse即使有bug也不是什么人命關天的事,也不會有人為此損失幾百萬美元。值得一提的是FitNesse用戶上萬,但它的bug列表卻很短。

      當然,也不排除有些系統因其任務極其關鍵特殊,不能只靠簡短的自動化測試來判斷軟件是否已經足夠高質量,是否可以投入使用。而且,作為開發人員,你需要有個相對迅捷可靠的機制,以此判斷所寫的代碼可否正常工作,并且不會干擾系統的其他部分。因此,你的自動化測試至少要能夠讓你知道,你的系統很有可能通過QA的測試。

      3.2 不要破壞結構

      成熟的專業開發人員知道,聰明人不會為了發布新功能而破壞結構。結構良好的代碼更靈活。以犧牲結構為代價,得不償失,將來必追悔莫及。

      所有軟件項目的根本指導原則是,軟件要易于修改。如果違背這條原則搭建僵化的結構,就破壞了構筑整個行業的經濟模型。

      簡言之,你必須能讓修改不必花太高代價就可以完成。

      不幸的是,實在是已有太多的項目因結構糟糕而深陷失敗的泥潭。那些曾經只要幾天就能完成的任務現在需要耗費幾周甚至幾個月的時間。急于重新樹立威望的管理層于是聘來更多的開發人員來加快項目進度,但這些開發人員只會進一步破壞結構,亂上添亂。

      描述如何創建靈活可維護的結構的軟件設計原則和模式已經有許多了。專業的軟件開發人員會牢記這些原則和模式,并在開發軟件時認真遵循。但是其中有一條實在是沒幾個軟件開發人員會認真照做,那就是,如果你希望自己的軟件靈活可變,那就應該時常修改它!

      要想證明軟件易于修改,唯一辦法就是做些實際的修改。如果發現這些改動并不像你預想的那樣簡單,你便應該改進設計,使后續修改變簡單。

      該在什么時候做這些簡單的小修改呢?隨時!關注哪個模塊,就對它做點簡單的修改來改進結構。每次通讀代碼的時候,也可以不時調整一下結構。

      這一策略有時也叫“無情重構”,我把它叫作“童子軍訓練守則”:對每個模塊,每檢入一次代碼,就要讓它比上次檢出時變得更為簡潔。每次讀代碼,都別忘了進行點滴的改善。

      這完全與大多數人對軟件的理解相反。他們認為對上線運行的軟件不斷地做修改是危險的。錯!讓軟件保持固定不變才是危險的!如果一直不重構代碼,等到最后不得不重構時,你就會發現代碼已經“僵化了”。

      為什么大多數開發人員不敢不斷修改他的代碼呢?因為他們害怕會改壞代碼!為什么會有這樣的擔心呢?因為他們沒做過測試。

      話題又回到測試上來了。如果你有一套覆蓋了全部代碼的自動化測試,如果那套測試可以隨時快速執行,那么你根本不會害怕修改代碼。怎樣才能證明你不怕修改代碼呢?那就是,你一直在改。

      專業開發人員對自己的代碼和測試極有把握,他們會極其瘋狂隨意地做各種修改。他們敢于隨心所欲修改類的名稱。在通讀代碼時,如果發現一個冗長的方法,他們肯定會將它拆分,重新組織。他們還會把switch語句改為多態結構,或者將繼承層次重構成一條“命令鏈”。簡單地說,他們對待代碼,就如同雕塑家對待泥巴那樣,要對它進行不斷的變形與塑造。

      4 職業道德

      職業發展是你自己的事。雇主沒有義務確保你在職場能夠立于不敗之地,也沒義務培訓你,送你參加各種會議或給你買各種書籍充電。這些都是你自己的事。將自己的職業發展寄希望于雇主的軟件開發人員將會很慘。

      有些雇主愿意為員工買各種書籍或送員工參加各種培訓課程和會議。那樣挺不錯的,說明他們待你不薄。但可千萬別就此認為這些是雇主該做的。如果他們不為你做這些,你就該自己想辦法去做。

      另外,雇主也沒義務給你留學習時間。有些雇主會這么做,有些甚至要求你這么做。但是還是那句話,他們待你不薄,你應該適當表示感激。因為這些優待不是你理所當然就該享有的。

      雇主出了錢,你必須付出時間和精力。為了說明問題,就用一周工作40小時的美國標準來做參照吧。這40小時應該用來解決雇主的問題,而不是你自己的問題。

      你應該計劃每周工作60小時。前40小時是給雇主的,后20小時是給自己的。在這剩余的20小時里,你應該看書、練習、學習,或者做其他能提升職業能力的事情。

      你肯定會說:“那我的家庭該怎么辦?還有我的生活呢?難道我就該為雇主犧牲這些嗎?”

      在此,我不是說要占用你全部的業余時間。我是指每周額外增加20小時,也就是大約每天3小時。如果你在午飯時間看看書,在通勤路上聽聽播客,花90分鐘學一門新的語言,那么你就都能兼顧到了。

      做個簡單的計算吧。一周有168小時,給你的雇主40小時,為自己的職業發展留20小時,剩下的108小時再留56小時給睡眠,那么還剩52小時可做其他的事呢。

      或許你不愿那么勤勉。沒問題。只是那樣的話你也不能自視為專業人士了,因為所謂“術業有專攻”那也是需要投入時間去追求的。

      或許你會覺得工作就該在上班時完成,不該再帶回家中。贊成!那20小時你不用為雇主工作。相反,你該為自己的職業發展工作。

      有時這兩者并不矛盾,而是一致的。有時你為雇主做的工作讓你個人的職業發展受益匪淺,這種情況下,在那20小時里花點時間為雇主工作也是合理的。但別忘了,那20小時是為你自己的。它們將會讓你成為更有價值的專業人士。

      或許你會覺得這樣做只會讓人精力枯竭。恰恰相反,這樣做其實能讓你免于枯竭匱乏。假設你是因為熱愛軟件而成為軟件開發者,渴望成為專業開發者的動力也正是來自對軟件的熱情,那么在那20小時里,就應該做能夠激發、強化你的熱情的事。那20小時應該充滿樂趣!

      4.1 了解你的領域

      你知道什么是N-S(Nassi-Schneiderman)圖表嗎?如果不知道,那為什么不了解一下呢?你知道“米利型”(Mealy)和“摩爾型”(Moore)這兩種狀態機的差別嗎?你應該知道的。你能不需查閱算法手冊就可寫出一個快速排序程序嗎?你知道“變換分析”(Transform Analysis)這個術語的意思嗎?你知道如何用數據流圖進行功能分解嗎?你知道“臨時傳遞數據”(Tramp Data)的意思嗎?你聽說過“耦合性”(Conascence)嗎?什么是Parnas表呢?

      近50年來,各種觀點、實踐、技術、工具與術語在我們這一領域層出不窮。你對這些了解多少呢?如果想成為一名專業開發者,那你就得對其中的相當一大部分有所了解,而且要不斷擴展這一知識面。

      為什么要了解這些呢?這一行業發展迅速,許多舊見解似乎也已經過時了,不是嗎?前半句似乎是顯而易見的。確實,行業正迅猛發展,而有趣的是,從多個方面來看,這種進展都只是很淺層的。沒錯,我們不再需要為拿到編譯結果苦等上24小時,我們也已經可以寫出GB級別的系統,我們置身覆蓋全球的網絡之中,各種信息唾手可得。但另一方面,我們還是跟50年前一樣,寫著各種if和while語句。所以,改變說多也多,說少也少。

      舊見解過時了這種說法明顯是不對的。過去50年中產生的理念,已經過時的其實很少。有一部分理論確實在慢慢淡出,比如說“瀑布式開發”的理論確實不再流行了。但這并不表示我們不需要了解它,不需要知道它的長處和短處。

      總的來說,那些在過去50年中來之不易的理念,絕大部分在今天仍像過去一樣富有價值,甚至寶貴了。

      別忘了桑塔亞納的詛咒:“不能銘記過去的人,注定要重蹈覆轍。”

      下面列出了每個專業軟件開發人員必須精通的事項。

      設計模式。必須能描述GOF書中的全部24種模式,同時還要有POSA書中的多數模式的實戰經驗。

      設計原則。必須了解SOLID原則,而且要深刻理解組件設計原則。

      方法。必須理解XP、Scrum、精益、看板、瀑布、結構化分析及結構化設計等。

      實踐。必須掌握測試驅動開發、面向對象設計、結構化編程、持續集成和結對編程。

      工件。必須了解如何使用UML圖、DFD圖、結構圖、Petri網絡圖、狀態遷移圖表、流程圖和決策表。

      4.2 堅持學習

      軟件行業的飛速改變,意味著軟件開發人員必須堅持廣泛學習才不至于落伍。不寫代碼的架構師必然遭殃,他們很快會發現自己跟不上時代了;不學習新語言的程序員同樣會遭殃,他們只能眼睜睜看著軟件業一路發展,把自己拋在后面;學不會新規矩和新技術的開發人員更可憐,他們只能在日漸淪落的時候看著身邊人越發優秀。

      你會找那些已經不看醫學期刊的醫生看病嗎?你會聘請那些不了解最新稅法和判例的稅務律師嗎?雇主們干嘛要聘用那些不能與時俱進的開發人員呢?

      讀書,看相關文章,關注博客和微博,參加技術大會,訪問用戶群,多參與讀書與學習小組。不懂就學,不要畏難。如果你是.NET程序員,就去學學Java;如果你是Java程序員,就去學學Ruby;如果你是C語言程序員,就去學學Lisp;如果你真想練練腦子,就去學學Prolog和Forth吧!

      4.3 練習

      業精于勤。真正的專業人士往往勤學苦干,以求得自身技能的純熟精煉。只完成日常工作是不足以稱為練習的,那只能算是種執行性質的操作,而不是練習。練習,指的是在日常工作之余專門練習技能,以期自我提升。

      對軟件開發人員來說,有什么可以用以操練的呢?乍一聽,這概念顯得荒唐。但是再仔細想一會兒,想想音樂家是如何掌握演練技能的。他們靠的不是表演,而是練習。他們又是如何練習的呢?首先,表演之前,都需要經歷過特別的訓練,音階、練習曲、不斷演奏等。他們一遍又一遍地訓練自己的手指和意識,保持技巧純熟。

      那么軟件開發者該怎樣來不斷訓練自己呢?本書會用一整章的篇幅來談論各種練習技巧,所以在此先不贅述了。簡單說,我常用的一個技巧是重復做一些簡單的練習,如“保齡球游戲”或“素數篩選”,我把這些練習叫作“卡塔”(kata)。卡塔有很多類型。

      卡塔的形式往往是一個有待解決的簡單編程問題,比如編寫計算拆分某個整數的素數因子等。練卡塔的目的不是找出解決方法(你已經知道方法了),而是訓練你的手指和大腦。

      每天我都會練一兩個卡塔,時間往往安排在正式投入工作之前。我可能會選用Java、Ruby、Clojure或其他我希望保持純熟的語言來練習。我會用卡塔來培養某種專門的技能,比如讓我的手指習慣點擊快捷鍵或習慣使用某些重構技法等。

      不妨早晚都來個10分鐘的卡塔吧,把它當作熱身練習或者靜心過程。

      4.4 合作

      學習的第二個最佳方法是與他人合作。專業軟件開發人員往往會更加努力地嘗試與他人一起編程、一起練習、一起設計、一起計劃,這樣他們可以從彼此身上學到很多東西,而且能在更短的時間內更高質量地完成更多工作。

      并不是讓你花全部時間一直和別人共事。獨處的時間也很重要。雖然我很喜歡和別人一起編程,但是如果不能經常獨處,我也一樣會發瘋。

      4.5 輔導

      俗話說:教學相長。想迅速牢固地掌握某些事實和觀念,最好的辦法就是與你負責指導的人交流這些內容。這樣,傳道授業的同時,導師也會從中受益。

      同樣,讓新人融入團隊的最好辦法是和他們坐到一起,向他們傳授工作要訣。專業人士會視輔導新人為己任,他們不會放任未經輔導的新手恣意妄為。

      4.6 了解業務領域

      每位專業軟件開發人員都有義務了解自己開發的解決方案所對應的業務領域。如果編寫財務系統,你就應該對財務領域有所了解;如果編寫旅游應用程序,那么你需要去了解旅游業。你未必需要成為該領域的專家,但你仍需要用功,付出相當的努力來認識業務領域。

      開始一個新領域的項目時,應當讀一兩本該領域相關的書,要就該領域的基礎架構與基本知識作客戶和用戶訪談,還應當花時間和業內專家交流,了解他們的原則與價值觀念。

      最糟糕、最不專業的做法是,簡單按照規格說明來編寫代碼,但卻對為什么那些業務需要那樣的規格定義不求甚解。相反,你應該對這一領域有所了解,能辨別、質疑規格說明書中的錯誤。

      4.7 與雇主/客戶保持一致

      雇主的問題就是你的問題。你必須弄明白這些問題,并尋求最佳的解決方案。每次開發系統,都應該站在雇主的角度來思考,確保開發的功能真正能滿足雇主的需要。

      開發人員之間互相認同是容易的,但把一方換成雇主,人們就容易產生“彼”“此”之分。專業人士會盡全力避免這樣的狹隘之見。

      4.8 謙遜

      編程是一種創造性活動。寫代碼是無中生有的創造過程,我們大膽地從混沌之中創建秩序。我們自信地發布準確無誤的指令,稍有差錯,機器的錯誤行為就可能造成無法估量的損失。因此,編程也是極其自負的行為。

      專業人士知道自己自負,不會故作謙遜。他們熟知自己的工作,并引以為榮;他們對自己的能力充滿自信,并因此勇于承擔有把握的風險。專業人士不是膽小鬼。

      然而,專業人士也知道自己會摔跟頭,自己的風險評估也有出錯的時候,自己也有力不從心的時候。這時候,如果他們照照鏡子,會看到那個自負的傻瓜正對著自己笑。

      因此,在發現自己成為笑柄時,專業人士會第一個發笑。他從不會嘲諷別人,自作自受時他會接受別人的嘲諷。反之,他則會一笑了之。他不會因別人犯錯就對之橫加貶損,因為他知道,自己有可能就是下一個犯錯的人。

      專業人士都清楚自己的自負,也知道上天會注意到這種自負,并加以懲戒。如若果真遭遇挫折,最好的辦法就是按照霍華德說的——一笑了之吧!

      軟件開發 單元測試

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:一文詳解數據庫安全基礎
      下一篇:JS數據結構與算法總結 (第一篇)
      相關文章
      亚洲αv在线精品糸列| WWW国产亚洲精品久久麻豆| 亚洲avav天堂av在线网毛片| 亚洲日产2021三区在线| 亚洲午夜未满十八勿入网站2| 亚洲av无码专区在线电影天堂| 亚洲美女视频网站| 亚洲AV日韩AV永久无码久久 | 国产中文在线亚洲精品官网| 深夜国产福利99亚洲视频| 国产亚洲sss在线播放| 亚洲人成电影在线观看青青| 亚洲婷婷天堂在线综合| 亚洲另类图片另类电影| 亚洲一级免费毛片| 亚洲香蕉久久一区二区| 亚洲高清中文字幕免费| 亚洲一区二区三区在线观看网站| 亚洲高清中文字幕免费| 亚洲av无码专区首页| 亚洲爆乳精品无码一区二区| 久久亚洲AV成人无码国产最大| 亚洲欧美成aⅴ人在线观看| 亚洲色大成WWW亚洲女子| 亚洲人成网站18禁止| 成人亚洲国产va天堂| 亚洲一区二区三区高清不卡| 亚洲一线产品二线产品| 亚洲av无一区二区三区| 亚洲av无码国产精品色在线看不卡| 亚洲AⅤ无码一区二区三区在线 | 亚洲小说区图片区另类春色| 亚洲乱码中文字幕综合| 亚洲伊人久久大香线蕉综合图片| 亚洲乱码国产乱码精品精| 亚洲老妈激情一区二区三区| 亚洲日本精品一区二区| 亚洲天堂一区二区三区| 亚洲AV日韩综合一区尤物| 久久亚洲欧美国产精品| 亚洲午夜精品久久久久久浪潮|