1、問題背景
一切為了進度,軟件開發(fā)的首要目標就是以最快的速度滿足客戶需求,“快”是第一要素,但是短期指標;可復用性、擴展性等長期指標被忽略,導致后期的維護、功能增減調整都非常困難。一個小的業(yè)務需求會牽一發(fā)而動全身,一個小的故障修復可能引入更多的問題。整個系統(tǒng)包袱越來越沉重,軟件的質量和開發(fā)周期越來越不可控。
排除軟件開發(fā)人員的水平和項目進度的原因,主要影響因素還包括軟件架構,和軟件缺陷的修復能力。對于量產軟件,架構問題是先天性的,后期很難大改,只能前期預防;軟件缺陷問題是無法避免的,只能期望快速修復。拋磚引玉,也可先參看《嵌入式軟件bug從哪來,怎么去》。
2、軟件架構問題
2.1 軟件架構的特點
1. 承載力
正如一艘船最多能裝多少人,從軟件方面來說是軟件架構能承載多少業(yè)務或功能需求,當然,這需要架構師一開始架構系統(tǒng)的時候,就需要有一定的預見性。但也沒必要為了極小概率事件增加過多的冗余。
2. 易用性
易用性決定了軟件的整體開發(fā)效率,好的架構會讓團隊成員容易上手,子系統(tǒng)容易對接,開發(fā)效率高,各模塊和子系統(tǒng)的編寫只需要關注系統(tǒng)的設計和編碼工作,其他模塊間通信方面的事情架構可以提供很好的兼容。
3. 擴展性
一個水杯除了用來喝水,也可用來喝酒,適應不同場景,在一定范圍內滿足不同的需求,是非常有必要的。軟件架構也是這樣,要新增更多的功能就要具備更高的擴展性??蓴U展性的關鍵就在于新增部分不能影響其他,如果增刪導致系統(tǒng)整體使用異常,那么這個架構的可擴展性就很差。
4. 伸縮性
伸縮性就是設計的方案或系統(tǒng)是否可以根據(jù)需求適配不同數(shù)量的功能或子系統(tǒng),在我們設計的軟件系統(tǒng)中,架構的可伸縮性決定了架構的可適配性,例如,當硬件資源不足時,可以調整配置如flash的空間分配,支持減少一些服務但仍能正常運行。
5. 容錯性
軟件運行中的異常,如用戶的非法操作,或者軟件本身的小缺陷導致整個系統(tǒng)無法使用,那這個架構容錯性就很差。軟件中的一些缺陷無法避免,但是我們應盡量保證這個缺陷的影響范圍最小。倘若出現(xiàn)系統(tǒng)無法使用的情況,應該有備份方案,比如自動重啟或者自動恢復數(shù)據(jù)等功能,也應該能夠讓開發(fā)人員及時知道問題的發(fā)生,以及問題所在的位置并記錄錯誤信息。
在架構設計中,以上五項基本能力缺一不可,某項能力的突出并不能帶動其他項,如果某一項能力比較弱,隨著時間的推移,問題會越來越大,甚至系統(tǒng)崩潰。就像木桶原理那樣,一個木桶的容量不是取決于最長的那根木板,而是取決于最短的那根。
2.2 如何規(guī)劃軟件架構
2.2.1 必須熟悉業(yè)務
軟件是為業(yè)務服務的,業(yè)務才是“目的”,軟件系統(tǒng)是為了達成業(yè)務系統(tǒng)目標的手段和方法。適應當前的業(yè)務需求是基礎,充分考慮和預測未來的業(yè)務擴展,根據(jù)業(yè)務的擴展性來設計軟件的擴展性。如果可預見未來沒有擴展重大新業(yè)務的需求,那么相應的軟件架構就沒有必要采用高擴展的軟件架構。比如嵌入式的傳感器數(shù)據(jù)采集小設備,就沒有必要把云計算等,業(yè)務范圍不沾邊的技術點放到其中。軟件架構必須以服務業(yè)務為核心思想,不熟悉當前軟件業(yè)務、和未來業(yè)務的擴展的架構師是很難設計出好的軟件架構。
2.2.1 借鑒業(yè)內成熟的架構
不照搬,并不意味著不要借鑒。借鑒業(yè)內成熟的軟、硬件架構是相對穩(wěn)妥、高效的做法。以業(yè)內的架構為基礎,根據(jù)自身業(yè)務的特點,進行適配、裁剪和增加新的功能。熟悉業(yè)內常規(guī)的、成熟的、最新的軟件架構是架構師的一項基本功。但熟悉并不是意味著必須立即在目標系統(tǒng)中實施這些軟件架構。
2.2.3 采用設計模塊
設計模式(Design pattern)代表了最佳實踐,設計模式是軟件開發(fā)人員在開發(fā)過程中對一般問題的解決方案;是一套被反復使用的、多數(shù)人知曉的代碼設計經驗的總結,經過相當長的一段時間的試驗和錯誤總結出來的。
使用設計模式是為了重用代碼、讓代碼更容易被他人理解、保證代碼可靠性,合理地運用設計模式可以完美地解決很多問題。每種模式在現(xiàn)實中都有相應的原理來與之對應,每種模式都描述了一個在我們周圍不斷重復發(fā)生的問題,以及該問題的核心解決方案,這也是設計模式能被廣泛應用的原因。
用設計模式構建一個新的軟件模塊時,短期會讓人感覺有多此一舉的味道;但中長期來看,設計模式能夠克服“壞”架構的特征。學習這些模式有助于經驗不足的開發(fā)人員通過一種簡單快捷的方式來學習軟件設計。盡管設計模塊通常被有經驗的面向對象的軟件開發(fā)人員所采用,但是嵌入式軟件C語言也可以借鑒,參考《嵌入式軟件的設計模式(上)》,《嵌入式軟件的設計模式(下)》。
2.2.4 合理的橫向和縱向切分
橫向切分 :從硬件、驅動、組件到業(yè)務層,軟件分層隔離。如數(shù)據(jù)通信:PHY/MAC/IP/TCP/應用層
縱向切分 :根據(jù)業(yè)務處理流程的環(huán)節(jié)縱向切分,不同的環(huán)節(jié)為不同的模塊,不同的業(yè)務功能為不同的模塊,如socket網絡、GNSS衛(wèi)星定位。
2.2.5 按樹形結構組織
按照樹形結構的方式組織軟件系統(tǒng),不同的大功能拆分為小功能,文件夾內套文件夾的實現(xiàn)形式,命名上統(tǒng)一,方便按功能快速找到對應的源碼。
2.2.6 降低模塊之間的耦合度
耦合性是一種軟件度量,是指一程序中模塊及模塊之間信息或參數(shù)依賴的程度;內聚性是一個和耦合性相對的概念,一般而言低耦合性代表高內聚性,反之亦然。
2.2.7 降低模塊與模塊之間通信
一個軟件內模塊與模塊之間的通信,構成了一個內部的通信網,避免內部模塊的通信采用網狀結構,這種解決方案是設計模式中的中介者模式。
2.3 重構和演進架構
架構不能一成不變,要隨著業(yè)務需求的演進而升級重構,一成不變的架構是危險的,總有一天架構成為業(yè)務演進的最嚴重的制約因素。
這種需要實際開發(fā)中除完成既定的項目外,預留部分人力進行架構升級維護,持續(xù)小改動,不定期根據(jù)業(yè)務的需求進行架構的重構,未雨綢繆。
3、軟件問題的分析與解決
嵌入式軟件由于調試手段的限制、部署場景的多樣化、軟硬件問題混合在一起、外部環(huán)境因素的影響等因素,導致軟件經常會遇到一些非常難以解決的問題。
3.1 解題思想
熟悉軟件的業(yè)務流程:從業(yè)務的角度發(fā)現(xiàn)問題、復現(xiàn)問題并解決問題。
熟悉軟件的總體架構:軟件架構是解決難題問題的基本框架,基于軟件架構解決問題不會陷入到局部細節(jié),導致修復一個問題的同時產生新的問題,不會犯原則性、方向性錯誤。
熟悉軟件代碼的實現(xiàn):熟悉代碼的細節(jié),能夠更好、更快的在蛛絲馬跡中找到證據(jù)和突破點,甚至在問題還沒有收斂前,提供一種收斂的方向,引領問題的解決,對代碼的熟悉程度直接關系到解決問題的速度。
3.2 調試手段和信息不足相關問題
3.2.1 現(xiàn)場偶發(fā)性、難復現(xiàn)性引發(fā)的問題
一些偶發(fā)性現(xiàn)象級問題,甚至導致系統(tǒng)偶發(fā)性的重啟,無法復現(xiàn),設備重啟之后,故障消失后,再也很難復現(xiàn)。
1、分析日志文件
從log中尋找異常提示,是應對不可重復性、偶發(fā)性故障最基本的手段。在系統(tǒng)某處發(fā)生異常時,一定會在log中留下蛛絲馬跡,可以請客戶協(xié)助提供串口日志,在log文件中查找問題?;蛘咴O備自己內部記錄log,但嵌入式設備由于存儲空間的限制,可能先前過于久遠的信息,就會被新的信息被覆蓋,針對這種情況,就需要定期清除無效日志。有些異常會導致系統(tǒng)重啟,而重啟之后,就會導致異常信息被正常重啟的信息覆蓋,這就需要系統(tǒng)能夠支持log的備份。不管怎么樣,log為定位現(xiàn)場問題提供了最基本的、最主要的信息來源。一個完善的log機制,對于定位現(xiàn)場問題非常有幫助。如果不滿足,可能首要任務是先完善日志功能。
2、回退軟件版本,緊急消除現(xiàn)場問題
有些現(xiàn)場問題,雖然偶發(fā)事件,但發(fā)生后影響嚴重,客戶無法接受。針對這種情況,在解決問題之前,可以先把軟件降級,降級到相對穩(wěn)定,沒有嚴重故障的版本。
3、比較相鄰版本之間的代碼改動
如果不容易復現(xiàn)的故障,確認在升級了某個軟件版本之后才出現(xiàn)的,而其他現(xiàn)場條件都沒有變化,且分析log也無法發(fā)現(xiàn)異常點。此時,一種高效的解決此問題的方法,就是比較兩個版本之間的代碼的改動。
代碼改動比較少,分析代碼比較容易;如果代碼改動比較多,就需要根據(jù)用戶描述的現(xiàn)象,結合前后代碼的改動模塊,初步分析最可能是哪個模塊引起的,這種往往需要對系統(tǒng)架構較深刻的理解。在眾多修改模塊中,分析最有可能關聯(lián)的代碼模塊的改動,然后逐一排查 。分析代碼的改動與出現(xiàn)的現(xiàn)象之間可能的關聯(lián)關系,對開發(fā)人員個人的技術素養(yǎng)和方法論有較高的要求 。比較相鄰版本之間的代碼改動,針對某些棘手的現(xiàn)場問題,有時候確實是一個非常有效的手段。
4、問題復現(xiàn)
雖然常規(guī)來說現(xiàn)場很難復現(xiàn),但可以人為的修改軟件、構建或增加模擬數(shù)據(jù),人為創(chuàng)造或觸發(fā)條件,增加故障復現(xiàn)的幾率。在設計觸發(fā)條件時,需要圍繞用戶描述的現(xiàn)場故障現(xiàn)象來設計觸發(fā)條件,觀察是否能否復現(xiàn),且表現(xiàn)一致。
5、分析代碼
根據(jù)用戶描述的現(xiàn)象,硬分析代碼,是一種通用的方法,放之四海皆準的方法,熟悉自身代碼的邏輯關系是基本功,但解決問題的效率就比較難把握了。
6、增加 log 更新版本繼續(xù)測
如果常規(guī)的log無法展現(xiàn)故障的異常,就需要在猜測有可能的部分增加日志,在現(xiàn)場復測。但這種日志添加的位置是否合理,決定了問題再次出現(xiàn)時是否能定位問題的準確性。這種方法在工程實踐中,實施難度大,需要客戶多次配合。
3.2.2 現(xiàn)象與真正的原因不在一起的問題
大多時候解決軟件故障,是可以做到頭痛醫(yī)頭,腳痛醫(yī)腳。有些時候,頭痛的原因并不在“頭”,而在“腳”。這就需要知道“頭痛” 與 “腳” 的某種關聯(lián)關系。
解決這樣的問題,對技術人員的綜合技能的要求非常高,因為這個問題,不再是局部問題,而是發(fā)散到調查該問題的技術人員不熟悉的其他的軟件組件領域。即使對于熟悉整個系統(tǒng)的人而言,也是一個難點,因為問題的現(xiàn)象與根源之間的路徑是發(fā)散的,沒有一個確切的路徑。
首先,必須以故障的表面現(xiàn)象作為錨點,作為出發(fā)點。為后續(xù)進一步的調查立一個基點。根據(jù)現(xiàn)象找到出問題的代碼,根據(jù)代碼和log分析代碼的表面原因。如果確實是本處代碼的問題,直接在此解決即可。即頭痛醫(yī)頭,腳痛醫(yī)腳。
很多情形下,真正的原因不在顯示異常的地方,比如收到了異常的事件、或參數(shù)不合理、或自身狀態(tài)機的問題等。這時候就需要追溯,為什么會有這樣的事件或消息?有時候,由于復雜系統(tǒng)的程序員沒有系統(tǒng)的視角,常以為消除了故障表面現(xiàn)象就是解決了問題。很多時候站在系統(tǒng)的視角,可以從多個層面加以解決,消除異常事情,可以從規(guī)則過濾模塊解決,也可從前置模塊或后續(xù)模塊解決。具體在哪兒解決最合理,這就需要有系統(tǒng)和結構的視角。當然,也曾遇到有人解決類似問題是屏蔽異常消息或者屏蔽ASSERT,并沒從根源去消除為什么產生了異常。
3.2.3 報錯點發(fā)生在第三方庫內部
軟件報錯的地方是在第三方庫,而第三方庫有沒有源代碼或不熟悉
如果集成的第三方庫沒有源代碼,則把這個問題上報給第三方,讓第三方給出內部出錯的原因,更新庫或者配合抓日志分析。如果第三方庫有源代碼的話,可分析第三方代碼,增加日志或檢查傳入第三方庫函數(shù)的參數(shù)是否正確,是否合法;大多數(shù)時候,是錯誤地傳入了不合適的參數(shù)給第三方庫。檢查使用第三方的時序是否正確,在軟件系統(tǒng)中,時序是一個非常重要,同樣的函數(shù),同樣的代碼,如果時序不對,也會導致代碼邏輯紊亂。不過現(xiàn)在提供庫或者SDK,一般都有技術支持,也可直接尋求幫助。
3.2.4 軟硬件結合導致的無法定位的問題
在嵌入式系統(tǒng)中,有時候會出現(xiàn)硬件異常導致軟件狀態(tài)或邏輯錯誤,硬件人員很難根據(jù)有限的信息判斷硬件到底怎么了,通常軟件和硬件就會反復的踢皮球。但是用戶角度看到的異常是在軟件這邊。
由于硬件團隊對客戶現(xiàn)場的設備,通常沒有檢測手段來判斷是否真是硬件問題的,軟件團隊最好能夠通過日志配置,確認硬件故障單元?;蛘咧苯訉臋C寄回硬件部門,軟件配合復現(xiàn)問題,以幫助硬件團隊判斷。
硬件故障問題,需要特別關注供電、時鐘信號,復位時間等,曾經遇到幾次因為串口漏電出去導致外部傳感器復位異常的問題??傊?,軟硬件的交合處,是容易扯皮的地方,這需要軟件人員也同時了解硬件的工作原理,在出故障時,能夠更好的判斷是軟件異常,還是硬件真的有故障。
還有一個商業(yè)上的問題,如果客戶感受到是硬件的問題,需要回收設備,會造成很大的經濟損失。一般情況下是軟件想辦法規(guī)避異常,畢竟軟件復制不需要成本。
3.3 內存與指針相關問題
3.3.1 隱性的內存泄露問題
內存泄漏(Memory Leak)是指程序中已動態(tài)分配的堆內存由于某種原因程序未釋放或無法釋放,造成系統(tǒng)內存的浪費,導致程序運行速度減慢甚至系統(tǒng)崩潰等嚴重后果。內存泄露是一個嚴重的慢性病,不會立即展現(xiàn),但不知道未來的哪一天,所有的設備,會在相近的時間點爆發(fā)問題。
內存泄漏還會導致系統(tǒng)意外的重啟,重啟的原因可能千奇百怪。因此,檢測和解決內存泄漏,就顯得非常重要。
1. 泄漏的原因
內存泄漏主要是發(fā)生在堆內存分配方式中,即malloc方式中,申請的內存沒有得到釋放,或者對應的指針被被覆蓋,內存直接泄漏。因為內存泄漏屬于程序運行中的問題,無法通過編譯識別,主要在程序運行過程中來判別和診斷。
2. 動態(tài)檢測或監(jiān)控是否內存泄露
監(jiān)控系統(tǒng)內存,周期性監(jiān)控堆中可用內存的大小,是檢測系統(tǒng)是否有內存泄漏的最有效的手段。系統(tǒng)的內存短期會隨著業(yè)務數(shù)據(jù)的變化而變化,但長期來看,可用的剩余可用內存會圍繞一個中軸線上下波動,如果存在內存泄漏,其剩余可用內存隨隨著時間的推移逐漸減少。
3. 如何找到在哪兒內存泄露
可以使用工具檢測代碼中有沒有靜態(tài)的內存泄露,也可以在代碼中增加標記,檢測長期未釋放的堆是誰申請的,在代碼中查找??梢詤⒖嘉恼隆?strong>動態(tài)內存管理及防御性編程》。
3.3.2 指針跑飛的問題
指針跑飛就是指針指向不正確的位置,指針未初始化或數(shù)組/指針越界訪問,導致系統(tǒng)崩潰。
指針跑飛是常見的問題,問題很嚴重,但解決起來其實并不難,指針跑飛系統(tǒng)crash時,如果平臺軟件會打印出函數(shù)調用棧、segment fault錯誤、代碼出錯的地方、coredump文件等信息。有了這些信息,再分析源代碼,其實是很容發(fā)現(xiàn)或找出當前代碼中指針跑飛的原因的。
如果基于第三方的SDK開發(fā),指針跑飛直接就重啟,可能不會有任何提示,因此,最好能夠在編碼時就能夠提前預防,而不是等待程序跑飛之后再定位解決?。常見的手段:
1、熟悉和遵守代碼編寫規(guī)范,加強代碼的評審,把問題消滅在編碼階段。
2、靜態(tài)檢測工具對代碼進行檢測。
3、增加邊界性測試用例,一般指針異常是在邊界或異常情形下發(fā)生的。
4、增加異常場景的測試,異常場景是違反常規(guī)的測試場景,這些異常業(yè)務場景,能夠盡早shi發(fā)現(xiàn)隱藏的問題。
3.3.3 空指針的問題
空指針是“指針跑飛”的一種特殊情況,即指針為NULL,通常出現(xiàn)在指針用NULL值初始化后,在某些情況下沒有給指針賦值,就直接使用指針范圍內存。或者接收函數(shù)返回的指針變量,忽略了函數(shù)返回NULL的情形。
在使用指針前,檢查指針是否為空,如果為空,在代碼中執(zhí)行異常處理流程,如打印出錯信息,或者ASSERT,這樣就可以避免引起更嚴重的問題,相對來說多使用一個if即可規(guī)避。
3.3.4 棧溢出導致的問題
棧溢出時會訪問不存在的RAM空間,造成代碼跑飛,這時無法得到溢出時的上下文數(shù)據(jù),也無法對后續(xù)的程序修改提供有用信息。
函數(shù)遞歸調用,系統(tǒng)要在棧中不斷保存函數(shù)調用時的現(xiàn)場和產生的變量,如果遞歸調用太深,就會造成棧溢出。函數(shù)內局部數(shù)組變量的內存空間過大,或者局部數(shù)組變量的下標范圍溢出,破壞了??臻g中的內容。這種問題容易解決但初始不容易查到原因。如果是帶操作系統(tǒng)的,一般系統(tǒng)內核會直接提示棧空間不足,將任務棧空間加大,或者不靜態(tài)分配,用malloc動態(tài)創(chuàng)建,從堆中分配的。平時編碼中禁止使用循環(huán)遞歸函數(shù)。
3.4 軟件時序設計相關的問題
時序問題是最容易出問題的地方,“時”代表時間順序和時效性,一旦執(zhí)行順序錯亂,或執(zhí)行過慢失去時效,就會導致錯誤。
3.4.1 消息的串行化處理
每個任務、線程,只能按順序的處理串行的消息,然而,其他線程發(fā)送過來的消息并不是串行發(fā)送的,不同線程都是并行、異步發(fā)送消息的,這會導致線程在沒有處理完一個消息,另一個消息又回來了。如何把外部的并發(fā)消息轉換成線程的串行處理呢?
每個任務、線程都應有一個消息隊列,外部線程向消息隊列中發(fā)送數(shù)據(jù),目標線程從消息隊列中讀取消息,這樣所有的消息被串行在消息隊列中,線程就會串行的處理每個消息,只有當一個消息處理完(函數(shù)調用返回)時,才會處理另一個消息。參考《嵌入式軟件的設計模式(上)》中的 第3.3節(jié)?“隊列模式”。
3.4.2 超時或消息丟失引發(fā)的問題
一個任務、線程給另一個任務、線程發(fā)送消息,等待對方的應答,有時候對方忙,發(fā)送時隊列滿發(fā)送失敗,或者接收方沒有處理回復,等待一段時間后空閑了才處理該消息并應答時,但對于發(fā)送方已經超時。發(fā)送方超時,就需要進入異常處理。這里容易出問題,它可能會引發(fā)一連串的異常處理反應,也有可能影響后續(xù)的正常消息的處理。
消息丟失是必須考慮情況,發(fā)送方不能假設接收方一定能夠收到消息,也不能假設接收方一定能夠及時的回應,必須充分考慮到消息因為傳輸?shù)膯栴}丟失或對方忙,沒有及時回應的情形。
消息丟失就容易產生理論上該執(zhí)行的動作沒有執(zhí)行,或者消息里面動態(tài)內存未釋放?;蛘呦⑻幚砺龑е聦ν庠O的控制延遲產生異常,曾經出現(xiàn)共享單車鎖里面的馬達停止消息處理不及時導致車鎖無法再次上鎖。尤其處理通信時序要求嚴格,或外設控制要及時的場景需要注意。
3.4.3 性能本身問題
數(shù)據(jù)處理尤其是復雜算法耗時,導致消息處理不及時,最終對外設的控制或者通信交互時序狀態(tài)延遲,產生異常。這種只能優(yōu)化算法,或對時序部分單獨特殊處理,不考慮設計模式保執(zhí)行效率?;蛘咴u估階段就選擇性能資源更佳的硬件方案。
3.5 異常處理不充分問題
軟件設計一般是考慮正常流程,然而實際運行中,并非是理想狀態(tài),系統(tǒng)總會遇到各種異常,健壯的系統(tǒng),能夠充分考慮到各種異常情況,一旦異常發(fā)生,程序也不會輕易崩潰。
超時:增加超時定時器事件以及事件處理,不能假設對方一定應答消息。
空指針:不能假設一定能夠申請到內存,要考慮到返回為NULL的情形,通過指針訪問內存對象時需要及時的檢查指針是否為空。
并發(fā)訪問:在并發(fā)執(zhí)行的系統(tǒng)中,如果要訪問全局變量,不能假設只有一個線程訪問全局變量,需要通過鎖對全局共享資源進行加鎖,特別是要訪問全局的數(shù)據(jù)結構。
消息隊列:不能假設消息隊列始終有效,要考慮消息隊列滿或空的情形。
設計:在軟件設計時就考慮軟件的異常處理機制,功能層面就支持異常記錄、售后調試的需求,而不是把這個工作留給編程人員。
4、非技術性問題
大規(guī)模系統(tǒng)中軟件會分割成無數(shù)個模塊,負責這些的開發(fā)人員來自不同的職能部門,這些部門又有著各自不同優(yōu)先級的任務,而解決那些復雜的問題又需要這些部門的配合,才能找到真正的出錯原因和找到最終的解決方案?;蛟S最終解決問題的代碼僅僅在一個組件中,或許只有簡單的一兩行代碼,然而找到問題的原因并給定解決方案的過程卻是漫長、繁瑣的。
4.1 人員分配
在大規(guī)模分工的系統(tǒng)中,每個技術領域都是一群人負責,解決問題效率與個人的技術能力有極大的關系。有些簡單技術問題,如果參與的不是合適的技術人員,例如人員的變動導致原來的軟件人員不再負責該軟件,那簡單的問題也變得復雜。正所謂“難者不會,會者不難”。技術是長期積累的過程,同一類問題不要頻繁的更換人員。
4.2 任務分配
復雜系統(tǒng)中,一個問題需要涉及到多個部門,一個程序員在某個環(huán)節(jié)上的放緩,導致基于這個前置條件的進度也跟著放緩,整個組織的執(zhí)行就會極大的降低,從宏觀上看,整個組織都很忙,但總體的效率卻很低。
按優(yōu)先級排序分配任務,在一個高優(yōu)先任務完成前,不要處理其他任務,降低程序員并發(fā)處理故障的個數(shù),否則“任務”切換的開銷就很大。高難度與低難度任務搭配,同時處理多個高難度問題,整體效率是下降的,而且一個延期會連鎖導致后續(xù)都延期。
4.3 項目分配
實現(xiàn)一個復雜功能,或者解決某個問題,往往可以在不同的子系統(tǒng)解決,各個子系統(tǒng)出于各自原因,都希望最終的解決方案不要放到自己的子系統(tǒng),希望推到其他子系統(tǒng)。此時,一般是地位低的子系統(tǒng)人員妥協(xié),即使其子系統(tǒng)的實現(xiàn)不是最佳方案,這種就看項目分配,需要具有一定技術背景和決策權的人協(xié)調。
5、結語
關于軟件問題的分析理論,也只是拾人牙慧。理論和實際存在較大差異,真正遇到軟件問題,這些方法并不一定靠譜。