Linux中國

程序員的學習之路

要成為一名專業的程序員,你需要知道的事情多得令人吃驚:語言的細節、API、演算法、數據結構、系統和工具。這些東西一直在隨著時間變化——新的語言和編程環境不斷出現,似乎總有一些「每個人」都在使用的熱門的新工具或新語言。緊跟潮流,保持專業,這很重要。木匠需要知道如何為工作選擇合適的鎚子和釘子,並且要有能力筆直精準地釘入釘子。

與此同時,我也發現有一些理論和方法有著廣泛的應用場景,它們能使用幾十年。底層設備的性能和容量在這幾十年來增長了幾個數量級,但系統設計的思考方式還是互相有關聯的,這些思考方式比具體的實現更根本。理解這些重複出現的主題對分析與設計我們所負責的系統大有幫助。

謙卑和自我

這不僅僅局限於編程,但在編程這個持續發展的領域,一個人需要在謙卑和自我中保持平衡。總有新的東西需要學習,並且總有人能幫助你學習——如果你願意學習的話。一個人即需要保持謙卑,認識到自己不懂並承認它,也要保持自我,相信自己能掌握一個新的領域,並且能運用你已經掌握的知識。我見過的最大的挑戰就是一些人在某個領域深入專研了很長時間,「忘記」了自己擅長學習新的東西。最好的學習來自放手去做,建造一些東西,即便只是一個原型或者 hack。我知道的最好的程序員對技術有廣泛的認識,但同時他們對某個技術深入研究,成為了專家。而深入的學習來自努力解決真正困難的問題。

端到端觀點

1981 年,Jerry Saltzer、 Dave Reed 和 Dave Clark 在做網際網路和分散式系統的早期工作,他們提出了 端到端 end to end 觀點,並作出了經典的闡述。網路上的文章有許多誤傳,所以更應該閱讀論文本身。論文的作者很謙虛,沒有聲稱這是他們自己的創造——從他們的角度看,這只是一個常見的工程策略,不只在通訊領域中,在其他領域中也有運用。他們只是將其寫下來並收集了一些例子。下面是文章的一個小片段:

當我們設計系統的一個功能時,僅依靠端點的知識和端點的參與,就能正確地完整地實現這個功能。在一些情況下,系統的內部模塊局部實現這個功能,可能會對性能有重要的提升。

該論文稱這是一個「觀點」,雖然在維基百科和其他地方它已經被上升成「原則」。實際上,還是把它看作一個觀點比較好,正如作者們所說,系統設計者面臨的最難的問題之一就是如何在系統組件之間劃分責任,這會引發不斷的討論:怎樣在劃分功能時權衡利弊,怎樣隔離複雜性,怎樣設計一個靈活的高性能系統來滿足不斷變化的需求。沒有簡單的原則可以直接遵循。

互聯網上的大部分討論集中在通信系統上,但端到端觀點的適用範圍其實更廣泛。分散式系統中的「 最終一致性 eventual consistency 」就是一個例子。一個滿足「最終一致性」的系統,可以讓系統中的元素暫時進入不一致的狀態,從而簡化系統,優化性能,因為有一個更大的端到端過程來解決不一致的狀態。我喜歡橫向拓展的訂購系統的例子(例如亞馬遜),它不要求每個請求都通過中央庫存的控制點。缺少中央控制點可能允許兩個終端出售相同的最後一本書,所以系統需要用某種方法來解決這個問題,如通知客戶該書會延期交貨。不論怎樣設計,想購買的最後一本書在訂單完成前都有可能被倉庫中的叉車運出厙(LCTT 譯註:比如被其他人下單購買)。一旦你意識到你需要一個端到端的解決方案,並實現了這個方案,那系統內部的設計就可以被優化以利用這個解決方案。

事實上,這種設計上的靈活性可以優化系統的性能,或者提供其他的系統功能,從而使得端到端的方法變得如此強大。端到端的思考往往允許內部進行靈活的操作,使整個系統更加健壯,並且能適應每個組件特性的變化。這些都讓端到端的方法變得健壯,並能適應變化。

