《重構》第三章學習筆記

          我們必須培養自己的判斷力,來決定在什么時候進行重構。

          1.1  Duplicate Code(重復代碼)

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

          1.2  Long Method(過長函數)

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

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

          現在OO 語言基本解決了函數調用所產生的開銷。

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

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

          復雜條件式和循環液常常是提煉的信號。

          1.3  Large Class(過大類)

          如果想利用單一的class 做太多的事情,其內往往會出現太多的 instance 變量。

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

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

          過長的產生導致程序難以理解。

          1.5  Divergent Change(發散式變化)

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

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

          1.6  Shotgun Surgery(散彈式修改)

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

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

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

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

          1.7  Feature Envy(依戀情節)

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

          1.8  Data Clumps(數據泥團)

          數據泥團指的是總是綁定在一起出現的數據。

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

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

          1.9  Primitive Obsession(基本型別偏執)

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

          1.10  Switch Statements( switch 驚悚現身)

          使用面向對象編程,要少用switch 和 case 語句。而是用多態來替換它。

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

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

          1.12  Lazy Class(冗贅類)

          類顯得多余,沒有價值。

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

          這個往往是過度設計的結果:對某種變化的應對,而這種變化沒有發生。

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

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

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

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

          1.16  Middle Man(中間轉手人)

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

          1.17  Inappropriate Intimacy (親密關系)

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

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

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

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

          基礎類庫無法滿足實際的需求。

          1.20  Data Class(純稚的數據類)

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

          1.21  Refused Bequest(被拒絕的遺贈)

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

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

          1.22  Comments(過多的注釋)

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

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

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

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

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

          先拋開上面這個實例的設計思路,這里面反映出一個問題:軟件開發過程中,軟件體系結構同樣需要“重構”。

          結合經典的《重構》,這里簡單的寫一下軟件體系結構重構的定義,原因,設計,方法。僅作拋磚引玉,希望能和大家一起思考。

          何謂重構

          對軟件體系結構的一種調整,目的是在不改變其“外在行為”的前提下,調整其結構,使其易于修改,維護和理解。

          為何重構

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

          2、調整系統中各個模塊的功能,角色,使整個系統更容易理解。
          何時重構

          由于系統結構的重構成本非常高,所以要選擇一個合適的重構時機。

          1、為系統添加功能時重構。此時項目進度壓力如果非常大,這放棄此時重構。

          2、軟件第一個版本開發完畢后重構。在第一個版本開發完畢,第二個版本開發之前,根據第一個版本的開發經驗,對系統進行重構。

          3、開發出系統原型時進行重構。開發出一個系統的原型的時候,如果發現系統需要重構,這及時的進行,這個時候重構成本較低,但對是否重構決策要求較高。

          重構的必要條件

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

          重構與設計

          系統架構層次的重構,因為重構的成本相對較高,所以預先設計的程度要相對較深,要盡量考慮系統可能遇到的情況,方案要適當的靈活和強固。盡量減少系統結構的重構。

          軟件體系結構的重和代碼的重構的區別

          1、針對的層次不同:一個是系統結構層次的,一個是代碼層次的。

          2、重構成本不同,系統結構的重構成本相對較高。

          3、是否重構的決策者不同。

          4、重構的時機不同。

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

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

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

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

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

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

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

          1  構筑測試體系

          如果你想進行重構,首要前提就是要擁有一個可靠的測試環境。

          “編寫優良的測試程序,可以極大的提高我的編程速度,即使不進行重構也是如此?!?

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

          “Class 應該包含他們自己的測試代碼。”

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

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

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

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

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

          構建自我測試的代碼。

          1.2  JUnit測試框架( Testing Framew )

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

          單元測試和功能測試

          “每當你接獲臭蟲提報,請先撰寫一個單元測試來揭發這只臭蟲?!薄绾谓野l?這里需要根據報告準確定位。單元測試會對此有幫助嗎?

          1.3  添加更多的測試

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

          “測試應該是一種風險驅動(risk driven )行為,測試的目的是希望找出現在或未來的可能出現的錯誤?!?

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

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

          “編寫不是十分完美的測試并實際運行,好過對完美測試的無盡等待。”——我持懷疑態度。

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

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

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

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

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

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

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

          上一篇介紹了微內核流程引擎開發背景,這篇介紹它的功能描述。

          基本功能:

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

          2、對軟交換系統應用服務器的所有的接口都可以編輯。

          3、異常處理,實現補償機制。

          4、流程要支持:順序執行,分支處理,跳轉執行。

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


          擴展功能:

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

          2、實現一個流程引擎虛擬機。專門處理流程。

          3、支持業務以無狀態的形式開發。所有的狀態在腳本中定義。

          4、開發一個流程編輯界面。

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

          6、開發一個簡單的語言,實現快速流程編輯的功能。這里要實現一個編譯器,編譯結果就是流程腳本。

          7、實現一個方向編譯器,從流程腳本到流程開發語言。

          上面的這些功能有的已經實現,有的正在實現。后面我會詳細描述這些功能的設計與實現。

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

          我設計的流程引擎是腳步驅動的。腳本中定義了流程執行的環境,流程操作的對象,流程執行的步驟。下面是一個流程腳本的示例:

          <?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>
               //用戶對象描述中,號碼是必須的,是流程引擎和業務的交互唯一標識,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屬性表示流程的名稱,用于在程序中調用。

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

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

          4、<sequence>表示順序調用下面的節點。

          5、<invoke >表示調用節點。屬性“interface="make_call"”表示此節點調用的接口是make_call。make_call是在代碼中定義好的關鍵字,對應一個軟交換系統的接口。屬性“node”表示節點的唯一標識,在流程內部唯一,可以在流程跳轉的時候使用。 “object_user="obj_user"“表示make_call 接口操作的對象。有<object>創建。 calling_number="6699" original_number="123456" call_type="local_call"表示的是make_call接口調用時的數據。

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

          這個腳本的意思是,根據流程輸入的號碼,創建用戶對象,并且發起呼叫,對用戶進行放音。


          復雜的腳步定義:

          上面的是一個簡單的示例。為了能夠實現流程編輯,要考慮很多的情況,要能夠進行分支處理,跳轉執行,捕獲事件等。

          1、分支的實現

              <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秒為收到按鍵則認為用戶按鍵結束。

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

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

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

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


          2、跳轉的實現:

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

          表示此節點是一個跳轉節點,要跳轉到的下一個節點是play_voice_001。


          3、信號捕獲的實現:

                 <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>活動會等待一組相互排斥事件中的一個事件的發生,然后執行與發生的事件相關聯的活動。它會阻塞業務流程執行,以等待某一特定的事件發生,比如接收到一個合適的消息或超時警報響起。當其中任何一個事件被觸發后,業務流程就會繼續執行,pick也隨即完成了,不會再等待其他事件的發生。

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

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

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

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

          開發背景

          我們公司是主要從事企業語音方面產品的開發,主要產品比如:調度系統,指揮系統,電話會議系統,呼叫中心系統等。這些系統都有一個共同特點,就是涉及到呼叫,放音,收發按鍵,會場操作。我們的業務產品都是基于我們的軟交換系統之上構建的,軟交換系統的應用服務器向外提供這些服務。


          產生的問題

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

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

          由于我們的系統重新架構,正在開發軟交換API接口,所以我們試圖解決這個問題。

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

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

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

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


          新的思路

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

          揭秘jbpm流程引擎內核設計思想及構架

          微內核過程引擎的設計思路和構架

          微內核工作流引擎體系架構與部分解決方案參考

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


          使用開源還是自己開發

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

          1、JBPM是用java開發,我們公司的業務產品目前基本上都是c,和java交互不便。

          2、JBPM是針對企業工作流設計的,工作流和IVR導航一個重要的區別是,IVR導航對時效性要求很高。要求系統能夠及時響應。

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

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

          如果是現在的話,即便是決定自己開發,一會好好研究一下JBPM的源碼的。


          借鑒的其他思路

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

          在學習的不同的階段我們應該保持的心態:

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

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


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

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


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

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

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

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

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

          Copyright © 常高偉

          主站蜘蛛池模板: 芮城县| 新乐市| 图木舒克市| 沿河| 汉源县| 武陟县| 永胜县| 顺平县| 东丰县| 汝城县| 新乡县| 镇雄县| 达孜县| 施秉县| 巫溪县| 安阳市| 德兴市| 上饶市| 大庆市| 孝义市| 玛曲县| 长宁县| 大洼县| 通渭县| 长泰县| 武邑县| 林芝县| 乌兰察布市| 濮阳县| 西安市| 遂昌县| 临桂县| 墨脱县| 延庆县| 蒙城县| 普安县| 易门县| 同仁县| 台中县| 广南县| 白河县|