隔行如隔山,在別的行業(yè)的人看來,編程非常神秘,覺得很神奇,怎么就在電腦和手機上出現(xiàn)了那個效果呢?怎么就批量處理那么快呢?而對于行業(yè)內(nèi)的人來說,這一切都非常簡單,就跟開車、游泳、說英語一般,不會的人覺得好難,會了的人覺得好簡單。今天就來系統(tǒng)化系地闡述下編程初學者應該如何學習編程。
編程究竟是個啥?
首先,編程是通過計算機語言來實現(xiàn)數(shù)據(jù)計算和邏輯控制操作,主要內(nèi)容是數(shù)據(jù)結構加算法。數(shù)據(jù)計算就是加減乘除,邏輯操作就是如果那么否則或者以及循環(huán)等。數(shù)據(jù)結構就是數(shù)據(jù)的組織方式,是本字典還是書架抑或一張圖表。算法就是依據(jù)計算機語言對數(shù)據(jù)進行邏輯處理。
其次,編程離不開編程語言,你需要通過編程語言給計算機下命令。說白了,就是你想讓計算機做什么,你通過編程語言來告訴它。編程語言會將你的想法翻譯為計算機能看懂的命令,然后去執(zhí)行。編程語言有很多種,不同語言應用場景不同,但語法結構和基本概念大同小異,深入理解一門之后就可以輕松掌握其他的。
最后,編程很簡單,比數(shù)學、語文、歷史、地理等專業(yè)知識都要簡單,人人都可以學會編程,但要學好編程并不容易,因為最好的程序員不是說掌握了多少門編程語言,也不是說某種程序有多少種寫法,而是深入理解了某個專業(yè)或領域,利用編程語言解決了復雜的問題。這其實對于哪個行業(yè)來講都并非易事,這需要理解各個領域的門道。

作為一個初學者,應該怎么樣來學習編程呢?
編程有哪些需要掌握的知識呢?我這里進行了基本的總結,希望能夠幫助到你。如果你對此有個基本的掌握,那么可以說是編程入門了,做一些項目開發(fā)不成問題。如果你能夠深入掌握以下這些知識,那么成為編程高手只是遲早的事情。
(一)從基礎學起
1、編程的基礎是數(shù)據(jù)結構加算法。數(shù)據(jù)結構就是數(shù)據(jù)組織的方式,算法就是數(shù)據(jù)運算的過程。
2、選擇一門流行的高級語言入手,哪一門都可以,找你認為看著最舒服的。比如C、Java、Python、JavaScript、Go、Swift……。具體應該從哪一門開始,可以看下之前寫的關于入門語言選擇。

3、選一個操作系統(tǒng)、運行環(huán)境和開發(fā)環(huán)境。比如Windows、Linux、Mac,語言SDK或瀏覽器。開發(fā)環(huán)境,也就是IDE。文本編輯器即可,比如記事本、Notepad++、Sublime、VSCode之類。
(二)熟悉語言規(guī)則
1、找一本編程語言書或者對著網(wǎng)上語言入門教程,不斷重復地敲代碼。編程語言無非是語法、句法和數(shù)據(jù)類型和內(nèi)置對象、方法等。這些不同語言有些差異,但差異不大。C/C++或者Python、Java、JavaScript、Go均可。
2、不斷地調試結果,變換一些變量、參數(shù)、條件進行嘗試。通過大量測試,慢慢就會熟悉語法規(guī)則。真的很好理解,就是像是人說話一樣,按照最簡單的方式來,別整復雜的。
3、熟悉語言的基本語法、數(shù)據(jù)類型、流程控制等。語言跟說話差不多,你會說話那么就會編程。編程在于重復練習已經(jīng)學過的知識,學而時習之、溫故而知新。
以下是一段關于質因數(shù)分解的C語言代碼,結合注釋,看下是否很簡單。

(三)學好數(shù)據(jù)結構
數(shù)據(jù)結構就是數(shù)據(jù)組織存儲方式,也就是把數(shù)據(jù)聚合在一起,以便進行加工整理。把數(shù)據(jù)從一種結構換成另一種結構就是數(shù)據(jù)處理,這是編程最常見的工作。
1、數(shù)據(jù)一般分為整型、字節(jié)、浮點、字符、和布爾等類型,也就是生活中的數(shù)字和文字,把它按照一定規(guī)則分下類,不同語言略有些不同。
2、數(shù)據(jù)結構有兩種分類方法:
- 線性結構(數(shù)據(jù)一一相連)和非線性結構(數(shù)據(jù)非一一相連)。
- 集合結構(數(shù)據(jù)無關系)、線性結構(數(shù)據(jù)一對一)、樹形結構(數(shù)據(jù)一對多)、圖形結構(數(shù)據(jù)多對多)。
3、常見的結構有以下8種:
- 堆棧(Stack),線性結構,后進先出。
- 隊列(Queue),線性結構,先進先出。
- 數(shù)組(Array),聚合數(shù)據(jù)的集合,可以實現(xiàn)線性和非線性。
- 鏈表(Linked List),線性結構,數(shù)據(jù)以鏈式結構存儲。
- 樹(Tree),非線性結構,模擬樹狀結構性質的數(shù)據(jù)集合,一個頂點。
- 圖(Graph),非線性結構,節(jié)點相互連接,每個節(jié)點都可以作為頂點。
- 堆(Heap),非線性結構,特殊的樹形數(shù)據(jù)結構,一般指完全二叉樹。
- 散列(Hash),線性結構,根據(jù)鍵訪問儲存位置的數(shù)據(jù)結構。

數(shù)據(jù)結構的概念一下子可能不好看懂,也不明確其中的區(qū)別。你可以把數(shù)據(jù)結構看成是一個個盛放東西的柜子或書架,里面有不同的東西。數(shù)據(jù)結構主要是用來給數(shù)據(jù)進行分門別類的,這樣便于對于事物的歸納和理解。
(四)學好算法
算法那就是用計算機程序語言來解決某個問題的計算方法和步驟,比如從一堆數(shù)字中找出最大的一個,比如計算圓周率,比如實現(xiàn)一個文件加密和解密。
1、算法是一個計算的過程,包括加減乘除和邏輯運算。
算法人人都會,就是通過程序來一步步解決具體邏輯問題。其中有很多算法思想,采用好的思想遠勝過一般思路。常見算法思想包括分治法、動態(tài)規(guī)劃法、貪心算法、線性規(guī)劃法、簡并法等。

2、算法實現(xiàn)方式有遞歸與迭代。
遞歸是指在函數(shù)體里不斷調用函數(shù)自身的方式。迭代是反復地運用同一計算方式的過程,一般是for和while循環(huán)。實現(xiàn)算法可以是串行計算、并行計算和分布式計算。
3、評價算法的優(yōu)劣方式有時間復雜度和空間復雜度。
算法的時間復雜度是指算法執(zhí)行所消耗的時間,用T(n)表示。算法執(zhí)行時間通常是漸進式的,如果用函數(shù)f(n)來表示執(zhí)行動作,大O符號來表示漸進性,則算法復雜度可以用 O(f(n)) 來表示,即T(n)=O(f(n))。算法的空間復雜度是指算法執(zhí)行需要占用的空間,可以用S(n)來表示。算法占用的空間也是漸進性的,也可以用大O符號來描述,即S(n)=O(f(n))。時間復雜度和空間復雜度往往是相互影響的,但在表示一個算法的復雜度O(f(n))時,人們通常指的是時間復雜度。
4、常見的算法有哪些?
- 文本,字符串搜索、字符串壓縮、最大公共子序列、回文計算等。主要是針對字符串進行查找。
- 數(shù)字,進制轉換、開平方、斐波那契數(shù)列、質因數(shù)分解、數(shù)字三角形等。主要是進行數(shù)值的運算。
- 十大排序,冒泡、選擇、插入、希爾、歸并、快速、堆、計數(shù)、桶、基數(shù)等。這些跟打撲克排序和挑大小差不多,很好理解。

其他算法還有很多,什么動態(tài)規(guī)劃、貪心、矩陣、回溯算法等,這些呢也有用,但是暫時不用掌握那么多。
學習和應用算法并不難,只要會走路、會做飯、會打牌、會下棋就會算法。難的是發(fā)明新的算法,但那屬于數(shù)學家、計算機科學家或哲學家的工作。絕大部分程序員都不需要發(fā)明新的算法,而是掌握現(xiàn)成的算法,進行算法組合和策略調優(yōu)。所以,學編程,掌握算法其實并不難,學習算法更多的是掌握不同解決問題的思路。如果不知道該寫什么算法,可以去leetcode看別人的問題和例子,那有很多算法題和解法。
(五)學會找開源代碼
掌握基本的數(shù)據(jù)結構和算法之后,然后就是看別人的源碼。
1、找開源精品,去github找就行,任何語言的任何庫,算法或數(shù)據(jù)結構源碼,任何框架。優(yōu)秀源代碼太多了,這里不一一列舉,找適合自己的練習。如何區(qū)分代碼好壞?一是可以看他人的評價,二是看目錄結構是否清晰,三是看編碼規(guī)范和代碼結構。

2、看優(yōu)秀書籍的源碼。優(yōu)秀的書很多,亂七八糟的書也很多??吹讲缓玫睦訒钍芷浜?。那該如何甄別呢?從stackoverflow或quora、medium上找熱門帖子,或者從豆瓣看編程書籍排名。書籍最好看國外作者的書,尤其是某語言、框架的作者,或者大學老師,大企業(yè)里的高級工程師。那些書有共同點,就是講得非常透徹,把來龍去脈搞得清清楚楚,不會模棱兩可,不會胡吹海侃。有三種書可以不看,一是國內(nèi)作者的書,二是某語言和框架速成書,三是某某開發(fā)應用實踐。

3、找到好的源碼后,就是不斷練習,類似打字就行。一定要對照他人的源碼,不斷地敲。一開始看不懂,也不明白是對的,但敲的次數(shù)多了,也就領悟了。這跟讀四書五經(jīng)和老子是一個道理,看不懂就不斷朗讀即可,讀得多了,慢慢就會有所理解。所謂讀書百遍,其義自現(xiàn)。寫程序也是這樣,找到經(jīng)典源碼,反復對照練習。
這是第五個建議,當完成這一步了,那基本上是一個合格程序員了。
(六)學好設計模式
掌握了數(shù)據(jù)結構與算法,通過不斷實踐也積攢了大量的代碼,也開發(fā)了一些小程序和Web系統(tǒng)了,現(xiàn)在需要進行優(yōu)化代碼了。
如何讓代碼更加整潔、清晰、有效,有利于維護和可擴展呢?這時候就需要用到設計模式(Design pattern),也就是通用最佳實踐方案。
1、有哪些常見的設計模式?
根據(jù)設計模式的參考書 Design Patterns - Elements of Reusable Object-Oriented Software中所提到的,總共有 23 種設計模式??偨Y起來有這么幾個類型。
- 是創(chuàng)建型模式,也就是創(chuàng)建時不是直接new出一個實例,而是把new這個操作隱藏在方法背后,而是根據(jù)需要來創(chuàng)建對象。比如工廠、抽象工廠、原型、單例、建造者等5種。
- 是結構型模式,這里主要是類的繼承被對象組合所替代的模式。有適配器、橋接、組合、裝飾器、外觀、享元、代理模式等7種。
- 是行為類模式,主要關注對象之間的通信問題。包括責任鏈模式、命令模式、解釋器模式、迭代器模式、中介者模式、備忘錄模式、觀察者模式、狀態(tài)模式、策略模式、模板模式、訪問者模式等。

2、設計模式的7大原則。
- 開閉原則,對擴展開放,對修改關閉。希望程序擴展功能的時候,通過開放的接口來實現(xiàn),而不是修改代碼。
- 里氏替換原則,任何父類出現(xiàn)的地方,子類也可以出現(xiàn)。子類可以實現(xiàn)父類的抽象方法,但不能覆蓋父類的非抽象方法。
- 單一職責原則,對一個類來說的,職責應該單一,只做一件或一類具體的事情。
- 依賴倒置原則,是開閉原則的基礎。指針對接口編程,高層模塊不應該依賴低層模塊,二者都依賴于抽象而不依賴于具體實現(xiàn)編程。
- 接口隔離原則,一個類對另一個類的依賴應該建立在最小的接口上,不依賴不需要的接口。盡量強調降低依賴,降低耦合。
- 迪米特法則,又稱最少知道原則,一個實體應當盡量少地與其他實體之間發(fā)生相互作用,使得系統(tǒng)功能模塊相對獨立。
- 合成復用原則,寫代碼會涉及到代碼復用,盡量使用組合而少使用繼承。大多數(shù)情況下組合可以替代繼承。
這幾個原則也是面向對象編程原則,也有說6個的。總體上的意思是代碼需要重用、要便于擴展,盡量通過抽象來解耦,盡量減少依賴關系。
2、設計模式和分層架構的區(qū)別?
軟件是一個服務或功能集合,可大可小,有的是一個房間,有的是一座樓房、一個小區(qū)、一個學校乃至一座城市。軟件需要架構設計,讓各模塊各司其職,相互協(xié)調。那么就需要良好的架構設計。軟件架構有很多角度,有部署架構、內(nèi)核架構、服務架構等。這里說的分層架構主要是指軟件設計按照能力劃分不同層級,常見軟件分層包括數(shù)據(jù)層、持久層、業(yè)務層、表現(xiàn)層。常見分層架構有MVC、MVP、MVVM、DDD模式等。


設計模式與分層架構的主要區(qū)別是設計模式解決具體的類和類之間關系的設計思想,而分層架構則是解決軟件整體的設計思想。
3、設計模式要適應業(yè)務需要。
設計模式是一種原則和思想,業(yè)務邏輯應該遵循這些原則去劃分和拆解,但當遇到?jīng)_突時應該尊重業(yè)務需要,而不是讓業(yè)務來遵循原則。避免走入教條主義或本本主義,而是在堅持原則的情況下靈活應變。
(七)熟悉正則表達式
正則表達式(regular expression)是一種字符串匹配的模式(pattern),可以用來檢查一個串是否含有某種子串,再將匹配的子串替換為其他字符。正則表達式幾乎是每一門語言所必備的功能,也是每一個開發(fā)人員所應該掌握的能力。
1、懂得正則表達式, 開發(fā)起來就變得非常靈活,很多事情都變得得心易手。無論是shell腳本,還是各種編程語言,或者是文本編輯器,都存在大量查找替換的情形。掌握正則表達式,可謂事半功倍,效率得到極大提升。

2、通過基本字符規(guī)則,加上限定符、修飾符等組成一個基本的規(guī)則器,可以針對文本按照規(guī)則進行解析。比如 ^[a-z][0-9] 表示匹配2個字符,第一個是小寫字母,第二個是數(shù)字。

3、大學里一般也不教正則表達式,再加上正則表達式偏向實踐應用,理論上并不復雜,因此正則表達式可以通過大量練習來變得熟練??梢哉?guī)资畟€不同的場景反復加以練習,直到自己寫的規(guī)則一點不差。
4、正則表達式并不需要精通掌握,掌握基本規(guī)則即可,簡單語句就可以滿足大部分場景。不要寫過于復雜的正則表達式,對于復雜的場景應用,可以結合邏輯代碼來完成。

