程序员编程能⼒7个能⼒提升阶段分析
前⾔
程序员的编程技能随着经验的积累,会逐步提⾼。我认为编程能⼒可以分为⼀些层次。
百⽜信息技术bainiu.ltd整理发布于博客园
下⾯通过两个维度展开编程能⼒层次模型的讨论。
⼀个维度是编程技能层次,另⼀个维度是领域知识层次。
编程技能层次
编程技能层次,指的程序员设计和编写程序的能⼒。这是程序员的根本。
0段—⾮程序员:
初学编程者,遇到问题,完全是懵懵懂懂,不知道该怎么编程解决问题。也就是说,还是门外汉,还不能称之为“程序员”。计算机在他⾯前还是⼀个神秘的⿊匣⼦。
1段—基础程序员:
学习过⼀段时间编程后,接到任务,可以编写程序完成任务。
编写出来的代码,正常情况下是能够⼯作的,但在实际运⾏中,碰到⼀些特殊条件就会出现各类BUG。也就是说,具备了开发Demo软件的能⼒,但开发的软件真正交付给客户使⽤,恐怕会被客户骂死。
程序员程序是写好了,但到底为什么它有时能正常⼯作,有时⼜不⾏,程序员⾃⼰也不知道。
运⾏中遇到了bug,或者需求改变,需要修改代码或者添加代码,很快程序就变得结构混乱,代码膨胀,bug丛⽣。很快,就连最初的开发者⾃⼰也不愿意接⼿维护这个程序了。
2段—数据结构:
经过⼀段时间的编程实践后,程序员会认识到“数据结构算法=程序”这⼀古训的含义。他们会使⽤算法来解决问题。进⽽,他们会认识到,算法本质上是依附于数据结构的,好的数据结构⼀旦设计出来,那么好的算法也会应运⽽⽣。
设计错误的数据结构,不可能⽣长出好的算法。
记得某⼀位外国先贤曾经说过:“给我看你的数据结构!”
3段—⾯向对象:
再之后,程序员就会领略⾯向对象程序设计的强⼤威⼒。⼤多数现代编程语⾔都是⽀持⾯向对象的。但并不是说,你使⽤⾯向对象编程语⾔编程,你⽤上了类,甚⾄继承了类,你就是在写⾯向对象的代码了。
我曾经见过很多⽤Java,Python,Ruby写的⾯向过程的代码。
只有你掌握了接⼝,掌握了多态,掌握了类和类,对象和对象之间的关系,你才真正掌握了⾯向对象编程技术。
就算你⽤的是传统的不⽀持⾯向对象的编程语⾔,只要你⼼中有“对象”,你依然可以开发出⾯向对象的程序。
如,我⽤C语⾔编程的时候,会有意识的使⽤⾯向对象的技巧来编写和设计程序。⽤struct来模拟类,把同⼀类概念的函数放在⼀起模拟类。如果你怀疑⽤C语⾔是否能编写出⾯向对象的代码,你可以看⼀下Linux内核,它是⽤C语⾔编写的,但你也可以看到它的源代码字⾥⾏间散发出的浓浓的“对象”的味道。
真正掌握⾯向对象编程技术并不容易。
在我的技术⽣涯中,有两个坎让我最感头疼。
⼀个坎是Dos向Windows开发的变迁过程中,框架的概念,很长⼀段时间我都理解不了。Dos时代,都是对函数库的调⽤,你的程序主动调⽤函数。Windows时代,则换成了框架。就算是你的main程序,其实也是被框架调⽤的。UI线程会从操作系统获取消息,然后发送给你的程序来处理。Java程序员熟悉的Spring框架,也是这样⼀个反向调⽤的框架。
现在因为“框架”这个术语显得很⾼⼤上,因此很多“类库”/“函数库”都⾃称为“框架”。在我看来这都是名称的滥⽤。
“类库”/“函数库”就是我写的代码调⽤它们。
“框架”就是我注册回调函数到框架,框架来调⽤我写的函数。
另⼀个坎就是⾯向对象。很长⼀段时间我都不知道应该怎么设计类和类之间的关系,不能很好的设计出类层次结构来。
我记得当时看到⼀本外国⼤⽜的书,他讲了⼀个很简单、很实⽤的⾯向对象设计技巧:“叙述问题。然后把其中的名词出来,⽤来构建类。把其中的动词出来,⽤来构建类的⽅法”。虽然这个技巧挺管⽤的,但也太草根了点,没有理论依据,也不严谨。如果问题叙述的不好,那么获得的类系统就会是有问题的。
掌握⾯向对象思想的途径应该有很多种,我是从关系数据库中获得了灵感来理解和掌握⾯向对象设计思想的。
在我看来,关系数据库的表,其实就是⼀个类,每⼀⾏记录就是⼀个类的实例,也就是对象。表之间的关系,就是类之间的关系。O-Rmapping技术(如Hibernate),⽤于从⾯向对象代码到数据库表之间的映射,这也说明了类和表确实是逻辑上等价的。
既然数据库设计和类设计是等价的,那么要设计⾯向对象系统,只需要使⽤关系数据库的设计技巧即可。
关系数据库表结构设计是很简单的:
1、识别表和表之间的关系,也就是类和类之间的关系。是⼀对⼀,⼀对多,多对⼀,还是多对多。这就是类之间的关系。
2、识别表的字段。⼀个对象当然有⽆数多的属性(如,⼈:⾝⾼,体重,性别,年龄,姓名,⾝份证号,驾驶证号,银⾏卡号,护照号,港澳通⾏证号,⼯号,病史,婚史etc),我们写程序需要记录的只是我们关⼼的属性。这些关⼼的属性,就是表的字段,也就是类的属性。“弱⽔三千,我取⼀瓢饮”!
4段—设计模式:
曾经在⽹上看到这样⼀句话:“没有⼗万⾏代码量,就不要跟我谈什么设计模式”。深以为然。
记得第⼀次看Gof的设计模式那本书的时候,发现虽然以前并不知道设计模式,但在实际编程过程中,其实还是⾃觉使⽤了⼀些设计模式。设计模式是编程的客观规律,不是谁发明的,⽽是⼀些早期的资深程序员⾸先发现的。
不⽤设计模式,你也可以写出满⾜需求的程序来。但是,⼀旦后续需求变化,那么你的程序没有⾜够的柔韧性,将难以为继。⽽真实的程序,交付客户后,⼀定会有进⼀步的需求反馈。⽽后续版本的开发,也⼀定会增加需求。这是程序员⽆法回避的现实。
写UI程序,不论是Web,Desktop,Mobile,Game,⼀定要使⽤MVC设计模式。否则你的程序⾯对后续变化的UI需求,将⽆以为继。
设计模式,最重要的思想就是解耦,通过接⼝来解耦。这样,如果将来需求变化,那么只需要提供⼀个新的实现类即可。
主要的设计模式,其实都是⾯向对象的。因此,可以认为设计模式是⾯向对象的⾼级阶段。只有掌握了设计模式,才能认为是真正彻底掌握了⾯向对象设计技巧。
我学习⼀门新语⾔时(包括⾮⾯向对象语⾔,如函数式编程语⾔),总是会在了解了其语法后,看⼀下
各类设计模式在这门语⾔中是如何实现的。这也是学习编程语⾔的⼀个窍门。
5段–语⾔专家:
经过⼀段时间的编程实践,程序员对某⼀种常⽤的编程语⾔已经相当精通了。有些⼈还成了“语⾔律师”,擅长向其他程序员讲解语⾔的⽤法和各种坑。
这⼀阶段的程序员,常常是⾃⼰所⽤语⾔的忠实信徒,常在社区和论坛上和其他语⾔的使⽤者争论哪⼀种语⾔是最好的编程语⾔。他们认为⾃⼰所⽤的语⾔是世界上最好的编程语⾔,没有之⼀。他们认为,⾃⼰所⽤的编程语⾔适⽤于所有场景。他们眼中,只有锤⼦,因此会把所有任务都当成是钉⼦。
6段–多语⾔专家:
这⼀个阶段的程序员,因为⼯作关系,或者纯粹是因为对技术的兴趣,已经学习和掌握了好⼏种编程语⾔。已经领略了不同编程语⾔不同的设计思路,对每种语⾔的长处和短处有了更多的了解。
他们现在认为,编程语⾔并不是最重要的,编程语⾔不过是基本功⽽已。
他们现在会根据不同的任务需求,或者不同的资源来选择不同的编程语⾔来解决问题,不再会因为没有使⽤某⼀种喜爱的编程语⾔开发⽽埋怨。
编程语⾔有很多种流派和思想,有⼀些编程语⾔同时⽀持多种编程范式。
静态类型编程范式
采⽤静态类型编程范式的编程语⾔,其变量需要明确指定类型。代表语⾔:
编程能⼒七段论
这样做的好处是:
1、编译器可以在编译时就能出类型错误。
2、编译器编译时知道类型信息,就可以提⾼性能。
这种范式认为,程序员肯定知道变量的类型,你丫要是不知道变量的类型,那你就别混了!编译时,程序会报错。
Swift和Go语⾔都是静态类型编程语⾔,但它们都不需要明确指定类型,⽽是可以通过推断由编译器⾃动确定其类型。
动态类型编程范式
采⽤静态类型编程范式的编程语⾔,其变量不需要明确指定类型。任意变量,可以指向任意类型的对象。代表语⾔:
Python,Ruby,JavaScript。
动态类型的哲学可以⽤鸭⼦类型(英语:ducktyping)这个概念来概括。JamesWhitcombRiley提出的鸭⼦测试可以这样表述:“当看到⼀只鸟⾛起来像鸭⼦、游泳起来像鸭⼦、叫起来也像鸭⼦,那么这只鸟就可以被称为鸭⼦。”
这种范式认为,程序员肯定知道变量的类型和它⽀持的⽅法和属性,你丫要是不知道变量的类型,那你就别混了!运⾏时程序会崩溃!程序崩溃怨谁?怨你⾃⼰呗,你不是合格的程序员!
动态类型的好处是:
不需要明确定义接⼝和抽象类型。只要⼀个类型⽀持需要的⽅法和属性,那么就OK。程序会相当灵活和简单。Java,C#视之为命脉的接⼝/基类,在动态语⾔这⾥都视如⽆物!
缺点是:
1、如果类型不对,编译器也⽆法到错误,⽽是运⾏时程序崩溃。
2、因为编译器不知道变量的类型,因此⽆法优化性能。
⾯向对象编程范式
⾯向对象编程范式,从上世纪70年代末开始兴起。它⽀持类和类的实例作为封装代码的模块。代表语⾔:
编程能⼒七段论
早期编程语⾔都是⾯向过程的。就是顺序,条件,循环,构成⼀个个函数。随着代码规模的增⼤,⼈们发现有必要对代码进⾏模块化。⼀个概念对应的代码放在⼀个⽂件中,这样便于并发开发和进⾏代码管理。
⼈们还发现了“程序=数据结构算法”的规律。因此,⼀个概念对应的数据结构和函数应该放在⼀个⽂件中。这就是类的概念。
⾯向对象编程范式,确实极⼤地提⾼了⽣产效率,因此得到了⼴泛的应⽤,因此在语⾔层⾯⽀持⾯向对象编程范式的语⾔是极多的。
C语⾔尽管在语⾔层⾯上并不⽀持⾯向对象编程范式,但现代的C语⾔开发都会应⽤⾯向对象的模块化思想,把同⼀类的数据结构和函数放在⼀个⽂件中,采⽤类似的命名⽅式。
毕竟C语⾔没有在语⾔层⾯上⽀持⾯向对象,因此就有很多程序员想给C语⾔添加⾯向对象⽀持。其中的代表是编程能⼒七段论和Objective-C。
编程能⼒七段论是⼀种新的语⾔,但⼤部分语⾔元素是和C兼容的。
Objective-C是完全兼容的C的。Objective-C是给C添加了薄薄的⼀层语法糖以⽀持接⼝(就是其他语⾔的类)和协议(就是其他语⾔的接⼝)。甚⾄,Objective-C⼀开始的实现,就是⼀个C语⾔的预编译器。Objective-C坦⽩讲,除了添加的语法不太符合C流外,实际上其⾯向对象系统设计是相当精妙的。乔布斯早年慧眼识珠,把Objective-C收⼈囊中,因为封闭于Apple/NextStep系统内,因此少有⼈知。随着iOs 系统的普及,Objective-C近⼏年才名满天下。
函数式编程范式
函数式编程范式,是⼀些数学家发明的编程语⾔,他们认为程序就是数学函数嘛。代表语⾔:Lisp,Erlang,JavaScript,OCaml,Prog。
有很多⼤⽜极⼒⿎吹过函数式编程语⾔,认为其极具⾰命性。但我认为他们过⾼估计了函数式编程范式的威⼒,我并不认为函数式编程范式相对于⾯向对象编程范式有何⾼明之处。
函数式编程语⾔,核⼼就是函数,它们没有Class类的概念。但它的函数⼜不是传统⾯向过程语⾔的函
数,它的函数⽀持“闭包”的概念。
在我看来,函数式编程语⾔的函数,也就是“闭包”,说⽩了,其实就是“类”。编程语⾔发展到今天,就是需要模块化,就是需要把“数据结构”和“算法”结合起来。不论何种语⾔,不把它们结合起来的编程⽅式,都是没有出路的。
⾯向对象编程语⾔,⽤类把“数据结构”和“算法”结合起来。类的核⼼是“数据结构”,也就是其“属性”,⽽不是“算法”,其“函数”。在类中,是函数依附于属性。
⽽函数式编程语⾔,⽤闭包把“数据结构”和“算法”结合起来。是函数能够抓取外部的字段。是“属性”依附于“函数”。
“类”本质上和“闭包”是等价的。现在很多⾯向对象编程语⾔都加上了对闭包的⽀持。观察其代码,我们可以发现,它们实际上都是⽤“类”来实现“闭包”的。
“类”和“闭包”谁更易⽤?明显是“类”。
⽽“闭包”更简洁⼀些,因此“闭包”在⾯向对象编程语⾔中常⽤来替换匿名类。只有⼀个函数的类,写成⼀个类太⿇烦,不如写成闭包,更加简洁。
吐槽⼀下OCaml语⾔,其前⾝Caml语⾔本⾝是⼀种挺好的函数式语⾔,硬⽣⽣添加了⼀套完整的⾯向对象机制,同时⽀持⾯向对象和函数式编程范式,很容易像C ⼀样脑裂的。
也有很多⾯向对象语⾔控看着JavaScript嫌烦,总是想把⾯向对象⽀持添加到JavaScript上。ActionScript就是其中⼀种尝试。我⽤过,真的是和Java没多少区别了。
再吐槽⼀下ExtJS。当初选型Web前端开发框架时⽐较了ExtJS和JQuery。
ExtJS明显是Java⾼⼿开发的,硬⽣⽣⽤JavaScript模拟Swing的设计思想,搞了⼀套UI库。
JQuery开发者明显是领悟了JavaScript的函数式编程范式,依据JavaScript的动态函数式编程语⾔的特点打造了⼀套UI库,⽴刻秒杀ExtJS。由ExtJS和JQuery的故事,我们可以看到多语⾔编程能⼒是多么的重要。ExtJS的作者精通并喜爱Java,因此他把⼿术⼑JavaScript当做锤⼦Java使,⼀通乱敲,费⼒不讨好。
函数式编程语⾔,还有尾递归等⼀些⼩技巧。尾递归可以不⽤栈,防⽌递归调⽤时栈溢出。
模板编程范式
模板编程,就是把类型作为参数,⼀套函数可以⽀持任意多种类型。代表语⾔:C 。
模板编程的需求,是在C 开发容器库的时候发明的。因为容器需要保存任意类型的对象,因此就有了泛型的需求。
C 的模板编程,是在编译时,根据源码中的使⽤情况,创建对应类型的代码。除了C 这种⽅式,Java,C#也有类似的机制,叫做“泛型”,但它们的实现⽅式和C 的模板很不同。它们的编译器不会⽣成新的代码,⽽是使⽤强制类型转换的⽅式实现。
在没有模板/泛型的编程语⾔中,怎样在容器中存放对象呢?存取公共基类类型(Java,C#)的对象,或者void*指针(C)即可,取出时⾃⼰强制类型转换为实际类型。动态类型语⾔,不关⼼类型,更是⽆所谓了,随便什么对象直接往容器⾥扔进去,取出来直接⽤即可。
⼀些C ⾼⼿⼜在模板的基础上搞出了“模板元编程”。因为模板编程,就是C 的编译器搞定的嘛,模板元编程就是让编译器运算,编译完结果也就算出来了。我不知道除了研究和炫技,这玩意有啥⽤?
⼩结
⼀门语⾔是否值得学习,我认为有⼏个标准:
1、是否要⽤,要⽤就得学,这么没有疑问的。毕竟我们都要吃饭的嘛。
2、其语⾔特性是否给你⽿⽬⼀新的感觉。如果是,那就值回票价了。如Go语⾔废掉了异常,改⽤返回多值。我深以为然。我其实已经主动不⽤异常好多年了。因为,我觉得既然C不⽀持异常也活得很好,为什么需要异常呢?出错了,返回错误码。⽆法挽回的错误,直接Abort程序就可以嘛!⽽且,异常实际上是违反⾯向过程编程原则的。⼀个函数应该只有⼀个⼊⼝⼀个出⼝。抛出异常就多了出⼝了。
3、是否擅长某⼀个领域。如果你⼿⾥只有⼀把锤⼦,那么你就只能把所有任务都当做钉⼦猛锤⼀通。但如果⼯具箱⾥有多种⼯具,那⾯对不同的任务就得⼼应⼿多了。
7段—架构设计
还需要掌握架构设计的能⼒,才能设计出优秀的软件。架构设计有⼀些技巧:程序员和编程员的区别
1、分层
⼀个软件通常分为:
表现层–UI部分
接⼝层–后台服务的通讯接⼝部分
服务层–实际服务部分
存储层—持久化存储部分,存储到⽂件或者数据库。
分层的软件,可以解耦各个模块,⽀持并⾏开发,易于修改,易于提升性能。
2、SOA
模块之间通过⽹络通讯互相连接,松耦合。每⼀个模块可以独⽴部署,可以增加部署实例从⽽提⾼性能。每⼀个模块可以使⽤不同的语⾔和平台开发,可以重⽤之前开发的服务。SOA,常⽤协议有WebService,REST,JSON-RPC等。
3、性能瓶颈
1)化同步为异步。
⽤内存队列(Redis),⼯作流引擎(JBpm)等实现。内存队列容易丢失数据,但是速度快。⼯作流引擎会把请求保存到数据库中。
通过化同步请求为异步请求,基本上99.99%的性能问题都可以解决。
2)⽤单机并⾏硬件处理。
如,使⽤GPU,FPGA等硬件来处理,提⾼性能。
3)⽤集计算机来处理。
如,Hadoop集,⽤多台计算机来并⾏处理数据。
⾃⼰的软件栈中,也可以把⼀个模块部署多份,并⾏处理。
4)⽤cache来满⾜请求。常⽤的内容加热cache后,⼤量的⽤户请求都只是内存读取数据⽽已,性能会得到很⼤的提升。
cache是上帝算法,记得好像它的性能只⽐最佳性能低⼀些,就好像你是上帝,能够预见未来⼀样。现在X86CPU遇到了主频限制,CPU提升性能的主要途径就是增加⾼速Cache了。
4、⼤系统⼩做
遇到⼤型系统不要慌,把它切分成多个模块,⽤多个⼩程序,通过SOA协作来解决。这秉承了Unix的设计思想。Unix上开发了⼤量单⼀⽬的的⼩程序,它主张⽤户通过管道来让多个⼩程序协作,解决⽤户的需求。当然,管道⽅式通讯限制太多,不够灵活。因此,现在我们可以通过URI,通过SOA的⽅式来让多个程序协作。Andorid和iOS上的应⽤程序,现在都是通过URI实现协作的。这也算是Unix设计思想的现代发展吧?!
5、Sharding切⽚
现在有⼀个潮流,就是去IOE。I-IBM⼤型机,O-Oracle数据库,E-EMC存储。之前,⼤型系统常⽤IOE去架构,在⼤型机上部署⼀个Oracle 数据库,Oracle数据库⽤EMC存储保存数据。IOE是当今最强的计算机,数据库和存储。但他们⾯对海量系统也有抗不住的⼀天。
Oracle数据库是Shareeverything的,它可以在⼀个计算机集(服务器节点不能超过16个)上运⾏。计算机集都共⽤⼀个存储。
去IOE运动,标志着ShareEverything模式的破产。必须使⽤ShareNothing,系统才能⽆限扩展。
⽤MySQL数据库就可以应付任意规模的数据了。前提是,你会Sharding分⽚。把⼤系统切分成若⼲个⼩系统,切分到若⼲台廉价服务器和存储上。更Modern⼀些,就是切分到⼤量虚拟机上。
如,铁道部的12306⽹站。我们知道⽕车票都是从属于某⼀列列车的。那么我们把每⼀个列车作为⼀个单元来切分,就可以把12306⽹站切分成⼏千个模块。⼀台虚拟机可以承载若⼲个模块。当某些列车成为性能瓶颈之后,就可以把它们迁移到独⽴的虚拟机上。即使最终有部分列出服务不可⽤,系统也不会完全不可⽤。
12306⽹站,只有⼀个全局的部分,就是⽤户登录。这个可以交给第三⽅负责。如可以让⽤户⽤,
微博,qq等账户登录。
也可以⾃⼰实现⽤户登录服务。还是⽤切⽚的⽅式⽤多台Redis服务器提供服务。Redis服务器存储每⼀个登录⽤户的sessionId和userId,⾓⾊,权限等信息。sessionId是随机⽣成的,可选择其部分bit⽤于标识它在哪⼀个Redis服务器上。⽤户登录后,把sessionId发给客户。⽤户每次请求时把sessionId发回给服务器。服务器把sessionId发给Redis服务器查询得到其⽤户信息,对⽤户请求进⾏处理。如果在redis服务器上不到sessionId,则让⽤户去登录。即使所有注册⽤户同时登陆,也不需要太多的内存。⽽且,可以在session内存过多时,删除最早登陆的⽤户的session,强制他再次登陆。同时活跃的⽤户数不会太多。
领域知识层次
前⾯的所有层次,都是关注编程本⾝的技能,说⽩了,就是基本功,本⾝并不能产⽣太⼤的价值。但有太多的程序员浪费太多的时间在那些筑基的层次上。
有些程序员特别喜欢钻研编程语⾔,每有⼀种新的编程语⾔出来或者旧语⾔被热炒,就会投⼊精⼒进去研究。我就是其中之⼀,浪费了很多精⼒在编程语⾔上,在奇技淫巧上。
我觉得编程能⼒七段论语⾔是⼀个特别⼤的坑。刚开始是作为⾯向对象的C被开发的。后来发现了模板
编程,就⼤⼒⿎吹模板编程和进⼀步的模板元编程。最近⼜推出了新标准,进⼀步添加了很多新东西,函数式编程,类型推断等,过分复杂,太多的坑消耗了⼤量程序员的⼤量精⼒。我使⽤编程能⼒七段论时,只使⽤⾯向对象部分和模板部分,其他过于精深的特性都不使⽤。
计算机科学是⼀个⾯相当⼴泛的学科,有很多领域知识需要和值得我们深⼊研究,我们才能写出有价值的程序来。软件必须要和⾏业结合起来,要落地才有价值。仅仅研究编程技巧,不懂领域知识是写不出有价值的程序的。
计算机科学领域有很多,列举⼀些如下:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论