精华内容
下载资源
问答
  • 程序员技能层次模型

    千次阅读 2015-03-15 19:22:01
    也就是说,还是门外汉,还能称之为“程序员”。计算机在他面前还是一个神秘的黑匣子。1段—基础程序员: 学习过一段时间编程后,接到任务,可以编写程序完成任务。 编写出来的代码,正常情况下是能够工作的,但...

    编程技能层次
    编程技能层次,指的程序员设计和编写程序的能力。这是程序员的根本

    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段–多语言专家:

    这一个阶段的程序员,因为工作关系,或者纯粹是因为对技术的兴趣,已经学习和掌握了好几种编程语言。已经领略了不同编程语言不同的设计思路,对每种语言的长处和短处有了更多的了解。
    他们现在认为,编程语言并不是最重要的,编程语言不过是基本功而已。
    他们现在会根据不同的任务需求,或者不同的资源来选择不同的编程语言来解决问题,不再会因为没有使用某一种喜爱的编程语言开发而埋怨。
    编程语言有很多种流派和思想,有一些编程语言同时支持多种编程范式。

    静态类型编程范式

    采用静态类型编程范式的编程语言,其变量需要明确指定类型。代表语言:C,C++,Pascal,Objective-C,Java,C#,VB.NET,Swif,Golang。
    这样做的好处是:
    1,编译器可以在编译时就能找出类型错误。
    2,编译器编译时知道类型信息,就可以提高性能。
    这种范式认为,程序员肯定知道变量的类型,你丫要是不知道变量的类型,那你就别混了!编译时,程序会报错。
    Swift和Go语言都是静态类型编程语言,但它们都不需要明确指定类型,而是可以通过推断由编译器自动确定其类型。

    动态类型编程范式
    采用静态类型编程范式的编程语言,其变量不需要明确指定类型。任意变量,可以指向任意类型的对象。代表语言:Python,Ruby,JavaScript。
    动态类型的哲学可以用鸭子类型(英语:ducktyping)这个概念来概括。JamesWhitcombRiley提出的鸭子测试可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
    这种范式认为,程序员肯定知道变量的类型和它支持的方法和属性,你丫要是不知道变量的类型,那你就别混了!运行时程序会崩溃!程序崩溃怨谁?怨你自己呗,你不是合格的程序员!
    动态类型的好处是:
    不需要明确定义接口和抽象类型。只要一个类型支持需要的方法和属性,那么就OK。程序会相当灵活和简单。C++,Java,C#视之为命脉的接口/基类,在动态语言这里都视如无物!
    缺点是:
    1,如果类型不对,编译器也无法找到错误,而是运行时程序崩溃。
    2,因为编译器不知道变量的类型,因此无法优化性能。

    面向对象编程范式
    面向对象编程范式,从上世纪70年代末开始兴起。它支持类和类的实例作为封装代码的模块。代表语言:Smalltalk,C++,Objective-C,Java,C#,VB.NET,Swift,Go,Python,Ruby,ActionScritp,OCaml.
    早期编程语言都是面向过程的。就是顺序,条件,循环,构成一个个函数。随着代码规模的增大,人们发现有必要对代码进行模块化。一个概念对应的代码放在一个文件中,这样便于并发开发和进行代码管理。
    人们还发现了“程序=数据结构+算法”的规律。因此,一个概念对应的数据结构和函数应该放在一个文件中。这就是类的概念。
    面向对象编程范式,确实极大地提高了生产效率,因此得到了广泛的应用,因此在语言层面支持面向对象编程范式的语言是极多的。
    C语言尽管在语言层面上并不支持面向对象编程范式,但现代的C语言开发都会应用面向对象的模块化思想,把同一类的数据结构和函数放在一个文件中,采用类似的命名方式。
    毕竟C语言没有在语言层面上支持面向对象,因此就有很多程序员想给C语言添加面向对象支持。其中的代表是C++和Objective-C。
    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++语言是一个特别大的坑。刚开始是作为面向对象的C被开发的。后来发现了模板编程,就大力鼓吹模板编程和进一步的模板元编程。最近又推出了C++11,C++14等新标准,进一步添加了很多新东西,函数式编程,类型推断等。C++过分复杂,太多的坑消耗了大量程序员的大量精力。我使用C++时,只使用面向对象部分和模板部分,其他过于精深的特性都不使用。
    计算机科学是一个面相当广泛的学科,有很多领域知识需要和值得我们深入研究,我们才能写出有价值的程序来。软件必须要和行业结合起来,要落地才有价值。仅仅研究编程技巧,不懂领域知识是写不出有价值的程序的。
    计算机科学领域有很多,列举一些如下:
    •存储—-块设备,文件系统,集群文件系统,分布式文件系统,光纤SCSI,iSCSI,RAID等。
    •网络—-以太网,光纤网,蜂窝网络,WIFI,VLAN等。
    •计算机体系结构,主要就是CPU指令集。x86,ARM等。
    •USB协议。需要知道URB包。
    •PCI协议,PCI-E协议。现代计算机的外设都是PCI协议和PCI-E协议的。显卡现在全是通过 PCI-E协议连接到计算机上的。相对来说减少了很多需要学习的知识。搞虚拟化就需要深入掌握PCI协议。
    •图像处理–图像压缩,视频实时编码等。
    •3D游戏
    •关系数据库
    •NoSQL数据库
    •操作系统
    •分布式操作系统
    •编译原理
    •机器学习–现在大数据要用哦!
    了解这些领域知识,也包括了解该领域现有的商用硬件、商用软件和开源软件。很多时候,你要完成的工作,已经有现成的工具了。你只要使用现成的工具就可以完成任务,不需要进行开发。有时候,只需要组合现有的工具,写一些脚本就可以完成任务。
    如,我一次要实现一个双向同步任务。找到了一个优秀的开源软件Unison,编写一下配置文件就圆满地完成了任务。不需要编写任何代码。
    还有一次,要做高可用,用Python调用了几个开源软件就轻松实现了。
    编写安装程序,定制操作系统,知道了操作系统的领域知识,写几行脚本就可以轻松搞定。
    不具备领域知识的人,就可能不得不进行大量无谓的开发,甚至开发很久之后才发现,这根本就是一条死路。
    另外,扎实的领域知识,可以大大提高编程调试、查错的能力。知道编译器和编程语言运行时工作原理,就能快速根据编译错误和警告信息修改代码。
    知道操作系统底层运行机制,就能快速找到运行时错误的问题根源。如,有一次我编写一个windows升级服务程序。它是一个windows服务,需要执行dos脚本,这个脚本会替换掉这个windows服务本身。发现有时脚本执行无效,查了一晚上,发现当windows服务安装后,第一次启动就执行脚本时就会有权限问题,log都正确,但实际执行这个脚本没有任何效果。但一旦windows服务程序启动一次之后就ok。这必然是windows操作系统底层安全机制的问题,因为我对Windows内核了解不多,因此花了很长时间才发现这个问题,并对造成这个问题的根源并不清楚。

    0段—领域知识菜鸟
    对领域知识没有多少认知,通过搜索引擎找到一些该领域的软件和硬件的介绍性文章,按照文章指示配置和使用软件。勉强能够使用现有软硬件。

    1段—领域知识行家
    了解领域内常用硬件,深入掌握领域内常用软件的配置和使用技巧。能够使用现有软硬件熟练搭建解决方案,能够解决实际工作中遇到的种种问题。

    2段—领域知识专家
    当你不仅仅掌握了该领域的软件和工具,知道怎么用,还知道其原理,“知其然,也知其所以然”,就是该领域的知识专家了。
    你知道网络协议的原理,你才能在网络出现问题时知道是哪里可能出现了问题。是mac冲突,ip冲突,还是网络环路?
    你知道存储的原理,你才能知道为什么这种存储方式不适合虚拟化,那种存储方式适合虚拟化,另一种方式适合资料备份。
    你知道PCI协议,你才能知道你怎样才能虚拟化一个硬件设备。
    你知道网卡硬件协议,你才能模拟出一个虚拟机能正常使用的虚拟网卡。
    你知道视频编码格式和原理,才能知道什么视频格式占用带宽最少,什么视频格式占用CPU最少。
    你了解IntelVT/Amd V指令集,才能知道虚拟化是怎样实现的。
    你明白工作流其实就是状态机,在遇到复杂工作流程时,你才能知道怎样设计满足要求的工作流引擎。

    3段—科学家
    你是领域知识专家,但你的知识都是来自于书本,来自于其他人的。
    如果你满足于当领域知识专家,你只能拾人牙慧,永远别想超越。别人的研究成果,未必愿意告诉你。当别人告诉你的时候,它可能已经发现了更新的理论,并且新一代产品可能马上就要发布了。
    科学家是探索未知,勇于创新的人,是推动人类社会进步的人。
    传说,思科的一位高管曾经半开玩笑地说过:“如果思科停止了新技术的研发,华为就会找不着方向”。这是在嘲笑华为只是处在领域知识专家的水平,只能山寨无法超越。我不知道华为的实际情况,但希望现在的华为已经走到了领跑者的位置。
    欧文·雅各布斯发现了CDMA码分多址的原理,并发现它在通讯上大有可为,组建了高通公司。高通公司主要以专利授权费为生,它雇佣了大量科学家在通讯领域展开研究。有人说高通是专利流氓。这些人不明白知识的价值。在他们眼里,Windows的合理价格就应该是5元钱,一张光盘的价格。iPhone就应该是1000多元裸机的价格。高通是专利流氓,那你也流氓一个CDMA,LTE出来给我看看!
    X86芯片在设计上没有考虑虚拟化。因此会有所谓的“虚拟化漏洞”出现。就是说,一些CPU特权指令执行时,在虚拟机环境下不会抛出异常,因此就无法切换到Host。这样,X86芯片上就无法运行虚拟机。
    VmWare公司是由美国的几位科学家在1998年创建的。他们发现可以使用二进制翻译的技术,在X86计算机上运行虚拟机。
    Xen虚拟化软件也是几位科学家发明的。他们发现只要修改虚拟机操作系统和Host操作系统的内核,在需要执行“虚拟化漏洞”指令时直接调用Host的功能,就可以实现虚拟化,而且大大提高了虚拟机的运行性能。
    后来,Intel为自己的芯片添加了IntelVT指令集,Amd为自己的芯片添加了AmdV指令集,弥补了“虚拟化漏洞”。于是就有了KVM虚拟机软件,它直接用CPU硬件指令实现虚拟化。
    KVM在执行CPU指令时,是直接在物理CPU上运行的,因此效率极高。但是,虚拟机运行虚拟外设时,就必须用软件模拟,因此虚拟机的IO访问速度很慢。
    IBM科学家RustyRussell,借鉴了Xen的研发经验,创建了VirtIO技术。就是在虚拟机中编写一套PCI虚拟设备和驱动,这套虚拟PCI设备有一块虚拟设备内存。这个虚拟设备内存Host是可以访问的,虚拟机通过VirtIO驱动程序也可以访问。也就是一块内存在虚拟机和Host中共享,这就解决了虚拟机的IO性能问题。
    再讲一个搜索引擎的故事:
    很久以前,我要给一个程序添加搜索功能。刚开始使用sql查询实现,发现实在太慢了。后来找了开源的Lucene项目。它使用反向索引技术,通过在文件中创建反向索引,大大提高了搜索速度。
    Google的两位创始人发现了html中link的秘密,他们发现可以通过html页面的link关系来为每一个html页面设置权重。也就是PageRank算法。于是,Google的自动搜索引擎击败了Yahoo人工分类的搜索引擎。
    OK,利用反向索引技术和PageRank,以及一个简单的html爬虫机器人,我们就可以创建一个搜索引擎了。但是,互联网很大,每天产生大量新网页,要为整个互联网建立反向索引是很困难的。
    若干年后Google又公开了三篇论文:Googlefs,Mapreduce,Bigtable。于是Lucene项目的开发者根据Google的Mapreduce论文开发了Hadoop项目。MapReduce就是使用大量计算机存储数据并计算,最后汇总结果。使用Hadoop+反向索引+PageRank,就可以创建搜索引擎了。Yahoo,Baidu等公司纷纷基于Hadoop开发了自己的搜索引擎。
    但是,其他公司的搜索引擎效果还是没法和Google相比。这一点我们程序员最清楚。像我,就总是翻墙出去,只为了Google一下。
    Google黑板报上发表了吴军博士的一些文章,其中介绍了很多机器学习方面的知识。从文中可以知道,Google其实使用机器学习来分析搜集到的页面。Google明显不会把这个公式公开出来。即使有一天Google真的公开了这个公式,那么可以想见Google肯定又研发出了更加犀利的秘籍,山寨货的搜索引擎效果还是比不上Google的。
    山寨是通向创新的必由之路。在成为领域的领头羊和领导者之前,必然要经过学习,模仿的阶段。但要成为行业的老大,成为Champion,必须勇于弯道超车,勇敢地走上创新之路,成为真正的科学家,真正的大牛!

    总结
    编程能力可分为两个维度:一个是编程技能水平,另一个是领域知识水平。
    有些程序员可能把精力都花在提升编程技能上了,领域知识知之甚少,这其实在日常工作中也是极其有害的。有些需求可能早已经有了现成、开源免费的解决方案,或者只需要组合几个现有软件就可以快速搞定,而他们却不得不自己花大量时间去开发。另外,缺少领域知识,在程序出现非预期状况时,很难快速定位到问题的根源,很难解决bug。

    展开全文
  • 软件开发是一个跨度很大的技术工作,在语言方面,有C,C++,Java,Ruby等等等等,在环境方面,又分嵌入式,桌面系统,...很多程序新手也是因为缺少、达到或是不熟悉在这些基本技能,所以,他们需要有老手带,需要努力

    软件开发是一个跨度很大的技术工作,在语言方面,有C,C++,Java,Ruby等等等等,在环境方面,又分嵌入式,桌面系统,企业级,WEB,基础系统,或是科学研究。但是,不管是什么的情况,总是有一些通用的基本职业技能。

    这些最基本的职业技能通常决定了一个程序员的级别,能否用好这些技能,直接关系到了程序员的职业生涯。很多程序新手也是因为缺少、达不到或是不熟悉在这些基本技能,所以,他们需要有老手带,需要努力补齐这些技能。而高级程序员应该非常熟悉这些基本技能,而且有能力胜任并带领其他经验不足的程序员。

    下面这些基本职业技术可以用来做为对一个程序员的评估,很明显,下面的这些技能都可以用来做面试。虽然,还有很多非技术的因素,但对于评估一个程序员的技术能力来说,其应该是足够的了。

    下面是程序员所应该具备的基本职业技能:

    基本技能技能描述
    aaaaaaaaaaaaaaaaaaa
    阅读代码这个技能需要程序员能够具备读懂已经存在的代码的能力,这样的能力可以让程序员分析程序的行为,了解程序,这样才能和开发团队一起工作,继承维护或是改进现有的程序。
    编写程序编写程序并不包括程序设计。不要以为编程是一件很简单的事情,很多程序员都认为编程只需要懂得程序语言的语法,并把设计实现就可以了。但是这离编写程序还远远不够,使用什么样的编码风格成为编写程序员最需要具备的基本技能。能否使用非常良好的编程风格直接决写了程序员的级别。
    软件设计这一能力直接决定了需要吏用什么样的代码技术达到怎么样的功能,而系统架构设计直接决定了软件的质量、性能和可维护性。并不是所有的程序在这一方面都非常优秀,但每个程序员都需要或多或少的明白和掌握这一基本技能。
    熟悉软件工程每个程序员都应该明白软件工程是什么东西,都应该知道,需求分析,设计,编码,测试,Release和维护这几个阶段。当然,几乎所有的人都知道这些东西,但并不是每个人都很清楚这些东西。现在很多高级程序员都会混淆“需求规格说明书FS”和“概要设计HLD”。另外,程序员还需要知道一些软件开发的方法论,比如:敏捷开发或瀑布模型。
    使用程序库或框架一个程序员需要学会使用已有的代码,无论是标论的程序库,或是第三方的,还是自己公司内部的,都需要学会做。比如:C++中,需要学会使用STL,MFC,ATL,BOOST,ACE,CPPUNIT等等。使用这些东西,可以让你的工作事半功倍。
    程序调试程序调试是分析BUG和解决问题最直接的能力。没有人能够保证程序写出来不用调试就可以运行正常,也没有人可以保证程序永远不会出BUG。所以,熟练使用调试器是一个程序员需要具备的基本技能。
    使用IDE学会使用IDE工具也会让你的工作事半功倍。比如,VC++,Emacs,Eclipse等等,并要知道这些IDE的长处和短处。
    使用版本控制一定要学会使用版本控制工具,什么叫mainline/trunk,什么叫tag,什么叫branch,怎么做patch,怎么merge代码,怎么reverse,怎么利用版本控制工具维护不同版本的软件。这是程序员需要明的的软件配置管理中最重要的一块。
    单元测试单元测试是每个程序都需要做的。很多单元测试也是需要编码的。一定要学会在xUnit框架下进行单元测试。比如JUnit, NUnit, CppUnit等等。
    重构代码每个程序员都需要有最基本的能力去重构目前已有的代码,使代码达到最优但却不能影响任何的已有的功能。有一本书叫《软件的重构》,每个程序员都应该读一下。
    自动化编译程序员需要使用一个脚本,其能自动化编程所有的工程和代码,这样,整个开发团队可以不停地集成代码,自动化测试,自动化部署,以及使用一些工具进行静态代码分析或是自动化测试。


    当然,还有很多的基本技术也是非常重要的,比如,与人的沟通能力,语言的表达能力,写作能力,团队协作能力,适应变化的能力,时间管理能力,多任务处理能力,自我学习能力,故障处理能力,等等,等等,这里只是列举了和技术相关的能力,这些是程序最最最基本的能力,只要是程序员就必需要有的能力。

    作者:陈浩
    来源:http://blog.csdn.net/haoel/article/details/4065115

    展开全文
  • 前言 作为Java程序员,你有没有被JVM伤害过?...保存的是程序当前执行的指令的地址(也可以说保存下一条指令的所在存储单元的地址),当 CPU 需要执行指令时,需要从程序计数器中得到当前需要执行的指...

    前言

    作为Java程序员,你有没有被JVM伤害过?面试的时候是否碰到过对JVM的灵魂拷问?

     

    一、JVM 内存区域划分

    1.程序计数器(线程私有)

    程序计数器(Program Counter Register),也有称作为 PC 寄存器。保存的是程序当前执行的指令的地址(也可以说保存下一条指令的所在存储单元的地址),当 CPU 需要执行指令时,需要从程序计数器中得到当前需要执行的指令所在存储单元的地址,然后根据得到的地址获取到指令,在得到指令之后,程序计数器便自动加 1 或者根据转移指针得到下一条指令的地址,如此循环,直至执行完所有的指令。也就是说是用来指示执行哪条指令的。

    由于在 JVM 中,多线程是通过线程轮流切换来获得 CPU 执行时间的,因此,在任一具体时刻,一个 CPU 的内核只会执行一条线程中的指令,因此,为了能够使得每个线程都在线程切换后能够恢复在切换之前的程序执行位置,每个线程都需要有自己独立的程序计数器,并且不能互相被干扰,否则就会影响到程序的正常执行次序。因此,可以这么说,程序计数器是每个线程所私有的。

    在 JVM 规范中规定,如果线程执行的是非 native 方法,则程序计数器中保存的是当前需要执行的指令的地址;如果线程执行的是 native 方法,则程序计数器中的值是 undefined。

    由于程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,因此,对于程序计数器是不会发生内存溢出现象(OutOfMemory)的。

    异常情况:

    不存在

    2.Java 栈(线程私有)

    3.本地方法栈(线程私有)

    4.堆(线程共享)

    5.方法区(线程共享)

    6.直接内存(线程共享)

     

    二、JVM 执行子系统

    1.Class 类文件结构

    1.1 Java 跨平台的基础

    各种不同平台的虚拟机与所有平台都统一使用的程序存储格式——字节码(ByteCode)是构成平台无关性的基石,也是语言无关性的基础。Java 虚拟机不和包括 Java 在内的任何语言绑定,它只与“Class 文件”这种特定的二进制文件格式所关联,Class 文件中包含了 Java虚拟机指令集和符号表以及若干其他辅助信息。

    1.2 Class 类的本质

    任何一个 Class 文件都对应着唯一一个类或接口的定义信息,但反过来说,Class 文件实际上它并不一定以磁盘文件的形式存在。Class 文件是一组以 8 位字节为基础单位的二进制流。

    1.3 Class 文件格式

    各个数据项目严格按照顺序紧凑地排列在 Class 文件之中,中间没有添加任何分隔符,这使得整个 Class 文件中存储的内容几乎全部是程序运行的必要数据,没有空隙存在。Class 文件格式采用一种类似于 C 语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表。

    无符号数属于基本的数据类型,以 u1、u2、u4、u8 来分别代表 1 个字节、2 个字节、4 个字节和 8 个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照 UTF-8编码构成字符串值。

    表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性地以“_info”结尾。表用于描述有层次关系的复合结构的数据,整个 Class 文件本质上就是一张表。

    2.字节码指令

    2.1 加载和存储指令

    2.2 运算或算术指令

    2.3 类型转换指令

    2.4 创建类实例的指令

    2.5 创建数组的指令

    2.6 访问字段指令

    2.7 数组存取相关指令

    2.8 检查类实例类型的指令

    2.9 操作数栈管理指令

    2.10 控制转移指令

    2.11 方法调用指令

     

    2.12 方法返回指令

    2.13 异常处理指令

    2.14 同步指令

    3.类加载机制

    4.类加载器

    4.1 系统的类加载器

    4.2 双亲委派模型

    5.Tomcat 类加载机制

    6.方法调用详解

    6.1 解析

    6.2 静态分派

    6.3 动态分派

    6.4 基于栈的字节码解释执行引擎

    三.垃圾回收器和内存分配策略

    1.Java 中是值传递还是引用传递?

    2.引用类型

    3.基本垃圾回收算法

    3.1.1 引用计数(Reference Counting):

    比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为 0 的对象。此算法最致命的是无法处理循环引用的问题。

    3.1.2 可达性分析清理

     

    标记-清除(Mark-Sweep):此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。

     

    复制(Copying): 此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。次算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间。

     

    标记-整理(Mark-Compact):此算法结合了“标记-清除”和“复制”两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,清除标记对象,并未标记对象并且把存活对象“压缩”到堆的其中一块,按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。

    3.1 按照基本回收策略分

    3.2 按分区对待的方式分

    3.3 按系统线程分

    4.分代处理垃圾

    5.JAVA 中垃圾回收 GC 的类型

     

    四、编写高效优雅 Java 程序

    1.面向对象

    1.1 构造器参数太多怎么办?

    用 builder 模式,用在

    (1)5 个或者 5 个以上的成员变量

    (2)参数不多,但是在未来,参数会增加

    Builder 模式:

    属于对象的创建模式,一般有

    (1)抽象建造者:一般来说是个接口,包含

    1)建造方法,建造部件的方法(不止一个)

    2)返回产品的方法

    (2) 具体建造者

    (3) 导演者,调用具体的建造者,创建产品对象

    (4)产品,需要建造的复杂对象

    对于客户端,创建导演者和具体建造者,并把具体建造者交给导演者,然后由客户端通知导演者操纵建造者进行产品的创建。

    在实际的应用过程中,有时会省略抽象建造者和导演者。

    1.2 不需要实例化的类应该构造器私有

    1.3 不要创建不必要的对象

    1.4 避免使用终结方法

    1.5 使类和成员的可访问性最小化

    1.6 使可变性最小化

    1.7 复合优先于继承

    1.8 接口优于抽象类

    2.方法

    2.1 可变参数要谨慎使用

    2.2 返回零长度的数组或集合,不要返回 null

    2.3 优先使用标准的异常

    3.通用程序设计

     

    五、性能优化

    一个 web 应用不是一个孤立的个体,它是一个系统的部分,系统中的每一部分都会影响整

    个系统的性能

    1.常用的性能评价/测试指标

    1.1 响应时间

    提交请求和返回该请求的响应之间使用的时间,一般比较关注平均响应时间。

    常用操作的响应时间列表:

     

    1.2 并发数

    同一时刻,对服务器有实际交互的请求数。

    和网站在线用户数的关联:1000 个同时在线用户数,可以估计并发数在 5%到 15%之间,也就是同时并发数在 50~150 之间。

    1.3 吞吐量

    对单位时间内完成的工作量(请求)的量度

    1.4 关系

    系统吞吐量和系统并发数以及响应时间的关系:

    理解为高速公路的通行状况:

    吞吐量是每天通过收费站的车辆数目(可以换算成收费站收取的高速费),并发数是高速公路上的正在行驶的车辆数目,响应时间是车速。车辆很少时,车速很快。但是收到的高速费也相应较少;

    随着高速公路上车辆数目的增多,车速略受影响,但是收到的高速费增加很快;

    随着车辆的继续增加,车速变得越来越慢,高速公路越来越堵,收费不增反降;

    如果车流量继续增加,超过某个极限后,任务偶然因素都会导致高速全部瘫痪,车走不动,当然后也收不着,而高速公路成了停车场(资源耗尽)。

    2.常用的性能优化手段

    2.1 避免过早优化

    2.2 进行系统性能测试

    2.3 寻找系统瓶颈,分而治之,逐步优化

    2.4 前端优化常用手段

     

    3 应用服务性能优化

    3.1 缓存

    3.1.1 缓存的基本原理和本质

    3.1.2 合理使用缓冲的准则

    3.1.3 分布式缓存与一致性哈希

    3.2 异步

    3.2.1 同步和异步,阻塞和非阻塞

    3.2.2 常见异步的手段

    3.3 集群

     

    3.4 应用相关

    3.4.1 代码级别

    3.4.2 并发编程

    3.4.3 资源的复用

    3.4.4 JVM

    3.4.5 GC 调优

    3.4.6 调优实战

    3.4.7 存储性能优化

     

    上面的这些问题只是给大家一个借鉴作用,最主要的是给自己增加知识的储备,有备无患。

    关于JVM与性能调优总结了将近50页pdf文档,欢迎关注我的公种浩:程序员追风,获取这些整理的资料!

     

    希望能帮助到你面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。

    最后

    欢迎大家一起交流,喜欢文章记得关注我点个赞哟,感谢支持!

    展开全文
  • 数学对我们每一个程序员来说,都是最熟悉的陌生人。你从小就开始学习数学,那些熟悉的数学定理和公式陪伴你走过好多年。但是,自从当了程序员,你可能早就将数学抛在了脑后。 数学学得好不好将会直接决定一个程序员...

    数学对我们每一个程序员来说,都是最熟悉的陌生人。你从小就开始学习数学,那些熟悉的数学定理和公式陪伴你走过好多年。但是,自从当了程序员,你可能早就将数学抛在了脑后。

    数学学得好不好将会直接决定一个程序员有没有发展潜力。往大了说,数学是一种思维模式,考验的是一个人归纳、总结和抽象的能力。将这个能力放到程序员的世界里,其实就是解决问题的能力。往小了说,不管是数据结构与算法还是程序设计,其实底层很多原理或者思路都源自数学,所以很多大公司在招人时也会优先考虑数学专业的毕业生,因为这些人的数学基础很好,学起编程来也容易上手。

    如果编程语言是血肉,那么数学的思想和知识就是灵魂。它可以帮助你选择合适的数据结构和算法,提升系统效率,并且赋予机器智慧。在大数据和智能化的时代更是如此。举个例子,我们在小学就学过的余数,其实在编程的世界里也有很多应用。你经常用到的分页功能,根据记录的总条数和每页展示的条数来计算整体的页数,这里面就有余数的思想。再难一点,奇偶校验、循环冗余检验、散列函数、密码学等都有余数相关的知识。遇到这些问题的时候,你能说你不懂余数吗?我想你肯定懂,只是很多时候没有想到可以用余数的思想来解决相关问题罢了。

     

    “程序员需要学的数学知识”都在《程序员的数学基础课》中

     

    • 生动形象地解读程序员必学的数学概念
    • 精讲常用概率统计与线性代数知识点
    • 紧密结合数学理论与Python工程实践
    • 降低人工智能学习门槛

    按照这样的讲解路线,既能让你巩固基础的概念和知识,同时又能让你明白这些基础性的内容,对计算机编程和算法究竟意味着什么。不过话又说回来,我认为数学理论和编程实践的结合其实是“决裂”的,所以学习数学的时候,你不能太功利,觉得今天学完明天就能用得着,我觉得这个学习思路可以用在其他课程中,但放在数学里绝对不合适。因为数学知识总是比较抽象,特别是概率统计和线性代数中的概率、数据分布、矩阵、向量等概念。它们真的很不好理解,需要我们花时间琢磨,但是对高级一点的程序设计而言,特别是和数据相关的算法,这些概念就非常重要了,它们都是前人总结出来的经验。

     

    如果你能够将这些基本概念和核心理论都搞懂、搞透,那么面对系统框架设计、性能优化、准确率提升这些难题的时候,你就能从更高的角度出发去解决问题,而不只是站在一个“熟练工”的视角,去增删改查。最后,我希望数学能够成为你的一种基础能力,希望这本书能帮你用数学思维来分析问题和解决问题。数学思想是启发我们思维的中枢,如果你对数学有更好的理解,遇到问题的时候就能追本溯源,快、准、稳地找到解决方案。伽利略曾经说过,“宇宙这本书是用数学语言写成的”,数学是人类科学进步的重要基础,所以,你我都要怀着敬畏之心去学习、思考数学。编程的世界远不止条件和循环语句,程序员的人生应当是创造的舞台。最后,我希望,通过这本书的学习,能够让你切实感受到数学这个古老学科的活力和魅力。

    读目录

     

    第 一篇 基础思想1
    第 1章 二进制、余数和布尔代数2
    1.1 二进制2
    1.1.1 二进制计数法2
    1.1.2 二进制的位操作3
    1.1.3 负数的二进制表示11
    1.2 余数15
    1.2.1 求余和同余定理15
    1.2.2 哈希16
    1.2.3 奇偶校验17
    1.2.4 交叉验证19
    1.3 布尔代数19
    1.3.1 逻辑19
    1.3.2 集合23
    第 2章 迭代、数学归纳和递归30
    2.1 迭代法30
    2.1.1 迭代法简介30
    2.1.2 迭代法的应用31
    2.2 数学归纳法37
    2.3 递归41
    2.3.1 从数学归纳法到递归42
    2.3.2 分而治之44
    2.4 迭代法、数学归纳法和递归的关联56
    第3章 排列、组合和动态规划58
    3.1 排列58
    3.2 组合62
    3.3 动态规划65
    3.3.1 编辑距离66
    3.3.2 状态转移67
    3.3.3 状态转移方程和编程实现70
    3.3.4 动态规划解决最优组合72
    第4章 树和图74
    4.1 图和树的概念74
    4.2 树的常见应用77
    4.2.1 WordNet中的关联词77
    4.2.2 二叉树81
    4.3 树的深度优先搜索和遍历83
    4.3.1 前缀树的构建和查询83
    4.3.2 深度优先的实现88
    4.4 树和图的广度优先搜索和遍历94
    4.4.1 社交网络中的好友问题94
    4.4.2 实现社交好友推荐99
    4.4.3 如何更高效地求两个用户间的最短路径104
    4.4.4 更有效的嵌套型聚合111
    4.5 图中的最短路径114
    4.5.1 基于广度优先或深度优先搜索的方法115
    4.5.2 一个优化的版本:Dijkstra算法116
    第5章 编程中的数学思维126
    5.1 数据结构、编程语言和基础算法126
    5.1.1 数据结构126
    5.1.2 编程语句128
    5.1.3 基础算法128
    5.2 算法复杂度分析129
    5.2.1 复杂度分析的原理和法则130
    5.2.2 复杂度分析的案例134
    第二篇 概率统计138
    第6章 概率和统计基础139
    6.1 概论和统计对于编程的意义139
    6.1.1 概率和统计的概念139
    6.1.2概率和统计可以做什么140
    6.2 随机变量、概率分布和期望值141
    6.2.1 随机变量141
    6.2.2 概率分布142
    6.2.3 期望值157
    6.3 联合概率、条件概率和贝叶斯定理159
    6.3.1 联合概率、条件概率和边缘概率159
    6.3.2 贝叶斯定理162
    6.3.3 随机变量之间的独立性163
    第7章 朴素贝叶斯分类165
    7.1 原始信息的转换165
    7.2 朴素贝叶斯的核心思想166
    7.3 基于朴素贝叶斯算法的文本分类170
    7.3.1 文本分类系统的基本框架170
    7.3.2 自然语言的预处理171
    7.3.3 朴素贝叶斯模型的构建174
    7.3.4 朴素贝叶斯模型的预测176
    7.3.5 朴素贝叶斯分类的实现177
    第8章 马尔可夫过程181
    8.1 语言模型181
    8.1.1 链式法则181
    8.1.2 马尔可夫假设181
    8.1.3 模型推导182
    8.2 语言模型的应用183
    8.2.1 信息检索183
    8.2.2 中文分词184
    8.3 马尔可夫模型184
    8.4 隐马尔可夫模型188
    8.4.1 模型的原理188
    8.4.2 模型的求解192
    8.4.3 模型的实现195
    第9章 信息熵200
    9.1信息熵和信息增益200
    9.1.1 性格测试中的信息熵200
    9.1.2 信息增益203
    9.2 通过信息增益进行决策204
    9.2.1 通过信息熵挑选合适的问题204
    9.2.2 几种决策树算法207
    9.3 特征选择209
    9.3.1 特征选择209
    9.3.2 利用信息熵进行特征选择209
    9.3.3 利用卡方检验进行特征选择210
    第 10章 数据分布212
    10.1 特征变换212
    10.1.1 为什么需要特征变换212
    10.1.2 两种常见的特征变换方法214
    10.2 统计意义217
    10.2.1 显著性差异219
    10.2.2 统计假设检验和显著性检验220
    10.2.3 P值220
    10.2.4 不同的检验方法221
    10.3 拟合、欠拟合和过拟合及其处理229
    10.3.1 拟合、欠拟合和过拟合229
    10.3.2欠拟合和过拟合的处理233
    第三篇 线性代数235
    第 11章 线性代数基础236
    11.1 向量和向量空间236
    11.1.1 向量的概念236
    11.1.2 向量的运算239
    11.1.3 向量空间244
    11.2 矩阵250
    11.2.1 矩阵的运算250
    11.2.2 矩阵运算的几何意义252
    第 12章 文本处理中的向量空间模型256
    12.1 信息检索256
    12.1.1 信息检索的概念256
    12.1.2 信息检索中的向量空间模型257
    12.2 文本聚类259
    12.2.1 聚类算法的概念259
    12.2.2 使用向量空间进行聚类260
    12.3 文本分类263
    第 13章 对象间关系的刻画——矩阵267
    13.1 PageRank的矩阵实现267
    13.1.1 PageRank算法的回顾267
    13.1.2 简化PageRank公式267
    13.1.3 考虑随机跳转269
    13.1.4 代码的实现270
    13.2 用矩阵实现推荐系统272
    13.2.1 用矩阵实现推荐系统的核心思想272
    13.2.2 基于用户的过滤272
    13.2.3 基于物品的过滤277
    第 14章 矩阵的特征279
    14.1 主成分分析(PCA)279
    14.1.1 PCA的主要步骤279
    14.1.2 PCA背后的核心思想286
    14.2 奇异值分解(SVD)288
    14.2.1 方阵的特征分解288
    14.2.2 矩阵的奇异值分解289
    14.2.3 潜在语义分析和SVD291
    第 15章 回归分析294
    15.1 线性方程组294
    15.1.1 高斯消元法295
    15.1.2 使用矩阵实现高斯消元法296
    15.2 最小二乘法299
    15.2.1 通过观测值的拟合300
    15.2.2 最小二乘法302
    15.2.3 补充证明和解释303
    15.2.4 演算示例305
    第 16章 神经网络311
    16.1 神经网络的基本原理311
    16.2 基于TensorFlow的实现317
    16.3 Word2Vec327

    程序员的数学基础课 从理论到Python实践

     

    本书紧贴计算机领域,从程序员的需求出发,精心挑选了程序员真正用得上的数学知识,通过生动的案例来解读知识中的难点,使程序员更容易对实际问题进行数学建模,进而构建出更优化的算法和代码。

    本书共分为三大模块:“基础思想”篇梳理编程中常用的数学概念和思想,既由浅入深地精讲数据结构与数学中基础、核心的数学知识,又阐明数学对编程和算法的真正意义;“概率统计”篇以概率统计中核心的贝叶斯公式为基点,向上讲解随机变量、概率分布等基础概念,向下讲解朴素贝叶斯,并分析其在生活和编程中的实际应用,使读者真正理解概率统计的本质,跨越概念和应用之间的鸿沟;“线性代数”篇从线性代数中的核心概念向量、矩阵、线性方程入手,逐步深入分析这些概念是如何与计算机融会贯通以解决实际问题的。除了理论知识的阐述,本书还通过Python语言,分享了通过大量实践积累下来的宝贵经验和编码,使读者学有所用。

    本书的内容从概念到应用,再到本质,层层深入,不但注重培养读者养成良好的数学思维,而且努力使读者的编程技术实现进阶,非常适合希望从本质上提升编程质量的中级程序员阅读和学习。

    关于作者

    展开全文
  • <br />软件开发是一个跨度很大的...很多程序新手也是因为缺少、达到或是不熟悉在这些基本技能,所以,他们需要有老手带,需要努力补齐这些技能。而高级程序员应该非常熟悉这些基本技能,而且有能力胜任并带领其
  • 软件开发是一个跨度很大的技术工作,在语言方面,有C,C++,Java,Ruby等等等等,在环境方面,又分嵌入式,桌面系统,企业级...很多程序新手也是因为缺少、达到或是不熟悉在这些基本技能,所以,他们需要有老手带,需
  • 程序员不得了解的硬核知识大全

    万次阅读 多人点赞 2020-01-15 11:51:39
    我们每个程序员或许都有一个梦,那就是成为大牛,我们或许都沉浸在各种框架中,以为框架就是一切,以为应用层才是最重要的,你错了。在当今计算机行业中,会应用是基本素质,如果你懂其原理才能让你在行业中走的更远...
  • 程序员需要知道的知识 程序员必具备的基本知识和概念 1、计算机是什么?其工作原理。 2、机器语言和微指令的概念。 3、程序的概念。 4、汇编语言是低级语言,但不是机器语言。 5、高级...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 47,867
精华内容 19,146
关键字:

关系模型的程序员不需要熟悉