即使认为这基本上是大家在成长过程中最常说的一句话,但我看到大多数人还是没有“学会”。当他们开始学习新的东西时,他们的第一直觉就是抓一大堆教程和书籍,仅此而已。这篇文章主要是针对软件开发工程师的,我见过太多人太多次迷失在教程的炼狱里,花了太多时间和精力去“学习”。
那么,实际问题是什么呢?当你在学习一门新的技术或者完全开始技术生涯的时候,看一些教程没什么问题。但教程只会耗费你更多的时间,会教给你一套非常有限的指令,而这些指令在实际的场景中可能并不会有任何意义。
从零开始构建一个应用程序会涉及到很多部件,这些部件通常并不会出现在这些教程中。教程往往只涉及表面。
教程炼狱
我见过很多初学者都掉进了教程炼狱这个陷阱。一开始,他们不知道该学什么,因为要成为一名软件开发人员,你需要掌握很多学科的知识。
于是,他们就在谷歌上搜索“随机编程语言教程”来开始学习一些东西。他们就会挑选一些基础知识来看。然后他们搜索更多的教程。然后就跟着教程做。通过完成每一个教程感受到了多巴胺的刺激。觉得自己也蛮聪明的,感觉自己进步了。
但是在完成了一些教程之后,实际的学习就停止了。然而他们还是继续去搜教程,不断从不同的学习平台去购买教程,并陷入不断的一个又一个的教程中。
这就是教程炼狱。新手很容易掉入的心理陷阱。他们从教程中反复学习同样的东西,殊不知他们缺失了该有的成长。同样的概念以不同的形式出现,给人以进步的错觉。
教程是不够的。这些教程足以让你跟着开始并构建一些非常具体的作者想要的东西,给你一个明确的步骤清单,你跟着做就行。在最后,你也完成了课程,并且构建出了作者希望你构建的东西。然而实际上,并没有真正构建起任何的东西。
要想挣脱束缚,该怎么做呢?在我看来,软件工程远不止写代码这么简单。当然,对很多人来说,写代码这个职业已经是一个不错的选择,但如果你只知道写代码,那么一段时间后就会停止发展。
软件开发是建立问题的解决方案、分析问题、将其分解成步骤、建立算法、给出所需的结果并交付可用的东西。
软件开发者需要知道什么?
这还真不好说,这与每个人的看法有关。每个人的经历不同,对这个问题的看法也就会不一样。有时候也会产生关于数学是否有用的分歧。在我看来,一个成功的软件工程师,应该对大多数与计算机相关的领域都有一个大概的了解,这样才能看清和了解全局,并围绕全局展开工作。
最关键的领域有:
数学 —— 是的,一个有点不受欢迎的观点,但是我认为数学是软件开发中的一个关键部分。并不是因为公式和微积分可能会帮你构建 web 应用,而是你在学数学时培养的批判性思维和结构性思维对你如何处理问题至关重要。从某种程序上来看,数学就是将需要解决更大的问题,分解成更小的更容易解决的问题,并将结果结合起来。这基本上就是:发明、遵循并结合算法。
如何学习?
嗯,答案可能不会让你感到惊讶:做数学题。还记得那些你没有做或者试图逃避做的数学作业吗?当你的大脑大部分时间都设置在学习模式时,所有这些都会有助于建立你的算法思维。现在应该还是这样,但现在你的时间和精力比较有限。
软件工程最难接受的是,其实你必须在一定程度上喜欢数学,才能在工作中取得成功,或者对解决问题充满热情。如果不是这样,软件工程可能不是最好的职业选择,你最终要么会被炒掉,要么就会讨厌你的工作。
低级编程语言 —— 基本上就是对 C/C++ 的了解。什么是编译,什么是内存管理,什么是文件描述符管理,甚至是一些汇编的知识都会很有用。掌握这方面的一些知识,当你看到你正在构建的代码时,肯定会帮助你调试和发现问题。例如,如果你不知道要找什么,内存泄漏就很难修复。如果你有一些低级编程的知识,你就会知道,你必须四处寻找未释放的内存,陈旧的引用,防止一些数据结构从内存中删除,或者未关闭的文件描述符。
如何学习?
实际学习和用 C/C++ 构建小程序。必须处理分配内存的实际案例场景,并注意非法内存访问和与指针的工作,肯定会让你学到很多东西。潜心研究一下汇编也许是值得的,因为你会看到处理器看到的代码,而不是你写的代码,你最终会明白,你写的所有东西对处理器来说都变成了一堆的指令(比如移动数据,管理执行指针,以及一直从堆栈中推送和弹出东西)。
操作系统 —— 因为每一段代码都是在操作系统上运行的,你在电脑上度过的每一刻,基本上都是在使用操作系统,所以了解你所处理的东西至关重要。磁盘、文件、目录是如何工作的?什么是用户,程序突然关闭是什么意思,突然风扇开始吹热风,发出很大的噪音是什么意思?你会从哪里收集更多的信息?
如何学习?
这里就比较棘手了。没有正确的方法来解决,它,但有一些选择,肯定会让你更容易。学习操作系统最有影响的方法是上 Linux,开始用C语言实现你在Linux中找到的基本命令:cd、ls、mkdir、ps等。重新发明轮子是比打造原创性的东西更好的学习体验。
网络 —— 虽然是一个很难的话题,但在当前的软件开发环境下,了解进程如何通信是至关重要的。单一服务器上的单一应用的时代已经结束,云计算的时代已经到来。你需要知道这些移动的部件是如何结合在一起的,最重要的是,它们之间是如何沟通的?经常有人问我,即使是全新的路由器,如何通过内存知道它的地址?联网。在一个软件项目中,你会遇到的很多错误都与网络有关,比如连接一直被关闭,定时出错,被拒绝,搞清楚数据库连接需要什么配置才能工作等等。这些都在于网络领域。
如何学习?
简单的答案和操作系统要点的答案是一样的。构建一些流行的开源应用的客户端,如数据库,电子邮件服务器,甚至SSH,如果你觉得冒险的话。这将提供一个很好的学习经验。
设计模式 —— 这是一个你真的不需要学习的话题,因为你会从构建中,随着你的经验越来越多,逐渐学会。学习这种东西最有力的方法就是用错误的方式构建一些东西,完全不使用任何设计模式,然后重构(或从头开始重新构建)来整合它们。看到第一手的例子,了解它们是如何帮助你的代码变得更容易管理的,这将保证对 “为什么 “的深刻理解。而这才是最重要的事情:弄清楚为什么要使用某些设计模式,并认识到它们所解决的问题,这样你就能在问题真正成为问题之前就能得到 “感觉”。
如何学习?
靠经验和耐心。你会犯错误。每个人都会犯错。而且这很好。代码不一定要从迭代一开始就完美。一个应用程序/项目永远不会完成,它的代码库会不断变化。每一次变化都应该努力增加功能,或者减少技术债。
另一种学习设计模式的方法是使用框架和探索开源代码:它们已经融入了良好的实践和设计模式。这对体验这些设计模式的优点和缺点会很有用。
是不是觉得奇怪,怎么这个列表中并没有编程语言?我并不认为懂得一门编程语言是一个软件开发者的关键技能。毕竟,编程语言是我们用来解决问题的工具,而工具是可以切换的。当然,随着时间的推移,我们会对一种工具的使用比其他工具更加熟练,并且会在大部分时间内更喜欢使用某一种语言,并在此基础上建立自己的职业生涯,但它不应该成为定义你职业生涯的东西。最终你需要成长起来,把语言仅仅看作是工具,真正的挑战是整个应用。用任何语言(甚至是PHP)都可以建立伟大的东西。
在实践中学习
回到最开始的想法:在实践中学习。从零开始构建一些东西,体验真实开发中会出现的全部问题和挑战,这一点很重要。当你在软件开发行业工作时,你的工作就是在解决真实应用/系统中的实际问题。
只在工作中学习也有一些非常大的弊端:学习率和探索解决方案的灵活性非常有限,因为有真实的利益关系在里面,人们会监督你的工作,你会被限制在一些有限的资源内,更大的重构环节需要大量的规划,并且会被多人分担,所以知识的获得也是会被分割的。
要想真正让你的软件开发能力突飞猛进,你应该有一些你自己热衷的个人项目。你应噶在工作时间之外建立一些东西,并把它作为一个允许任何错误并且没有风险的竞争场。你唯一需要投入的资源就是时间,与其把时间浪费在社交媒体上,不如每天花上至少一个小时时间来构建你自己的项目。
一开始,会很乏味,大多数人放弃这样的学习方法转而拿起教程进行学习的原因就在于此:你从一无所知开始,你需要弄清楚步骤是什么。
那么,假设你想构建一个 Twitter. 你应该怎么开始?用户?推文?提及?
这是一个艰难的决定,但这肯定是任何项目开始时都需要作出的决定。在企业环境中,有一整套专门的流程,需要花费大量的时间和人力。
但作为一个独立开发者,一开始就一头扎进去,边干边想也是可以的。犯错可以创造学习的机会。
比如,我目前正在构建 Amethyst Platform ,我五次重新开始此项目。每一次,我的起点都比之前知道得更多。最终,每一次迭代,都会有更多的进步。
构建个人项目给了你尝试任何事物的土壤:新技术、新工艺、新设计模式、新架构、新方法。
总结
我对任何想让自己的职业生涯保持在上升轨道上的软件开发人员的建议就是:拥抱软件开发行业的广阔天地,专注于构建个人项目。
通过构建自己的东西,我们可以获得新的技能,我们能够无风险地进行试验并犯很多错误,而且没有老板和最后期限的压力。
为了了解更多的东西,有必要掌握互联网的构件,从运行我们的代码的机器,数据在世界各地的移动方式到我们代码的架构和结构,这样我们就能更容易地驾驭它。