端到端方法意味著,添加會犧牲整體性能靈活性的抽象層和功能時要非常小心(也可能是其他的靈活性,但性能,特別是延遲,往往是特殊的)。如果你展示出底層的原始性能(LCTT 譯註:performance,也可能指操作,下同),端到端的方法可以根據這個性能(操作)來優化,實現特定的需求。如果你破壞了底層性能(操作),即使你實現了重要的有附加價值的功能,你也犧牲了設計靈活性。

如果系統足夠龐大而且足夠複雜,需要把整個開發團隊分配給系統內部的組件,那麼端到端觀點可以和團隊組織相結合。這些團隊自然要擴展這些組件的功能,他們通常從犧牲設計上的靈活性開始,嘗試在組件上實現端到端的功能。

應用端到端方法面臨的挑戰之一是確定端點在哪裡。 俗話說,「大跳蚤上有小跳蚤,小跳蚤上有更少的跳蚤……等等」。

關注複雜性

編程是一門精確的藝術,每一行代碼都要確保程序的正確執行。但這是帶有誤導的。編程的複雜性不在於各個部分的整合,也不在於各個部分之間如何相互交互。最健壯的程序會將複雜性隔離開,讓最重要的部分變的簡單直接,通過簡單的方式與其他部分交互。雖然隱藏複雜性和信息隱藏、數據抽象等其他設計方法一樣,但我仍然覺得,如果你真的要定位出系統的複雜所在,並將其隔離開,那你需要對設計特別敏銳。

在我的文章中反覆提到的例子是早期的終端編輯器 VI 和 Emacs 中使用的屏幕重繪演算法。早期的視頻終端實現了控制序列,來控制繪製字元核心操作,也實現了附加的顯示功能,來優化重新繪製屏幕,如向上向下滾動當前行,或者插入新行,或在當前行中移動字元。這些命令都具有不同的開銷,並且這些開銷在不同製造商的設備中也是不同的。(參見TERMCAP 以獲取代碼和更完整的歷史記錄的鏈接。)像文本編輯器這樣的全屏應用程序希望儘快更新屏幕,因此需要優化使用這些控制序列來從一個狀態到另一個狀態屏幕轉換。

這些程序在設計上隱藏了底層的複雜性。系統中修改文本緩衝區的部分(功能上大多數創新都在這裡)完全忽略了這些改變如何被轉換成屏幕更新命令。這是可以接受的,因為針對任何內容的改變計算最佳命令所消耗的性能代價,遠不及被終端本身實際執行這些更新命令的性能代價。在確定如何隱藏複雜性,以及隱藏哪些複雜性時,性能分析扮演著重要的角色,這一點在系統設計中非常常見。屏幕的更新與底層文本緩衝區的更改是非同步的,並且可以獨立於緩衝區的實際歷史變化順序。緩衝區是怎樣改變的並不重要,重要的是改變了什麼。非同步耦合,在組件交互時消除組件對歷史路徑依賴的組合,以及用自然的交互方式以有效地將組件組合在一起是隱藏耦合複雜度的常見特徵。

隱藏複雜性的成功不是由隱藏複雜性的組件決定的,而是由使用該模塊的使用者決定的。這就是為什麼組件的提供者至少要為組件的某些端到端過程負責。他們需要清晰的知道系統的其他部分如何與組件相互作用,複雜性是如何泄漏出來的(以及是否泄漏出來)。這常常表現為「這個組件很難使用」這樣的反饋——這通常意味著它不能有效地隱藏內部複雜性,或者沒有選擇一個隱藏複雜性的功能邊界。

分層與組件化

系統設計人員的一個基本工作是確定如何將系統分解成組件和層;決定自己要開發什麼,以及從別的地方獲取什麼。開源項目在決定自己開發組件還是購買服務時,大多會選擇自己開發,但組件之間交互的過程是一樣的。在大規模工程中,理解這些決策將如何隨著時間的推移而發揮作用是非常重要的。從根本上說,變化是程序員所做的一切的基礎,所以這些設計決定不僅要在當下評估,還要隨著產品的不斷發展而在未來幾年得到評估。

