1. 程式人生 > >《Web全棧工程師的自我修養》濃縮筆記(上)

《Web全棧工程師的自我修養》濃縮筆記(上)

《Web全棧工程師的自我修養》濃縮筆記(上)

2017.03.16 21:45 13917瀏覽  

圖片描述
本書的作者餘果,騰訊社交使用者體驗設計部高階UI工程師,前端開發組負責人,熟悉前端開發、iOS開發、PHP開發和Ruby開發等。這本書所講的內容適合所程式設計師,不限於前端後端客戶端,很多內容其實都是常識。第二遍閱讀,特此整理此書精華內容筆記。

一、什麼是全棧工程師?

對於全棧工程師 ,業界並沒有嚴格的定義 ,並不是說一定要一種都不能少地具備哪幾項知識才能叫做全棧工程師 。我傾向於認為 ,應該從能力和思維方式兩方面 ,來判定一個人是否是一個合格的全棧工程師 。

國外是怎麼樣定義的呢?在著名的問答網站Quora上有一個高票的回答:

全棧工程師是指 ,一個能處理資料庫 、伺服器 、系統工程和客戶端的所有工作的工程師 。根據專案的不同 ,客戶需要的可能是移動棧 、 Web棧 ,或者原生應用程式棧 。

簡單來說 ,全棧工程師就是可以獨立完成一個產品的人 。當客戶讓他去做一些舒適區之外的工作時 ,他敢於迎難而上 ,併成功完成任務 。

“各司其職”的弊端

雖然流水線式的職業劃分和工程管理有很多優點,但是它就像一把雙刃劍,在帶來高可控性、可用性和可管理性的同時,也給工程師帶來了一些困境。

1. 工程師職責不清導致效率低下

2. 工程師缺乏主人感導致產品質量差

3. 工程師缺乏全域性的視野影響個人成長
當工程師希望晉升到更高階的職位 ,如高階工程師或者管理崗位時 ,公司對他的大局觀會有更高的要求 ,這就不僅僅是做好 “分內 ”的工作就行的 。高階工程師需要有對設計的理解 、對後臺知識的瞭解 ,以及有跨團隊推動專案的能力 。長期研究專精的專業知識會讓一個人視野變窄 ,變成 “學術派 ” ,而不是 “實踐派 ” 。

4. 更多角色導致專案效率低下

全棧工程師登上舞臺

因為各司其職的工作流程有效率低下 、成本高的缺點 ,所以很多創業公司都不會配備齊全的流水線 ,而是希望採用更靈活的方式來組建團隊 ,全棧工程師也因此成為了理想的選擇 。但是全棧工程師的興起還離不開這兩個重要因素 :技術的發展 ,以及提供 PaaS服務的平臺越來越多 。

全棧工程師基本要有的覺悟

而我推崇的全棧工程師則是與專精工程師不同的另一條道路 。全棧工程師除了在一個專精知識領域有深入研究之外 ,還以知識廣博和解決問題能力強著稱 。所以我認為有志成為全棧工程師的學習者 ,要有這樣幾個覺悟 。

1. 一專多長
一專多長的意思是 ,工程師首先有一個專精的方向 ,在這個方向上足夠精通之後 (高階工程師級別 ) ,以此為突破點去學習更多的知識 ,增加自己的長處 。如果還沒有獲得某個方向上足夠深入的理解 ,就不要囫圇吞棗地去學習其他領域的知識 。

2. 解決問題,而不是醉心技術

二、如何成為全棧工程師

先精後廣,一專多長

“先精後廣 ,一專多長 ”是指 ,建議初學者學習全棧技能的時候 ,先在一個特定的方向上有比較深入的鑽研 ,然後再將學習目標漸漸推廣開來 。比如先從前端方向入手 ,掌握了基本的 HTMLCSS 、JavaScript之後 ,不要轉頭向伺服器端語言或者 App 方向發展 ,而是深入到效能優化 、 SEO 、多種框架 、響應式頁面等前端細節中去 。經過一到兩年的深入研究之後 ,再去學習其他方向 。

