软技能2:软件开发者职业生涯指南
上QQ阅读APP看书,第一时间看更新

第3章 傍身之技:你需要具备的技术技能

我强烈建议:软件开发者除具备应对本职工作的技术技能之外,还必须大力拓展自己的“软技能”。事实上,关于这一点我写了整整一本书。尽管如此,我仍然无可否认:技术技能还是至关重要的。

我的意思是,如果你不会写代码,不能开发软件,那么你学到的所有的软技能对你而言都是“屠龙之技”。也许你会成为一个好经理、好教练,但不会成为一名软件开发者。

因为你正在阅读本书的这部分内容,所以我就假设你有兴趣成为一名优秀的软件开发者,我们就来谈谈要在软件开发这一行登堂入室,你需要了解的傍身之技。

现在要谈论的是一个很容易令许多初级软件开发者不知所措的话题,因为他们会觉得有太多的东西要去了解,千头万绪不知道从哪里下手。

我要试着解构一下这个问题,这里只论述能使你迅速成长成为软件开发者的最为重要的和最有价值的技能。

本章绝不能作为软件开发者可能需要的所有技术技能的事无巨细的详尽清单,我只打算列出必要的内容,并在这里逐一进行概述。

别担心,在本书的第三篇“关于软件开发你需要知道些什么”中,我还将另外奉献一章,对每一项技能我都会抽丝剥茧地深入探讨。我还把这个清单压缩成一个有用的工具——“软件开发者技能评估”,供你免费下载。

因此,毫无疑问,下面将简要介绍我认为最重要的技术技能。

我想我们最好是从这个话题开始,不是吗?

想成为一名程序员,却连一门编程语言都不懂,那可是缘木求鱼。你懂我的意思,对吧?(不明白的可参考Ernest P. WorrellErnest P. Worrell是由美国演员Jim Varney扮演的系列滑稽喜剧电视、电影里的人物。本书这里的原文为“you know what I mean, Vern?”其中的Vern直接取自Ernest P. Worrell的著名儿童系列电视剧Hey Vern, It’s Ernest!,Vern是Ernest的不出镜的好朋友,Ernest每次提到Vern的时候均表现出夸张、滑稽、小丑一般的表情。(以上摘编自维基百科)——译者注的系列电影,很搞笑的。)

我们将在第5章中详细讨论如何选择一门编程语言,所以这里不再赘述。不过,我要说的是,选择到底该学习哪一门编程语言其实并不像你想象中那么重要。相反,让我们来谈谈,为什么我建议从学习“一门”编程语言开始,而不是试图学习太阳底下的每一门编程语言。

许多初学编程的人在找到软件开发的第一份工作之前,都试图竭尽全力学好几门编程语言,借此来增加自己找工作的砝码。但我认为,虽然你最终应该学习掌握的编程语言不止一种,但是我并不建议你在前期就学习很多编程语言,因为这只会导致混乱,让你将本应用于学习其他技术技能的精力耗散殆尽。恰恰相反,我建议你潜心钻研一门编程语言的来龙去脉,这样你才可以胸有成竹地宣称:我具备用这门语言编写代码的能力。

还记得我们在第2章讨论“你想成为哪种软件开发者”时不厌其烦地强调你需要尽量具体、具体再具体吗?

在这里,道理是一模一样的。

在学习一门编程语言之后,甚至是正在学习这门编程语言的过程当中,你就需要了解如何正确地结构化你的代码。这是我的坚定信仰。

我已经给你准备好了极佳的资源,以此来帮你结构化代码这一极有价值的技能——由Steven McConnell编写的《代码大全》。

那么,“结构化代码”到底是什么含义呢?

我的意思是:编写优质的、整洁的、不需要太多注释就能理解的通俗易懂的代码,因为代码本身是用于沟通的。

许多软件开发者终其整个职业生涯也没有学会这项技能,那只能用“命途多蹇”来形容他了。因为包括我在内的许多人都依此来评价一名软件开发者的技能高低和竞争力强弱。