以下是關於系統分解的一些事情,它們最終會佔用大量的時間,因此往往需要更長的時間來學習和欣賞。

  • 層泄漏。層(或抽象)基本上是泄漏的。這些泄漏會立即產生後果,也會隨著時間的推移而產生兩方面的後果。其中一方面就是該抽象層的特性滲透到了系統的其他部分,滲透的程度比你意識到得更深入。這些滲透可能是關於具體的性能特徵的假設,以及抽象層的文檔中沒有明確的指出的行為發生的順序。這意味著假如內部組件的行為發生變化,你的系統會比想像中更加脆弱。第二方面是你比表面上看起來更依賴組件內部的行為,所以如果你考慮改變這個抽象層,後果和挑戰可能超出你的想像。
  • 層具有太多功能。您所採用的組件具有比實際需要更多的功能,這幾乎是一個真理。在某些情況下,你決定採用這個組件是因為你想在將來使用那些尚未用到的功能。有時,你採用組件是想「上快車」,利用組件完成正在進行的工作。在功能強大的抽象層上開發會帶來一些後果。
    1. 組件往往會根據你並不需要的功能作出取捨。
    2. 為了實現那些你並不沒有用到的功能,組件引入了複雜性和約束,這些約束將阻礙該組件的未來的演變。
    3. 層泄漏的範圍更大。一些泄漏是由於真正的「抽象泄漏」,另一些是由於明顯的,逐漸增加的對組件全部功能的依賴(但這些依賴通常都沒有處理好)。Office 軟體太大了,我們發現,對於我們建立的任何抽象層,我們最終都在系統的某個部分完全運用了它的功能。雖然這看起來是積極的(我們完全地利用了這個組件),但並不是所用的使用都有同樣的價值。所以,我們最終要付出巨大的代價才能從一個抽象層往另一個抽象層遷移,這種「長尾」沒什麼價值,並且對使用場景認識不足。
    4. 附加的功能會增加複雜性,並增加功能濫用的可能。如果將驗證 XML 的 API 指定為 XML 樹的一部分,那這個 API 可以選擇動態下載 XML 的模式定義。這在我們的基本文件解析代碼中被錯誤地執行,導致 w3c.org 伺服器上的大量性能下降以及(無意)分散式拒絕服務攻擊。(這些被通俗地稱為「地雷」API)。
  • 抽象層被更換。需求在進化,系統在進化,組件被放棄。您最終需要更換該抽象層或組件。不管是對外部組件的依賴還是對內部組件的依賴都是如此。這意味著上述問題將變得重要起來。
  • 自己構建還是購買的決定將會改變。這是上面幾方面的必然結果。這並不意味著自己構建還是購買的決定在當時是錯誤的。一開始時往往沒有合適的組件,一段時間之後才有合適的組件出現。或者,也可能你使用了一個組件,但最終發現它不符合您不斷變化的要求,而且你的要求非常窄、很好理解,或者對你的價值體系來說是非常重要的,以至於擁有自己的模塊是有意義的。這意味著你像關心自己構造的模塊一樣,關心購買的模塊,關心它們是怎樣泄漏並深入你的系統中的。
  • 抽象層會變臃腫。一旦你定義了一個抽象層,它就開始增加功能。層是對使用模式優化的自然分界點。臃腫的層的困難在於,它往往會降低您利用底層的不斷創新的能力。從某種意義上說,這就是操作系統公司憎恨構建在其核心功能之上的臃腫的層的原因——採用創新的速度放緩了。避免這種情況的一種比較規矩的方法是禁止在適配器層中進行任何額外的狀態存儲。微軟基礎類在 Win32 上採用這個一般方法。在短期內,將功能集成到現有層(最終會導致上述所有問題)而不是重構和重新推導是不可避免的。理解這一點的系統設計人員尋找分解和簡化組件的方法,而不是在其中增加越來越多的功能。

愛因斯坦宇宙

幾十年來,我一直在設計非同步分散式系統,但是在微軟內部的一次演講中,SQL 架構師 Pat Helland 的一句話震驚了我。 「我們生活在愛因斯坦的宇宙中,沒有同時性這種東西。」在構建分散式系統時(基本上我們構建的都是分散式系統),你無法隱藏系統的分散式特性。這是物理的。我一直感到遠程過程調用在根本上錯誤的,這是一個原因,尤其是那些「透明的」遠程過程調用,它們就是想隱藏分散式的交互本質。你需要擁抱系統的分散式特性,因為這些意義幾乎總是需要通過系統設計和用戶體驗來完成。

擁抱分散式系統的本質則要遵循以下幾個方面:

  • 一開始就要思考設計對用戶體驗的影響,而不是試圖在處理錯誤,取消請求和報告狀態上打補丁。
  • 使用非同步技術來耦合組件。同步耦合是不可能的。如果某些行為看起來是同步的,是因為某些內部層嘗試隱藏非同步,這樣做會遮蔽(但絕對不隱藏)系統運行時的基本行為特徵。
  • 認識到並且明確設計了交互狀態機,這些狀態表示長期的可靠的內部系統狀態(而不是由深度調用堆棧中的變數值編碼的臨時,短暫和不可發現的狀態)。
  • 認識到失敗是在所難免的。要保證能檢測出分散式系統中的失敗,唯一的辦法就是直接看你的等待時間是否「太長」。這自然意味著取消的等級最高。系統的某一層(可能直接通向用戶)需要決定等待時間是否過長,並取消操作。取消只是為了重建局部狀態,回收局部的資源——沒有辦法在系統內廣泛使用取消機制。有時用一種低成本,不可靠的方法廣泛使用取消機制對優化性能可能有用。
  • 認識到取消不是回滾,因為它只是回收本地資源和狀態。如果回滾是必要的,它必須實現成一個端到端的功能。
  • 承認永遠不會真正知道分散式組件的狀態。只要你發現一個狀態,它可能就已經改變了。當你發送一個操作時,請求可能在傳輸過程中丟失,也可能被處理了但是返回的響應丟失了,或者請求需要一定的時間來處理,這樣遠程狀態最終會在未來的某個任意的時間轉換。這需要像冪等操作這樣的方法,並且要能夠穩健有效地重新發現遠程狀態,而不是期望可靠地跟蹤分散式組件的狀態。「最終一致性」的概念簡潔地捕捉了這其中大多數想法。

我喜歡說你應該「陶醉在非同步」。與其試圖隱藏非同步,不如接受非同步,為非同步而設計。當你看到像冪等性或不變性這樣的技術時,你就認識到它們是擁抱宇宙本質的方法,而不僅僅是工具箱中的一個設計工具。

性能

我確信 Don Knuth 會對人們怎樣誤解他的名言「過早的優化是一切罪惡的根源」而感到震驚。事實上,性能,及性能的持續超過 60 年的指數增長(或超過 10 年,取決於您是否願意將晶體管,真空管和機電繼電器的發展算入其中),為所有行業內的驚人創新和影響經濟的「軟體吃掉全世界」的變化打下了基礎。

要認識到這種指數變化的一個關鍵是,雖然系統的所有組件正在經歷指數級變化,但這些指數是不同的。硬碟容量的增長速度與內存容量的增長速度不同,與 CPU 的增長速度不同,與內存 CPU 之間的延遲的性能改善速度也不用。即使性能發展的趨勢是由相同的基礎技術驅動的,增長的指數也會有分歧。延遲的改進跟不上帶寬改善。指數變化在近距離或者短期內看起來是線性的,但隨著時間的推移可能是壓倒性的。系統不同組件的性能的增長不同,會出現壓倒性的變化,並迫使對設計決策定期進行重新評估。

這樣做的結果是,幾年後,一度有意義的設計決策就不再有意義了。或者在某些情況下,二十年前有意義的方法又開始變成一個好的決策。現代內存映射的特點看起來更像是早期分時的進程切換,而不像分頁那樣。 (這樣做有時會讓我這樣的老人說「這就是我們在 1975 年時用的方法」——忽略了這種方法在 40 年都沒有意義,但現在又重新成為好的方法,因為兩個組件之間的關係——可能是快閃記憶體和 NAND 而不是磁碟和核心內存——已經變得像以前一樣了)。