如果是畢業生或者初學者 ,我不建議在剛開始的一到兩年接觸太多技術 ,雜而不精 ,結果可能會對後面的職業道路產生副作用 。

為什麼要強調在開始的時候要專精方向的重要性呢?因為這樣您才能在求職的時候有一個“亮點”。

無論是畢業生還是社會招聘 ,僅僅滿足招聘要求是不夠的 。您需要在招聘要求的方向上以 200%的能力來得到這個職位 。一個求職者在整個流程中會受到多方考核 : HR考核您的成本和價值 ,專業面試官 (不是全棧工程師 )考核您的專業能力 ,經理考核您的溝通能力 。在所有這些考核中 ,其實每一環都是漏斗型篩選 ,會過濾掉一些人 。

讓我再次重複這一點 ,作為求職者 ,一定要在某個特定方向上有非常深入的理解 。僅僅會做還不夠 ,還要理解背後的原因 ,還有背後的背後的原因 。

圍繞商業目標

我的第一條建議是 ,在考慮做什麼專案的時候 ,圍繞商業利益作為目標 。歸根結底 ,技術是服務於商業目標的 。

老闆僱用一個員工 ,不是因為他能寫程式 ,而是因為他能幫助自己賺錢 。賺錢有兩種方法 :減少成本 ,或者增加收入 。程式設計師如果能加快內部系統的執行效率 ,讓產品製作流程更加順暢 ,就是減少成本 。如果能讓使用者更容易地購買產品 ,或者提高服務質量吸引更多使用者 ,就能增加收入 。在老闆看來 ,程式設計師只是一個昂貴的勞動力 ,他會不會寫程式都沒那麼重要 ,重要的是能賺錢 。

所以如果您想成為一個高階開發者 (或者高階設計師 ) ,就一定要學會這種思維方式 。

所謂 “商業目標 ”要廣義地去解讀 。對於直接製作產品 ,給使用者使用的團隊 ,就需要對外關注如何提高產品質量 、降低產品成本 ;對內應該關注如何優化流程 、減少錯誤率 。如果團隊輸出的成果是公司內其他部門需要的原材料 ,就要關注下游的需求 ,研究如何更好地輸出成果 ,如何在流程上使得輸出產品的過程更順暢 。

關注商業目標需要持久的練習 。等到自己成為全棧工程師 ,或者成為團隊管理者 ,更加需要在多個目標任務之中做出選擇 。全棧工程師需要做和能夠做的事情是很多的 ,他會很多技能 ,也負責處理很多工作 ,所以他更需要能力從諸多事情中找到最有商業價值的一個 :可能是製作一款工具提升團隊效率 ,也可能是成本上的優化 。

全棧工程師可以做得事情越多 ,就越需要具備判斷做什麼的能力 。如果增加一個使用者需要的功能是加分項的話 ,拒絕一個使用者不需要的需求更加值得推崇 。

一切都要圍繞商業目標來進行 ,包括您做的專案 、您的彙報方式 ,以及您在學習新技能時進行的取捨 。永遠從商業目標的角度來決定學習哪些東西 ,而不是純粹為了鍛鍊技術能力而去學習 。

關注使用者體驗

  • 每一個糟糕的體驗背後都蘊藏著商機(騰訊HR的故事)
  • 使用者是誰
  • 大巧若拙
    意思是指,真正聰明的人,不會顯露自己,反而從表面上看好像還很笨拙
  • 做自己會用的產品

我如果開創一個公司需要招聘 “全棧工程師 ” ,我要求的三個能力就是一專多長 、關注商業目標 、關注使用者體驗 。

三、工程師事業指南

技術、成長和聲望

軟體工程師事業指南告訴您 ,最核心的 3個詞就是技術 、成長和聲望 。技術是您的武器 ,成長就是好好打磨武器 ,而聲望是您一生的積累 。怎樣獲得良好的聲望 ?很簡單 ——答應做的事 ,全部都要完成 。