良好的代码结构体现了一个人对技术的奉献精神,而不是敷衍了事。结构化代码实际上正是软件开发过程中的艺术部分,同时也是关键部分,因为你和你的同事正是通过代码来交流和共事的,而且你们还要旷日持久地花费大把时间维护现有代码,而不是编写新代码。

我不会在本书中与你详细讨论如何正确地结构化你的代码。因为正像我说过的,我已经给你提供了极佳的资源,但是你必须从一开始就努力学习如何写出优质的、整洁的代码,而不是“以后”在学这一技能。

我向你保证,即使你是一个初学者,只要你能写出优质、整洁、简洁、易懂的代码来表达它的结构、它的含义,那么任何一个看到你的代码的面试官都会认为你是一位有经验的专业人士。

不仅如此,从某种程度上讲,你一定会成为专业人士,至少已经走在通往这个方向的路上。因为你已经把这份职业当作一门专业,而不只是一份工作,这正是真正的工匠精神的标志。

有人可能会对这一点提出质疑,特别是当你正在学的不是面向对象(OO)的编程语言时,但在软件开发界已经有了种类繁多的面向对象的设计思想,所以你需要确保自己了解它。

面向对象设计是一种设计复杂程序的方法,它将复杂程序分解为单个的、代表特定角色与职责的类或者对象(类的实例化),其中封装功能。

在软件开发的世界里,我们一直在矢志不渝地管理复杂度,以“对象”的方法来思考将有助于我们定义和设计复杂的系统,我们会把一个系统看作是一群相互作用的组件,而不是试图从整体上处理这个复杂的组合体。

今天,函数式编程语言多种多样,但你会发现,最流行的软件开发语言和模式仍然在部分地或者全量地深受面向对象的设计与分析的影响。因此,你应该深刻理解什么是类,牢固掌握不同类型的继承关系有哪些,并且明确领会面向对象的术语,如多态、封装。

如果你想在大学或者各类学院通过传统的学位教育获得计算机科学学位,你会发现这一内容是最难啃的硬骨头。

算法是解决各种计算机科学/编程问题的常用方法。例如,有几种常用的算法可以将事物按照规定的要求排序。根据算法的速度、内存大小和里昂的数据类型的不同,这些排序算法的性能不尽相同。

在计算机科学领域有很多这种算法,了解如何根据这些算法来编写自己的程序以解决实际问题是非常重要的,特别是当问题非常棘手的时候。通常,精通各类算法的开发者用区区一个小时就可以解决盘亘在其他开发者手上好几天都束手无策的问题。

如果你对各类算法做不到融会贯通,你就无法知晓其实优雅的解决方案早已比比皆是。因此,仅凭这个原因,我认为算法就是一项价值千金的技能。

数据结构也属于类似的范畴,通常与算法一起协同工作。

所有的软件开发者都应该熟悉下面几种常用的数据结构,包括:


●数组或向量;

●链表;

●栈;

●队列;

●树;

●散列表;

●集合。


通过掌握数据结构和算法,可以轻而易举、气定神闲地解决许多编程难题。

刚开始学习编程时,我对数据结构和算法的知识是一头雾水的,因为大部分内容我是自学的。我不知道它们的真正价值,直到我在一个叫作“顶级程序员”(TopCoder)的网站上参加竞赛的时候我才发现,通晓数据结构和算法的知识会给你带来巨大的优势。

很快,这些技能在编程领域的现实世界中举足轻重的作用便凸显在我眼前,因为我遇到了一些既简单又有趣的问题,而这些问题在我认真学习算法和数据结构之前是不知道该如何解决的。

事实上,我认为算法和数据结构是软件开发中最有趣的领域之一。通过算法和数据结构可以事半功倍地解决难题,利用数据结构和算法可以开发出简单、优雅的解决方案,而且效果还非常好。

截至我写本书时,关于这方面最棒的资源还是Gayle Laakmann McDowell的名著《程序员面试金典》。在书中,她详细介绍了你需要知道的算法和数据结构的所有知识。

学习这项技能是一项挑战,但是物有所值。这是一项能令你在同行中脱颖而出的技能。因为大多数软件开发者在这方面的技能都少得可怜。

如果想通过微软或谷歌这样的公司的面试,你必须掌握这项技能,势在必行。

你应该至少具备一个开发平台的相关经验,并精通与之相关的技术或者框架。

我说的平台是什么意思呢?一般来说,它指的是操作系统(OS),但它也可以指代其他类似于操作系统的抽象。例如,你可以是Mac开发者,也可以是Windows开发者,前者专注于Mac操作系统,后者则专注于Windows操作系统,你也可以成为专注于某个特定Web平台上的Web开发者。

在这里我可不想陷入对某一个具体平台的论战之中,不同的人会有不同的见解,但是为了方便当前讨论,我会把一个平台看作是一个特定的环境,而你个人的职业发展将会随着不同的环境有着不同的生态与特性。

再强调一次,与选哪一门编程语言类似,我认为你到底该选哪种平台其实无关紧要,重要的是你必须得选一种。

每家公司雇用的开发者通常都是固定于某一个特定平台或技术的。如果你拥有在iOS平台上的开发经验,那么你找到一份iOS开发的工作就会简单得多。这意味着你需要熟悉平台本身,以及程序员在该平台上做开发时通常会使用的开发工具、惯用模式和常见框架。

你可能认为选择哪种编程语言决定了选择哪种平台,事实上这种情况很少发生。以C#语言为例,今天的C #开发者可以为Windows、iOS或者Android平台编写代码,也可以为Mac、Linux甚至是嵌入式系统开发程序。因此,不必在乎选择哪种语言,你需要选择的是一个平台。

除学习特定的编程语言和特定的平台之外,我还强烈建议你学习一种框架,以及与该框架相关联的完整的开发栈。

什么是框架?什么是栈?

框架就是一系列用于在特定平台上或跨多个平台上编写的库。通常,框架可以使在该平台上的一般性编程任务变得更容易。

回到刚才的C #例子。大多数C #开发者使用.NET框架编写C #应用程序。在.NET框架中包含有大量的库与类,这可以让一位C#开发者工作在更高层级的抽象上,每次当他想写做点儿什么的时候他并不需要完全从底层开始。例如,.NET框架中含有用于图像操控的代码。从头开始编写这些代码,无疑是非常困难的。所以框架为C#开发者带来巨大的好处,可以让他们不需要编写代码,只需要以某种方式熟练操控库函数即可。

栈稍有所不同。栈是用于创建一个完整的应用程序所必备的一系列相关技术,通常包括一个框架。

例如,常见的MEAN栈。它是MongoDB、Express.js、AngularJS和Node.js四种技术的合称。MongoDB是数据库技术,Express.js是基于Node.js的用于创建Web应用程序的框架,AngularJS是用于创建Web应用程序用户界面的前端JavaScript框架,Node.js是开发Web应用程序中的JavaScript运行环境。

是否理解上述技术无关紧要,除非你是一名MEAN栈的开发者。重要的是,你要明白,如果你对上述所有技术和框架都了解,你就可以开发出完整的Web应用程序。

栈可以让创建应用程序变得更加简单,因为栈提供了一种通用的范型,需多开发者都在使用它来开发应用程序,因此可以轻而易举地做到知识共享,并且你可以确信:一组特定的技术在协同工作方面是行之有效的。

学会了某个栈时非常有价值的,因为这意味着你拥有开发完整应用程序所需的全部技能。许多公司都是使用某一个特定的栈来开发应用程序的,所以他们都在竭力网罗搜寻熟悉该栈的开发者,希望自己能够在竞争中借此旗开得胜。

尽管在过去几年中数据库技术发生了非常大的变化,但我并不认为数据库很快就会消失,所以我想你应该了解一些关于数据库的技术,你觉得呢?

在编写本书时,现行的数据库技术主要有两种:关系型数据库和文档型数据库。我认为,今天的开发者至少应该熟悉关系型数据库的知识,可能也需要对文档型数据库有一定的了解。

在软件开发中,数据库通常用来存储应用程序的数据。当然,有些软件开发团队有专职的数据库开发者或者数据库管理员(DBA),但这并不能够成为你不去了解数据库基础知识的借口。

最低限度,你需要了解以下机制:


●数据库如何运行;

●如何执行基本的查询语句以获取数据;

●如何插入、更新与删除数据;

●如何连接数据集。


此外,你可能还需要了解如何使用你所选择的平台和/或框架来编写程序以检索和存储数据。

大多数开发者都能编写与数据库交互的代码。

源代码控制是任何一个软件开发项目的必要组成部分。

遥想当年,在我们那个年代,还没有什么源代码控制,我们要么把项目的全部文件都放到网络上共享,要么就靠纯手工来回传递软件的不同版本。我很惭愧,当年的我不止一次地参与过这些令人啼笑皆非的“游戏”。但是,当时的我还很年轻,也很蠢萌,你没必要这么做。

现在,几乎所有的专业开发者都应该知道如何使用源代码控制来签入和签出代码,并且能够合并来自多个源代码版本的变更。

源代码控制的最基本要求就是,在一个软件项目中各个文档与代码上所有变更的历史记录都被完整无误地保存下来;同时还允许多个开发者在同一时间处理同一段代码,并将这些更改合并在一起。

这里我们不讨论源代码控制的细节,但是你应该熟悉至少一种源代码控制系统,并且熟悉源代码控制的基本概念。

在当今的软件开发界,几乎所有的专业软件开发团队都会使用某种源代码控制系统。

今天,大多数软件开发项目都会应用某种自动化构建和部署系统。

这些任务过去都是手工完成的。现在,有好几种不同的软件应用程序可以帮助团队自动化这两项任务。而对有些团队来说,这两项工作仍然是手动的。

那么,什么是构建和部署呢?好问题。

你知道如何编写代码并将代码签入源代码控制系统吗?在完成签入工作之后确保代码确实有效,这可是个好主意。这就是构建系统的作用。构建系统的最基本作用就是编译所有的源代码,并确保不出现任何编译错误。

一个复杂的构建系统还可以运行单元测试用例或用户测试用例,执行针对代码的质量检查,并提供代码库的当前状态报告。

部署系统将负责将代码部署到生产环境或者测试环境中。

你不必成为这方面的技术专家,但是了解这些系统如何工作、了解构建和部署代码的过程是非常重要的。

如今,在通常情况下,创建和维护构建与部署系统这个领域里最热门的话题非DevOps(Developer Operation的简写)莫属。但是,这并不能构成你不了解如何运作这个过程的理由。

过去,开发者不需要对测试有太多了解。我们会写一大堆代码,然后就像甩包袱一般把它们扔给一堆测试人员,他们会在我们的代码中找出各种各样的bug,我们再去修复这些bug,就是这样。

这样的日子一去不复返了。如今,越来越多的软件项目都采用了所谓的敏捷过程,(下面我们会在“方法论”一节讨论更多有关敏捷的话题),在敏捷过程中软件开发者和测试人员必须更加紧密地合作。

质量已然成为整个团队的责任——我更愿意强调,其实一直都是这样的。因此,你需要知道一些关于测试的知识。你至少应该熟悉一些基本术语,例如:


●白盒测试;

●黑盒测试;

●单元测试(并非真正意义上的测试);

●边界条件;

●测试自动化;

●验收测试。


一个优秀的开发者(我假设你至少想成为一个优秀的开发者)会在自己测试了自己编写的代码之后才将代码交付给别人。

如果你真的想被别人视为专业人士而不仅仅是一名黑客,这一点是无可辩驳的。

很多新手的软件开发者的梦都是在调试器面前破碎的。

每个人都想写代码,对吧?但是没有人想调试他们的代码,对吧?明白我的意思了吧?以下就是见证真相的时刻。

身为软件开发者,你90%的时间都会消耗在苦苦探究“我的代码为什么不能正常工作”这个问题上。我知道这一点也不刺激。我知道你幻想着每天只写新代码,然而真实的世界不是这样运作的。

如果你使用的是类似“测试驱动开发”的方法,你可能会在调试器上花费比较少的时间。但是,无论如何你都必须学习如何调试自己的以及其他人的代码,无可逃避。因此,与其对你必须做的事情采取心不在焉的态度,还不如咬紧牙关,真正学会如何卓有成效地做好调试工作。

在第32章中,我会更多地讨论这个问题,现在你只需要知道调试工作的必要性和必然性。

被上面这一长串你需要知道的技能清单吓倒了吗?如果还没有的话,我这里还得再加一个,不过我保证这是最后一个。

当一个软件开发团队刚开始编写代码并努力完成工作时,大多数情况下都会使用某种至少他们会假装遵循的方法。(在这里顺便说一下,请注意:不要期望任何一支团队真正遵循他们声称的自己正在使用的软件开发方法。在这里,我可不想愤世嫉俗地指手画脚,我只是一个现实主义者,而且我碰巧知道有很多人说他们正在实施某种软件开发方法,如Scrum,因为他们每天都有一个会议,在会上每个人都要站着。)

因此,你至少要对一些最常见的软件开发方法背后的基本思想了如指掌,这一点非常关键。在这里我要着重强调瀑布式开发和敏捷开发这两种开发方法。

大多数团队都声称他们在使用敏捷方法工作。敏捷本身是一个相当松散的概念,但是,如果你想要谈论这个话题并且融入敏捷团队,那么你应该知道敏捷包含一些实践,还有一些仪式(可以这么说)。

我们将在第27章中更深入地探讨这个话题。

我知道上面我列举了相当多的东西,而且我还只是触到这些话题的表面。现在,你可能会感到有点不知所措,因为你不明白这些技术技能的确切含义。

没关系,还不到你应该知道确切含义的时候——除非你已经是一名软件开发者,如果你已经是一名软件开发者还不知道这一点,你应该感到羞愧!(开玩笑的,但你最好应该把你的知识体系整理清爽,真的。)

不用担心,我将在第三篇“关于软件开发你需要知道些什么”中深入细致地讨论这些主题。因此,就像俗话说的那样——淡定。

接下来,我将告诉你学习这些技术技能的通用方法,这样在你阅读到关于这些技术技能的具体章节时,你就可以开始学习它们了。

向John提问:我注意到本书中有很多链接,你似乎在推销你的其他产品。你的书里到底有什么干货呢?

我很高兴你能这么问我。

首先,让我们讨论一下链接的问题。是的,这本书有很多链接。但是,别担心,你不需要查阅所有的链接。你只需点开你感兴趣的内容。我主要是试图链接到一些我在过去撰写发表过的相关内容,以便于你能够深入细致地了解某一个主题。大多数链接都会指向我的博客帖子或者我在YouTube发布的视频,那里通常会有更多更细致的描述与论述,抑或只是因为它们很有趣。(此外,如果你访问本书中的任何一个链接,就会被带到一个页面上,那里有一张按章排列的书中所有链接的列表。)

还有我的其他产品。是的,你猜得对。我确实是在通过本书推广它们。这里我耍了一点小聪明。书很便宜。写一本书赚不了几个钱。事实上,如果你想写一本书,目的肯定不是为了赚钱。我写本书的一个原因就是要帮助推广我的一些其他产品和内容,我觉得你会感受到它们的价值。

它们可不是“垃圾邮件”,而且你并没有被强制要求购买任何东西(本书的装帧设计本身就是物超所值的)。但是,如果你想要得到它,它就在那里。