(八)熟悉網(wǎng)絡分層協(xié)議
網(wǎng)絡要想有效地傳輸信息,那么需要良好的分層架構。網(wǎng)絡請求的基本模型就是從客戶端請求數(shù)據(jù),客戶端接受響應后返回。

根據(jù)國際標準化組織設定的OSI模型,網(wǎng)絡可以分為7層。通過這7層,數(shù)據(jù)將從一臺主機傳送到另一臺機器。而我們一般學習通常是4層或5層,以下是它們的對比圖。

- 第一層:物理層(Physical)(單位類型:比特):實現(xiàn)比特流的透明傳輸,物理接口,指網(wǎng)線、網(wǎng)卡等物理設備。
- 第二層:數(shù)據(jù)鏈路層(Data Link)(單位類型:幀):數(shù)據(jù)在該層封裝成幀;用MAC地址作為訪問媒介;具有錯誤檢測與修正功能。
- 第三層:網(wǎng)絡層(Network)(單位類型:報文):提供邏輯地址,選擇路由數(shù)據(jù)包,負責在源和終點之間建立連接,通常是IP之類。
- 第四層:傳輸層(Transport):實現(xiàn)端到端傳輸;分可靠與不可靠傳輸;在傳輸前實現(xiàn)錯誤檢測與流量控制,通常是TCP和UDP。
- 第五層:會話層(Session):主機間通信;對應用進行會話管理,同步不同機器之間的狀態(tài)。
- 第六層:表示層(Presention):數(shù)據(jù)表現(xiàn)形式;比如原始設備上加密的數(shù)據(jù)可以在目標設備上正確地解密。
- 第七層:應用層(Application):網(wǎng)絡進程訪問應用層,給用戶使用的應用協(xié)議,如HTTP或FTP之類。

理解了網(wǎng)絡分層,還需要熟悉TCP/IP協(xié)議,因為互聯(lián)網(wǎng)大都是基于TCP/IP來進行傳遞數(shù)據(jù)的。TCP建立連接分為3次握手,握手成功則可以傳遞數(shù)據(jù),斷開連接稱為4次揮手。了解TCP/IP之后,還需要掌握HTTP協(xié)議,HTTP很簡單,按照格式提交數(shù)據(jù)和接受數(shù)據(jù)即可。在掌握了基本的網(wǎng)絡分層、TCP/IP、HTTP知識后,那么就可以進行網(wǎng)絡編程開發(fā)了。
(九)熟悉數(shù)據(jù)庫
數(shù)據(jù)庫就是根據(jù)數(shù)據(jù)結構來組織、存儲和管理數(shù)據(jù)的倉庫,這里不說大數(shù)據(jù),只說普通的關系型和非關系型數(shù)據(jù)庫。
可以把關系型數(shù)據(jù)庫(RDBS)理解為一個Excel表格,每列是字段,每行就是一條記錄。Excel有多個二維表,每個表都是由行和列組成的。關系數(shù)據(jù)庫里存放的也是一張張二維表,各個表之間存在關系。簡單來說:關系數(shù)據(jù)庫由多張二維表和各表之間的關系組成。
非關系型數(shù)據(jù)庫,也叫NoSQL則可以理解為一個Key-Value文檔樹,里面有很多屬性,每個屬性對應一個值。NoSQL 數(shù)據(jù)庫的類型因數(shù)據(jù)模型而異,主要類型包括文檔、鍵值、寬列和圖形。