那如果上司真的給出一個非常棘手的問題 ,您該如何回答 ?沒錯 ,您不能直接拒絕 。拒絕上司是很困難的 。但您也不能什麼都答應下來 ,隨後又無法完成任務 。那時候您會丟掉更多的得分 。正確的方法是 ,講出事實 。

積累作品集

四、全棧工程師眼中的HTTP

HTTP簡介

1. OSI七層模型
OSI模型義了整個世界計算機相互連線的標準,總共分為 7層 ,其中最上層 (也就是第 7層 )就是應用層 , HTTP 、HT TPS、FTP、TELNET、SSH、SMTP和POP3都屬於應用層 。這是軟體工程師最關心的一層 。 SI模型越靠近底層 ,就越接近硬體 。在 HTTP協議中 ,並沒有規定必須使用它或它支援的層 。事實上 , HTTP可以在任何網際網路協議或其他網路上實現 。 HTTP假定其下層協議提供可靠的傳輸 ,因此 ,任何能夠提供這種保證的協議都可以被其使用 ,也就是其在 T CP / IP協議族使用 TCP作為其傳輸層 。
OSI七層模型

2. 關於HTTP版本
1999年釋出HTTP1.1,比1.0它增加了快取處理和持續連線,以及其他一些效能優化。

2015年2月,HTTP/2正式釋出 。新的 HTTP版本有一些重大更新 ,除了一如既往地向下相容 HTTP/1以外 ,還有一些優化 ,比如減小網路傳輸延遲 ,並簡化伺服器向瀏覽器傳輸內容的過程 。主流的伺服器 (Apache 、Nginx等 )和瀏覽器 (Firefox、Chrome、Safari以及 iOS和Android的瀏覽器等 )的最新版都已經支援 HTTP/2 ,剩下的就需要網站管理員把伺服器升級到最新版了 。

前端視角

每一個前端工程師都知道的基本優化方法是:儘量減少統一域下的HTTP請求數,以及儘量減少每個資源的體積。

儘量減少統一域下的HTTP請求數
瀏覽器常常限定了對同一域名發起的併發連線數的上限 。 各種瀏覽器普遍把這一上限設定為 4至 8個 。如果瀏覽器需要對某個域進行更多的連線 ,則需要在用完了當前連線之後 ,重複使用或者重新建立 T C P連線 。

由於瀏覽器針對資源的域名限制併發連線數 ,而不是針對瀏覽器位址列中的頁面域名 ,所以很多靜態資源可以放在其他域名下 (不同的子域名也被認為是不同的域名 ) 。如果您只有一臺伺服器 ,可以把這些不同的域名同時指向一個 I P ,也就提高了對這臺伺服器的併發連線數限制 (不過要小心伺服器壓力過大 ) 。

把靜態資源放在非主域名下 ,這種做法除了可以增加瀏覽器併發 ,還有一個好處是 ,減少HTTP請求中攜帶的不必要的cookie資料 ,因為這對頻寬和連結熟讀都造成了影響,所以我們一般把靜態資源放在單獨的域名下。

儘量減少每一個資源的體積
我們不光要限制請求數 ,還要儘量減少每一個資源的體積。因為資源的體積越大 ,在傳輸中消耗的流量就越多 ,等待時間也越久 。

在面試應聘者的時候,我會問的一個基礎題目是 “常用的圖片格式有哪些 ,它們的使用場景是什麼 ” 。如果能選擇合適的圖片格式 ,就能夠用更小的體積 ,達到更好的顯示效果 。對圖片格式的敏感 ,能反映出工程師對頻寬和速度的不懈追求 。此外 ,對於比較大的文字資源 ,必須開啟 gzip壓縮 。因為 gzip 對於含有重複 “單詞 ”的文字檔案 ,壓縮率非常高 ,能有效提高傳輸過程 。

後臺視角

前端工程師對HTTP的關注點在於儘量減少同一域下的HTTP請求數 ,以及儘量減少每一個資源的體積 。與之不同 ,後臺工程師對於HTTP的關注在於讓伺服器儘快響應請求 ,以及減少請求對伺服器的開銷 。