當這些指數超越人自身的限制時,重要的轉變就發生了。你能從 2 的 16 次方個字元(一個人可以在幾個小時打這麼多字)過渡到 2 的 32 次方個字元(遠超出了一個人打字的範圍)。你可以捕捉比人眼能感知的解析度更高的數字圖像。或者你可以將整個音樂專輯存在小巧的磁碟上,放在口袋裡。或者你可以將數字化視頻錄製存儲在硬碟上。再通過實時流式傳輸的能力,可以在一個地方集中存儲一次,不需要在數千個本地硬碟上重複記錄。

但有的東西仍然是根本的限制條件,那就是空間的三維和光速。我們又回到了愛因斯坦的宇宙。內存的分級結構將始終存在——它是物理定律的基礎。穩定的存儲和 IO、內存、計算和通信也都將一直存在。這些模塊的相對容量,延遲和帶寬將會改變,但是系統始終要考慮這些元素如何組合在一起,以及它們之間的平衡和折衷。Jim Gary 是這方面的大師。

空間和光速的根本限制造成的另一個後果是,性能分析主要是關於三件事: 局部化 locality 局部化 locality 局部化 locality 。無論是將數據打包在磁碟上,管理處理器緩存的層次結構,還是將數據合併到通信數據包中,數據如何打包在一起,如何在一段時間內從局部獲取數據,數據如何在組件之間傳輸數據是性能的基礎。把重點放在減少管理數據的代碼上,增加空間和時間上的局部性,是消除雜訊的好辦法。

Jon Devaan 曾經說過:「設計數據,而不是設計代碼」。這也通常意味著當查看系統結構時,我不太關心代碼如何交互——我想看看數據如何交互和流動。如果有人試圖通過描述代碼結構來解釋一個系統,而不理解數據流的速率和數量,他們就不了解這個系統。

內存的層級結構也意味著緩存將會一直存在——即使某些系統層正在試圖隱藏它。緩存是根本的,但也是危險的。緩存試圖利用代碼的運行時行為,來改變系統中不同組件之間的交互模式。它們需要對運行時行為進行建模,即使模型填充緩存並使緩存失效,並測試緩存命中。如果模型由於行為改變而變差或變得不佳,緩存將無法按預期運行。一個簡單的指導方針是,緩存必須被檢測——由於應用程序行為的改變,事物不斷變化的性質和組件之間性能的平衡,緩存的行為將隨著時間的推移而退化。每一個老程序員都有緩存變糟的經歷。

我很幸運,我的早期職業生涯是在互聯網的發源地之一 BBN 度過的。 我們很自然地將將非同步組件之間的通信視為系統連接的自然方式。流量控制和隊列理論是通信系統的基礎,更是任何非同步系統運行的方式。流量控制本質上是資源管理(管理通道的容量),但資源管理是更根本的關注點。流量控制本質上也應該由端到端的應用負責,所以用端到端的方式思考非同步系統是自然的。緩衝區膨脹的故事在這種情況下值得研究,因為它展示了當對端到端行為的動態性以及技術「改進」(路由器中更大的緩衝區)缺乏理解時,在整個網路基礎設施中導致的長久的問題。

我發現「 光速 light speed 」的概念在分析任何系統時都非常有用。光速分析並不是從當前的性能開始分析,而是問「這個設計理論上能達到的最佳性能是多少?」真正傳遞的信息是什麼,以什麼樣的速度變化?組件之間的底層延遲和帶寬是多少?光速分析迫使設計師深入思考他們的方法能否達到性能目標,或者否需要重新考慮設計的基本方法。它也迫使人們更深入地了解性能在哪裡損耗,以及損耗是由固有的,還是由於一些不當行為產生的。從構建的角度來看,它迫使系統設計人員了解其構建的模塊的真實性能特徵,而不是關注其他功能特性。

我的職業生涯大多花費在構建圖形應用程序上。用戶坐在系統的一端,定義關鍵的常量和約束。人類的視覺和神經系統沒有經歷過指數性的變化。它們固有地受到限制,這意味著系統設計者可以利用(必須利用)這些限制,例如,通過虛擬化(限制底層數據模型需要映射到視圖數據結構中的數量),或者通過將屏幕更新的速率限制到人類視覺系統的感知限制。

