说明
整书有很多内容,从成为一名软件开发者一直到完整的职业生涯,这里只是记录自己阅读过程中感受最深或者最受用的部分。
关于自动化
在自动化某一个过程之前,你必须知道手动完成这件事情的全过程。
软件开发的过程往往都是从对问题的透彻理解开始的。也就是,你需要自动化些什么?
关于简历
简历基本上就是关于你自己的一页纸广告 写简历是一门艺术;写作,尤其是有说服力的写作,是一项技能
开发方法
瀑布式
构成瀑布式开发方法的就是软件开发生命周期(Software Development Lifecycle,SDLC)。每一种软件开发方法都有各自的SDLC作为自己的表达方式。在瀑布式开发中,SDLC是顺序的。事实上,你可以说瀑布式开发就是一步一步地遵循SDLC行事,需求分析,软件设计,实施(开发业务),测试,部署,维护。
瀑布式开发面临的最大的一个问题就是需求变更,或者说,直到项目后期才知道需求有变化。
如果你尝试着循序渐进地开发软件,并且努力在项目前期获得所有的需求,那么只要突然间这些需求发生了变化,或者又提出了新的需求,对你来说就不是什么好兆头。此时你可能已经完成了整个系统的架构设计,正在编写代码老实现所有需求,而需求的变更将迫使你必须改变一些设计和实现的内容,这时你要么放弃已经做好的东西退回去,要么必须坚持己见、毅然拒绝需求变更的请求。
敏捷开发
敏捷开发遵循的十二条原则,定义如下:
(1)我们最重要的目标是通过持续不断地及早交付有价值的软件使客户满意。
(2)欣然面对需求变化,即使在开发后期也一样。善于掌控变化,帮助客户获得竞争优势。
(3)频繁地交付可工作的软件,相隔几星期或一两个月,倾向于采取较短的周期。
(4)业务人员和开发人员必须相互合作,项目中的每一天都不例外。
(5)激发个体的斗志,以他们为核心搭建项目。提供他们所需的环境和支持,相信他们能够达成目标。
(6)不论团队内外,传递信息效果最好效率也最高的方式是面对面的交谈。
(7)可工作的软件是进度的首要度量标准。
(8)敏捷过程倡导可持续开发。发起人、开发者和用户要能够共同维持其步调稳定延续。
(9)对技术精益求精,对设计不断完善,将提高敏捷能力。
(10)以简洁为本,极力减少不必要工作量。
(11)最好的架构、需求和设计出自于自组织的团队。
(12)团队定期地反思如何能提高成效,并依此调整团队的行为。
Scrum
r和Jeff Sutherland在20世纪90年代初同时创建的。在1995年,他们合著了一篇联合论文,合并了他俩各自的方法,定义了Scrum方法。
Scrum是一种形式化、规则化的方法,它定义了软件开发团队中的具体角色、开发软件的工作流,以及在开发每一次迭代(也被称为sprint)中应该召开怎样特定的会议。
1.Scrum中的角色
Scrum方法中有三个主要角色。
首先,产品负责人(Product Owner,PO)充当客户的代言人,他将最终决定工作任务的优先次序,并与业务人员、客户以及其他利益相关人进行沟通。
其次,开发团队不仅编写代码,而且要执行分析、设计、测试以及所有与交付软件相关的其他任务。
最后,Scrum专家(Scrum Master,SM)充当团队的教练,帮助消除任何阻碍团队发展的障碍,与产品负责人沟通,推进Scrum过程。
2.Scrum是如何运转的
Scrum背后的基本思想就是,软件开发被分解成若干个更小的迭代称作Sprint,每一个Sprint由一组锁定在那个时间框架内必须完成的工作组成。然后,在每个Sprint结束时,其结果增量地交付给客户。
需要为软件开发的所有功能都被合并到一个所谓的产品待办事项清单中。(基本上它与系统的需求类似。)
产品待办事项是按优先级别排列的,在每一个Sprint周期内,都会从产品待办事项清单中提取一组待办事项从而创建该Sprint的待办事项清单,以定义在该Sprint过程中工作任务,每一个Sprint通常持续一两个星期。
在每个Sprint开始时,将举行计划会议,把产品待办事项中的一部分工作拉到当前的Sprint中,团队估算出完成这些任务所需的工作量。
从技术上讲,团队应该致力于在Sprint过程中完成列举在Sprint待办事项中的所有工作,但我发现在实践中很少会出现这样的情况。(承诺是困难的。)
每天都会有一个叫作Scrum的快速站立式会议,每个人在会上都要给出非常快速的报告。
Scrum会议的理念是让每个人都了解进展状况,排除可能会延缓进度的任何障碍。
Scrum会议每天在同一时间同一地点举行,每一名团队成员需要回答三个问题。
(1)昨天你做了什么,有帮助团队达成Sprint目标吗?
(2)你今天会做哪些帮助团队达成Sprint目标的工作?
(3)是否有任何障碍阻碍你或团队达成Sprint目标?
我发现,通过第二个问题来寻求个人承诺是非常奏效的。因此,我会把它改成“我今天承诺要做什么工作以帮助团队达成Sprint目标?”以我的经验,这一点微妙的修改可以促成很大的改变。
在Sprint期间,团队合作完成Sprint中的所有待办事项,并且使用燃尽图跟踪团队完成待办事项的进度和速度。
燃尽图跟踪剩余的时间、故事点、困难点,以及任何被用于跟踪本Sprint中剩余的工作的表征方法。当Sprint结束时,在Sprint期间完成的功能被展示给利益相关人,实施评审的工作。
最后,要召开一个回顾性会议,团队需要反思已经完成的这个Sprint,并为如何改进下一个Sprint发表一些想法。
测试
测试的核心实际上是降低风险。测试软件的目的不是为了发现错误,或者让软件更加优秀。测试是通过主动发现和消除问题来降低软件的风险,这些问题对将来使用软件的客户会产生很大的影响。
黑盒测试
黑盒测试就是简单地把软件本身看成是一个黑匣子进而开始的测试。
当你做黑盒测试的时候,你只用关心输入和输出,不必关心实际输出是如何产生的。你也不需要了解代码,更不需要知道代码是如何工作的,只需要对软件输入一组给定的输入值,然后相应地应该产生一组给定的输出值。
白盒测试
白盒测试就是当你对系统的一些内部结构有所了解并且可以访问实际的源代码时,你可以使用实际的源代码来设计你的测试、执行你的测试。
验收测试
验收测试的基本思路就是:你需要执行一组测试以检验客户的实际需求或期望,以及其他针对系统整体运行效果的测试。
验收测试需要测试系统的整体功能,也需要测试系统的可用性。
验收测试的思想就是:验收测试需要根据用户的预期来检验系统的实际运行状况。
自动化测试
自动化测试:自动执行测试并且验证结果的任何类型的测试。
因此,你可以通过运行脚本来自动测试Web应用程序,这些脚本会自动打开一个网页、输入一些数据,按下一些按钮,然后自动检查页面上的一些结果。你还可以通过编写脚本来自动测试API,这些脚本会自动使用各种数据调用API,然后自动检查返回的结果。
越来越多的测试过程正在转向自动化测试,因为一遍又一遍地手动运行测试用例可能既单调乏味又容易出错,代价还很高昂,特别是在敏捷环境中,可能需要每两周左右就运行一组相同的测试,以验证是否有什么被破坏。
回归测试
回归测试基本上就是为了验证系统是否仍然按照以前的方式工作而进行的测试。
回归测试的目的就是要确保软件在功能上不会倒退。这对于敏捷开发方法非常重要,因为在敏捷开发过程中,软件是增量开发的,于是产生了一个潜在的风险:不断添加新功能可能会破坏现有的功能。
总结:
作为一名软件开发者,你应该比任何人都更关心质量。你不能抱有“反正测试人员会在代码中找出bug”的心态。相反,在对代码进行测试之前,你绝对应该将查找和修复bug视为己任。原因很简单。软件开发过程中bug发现得越晚,修复成本越高。
持续集成
关于持续集成,因为有搞过,所以这里通过自己理解简单概述如下: 一个项目的基本框架应该包括代码规范,基础插件集成,单元测试,E2E测试,代码格式校验,代码提交自动打包部署。 当以上框架搭建完成,开发人员只需要编写符合规范的业务代码及对应的测试用例,的规范,在代码提交的时候自动运行代码检查,代码推送之后触发action自动完成打包部署
调试
1. 重现bug
在调试bug时,首先要做的就是确保自己能够重现bug。如果你做不到这一点,那就去找人帮忙。如果测试人员记录了bug,那就请他们来为你重现bug。如果bug只是间歇性的、无法被可靠地重现,这意味着你并不知道重现问题所需要的情境。
其实并没有间歇性的问题。如果这是一个问题,它就一定可以被重现;你要知道的就是如何重现它。
2. 坐下来思考
思考一下问题,思考一下可能导致这个问题的原因。想想这个系统是如何工作的,以及导致系统产生古怪行为的可能的原因。
3. 检验你的假设
不是通过控制台,而是写一个单元测试用例来检验你的假设。如果你认为系统的某些部分不能正常工作,就编写一个你认为能够利用这个问题的单元测试用例。
如果你的假设是正确的,并且你已经发现了问题所在,那么你就可以立即着手修复它。现在,你利用一个单元测试用例就可以让验证和修复一步到位,并确保它永远不会再次发生。(不过,在你宣称bug已被修复之前,仍然要确保你尝试了重现实际的bug。)
如果你的假设错了,并且你编写的单元测试能够如预期那样通过,那么你也只是向项目中添加了另一个单元测试用例而已(假设你编写的这个单元测试实际上只有一个断言),这样能够保证系统更加健壮,并且你已经利用它否定了你的一项假设。
4. 缩小范围
有时候,如果你在调试的时候卡住了,你需要做的就是找出一种方法来把待解决的问题的范围缩小一半,即尽你所能把大块头的部分先剔除出去。具体采取的方法可以根据问题的不同而不尽相同,但是,基本思路就是尝试并考虑如何消除大量的代码或删除大部分的系统或变量,然后看看bug是否仍然可以重现。
5. 验证bug被修复
验证问题是否被修复,还需要针对这个问题编写一个回归测试用例,以确保它再也不会出现。
如果你真正理解自己所修复的问题,你就能针对这个问题编写一个单元测试用例,修复之后的代码就应该能够通过这个单元测试。
最后,你需要查找一下是否还有同类型bug。bug通常都是成群结队出现的。如果你发现在某种前置条件下会导致某个代码错误,那么很可能还会有由这个问题引起的其他bug。
控制台也是一个很有帮助的调试工具,但是这里要强调的是要带着验证某种可能性去使用控制台调试,知道你要检查什么,而不是随便看看。
代码维护
重构
影响代码可维护性的最重要因素之一就是代码的可读性。代码的可读性越强,维护代码就越容易;代码越神秘、越难理解,维护起来越困难。就这么简单。
本质上讲,重构改善了既有代码的设计。对我来说,重构意味着在不改变其功能的情况下使现有的代码更具可读性。
重构和单元测试需要双管齐下,因为如果你没有办法测试代码,你就很难确认你是否改变了代码的功能。在进行重构之前做一些单元测试是一个好主意,特别是当这次修改不同寻常的时候。
与同事的相处之道
只要人们为了实现一个目标而共同努力、聚集在一起工作,就会有某种形式的冲突存在。我认为应该这样,你认为应该那样,你认为我是笨蛋,我认为你是白痴,所以我们之间就有了冲突。
一定程度的冲突是健康的,存在冲突有益于任何形式的人际关系。不能总是要求人们都持赞同意见。人们的观点不同,世界观也不同。
如果解决得当,冲突是有益的,因为它可以产生更好的结果,优于来源于你或者我们各自有限的想法所导致的结果。所以不用回避冲突。如果你不同意某人的建议,那就要用恰当的方式表达你的意见。
冲突不应该演变为私人恩怨。一旦发现有这种趋势,那你可能需要冷静下来,离开这个场合直到你能以一种平和的、富有建设性的方式与你的同事重新交流。你的目标应该是找到解决问题的最佳方法,而不是极力去证明你是对的,也不是要证明你比同事更聪明,更不是为了证明他们的想法愚不可及。
真正的工作/生活平衡
记住,只有在你不再试图实现工作/生活平衡的时候,在你专注于尽可能充实你的生活的时候,你才能真正做到工作/生活平衡,而只有在你愿意花时间和精力去主动思考决定你想要过怎样的生活,并且在你采取必要的行动使之成为现实的时候,你才能做到这一点。
照顾好自己,谨慎挑选自己的人际关系,尽可能地活在当下,你就会发现,你的生活并不需要“平衡”,因为无论你做什么,你都会找到快乐和满足。
推销自己的想法
寻找共性
一个最好的最简单的说服别人的方式,就是尝试找出一些共同点。
争论是寻找差异,而说服是寻找共性。
当我试图向一个持相反观点的人讲明“我们说的其实基本上是一样东西”时,我通常都会得到最好的结果。我寻找共同点,特别是从动机出发寻找共同点,我会尝试把重点放在这些方面,我会强调我的建议或我所说的与他们已经提出的其实是一致的,或者是服务于他们的核心目的的。
你越能更好地弥合隔阂,你需要人们做出的跨越也就越小,这样他们才能聚拢在你的身旁。你也可以收回自己的想法,以一种能让你的听众更满意的方式重新组合它。重组的威力超级强大。重组后的框架如果构建得当,可以以完全不同的角度呈现完全相同的想法。
“赞成枪支管制”和“反对拥有枪支”听起来有很大的区别。其实这都是框架一手造就的差别。想想你的听众,想想他们的框架和参照系是什么,然后让你的想法与他的框架相符合。
假设你的老板对一个项目的进度很在意,而你又想向他建议:应该在应用程序中应用一个全新的、漂亮的框架以显著地提升代码的可维护性。这时你该怎么办呢?
不要跟他谈论“显著地提升代码的可维护性”。你的老板不在乎这个。他甚至还有这样的印象:每当有人谈到提升代码的可维护性时,在开发上就得花费更长的时间。相反,跟他说说:如果切换到新的框架将缩短开发时间,并有助于项目更快完成。
你的想法的框架必须适应于听众。
循循善诱
另一个能让人们确信你的想法就是好方法的做法就是引导他们朝着这个想法的方向前进,而不是直接把想法硬塞给他们。让他们自己去发现这个想法,而你只去做一个向导,轻轻地把他们推到你想要他们去的方向就好。著名的哲学家苏格拉底经常使用这种方法,所以这个方法有时也被称为“苏格拉底法”。
利用措辞谨慎的问题引导你的听众走上那条最终可以发现你的想法的道路。人们更可能相信他们自己发现的想法,或者他们自己思考过的想法。如果你通过提问来引导人们找到这个想法,你可能不得不放弃一些骄傲和荣誉,但你会得到更多的认同,而不仅仅是给他们现成的答案。
给予更多信息
不要直截了当地试图说服别人你对测试驱动开发(TDD)的想法,也不要试图说服他们为什么要这么做。相反,做一个关于TDD的演示。让你的听众了解TDD是什么,它的工作机制和工作流程又是什么。让你的听众了解实现TDD都有哪些工具以及他们可以阅读哪些书籍,从而让他们了解更多关于TDD的知识。先给他们一堆有价值的信息,然后再让他们接受。
当你采用这种方法时,他们会更容易接受你的观点、更容易被说服,不要只是试图让他们相信TDD是好的,你应该在项目中这样做。
绩效评估
一旦你制订了今年的计划,并且在其中概述了你的目标与工作领域,你就应该至少以每两周一次、最好是每周一次的频率向老板汇报你的进展情况。你应该直截了当地询问你做得如何,询问你正在做的任何事情中有哪些需要改进的地方,注意,是“任何事情”。
如果有任何需要改进的地方,就去立即着手去做,然后在下一轮“回顾检查”中展示你的进展状况。如果没有什么需要改进的地方,那就再确认一下。你可以说:“那么,你的意思是,现在我已经百分之百地达到了今年的所有目标,你确定我没有什么需要改进的?”“我只是想确保我把整件事都搞清楚了。”
关于领导
高效能领导者是那种能鼓舞、激励和推动团队以保证团队成功的领导者,那种不需要正式授权就可以赢得尊重、促进合作和激发最佳成绩的领导者,而不是那种被简单地授予“领导者”头衔的领导者。 领导力不是头衔,也不是职位。领导力是你的所作所为,也是你发挥出的榜样力量。
你可以被告知你是领导者,你也可以被授予领导者的正式头衔,你可以被任命去负责一个团队。但没有人,绝对没有人,能够让你成为领导者。你必须靠自己去做到这一点。你必须自己去掌控“领导者”的职权。
领导力就是让人们跟随你进入你对未来的憧憬之中,因循你所要前进的方向,沿着你所选定的道路前进。这意味着你必须身先士卒、率先垂范。领导是站在前面的人,而不是从后面推别人的人。
没有头衔,没有正式的称号,没有来自上级的授权说“你就是那位领导”,因为服从不是目标,发自心底的全力支持才是目标。
你可以用武力或者权威来暂时控制某人的行为,但是身为领导者,需要你去试图赢得他们的内心与灵魂,激发出忠诚而不是恐惧。
建立声望
你必须要意识到,这里有一条重要的原则,同时也是一个重要的观念:你要为他人创造价值。如果你不是基于这条重要的原则做事,那么在这个世界上再完美无缺的品牌以及所有的自我推销工作都是徒劳无功的。
你能做的最好的营销工作就是给别人的生活增添价值。你还应该被人们称为“给予者”。
做一个其他人想和你在一起的人,因为他们觉得当他们围绕在你身边的时候,他们时受益的。
很多公司都倒闭了,很多品牌都失败了,因为他们试图从他们的客户那里榨取到最后一点儿利益。他们试图吸取价值而不是注入价值。
我向你保证,如果你能为人们的生活注入价值,能为人们的生活带来真正的改变,而且始终如一地坚持这么做,那么你一定会获得回报。
只要你能帮助足够多的人得到他们想要的东西,那么你就能得到生活中你想要的一切。
读书
如果你正在使用某种特定的技术,而你当前在大多数时间里都会用到它,那么你应该优先学习这一特定技术,因为它可以节省你的时间,让你的工作更有效率。在这种情况下,立即投资于技术技能的学习将会有高额的回报。
这样,即使将来你换了工作,看起来好像是“浪费时间”学习一项对将来无用的技能,也就是说你花费了很多时间在一项你不再使用的技能上,你也可能从最初投入的时间中获得足够多的好处,从这一点上来说这么做还是值得的。
但是,如果你对当前正在做的事情非常精通,目前你只是要寻找一种新的技能去学习,那么你可能要优先考虑那些提高编写质量代码以及有关个人发展的经典书籍,从长远来看,这么做将给你带来更大的好处。
学习目标
做一专多能的人
几乎所有的专家都是通才,但是没有一个通才是专家。
我这么说是什么意思呢?我的意思是,通常,为了能够成为一名专家,需要日积月累大量的综合性知识。如果在你的领域里没有对综合性知识的广泛积累作为基础,那么想成为一名优秀的专家是非常难的。
关于博客
保持持续输出,坚持下去,所有失败了的人都是歇了一段时间没有反馈,或者因为其他各种原因放弃写博客的人。
职业发展路径
太多的初级程序员从不花时间考虑他们的职业发展道路,从来没有深思熟虑过他们想要走什么样的道路,想要投身于哪一个领域。相反,他们只会站在路边,声嘶力竭地高喊“有没有哪个团队想要我”,然后随随便便就加入一群想要去铤而走险的人中,把别人的道路当作是自己的道路。
思考一下:你想成为怎样的软件开发者。你想永远都做职业开发者吗?如果是,那你想做哪个领域的开发者:Web开发者、移动开发者,还是云开发者?还有,你的职业生涯的终点在哪里?最终,你想做一名架构师吗?还是说,你只是想一直编码、一直都在做一些很酷的事情,永远都不要操心自己该往哪个方向前进?你想让自己的职业发展得尽善尽美吗?
如果是这样的话,那你最好现在就开始寻找拥有高级技术发展通道的公司。也许你想最终进入管理层,或者成为首席技术官,甚或是首席执行官。又或许你想在自己的职业生涯早期做一名开发者,然后转变成为一名自由职业者甚或是创业。
无论你决定做什么,最重要的是:你需要做出决策,并且为此做出计划。
即使你做出了选择,你也不必死守在一条通道上一成不变,你可以不断调整改变计划。但是,你应该至少制订一些计划,否则你会在自己的职业生涯中漫无目的地随波逐流。