提高伺服器的請求處理能力
Apache是市場份額最大的伺服器 ,超過 50%的網站執行在Apache上 。Apache通過模組化的設計來適應各種環境 ,其中一個模組叫做多處理模組(MPM)專門用來處理多請求的情況 。Apache安裝在不同系統上的時候會呼叫不同的預設MPM ,我們不用關心具體的細節,只需要瞭解Unix上預設的MPM是prefork。為了優化,我們可以改成worker模式 。

preforkworker模式的最大區別就是 ,prefork的一個程序維持一個連線 ,而worker的一個執行緒維持一個連線 。所以prefork更穩定但記憶體消耗也更大 ,worker沒有那麼穩定 ,因為很多連線的執行緒共享一個程序 ,當一個執行緒崩潰的時候 ,整個程序和所有執行緒一起死掉 。但是worker的記憶體使用要比prefork低得多 ,所以很適合用在高HTTP請求的伺服器上 。

在高連線併發的情況下 ,Nginx是Apache伺服器不錯的替代品或者補充 :一方面是Nginx更加輕量級 ,佔用更少的資源和記憶體;另一方面是Nginx處理請求是非同步非阻塞的 ,而Apache則是阻塞型的 ,在高併發下Nginx能保持低資源 、低消耗和高效能 。由於Apache和Nginx各有所長 ,所以經常的搭配是Nginx處理前端併發 ,Apache處理後臺請求 。值得一提的是 ,新秀Node.js也是採用基於事件的非同步非阻塞方式處理請求 ,所以在處理高併發請求上有天然的優勢 。

DDos攻擊
DDos是Distributed Denialof Service的縮寫,DDos攻擊翻譯成中文就是 “分散式拒絕服務 ”攻擊 。

攻擊者通過海量的請求 ,讓目標伺服器癱瘓 ,無法響應正常的使用者請求 ,以此達到攻擊的效果 。對於這樣的攻擊 ,幾乎沒有什麼特別好的防護方法 。除了增加頻寬和提高伺服器能同時接納的客戶數 ,另一種方法就是讓首頁靜態化 。

DDos攻擊者喜歡攻擊的頁面一般是會對資料庫進行寫操作的頁面,這樣的頁面無法靜態化,伺服器更容易宕機 。DDos攻擊者一般不會攻擊靜態化的頁面或者圖片,因為靜態資源對伺服器壓力小,而且能夠部署在CDN上 。

BigPipe
通俗來解釋,BigPipe首先把HTML頁面分為很多部分 ,然後在伺服器和瀏覽器之間建立一條管道 (BigPipe就是 “大管道 ”的意思 ) ,HTML的不同部分可以源源不斷地從伺服器傳輸到瀏覽器 。BigPipe首先輸送的內容是框架性HTML結構 ,這個框架結構可能會定義每個Pagelet模組的位置和寬高 ,但是這些Pagelet都是空的,就像只有鋼筋混泥土骨架的毛坯房 。

接下來管道里源源不斷地傳輸過來很多模組 ,這時候最開始載入在伺服器中的JS程式碼開始工作 ,它會負責把每一個模組依次渲染到頁面上,在使用者的感知上,頁面非常快地出現在眼前 ,但是所有的模組都顯示正在載入中 ,然後主要的區域 (比如重要的使用者動態 )優先出現,接下來是logo、邊欄和各種掛件等 。

為什麼BigPipe能夠讓伺服器對瀏覽器說“我這個請求還沒結束,我們保持這個連結不要斷開”呢?答案是HTTP1.1的分塊傳輸編碼。

HTTP1.1引入分塊傳輸編碼 ,允許伺服器為動態生成的內容維持HTTP持久連結。如果一個HTTP訊息(請求訊息或應答訊息)的Transfer Encoding訊息頭的值為chunked,那麼訊息體由數量不確定的塊組成 ——也就是說想傳送多少塊就傳送多少塊 ——並以最後一個大小為0的塊為結束 。

五、高效能網站的關鍵——快取

1. 伺服器快取