複雜性的本質

我的整個職業生涯都在與複雜性做鬥爭。為什麼系統和應用變得複雜呢?為什麼在一個應用領域內進行開發並沒有隨著時間變得簡單,而基礎設施卻沒有變得更複雜,反而變得更強大了?事實上,管理複雜性的一個關鍵方法就是「走開」然後重新開始。通常新的工具或語言迫使我們從頭開始,這意味著開發人員將工具的優點與從新開始的優點結合起來。從新開始是重要的。這並不是說新工具,新平台,或新語言可能不好,但我保證它們不能解決複雜性增長的問題。控制複雜性的最簡單的方法就是用更少的程序員,建立一個更小的系統。

當然,很多情況下「走開」並不是一個選擇——Office 軟體建立在有巨大的價值的複雜的資源上。通過 OneNote, Office 從 Word 的複雜性上「走開」,從而在另一個維度上進行創新。Sway 是另一個例子, Office 決定從限制中跳出來,利用關鍵的環境變化,抓住機會從底層上採取全新的設計方案。我們有 Word、Excel、PowerPoint 這些應用,它們的數據結構非常有價值,我們並不能完全放棄這些數據結構,它們成為了開發中持續的顯著的限制條件。

我受到 Fred Brook 討論軟體開發中的意外和本質的文章《沒有銀彈》的影響,他希望用兩個趨勢來儘可能地推動程序員的生產力:一是在選擇自己開發還是購買時,更多地關注購買——這預示了開源社區和雲架構的改變;二是從單純的構建方法轉型到更「有機」或者「生態」的增量開發方法。現代的讀者可以認為是向敏捷開發和持續開發的轉型。但那篇文章可是寫於 1986 年!

我很欣賞 Stuart Kauffman 的在複雜性的基本性上的研究工作。Kauffman 從一個簡單的布爾網路模型(「NK 模型」)開始建立起來,然後探索這個基本的數學結構在相互作用的分子,基因網路,生態系統,經濟系統,計算機系統(以有限的方式)等系統中的應用,來理解緊急有序行為的數學基礎及其與混沌行為的關係。在一個高度連接的系統中,你固有地有一個相互衝突的約束系統,使得它(在數學上)很難向前發展(這被看作是在崎嶇景觀上的優化問題)。控制這種複雜性的基本方法是將系統分成獨立元素並限制元素之間的相互連接(實質上減少 NK 模型中的「N」和「K」)。當然對那些使用複雜隱藏,信息隱藏和數據抽象,並且使用鬆散非同步耦合來限制組件之間的交互的技術的系統設計者來說,這是很自然的。

我們一直面臨的一個挑戰是,我們想到的許多拓展系統的方法,都跨越了所有的方面。實時共同編輯是 Office 應用程序最近的一個非常具體的(也是最複雜的)例子。

我們的數據模型的複雜性往往等同於「能力」。設計用戶體驗的固有挑戰是我們需要將有限的一組手勢,映射到底層數據模型狀態空間的轉換。增加狀態空間的維度不可避免地在用戶手勢中產生模糊性。這是「純數學」,這意味著確保系統保持「易於使用」的最基本的方式常常是約束底層的數據模型。

管理

我從高中開始擔任一些領導角色(學生會主席!),對承擔更多的責任感到理所當然。同時,我一直為自己在每個管理階段都堅持擔任全職程序員而感到自豪。但 Office 軟體的開發副總裁最終還是讓我從事管理,離開了日常的編程工作。當我在去年離開那份工作時,我很享受重返編程——這是一個出奇地充滿創造力的充實的活動(當修完「最後」的 bug 時,也許也會有一點令人沮喪)。

儘管在我加入微軟前已經做了十多年的「主管」,但是到了 1996 年我加入微軟才真正了解到管理。微軟強調「工程領導是技術領導」。這與我的觀點一致,幫助我接受並承擔更大的管理責任。

主管的工作是設計項目並透明地推進項目。透明並不簡單,它不是自動的,也不僅僅是有好的意願就行。透明需要被設計進系統中去。透明工作的最好方式是能夠記錄每個工程師每天活動的產出,以此來追蹤項目進度(完成任務,發現 bug 並修復,完成一個情景)。留意主觀上的紅/綠/黃,點贊或踩的儀錶板。

