聊聊Web程序員所具有的基本技能
前言:同步一篇2017年1月在QQ空間寫的隨筆,2017年,我還在實習,現在回首,已經好幾年過去,現在看起來,還挺有意思的。
web相對于其他方向來說,會簡單點,但是涉及的東西會多點,如今的web程序員,所需的基本技能應該有三劍客,nodejs,php,mysql,http系列協議,網絡,瀏覽器基本原理,apache/nginx,其中包括幾十個javascript庫和幾百個框架,沒準還需要個shell和linux常用命令,如果這些都涉獵過了,沒事,面試人家還會問各種源碼,原理,機制有沒有。不過需要的技能其實很大程度上依賴于公司,具體來說應該有這么幾種情況 ,參與小系統或者內部系統的開發時,前端程序員其實就是個web程序員,需要自己建表,寫服務端邏輯,前端邏輯,寫頁面樣式,交互,俗稱全棧,如果有個后臺和你搭配,或許你可以免去寫后端的代碼。參與中型系統開發時,前端程序員需要做的是寫交互,頁面和樣式有重構,前端只需要處理用戶操作然后和后臺搞好接口就行,參加大型系統開發時,前端程序員還需要寫中間轉發層,因為前端有個同源策略,對于一般的系統,整個系統都是由一個團隊負責的,前后端的代碼再怎么分離,也還是有辦法解決同源問題,但是大型系統的后臺有時候并不是由一個團隊負責的,這時候,前端看到的就是一個黑盒子,我們只是根據后臺給的接口,把前端的數據傳到我們的后臺,也就是中間層(中間層可以是nodejs或者php來做),然后在后臺去訪問別的后臺,而且后面可能有好幾十個后臺串起來,這時候就沒有什么前端和后臺了,或許叫客戶端和服務端更加好,利用中間層,我們解決了同源問題,但是中間層不僅僅是為了解決同源問題。現在很多公司的系統都拆成服務化,比如做一個登錄的子系統,然后一大波平臺都統一去那校驗登錄態。中間層也是為了業務的接入。所以,參與開發的系統不同,所需要的技能也不一樣。
但是,作為web程序員,最核心的應該還是javascript,javascript這門語言,套路很深,而且和很多傳統的語言差別很大,無論是鼻祖c語言,還是各種面向對象的語言,我覺得函數里分配的變量在函數執行完還能被訪問,這個點就很不一樣,javascript的知識點不算是很多,核心的大概有詞法作用域,原型鏈,this問題,bind/call/apply系列函數,閉包,變量提升,正則,函數是一等公民,變量對象,執行上下文,arguments,setTimeout系列函數等,因為有垃圾回收器,內存管理這個大難題我們就不需要過于擔心了,但是javascript的知識只是前端的其中一部分,接下來的還有BOM和DOM的知識還有API非常多,雖然常用的都不會很難,但是一不小心還是會踩坑,高級點的還有v8的一些知識,包括javascript編譯和執行的過程原理,js引擎是單線程,瀏覽器是多線程,事件驅動模型,事件隊列,頁面加載和渲染原理,瀏覽器的工作原理。
網絡協議也是很重要的一部分,應用層現在說的基本都是http1.1,https和http2,http2的前身spyd已經在chrome里部署,http2目測也要來臨了,不過現在討論比較多的還是https,畢竟安全也是很重要的, http1.1主要需要搞一下rfc文檔和http權威指南就功力大增了。http協議的核心知識應該有緩存機制,常見的請求方法,cookie機制,持久連接和管道化機制,常見的http響應碼,請求頭,響應頭的意義。還包括一些安全的,協議升級協商,解決跨域的頭部。https協議的知識包括ssl握手機制和過程,connect方法實現https流量的轉發,https服務器的搭建。http2加了很多高大上的特性,提供了很多新的功能和對http1.1的性能進行了優化。tcp/ip,dns協議也是前端需要學習的知識,瀏覽器對域名進行解析或預解析時需要使用dns協議。需要了解瀏覽器解析域名的機制,比如瀏覽器里有對域名的解析進行緩存,這會導致使用dns服務器進行負載均衡時達不到效果,host文件里也有域名的映射,利用host文件可以配置不同的域名指向127.0.0.1來進行同源策略的學習,然后dns服務器自然也有緩存或者域名對應的ip,最后還需要了解dns服務器進行域名解析的機制,這些在計算機網絡里都會說到。tcp/ip協議里,前端的知識里似乎沒有太多涉及到ip協議的,tcp卻是很重要的一部分,tcp協議是ssl和http協議的基礎,后者都是需要在建立tcp連接的基礎上進行工作的,理解tcp協議對前端的優化有很大幫助。
瀏覽器基本工作原理是前端比較重要的一塊,webkit內部這本書講了很多這方面的知識,而且也很全面, 瀏覽器工作原理包括域名解析和緩存,tcp連接的管理,cookie管理,同源策略機制,緩存管理,頁面代碼的分析,布局計算,渲染,js引擎和渲染引擎的互斥工作,dom樹和cssom樹的構建,dns預解析,頁面預渲染,tcp預連接,其實js引擎是單線程和瀏覽器是多線程這個知識也比較重要,這個對理解為什么大量的cpu密集型的計算會導致瀏覽器掛掉。為什么js引擎正在執行代碼時,點擊了按鈕,點擊事件的回調還可以被會加到事件隊列里。還有setTimeout(0)的原理有很大的幫助。瀏覽器什么時候會進行布局計算和重繪影響我們如何寫代碼,以免引起性能問題。輸入url時,瀏覽器發生了什么,這個面試題基本是前端面試必問。可見瀏覽器的原理也是需要了解的。
代理/web服務器也是比較重要的一部分,因為大部分的對外系統,因為安全,性能等問題,都是有代理的,squid和nginx是比較重要的代理服務器,squid是緩存代理,是對靜態資源進行緩存以提高性能,nginx是神器,功能太多,接觸到的都是做反向代理的,nginx的代碼和架構都是享有美譽的,看代碼是理解軟件的最好方式,作為一個前端,其實去深入研究nginx代碼或許暫時沒有必要,但是大概看一些工作原理和代碼的設計架構,對自己的水平和對nginx的工作原理都是有好處的,tnginx是淘寶基于nginx開發的一個服務器,他們把研究的思路和心得都發布到他們的網站上,有興趣的可以去瞅瞅,理解了nginx的基本工作原理,nodejs和nginx都是用了一種神技,就是事件驅動模型+單線程,應對網絡高并發無壓力,和傳統的一言不合就開進程和線程不同,進程線程的切換花銷很大,而且同步互斥問題很復雜,事件驅動是通過注冊事件,事件發生時把回調扔到事件隊列里去排隊執行,單線程就去不斷輪詢事件隊列,執行回調,其實js也是這樣。但這種模式不適合cpu密集型的應用,因為單線程,傷不起。nginx的功能很多,可以做代理服務器,也可以做web服務器(比如配置一個https服務器),郵件服務器,緩存服務器等等,使用nginx主要是需要學會使用nginx.conf。至于參數調優,開發自己的模塊,這都是高級話題。說到服務器,誰敢不說老前輩apache,apache一般作為web服務器使用,管理靜態頁面和和后端的cgi程序通信,把前端的請求分配給cgi程序處理,一般使用的是php,apache一般是以一種預先派生進程/線程的方式工作,這樣前端的請求來的時候,就不需要急忙地創建進程/線程,來一個請求,從線程池里拿出一個進程/線程,所以高并發會爆,使用apache一般也是熟悉httpd.conf文件,里面包括配置虛擬主機,需要監聽的ip和端口,每個目錄的權限控制,文件權限控制,url重寫,打log,對靜態文件進行緩存管理,配置一些http頭,壓縮,加載相應的模塊等,和nginx類似但是語法不太一樣。
后端,作為一個前端,有時候也需要知道后端的知識,因為你不知道什么時候你需要去寫后端,學習點后端不至于到時候一臉懵逼,后端現在一般是使用nodejs和php,python也有人用,很多人說對于前端來說,學習nodejs可能不是很難,但其實也不是這么簡單,至少不會比php簡單,因為對于lamp下的網站,前端發請求到apache,然后apache把請求扔給php,php處理,最多連個數據庫,比較簡單,但是nodejs就不一樣了,因為nodejs是集web服務器和應用服務器與一身的,你用nodejs可以直接監聽一個端口,這就是一個服務器,不需要像apache和nginx那樣配置什么,然后你前端的請求到nodejs后,nodejs會執行相應的回調,這里有很多東西需要自己去做,而且nodejs的框架如express基本沒什么功能,需要安裝一大堆中間件去幫你干活。不像php那些框架,什么都幫你做好了,像在php里上傳一個文件,用$_FILES就可以拿到文件的內容和信息,在nodejs里你首先要百度一波,然后找一個希望沒把你折磨死的中間件,才能完成這個功能,再比如前端傳的查詢字符串,在php里可以直接根據鍵值拿到相應的值,在nodejs甚至express里,你得到的只是一個字符串,然后你自己去解析,或者你用中間件去解析,在express的早期版本里,前端post一個嵌套了兩層的對象過去,在express里第二層的對象直接變成數組了,差點沒嚇死我,原因就是早期的中間件功能還不夠牛逼,所以對于這種框架,除非你牛逼,自己寫中間件,要不然你就是等著那些大牛寫中間件給你用的處境,這只是說一下nodejs的學習成本并不低,現在nodejs和相關的框架已經進化得很好,是比較熱門的一個技術,因為nodejs的語法是基于js的,所以也比較適合前端程序員學習,只是我們在nodejs里,有時候我們可能需要比在php里做的更多。這差不多就是nodejs給我們最原始的玩意,讓我們自己隨心所欲去做我們想做的事情。不像python,能用一句代碼解決的事情,就不要用兩句。nodejs的相關知識點很多,畢竟功能比較強大,常用的大概包括進程相關的,文件系統相關的,處理網絡請求相關的,字符串處理相關的。nodejs的運行原理和架構也需要去學習,因為這樣才能用好用對nodejs。如果使用express的話可以去瞅瞅他的源碼,源碼不是很多,因為他是靠大量的中間件來工作的,其中路由的源碼是比較核心的,路由也是express里很重要的功能,這里的路由不是前端請求最后怎么分發到具體的業務代碼里,指的是對于每一個前端請求,在express里是怎么被處理的。express的路由思想看起來不是很難,不過很有意思,類似于nginx的請求被處理的過程,對于每一個進來的請求,被串行地傳到一個個函數或者模塊里進行處理,然后決定要傳給下一個還是結束這個請求,nginx里也是這么一個過程,有點像設計模式里的責任鏈模式。最后express里的很多package源碼非常值得研究,在npm官網的里很多源碼包也值得研究,對js的功力提升有很多的幫助。
數據庫,前端其實很少會接觸到數據庫,基本上就是設計一些簡單的表,然后進行增刪改查,需要了解一些sql, 對于數據庫,其實也是基于一個客戶端,服務器模型,我們的cgi程序去連接遠端的數據庫,也就是進程間的通信,只是有時候是不同的主機間的,連接數據庫,基本的參數是數據庫進程所在的主機ip,端口(默認是3306),數據庫名,用戶名,密碼。數據庫也是一個復雜的玩意,比如sql的解析和優化,連接管理,對數據的緩存和管理。
安全也是web程序員很重要的一部分知識,和前端相關的大概有xss,csrf,點擊劫持,和后端相關的大概有sql注入,http頭注入,會話劫持,文件上傳。xss主要是提交和顯示的時候需要對內容進行轉義,csrf主要是利用csrfCode來確認某個請求是否是用戶自愿發出的,點擊劫持遇到不是很多,有一個方法是引用iframe嵌入第三方網站的界面,然后隱藏自己的界面進行劫持用戶的輸入和點擊。這種可以使用http頭禁止自己的網頁被嵌到別的網頁里,或者在前端代碼里進行判斷跳轉,后端的安全主要是需要對用戶的輸入進行過濾,會話劫持可以修改php配置文件解決,文件上傳沒有接觸過。前端安全中最重要的應該屬于同源策略了,現在增加了很多新特性來防止各種安全問題,包括一些http頭來定義返回的html文檔里資源訪問的限制,和對iframe標簽里的文檔進行權限控制。還有一個是之前比較出名的a標簽的target='_blank'的安全問題。
設計模式也是一個重要的部分,寫代碼一開始是先隨便寫,實現功能第一,漸漸地,就需要開始考慮怎樣寫好代碼,怎么寫比較好,怎么組織比較好,有時候,有些設計模式的確會很優雅地解決一些問題,代碼的重用和可維護性對于自己和別人都是很重要的。提高寫代碼的方法,不僅需要看書學習,也需要不斷琢磨,思考,還需要不斷地看別人的代碼和一些寫得比較好的源碼。因為如今的前端不再是以前的幾個交互,現在的前端已經變得越來越復雜,所以寫可持續發展的代碼變得很重要。
函數庫,框架和軟件是用來提高工作和學習效率的,web程序員的常用軟件大概有fiddler神器,wireshark神器,whistle還有瀏覽器f12出來的各種tab,隨著瀏覽器原生地支持很多功能,有些庫的功能可能會漸漸變得沒必要,現在各大公司已經漸漸放棄作死的ie,不再支持8以下的版本,很多兼容性問題漸漸也會消失。剩下的一堆打包壓縮工具就沒啥好說的了。
工作其實最主要的技能是學習能力和解決問題能力,學習能力是必不可少的,學習一個新東西時,首先看他的文檔先使用它,然后再看他的源碼,因為這樣才能真正了解他的本質,這是有必要的,即使像nodejs的源碼,雖然不可能完全看懂,但是大致的脈搏還是需要摸清一下的,至少我覺得這樣用起來才會安心,舒服。當擁有一定的知識后,遇到問題怎么解決,這也是一個重要的部分,控球好的人不一定就會過人,做一個需求,有時候可能只是改一點點東西,但是在哪改,改完會不會對之前的功能有影響。所以改一點點東西的需求,首先你要去看別人的一堆代碼,而這堆代碼還不一定是在同一個地方,甚至不在一個系統里, 但是這種問題始終需要解決,但這種困難就像看英文文檔一樣,一開始是會很痛苦,但是慢慢地,你就會習慣這種情況,并且潛移默化中提升了自己的能力。還有一種需求是開發一個完全新的功能,這時候你不需要看別人的代碼了,所以這時候你就可以考慮,琢磨你該如何組織和編寫自己的代碼,使得看起來很舒服,維護和擴展也很容易,這無形中又提高了自己,工作的勞累和壓力其實不僅僅來源于工作本身的內容,更來源于你無時無刻都需要思考,很多事情,只有細細考慮,慢慢琢磨才能做好,做對,這會大量消耗你的腦力,所以做技術費腦,有時候并不一定是說你要多聰明,而是你要一直保持你大腦的效率和清晰。
最后想說的是,其實做技術還是需要找到自己的興趣和方向,抓住重點去 學習,現在技術更新太快,枝繁葉茂,難免會有點方,但是還是需要按照自己的計劃慢慢去學,不需要太急躁!多去學一些本質的知識,因為只有這些是不會變的,比如es6的class,其實只是一種語法糖,他的背后也還是以前的原型鏈知識。現在的開源社區非常活躍,你在上面其實會發現很多很好的代碼和很厲害的人,但是我覺得應該學習他們,而不是給自己不好的心理壓力。蘇軾說的對,早年讀書無甚解,晚年省事有奇功,學習的時候,很多東西你覺得沒用的,其實在一定程度上他已經提高了你。