關系型數(shù)據(jù)庫通過SQL來進行增(Create)刪(Delete)查(Read)改(Update)操作,已實現(xiàn)對數(shù)據(jù)的管理。SQL語句很簡單,類似用英語說指令,稍微熟悉即可掌握。但要設計一套優(yōu)雅的業(yè)務數(shù)據(jù)庫,卻并非易事,尤其是對于復雜業(yè)務來講,我們的設計需要符合數(shù)據(jù)庫設計范式。當然數(shù)據(jù)庫范式也很簡單,主要目的在于表和表之間的獨立和解耦,便于未來擴展和數(shù)據(jù)的修改、查找等,為了設計好數(shù)據(jù)庫,一般會設計ER實體關系圖(Entity Relationship Diagram)。關系型數(shù)據(jù)庫為保證一個數(shù)據(jù)操作事務(transaction)的正確可靠,一般要求具備四個特性:原子性(atomicity,或稱不可分割性)、一致性(consistency)、隔離性(isolation,又稱獨立性)、持久性(durability)。這些概念,隨著數(shù)據(jù)庫的開發(fā)經(jīng)驗積累漸漸就明白了。
NoSQL數(shù)據(jù)庫不需要建立關系模型,因此存儲結構比較簡單,在查詢會非???。NoSQL相比關系型數(shù)據(jù)庫還可以更方面擴容和做分布式設計,非常靈活。NoSQL各文檔間缺乏標準化規(guī)則,通常采用針對文檔按對象進行鏈式調用來查詢,這樣在寫語句時不如SQL那么強大,而且有時候需要多次連接,同時它也不提供事務的一致性。當數(shù)據(jù)量增加時,由于key變得困難,很難維護key的唯一性。

由于RDBS和NoSQL的特性,一般關系型數(shù)據(jù)庫會用來做強關系的業(yè)務系統(tǒng),而非關系型數(shù)據(jù)庫則用來做高性能的緩存、鍵值讀取等。當然理論上NoSQL和MySQL可以互相替代。
作為程序員,不是DBA,一般掌握基本的SQL和NoSQL語句即可,不一定需要多么強大的數(shù)據(jù)設計和管理能力,但一定要理解其中的基本原理。數(shù)據(jù)庫的設計和操作對于系統(tǒng)健壯性和性能至關重要。
(十)熟悉操作系統(tǒng)
PC操作系統(tǒng)主要是3個,Linux、Windows以及Mac,手機端有iOS和Android。Windows大家都會用,作為開發(fā)人員,主要是熟悉Linux即可。如何才能熟悉操作系統(tǒng)呢?其實對于應用層程序員,不是做系統(tǒng)開發(fā),并不需要深入理解操作系統(tǒng)的原理和結構,只要掌握大部分命令就夠了。
這些命令掌握起來其實很簡單,看一篇命令大全,再實操演練,強化理解,自然就會了。可以說操作系統(tǒng)命令以及Shell腳本并不難,只是一個熟能生巧的過程。看到全是命令行,會使得初學者有點擔心,覺得不好理解。但其實對于開發(fā)者而言,命令行要遠比操作界面方便。
- 操作系統(tǒng)基本結構

- Linux常用開發(fā)命令

再次強調,學習編程其實與操作系統(tǒng)關系并不大,有很多程序語言是基于虛擬機或瀏覽器運行 ,有專門的運行環(huán)境,因此只有系統(tǒng)開發(fā)工程師才需要非常熟悉操作系統(tǒng)。對于大多數(shù)程序員而言,掌握基本的系統(tǒng)命令,理解操作系統(tǒng)結構就夠了。
最后
至此,關于如何學好編程的10條入門建議就完成了。只要把以上涉及到的知識點掌握了,就可以說編程入門了,找一份編程的工作不成問題。學好編程,最核心的還是數(shù)據(jù)結構和算法,掌握這兩樣基本上就會編程了。而數(shù)據(jù)結構和算法,其實就是對于事物的歸納理解以及邏輯推理能力,這個按理來說人人都會。軟件開發(fā)無非是解決一些特定的問題,與人們生活中要解決的問題并無本質的不同。因此,人人都可以學習編程,人人都可以學好編程。
重要的事情說三遍:編程很簡單!編程很簡單!編程很簡單!