我過去說我的工作是設計反饋迴路。獨立工程師,經理,行政人員,每一個項目的參與者都能通過分析記錄的項目數據,推進項目,產出結果,了解自己在整個項目中扮演的角色。最終,透明化最終成為增強能力的一個很好的工具——管理者可以將更多的局部控制權給予那些最接近問題的人,因為他們對所取得的進展有信心。這樣的話,合作自然就會出現。

關鍵需要確定目標框架(包括關鍵資源的約束,如發布的時間表)。如果決策需要在管理鏈上下不斷流動,那說明管理層對目標和約束的框架不好。

當我在 Beyond Software 工作時,我真正理解了一個項目擁有一個唯一領導的重要性。原來的項目經理離職了(後來從 FrontPage 團隊僱傭了我)。我們四個主管在是否接任這個崗位上都有所猶豫,這不僅僅由於我們都不知道要在這家公司堅持多久。我們都技術高超,並且相處融洽,所以我們決定以同級的身份一起來領導這個項目。然而這槽糕透了。有一個顯而易見的問題,我們沒有相應的戰略用來在原有的組織之間分配資源——這應當是管理者的首要職責之一!當你知道你是唯一的負責人時,你會有很深的責任感,但在這個例子中,這種責任感缺失了。我們沒有真正的領導來負責統一目標和界定約束。

我有清晰地記得,我第一次充分認識到傾聽對一個領導者的重要性。那時我剛剛擔任了 Word、OneNote、Publisher 和 Text Services 團隊的開發經理。關於我們如何組織文本服務團隊,我們有一個很大的爭議,我走到了每個關鍵參與者身邊,聽他們想說的話,然後整合起來,寫下了我所聽到的一切。當我向其中一位主要參與者展示我寫下的東西時,他的反應是「哇,你真的聽了我想說的話」!作為一名管理人員,我所經歷的所有最大的問題(例如,跨平台和轉型持續工程)涉及到仔細傾聽所有的參與者。傾聽是一個積極的過程,它包括:嘗試以別人的角度去理解,然後寫出我學到的東西,並對其進行測試,以驗證我的理解。當一個關鍵的艱難決定需要發生的時候,在最終決定前,每個人都知道他們的想法都已經被聽到並理解(不論他們是否同意最後的決定)。

在 FrontPage 團隊擔任開發經理的工作,讓我理解了在只有部分信息的情況下做決定的「操作困境」。你等待的時間越長,你就會有更多的信息做出決定。但是等待的時間越長,實際執行的靈活性就越低。在某個時候,你僅需要做出決定。

設計一個組織涉及類似的兩難情形。您希望增加資源領域,以便可以在更大的一組資源上應用一致的優先順序劃分框架。但資源領域越大,越難獲得作出決定所需要的所有信息。組織設計就是要平衡這兩個因素。軟體複雜化,因為軟體的特點可以在任意維度切入設計。Office 軟體部門已經使用共享團隊來解決這兩個問題(優先次序和資源),讓跨領域的團隊能與需要產品的團隊分享工作(增加資源)。

隨著管理階梯的提升,你會懂一個小秘密:你和你的新同事不會因為你現在承擔更多的責任,就突然變得更聰明。這強調了整個組織比頂層領導者更聰明。賦予每個級別在一致框架下擁有自己的決定是實現這一目標的關鍵方法。聽取並使自己對組織負責,闡明和解釋決策背後的原因是另一個關鍵策略。令人驚訝的是,害怕做出一個愚蠢的決定可能是一個有用的激勵因素,以確保你清楚地闡明你的推理,並確保你聽取所有的信息。

結語

我離開大學尋找第一份工作時,面試官在最後一輪面試時問我對做「系統」和做「應用」哪一個更感興趣。我當時並沒有真正理解這個問題。在軟體技術棧的每一個層面都會有趣的難題,我很高興深入研究這些問題。保持學習。

via: https://hackernoon.com/education-of-a-programmer-aaecf2d35312

作者:Terry Crowley 譯者:explosic4 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國