續前文 後端好書閱讀與推薦 - Mageek`s Wonderland ,幾十天過去了,又看了兩本好書(還有之前看過的書),這裏依然把它們總結概括一下,加入一些本身的見解、有用的連接和可能的延伸閱讀,並推薦給須要的同窗。php
深刻理解Java虛擬機 (豆瓣) https://book.douban.com/subje...html
Java怎麼用,是一個問題;怎麼用好是一個大問題;這麼用是爲何,是一個更大的問題。搞懂這三個問題應該是每個搞Java的人都要追求的目標,讀完本書,就能把這個更大的問題搞懂了。java
本書亮點:node
模塊化是解決應用系統與技術平臺愈來愈複雜,愈來愈龐大的問題的一個重要途徑,也是創建各類功能的標準件的前提。ios
Java運行時數據區幾個主要部分:程序計數器(可看做當前線程所執行的字節碼的行號指示器)、虛擬機棧(每個方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出棧的過程,而棧幀存儲局部變量表、 操做數棧、 動態連接、 方法出口等信息)、本地方法棧(Native方法對應的棧)、堆(全部線程共享的一塊內存區域,存放對象實例)、方法區(各個線程共享的內存區域,存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據)、常量池(方法區的一部分,存放編譯期生成的各類字面量和符號引用)。nginx
對象訪問方式取決於虛擬機實現而定的,目前主流的訪問方式有使用句柄和直接指針兩種:若是使用句柄訪問的話,那麼Java堆中將會劃分出一塊內存來做爲句柄池,reference中存儲的就是對象的句柄地址,而句柄中包含了對象實例數據與類型數據各自的具體地址信息;若是使用直接指針訪問,reference中存儲的直接就是對象地址。git
Java垃圾回收採用分代回收機制,新生代和老生代採用不一樣的算法(node.js也是),而無論什麼機制,判斷一個對象是否存活都是基本的步驟,方法有:引用計數法,給對象添加一個引用計數器,每當一個地方引用它時,計數器就加1,引用失效時,計數器就減1,任什麼時候刻計數器爲0的對象就是不可能再被使用的,這個方法實現簡單,可是不能解決循環引用問題,因此主流JVM不使用,可是這個算法也適用於許多地方如Python,微軟的COM;可達性分析,按照對象之間的引用關係維護一個引用鏈,若是一個對象不可達GC Roots,那麼就是可回收的,應用於主流JVM中。程序員
finalize是一種迎合C++程序員的妥協,運行代價高昂,不肯定性大,沒法保證各個對象的調用順序。有些教材中描述它適合作「關閉外部資源」之類的工做,這徹底是對這個方法用途的一種自我安慰。finalize能作的全部工做,使用try-finally或者其餘方式均可以作得更好、更及時,因此建議你們徹底能夠忘掉Java語言中有這個方法的存在。web
幾乎各類語言或多或少都提供過一些語法糖來方便程序員的代碼開發,這些語法糖雖然不會提供實質性的功能改進,可是它們或能提升效率,或能提高語法的嚴謹性,或能減小編碼出錯的機會。不過也有一種觀點認爲語法糖並不必定都是有益的,大量添加和使用「含糖」的語法,容易讓程序員產生依賴,沒法看清語法糖的糖衣背後代碼的真實面目。因此咱們既要會使用語法糖,同時也要搞懂背後的原理,這樣才能進階呀。好比泛型技術:泛型只在程序源碼中存在,在編譯後的字節碼文件中,就已經替換爲原來的原生類型。redis
Java程序最初是經過解釋器(Interpreter)進行解釋執行的,當虛擬機發現某個方法或代碼塊的運行特別頻繁時,就會把這些代碼認定「熱點代碼」(Hot Spot Code)。 爲了提升熱點代碼的執行效率,在運行時,虛擬機將會把這些代碼編譯成與本地平臺相關的機器碼,並進行各類層次的優化,完成這個任務的編譯器稱爲即時編譯器(Just In Time Compiler,簡稱JIT編譯器)
基於高速緩存(Cache)的存儲交互很好地解決了處理器與內存的速度矛盾,可是也爲計算機系統帶來更高的複雜度,由於它引入了一個新的問題:緩存一致性;除了增長高速緩存以外,爲了使得處理器內部的運算單元能儘可能被充分利用,處理器可能會對輸入代碼進行亂序執行(Out-Of-Order Execution)優化,相似的JVM也有指令重排(Instruction Reorder)。這兩點是提升程序運行的主要方法,然而也是多線程程序難以正確編寫的主要緣由。
先行發生(happens-before)是Java內存模型中定義的兩項操做之間的偏序關係,若是說操做A先行發生於操做B,其實就是說在發生操做B以前,操做A產生的影響能被操做B觀察到,「影響」包括修改了內存中共享變量的值、發送了消息、調用了方法等。時間前後順序與先行發生原則之間基本沒有太大的關係,因此咱們衡量併發安全問題的時候不要受到時間順序的干擾,一切必須以先行發生原則爲準。
這本書是基於jdk1.7的,若是要追蹤最新的Java和JVM規範,能夠看這裏。
另外,上面提到的第一個問題能夠參閱Java核心技術,第二個問題能夠參閱Java編程思想、Effective Java,第三個問題還能夠參閱HotSpot實戰。這幾本書我都瀏覽過,部分有細讀,都是至關經典的。
高性能MySQL (豆瓣) https://book.douban.com/subje...
這本書可謂是MySQL領域的權威之做,從架構到測試,從性能分析到查詢優化,從軟件配置優化到服務器硬件優化,從單實例到主從複製、負載均衡,從底層數據庫優化到應用層優化......本書真可謂是面面俱到,同時又頗有深度,絕非淺嘗輒止。
本書亮點:
所謂的鎖策略,就是在鎖的開銷和數據的安全性之間尋求平衡,這種平衡天然也影響到性能。這句話適用於世間的一切工具,安全性和可用性老是矛盾的,咱們在使用工具或者開發工具的時候,都要尋求一個最佳平衡點。
除非須要使用InnoDB不具有的的特性,而且沒有其餘辦法能夠替代,則都應該優先使用InnoDB引擎,也不要多引擎混用,例如全文索引能夠使用InnoDB+Sphinx,而不要使用MyISAM引擎,由於InnoDB其餘方面的優勢能夠徹底碾壓MyISAM,好比崩潰恢復快,支持事務,支持行級鎖,支持真正的熱備份等等。
基準測試能夠驗證對於系統的假設,檢查異常行爲,找出擴展性瓶頸等等。須要注意的是不要使用真實數據的子集,做物的數據分佈,忽略預熱等等,這些錯誤的操做會使得測試結果無用或者不精確。並且要創建參數與結果文檔化的規範,這樣才利於結果分析與優化。
不少人在優化時都將精力放在修改某些東西上,卻不多去測量;正確的作法是要儘可能測量響應花的時間在哪,正確的測量通常都能將性能問題的點暴露出來,咱們就能更好的對症下藥,而不是盲目優化(花1000塊優化一個只值500塊的業務,或者已經處於頂點的業務不就是虧了嗎)。因此說,決策要基於數據而不是感受。
良好的邏輯設計和物理設計是高性能的基石,某些反範式的設計可能加快某些查詢,好比計數表和彙總表是一種很好的查詢優化方式,能提升統計類的查詢速度,可是維護起來就比較麻煩,可能下降數據插入速度。這些都須要本身根據業務來進行權衡(好比讀寫比),有陰就有陽嘛。
選擇能正確存儲數據的最小類型:既省空間又省計算時間,簡單就好:好比使用MySQL內建時間戳而不是本身使用字符串,儘可能避免null:由於null使得索引、統計、值比較都更加複雜還可能會佔用更多空間。
InnoDB有一個「自適應哈希索引」的功能,當引擎注意到某些索引值被頻繁使用時就會在內存中基於B+Tree索引之上再建立一個hash索引,這樣就讓B+Tree也具備hash索引的優勢好比快速查找。
小表一般全表掃描更高效,中大型表才適合用索引,使用索引過程當中要注意,索引列必須單獨的出如今比較符號的右側而不是表達式的一部分(這會使索引失效),使用前綴索引來節省空間提升檢索效率,多列索引要注意順序否則容易失效,聚簇索引能夠提升訪問速度。
慢查詢優化:只向數據庫請求須要的列(好比不要隨意select * )、避免沒必要要的行掃描、必要的時候分解查詢(拆分大的查詢,分解關聯查詢)。
默認配置文件是通過大量測試,因此屬於較優解,通常符合普通用戶,要修改也主要是根據業務而不是服務器配置;任何打算長期使用的配置都應該寫到全局配置文件而不是在命令行指定,由於若是偶然啓動忘了(事實是常常會忘,好記性不如爛筆頭是個真理)設置就會有風險。
MySQL複製功能不只有利於構建高性能應用,同時也是高可用性(負載均衡、故障切換)、可擴展性(升級)、災難恢復、備份以及數據倉庫等工做的基礎。
數據若是很是龐大,好比幾億行了,單臺機器已經撐不住了,一般要採起分片技術,分片最大的問題就是查詢與獲取數據,咱們的目標是對最重要且頻繁查詢的數據減小分片(熱點數據一般就那麼多)。因此分片關鍵問題就在於選擇一個好的分區鍵,一般是一個數據庫中很是重要的實體的主鍵。
不只要關注MySQL,還要關注應用層優化:Apache服務器處理靜態文件均可能使用一個佔用內存很大的進程(上一個請求處理完後,該進程仍然保持着),因此最好使用Nginx或者Lighttpd來處理靜態內容服務,並且靜態文件名不要重用,要加上版本號,這樣就能避免瀏覽器緩存問題;主動緩存如Squid,被動緩存如Memcached,均可以對性能得到數量級的提高,關鍵就在於找到正確的粒度和緩存過時策略組合,一般主動緩存更好,由於對應用層隱藏了檢查-生成-存儲這個過程;
......
亮點太多,列不完了,須要你們本身去尋找。另外,這本書不適宜一次性的精讀完畢(太厚,內容太多),能夠快速瀏覽一遍,大概瞭解,之後趕上問題就能夠把這本書看成一本問題解答手冊來查詢解決方案,或者找找靈感。
Redis實戰 (豆瓣) https://book.douban.com/subje...
本書對redis的介紹是至關全面了,從基本用法講起,而後講了許多應用場景,包括購物車、數據庫緩存等,而後講了一些常見問題的解決辦法,好比內存佔用太高,自定義擴展來豐富redis的用法等等,看完一本書事後就能很好的使用redis了(還有本好書:redis設計與實現,我大體瀏覽了一下,這本書主要講了redis的實現原理,這兩本書加起來就能既懂原理又會使用,把redis搞個透徹)。
本書亮點:
使用冒號 : 或者管道號 | 等來實現命名空間的做用,好比一個名爲 article:12222 的hash存了這篇article的title,link,time等屬性,article:12223又是另外一篇文章,這個能夠部分實現數據庫檢索的功能。
爲了減小redis與客戶端之間的通訊次數,能夠用multi和exec來作事務處理,事務會一次性的把一批命令一次發給redis,提升吞吐率;另外事務還能保證一批操做的原子性。在node-redis實現中,若是隻是想提升吞吐率則能夠用batch替代multi。
經過複製(主從)和AOF可以加強redis抵抗系統崩潰損失數據的能力,AOF若是用得很差的話,要麼損失不少數據,要麼嚴重下降吞吐量,比較合適的作法是appendfsync everysec 亦即把每一秒的命令一次同步進文件。
使用 redis 的 setnx 來實現基本上正確的的分佈式鎖,再加上expire能夠實現具備超時功能的鎖,保證即便得到鎖的客戶端崩潰沒有主動釋放鎖時,其餘進程也有機會得到鎖。
用 list 來替代 subscribe、publish 實現更可靠的發佈訂閱系統;另外,利用subscribe、publish加list來實現具備離線緩存的消息隊列系統,保證即便發生鏈接故障也能把消息送達。
利用反向索引以及 redis 集合的並、交、差功能能夠實現簡易的搜索引擎,利用 hash 結構的 sort 功能還能對搜索結果進行簡易的排序功能,利用有序集合 zset 能實現更高級的排序功能。
社交網站一般是用時間線這一數據結構來實現新鮮事瀏覽這一功能,雖然致使了大量的冗餘信息,可是可以節省查詢時間,這是典型的以空間換時間的操做,我之前作社交APP後臺的時候直接把全部新鮮事直接放在一張表中,而後按用戶id查詢,這樣雖然省了空間,可是若是用戶劇增((⊙﹏⊙)b,咱們的APP並無用戶劇增)就不行了,一張表幾億行還怎麼查。
使用短結構來節約內存,使用較短的鍵名節約內存,分片下降單實例的內存佔用。
使用lua腳本,在不編寫C代碼的狀況下,爲redis添加新的功能。
時效性問題,本書沒有一些最新特性 好比 geohash 解決了地理座標問題,鍵的異步釋放使得咱們能夠放心刪除而沒必要擔憂大量數據的刪除使得redis短暫不可用。總之,要更好的利用redis仍是要追蹤redis的最新變化,以便更簡潔、更靠譜的解決問題。
深刻剖析Nginx (豆瓣) https://book.douban.com/subje...
本書從源碼入手,依次講解了進程模型、模塊、響應處理機制、過濾、負載均衡等相關原理,極大的知足了個人好奇心,由於以前一直就對nginx高併發處理能力有一丟丟了解(好比nginx採用事件驅動機制而非apache的進程、線程每請求方式),本身也用過nginx,可是對他的原理還不是特別的明白,本書算是填補了個人這個空白。
本書亮點:
Nginx 將職責分爲監控進程(主進程)和工做進程(主進程fork的子進程),監控進程與用戶交互並對工做進程進行監控管理,工做進程完成具體業務邏輯,二者都有一個無限的for循環,這是服務進程的基本寫法。
Nginx僅提供針對大塊內存的回收不提供小塊內存的回收,這是由於web server的特殊性亦即階段和時效,請求就申請內存,處理完畢就釋放內存,因此不會存在nginx長時間佔據大量無用內存的狀況,那麼小內存也天然沒必要急於回收,而是成爲大內存後在回收。
對於客戶端的請求,nginx將整個過程分爲11個階段,每一個階段有數個回調函數進行專門的處理,每一個階段的處理功能都比較單一,達到高內聚低耦合的目的。
Nginx是以事件爲驅動的,也就是說Nginx內部流程的向前推動基本都是靠各類事件的觸發來驅動,內部事件主要有兩類:IO事件與定時器事件。其中IO事件主要靠epoll,epoll主要優勢是監控數目不受文件描述符限制、事件響應是觸發式的,不須要遍歷描述符(select須要)。
Nginx要處理動態的內容通常須要轉發給後端服務器,常見的搭配是nginx+fastcgi+php,nginx把http請求轉化爲fastcgi協議的數據後轉發給PHP引擎,PHP引擎處理結果後把數據返回給nginx,nginx把數據轉化爲http格式返回給客戶端。
負載均衡有多重含義(或者說多重級別),能夠是進程上的(根據master進程根據子進程壓力調整其獲取監聽套接口的概率),更廣的意義上是指反向代理上,亦即nginx把請求均衡的轉發給後端服務器如PHP引擎,發揮多個單元的總體效能。通常採起加權輪詢、IP hash等策略,可是隻靠nginx是不能實現完整的負載均衡的,詳見我之前寫的一篇文章。
這本書主要從應用及其原理方面來介紹nginx,對於後端程序員應該是夠用了(我也忽略了許多源碼,由於只是想了解一下原理)。可是對於要想本身深刻、進行模塊編寫的讀者應該還不夠用,能夠再參考一下這本書 深刻理解Nginx(第2版)(我大概瀏覽了一下,本書會指導讀者編寫具體的模塊及其底層原理,比咱們今天介紹的書更深刻一些)。
第一本Docker書 修訂版 (豆瓣) https://book.douban.com/subje...
書如其名,這就是真正的第一本docker書。docker是什麼、怎麼安裝、如何使用、測試集成、構建服務等都有介紹。以前就久仰docker大名,也試着試用了一下,可是直到這本書讀完我纔對docker有了一個完整的認知。另外,不出意料,本書的推薦序也很精彩。
本書亮點:
docker的核心價值在於可能改變軟件的交付方式和運行方式。傳統的交付方式下,軟件運行期依賴的環境是沒法控制,不能標準化的,開發人員經常須要解決開發環境和生產環境的差異帶來的問題,而docker則把軟件及其依賴環境打包在一塊兒,以鏡像形式交付,讓軟件運行在標準環境中,很是符合雲計算的需求,同時docker的輕量虛擬化技術也符合實例水平擴展,資源動態調整的要求。
docker提供如下幾個好處:簡單輕量的建模方式,工程容易docker化,隨時修改代碼,運行快速;職責分離,開發人員只管開發,運維人員只管容器管理,減小環境不一樣帶來的問題;快速高效的開發生命週期,程序容易部署、移植和協做;容易實現面向服務的架構和微服務架構。
docker只支持64位架構,原生的Linux容器格式:libcontainer,使用命名空間來隔離文件系統(每一個容器都有本身的root系統)、進程(每一個容器都運行在本身的進程環境中)和網絡(容器間虛擬網絡地址和IP地址都是分開的),使用cgroups將CPU內存之類的資源獨立分配給容器,寫時複製使得文件系統分層隔離、速度更快、佔用空間更小,還提供日誌和交互式shell。
鏡像分層:新鏡像是從 base 鏡像一層一層疊加生成的,文件系統發生變化時,就在現有鏡像的基礎上增長一層,這一層叫作「容器層」(讀寫層),「容器層」之下的都叫「鏡像層」(只讀層),只有當須要修改時才從鏡像層複製一份數據到容器層,這種特性被稱做寫時複製(Copy-on-Write),達到了鏡像共享,快速構建的目的。
能夠使用docker commit來構建鏡像,也能夠基於dockerfile和docker build命令構建,一般建議使用後者,由於dockerfile更具有透明性(能夠清晰地看出安裝了什麼軟件,修改了什麼配置)、可重複性(一次編寫,屢次使用。此外構建緩存還能夠製做構建模板)、冪等性(同一個dockerfile不論執行多少次,結果都是相同的)。
docker容器之間通信有3種方式,1.9以前推薦用Docker Link(安全:只有link以前的容器能夠通訊,沒必要硬編碼,不支持多主機),1.9以後推薦Docker Networking(支持多主機容器鏈接,能夠熱更新容器,Networking網絡內部容器能夠自主發現),不太推薦docker內部網絡(IP硬編碼等致使該方法不夠靈活)。
volume(卷)具備一些有用的特性:容器之間共享數據,對卷的修改會直接反映在包含改卷的容器裏因此能夠在不修改容器的狀況下向容器里加入、更新、刪除數據,更新鏡像時不會影響卷。利用這些特性能夠更好的進行數據共享與持久化。
docker編排與集羣化之路:Docker Compose 是用來作 docker 的多容器控制,使用Compose ,你能夠在一個文件中定義多個容器應用,而後使用一條命令來啓動你的全部應用,避免繁複操做,docker 自動化構建容器棧;Consul提供了一個易於使用,基於開放標準的服務發現解決方案,服務發現容許某個組件在想與其餘組件通信時自動找到對方;Docker Swarm是一個用於建立Docker主機(運行Docker守護進程的服務器)集羣的工具,使用Swarm操做集羣,會使用戶感受就像是在一臺主機上進行操做亦即將容器抽象到集羣級別。還有其餘不少工具如:fleet、etcd、Kubernetes、Apache Mesos、Helios、Centurion。
時效性緣由,書中一些例子已通過時(如Docker1.12開始內置編排機制,Docker1.13正式支持docker stack),須要結合最新版本來使用。
另外,想要深刻理解docker能夠閱讀這本書 Docker——容器與容器雲。我大體瀏覽了下,這本書不只講了docker如何使用,還深刻講解了docker的核心原理如namespace資源隔離、cgroups資源限制、libcontainer原理和一些高級實踐技巧。此外,還講了對容器、容器雲的思考,包括如何構建本身的容器雲,以及Kubernetes實現一切皆容器的「大同理想」。
UNIX/Linux 系統管理技術手冊 (豆瓣) https://book.douban.com/subje...
又是一本進千頁的大部頭,可是不怕,這本書如其名,是一本手冊性質的書,很是大而全,包括基本管理技術、網絡管理技術和其餘補充管理技術,幾乎包攬了全部咱們可能用到的功能(小到一行代碼整麼寫,大到數據中心怎麼建),對於宏觀把握整個Linux生態系統有很大做用。個人應對策略是跳躍式閱讀(不錯,就像上面那本MySQL),留下總體映像,等趕上問題時再來具體的查詢相關部分的內容。也就是說,大腦至關於內存,書本至關於硬盤數據庫,咱們首次閱讀就是在內存中創建索引,便於提高之後的查找速度:-D。
本書亮點:
Linux各個發行版其實並無那麼巨大的差異,咱們選擇一個發行版時主要考慮幾點:是否能長期存在,是否會有持續的安全補丁,是否會持續更新軟件,發行商是否會在出了問題時幫咱們解決,不一樣發行版側重點會有所不一樣咱們要根據本身的業務來進行選擇。
編寫腳本時注意造成一種指導風格,這樣你和你的團隊成員能夠按照相同的規範來書寫代碼,有了這種指導在閱讀別人寫的代碼或者別人閱讀你的代碼時都會更容易;註釋不要多也不要少,最好的效果是一兩個月後再來讀代碼發現註釋和有用。
一個進程由一個地址空間(一組內存頁面)和內核一部分數據(有關進程的信息如地址空間映射、狀態、優先級、資源)組成;一個線程是在進程內執行fork的結果,繼承了包含它的進程的許多屬性,多個線程能夠共享該進程內數據,並行(多核)或併發(單核,模擬並行)執行
Unix家族的文件系統目前沒有一個標準,咱們儘可能按照以下標準來組織。bin:核心操做系統命令;sbin:系統最小規模運行所需命令;boot:內核及加載內核所需軟件;etc:關鍵啓動文件及配置文件;usr:次要的命令文件;var:隨主機變化的文件如日誌,數據文件;mnt:可移動介質臨時掛載點;opt:可選的應用軟件包;proc:正在運行的進程信息;tmp:臨時文件;
合適的備份計劃取決於:文件系統的活躍性,轉儲設備的容量,用戶指望的冗餘度,想要購買的備份介質數量。
版本控制與多人合做:svn是集中式的,一臺中央服務器充當了一個項目的權威庫;git是分佈式的,沒有中央庫,每一個用戶都含有一個完整的項目,採用的是拷貝-分支策略。
信息安全領域的基本思想——CIA原則:Confidentiality(機密性),Integrity(完整性),Availability(可用性)。在設計、實現或者維護系統的時候,須要考慮CIA安全三原則,正如老話所說「安全性是一個過程」。
負載均衡既提升了性能又增長了冗餘性,包括幾種方式:循環域名服務(也就是DNS輪詢)、負載均衡硬件(好比Big-IP Controller、Content Services Switches等)、軟件負載均衡(好比Nginx)。
Squid既是一個高速緩存軟件也是一個代理服務程序,代理服務頗有用,可是Squid真正厲害之處是其高速緩存,它甚至可以造成一個緩存層次結構,以最大化提升緩存命中率。Squid是有意義的,由於用戶對web的探索具備趨同性,因此在適度的規模上會出現至關多重複請求,運行高速緩存能夠節省帶寬和計算資源。
虛擬化技術讓多個彼此獨立的操做系統同時運行在相同的物理硬件上,系統管理員把每一個虛擬機當作一臺獨立的服務器,既知足了軟件廠商的要求,又下降了單一服務的成本。包括全虛擬化(如VMwareESX)、半虛擬化(Xen)、操做系統級別虛擬化(如workload partition)。除了傳統的虛擬化技術,近年來的雲計算也是一種(或者說類)虛擬化技術,它把計算能力做爲對外提供的服務相似於水電等基礎設施,直接使得硬件層對開發人員和系統管理員透明,提升了效率。
分析性能問題步驟:明確表述問題、收集證據並分類、批判性的評價數據、用語言和圖示總結證據、造成一份總結說明。這一套其實不止適用於性能分析問題,也適用於大多數其餘問題,好比架構、重構、debug等等。
系統管理不是一種行爲藝術。不管作的什麼,都應該能重複完成,切先後一致。一般意味着最底層的變化應該有腳本或者配置程序來作,而不是管理員來作。配置上的變化應該體如今系統管理軟件的配置文件裏。說白了,就是文檔的重要性,在我看來:首先文檔就是一家公司的財富,沒有文檔,人走了,那麼以前公司的積累也就沒了,又得重頭來,損失很大;其次,文檔是一種保證,你們都按約定辦事,保證操做可重複,避免歧義與甩鍋;再其次,文檔能節約時間,雖然寫的時候可能費點事,可是能節省後面大量的人員溝通的時間;最後,文檔保證了系統的完整性,亦即文檔保證了系統的後續修改遵循一致的思路和風格,纔不至於系統隨着時間流逝而愈來愈亂,難以維護與使用。
本書教會了咱們怎麼使用Linux,這對於咱們後端開發人員是足夠受用了。而這本書Linux內核設計與實現(原書第3版)就會告訴咱們Linux是如何實現它這麼多這麼強大的功能的內在原理,精力有限,我只是瀏覽了一下沒有細讀,等之後真的用得上Linux的深刻知識時,或者趕上了什麼解決不了的問題,我會再來求助於這本書的。
代碼整潔之道 (豆瓣) https://book.douban.com/subje...
本書提出一個觀點就是:代碼質量與整潔度成正比,圍繞提升整潔度,做者展開了方方面面的闡述,從命名的方法到函數的定義,從註釋的使用到格式的目的,還介紹了對象,錯誤處理等等等等。看完後的感受就是:寫好代碼,從本書開始。雖然我如今寫的代碼還比較「亂」,可是從此的代碼中會努力踐行書中的原則,爭取寫出整潔的代碼。
本書亮點:
軟件質量既依賴於架構和項目管理,又與代碼質量緊密相關,而代碼質量與整潔度成正比,因此咱們要致力於寫出乾淨整潔的代碼。而且不只要知道書寫整潔代碼的原則,還有查看大量代碼實例,進行案例研究,在實踐中貫徹這些原則,才能真正作到知行合一。
不一樣的人對整潔代碼有不一樣的理解,總歸起來,有以下一些特色:代碼邏輯直截了當,依賴關係不多,性能最優,每一個函數模塊類專一於一件事,能夠輕易的被其餘人閱讀,具備完整的測試,做者本身要在意本身的代碼悉心維護,沒有重複代碼提早構建重複代碼應有的抽象,體現系統的全部設計理念,包含儘可能少的實體。
命名看似簡單卻無處不在,因此咱們不妨命好名,幾個原則:名副其實,不用註釋也能明白這個變量表明什麼;避免誤導,不要用保留詞或太相同的詞引發歧義;作有意義的區分,不要添加在名字後數字或者廢話而是以讀者能鑑別不一樣之處的方式來區分;名字要讀的出來,便於交流;名稱要便於搜索;一個概念統一用一個詞,好比不要混用manager和Controller;避免雙關詞;給名詞添加語境,可是避免冗餘的語境,含義明確的狀況下,短名字老是比長名字好呀......
函數構成了當今程序的基石,函數要寫的明白要遵循以下原則:短小;只作一件事,也就是函數中的語句要在同一個抽象層級上,不在同一個抽象層級就得拆出來造成一個新的函數;把switch埋藏在較低的抽象層級,好比抽象工廠中,雖然依然免不了判斷或者條件增多時要增添代碼,可是可以把變化截留在工廠內,減小影響範圍;不要向函數傳入標誌參數,好比TRUE/FALSE,而是應該直接把這個函數重構成兩個函數;一個函數要麼下達什麼指令(set)要麼回答什麼問題(get),不要添加反作用;DRY(別重複本身)。
註釋是一種必須的惡,若是代碼寫的好根本不須要註釋(感受有點過了,至少一個大的模塊用來幹啥仍是因該用註釋或者說文檔直接來講明),並且代碼纔是真實的地方,註釋極可能沒有被維護而致使失效;別給糟糕的代碼加註釋,重寫吧;版本控制系統能夠幫咱們省掉許多註釋如做者署名,註釋掉的代碼。
或許你認爲「讓代碼工做」是開發者的頭等大事,可是其實並非這樣的,代碼風格關係着溝通,而溝通才是頭等大事。代碼風格影響着可維護性和擴展性,即便代碼已不復存在,其風格和律條依然存在,於是一個團隊應該造成一個統一的風格,便於溝通與維護。
隱藏實現並不是就是簡單的在變量之間放一個函數層。隱藏關乎抽象,類並非簡單的用取值器和賦值器將變量向外推,而是暴露抽象接口,以便用戶無需瞭解數據的具體實現就能操做數據自己。對象暴露行爲,隱藏數據;數據結構暴露數據,沒有明顯的行爲。要合理的利用兩者。
錯誤處理一旦處理很差就容易污染整潔的代碼:使用異常來保證錯誤處理不會打亂正常的程序邏輯;可檢異常可能會破壞開閉原則,要謹慎使用;打包第三方API就下降了對它的依賴;不要返回null值,只是忽然增長了工做量,能夠用異常或者特例對象來代替。
測試很是重要:測試代碼和生產代碼同樣重要,髒測試就等於沒測試;有了測試就能夠毫無顧慮的進行重構和改善,由於有保證,消除了清理代碼就會破壞代碼的恐懼(這句話可謂是戳中了我,我以前的項目也有過一些重構的努力,可是就是怕重構事後不能正常運行,致使重構舉步維艱);測試代碼要清晰,符合構造-操做-檢驗三個環節;單個測試中的斷言應該最小化,保證一個測試對應一個概念;整潔的測試遵循 FIRST 原則(fast,independent,repeatable,self-validing,timely)。
系統層級的整潔:城市能有效運轉是由於演化出了恰當的抽象層級和模塊,有人負責全局有人負責細節,因此軟件系統也有架構師和項目經理等;將構造和使用分開(依賴注入,控制反轉);擴容(要考慮可擴展性,可是注重現有的系統的構造,未來再重構和添加,不必Big Design Up Front,考慮好模塊化和關注切面劃分就好)。
KISS(Keep It Simple, Stupid),簡單設計原則:運行全部測試(測試是對一個系統的保證);不要重複(重複意味着額外的工做、風險、複雜度);表達了程序員的意圖(清晰可讀);儘量少的類和方法數量(避免教條如:每一個類都要有接口)。
編程是一種技藝甚於科學的東西,不要期望一開始就寫出優雅整潔的代碼,通常是先寫出骯髒的代碼,而後進行重構,清理。因此代碼僅僅能工做還不夠,知足於代碼能工做的程序員不夠專業,他們懼怕沒時間進行代碼結構的從新設計,其實沒有什麼比糟糕的代碼給項目帶來更長遠的損害了,糟糕的代碼會一直腐敗發酵,影響各個模塊(找出這些依賴和影響至關不容易)無情的腐蝕整個項目和團隊。
......
這本書裏面的良心建議實在是太多了,沒法一一列舉,真的得本身看一遍纔能有收穫。
重構 (豆瓣) https://book.douban.com/subje...
上一本書教會咱們怎樣書寫整潔的代碼,那麼面對不整潔的代碼,咱們怎麼辦呢?這本書就手把手教咱們怎麼重構,改善現有的代碼。從一個實例入手,講了重構的理由、原則、技巧、步驟與時機。我讀完事後感受內心就有了些烙印,不管是寫代碼仍是改代碼,基本都會不自主的向這本書靠攏,頗有收穫。
本書亮點:
重構是在不改變代碼外在行爲的前提下對代碼做出修改,以改進程序的內部結構,本質上說重構就是在代碼寫好後改進其設計,提升其可理解性,下降修改爲本;記住全部代碼的「壞味道」及其對應的重構手法,纔能有信心面對各類狀況——學會全部招式纔可能「無招勝有招」;爲了不自掘墳墓,重構必須系統化進行,用一些通過檢驗的重構手法,就能夠一次一小步的修改代碼,因此任何錯誤均可以比較容易的發現,下降了重構過程當中的風險。
若是你發現本身須要爲程序添加一個特性,而現有的代碼結構使你沒法方便的添加,那就先重構程序,使得特性添加變得容易,而後再添加這個特性。而重構的第一步就是創建一組可靠的測試,來儘可能避免bug,保證重構的正確性。
對象A最好不要在另一個對象B的屬性基礎上使用switch語句,由於未來B變了A也必須變,若是不得不使用switch也要在本身的屬性上使用,也就是把switch移動至B裏面去;最好是用多態替換switch語句(其實也不是替換,而是把switch放在了較低的抽象層級,使得可能變化的部分就在一個對象裏面,將其與不變的部分隔離開)。
添加新功能和重構是兩種行爲,必定要加以區分,而且同一時刻只作好一件事就行。
任何可以查詢的東西,我都不太願意去記,由於怕把大腦擠爆了。因此說大腦這個珍貴而有限的內存主要作的事必定是建好索引,而非存儲數據;另外一方面,經常使用的數據也應該存進大腦,以提升效率,這和內存中的緩存是一個道理。
不要爲了重構而重構,必定是由於你想作某件事時重構剛好能夠幫你作好,重構的幾個時機:添加新特性時,修補錯誤時,複審代碼時。
程序有兩面價值「今天能夠爲你作什麼」和「明天能夠爲你作什麼」,若是隻關注今天的工做,那麼明天咱們將沒法工做,因此須要重構,來避免代碼出現如下四個狀況:難以閱讀,重複太多,新行爲沒法簡單添加,邏輯複雜。這四個狀況致使的結果都是程序難以改變(修改),而惟一不變的就是改變:-D
代碼的壞味道——重構的時機:重複代碼、過長函數、過大的類、過長的參數列、發散式變化、霰彈式修改、依戀情結、數據泥團、基本類型偏執、switch語句、平行繼承體系、冗贅類、誇誇其談將來性、臨時字段、過渡耦合的消息鏈、中間人、不適合的親暱關係、殊途同歸的類......
本書給出了一份重構列表,包含了不少不少的重構類型的名稱、動機、方法、範例,涵蓋了函數、對象、數據、表達式、調用、歸納關係、大型項目等方方面面,值得咱們借鑑,下面摘抄幾條做爲示例。
當我看見一個過長的函數或者一段須要註釋才能讓人理解用途的代碼就會把這段代碼放進一個獨立的函數中。短函數的好處:更可能被複用,讓高層函數看起來更清晰易懂,複寫更容易。「短」的含義不在代碼行數,而在於函數名稱和函數本體之間的語義距離。
若是一個類的某個方法、字段被另外一個類頻繁使用,就應該搬移該方法、字段。
混亂的繼承體系是一個嚴重的問題,由於它會致使重複的代碼,這正是程序員職業生涯的致命毒藥。它還會使修改變得困難,由於特定問題的解決策略被分散到了整個繼承體系,最終你的代碼難以理解。因此能夠經過創建多個繼承體系,並利用委託來互相調用,使得原來負責多個任務的繼承體系變成多個負責單個任務的繼承體系。
......
感受本書最大的問題就是太老了(1999年),有些工具或者方法在現在技術進步的狀況下顯得有些多餘,好比如今的IDE如Eclipse或者IDEA都有很強大的功能,書裏提到的一些技巧徹底用不着。不過經典終究是經典,裏面的絕大部分思想咱們現在都仍是能夠借鑑的,尤爲是對於重複代碼的觀點——應該堅定消滅重複。
花費了幾個月來看書,又花了幾天來整理,但願對咱們都有所幫助:-D。歡迎拍磚,個人主頁Mageek`s Wonderland。
查看原文