基本的資料庫查詢快取
MySQL預設不開啟查詢快取 ,但我們可以通過修改MySQL安裝目錄中的 my.ini來設定查詢快取 。設定的時候可以根據實際情況配置緩衝區大小 、單個查詢的緩衝區大小等 。

可以在MySQL配置中增加這兩項

query_cache_size = SIZE 

SIZE是指為查詢快取開闢多大的空間 。預設是 0 ,也就是禁用查詢快取。

query_cache_type = OPTION

設定查詢快取的型別 ,可選的值有以下這三種 。

  • 0:設定查詢快取的型別 ,可選的值
  • 1:所有的快取結果都快取起來 ,除非查詢命令以 SELECTS_NO_CACHE 開始 。
  • 2:只快取查詢命令以 SELECT SQL_CACHE開始的查詢結果 。

所以 ,對於查詢操作遠遠多於修改操作的資料庫 ,開啟資料庫查詢快取是很有益的 ;但是對於修改操作很多的資料庫 ,由於快取經常會失效 ,就起不到加速的效果 。不僅如此 ,由於資料庫要花費時間寫快取 ,所以實際上速度更慢了 。

這裡需要注意的是 ,兩次 SQL 文字必須完全相同 。如果前後兩次查詢使用了不同的查詢條件 ,就會重新查詢 。

擴充套件資料庫快取:memcached
memcached的快取失效採用的是按時間來過期的設計 。memcached相當於應用程式和資料庫之間的中間層 ,通過網路 API設定和呼叫 。memcached儲存的是名值對 ,而且設定了一個過期時間 ,只要過期時間沒有到 ,應用程式就會從memcached中獲取資料 。這時候即使發生了資料庫更新操作 ,快取的查詢結果也仍然是之前儲存的舊資料 ,直到設定的時間過期 。這樣提高了快取的效能 ,帶來的影響就是 ,資料可能是 “不新鮮 ”的 。

但是 memcached 也不是總是那麼有效,因為如果只有一臺伺服器,就用不到它的伺服器叢集的優勢,反而讓系統更慢 。

再加一層檔案快取
除了可以將資料庫查詢結果快取在記憶體中還可以將被頻繁造訪的資料快取在檔案中。檔案 I/O 比起記憶體有以下幾個好處。硬碟容量比記憶體大,所以可以快取更多資料。資料更安全,斷電之後資料還在。易於擴充套件,硬碟不夠用的時候還可以新增硬碟。但是檔案快取沒有記憶體快取快,只能作為記憶體快取的補充,在獲取資料時,先從最快的地方讀取,如果沒有就繼續往後找。查詢優先順序為:記憶體快取 檔案快取 資料庫 。

快取檔案不會過期,除非您刪掉它,否則任何被快取了的查詢會一直存在。快取系統允許您按頁面清除,或把所有快取都清除掉 。一般來說,您可以在某些事件(比如向資料庫添加了資料 )發生時用特定的函式來清除快取 。

靜態化
有兩種靜態化的方法,其中一種是類似 WordPress 的靜態化外掛,安裝很簡單,每次有新文章就自動生成靜態頁面。這種方法還是將資料儲存在資料庫中,只是會讀取資料庫之後生成一些靜態頁。這一種方法的原理跟檔案快取很相似 。

另一種方法就是直接拋棄資料庫 。比如有一些部落格作者會用 Jekyll 系統來寫部落格,將整個部落格站點靜態化。完全拋棄資料庫的好處是,可以將生成的靜態網頁直接託管在靜態資源站點,比如 GitHub Pages 或者 Amazon S3,而不用操心資料庫伺服器的問題,不光整個系統穩定很多,費用上也更加低廉 (GitHub更是完全免費的,而且提交 Markdown 原始碼後可以讓它在伺服器端生成站點) 。

2. 瀏覽器快取

當瀏覽器訪問一個站點的時候,網路連線是主要瓶頸,我們可以通過設定瀏覽器快取來跳過 HTTP請求。如果在瀏覽器設定快取,通常有兩個主要作用。

  • 使用者來說,減少請求可以更快地載入頁面,節省流量。如果使用者是在手機上用3G或4G訪問頁面,這一點就很關鍵。
  • 對網站來說,減少頻寬壓力和費用。假設有1億的訪問量,如果能把大小為 10KB的 CSS快取起來,可以節省不小的開支。

主要的兩種快取指令
第一種:Expires
這種快取是最快的,因為沒有任何 HTTP請求發生。當用戶需要這個資源,瀏覽器就直接從快取中讀取,不再需要詢問伺服器端的意見(伺服器端甚至不知道您在瀏覽 image.png) 。所以 HttpWatch是推薦對所有的靜態資源都設定Expires 。

第二種:Last-Modified
通過這種快取方式 ,無論資源是否發生了更新 ,仍然至少會發生一來一去 HTTPS 頭的傳輸和接收 ,所以速度比不上Expires 。

從伺服器端的角度來看 ,有時候我們並不希望對靜態資源的請求中大部分都返回304。因為這可能說明我們的很多使用者都在頻繁訪問站點 ,而且我們的資源很少更新 ,就好像它們一直問 “資源修改了嗎? ” ,我們一直回答 “沒有修改 ” 。這裡可以使用Expires來設定過期時間 ,這樣它們就不會 “煩我們 ”了 。對於伺服器管理員來說,保持304為一個合理的比例即可 。我們可以通過檢視伺服器的log ,檢視304響應與200響應的比例,來做出一個合理的快取策略 。

Restful Web API
表徵性狀態傳輸(Representational State Transfer,REST)是一種軟體架構風格。在 3種主流的Web服務實現方案中,因為REST模式最簡潔,也能合理地利用HTTP操作的語義,所以越來越多的Web服務開始採用REST風格設計和實現 。

Restful的目的是定義如何正確地使用Web標準,優雅地使用HTTP本身的特性。原則上是對資源、集合、服務(URL)、get、post 、put、delete(操作)的合理使用。舉例來說,如果請求一個資源,但是伺服器上沒有這個資源,這時候就應該對HTTPS頭設定404,而不是設定200。

HTTP1.1加入的Cache-Control
它的功能跟Expires類似,不過有更多的選項。Expires的值是一個日期,表示某日期之前都不再詢問。Cache-Control的值是 : maxage = 7776000, maxage的單位是秒,從瀏覽器接收到檔案之後開始計時。

按照HTTP規範 ,如果修改了請求資源的QueryString,就應該被視為一個新的檔案。

下面是推薦的瀏覽器快取設定最佳實踐。

  • 對於動態生成的HTML頁面使用HTTPS頭:Cache-Control:nocache
  • 對於靜態HTML面使用HTTPS頭:Last-Modified 。
  • 其他所有的檔案型別都設定Expires頭,並且在檔案內容有所修改的時候修改QueryString。

瀏覽器快取的現實世界
伺服器端可以設定快取規則,告訴瀏覽器應該如何遵循和實現,但在伺服器不能掌控的地方也許會出現一些意外。快取會被擠出。檔案有可能在運營商伺服器上被劫持。

第二個問題是 ,使用者的寬頻運營商為了提高速度 ,可能會在自己某節點伺服器上快取您的檔案(比如style.css?v1),好處是當用戶請求這個檔案的時候,運營商無需來您的伺服器上請求檔案,而自己直接就給出了。

問題來了,如果您的QueryString更新了(style.css?v2),按照HTTP規範,這理應被視為一個新的檔案,但是運營商仍然可能會拿自己節點的快取,而不是遵循規範。有點可惡對不對?這就是我們在使用者量極大的情況下偵測到的情況,雖不太常見,但是有可能發生。所以,為了保證更新的檔案下發到所有的使用者,我們會使用更加強硬的方法:修改檔名,而不是僅僅修改QueryString。

QQ空間靜態資源在瀏覽器端使用的快取策略。

  • 對於動態生成的HTML頁面使用HTTPS頭:Cache-Control:nocache
  • 對於靜態HTML頁面使用HTTPS頭 :Last-Modified 。
  • 其他所有的檔案型別都設定Cache-Control頭,並且在檔案內容有所修改的時候修改檔名。