日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

专业程序员必知必会的技巧:驯服复杂代码

發(fā)布時間:2023/12/10 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 专业程序员必知必会的技巧:驯服复杂代码 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

你從入職第一天起就要應(yīng)對復(fù)雜代碼。

若是還未遇到過無法理解的程序,那說明你編程的年頭還不夠長。在行業(yè)里,要不了多久你就會碰到讓人發(fā)懵的混亂代碼:巨獸、面條工廠、來自地獄的遺留系統(tǒng)。我曾接手過一個程序,它的前任在聽說要增加一個分量不輕的新特性時,選擇了辭職。(我并不怪他。)

軟件系統(tǒng)的復(fù)雜度是不可避免的。有些問題就是很難,它們的解決方案很復(fù)雜。然而,你在軟件中找到的大多數(shù)復(fù)雜度是我們自己造成的。在《The Mythical Man-Month》(人月神話)[Bro95]里,Fred Brooks將復(fù)雜度的兩個來源分成必然(necessary)復(fù)雜度和偶然(accidental)復(fù)雜度。

這里有一種區(qū)分必然復(fù)雜度和偶然復(fù)雜度的思考方法:什么復(fù)雜度是問題域固有的?假設(shè)你面對的是一個日期/時間處理代碼散落各處的程序。在處理時間時,存在一些必然復(fù)雜度:每月的天數(shù)不同,必須考慮閏年,等等。但多數(shù)我碰到的程序充斥著大量與處理時間相關(guān)的偶然復(fù)雜度:用不同格式保存的時間,加減時間的新奇(同時也是充滿Bug的)方法,不一致的時間打印格式,說都說不完。

復(fù)雜度的死亡螺線

編程時常會遇到這種情況:產(chǎn)品代碼庫中的偶然復(fù)雜度漸漸壓倒必然復(fù)雜度。情況在某一時刻會自我放大,我稱這種現(xiàn)象為復(fù)雜度的死亡螺線,如圖1所示。


圖1 復(fù)雜度的死亡螺線

問題1:代碼規(guī)模

構(gòu)建產(chǎn)品時,它的代碼規(guī)模最終將遠超任何在學(xué)校或消遣項目中所遇到的。行業(yè)中的代碼庫的度量結(jié)果從成千到上百萬代碼行(Line of Code, LOC)不等。

John Lions在《Lions’ Commentary on UNIX 6th Edition》一書中寫道:單個程序員能夠理解和維護的程序大小的實際限制規(guī)模是1萬行代碼。于1975年發(fā)布的UNIX第6版的規(guī)模大約是9000行代碼(不算機器特定的設(shè)備驅(qū)動程序)。

相比而言,Windows NT在1993年有4百萬~5百萬行代碼。10年后,Windows Server 2003配備了2000名開發(fā)人員和2000名測試人員,他們管理多達5千萬行代碼。大多數(shù)行業(yè)項目并不像Windows那樣巨大,但它們也都輕易地跨過了Lions設(shè)定的1萬行代碼的警戒線。這樣的規(guī)模意味著公司內(nèi)部沒有人能理解整個代碼庫。

問題2:復(fù)雜度

隨著代碼規(guī)模的增長,最初想法的概念優(yōu)雅性消失了。曾經(jīng)對于車庫中兩個小伙水晶般清澈的想法變成了大批開發(fā)人員艱難跋涉其中的陰暗沼澤。

復(fù)雜度并不是代碼規(guī)模的必然產(chǎn)物。大型代碼庫完全有可能被拆分成許多模塊,其中每個模塊都有清晰的用途、優(yōu)雅的實現(xiàn)和為人熟知的與鄰近模塊的交互。

然而,即使設(shè)計良好的系統(tǒng)也會在它們變大時變得復(fù)雜。一旦沒有一個人可以理解整個系統(tǒng),這時多個人必須去理解系統(tǒng)中自己那部分—且沒有人的理解跟其他人是完全一樣的。

問題3:Bug

產(chǎn)品復(fù)雜度飆升,Bug也就不可避免地出現(xiàn)了。這是注定的—就算是偉大的程序員也不是完人。但每個Bug并非生而平等:高度復(fù)雜系統(tǒng)里的那些Bug尤其難覓蹤跡。總是聽到程序員說:“真搞不懂,伙計,系統(tǒng)剛剛崩潰了。”歡迎來到這糟糕的調(diào)試世界!

問題4:快速修補

問題并不在于產(chǎn)品是否有Bug—它肯定有,關(guān)鍵在于工程團隊在出現(xiàn)Bug之后如何響應(yīng)。在推出產(chǎn)品的壓力之下,大多數(shù)程序員經(jīng)常求助于快速修補。

快速修補是給問題打補丁,而非解決其根本原因。甚至常常不尋找根本原因。

程序員:在試圖往網(wǎng)絡(luò)隊列中放入一個任務(wù)(job)且隊列在10秒內(nèi)無響應(yīng)時,程序崩潰了。

