【筆記】Web全棧工程師的自我修養(上)


【筆記】Web全棧工程師的自我修養(上)

作者:杜尼卜

轉發鏈接:
https://segmentfault.com/u/dunizb

前言

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

一、什麼是全棧工程師?

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

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

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

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

“各司其職”的弊端

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

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

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

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

4. 更多角色導致項目效率低下

全棧工程師登上舞臺

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

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

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

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

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

二、如何成為全棧工程師

先精後廣,一專多長

“先精後廣 ,一專多長 ”是指 ,建議初學者學習全棧技能的時候 ,先在一個特定的方向上有比較深入的鑽研 ,然後再將學習目標漸漸推廣開來 。比如先從前端方向入手 ,掌握了基本的 HTML、CSS 、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作為其傳輸層 。

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模式 。

prefork和worker模式的最大區別就是 ,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配置中增加這兩項

<code>

query_cache_size

 = SIZE /<code>

SIZE是指為查詢緩存開闢多大的空間 。默認是 0 ,也就是禁用查詢緩存。

<code>

query_cache_type

 = OPTION/<code>

設置查詢緩存的類型 ,可選的值有以下這三種 。

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

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

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

擴展數據庫緩存:memcachedmemcached的緩存失效採用的是按時間來過期的設計 。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頭,並且在文件內容有所修改的時候修改文件名

本篇還未完結,請看下一篇

【筆記】Web全棧工程師的自我修養(下)

作者:杜尼卜

轉發鏈接:
https://segmentfault.com/u/dunizb


分享到:


相關文章: