開(kāi)發(fā)中的新理解——成長(cháng)在2013
今年在公司里,收獲很多。從很多方面,都一個(gè)新的認識。因為參與公司的幾個(gè)項目。有的是維護原有代碼,有的是從需求開(kāi)始,從0做起,有的做了一半,因為調整不做了,有的剛開(kāi)了個(gè)頭,因為其他項目需要暫停了。每一個(gè)項目,做的程度都不一樣。但是每一個(gè)項目,都讓自己對于完成一個(gè)項目,有了更深的認識。也慢慢在改變自己以前那種學(xué)校式的研發(fā)狀態(tài)。由一開(kāi)始想從每一個(gè)項目中學(xué)習新技術(shù),到想辦法確保每一個(gè)項目都能按照預期按時(shí)結束,做出能夠交付的穩定產(chǎn)品。而這本身也是一種學(xué)習。
/* ---------------------------------------------------------------------------*/
年初,公司接到一個(gè)項目,給客戶(hù)提供一套軟硬件系統。其中自己負責的部分,需要對一年半前的代碼進(jìn)行維護,修復其中的Bug。對于這份代碼由于是一年半前由兩個(gè)人寫(xiě)就。當維護的時(shí)候,第一件事就是怎樣讀懂代碼,找到能入手的地方。當開(kāi)始研讀代碼的時(shí)候,發(fā)現全局變量定義實(shí)在是多。一個(gè).c文件中,多的時(shí)候就會(huì )有二十幾個(gè)。而代碼之間的耦合,造成全局變量的定義和使用可能在幾個(gè).c文件中。函數間的參數傳遞,有些就是直接用全局變量實(shí)現的。代碼過(guò)長(cháng)的函數,就有好幾個(gè),有的函數一個(gè)switch就會(huì )有200行以上。當時(shí),讀到這些代碼的時(shí)候,第一反應是一定要把這些當時(shí)認為不好的代碼全部修改了。確實(shí)一開(kāi)始也這樣做了,以為只要費些時(shí)間就會(huì )弄完,然后,有了一個(gè)熟悉的代碼理解也會(huì )更快。
但是一段時(shí)間后發(fā)現要改的地方真是很多,而且測試起來(lái)也很難辦。因為是嵌入式上的程序,很多地方都要手動(dòng)去一個(gè)個(gè)測試(當時(shí)如果知道了《重構》的經(jīng)驗與教訓或許不會(huì )那么大刀闊斧的來(lái))。測試的過(guò)程十分麻煩,而且會(huì )造成有些地方測試不到。由于源代碼底層代碼與應用層代碼耦合比較厲害,如果有改動(dòng),底層的不穩定會(huì )導致整個(gè)系統的不穩定。而這個(gè)在最后發(fā)現了。由于中途臨時(shí)需要交付一個(gè)Release版本,有些地方改了還沒(méi)有測試,只好將沒(méi)有測試的地方恢復。這樣代碼中就出現了改了一半的代碼。由于自己在修改的過(guò)程中,也沒(méi)有遵循原有代碼的代碼風(fēng)格(由于原有代碼tab鍵與空格混用,看不出風(fēng)格,變量名也比較隨意)。也有些地方遵循自己的編程習慣,修改了代碼中存在遞歸的代碼。
最后發(fā)現,程序并沒(méi)有比原來(lái)更好理解,耦合性還是很高。在后期考慮到硬件有一個(gè)元件已經(jīng)停產(chǎn),所以建議更換新的模塊。更換后,由于對于新的模塊不是十分熟悉,導致出現了比較嚴重的問(wèn)題。這個(gè)事后自己反思的時(shí)候,認為當時(shí)提的一個(gè)很錯誤的建議。在項目的后期,已經(jīng)沒(méi)有多少時(shí)間去測試穩定性了,而此時(shí)卻將以前穩定的元件替換掉,而換新的元件,測試時(shí)間又沒(méi)有那么多。直接導致了不穩定的存在。事后,也確實(shí)因為這個(gè)元件,導致了第一批出貨出現了返修。為此,連續三個(gè)周末在公司解Bug。
整體的維護中,雖然改善了原有代碼的的Bug,但是卻也引入了新的Bug。在這個(gè)過(guò)程中,前期也是自己對于代碼維護的理解有偏差。如果說(shuō)重構,也要是用到的地方進(jìn)行重構,而不是對于很多地方重構。更不應該在項目后期,進(jìn)行元件的替換。如果說(shuō)維護是為了保證產(chǎn)品的穩定性,那么就要在最小的范圍內做修改。盡量避免修改不需要修改的代碼。但是,這里邊涉及一個(gè)問(wèn)題,怎么判定那些是需要修改,那些事不需要修改的?有些容易判斷,但是有些就十分模糊。
這里還有一點(diǎn),如果說(shuō)盡可能減少修改的地方,那么對于維護者而言是否會(huì )接受這樣的概念?對于一個(gè)初做的人,總會(huì )想多做一些。是得過(guò)且過(guò),還是精益求精?這個(gè)或許《重構》最后的一個(gè)建議很好“使重構成功的不是前面各種技術(shù),而是這種節奏”,懂得重構是在于“可以自信地停止重構”。但是這種節奏的獲得需要有大量的實(shí)踐才會(huì )獲得,這種自信也需要從實(shí)踐中一點(diǎn)點(diǎn)獲取。在此次維護結束后,想要找到自己在維護的過(guò)程中犯下的錯,以期以后不會(huì )在同一個(gè)坑中栽倒第二次。如何在以后的類(lèi)似工作中做地更好,在反思了一些以及看了一些書(shū)后。認為維護過(guò)程中有幾點(diǎn)是嚴重犯錯的地方:
沒(méi)有做到對于不必要的地方不修改;
缺少質(zhì)量管理的觀(guān)念。
經(jīng)過(guò)這次維護的經(jīng)歷,得出了以下幾點(diǎn):
確定code style,編寫(xiě)易讀性代碼,代碼可讀才會(huì )使維護更容易;
使用lint工具檢查代碼;
積累重構;
注意C的安全性與非安全性;
建立代碼質(zhì)量的觀(guān)念,建立產(chǎn)品質(zhì)量的觀(guān)念;
/* ---------------------------------------------------------------------------*/
年中,接到另一個(gè)項目。和前一個(gè)項目完全不一樣,這個(gè)是要從零開(kāi)發(fā)。自己負責軟件中的一部分。初期由自己做設計初步的通信協(xié)議,以及通信機制。在開(kāi)發(fā)過(guò)程中,發(fā)現由于客戶(hù)不了解元件的特性,推薦的元件型號不滿(mǎn)足客戶(hù)自己的要求。于是,進(jìn)行了元件更換。在新的元件上,很容易做到客戶(hù)要求的指標。這些完成后,要給客戶(hù)提供一批樣品進(jìn)行測試。這個(gè)過(guò)程中發(fā)生了一些意外。試產(chǎn)的第一批在使用測試程序后,發(fā)現有一半測試不合格。經(jīng)過(guò)測試分析,發(fā)現硬件的模擬部分不同PCBA之間存在差異,原有程序的初始值在差異較多的時(shí)候會(huì )出現異常。于是將程序的初始值,修改后重新測試發(fā)現大部分輸出都正常了。
在后來(lái)生產(chǎn)的過(guò)程中,發(fā)現由于實(shí)際要裝配的東西很多,裝配的過(guò)程很多,而選擇的外殼內部空間較小,造成內部空間很緊張,給裝配人員實(shí)際造作中帶來(lái)很**煩。直接的影響就是裝配的效率偏低。在催促他們提高裝配速度的時(shí)候,也確實(shí)很難提高速度。測試的項目很多,需要時(shí)間。外殼的尺寸和元器件之間內部空間的限制,以及外殼螺絲都成了影響的一個(gè)因素(采購的外殼,有些螺絲因為攻絲有問(wèn)題,導致螺絲裝卸較困難)。元件多,要裝的步驟會(huì )相應多一些。
在這個(gè)過(guò)程中,反思為什么會(huì )出現這樣的問(wèn)題。
首先,軟件上的設計一開(kāi)始沒(méi)有深入了解具體的硬件情況,導致軟件上的參數設置和硬件的偏差配合不上很好。對于具體要應用的場(chǎng)合了解還欠缺深入。在提供給測試部的程序將測試程序與正式程序分開(kāi),導致測試人員在測試完成后還要重新燒錄正式程序。如果當時(shí),自己在設計程序的時(shí)候,將測試流程包含在正式程序中,通過(guò)特殊條件觸發(fā),能減少測試人員的測試時(shí)間,提高他們的速度。同樣,在需要的一些測試環(huán)節,或許還有可以提高的地方。
其次,選擇的外殼和連接線(xiàn),PCBA之間配合不好。這方面如果考慮多一些,裝配人員就能省下來(lái)很多時(shí)間,提高裝配效率。也不會(huì )抱怨產(chǎn)品那么難裝配。更降低了裝配的主動(dòng)性。
在這個(gè)過(guò)程中,深深感受到保證每一環(huán)正確的重要性,即使有一步缺失都會(huì )造成最后產(chǎn)品生產(chǎn)的進(jìn)度與性能。
/* ---------------------------------------------------------------------------*/
后來(lái)又根據需要接手了兩個(gè),由于預期的調整,每一個(gè)都做了有一個(gè)月左右停下。
/* ---------------------------------------------------------------------------*/
在這個(gè)過(guò)程中,慢慢明白了,在一個(gè)團隊中、在開(kāi)發(fā)產(chǎn)品的工程中最重要的不是技術(shù)問(wèn)題,因為對于一個(gè)開(kāi)發(fā)者而言技術(shù)通常不是問(wèn)題。技術(shù)可以一點(diǎn)點(diǎn)習得,技術(shù)可以google,可以研究,可以向別人請教。而一個(gè)開(kāi)發(fā)者通常欠缺的是——建立項目的概念,進(jìn)行有效溝通。項目進(jìn)行過(guò)程中,每一步都是由有效的溝通驅動(dòng)。了解需求,團隊合作,協(xié)同開(kāi)發(fā),測試反饋,生產(chǎn)反饋……。如果這些過(guò)程中,有地方?jīng)]有明確理解對方表達的意義,或者沒(méi)有明確表達自己的意思,都會(huì )造成整個(gè)項目開(kāi)發(fā)上的delay。沒(méi)有正確了解需求,開(kāi)發(fā)出來(lái)的將是一堆無(wú)用的代碼;沒(méi)有團隊間的有效溝通,開(kāi)發(fā)中成員間將會(huì )互相掣肘;沒(méi)有有效的測試反饋,開(kāi)發(fā)出來(lái)的將是質(zhì)量無(wú)法保證的程序;沒(méi)有生產(chǎn)部門(mén)的有效反饋,開(kāi)發(fā)出的有可能是不利于生產(chǎn)的產(chǎn)品。同時(shí)建立一個(gè)項目管理的概念,也是十分必需。如果將項目廣義化,我們工作中接到的每一個(gè)任務(wù),對于我們自己而言都是一個(gè)項目,我們開(kāi)發(fā)結果的使用放就是我們的客戶(hù),而我們自身就要做好對于這個(gè)任務(wù)的管理。保證給我們的“客戶(hù)”是高質(zhì)量的產(chǎn)品,只有每一個(gè)環(huán)節都有高質(zhì)量的產(chǎn)出,才會(huì )做出最后高質(zhì)量的產(chǎn)品(產(chǎn)品質(zhì)量符合木桶理論,注1)。由此而言,作為一個(gè)開(kāi)發(fā)者,要關(guān)心的不僅僅是技術(shù),也要關(guān)心于有效溝通,建立項目管理的觀(guān)念,將它們用于平時(shí)的工作。技術(shù)可以保證我們出色完成當前分配好的工作,但是并不能保證我們提供一個(gè)高質(zhì)量的產(chǎn)出,更不能保證項目的順利完成。所以,技術(shù)很重要,但它不是全部。
/* ---------------------------------------------------------------------------*/
整體而言,這一年在公司經(jīng)歷了很多。從技術(shù),到其他感受也很深,收獲也很大。
從一開(kāi)始想要探究代碼,到現在對代碼三思而后行;
從一開(kāi)始想要鉆研,到現在工作上enough is good;
從一開(kāi)始不知何為代碼安全,到現在編程時(shí)刻將代碼安全放在心頭;
從一開(kāi)始不知如何修改代碼,到現在試著(zhù)找找重構的節奏;
從一開(kāi)始只知開(kāi)發(fā),到現在從測試、生產(chǎn)、使用的角度考慮設計;
從一開(kāi)始把代碼管理當做備份,到現在建立branches,打tags,查看版本graphic;
從一開(kāi)始不會(huì )lint,到現在用lint工具檢查C代碼;
從一開(kāi)始對項目一知半解,到現在慢慢建立項目管理的概念,指導平時(shí)的工作;
……
這些的這些,記錄了一年的酸甜苦辣,記錄了一年的變化。走過(guò),“回首向來(lái)蕭瑟處,也無(wú)風(fēng)雨也無(wú)晴”,留下的是——成長(cháng)。
/* ---------------------------------------------------------------------------*/
注:
關(guān)于合作。
……
關(guān)于《重構》
從實(shí)踐理解設計