經(jīng)理:重試隊列操作100次。

根本原因是什么?天知道,只要重試次數(shù)夠多,你就可以掩蓋任何問題。但如車身修補一樣,某一位置的霸道膠水(Bondo)比實際殘留的車本身部件還要多。

更難找的問題發(fā)生在補丁并沒有解決問題根本原因的時候,問題通常根本沒有消失—它只是轉(zhuǎn)移到別處。在前面的對話中,重試100次可能很好地掩蓋了問題,但萬一需要101次重試怎么辦?經(jīng)理只是隨便捏了個數(shù)字,這種膏藥式修補只會讓問題更難查。

沿著“快速修補”上行,我們現(xiàn)在得到了一個增加代碼規(guī)模的完整閉環(huán)。

走向清晰

提起復(fù)雜的反面,人們通常會想到簡單。但由于領(lǐng)域的必然復(fù)雜度,我們并不是總能寫出簡單的代碼。應(yīng)對復(fù)雜更好的方法是清晰。你是不是明白自己的代碼要做什么?

明確兩點會有助于我們減少軟件偶然復(fù)雜度:清晰思考和清晰表達。

清晰思考

在分析問題的原因時,我們試圖做出像“保存時間的方式應(yīng)該只有一種”這樣的清晰陳述。那為何UNIX C代碼里還混雜著像time_t、struct timeval和struct timespec這樣的結(jié)構(gòu)呢?那并不是太清晰。

如何調(diào)和你的清晰陳述和UNIX計時功能的復(fù)雜度?你需要隔離復(fù)雜度,或?qū)⑵涑橄蟮絾蝹€模塊中。在C里,這可能是結(jié)構(gòu)體和操作它的函數(shù);在C++里,它會是一個類。模塊化設(shè)計讓程序的其余部分可以用一種清晰的方式推導(dǎo)時間,而不用了解系統(tǒng)計時功能的內(nèi)部機制。

一旦能將時間作為程序的一個單獨模塊進行對待,你也就能證明你的計時機制的正確性。完成這一工作的最佳方式就是單獨測試,但是同行評審或書寫規(guī)格說明也行。當一組邏輯是隔離的而不是內(nèi)嵌在一大段代碼體內(nèi)時,它的測試和嚴格證明要容易得多。

清晰表達

隨著你清晰地思考模塊并將它與其余程序隔離,最終程序也就能更清晰地表達它的用途。處理問題域的代碼應(yīng)該真正專注于問題域。

將輔助代碼抽出放入自己的模塊之后,剩余邏輯讀起來應(yīng)該越來越像問題域的規(guī)格說明(雖然有更多分號)。

讓我們看看前后對比。我已經(jīng)無數(shù)次看到過如下這種C++代碼:

[cpp]?view plaincopy
  • Time.cpp??
  • void?do_stuff_with_progress1()??
  • {??
  • ????struct?timeval?start;??
  • ????struct?timeval?now;??
  • ????gettimeofday(&start,?0);??
  • ????//?干活,每半秒鐘打印一條進度消息??
  • ????while?(true)?{??
  • ????????struct?timeval?elapsed;??
  • ????????gettimeofday(&now,?0);??
  • ????????timersub(&now,?&start,?&elapsed);??
  • ????????struct?timeval?interval;??
  • ????????interval.tv_sec?=?0;??
  • ????????interval.tv_usec?=?500?*?1000;?//?500ms??
  • ????????if?(timercmp(&elapsed,?&interval,?>))?{??
  • ????????????printf("still?working?on?it...\n");??
  • ????????????start?=?now;??
  • ????????}??
  • ????????//?干活……??
  • ????}??
  • }??
  • 循環(huán)的關(guān)鍵是“干活”部分,但在實際干活之前有20行的POSIX計時代碼塊。這并沒有什么不對,但……就沒有一種方法讓循環(huán)保持對其問題域而不是對計時的關(guān)注嗎?

    讓我們把所有時間代碼放入它自己的類:

    [cpp]?view plaincopy
  • Time.cpp??
  • class?Timer??
  • {??
  • public:??
  • ????Timer(const?time_t?sec,?const?suseconds_t?usec)?{??
  • ????????_interval.tv_sec?=?sec;??
  • ????????_interval.tv_usec?=?usec;??
  • ????????gettimeofday(&_start,?0);??
  • ????}??
  • ??????
  • ????bool?triggered()?{??
  • ????????struct?timeval?now;??
  • ????????struct?timeval?elapsed;??
  • ????????gettimeofday(&now,?0);??
  • ????????timersub(&now,?&_start,?&elapsed);??
  • ????????return?timercmp(&elapsed,?&_interval,?>);??
  • ????}??
  • ??????
  • ????void?reset()?{??
  • ????????gettimeofday(&_start,?0);??
  • ????}??
  • ??
  • private:??
  • ????struct?timeval?_interval;??
  • ????struct?timeval?_start;??
  • };??
  • 我們現(xiàn)在可以簡化循環(huán)了:

    [cpp]?view plaincopy
  • Time.cpp??
  • void?do_stuff_with_progress2()??
  • {??
  • ????Timer?progress_timer(0,?500?*?1000);?//?500ms??
  • ????//?干活,每半秒鐘打印一條進度消息??
  • ????while?(true)?{??
  • ????????if?(progress_timer.triggered())?{??
  • ????????????printf("still?working?on?it...\n");??
  • ????????????progress_timer.reset();??
  • ????????}??
  • ????????//?干活……??
  • ????}??
  • }??
  • 計算機在上述兩種情況下做的事情是相同的,但考慮第二個例子對程序可維護性帶來的影響:

    • Timer類的測試和證明可獨立于它在程序中的使用方式。
    • “干活”循環(huán)內(nèi)的計時有了有意義的語義—triggered()和reset(),而不是一堆獲取、增加和比較函數(shù)。
    • 現(xiàn)在對于計時的終止位置和(捏造的)循環(huán)實際起始位置都清晰了。

    當工作在巨大丑陋的代碼上時,依次考慮:這段代碼想表達什么含義?它有沒有辦法說得更清楚一點?如果它是清晰表達的問題,你需要把那些礙事的代碼段抽象出來,同前面展示的Timer類一樣。若代碼還是有點混亂,那可能是沒有清晰思考的產(chǎn)品,需要在設(shè)計層面返工。

    行動指南

    聚焦于可被隔離和嚴格推導(dǎo)的一個編程方面,如計時。挖掘你正在從事的項目,識別出這樣的代碼段:若那部分邏輯被抽象到自己的模塊,它能否表達得更清晰。

    動手嘗試更模塊化的方法:選一組混亂的代碼,分離必然復(fù)雜度和偶然復(fù)雜度。在這一刻不要操心細節(jié),只看如何可以清晰地表達必要的業(yè)務(wù)邏輯,假設(shè)你有獨立模塊來處理支撐邏輯。

    ------------------------------------

    本文節(jié)選自《程序員修煉之道:專業(yè)程序員必知的33個技巧》“技巧4:馴服復(fù)雜度”。

    書名:《程序員修煉之道:專業(yè)程序員必知的33個技巧》

    原書名:New Programmer's Survival Manual: Navigate Your Workplace, Cube Farm, or Startup

    作者:Josh Carter

    譯者:胡鍵

    頁數(shù):212

    定價:49.00元

    ISBN:9787111411642

    豆瓣收藏:http://book.douban.com/subject/21323647/

    PDF下載:http://vdisk.weibo.com/s/paFl8

    當當購買:http://product.dangdang.com/main/product.aspx?product_id=23185207

    內(nèi)容簡介:

    這是每一位致力于成為專業(yè)程序員的軟件開發(fā)新手都應(yīng)該閱讀的一本書。它是資深軟件開發(fā)專家Josh Carter 20余年編程生涯的心得體會,從程序員成長的視角,系統(tǒng)總結(jié)和闡述了專業(yè)程序員在專業(yè)技能、編程工具、自我管理、團隊協(xié)作、工作態(tài)度以及需要采取的行動等方面應(yīng)該掌握的33個非常重要且實用的技巧。作者以自己以及身邊的同事積累下來的經(jīng)驗、犯過的錯誤為素材,旨在為新人們引路,讓他們在能力修煉的過程中少走彎路!

    全書分為四個部分:第一部分(技巧1~14),從編程技能和工具使用兩個方面總結(jié)了14個技巧,包含如何正確地書寫代碼、測試驅(qū)動設(shè)計、管理代碼復(fù)雜度、改善遺留代碼、代碼評審、開發(fā)環(huán)境優(yōu)化、自動化等;第二部分(技巧15~24),從自我管理和團隊協(xié)作兩個方面總結(jié)了10個技巧,包括如何樹立自我形象、壓力管理、建立良好人脈和高效會議等;第三部分(技巧25~30),介紹了典型高科技公司的組織結(jié)構(gòu)以及你在整個公司中的位置,并且闡述了薪酬分配的問題;第四部分(技巧31~33),介紹了在日常工作中如何持續(xù)改善自己的工作和學(xué)習(xí)狀態(tài)。

    作者簡介:

    Josh Carter,資深軟件設(shè)計師,具有超過20年編程行業(yè)從業(yè)經(jīng)驗。熱衷于編程和追逐前沿技術(shù),但同時謹記史蒂夫?喬布斯的箴言“真正的藝術(shù)家能讓產(chǎn)品面市”。他還涉足工程管理領(lǐng)域,曾經(jīng)主管大型企業(yè)軟件開發(fā)團隊。目前已出版多本關(guān)于計算機軟件的技術(shù)書籍,同時他還在主流計算機雜志的技術(shù)專欄發(fā)表文章。

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

    總結(jié)

    以上是生活随笔為你收集整理的专业程序员必知必会的技巧:驯服复杂代码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。