《重構(gòu)》第三章學習筆記

          我們必須培養(yǎng)自己的判斷力,來決定在什么時候進行重構(gòu)。

          1.1  Duplicate Code(重復代碼)

          如果你在一個以上地點看到相同的程序結(jié)構(gòu),那么將他們合而為一會更好。

          1.2  Long Method(過長函數(shù))

          擁有短函數(shù)的對象會活得比較好,比較長。

          間接層所能帶來的全部益處:解釋能力(可讀性),共享能力(重用性),選擇能力(?)。

          現(xiàn)在OO 語言基本解決了函數(shù)調(diào)用所產(chǎn)生的開銷。

          “ 你應該更積極進去的分解函數(shù)。我們遵循這樣一條原則:每當感覺需要以注釋來說明點什么的時候,我們就把需要說明的東西寫進一個函數(shù)中,并以其用途(而非實現(xiàn)手法)命名。我們可以對一組甚至短短一行代碼(擁有復雜邏輯,難以理解)做這件事。哪怕替換后的函數(shù)調(diào)用動作比函數(shù)自身還長,只要函數(shù)名稱能夠解釋其用途,我們也該毫不猶豫的這么做。關(guān)鍵不在于函數(shù)的長度,而在于“做什么”和“如何做”之間的語義距離。 ”

          “如何確定該提煉哪一段代碼?一個很好的技巧是:尋找注釋。它們通常是指出“代碼用途和實現(xiàn)手法間的語義距離”的信號。如果代碼需要用注釋來說明其用途,那么就要考慮把這段代碼提煉成獨立的函數(shù),并且用注釋來為此函數(shù)命名?!?

          復雜條件式和循環(huán)液常常是提煉的信號。

          1.3  Large Class(過大類)

          如果想利用單一的class 做太多的事情,其內(nèi)往往會出現(xiàn)太多的 instance 變量。

          如果class 中擁有太多的代碼,也是“代碼重復、混亂、死亡”的絕佳滋生點。

          1.4  Long Parameter List(過長的參數(shù)列表)

          過長的產(chǎn)生導致程序難以理解。

          1.5  Divergent Change(發(fā)散式變化)

          “ 一個class 受多個外界變化的影響 ”,則把這多個變化封裝成一個新的類。即“ 將總是一起變化的東西放在一起 ”

          針對外界某一變化所有相應的修改,都應該只發(fā)生在單一的class 中,而這個 class 的所有內(nèi)容都應該反映該外界變化??偟乃枷刖褪?,封裝變化。這個地方和設(shè)計模式的想法是一致的。

          1.6  Shotgun Surgery(散彈式修改)

          和發(fā)散式變化不同,每次遇到變化,都要在多個class 中進行小的修改以響應之。他們分散在多處,很容易出錯。

          這里的主要思想是集中變化。

          散彈式修改指的是,“ 一種變化引發(fā)多個class 的修改 ”,發(fā)散式變化指的是“ 一個class 受多個外界變化的影響 ”。

          這兩種情況下,通過重構(gòu), 使“外界變化”和“待修改類”呈一對一關(guān)系 的理想境地。

          1.7  Feature Envy(依戀情節(jié))

          某個函數(shù)對其他類的數(shù)據(jù)的興趣,高過對host class 的興趣。即對其他的類的數(shù)據(jù)的依賴十分大。

          1.8  Data Clumps(數(shù)據(jù)泥團)

          數(shù)據(jù)泥團指的是總是綁定在一起出現(xiàn)的數(shù)據(jù)。

          一個好的評斷方法:刪除眾多數(shù)據(jù)中的一項數(shù)據(jù),其他數(shù)據(jù)是否是因而失去了意義?如果他們不再有意義:你應該為他們產(chǎn)生一個新的對象。

          形成新的對象后,可以根據(jù)Feature Envy 將一些操作移至此對象中。

          1.9  Primitive Obsession(基本型別偏執(zhí))

          建立多個很小,但是很靈活的對象。

          1.10  Switch Statements( switch 驚悚現(xiàn)身)

          使用面向?qū)ο缶幊?,要少用switch 和 case 語句。而是用多態(tài)來替換它。

          1.11  Parallel Inheritance Hierarchies(平行繼承體系)

          每當你為一個class 增加一個 subclass 的時候,必須為另一個 class 增加一個 subclass 。一般這兩個 class 的前綴相同。

          1.12  Lazy Class(冗贅類)

          類顯得多余,沒有價值。

          1.13  Speculative Generality(夸夸其談未來性)

          這個往往是過度設(shè)計的結(jié)果:對某種變化的應對,而這種變化沒有發(fā)生。

          1.14  Temporary Field(令人迷惑的暫時值域)

          變量只在特定的情形下有效,而并不是所有的情況下有效。很多情況下,這些值域應該不屬于此class ,而應該單獨的提取成新的類。

          1.15  Message Chains(過度耦合的消息鏈)

          用戶向一個對象索取另一個對象,然后在向后者索求另一個對象,然后在索求另一個對象——客戶與查找過程的航行結(jié)構(gòu)緊密耦合。

          1.16  Middle Man(中間轉(zhuǎn)手人)

          對象的基本特征之一就是封裝——對外部世界隱藏實現(xiàn)細節(jié)——封裝往往伴隨委托。委托的過度運行,就導致了Middle Man 。

          1.17  Inappropriate Intimacy (親密關(guān)系)

          兩個class 之間的關(guān)系過于親密。比如,花大量的時間探究彼此的 private 成分。

          1.18  Alternative Classes with Different Interface(異曲同工的類)

          類名不同,但是功能相似。

          1.19  Incomplete Library Class(不完美的程序類庫)

          基礎(chǔ)類庫無法滿足實際的需求。

          1.20  Data Class(純稚的數(shù)據(jù)類)

          它們擁有一些值域,以及用于訪問(讀寫)這些值域的函數(shù),除此之外一無長物。

          1.21  Refused Bequest(被拒絕的遺贈)

          子類不像繼承父類的函數(shù)和數(shù)據(jù),這往往是繼承體系的錯誤。

          如果子類復用父類的行為,但又不愿支持父類的接口,這種情況下Refused Bequest 的壞味道會很強烈。

          1.22  Comments(過多的注釋)

          注釋其實是一種香味,更多的情況下它被用作除臭劑:即代碼中出現(xiàn)壞味道(設(shè)計糟糕的代碼),然后用注釋“除臭”。這個時候我們應該對這些壞味道的代碼進行重構(gòu),然后,你會發(fā)現(xiàn)注釋變成了多余的。

          當你感覺需要注釋,請先嘗試重構(gòu),試著讓所有的注釋都變得多余——代碼本身就是自注釋的。

          注釋可以用來記述“為什么做某事”、“打算做某事”、“無十足把握的區(qū)域”,而不必記錄“怎么做”。

          posted @ 2009-10-12 20:15 常高偉 閱讀(793) | 評論 (0)編輯 收藏

          以前做過一個產(chǎn)品,共分為三層:平臺層,應用服務(wù)器層,應用層。其中有一個業(yè)務(wù)流程,實現(xiàn)是在應用層,但它那里的信息不全,需要通過應用服務(wù)器層向平臺層獲取必要的業(yè)務(wù)數(shù)據(jù),然后通過應用服務(wù)器層控制業(yè)務(wù)流程。當時考慮這個結(jié)構(gòu)的時候,主要的出發(fā)點就是業(yè)務(wù)和控制分離,將業(yè)務(wù)處理從平臺層剝離開來。當時,在具體是實施過程中,我們工程師對這種結(jié)構(gòu)抵觸心理很強烈。他認為我們的業(yè)務(wù)開發(fā)非常的繁瑣,而且經(jīng)常要貼“狗皮膏藥”。

          先拋開上面這個實例的設(shè)計思路,這里面反映出一個問題:軟件開發(fā)過程中,軟件體系結(jié)構(gòu)同樣需要“重構(gòu)”

          結(jié)合經(jīng)典的《重構(gòu)》,這里簡單的寫一下軟件體系結(jié)構(gòu)重構(gòu)的定義,原因,設(shè)計,方法。僅作拋磚引玉,希望能和大家一起思考。

          何謂重構(gòu)

          對軟件體系結(jié)構(gòu)的一種調(diào)整,目的是在不改變其“外在行為”的前提下,調(diào)整其結(jié)構(gòu),使其易于修改,維護和理解。

          為何重構(gòu)

          1、使整個系統(tǒng)易于添加新的功能。為系統(tǒng)添加新功能將會非常的容易。

          2、調(diào)整系統(tǒng)中各個模塊的功能,角色,使整個系統(tǒng)更容易理解。
          何時重構(gòu)

          由于系統(tǒng)結(jié)構(gòu)的重構(gòu)成本非常高,所以要選擇一個合適的重構(gòu)時機。

          1、為系統(tǒng)添加功能時重構(gòu)。此時項目進度壓力如果非常大,這放棄此時重構(gòu)。

          2、軟件第一個版本開發(fā)完畢后重構(gòu)。在第一個版本開發(fā)完畢,第二個版本開發(fā)之前,根據(jù)第一個版本的開發(fā)經(jīng)驗,對系統(tǒng)進行重構(gòu)。

          3、開發(fā)出系統(tǒng)原型時進行重構(gòu)。開發(fā)出一個系統(tǒng)的原型的時候,如果發(fā)現(xiàn)系統(tǒng)需要重構(gòu),這及時的進行,這個時候重構(gòu)成本較低,但對是否重構(gòu)決策要求較高。

          重構(gòu)的必要條件

          重構(gòu)之前必須為軟件系統(tǒng)建立一個可靠的、自動化的功能測試環(huán)境,這樣才能有效防止重構(gòu)帶來的危害。好的測試時重構(gòu)的根本。重構(gòu)之前,首先檢查自己是否有一套可靠的測試機制。這些測試必須有自我檢驗(selfchecking)能力。

          重構(gòu)與設(shè)計

          系統(tǒng)架構(gòu)層次的重構(gòu),因為重構(gòu)的成本相對較高,所以預先設(shè)計的程度要相對較深,要盡量考慮系統(tǒng)可能遇到的情況,方案要適當?shù)撵`活和強固。盡量減少系統(tǒng)結(jié)構(gòu)的重構(gòu)。

          軟件體系結(jié)構(gòu)的重和代碼的重構(gòu)的區(qū)別

          1、針對的層次不同:一個是系統(tǒng)結(jié)構(gòu)層次的,一個是代碼層次的。

          2、重構(gòu)成本不同,系統(tǒng)結(jié)構(gòu)的重構(gòu)成本相對較高。

          3、是否重構(gòu)的決策者不同。

          4、重構(gòu)的時機不同。

          posted @ 2009-10-12 20:14 常高偉 閱讀(348) | 評論 (0)編輯 收藏

          在學習的不同的階段我們應該保持的心態(tài):
          1、接觸之前,擁有一個好奇的心態(tài)。與自己原有的知識對比,不要對新的知識產(chǎn)生偏見。比如,原來一直采用瀑布式軟件開發(fā),在接觸敏捷軟件開發(fā)之前,不要對敏捷軟件開發(fā)模式產(chǎn)生偏見:“敏捷開發(fā)根本不能夠和瀑布式開發(fā)相提并論”。偏見會阻礙新知識的學習,而是要對敏捷開發(fā)保持一種好奇心:

          1)這種理論為什么會提出來?
          2)主要為了解決什么問題?
          3)現(xiàn)有的理論無法解決此問題嗎?
          4)它是基于什么樣的原理?
          5)它是如何運行的?

          2、學習了一段時間,擁有一定基礎(chǔ)之后,要以一種批判的、懷疑的心態(tài)來對待學習的知識。當你擁有了對新知識的一定認識后,有可能會發(fā)現(xiàn)它很好解決了你以前遇到的一些非常棘手的問題,或者發(fā)現(xiàn)你找到了某一領(lǐng)域問題的完美的解決方案。這個時候,你要讓自己堅信,“沒有銀彈”,沒有包治百病的靈丹妙藥。任何方案、理論、技術(shù)都有其依賴的條件,或者在解決原有問題后,引入的新的問題。此時,你要以一種批判的、懷疑的態(tài)度來對待它。要搞清楚:

          1)它所依賴的前提條件是什么?
          2)應用它的時候有沒有什么假設(shè)?
          3)它在那些場景下適用、那些場景下不適用?
          4)它在解決原有問題之后,有沒有引入新的問題?

          3、當你達到專家級或頂級水平之后,應該持有一種“獨孤求敗”的心態(tài):尋求新的挑戰(zhàn),爭取“百尺竿頭更進一步”,就像獨孤求敗一樣,”闖蕩江湖,只求一敗 “:把每次的失敗看成進步的機會。同時保持敬畏、謙虛的心態(tài),你所掌握的知識,也不是”銀彈“,也有其局限之處,或者隨著環(huán)境的發(fā)展,已經(jīng)無法適應環(huán)境,需要尋求新的突破。這個時候,你要根據(jù)你豐富的實踐,提出創(chuàng)新的思路或知識。
          總之:
          1、在學習新知識、新領(lǐng)域的時候,要保持一個空杯的心態(tài),只有這樣才能為自己敞開自我提升之路。
          2、偏見導致對新知識的排斥,教條倒是對新知識的盲從。
          3、沒有絕對的真理,也沒有絕對的謬論。絕對的真理讓我們盲從,絕對的謬論讓我們偏見。

          posted @ 2009-10-12 20:13 常高偉 閱讀(135) | 評論 (0)編輯 收藏

          1  構(gòu)筑測試體系

          如果你想進行重構(gòu),首要前提就是要擁有一個可靠的測試環(huán)境。

          “編寫優(yōu)良的測試程序,可以極大的提高我的編程速度,即使不進行重構(gòu)也是如此。”

          1.1  自我測試代碼(Self-testing Code )的價值

          “Class 應該包含他們自己的測試代碼?!?

          “每個Class 都有一個測試函數(shù),并用它測試自己這個 Class ?!?

          確保所有的測試都完全自動化,讓它們檢查自己的測試結(jié)果。

          只要寫好一點功能,就立即添加測試。

          一整組(a suite of )測試就是一個強大的“臭蟲”偵測器,能夠大大縮減查找“臭蟲”所需要的時間。

          “實際上,編寫測試代碼的最有用時機是在開始編程之前。當你需要添加特性的時候,先寫相應的測試代碼。聽起來離經(jīng)叛道,其實不然。填寫測試代碼其實就是問自己:添加這個功能需要做什么。編寫測試代碼還能使你把注意力集中于接口而非實現(xiàn)上頭(永遠是件好事)。預先寫好的測試代碼也為你的工作按上一個明確的結(jié)束標志:一旦測試代碼運行正常,工作就可以結(jié)束了。”

          構(gòu)建自我測試的代碼。

          1.2  JUnit測試框架( Testing Framew )

          頻繁的運行測試,每次編譯請把測試也考慮進去,每天至少執(zhí)行每個測試一次。

          單元測試和功能測試

          “每當你接獲臭蟲提報,請先撰寫一個單元測試來揭發(fā)這只臭蟲。”——如何揭發(fā)?這里需要根據(jù)報告準確定位。單元測試會對此有幫助嗎?

          1.3  添加更多的測試

          “觀察Class 該做的所有事情,然后針對任何一項功能的任何一種可能失敗的情況,進行測試?!?

          “測試應該是一種風險驅(qū)動(risk driven )行為,測試的目的是希望找出現(xiàn)在或未來的可能出現(xiàn)的錯誤。”

          “測試的訣竅是:測試你最擔心的部分?!?

          這點和我目前的想法不大相同。我目前的想法是,測試要對程序做100% 的保證,所以,要測試程序可能行為的每一種情況,保證其正確性。按照我的想法,值域的設(shè)置和訪問函數(shù)也是要測試的。作者的意思是,測試代碼要用最低的成本,獲取最大的收益。這一點,要我在實際的環(huán)境中進行抉擇。

          “編寫不是十分完美的測試并實際運行,好過對完美測試的無盡等待?!薄页謶岩蓱B(tài)度。

          運用測試用例前后執(zhí)行的函數(shù):tearDown 和 setUp ,保證測試用例之間相互隔離,而非相互影響。

          做一個懶惰的程序員——。

          考慮可能出錯的邊界條件,把測試火力集中在那兒。

          “測試(優(yōu)先)可以調(diào)高編程速度”,這一點我要在實踐中驗證一下,如果真是這樣,那我就要嘗試在我們部門推行這種方法。

          “當測試達到一定的程度后,測試效益會呈現(xiàn)遞減態(tài)勢。”所以,你不要期望通過測試找出所有的bug ,而是要通過測試,找出絕大多數(shù)的 bug 。

          這個地方其實也符合“二八定律”:即20% 的測試可以找出 80% 的 bug ,其余的 80% 的測試可以找出剩下的 20% 的 bug 。我們要做的,就是寫這 20% 的測試,而非 100% 的測試。

          posted @ 2009-10-12 20:11 常高偉 閱讀(148) | 評論 (0)編輯 收藏

          上一篇介紹了微內(nèi)核流程引擎開發(fā)背景,這篇介紹它的功能描述。

          基本功能:

          1、能夠通過腳本定義流程,更改流程。

          2、對軟交換系統(tǒng)應用服務(wù)器的所有的接口都可以編輯。

          3、異常處理,實現(xiàn)補償機制。

          4、流程要支持:順序執(zhí)行,分支處理,跳轉(zhuǎn)執(zhí)行。

          5、腳本中支持簡單的數(shù)據(jù)庫操作,比如:記錄查詢(根據(jù)查詢結(jié)果決定流程),字段查詢,記錄增刪改。


          擴展功能:

          1、提供多種調(diào)用形式:1)動態(tài)鏈接庫直接調(diào)用;2)socket通信調(diào)用;3)遠程調(diào)用;4)WSDL方式調(diào)用。

          2、實現(xiàn)一個流程引擎虛擬機。專門處理流程。

          3、支持業(yè)務(wù)以無狀態(tài)的形式開發(fā)。所有的狀態(tài)在腳本中定義。

          4、開發(fā)一個流程編輯界面。

          5、開發(fā)一個腳本編譯器,檢查腳本的錯誤。

          6、開發(fā)一個簡單的語言,實現(xiàn)快速流程編輯的功能。這里要實現(xiàn)一個編譯器,編譯結(jié)果就是流程腳本。

          7、實現(xiàn)一個方向編譯器,從流程腳本到流程開發(fā)語言。

          上面的這些功能有的已經(jīng)實現(xiàn),有的正在實現(xiàn)。后面我會詳細描述這些功能的設(shè)計與實現(xiàn)。

          posted @ 2009-10-12 20:08 常高偉 閱讀(250) | 評論 (0)編輯 收藏

          我設(shè)計的流程引擎是腳步驅(qū)動的。腳本中定義了流程執(zhí)行的環(huán)境,流程操作的對象,流程執(zhí)行的步驟。下面是一個流程腳本的示例:

          <?xml version="1.0" encoding="utf-8"?>
          <process name="make_call">
              <data type="user_tel">called_number</data>
               <object type="user" id="global_data:called_number" operation="must">obj_user</object>
               //用戶對象描述中,號碼是必須的,是流程引擎和業(yè)務(wù)的交互唯一標識,callid是可選的。
              <object type="user" object_num="global_data:called_number" operation="must">obj_user</object>
              <sequence name="make_call">
                  <invoke interface="make_call" node="make_call_001" object_user="obj_user" calling_number="6699" original_number="123456" call_type="local_call">

                  </invoke>
                  <invoke interface="play_voice" node="play_voice_001" object_user="obj_user" play_long="100" play_file="/home/welcome.au">

                   </invoke>   
              </sequence>
          </process>


          腳本的含義

          1、process的name屬性表示流程的名稱,用于在程序中調(diào)用。

          2、<data type="user_tel">called_number</data>表示定義了一個流程的全局外部變量。有程序在調(diào)用流程是作為流程數(shù)據(jù)傳送給流程。這個數(shù)據(jù)要在后面的流程中使用。

          3、<object>部分在流程中定義流程操作的對象。一般分為用戶和會場。這里表示是用戶。屬性“id”表示對象的唯一標識。這里引用的是流程的全局數(shù)據(jù):global_data:called_number,也就是在上面定義的數(shù)據(jù)。屬性“operation”表示此對象是可選還是必選。如果是必須,這如果此對象被釋放,這流程也要被被結(jié)束。否則,不結(jié)束。中間的內(nèi)容表示對象在流程中的唯一標示,這里是obj_user,后面的節(jié)點可以通過使用它來操作對象。

          4、<sequence>表示順序調(diào)用下面的節(jié)點。

          5、<invoke >表示調(diào)用節(jié)點。屬性“interface="make_call"”表示此節(jié)點調(diào)用的接口是make_call。make_call是在代碼中定義好的關(guān)鍵字,對應一個軟交換系統(tǒng)的接口。屬性“node”表示節(jié)點的唯一標識,在流程內(nèi)部唯一,可以在流程跳轉(zhuǎn)的時候使用。 “object_user="obj_user"“表示make_call 接口操作的對象。有<object>創(chuàng)建。 calling_number="6699" original_number="123456" call_type="local_call"表示的是make_call接口調(diào)用時的數(shù)據(jù)。

          6、<invoke interface="play_voice"表示對此對象進行放音。

          這個腳本的意思是,根據(jù)流程輸入的號碼,創(chuàng)建用戶對象,并且發(fā)起呼叫,對用戶進行放音。


          復雜的腳步定義:

          上面的是一個簡單的示例。為了能夠?qū)崿F(xiàn)流程編輯,要考慮很多的情況,要能夠進行分支處理,跳轉(zhuǎn)執(zhí)行,捕獲事件等。

          1、分支的實現(xiàn)

              <recive event="user_key" ="" node="receive_key" object_user="obj_user" time_out="10"></recive>
              <switch condition_type="user_key" object="obj_user">
                      <case condition="9092">
                          <sequence name="d">
                          </sequence>
                      </case>
                      <case condition="time_out">
                          <sequence name="d">
                          </sequence>
                      </case>           
                      <otherwise>
                            <sequence name="">
                                <goto node="play_voice_001">goto_001</goto>
                            </sequence>
                      </otherwise>
              </switch>

          1)<recive event="user_key"表示接受指定用戶的按鍵。如果超過10秒為收到按鍵則認為用戶按鍵結(jié)束。

          2)<switch condition_type="user_key"表示一用戶的按鍵為分支條件,進行分支處理。

          3)<case condition="9092">表示如果用戶的按鍵式0092的話則進入此分支進行處理。

          4)<case condition="time_out">如果超時為收到用戶按鍵,這進入此分支處理

          5)<otherwise>如果上面的條件都不滿足,則進入此分支處理。


          2、跳轉(zhuǎn)的實現(xiàn):

          <goto node="goto_001" next_node="play_voice_001"></goto>

          表示此節(jié)點是一個跳轉(zhuǎn)節(jié)點,要跳轉(zhuǎn)到的下一個節(jié)點是play_voice_001。


          3、信號捕獲的實現(xiàn):

                 <pick name="pick_001" time_out="10">
                      <on_event event="on_ring_180" result="success" reason="normal">
                          <sequence name="008">
                          </sequence>
                      </on_event>
                      <time_out>
                          <sequence name="008">
                          </sequence>
                      </time_out>
                      <otherwise event="on_ring_180:on_ring_183">
                            <sequence name="009">
                              </sequence>
                      </otherwise>
                  </pick>

          1)<pick name="pick_001" time_out="10"><pick>活動會等待一組相互排斥事件中的一個事件的發(fā)生,然后執(zhí)行與發(fā)生的事件相關(guān)聯(lián)的活動。它會阻塞業(yè)務(wù)流程執(zhí)行,以等待某一特定的事件發(fā)生,比如接收到一個合適的消息或超時警報響起。當其中任何一個事件被觸發(fā)后,業(yè)務(wù)流程就會繼續(xù)執(zhí)行,pick也隨即完成了,不會再等待其他事件的發(fā)生。

          2)<on_event event="on_ring_180" result="success" reason="normal">表示如果收到的on_ring_180,且結(jié)果是success,原因是normal。觸發(fā)此流程的處理。

          3)<time_out>表示超時為收到制定事件的處理。

          4)<otherwise event="on_ring_180:on_ring_183">表示收到其他的事件,比如:on_ring_180或on_ring_183,都進入此分支處理。

          posted @ 2009-10-12 20:08 常高偉 閱讀(199) | 評論 (0)編輯 收藏

          開發(fā)背景

          我們公司是主要從事企業(yè)語音方面產(chǎn)品的開發(fā),主要產(chǎn)品比如:調(diào)度系統(tǒng),指揮系統(tǒng),電話會議系統(tǒng),呼叫中心系統(tǒng)等。這些系統(tǒng)都有一個共同特點,就是涉及到呼叫,放音,收發(fā)按鍵,會場操作。我們的業(yè)務(wù)產(chǎn)品都是基于我們的軟交換系統(tǒng)之上構(gòu)建的,軟交換系統(tǒng)的應用服務(wù)器向外提供這些服務(wù)。


          產(chǎn)生的問題

          我們在開發(fā)的過程中就發(fā)現(xiàn)一個問題,每個產(chǎn)品在此接口上都會做很多重復的開發(fā),特別是在IVR處理上面。

          IVR (Interactive Voice Response)即交互式語音應答,可以提高呼叫服務(wù)的質(zhì)量并節(jié)省費用。IVR是一種功能強大的電話自動服務(wù)系統(tǒng)。

          由于我們的系統(tǒng)重新架構(gòu),正在開發(fā)軟交換API接口,所以我們試圖解決這個問題。

          為了方便上層對底層接口的調(diào)用,減少重復開發(fā),產(chǎn)品能夠針對用戶需求迅速更改,我們提出了事務(wù)流的概念。即上層程序設(shè)定一個事務(wù)流,比如:相對用戶9092發(fā)起呼叫,用戶應答后對用戶放音,讓用戶輸入密碼,密碼驗證成功加入制定會場。上層程序設(shè)定好這樣的事務(wù)流后,發(fā)送給下層進行處理。下層處理完畢后,回復處理結(jié)果。

          事務(wù)流的概念最終并沒有實現(xiàn),一是我們對事務(wù)流的異常處理分析不足;二是采用事務(wù)流的概念擴展性,可維護性不是很好。

          后來我們在事務(wù)流的基礎(chǔ)上引進了SOA的概念,即將底層的接口封裝為一系列松散耦合的服務(wù),在上層通過對服務(wù)的編排實現(xiàn)流程編輯的功能。但是實施SOA困難非常大,一是SOA沒有大規(guī)模的應用,文檔,經(jīng)驗都比較少,實施風險較大;二是實施 SOA要工具的支持,需要投資。這樣的話我們寧可重復開發(fā)。

          最終這個流程編輯的功能并沒有完成,但是我們還是在API中實現(xiàn)了一個簡單的流程編輯,這個流程編輯是通過硬編碼來實現(xiàn)的,和我們的愿望相差較大。


          新的思路

          后來看了一家平臺軟件公司的介紹,他們是做企業(yè)應用平臺的。企業(yè)應用中很多的一點就是工作流。他們的平臺就是集成了一款開源的工作流引擎:JBPM。第一次接觸JBPM,感覺很多思路可以借鑒。后來在網(wǎng)上搜資料的時候搜到幾篇研究微內(nèi)核流程引擎的文章:

          揭秘jbpm流程引擎內(nèi)核設(shè)計思想及構(gòu)架

          微內(nèi)核過程引擎的設(shè)計思路和構(gòu)架

          微內(nèi)核工作流引擎體系架構(gòu)與部分解決方案參考

          這幾篇文章是我設(shè)計流程引擎的核心基礎(chǔ)??赐曛笞罱K決定自己設(shè)計一個微內(nèi)核流程引擎。


          使用開源還是自己開發(fā)

          決定動手開發(fā)前,有兩種方式,一是使用開源產(chǎn)品,比如JBPM;二是自己動手開發(fā)。當時的考慮是:

          1、JBPM是用java開發(fā),我們公司的業(yè)務(wù)產(chǎn)品目前基本上都是c,和java交互不便。

          2、JBPM是針對企業(yè)工作流設(shè)計的,工作流和IVR導航一個重要的區(qū)別是,IVR導航對時效性要求很高。要求系統(tǒng)能夠及時響應。

          3、我不是JAVA出身,當時對java還有些畏難心理。

          所以,最終決定自己用C++開發(fā)流程引擎。

          如果是現(xiàn)在的話,即便是決定自己開發(fā),一會好好研究一下JBPM的源碼的。


          借鑒的其他思路

          1、數(shù)據(jù)驅(qū)動(DD)。在腳本中XML定義流程,程序啟動后將流程讀入程序,然后供上層程序調(diào)用。如果流程更改,這直接修改腳本即可。

          2、BPEL。Business Process Execution Language 的縮寫,意為業(yè)務(wù)過程執(zhí)行語言 ,是一種基于XML 的,用來描寫業(yè)務(wù)過程的編程語言。我的腳步語言參考BPEL的描述。

          posted @ 2009-10-12 20:05 常高偉 閱讀(376) | 評論 (0)編輯 收藏

          在上一家公司的時候,一次新員工培訓的主題是員工的工作態(tài)度。當時有一個案例:有兩個員工,能力不相上下,都合格的完成了工作任務(wù),其中一個員工完成任務(wù)的同時中總是抱怨,發(fā)牢騷。案例的問題是“給這兩個員工進行績效考評,一個是A,一個是B,你會怎么評?”。

            我記得當時我們都豪不猶豫的把總是抱怨的員工評了B,理由是抱怨對團隊氛圍和工作效率的危害很大。

            現(xiàn)在想來當初的這個判斷很草率,不夠深刻。

            管理者如何正確對待員工的抱怨?

            首先應該對員工的抱怨足夠重視。其一是抱怨對團隊的危害性。其二,可以把員工的抱怨理解成客戶的抱怨。余世維在一個講座中提到,“會抱怨的客戶 是好客戶”,因為客戶的抱怨有助于提升公司的產(chǎn)品和服務(wù)。員工從一定意義上來說就是管理者的客戶,管理者要提供“服務(wù)”來提高客戶的工作效率。既然客戶的 抱怨有助于提升公司的產(chǎn)品和服務(wù),那么員工的抱怨是否就有助于發(fā)現(xiàn)公司流程、制度的缺陷,提升公司的管理水平?其三,管理者的首要任務(wù)是發(fā)現(xiàn)問題,既然有 員工抱怨,那么不是公司管理出現(xiàn)了問題,就是員工出現(xiàn)了問題,很多時候往往是兩者都出現(xiàn)了問題。管理者決不能放過這個發(fā)現(xiàn)問題的機會。

            其次,合理的重視員工的抱怨。對員工抱怨的重視不能簡單的體現(xiàn)在績效考核上——用績效考核的大棒把員工的抱怨打下去。這樣做的結(jié)果往往是不是員 工不抱怨了,而是在你看不見、聽不到的地方,或者心理抱怨。最終的后果是,“防人之口,甚于防川”,日積月累的抱怨會以一種更具有破壞性的形式發(fā)泄出來。

            管理者在獲知員工的抱怨后應該采取什么樣的行動?

            首先是調(diào)整好心態(tài)和員工開誠布公的溝通。應該以一種平和的(而不是先入為主的)心態(tài)和員工進行平等對話,深入的了解員工抱怨的真實原因。為了讓員工能夠沒有任何心理包袱,這樣的談話不要作為績效考核的依據(jù)(一個具有開放討論的組織文化的團隊是不存在這個問題的)。

            其次,找到問題的根源,和員工一起制定一個行動方案。如果是公司的流程、制度或管理出現(xiàn)了問題,管理者則要認真的分析,提出一個解決方案,以此來提升管理水平;如果是員工個人的問題,管理者就應該明確的告訴員工你的期望,目標,以促使員工的態(tài)度得到提升。

            最后,告訴員工,你有(比抱怨)更好的選擇。如果你對周圍的環(huán)境感覺不舒服,那就1)找出到底是什么讓你感覺不舒服?(what)2)為什么會 讓你感覺不舒服(why)?它有什么不合理的地方?3)怎么樣能讓它更加的合理(how)?4)應該在什么時間(when)、由什么人(who)來采取行 動? 最后,不要忘了把你的思考結(jié)果告訴給你的上司,并積極的參與到這項改善的行動中來。我把這種思維方式稱為管理者的思維方式。當然,如果你用這種方式來思考 問題,那你就離管理者的角色不遠了。

            在雙方都采取行動后,如果還是不能接受對方,那么矛盾有可能是不可調(diào)和的,比如說性格和企業(yè)文化的沖突。此時勉強維護雙方的關(guān)系對誰的都不好,最好的解決方案是放棄這種勞動關(guān)系。

            管理者能夠“看到”的抱怨往往只是冰山一角。如果更加深入的了解員工的想法,是一個值得深入探討的問題。鼓勵員工真實的表達自己的想法,培養(yǎng)一種開放討論的組織文化,消除員工坦露內(nèi)心世界的制度障礙,或許會對此有些幫助。

            如果說上面的做法一種守勢的思維方式,我們也可以換一種攻勢的思維方式:積極的引導你的團隊成員,以管理者的思維方式來思考問題。這樣你的團隊將會獲得一個良好的自我診斷和自我修復能力。我認為,良好的自我診斷和自我修復能力是卓越團隊的本質(zhì)特征之一。

            總之,治理員工的抱怨,和治水其實是一個道理,重在疏導。只要措施得當,我們絕對可以化弊為利。

          posted @ 2009-10-11 08:37 常高偉 閱讀(211) | 評論 (0)編輯 收藏

          在學習的不同的階段我們應該保持的心態(tài):

          1、接觸之前,擁有一個好奇的心態(tài)。與自己原有的知識對比,不要對新的知識產(chǎn)生偏見。比如,原來一直采用瀑布式軟件開發(fā),在接觸敏捷軟件開發(fā)之前,不要對 敏捷軟件開發(fā)模式產(chǎn)生偏見:“敏捷開發(fā)根本不能夠和瀑布式開發(fā)相提并論”。偏見會阻礙新知識的學習,而是要對敏捷開發(fā)保持一種好奇心:

          1)這種理論為什么會提出來?
          2)主要為了解決什么問題?
          3)現(xiàn)有的理論無法解決此問題嗎?
          4)它是基于什么樣的原理?
          5)它是如何運行的?


          2、學習了一段時間,擁有一定基礎(chǔ)之后,要以一種批判的、懷疑的心態(tài)來對待學習的知識。當你擁有了對新知識的一定認識后,有可能會發(fā)現(xiàn)它很好解決了你以前 遇到的一些非常棘手的問題,或者發(fā)現(xiàn)你找到了某一領(lǐng)域問題的完美的解決方案。這個時候,你要讓自己堅信,“沒有銀彈”,沒有包治百病的靈丹妙藥。任何方 案、理論、技術(shù)都有其依賴的條件,或者在解決原有問題后,引入的新的問題。此時,你要以一種批判的、懷疑的態(tài)度來對待它。要搞清楚:

          1)它所依賴的前提條件是什么?
          2)應用它的時候有沒有什么假設(shè)?
          3)它在那些場景下適用、那些場景下不適用?
          4)它在解決原有問題之后,有沒有引入新的問題?


          3、當你達到專家級或頂級水平之后,應該持有一種“獨孤求敗”的心態(tài):尋求新的挑戰(zhàn),爭取“百尺竿頭更進一步”,就像獨孤求敗一樣,”闖蕩江湖,只求一敗 “:把每次的失敗看成進步的機會。同時保持敬畏、謙虛的心態(tài),你所掌握的知識,也不是”銀彈“,也有其局限之處,或者隨著環(huán)境的發(fā)展,已經(jīng)無法適應環(huán)境, 需要尋求新的突破。這個時候,你要根據(jù)你豐富的實踐,提出創(chuàng)新的思路或知識。

          總之:
          1、在學習新知識、新領(lǐng)域的時候,要保持一個空杯的心態(tài),只有這樣才能為自己敞開自我提升之路。
          2、偏見導致對新知識的排斥,教條倒是對新知識的盲從。
          3、沒有絕對的真理,也沒有絕對的謬論。絕對的真理讓我們盲從,絕對的謬論讓我們偏見。

          posted @ 2009-10-11 08:31 常高偉 閱讀(73) | 評論 (0)編輯 收藏

          僅列出標題
          共2頁: 上一頁 1 2 

          posts - 19, comments - 0, trackbacks - 0, articles - 0

          Copyright © 常高偉

          主站蜘蛛池模板: 南溪县| 宁城县| 克东县| 鸡西市| 大化| 固镇县| 城口县| 鹿泉市| 介休市| 敦化市| 永定县| 平度市| 无锡市| 宜黄县| 洪泽县| 罗平县| 左贡县| 平度市| 盈江县| 泰和县| 龙陵县| 无棣县| 八宿县| 台州市| 久治县| 安图县| 汨罗市| 皮山县| 财经| 四平市| 桃江县| 正宁县| 紫云| 怀来县| 景谷| 南投县| 江孜县| 萨嘎县| 鄄城县| 南通市| 娱乐|