隔行如隔山,在别的行业的人看来,编程非常神秘,觉得很神奇,怎么就在电脑和手机上出现了那个效果呢?怎么就批量处理那么快呢?而对于行业内的人来说,这一切都非常简单,就跟开车、游泳、说英语一般,不会的人觉得好难,会了的人觉得好简单。今天就来系统化系地阐述下编程初学者应该如何学习编程。
编程究竟是个啥?
首先,编程是通过计算机语言来实现数据计算和逻辑控制操作,主要内容是数据结构加算法。数据计算就是加减乘除,逻辑操作就是如果那么否则或者以及循环等。数据结构就是数据的组织方式,是本字典还是书架抑或一张图表。算法就是依据计算机语言对数据进行逻辑处理。
其次,编程离不开编程语言,你需要通过编程语言给计算机下命令。说白了,就是你想让计算机做什么,你通过编程语言来告诉它。编程语言会将你的想法翻译为计算机能看懂的命令,然后去执行。编程语言有很多种,不同语言应用场景不同,但语法结构和基本概念大同小异,深入理解一门之后就可以轻松掌握其他的。
最后,编程很简单,比数学、语文、历史、地理等专业知识都要简单,人人都可以学会编程,但要学好编程并不容易,因为最好的程序员不是说掌握了多少门编程语言,也不是说某种程序有多少种写法,而是深入理解了某个专业或领域,利用编程语言解决了复杂的问题。这其实对于哪个行业来讲都并非易事,这需要理解各个领域的门道。
作为一个初学者,应该怎么样来学习编程呢?
编程有哪些需要掌握的知识呢?我这里进行了基本的总结,希望能够帮助到你。如果你对此有个基本的掌握,那么可以说是编程入门了,做一些项目开发不成问题。如果你能够深入掌握以下这些知识,那么成为编程高手只是迟早的事情。
(一)从基础学起
1、编程的基础是数据结构加算法。数据结构就是数据组织的方式,算法就是数据运算的过程。
2、选择一门流行的高级语言入手,哪一门都可以,找你认为看着最舒服的。比如C、Java、Python、JavaScript、Go、Swift……。具体应该从哪一门开始,可以看下之前写的关于入门语言选择。
3、选一个操作系统、运行环境和开发环境。比如Windows、Linux、Mac,语言SDK或浏览器。开发环境,也就是IDE。文本编辑器即可,比如记事本、Notepad++、Sublime、VSCode之类。
(二)熟悉语言规则
1、找一本编程语言书或者对着网上语言入门教程,不断重复地敲代码。编程语言无非是语法、句法和数据类型和内置对象、方法等。这些不同语言有些差异,但差异不大。C/C++或者Python、Java、JavaScript、Go均可。
2、不断地调试结果,变换一些变量、参数、条件进行尝试。通过大量测试,慢慢就会熟悉语法规则。真的很好理解,就是像是人说话一样,按照最简单的方式来,别整复杂的。
3、熟悉语言的基本语法、数据类型、流程控制等。语言跟说话差不多,你会说话那么就会编程。编程在于重复练习已经学过的知识,学而时习之、温故而知新。
以下是一段关于质因数分解的C语言代码,结合注释,看下是否很简单。
(三)学好数据结构
数据结构就是数据组织存储方式,也就是把数据聚合在一起,以便进行加工整理。把数据从一种结构换成另一种结构就是数据处理,这是编程最常见的工作。
1、数据一般分为整型、字节、浮点、字符、和布尔等类型,也就是生活中的数字和文字,把它按照一定规则分下类,不同语言略有些不同。
2、数据结构有两种分类方法:
- 线性结构(数据一一相连)和非线性结构(数据非一一相连)。
- 集合结构(数据无关系)、线性结构(数据一对一)、树形结构(数据一对多)、图形结构(数据多对多)。
3、常见的结构有以下8种:
- 堆栈(Stack),线性结构,后进先出。
- 队列(Queue),线性结构,先进先出。
- 数组(Array),聚合数据的集合,可以实现线性和非线性。
- 链表(Linked List),线性结构,数据以链式结构存储。
- 树(Tree),非线性结构,模拟树状结构性质的数据集合,一个顶点。
- 图(Graph),非线性结构,节点相互连接,每个节点都可以作为顶点。
- 堆(Heap),非线性结构,特殊的树形数据结构,一般指完全二叉树。
- 散列(Hash),线性结构,根据键访问储存位置的数据结构。
数据结构的概念一下子可能不好看懂,也不明确其中的区别。你可以把数据结构看成是一个个盛放东西的柜子或书架,里面有不同的东西。数据结构主要是用来给数据进行分门别类的,这样便于对于事物的归纳和理解。
(四)学好算法
算法那就是用计算机程序语言来解决某个问题的计算方法和步骤,比如从一堆数字中找出最大的一个,比如计算圆周率,比如实现一个文件加密和解密。
1、算法是一个计算的过程,包括加减乘除和逻辑运算。
算法人人都会,就是通过程序来一步步解决具体逻辑问题。其中有很多算法思想,采用好的思想远胜过一般思路。常见算法思想包括分治法、动态规划法、贪心算法、线性规划法、简并法等。
2、算法实现方式有递归与迭代。
递归是指在函数体里不断调用函数自身的方式。迭代是反复地运用同一计算方式的过程,一般是for和while循环。实现算法可以是串行计算、并行计算和分布式计算。
3、评价算法的优劣方式有时间复杂度和空间复杂度。
算法的时间复杂度是指算法执行所消耗的时间,用T(n)表示。算法执行时间通常是渐进式的,如果用函数f(n)来表示执行动作,大O符号来表示渐进性,则算法复杂度可以用 O(f(n)) 来表示,即T(n)=O(f(n))。算法的空间复杂度是指算法执行需要占用的空间,可以用S(n)来表示。算法占用的空间也是渐进性的,也可以用大O符号来描述,即S(n)=O(f(n))。时间复杂度和空间复杂度往往是相互影响的,但在表示一个算法的复杂度O(f(n))时,人们通常指的是时间复杂度。
4、常见的算法有哪些?
- 文本,字符串搜索、字符串压缩、最大公共子序列、回文计算等。主要是针对字符串进行查找。
- 数字,进制转换、开平方、斐波那契数列、质因数分解、数字三角形等。主要是进行数值的运算。
- 十大排序,冒泡、选择、插入、希尔、归并、快速、堆、计数、桶、基数等。这些跟打扑克排序和挑大小差不多,很好理解。
其他算法还有很多,什么动态规划、贪心、矩阵、回溯算法等,这些呢也有用,但是暂时不用掌握那么多。
学习和应用算法并不难,只要会走路、会做饭、会打牌、会下棋就会算法。难的是发明新的算法,但那属于数学家、计算机科学家或哲学家的工作。绝大部分程序员都不需要发明新的算法,而是掌握现成的算法,进行算法组合和策略调优。所以,学编程,掌握算法其实并不难,学习算法更多的是掌握不同解决问题的思路。如果不知道该写什么算法,可以去leetcode看别人的问题和例子,那有很多算法题和解法。
(五)学会找开源代码
掌握基本的数据结构和算法之后,然后就是看别人的源码。
1、找开源精品,去github找就行,任何语言的任何库,算法或数据结构源码,任何框架。优秀源代码太多了,这里不一一列举,找适合自己的练习。如何区分代码好坏?一是可以看他人的评价,二是看目录结构是否清晰,三是看编码规范和代码结构。
2、看优秀书籍的源码。优秀的书很多,乱七八糟的书也很多。看到不好的例子会深受其害。那该如何甄别呢?从stackoverflow或quora、medium上找热门帖子,或者从豆瓣看编程书籍排名。书籍最好看国外作者的书,尤其是某语言、框架的作者,或者大学老师,大企业里的高级工程师。那些书有共同点,就是讲得非常透彻,把来龙去脉搞得清清楚楚,不会模棱两可,不会胡吹海侃。有三种书可以不看,一是国内作者的书,二是某语言和框架速成书,三是某某开发应用实践。
3、找到好的源码后,就是不断练习,类似打字就行。一定要对照他人的源码,不断地敲。一开始看不懂,也不明白是对的,但敲的次数多了,也就领悟了。这跟读四书五经和老子是一个道理,看不懂就不断朗读即可,读得多了,慢慢就会有所理解。所谓读书百遍,其义自现。写程序也是这样,找到经典源码,反复对照练习。
这是第五个建议,当完成这一步了,那基本上是一个合格程序员了。
(六)学好设计模式
掌握了数据结构与算法,通过不断实践也积攒了大量的代码,也开发了一些小程序和Web系统了,现在需要进行优化代码了。
如何让代码更加整洁、清晰、有效,有利于维护和可扩展呢?这时候就需要用到设计模式(Design pattern),也就是通用最佳实践方案。
1、有哪些常见的设计模式?
根据设计模式的参考书 Design Patterns - Elements of Reusable Object-Oriented Software中所提到的,总共有 23 种设计模式。总结起来有这么几个类型。
- 是创建型模式,也就是创建时不是直接new出一个实例,而是把new这个操作隐藏在方法背后,而是根据需要来创建对象。比如工厂、抽象工厂、原型、单例、建造者等5种。
- 是结构型模式,这里主要是类的继承被对象组合所替代的模式。有适配器、桥接、组合、装饰器、外观、享元、代理模式等7种。
- 是行为类模式,主要关注对象之间的通信问题。包括责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板模式、访问者模式等。
2、设计模式的7大原则。
- 开闭原则,对扩展开放,对修改关闭。希望程序扩展功能的时候,通过开放的接口来实现,而不是修改代码。
- 里氏替换原则,任何父类出现的地方,子类也可以出现。子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
- 单一职责原则,对一个类来说的,职责应该单一,只做一件或一类具体的事情。
- 依赖倒置原则,是开闭原则的基础。指针对接口编程,高层模块不应该依赖低层模块,二者都依赖于抽象而不依赖于具体实现编程。
- 接口隔离原则,一个类对另一个类的依赖应该建立在最小的接口上,不依赖不需要的接口。尽量强调降低依赖,降低耦合。
- 迪米特法则,又称最少知道原则,一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
- 合成复用原则,写代码会涉及到代码复用,尽量使用组合而少使用继承。大多数情况下组合可以替代继承。
这几个原则也是面向对象编程原则,也有说6个的。总体上的意思是代码需要重用、要便于扩展,尽量通过抽象来解耦,尽量减少依赖关系。
2、设计模式和分层架构的区别?
软件是一个服务或功能集合,可大可小,有的是一个房间,有的是一座楼房、一个小区、一个学校乃至一座城市。软件需要架构设计,让各模块各司其职,相互协调。那么就需要良好的架构设计。软件架构有很多角度,有部署架构、内核架构、服务架构等。这里说的分层架构主要是指软件设计按照能力划分不同层级,常见软件分层包括数据层、持久层、业务层、表现层。常见分层架构有MVC、MVP、MVVM、DDD模式等。
设计模式与分层架构的主要区别是设计模式解决具体的类和类之间关系的设计思想,而分层架构则是解决软件整体的设计思想。
3、设计模式要适应业务需要。
设计模式是一种原则和思想,业务逻辑应该遵循这些原则去划分和拆解,但当遇到冲突时应该尊重业务需要,而不是让业务来遵循原则。避免走入教条主义或本本主义,而是在坚持原则的情况下灵活应变。
(七)熟悉正则表达式
正则表达式(regular expression)是一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串,再将匹配的子串替换为其他字符。正则表达式几乎是每一门语言所必备的功能,也是每一个开发人员所应该掌握的能力。
1、懂得正则表达式, 开发起来就变得非常灵活,很多事情都变得得心易手。无论是shell脚本,还是各种编程语言,或者是文本编辑器,都存在大量查找替换的情形。掌握正则表达式,可谓事半功倍,效率得到极大提升。
2、通过基本字符规则,加上限定符、修饰符等组成一个基本的规则器,可以针对文本按照规则进行解析。比如 ^[a-z][0-9] 表示匹配2个字符,第一个是小写字母,第二个是数字。
3、大学里一般也不教正则表达式,再加上正则表达式偏向实践应用,理论上并不复杂,因此正则表达式可以通过大量练习来变得熟练。可以找几十个不同的场景反复加以练习,直到自己写的规则一点不差。
4、正则表达式并不需要精通掌握,掌握基本规则即可,简单语句就可以满足大部分场景。不要写过于复杂的正则表达式,对于复杂的场景应用,可以结合逻辑代码来完成。
(八)熟悉网络分层协议
网络要想有效地传输信息,那么需要良好的分层架构。网络请求的基本模型就是从客户端请求数据,客户端接受响应后返回。
根据国际标准化组织设定的OSI模型,网络可以分为7层。通过这7层,数据将从一台主机传送到另一台机器。而我们一般学习通常是4层或5层,以下是它们的对比图。
- 第一层:物理层(Physical)(单位类型:比特):实现比特流的透明传输,物理接口,指网线、网卡等物理设备。
- 第二层:数据链路层(Data Link)(单位类型:帧):数据在该层封装成帧;用MAC地址作为访问媒介;具有错误检测与修正功能。
- 第三层:网络层(Network)(单位类型:报文):提供逻辑地址,选择路由数据包,负责在源和终点之间建立连接,通常是IP之类。
- 第四层:传输层(Transport):实现端到端传输;分可靠与不可靠传输;在传输前实现错误检测与流量控制,通常是TCP和UDP。
- 第五层:会话层(Session):主机间通信;对应用进行会话管理,同步不同机器之间的状态。
- 第六层:表示层(Presention):数据表现形式;比如原始设备上加密的数据可以在目标设备上正确地解密。
- 第七层:应用层(Application):网络进程访问应用层,给用户使用的应用协议,如HTTP或FTP之类。
理解了网络分层,还需要熟悉TCP/IP协议,因为互联网大都是基于TCP/IP来进行传递数据的。TCP建立连接分为3次握手,握手成功则可以传递数据,断开连接称为4次挥手。了解TCP/IP之后,还需要掌握HTTP协议,HTTP很简单,按照格式提交数据和接受数据即可。在掌握了基本的网络分层、TCP/IP、HTTP知识后,那么就可以进行网络编程开发了。
(九)熟悉数据库
数据库就是根据数据结构来组织、存储和管理数据的仓库,这里不说大数据,只说普通的关系型和非关系型数据库。
可以把关系型数据库(RDBS)理解为一个Excel表格,每列是字段,每行就是一条记录。Excel有多个二维表,每个表都是由行和列组成的。关系数据库里存放的也是一张张二维表,各个表之间存在关系。简单来说:关系数据库由多张二维表和各表之间的关系组成。
非关系型数据库,也叫NoSQL则可以理解为一个Key-Value文档树,里面有很多属性,每个属性对应一个值。NoSQL 数据库的类型因数据模型而异,主要类型包括文档、键值、宽列和图形。
关系型数据库通过SQL来进行增(Create)删(Delete)查(Read)改(Update)操作,已实现对数据的管理。SQL语句很简单,类似用英语说指令,稍微熟悉即可掌握。但要设计一套优雅的业务数据库,却并非易事,尤其是对于复杂业务来讲,我们的设计需要符合数据库设计范式。当然数据库范式也很简单,主要目的在于表和表之间的独立和解耦,便于未来扩展和数据的修改、查找等,为了设计好数据库,一般会设计ER实体关系图(Entity Relationship Diagram)。关系型数据库为保证一个数据操作事务(transaction)的正确可靠,一般要求具备四个特性:原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)。这些概念,随着数据库的开发经验积累渐渐就明白了。
NoSQL数据库不需要建立关系模型,因此存储结构比较简单,在查询会非常快。NoSQL相比关系型数据库还可以更方面扩容和做分布式设计,非常灵活。NoSQL各文档间缺乏标准化规则,通常采用针对文档按对象进行链式调用来查询,这样在写语句时不如SQL那么强大,而且有时候需要多次连接,同时它也不提供事务的一致性。当数据量增加时,由于key变得困难,很难维护key的唯一性。
由于RDBS和NoSQL的特性,一般关系型数据库会用来做强关系的业务系统,而非关系型数据库则用来做高性能的缓存、键值读取等。当然理论上NoSQL和MySQL可以互相替代。
作为程序员,不是DBA,一般掌握基本的SQL和NoSQL语句即可,不一定需要多么强大的数据设计和管理能力,但一定要理解其中的基本原理。数据库的设计和操作对于系统健壮性和性能至关重要。
(十)熟悉操作系统
PC操作系统主要是3个,Linux、Windows以及Mac,手机端有iOS和Android。Windows大家都会用,作为开发人员,主要是熟悉Linux即可。如何才能熟悉操作系统呢?其实对于应用层程序员,不是做系统开发,并不需要深入理解操作系统的原理和结构,只要掌握大部分命令就够了。
这些命令掌握起来其实很简单,看一篇命令大全,再实操演练,强化理解,自然就会了。可以说操作系统命令以及Shell脚本并不难,只是一个熟能生巧的过程。看到全是命令行,会使得初学者有点担心,觉得不好理解。但其实对于开发者而言,命令行要远比操作界面方便。
- 操作系统基本结构
- Linux常用开发命令
再次强调,学习编程其实与操作系统关系并不大,有很多程序语言是基于虚拟机或浏览器运行 ,有专门的运行环境,因此只有系统开发工程师才需要非常熟悉操作系统。对于大多数程序员而言,掌握基本的系统命令,理解操作系统结构就够了。
最后
至此,关于如何学好编程的10条入门建议就完成了。只要把以上涉及到的知识点掌握了,就可以说编程入门了,找一份编程的工作不成问题。学好编程,最核心的还是数据结构和算法,掌握这两样基本上就会编程了。而数据结构和算法,其实就是对于事物的归纳理解以及逻辑推理能力,这个按理来说人人都会。软件开发无非是解决一些特定的问题,与人们生活中要解决的问题并无本质的不同。因此,人人都可以学习编程,人人都可以学好编程。
重要的事情说三遍:编程很简单!编程很简单!编程很简单!