This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,148 @@
<audio id="audio" title="25 | 有哪些方法可以提高开发效率?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/27/ee/270ecdda65cd693db90dcc69ee1571ee.mp3"></audio>
你好,我是宝玉,今天我想与你讨论一个每个开发人员和项目管理者都关心的话题:如何提高开发效率。
我其实也一直很关注这个话题收集了很多方法让自己工作变得卓有成效。通过对这些方法的应用我也可以算得上是一个高效的程序员曾一个人在很短时间完成了飞信Web版客户端在DePaul上学之余帮学校完成了在线教学播放器系统的改造三个月时间帮公司完成了主站从jQuery到React的迁移。
如果让我对学过的这些方法做个整理和总结,再进一步精选提炼,我觉得对我影响最大的是“积极主动”、“以终为始”和“要事第一”这几条看似简单的工作原则。
## 积极主动,行动起来改变自己
相信你也和我有过相同的经历。成为一个高效程序员,最大的阻力不是来自于不知道方法,而是自己的消极心态。遇到进度延迟、效率低下之类的问题,你就会下意识觉得:
- 时间进度太紧了;
- 我已经尽力了;
- 最近加班太多了没精神;
- 产品经理太不靠谱了,需求没想清楚,害的我瞎忙活。
是的,你也知道这些答案都很消极负面,可是怎么控制自己不这么想呢?首先你要知道,无论这些事情的本质责任在于环境还是个人,抱怨排斥的心态对于实际工作的改进是没有任何帮助的。
当然,很多人也知道抱怨没用,但具体怎样才能做到不抱怨,并且积极主动呢?史蒂芬・柯维写在他的《高效能人士的七个习惯》书中,对这个问题提到了两个行之有效的建议,我们可以结合着软件开发来分析一下。
#### 想想再回应
我还记得第一次有人给我介绍单元测试很好用,能让你效率更高、代码质量更好时,我的第一反应是不可能,这样明明要多写很多代码,怎么可能会高效?
于是我有一段时间是很排斥的,直到后来参与一个已经有单元测试的项目,尤其是在重构代码的时候,我发现修改了大量代码后,程序还是很稳定,当时便觉得应了网友的那句话,“真香”!
每个人对于外界的刺激都会做出反应,本能的或者习惯性的,就像我前面举的例子,遇到事情会本能的觉得都是外部原因。如果一直这样,那就会进入恶性循环,变得更加消极麻木。
但如果在回应之前,给自己一点时间想想,站在积极的方面理性思考一下,就可以去控制你的本能反应。
所以很多次,就在我脱口而出“不可能”或者“不行”的时候,我提醒自己再想想。于是我会改口说:“我试试”、“我再想想”。这样很多次提醒自己以后,会一点点由“不可能”的本能变成“我想想”的习惯。
后来有人跟我说CI持续集成很好我思考过了之后进行了尝试在Github上建了一个项目把CI搭起来试了一下觉得真的是很好。如果我还是秉持着以前的消极心态不知道又要晚多久才能去尝试。
#### 减少关注圈,扩大影响圈
我关注很多事情,比如编程语言、明星八卦、国家大事,这些都是“关注圈”。而这其中,要区分哪些事,是我可以影响和掌控的,这些事则是“影响圈”。
**不要总盯着自己无法改变的部分,你需要要多花时间精力在影响圈上。**
比如说我不能改变996至少我可以利用这时间多学习一点找机会换一个更好的环境我不能要求每个人都写单元测试但是我自己的代码写了单元测试这样项目质量更好了我也更有价值我不能决定跟什么样的人一起共事但是我愿意跟他们分享我的经验他们成长了我也受益。
工作一段时间后,你也可以尝试去扩大自己的影响圈。
比如说,很多程序员像我一样,有过不少因为产品经理需求没想清楚导致返工的经历,后来我就格外关注产品设计相关的知识,业余时间自己学习了不少,这就相当于扩大了我的影响圈。
所以后来产品经理给我一个需求,我不需要在开发完成后才抱怨他不靠谱,而是在给我需求的时候就去跟他讨论,是不是有可能没想清楚。
当你不仅仅局限于程序员的角色思维,扩大了影响圈之后,你就可以试着向产品经理提出很多有价值的建议,比如:
- 这个布局在文字很长的情况下会有什么变化?
- 如果网络很慢,加载数据的时候应该显示什么?加载失败显示什么?
- 如果数据为空的时候这个列表应该显示什么?
其实“减少关注圈,扩大影响圈”这个道理也很简单:**接受不能改变的,改变能改变的,尽量扩大可改变项的范围。**
## 以终为始,想清楚再开工
如果对比一下我在十几年前作为一个新手程序员,和现在作为一个老手写代码有什么不同的话,我认为在新手阶段,我是拿到需求就开始写,写到一半发现好像不对,马上修改,好像还不太对,就这样反反复复,效率很低下。
而现在拿到一个需求,我会先仔细的分析需求文档,反复和产品经理确认各种细节,然后做个简单的设计,考虑清楚模块怎么设计,他们之间是什么关系,然后再写,写完还要加上测试代码。
你知道最大的区别是什么吗?我现在做一件事之前,会先想清楚“终”,然后才知道怎么“始”。所以我先搞清楚需求这个“终”,然后再设计规划出这个从“始”通向“终”的路线,最后从“始”出发写代码,一气呵成,不仅快,而且质量好。这就是“以终为始”。
要做到“以终为始”,就是在做事情的时候注意三点:**目标、原则和计划。**
#### 经常停下来想想目标
我刚毕业参加工作的时候要开发一个内容管理系统其中涉及有数据库访问这就需要把数据表的字段和类对应起来觉得太体力活了于是我开始写数据库生成代码工具。而要想写代码生成工具我还得学习Winform知识……就这样几个月过去了关于这个系统的代码还是最开始的几行
我的目标是写一个内容管理系统,结果却跑去写代码生成工具,这样怎么能做到高效呢?正确的做法应该是手动完成这几个类的生成,其实用不了几分钟,或者用一个现成的工具。如果觉得代码生成工具是个有意义的项目,应该另外立项,而不应该影响当前的项目。
这样的事情在我身上还发生过几次,所以我后来就逼着自己隔一段时间要停下来想想:我的原始目标是什么?我正在做的事是我的目标吗?如果不是,那么马上回到自己的原始目标去。
#### 制定原则
其实大部分很好的编程方法都是需要坚持做才有效果的,比如说自动化测试代码,有时候时间进度一紧,就会来不及写,时间一长,就会欠下技术债务。
所以我给自己定了一个原则增加一个功能就要写自动化测试如果来不及写就给自己写一条Ticket。
这条原则我坚持得很好,所以我的自动化测试代码得以坚持,从而真正帮助我做到高效开发。
你也可以给自己定一些原则,比如:
- “先运行再优化(Make it Work Make It Right Make It Fast)”——也就是在优化代码之前,先用简单的方法实现,再考虑怎么优化,这样可以保证设计的简单,也可以避免你陷入技术细节中而忽视了原始目标。
- “不复制粘贴代码(Dont repeat yourself)”——复制粘贴会导致代码臃肿,不便于维护,提取抽象可以保持简洁。
- “每个Pull Request要尽可能小”——这有助于把复杂的任务分解成几个简单的任务简单的任务更容易高效完成。
有原则了,你才能不忘初心,有始有终。
#### 公开自己的计划
那么有了原则就够了吗?显然不是,有了原则,你还要坚定不移地去执行。如何执行呢?做计划。
刚开始工作时,我是害怕做计划的,怕计划了完不成,问到我工作的时间安排时,我会给一个模凌两可的答复,这其实导致了我在实际开发时,缺少进度压力,从而迷失在细节中导致延误进度。
后来我尝试做出了一些改变,把任务细化,做个简单计划,主动给出一个明确的时间点。有了计划指引和时间点的压力,会倒逼着自己时刻专注于目标是什么,“终”在哪里,还有多少没有完成,这样下来工作效率自然而然就会高起来。
通过在做事时,围绕着目标、原则和计划这三个点,反复地刻意地练习,也可以让你慢慢养成“以终为始”的好习惯。
## 要事第一,把时间用在刀刃上
作为程序员其实大部分时间并不能专注写程序总有各种各样的事情打断我们比如一会产品经理找你过去开个会确认个需求一会测试过来找你重现一个Bug一会还有同事过来请教你一个问题微信上老朋友找你叙叙旧突然生产环境出故障了需要马上去解决。
就这样一天下去,感觉一直在忙忙碌碌,其实并没有多少时间在写程序。这时候怎么办呢,对手头的事情进行优先级管理。
时间四象限也许你不陌生,就是把事情分成重要紧急、重要不紧急、紧急不重要、不紧急不重要四个象限,不同的事情有不同的应对策略。
- **重要紧急的事情马上处理**
比如说,生产环境出故障了,测试环境部署失败了,这些都是重要并且紧急的事情,只能是马上处理。
- **重要不紧急的要事,要花最多的时间在上面**
对代码重构、写自动化测试代码、确认清楚需求文档,这些事情都属于重要不紧急的事情,但是如果不及时处理,就有可能变成重要紧急的事情,比如不偿还技术债务,就可能会变成生产环境故障。
所以这部分事情我会多花时间,重点做。通常我会每段时间只专注做一两件重要的事,其他事情尽可能忽略,比如前一个阶段我主要的工作就是重构前端代码,这个阶段我就在忙排查性能隐患,至于其他事情,就先放一放。
- **紧急不重要的事凑一起集中做**
像微信的消息通知,无关紧要的会议,请教一个不算很急的技术问题,这些都是紧急不重要的问题,然而却会占用我们大量时间。如果时间都用在这些事情上面,必然会占用在重要事情上所需的时间。
所以我有些小技巧也许你可以参考。比如我在专注干活时,会全屏幕、关掉所有消息通知,保证没有消息干扰,忙完一段后再去集中处理。
还有如果有人找我时我正在忙如果他的事情不是重要紧急的我会礼貌地告诉他我正好手头有点事情大约多少时间后我主动去找他。相应的我也会尊重别人的时间找别人的时候会先问一下“你什么时候有10分钟左右时间我想请教你一个问题
- **不重要不紧急的事情能不做就不做**
不紧急不重要的事也很多比如说我的Mac电脑突然提示我要更新系统了。我有点强迫症以前系统一有要升级我就迫不及待要升级到最新结果一升级系统半天就不能干活了。所以后来这种事情就放在不重要的时间去做比如周末、睡觉之前让它慢慢升级。
其实我在做开发的时候,觉得很多很杂的事情也不算太多,真正到后来转型做管理的时候,才真正体会到什么叫事情多而杂。但正是源于开发时期就形成的时间四象限方法的运用,让我可以在繁忙的时候,保证时间用在有价值的事情上。
要事第一,就是要保证你有限的时间用在最有价值的事情上。
## 总结
积极主动、 以终为始和要事第一,这三个原则以及其衍生出来的方法,正是帮助我逐步变成一个高效程序员的关键所在,希望也能对你有所帮助。
如果你已经学习了很多类似的原则或者方法,而觉得没什么效果,那也许只是因为没有尝试把它们变成习惯。你可以像我一样,把认同的好的原则或方法,通过反复的刻意练习,反复地提醒自己,训练成习惯,然后用习惯指导你的日常开发。
当然,这样的改变不会是一天两天就能完成,但也不用着急,因为习惯的养成需要时间的积累,才能变成条件反射。当你把好的原则或方法变成了直觉反应,自然就会成为一个高效的程序员。
## 课后思考
你知道的有哪些提升开发效率的方法?你身边那些高效程序员都是如何做到高效开发的?欢迎在留言区与我分享讨论。
感谢阅读,如果你觉得这篇文章对你有一些启发,也欢迎把它分享给你的朋友。

View File

@@ -0,0 +1,179 @@
<audio id="audio" title="26 | 持续交付:如何做到随时发布新版本到生产环境?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/d7/4d/d72b3913236245e77ed149826264934d.mp3"></audio>
你好,我是宝玉。到今天为止,持续交付已经成为一种公认的好的开发实践,越来越多的开发团队都已经应用持续交付,它通过自动化的方式,让你的代码在每一次提交后,都能自动化地走完编译、测试流程,完成后即可随时准备好部署发布。
持续交付如果细分,其实可以分成持续集成、持续交付和持续部署三个概念,这三个概念很相近,但又有所不同。
今天我将带你了解什么是持续集成、持续交付和持续部署?以及我们该如何用好它们,在项目中最大程度上发挥其效用。
## 集成、部署和交付的发展史
要想更好地理解并应用好持续集成、持续交付和持续部署,你需要了解它们的演变史。持续集成、持续交付和持续部署的历史还不算太长,但是集成、部署和交付却是伴随着软件工程一起发展的。
#### 集成的发展演变
在多人软件项目开发的时候,每个人都会负责一部分功能模块的开发,集成指的就是每个人把自己开发的分支代码,合并到主干上,以便测试打包。
- **集成的原始阶段**
早在瀑布开发的年代,在开发阶段,一般是不集成的。大家各自开发,等到开发阶段差不多快结束了,再一起提交代码到源代码管理工具,让代码集成在一起,再编译、部署发布到测试环境。
由于长时间都是在各自的开发环境运行每次集成都是很痛苦的过程会遇到各种问题比如说编译无法通过、hard code了开发环境地址、类库版本不一致、API格式不一致等通常要持续几天甚至几周才能逐步有一个相对稳定的版本。
[<img src="https://static001.geekbang.org/resource/image/9b/c6/9ba564d561097d452d8ea46b6e4c5ec6.png" alt="" title="图片来源Understanding the Difference Between CI and CD">](https://thenewstack.io/understanding-the-difference-between-ci-and-cd/)
《重构》的作者Martin Fowler说过“如果一件事很痛苦那么就更频繁的做if it hurts, do it more often. )”,持续集成本质上也是把集成这件让人痛苦的事情,更加频繁地去做。
[<img src="https://static001.geekbang.org/resource/image/8d/bf/8de10a3d3b2e46e2f8b945bdf4d37fbf.png" alt="" title="图片来源Understanding the Difference Between CI and CD">](https://thenewstack.io/understanding-the-difference-between-ci-and-cd/)
瀑布模型开发的集成,或者说传统的集成,都是在开发阶段整体完成的差不多了,才开始集成。而持续集成的做法,则是每次有代码合并入主干之前,都进行集成,持续的集成。**代码集成到主干之前,必须通过自动化测试,只要有一个测试用例失败,就不能集成。**
持续集成的好处很明显:
- 配合自动化测试,这样可以保证主干的代码是稳定的;
- 频繁集成可以让开发人员总能从主干及时获得最新的代码不至于像类库、API不一致等问题到最后测试的阶段才暴露出来。
持续集成主要的问题就是搭建整个持续集成环境,要稍微麻烦一点,另外需要配合一些流程规范来辅助执行,比如要求有一定自动化测试代码的覆盖率,要求测试通过才能合并到主干。
#### 部署和交付的发展史
部署指的是将代码发布到各种环境,比如部署测试环境以供测试。交付则指的是软件产品在测试验收通过后,具备发布到生产环境交付给客户使用的条件。
- **部署和交付的原始阶段**
在早些年,部署是一件很麻烦的事情。需要手动获取最新源代码、编译、再需要针对环境修改很多配置。
这事我确实深有体会,当年在飞信时就这样,几十个服务,一个服务有十几个项目,光挨个编译一遍就要好久,然后每个服务还有自己的配置。所以当年专门有一个人,就负责每天部署各种服务到测试环境。
生产环境就更麻烦了因为出错了会导致服务中断。最初部署生产环境是开发人员自己做的根据自己的经验把程序部署然后手动修改很多配置以保证正常运行。但这样经常会遗漏一些配置导致程序无法正常运行出问题后程序员很可能会直接在线上环境修复Bug导致更大问题。
随着分工的进一步细化,逐步发展成有专门的运维岗位,由运维人员负责部署。而开发人员上线前要写专门的部署文档和检查表,运维人员按照部署文档和检查表一步步部署生产环境。
这样确实有效减少了配置错误等问题,但整个部署过程还是很繁琐,尤其是服务器一多,耗时很长,仍然可能会因为人工操作错误导致失败。
所以为了避免部署出问题,会尽量避免进行生产环境部署,几周甚至几个月才会部署一次。
- **从手动部署到脚本自动化部署**
对于程序员来说,如果一件事能自动化解决,迟早会有人找出自动化的解决方案,部署也由原来的手动部署发展成为自动化部署。
早期的自动化部署解决方案是每日构建Daily Build简单来说就是大家在每天晚上下班后每日构建程序自动从源代码管理器下载最新代码编译、部署程序到测试环境。这样第二天测试人员就可以拿到最新的程序对前一天修复的Bug进行测试。
每日构建是个很大的进步,因为初步实现了自动化对代码进行编译、部署测试环境。但也有一些不完善的地方,比如说如果有开发人员提交的代码有问题,可能会导致当天的编译或部署失败,那么第二天开发人员上班后,还需要手动解决。
你会发现,自动化逐步应用到运维领域,确实是让部署过程更容易,但也只是让部署过程更容易,还是无法解决发布版本的质量问题,还是可能会因为配置错误导致失败,测试环境正常的功能到生产环境就不工作了。
- **从脚本部署到持续交付**
其实在理解了持续集成后,再理解持续交付就要容易多了。持续交付,就是在持续集成的基础上,再进一步,在功能合并到主干后,不仅会进行自动化测试,还会打包,并部署到测试环境中。
理论上来说也可以直接部署到生产环境,但是这个环节需要人工确认。参考下图,红色部分表示需要手动确认。
[<img src="https://static001.geekbang.org/resource/image/a2/00/a2e354c88a3bf0df871174980ef3a900.png" alt="" title="图片来源Understanding the Difference Between CI and CD">](https://thenewstack.io/understanding-the-difference-between-ci-and-cd/)
持续交付本质上也是把部署和交付这件让人痛苦的事情,更加频繁地去做,从而让部署和发布变得不但不痛苦,反而越来越简单。
把持续交付的工作做好后,部署生产环境会变得非常简单,只需要点一下按钮或者运行一个命令,就可以很快完成,不需要人为地去修改配置等手动操作,也将因为配置错误或者环境不一致导致的问题的可能性降到了最低。
- **从持续交付到持续部署**
持续交付,对于生产环境的部署,依然需要有手动确认的环节。而持续部署,和持续交付唯一的不同,就是手动确认的环节都没有了,每次代码从分支合并到主干,在自动化测试通过后,会直接自动部署生产环境,不需要人工确认。
但是,持续部署要想做好,还是很有挑战的一件事,毕竟从代码合并到生产环境的部署,如果没有人工干预仅仅依赖于自动化测试,这对自动化测试的覆盖率和稳定性要求非常高。尤其在开发新功能时,还需要引入新的自动化测试代码,可能会导致测试不全面。
当然对于新功能可能导致的不稳定问题也有解决策略就是把新功能用功能开关Feature flag隐藏起来设置特定的Cookie或者Header才打开到生产环境后人工再测试一遍通过后再打开如果没通过就继续修复继续持续部署。
## 该不该应用持续交付?
经常会有人问我类似的问题:我们是瀑布模型开发,该不该应用持续交付?
我的答案是:持续交付和用什么开发模型是没有关系的,瀑布模型也可以应用持续集成,应该尽快将持续集成的环境和相应的开发流程搭建起来,可以马上看到好处。
<li>
**尽快暴露问题**Martin Fowler说过“持续交付并不能消除Bug而是让它们非常容易发现和改正。”自动化测试可以保证很多问题在合并到分支之前就能被发现每次合并后就部署到测试环境也能让测试人员尽早介入及时发现问题。
</li>
<li>
**极大提升效率**:持续交付让开发过程中从代码合并,一直到最终部署,都实现了自动化,能极大程度上提高效率。
</li>
<li>
**提升质量**:每次合并之前都需要通过自动化测试,因此错误会少很多。
</li>
<li>
**降低项目成本**:在最初搭建持续交付环境的时候,是要投入一定成本的,但是从长远看,开发效率提升了,代码质量提高了,反而是对降低项目的整体成本有帮助的。
</li>
**虽然现在持续交付还不够普及,但未来就像源代码管理一样,成为开发团队的标配。**现在大厂都已经普及了持续交付,还会有专门的团队负责持续交付工具的开发和维护。对于中小厂,一般不需要自己开发持续交付工具,可以基于开源工具搭建,或者购买托管的持续交付工具,一样可以很好满足持续交付的需求。
如果你所在团队还没有开始用起来持续交付,那么不如现在开始应用起来,能有效提升团队的开发效率和代码质量。当然很多团队没有推行,主要问题还是不知道如何搭建一套持续交付的环境。接下来,我就给你介绍一下如何搭建自己的持续交付环境。
## 如何搭建持续交付环境?
要搭建好自己的持续交付环境,其实并不算太难,已经有很多持续集成工具和教程帮助我们做这件事。
#### 准备工作
根据前面对持续交付的说明,要想搭建自己的持续交付环境,并不是简单找一个持续集成工具一搭就可以工作了,而是还需要做一些准备工作。
我们先来看持续集成部分,持续集成相对要求简单:
1. 需要有源代码管理工具比如说git、svn因为持续集成工具需要从统一的源代码仓库获取代码
1. 需要写自动化测试代码,因为持续集成有一个很重要的条件,就是自动测试必须通过。
第一个条件其实好满足的,现在源代码管理工具已经是标配,无论是免费的还是收费的,都有很多选择。第二个条件其实也不是太大的问题,因为自动化测试覆盖率,可以逐步提升,不要求一步到位。所以可以先把自动化测试写起来,然后在开发过程中逐步增加覆盖率。
持续交付相对比持续集成要求更高,因为整个过程需要高度的自动化。要实现持续交付,你的项目需要满足以下条件:
1. 对代码构建的过程可以反复进行,并且每次构建的结果是一致的、稳定的;
1. 所有环境的配置都存在于源代码管理工具中,不仅仅是代码;
1. 需要自动创建针对于不同环境的发布包;
1. 所有环境的部署发布步骤都必须是自动化的。
上面这些要求,最难的部分其实就是自动化打包和自动化部署到各种环境,因为每套程序都不一样,每个服务器环境也不一样,这是必须要各个团队针对自己的项目情况去解决的问题。
#### 选择合适的持续集成工具
持续集成工具现在已经有很多选择,有开源的、商业的,有线上托管的,还有自己搭建的。
主要的持续集成工具有这些:
- Jenkins
[Jenkins](http://jenkins.io)应该是目前最好的开源持续集成工具,可以自己搭建,插件非常丰富,可以满足绝大部分项目的需要。相对使用难度要高一些,需要花一点时间学习。
- Go CD
[Go CD](http://www.gocd.org)是ThoughtWorks公司出品的持续集成工具可以免费使用。
- Travis CI
[Travis CI](http://travis-ci.org)是一个老牌的托管的商业CI系统和Github集成的非常好尤其是开源项目可以免费使用。
- GitLab CI
[GitLab CI](http://about.gitlab.com)是Gitlab推出的持续集成工具可以自己搭建也可以使用它的在线托管价钱便宜。
- Azure Pipelines
[Azure Pipelines](http://azure.microsoft.com/zh-cn/services/devops/pipelines/)是微软的持续集成平台,可以自己搭建也可以使用它的在线托管,和微软的开发语言和服务集成很好。
#### 根据选择的工具实施
在选好你要用的持续集成工具后,就需要根据工具的说明去搭建。这部分相对简单,网上也有比较多的教程,限于篇幅,这里我就不一一介绍啦,相信你通过它们的官方网站或者是搜索,很容易能找到很多相关的使用教程。
## 总结
今天我带你一起学习了与持续交付相关的一些概念:
- **持续集成**,就是持续频繁地将代码从分支集成到主干,并且要保证在合并到主干之前,必须要通过所有的自动化测试。
- **持续交付**,则是基于持续集成,在自动化测试完成后,同时构建生成各个环境的发布包,部署到测试环境,但生产环境的部署需要手动确认。
- **持续部署**,是在持续交付的基础上,对生产环境的部署也采用自动化。
要搭建持续交付环境,首先需要做好准备工作,例如自动化测试代码和自动部署脚本;然后要选择好持续集成工具;最后按照选择的持续集成工具来实施。
最后,推荐你配合阅读《[持续交付 : 发布可靠软件的系统方法](http://book.douban.com/subject/6862062/)》,这本书很系统地讲述了持续交付的概念和如何去实施的过程。
## 课后思考
你的项目中应用了持续交付吗?如果应用了,你觉得有哪些优缺点?如果没有应用,你觉得主要的障碍是什么?欢迎在留言区与我分享讨论。
感谢阅读,如果你觉得这篇文章对你有一些启发,也欢迎把它分享给你的朋友。

View File

@@ -0,0 +1,148 @@
<audio id="audio" title="27 | 软件工程师的核心竞争力是什么?(上)" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/c1/3e/c115edd3896b53ffb718bbd89e64d83e.mp3"></audio>
你好,我是宝玉。软件工程师,是软件项目重要的人员组成,从设计到编码实现以及上线后的运行维护,都需要软件工程师的参与。所以大家都很关心的一个问题是:软件工程师的核心竞争力是什么?
## 软件工程师的核心竞争力
其实我在微博上问过“软件工程师的核心竞争力是什么?”这个问题,得到很多答案:技术、代码、天赋和激情、经验、想象力……
我思考过这些答案,觉得很多答案挺好,但是不够突出核心竞争力,或者没有突出软件工程师的特点。
比如说技术和代码的能力,属于基础能力,而不属于核心竞争力;天赋和激情其实放哪个职业都可以这么说,何况天赋也不是决定性因素,聪明人不是好程序员的例子也很多;
经验是很重要,但是不能说明太多问题,有些号称有三年开发经验的程序员不过是把一年的经验重复了三次罢了;想象力是很重要,但我觉得更适合科学家或者艺术家,因为他们要通过想象力在未知的领域去探索,而工程师更多是利用已有的知识去打造产品,想象力算不上核心竞争力。
**我觉得软件工程师的核心竞争力,不是单一能力的体现,而是几种能力和价值的合集。学习能力、解决问题能力和影响力构成了软件工程师的核心竞争力。**
#### 学习能力
对于软件工程师来说,最基本的要求是技术和代码。如果你看招聘网站上招聘软件工程师的要求,都需要能掌握一门或者多门编程语言,会熟练使用工具、框架。
但熟练掌握一门编程语言、框架,还不能构成核心竞争力。因为现在技术更新迭代很快,现在你熟悉的语言或者框架,可能过几年就没有太大的市场了,需要学习新的技术。
这点做前端的同学一定深有体会比如说前几年jQuery很火你好不容易精通了过两年又要改用Angularjs而现在则是React、Vue的天下了。而且光会这些框架还不够还要学习使用配套的打包工具而这些工具也一直在推陈出新每次更新升级都需要重新学习。
就算是编程语言时间周期能稍微长一点但也没有谁能保证一门语言就可以一直很火。我早些年对Asp.Net的掌握程度已经到了技术专家级别后来公司要转型做移动应用就必须要去学习Objective-C否则就得换个公司才行。
出国留学后要重新找工作这时候Asp.Net和Objective-C的工作机会很少但是前端工作机会多我就需要去学习前端才能有更多的工作机会。
所以我觉得,编程语言、框架、工具,这些都不是软件工程师的核心竞争力,能快速学习掌握编程语言、框架、工具的学习能力才是软件工程师最**基础**的核心竞争力。
#### 解决问题的能力
为什么我说学习能力只能算是基础的核心竞争力呢因为技术学了是要用才能产生价值的。学的好不代表用的好所以你看很多Leetcode上刷题分很高的同学让他去实现一个需求代码可能还是会写的一团糟。
那么软件工程师怎么运用学到的技术呢?我们可以先看看软件工程师的日常工作,有哪些主要工作以及需要什么样的能力去解决:
1. 实现功能需求——需要先分析需求,然后抽象设计,最后实现;
1. 修复Bug——改Bug最大的挑战其实是重现问题也就是发现问题然后再分析问题最后解决问题
1. 重构代码、优化性能——对代码重构,优化性能,最难的地方其实在于发现代码问题在哪,发现性能的瓶颈,后面再去寻找解决方案,最后再解决。
也就是说,**软件工程师这些日常开发工作的核心还是在发现问题、分析问题和解决问题,在这里我统称为解决问题的能力。**这几个能力看起来没什么稀奇,但是要仔细分析,其实软件工程师的水平高低,恰恰就体现在解决问题的能力上面。
#### 发现问题
若干年前我们要做一个抽奖系统,负责这个任务的程序员设计了技术方案让我审查,他的方案从功能方面是没问题的,但在安全方面却欠考虑。
我就问他如果有人用个工具模拟用户操作反复点,岂不是可以不停参加抽奖,极大提高中奖概率?于是他说那可以在前端增加限制重复点击。我说如果通过抓包工具反复直接发送数据包,不还是一样可以绕过你前端的检查吗?
同样一个抽奖系统需求,新手程序员看到的是如何实现功能,而有经验的程序员,会发现可能存在的安全隐患,未雨绸缪,把可能的安全问题消除掉。这就是发现问题的能力体现。
- **分析问题**
软件工程师经常遇到的一个问题就是生产环境发生故障,新手程序员通过分析也能把问题修复,但修复完了就觉得没事了。而有经验的程序员,会在恢复后还会进一步分析故障产生的深层次原因,以及以后可以怎么预防类似的故障再次发生。
分析问题,不仅是分析表面的问题,还需要去分析问题深层次的原因,以及思考预防同类问题的机制。
- **解决问题**
在发现问题和分析问题后,解决问题相对会容易一些。但有时候明明知道问题在哪,但不知道怎么解决也是很苦恼的事情。
在工作中就经常有新手程序员跑来找我请教问题比如说遇到一个API不会用。这时候我通常不会直接告诉他答案因为我可能也不知道某个API的用法就算我知道告诉他这一次了他下一次还是不会自己去解决。
所以我会反问他:
- “查过官方文档吗”——基本上大部分API在官方文档都有说明的
- “有没有去搜索过”——很多问题已经有人遇到过而且还把解决方案都贴出来了比如StackOverflow就是个很好的地方
- “用的什么关键字?”——很多时候没找到结果就是因为关键字没选好,比如用中文关键字很难搜索出匹配的技术帖子,改成英文使用谷歌就可以找到更多更合适的结果;
还有的问题确实不是通过搜索能解决的,需要去寻求其他组或者外部专业人士的帮助。就算是问问题这种小事,一样都能体现程序员的水平。
比如我就遇到过很多次有程序员去请教别人问题但是都没人回复的并不是没有人愿意帮忙而是他基本的问题都没有描述清楚从他的问题很难知道表达的意思和要解决的问题。这时候我通常会建议他先去看看《提问的智慧How To Ask Questions The Smart Way》这篇文章。
这样的发现问题、分析问题和解决问题的能力,就是软件工程师的**进阶**核心竞争力。
#### 影响力
解决问题的能力,确实是软件工程师很重要的一种能力体现,但是还不能完全体现出软件工程师的核心竞争力。
为什么大部分程序员的技术水平和解决问题能力差不多,而有的升职加薪的机会更多?有的不需要去找工作,总有工作来找他们?这其中的差别,就在于他们的影响力不同。
有些程序员,做事情认真靠谱,做出来的结果让人放心,这样久而久之,就在公司形成了口碑和影响力,大家愿意与之共事。
有些程序员,乐于帮助其他人,分享自己的经验,跟一些新手程序员是亦师亦友的关系,在团队里有很高的威望。
有些程序员,有独特的项目、公司或者行业经历,比如在阿里巴巴这样的大厂有多年架构师经验,在业界有一定知名度。
有些程序员写自己的技术博客出去做技术讲座成了技术大v在技术圈子里面有一定的名气和影响力。
这样的影响力不是一朝一夕能形成的,但却是一个软件工程师最核心的价值体现。
你需要通过一点点技术成长的积累,需要通过一个个成功项目的积累,需要通过一篇篇技术文章分享的积累,需要通过一次次帮助其他人成长的积累。而一旦形成足够的影响力,就会变成软件工程师职场发展最牢固的护城河。
所以综合来说,软件工程师最核心的竞争力其实分三层:
- 最底层、最基础的就是学习能力,通过学习能力,快速学习掌握新技术;
- 中间一层就是解决问题的能力,充分利用学到的技术,去发现问题、分析问题和解决问题;
- 最上一层就是影响力,是核心竞争力的综合体现。
学习能力、解决问题能力和影响力一起构成了软件工程师的核心竞争力,就像下面这个金字塔图一样,我称之为软件工程师竞争力金字塔。
<img src="https://static001.geekbang.org/resource/image/f0/3b/f0c3d80880a2b2ff00af689d8338d53b.jpg" alt="">
但必须要注意,这三层缺一不可,你不能光去追求影响力而不踏踏实实学习和做事,也不能光去做事而不学习。必须要踏实地、一层层地打好基础,这样才能让你的竞争力是持久的,而不是昙花一现。
## 软件工程师竞争力金字塔的意义
如果你是软件工程师,了解了软件工程师竞争力金字塔,你就可以自下而上,更有针对性地培养、提高软件工程师的核心竞争力。
不是把自己绑死在一门技术或者一个框架上,而是训练自己的学习能力,让自己可以拥有快速学习掌握新技术的能力。
日常工作不仅仅是实现一个个的功能,做一个个的项目,而是在这个过程中,去锻炼和提升你发现问题、分析问题和解决问题的能力。这样才能使你的工作经验最大化,而不是机械重复没有积累。
在工作中,不仅是把事情做成,还要把事情做好;不仅是自己成长,还要帮助其他人成长;最大化的利用好所在平台和行业的经历,转变成你的经验和影响力。工作之外,也多分享,打造自己的品牌。
这样你就可以一点点搭建出来属于你的竞争力金字塔,构建出自己的核心竞争力。
如果你是要招聘优秀的软件工程师,了解了软件工程师竞争力金字塔,你可以自上而下,更容易筛选出来优秀的软件工程师。
首先你可以通过内部推荐,优先找那些口碑好,做事情认真靠谱的软件工程师。然后你可以考察他解决问题的能力。比如说你可以问他:
- “项目中遇到过的哪些复杂的问题?”
- “是怎么样去解决的?”
通过对问题的答复,再深入问一些细节问题,例如:“你当时是怎么考虑安全性问题的?”“如果访问量增加一倍,会有什么影响?”等等。你就可以对他解决问题的能力有个初步了解了。
最后你还可以考察一下学习能力。比如你可以问他:
- “最喜欢的编程语言是什么?”
- “你是如何学习这门语言的?”
- “如果让你学一门新的语言,你打算怎么学?”
这样你也可以对他的学习能力有一个大致了解。
## 总结
由于篇幅限制,我将文章分成了上下两篇。上篇主要分析了软件工程师的核心竞争力,也就是学习能力、解决问题能力和影响力。我会在下篇中,为你讲具体怎么做,才能有效提升软件工程师的核心竞争力。
学习能力,就是你学习并掌握一门技术、框架和工具的能力。好的学习能力,能帮助软件工程师在技术日新月异的今天,快速跟上技术发展的步伐。
解决问题的能力,就是发现问题、分析问题和解决问题的能力。解决问题的能力,是软件工程师非常重要的能力,帮助软件工程师在日常工作中高效完成工作,创造价值。影响力则是软件工程师价值的综合体现。
如果你是软件工程师,那么就需要自下而上,训练自己的学习能力,积累解决问题的经验,工作的过程中形成影响力,一点点去构建自己的核心竞争力。如果你要招聘或筛选优秀的软件工程师,则需要自上而下,选择那些口碑好有影响力的,能帮你解决问题的,有很好学习能力的人。
## 课后思考
你对于软件工程师的核心竞争力是怎么看的?有哪些是你认为有价值的能力?欢迎在留言区与我分享讨论。
感谢阅读,如果你觉得这篇文章对你有一些启发,也欢迎把它分享给你的朋友。

View File

@@ -0,0 +1,142 @@
<audio id="audio" title="28 | 软件工程师的核心竞争力是什么?(下)" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/0f/b6/0f92da314bf5f531806052a8e63c1db6.mp3"></audio>
你好,我是宝玉。在上一篇中,我们讨论了什么是软件工程师的核心竞争力,也就是学习能力、解决问题的能力和影响力。
今天我就来跟你谈一谈,如何提升软件工程师的核心竞争力,也就是说,如何分别提升你的学习能力、解决问题能力和影响力。
## 如何提升学习能力?
学习能力是软件工程师最基础的能力,学习能力直接决定了你掌握技术的速度。现实中,有的程序员掌握新技术就是比别人要快,似乎有什么秘籍,可以让他们快速学习和掌握新技术。真有这样的秘籍吗?如果有,那是什么样的内容呢?
前不久我要写一个家谱的微信小程序,要实现列表、检索等功能。此前我没有任何关于小程序的开发经验,于是我粗略地看了下开发文档,搭建了开发环境,下载了几个示例程序,前后花了一天时间完成了一个不算简单的小程序开发。
为什么我能在一天时间就可以学习掌握小程序的开发呢?其实只是因为我已经构建了自己的开发知识体系,而小程序开发所需要的知识,绝大部分在我的知识体系里面已经有了存储。这些部分我就不需要重新再学习,我只要去学习小程序所独有的知识就好了,而这部分知识只有很小比例,所以很快就可以掌握。
那么你可能会问,怎样可以构建自己的知识体系呢?
- **首先需要在一个技术领域深耕**
每个人精力其实很有限的,一开始专注在一个技术领域容易在短时间取得成绩,同时也相当于建立起了最初的知识体系,在未来的知识森林里种下的第一棵大树,这样当你开始学习新的技术的时候,已有的知识就可以直接借用,相当于这棵大树可以帮助新的知识树的成长提供很好的养分,快速培养出新的大树。
如果一开始就同时涉猎多个领域,每个领域的知识又没有掌握好,这样的知识是没法共享的,就相当于你种的只是一片知识的灌木,最终只能收获像灌木丛的知识体系。
**只有一个领域的知识你真正吃透,才能有效地共享到其他领域,构成一个知识领域的森林。**
我在毕业之后整整有6年时间是一直专注于Asp.Net技术领域让我能成为这个领域的专家也帮我构建了最基础的知识体系。所以在后来我去学iOS开发时发现像面向对象、网络协议、数据存储、MVC开发模式这些知识我就不需要再去学习因为我的知识体系已经有了这部分知识。
换个角度说如果我当时Asp.Net学的不够深入那么面向对象、数据存储、MVC 开发模式这些我还是要再学一遍自然也无法快速掌握iOS开发。
知识体系建立之初,确实是痛苦的,感觉什么都不懂,有很多要学习的。市面上有新技术出来也会觉得焦虑,觉得应该去学新的技术。但如果初期不能够专注在某个领域深入的话,你学了再多技术,结果也没有一门能深入,这就很难构建出有深度的知识树。
要在某一个领域的技术达到一定深度,通常需要三年以上的时间。当你熬过这个阶段,在一个技术领域取得了一定成就,不仅会收获你的知识树,还能收获技术上的自信,让你有信心在其他技术领域也同样取得成就。
- **然后往相近的领域逐步横向拓展**
当在一个技术领域达到一定深度后,可以开始横向扩展。最好是往相近的领域扩展,因为这样你之前的知识有很多是可以共享的,容易快速取得成绩。
这也是为什么我后来选择了前端因为对我来说前端跟我以前掌握的Asp.Net的经验是有很多重叠的我只需要去学习框架和工具那部分知识。
当然横向构建知识体系,也一样不是一个轻松的过程,因为以前你在某个领域取得的成就和经验,反过来也会成为一种阻力。因为以前你熟悉的知识,已经变成了你的舒适区,你会天然地不愿意走出舒适区,不愿意到挑战区或恐慌区去学习新的知识。
这其实就是我当初学React时候的感受我觉得jQuery已经用的很好了为什么要学这个我老想着用以前MVC的经验去套用React的编程模式反而更难理解。
但是,当你迈过去,掌握了新领域的知识,就会感觉整个知识体系一下子扩展了很大一块。相当于让你的知识体系,从一棵树,逐步变成了一个小树林,最终会成为一个森林。
快速掌握新技术的秘籍,就是要构建属于你的知识体系,让你在学习新知识时,能借用已有的知识,加快学习速度。
你可以现在思考一下你的知识体系是什么样子的,是一片灌木丛还是已经有大树了?如果只是一片灌木丛,你打算在哪个技术领域先打造你的知识树呢?
## 如何提高解决问题的能力?
解决问题的能力是软件工程师进阶的核心竞争力,你看现实中,那些解决问题能力强的程序员,遇到问题总是有办法,都能有条不紊地给解决了。
有一次我们组负责的一个网络服务出现异常大约1%的请求会出现异常导致服务报警,当时值班的同事正好是一个新手程序员,他也试着分析日志,但是没有找到明显的错误日志,完全不知道如何应对,只好让我帮忙。这个问题我以前也从来没遇到过,但我有一套应对这类问题的思维方式和逻辑。
我第一步就是回滚上一次的部署,看是否恢复正常,结果没效果。于是我再从日志找出所有有问题的请求,寻找规律,从中选取几个有问题的请求,去跟踪它们整个请求过程,结果在某一个路由环节发现指向到了一台错误的服务器,最终定位是某个路由程序出现的问题。
我们将这个问题反馈到相关组,问题马上就得以解决。然后我建议他在这个路由环节增加监控,这样以后再出问题就能第一时间报警通知。
为什么我有这样解决问题的能力呢?是因为我在多年的开发经验中,形成了一套解决问题的方法论,即使遇到没有解决过的问题,也能借助一套方法论去解决。
这其实很像我在专栏开头就提到的工程思维,遇到一个项目,哪怕不是软件项目,我也可以借鉴瀑布模型,用工程方法去解决。所以你要提高解决问题的能力,就要形成自己的一套解决问题的方法论。
在这里分享我解决问题的一套方法论,其实很简单,只有三步。
**第一步:明确问题**
解决问题,最重要的一步就是要明确问题是什么,这其实就跟做项目需要先做需求分析一样,搞清楚目标是什么,才能做到有的放矢。
同时这一步也要透过现象看本质,去明确问题背后是不是还有其他问题。就像我在前一篇文章中举例的抽奖项目,不能光看到功能需求,还需要看到安全上的需求;网络异常的问题,不能光想着应用程序错误,还要看看网络是不是有问题。
**第二步:拆分和定位问题**
前面我们学习架构思维的时候,也提到了,一个复杂的问题,只有经过拆分,才好找到本质的问题。
就像上面举的解决网络异常的例子,我首先拆分成程序问题和网络问题,通过回滚观察,我就可以基本上断定不是程序问题,那就说明是网络问题。然后对于网络问题,将整个请求过程拆分,最终就可以定位到有问题的环节。
**第三步:提出解决方案并总结**
发现并分析完问题后,找到解决方案是容易的,但很有必要总结一下。总结要做的就是两点:
- 下次有这种问题怎么解决,是不是可以做的更好?
- 这种问题是不是可以预防?如果可以,应该怎么做?
通过总结,就可以进一步提升解决问题的经验。如果你对于解决技术上的问题还没有总结出来自己的方法论,不妨可以先参考这套方法,一步步去发现问题,分析问题和解决问题。
尤其是在解决完问题后,再想一想如何预防以后类似问题的发生。**如果每次解决完问题,你还能提出一个预防问题发生的方案,一定会让大家印象深刻的。**
## 如何提升影响力?
刻意地去提升自己的影响力,是很多软件工程师忽略去做的事情。但影响力,却是程序员核心竞争力的最顶层,也是一个软件工程师能力的综合体现。培养影响力也是我职业生涯中受益良多的一件事。
其实当你意识到影响力是有价值有意义的事,怎么去做反而没那么难,比如这些方面可以去考虑。
- **在某个领域做出了足够牛的成绩**
有些程序员能在某一个技术领域做到一定深度做出了常人难以达到的成绩比如说PHP开发组核心成员的鸟哥惠新宸写Vue框架的尤雨溪前端的Winter。做到他们这样基本上就不用担心影响力的问题了。
要取得这样的成绩,要实力、要机缘、还要坚持。
- **做事情超出预期**
在软件项目中,你作为一个程序员,每个人都会对你有预期,项目经理希望你如期完成项目,产品经理希望你完成需求,其他程序员希望你代码质量好。如果你是初级程序员,则大家期望你代码不要有太多问题就好,如果你是高级程序员,大家不仅期望你要写好程序,还要能带带新人。
如果你做事情的结果能超出预期,就会让人对你刮目相看,进而会形成口碑。就像我前面举的例子,如果你解决完一个问题,还能想到怎么预防问题再次发生的方案,这通常就超出他人对你的预期了。
要让自己的表现超出其他人的预期,除了要付出很多努力外,也要学会管理好其他人的预期,我以前有写过一篇文章《[程序员也可以懂一点期望值管理](http://zhuanlan.zhihu.com/p/20046507)》,谈如何去了解别人对你的期望,降低别人对你的期望,最后做出高于期望的事。
- **帮助其他人就是在帮助自己**
我有遇到过很多程序员不愿意教别人,认为教会徒弟饿死师傅。其实这完全搞反了,帮助别人、教别人收获最大的恰恰是自己。
程序员的经验,很大部分来自于解决问题时积累的经验。你自己在工作中遇到的问题其实是很有限的,但如果帮助其他人解决问题,相当于增加了你解决问题的样本,这些样本能帮助放大你的工作经验。
帮助其他人,还是形成影响力最简单有效的途径。就像我微软最有价值的称号,就是因为我当年在社区热心组织活动,网上帮助其他人解决技术问题而获得的。
- **分享就是学习和打造影响力**
刘未鹏老师写过的一篇博客《[为什么你应该(从现在开始就)写博客](http://mindhacks.cn/2009/02/15/why-you-should-start-blogging-now/)》影响了很多人,这是一篇值得反复阅读的好文章,讲了写博客的好处,例如交朋友、帮助思考、学习。
我的观点也类似,包括在“[学习路径](https://time.geekbang.org/column/article/82697)”中,我就建议大家可以通过分享,在教中学。其实,在分享形式上也可以更多样化,除了写博客还有很多其他方式,比如公司内部的讲座就是很好的分享途径。
我在内部也会经常做培训分享,也会写博客分享技术经验,每一次分享都会帮助我学习巩固很多知识点,也是在帮我打造自己的影响力。
写东西这方面我做的不够好,写博客断断续续的,但还是在坚持,也收获很多,包括《软件工程之美》专栏的诞生,其实也是因为极客时间看到我写过的一篇《记在美国的一次校园招聘》,所以才邀请我开的专栏。
希望你也能思考一下影响力这个问题,想想你还可以在哪些方面,用哪些方法去打造你的影响力,和学习能力、解决问题能力一起,形成你的核心竞争力。
## 总结
最后简单总结一下。软件工程师的核心竞争力,体现在学习能力、解决问题能力和影响力三个方面。
要提升学习能力,要构建好自己的知识体系,首先需要在一个技术领域深耕然后往相近的领域逐步横向拓展。
要提升解决问题的能力,要形成自己的方法论,去发现问题,分析问题和解决问题。
要提升自己的影响力,可以在一个领域深入打造自己独特的有价值的能力,让自己做事情能超出别人的预期,同时乐于分享和帮助他人。
## 课后思考
你的知识体系是什么样子的,你是怎么打造你的知识体系的?你自己或者你周围哪些擅长解决问题的软件工程师都有哪些独特的方法?你是怎么提升影响力的?欢迎在留言区与我分享讨论。
感谢阅读,如果你觉得这篇文章对你有一些启发,也欢迎把它分享给你的朋友。

View File

@@ -0,0 +1,208 @@
<audio id="audio" title="29 | 自动化测试如何把Bug杀死在摇篮里" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/9f/3f/9f65a5e004df8246b6b2aec58b18f73f.mp3"></audio>
你好我是宝玉。前不久我所在项目组完成了一个大项目把一个网站前端的jQuery代码全部换成React代码涉及改动的项目源代码文件有一百多个变动的代码有几千行最终上线后出乎意料的稳定只有几个不算太严重的Bug。
能做到重构还这么稳定,是因为我们技术水平特别高吗?当然不是。还是同样一组人,一年前做一个比这还简单的项目,上线后却跟噩梦一样,频繁出各种问题,导致上线后不停打补丁,一段时间才逐步稳定下来。
这其中的差别,只是因为在那次失败的上线后,我们总结经验,逐步增加了自动化测试代码的覆盖率。等我们再做大的重构时,这些自动化测试代码就能帮助我们发现很多问题。
当我们确保每一个以前写好的测试用例能正常通过后就相当于把Bug杀死在摇篮里再配合少量的人工手动测试就可以保证上线后的系统是稳定的。
其实对于自动化测试,我们专栏已经多次提及,它是敏捷开发能快速迭代很重要的质量保障,是持续交付的基础前提。
所以今天我将带你一起了解什么是自动化测试,以及如何在项目中应用自动化测试。
## 为什么自动化测试能保障质量?
自动化测试并不难理解,你可以想想人是怎么做测试的:首先根据需求写成测试用例,设计好输入值和期望的输出,然后按照测试用例一个个操作,输入一些内容,做一些操作,观察是不是和期望的结果一致,一致就通过,不一致就不通过。
自动化测试,就是把这些操作,用程序脚本来完成的,本质上还是要输入和操作,要检查输出是不是和期望值一致。只要能按照测试用例操作和检查,其实是人来做还是程序来做,结果都是一样的。
不过,自动化测试有一个手工测试没有的优势,那就是可以直接绕过界面,对程序内部的类、函数进行直接测试,如果有一定量的自动化测试代码覆盖,相对来说软件质量是更有保障的。
而且一旦实现了自动化每测试一次的成本其实大幅降低了的几百个测试用例可能几分钟就跑完了。尤其是每次修改完代码合并到主干之前把这几百个测试用例跑一遍可以有效地预防“修复一个Bug而产生新Bug”的情况发生。
但现阶段,自动化测试还是不能完全代替手工测试的,有些测试,自动化测试成本比手工测试成本要高,比如说测试界面布局、颜色等,还是需要一定量的手工测试配合。
## 有哪些类型的自动化测试?
现在说到自动化测试已经有很多的概念除了大家熟悉的单元测试还有像集成测试、UI测试、端到端测试、契约测试、组件测试等。而很多时候同一个名字还有不同的解读很容易混淆。
在对自动化测试类型的定义方面Google的分类方法我觉得比较科学根据数据做出决策而不仅仅是依靠直觉或无法衡量和评估的内容。Google将自动化测试分成了三大类小型测试、中型测试和大型测试。
假设我们有一个网站是基于三层架构如下图所示业务逻辑层的类叫UserService类数据访问层的类叫UserDA我们将以用户注册的功能来说明几种测试的区别 。
<img src="https://static001.geekbang.org/resource/image/9b/2b/9b9fbf93cf03fa33b381ee144a26a92b.png" alt="">
#### 小型测试
小型测试是为了验证一个代码单元的功能,例如针对一个函数或者一个类的测试。我们平时说的单元测试就是一个典型的小型测试。
比如说UserService这个类有一个注册用户的函数现在要对它写一个单元测试代码那么看起来就像下面这样
<img src="https://static001.geekbang.org/resource/image/02/61/02aa850792c8fbb3c6bc626b9c944161.png" alt="">
通过这样的测试代码就可以清楚的知道UserService类的create这个函数是不是能正常工作。
小型测试的运行不需要依赖外部。如果有外部服务比如文件操作、网络服务、数据库等必须使用一个模拟的外部服务。比如上面例子中我们就使用了FakeUserDA这个模拟的数据库访问类实际上它不会访问真实的数据库。这样可以保证小型测试在很短时间内就可以完成。
<img src="https://static001.geekbang.org/resource/image/43/ee/43ce39715dddae2e51728d13714c31ee.png" alt="" title="小型测试图片来源《Google软件测试之道》">
#### 中型测试
中型测试是验证两个或多个模块应用之间的交互,通常也叫集成测试。
如果说要对用户注册的功能写集成测试那么就会同时测试业务逻辑层的UserService类和数据访问层的UserDA类。如下所示
<img src="https://static001.geekbang.org/resource/image/7d/e7/7dcb05ac985cdc8b554c9ba3b5691ee7.png" alt="">
对于中型测试,可以使用外部服务(比如文件操作、网络服务、数据库等),可以模拟也可以使用真实的服务。比如上面这个例子,就是真实的数据库访问类,但是用的内存数据库,这样可以提高性能,也可以减少依赖。
至于中型测试要不要使用模拟的服务,有个简单的标准,就是看能不能在单机情况下完成集成测试,如果可以就不需要模拟,如果不能,则要模拟避免外部依赖。
<img src="https://static001.geekbang.org/resource/image/cf/ab/cfb41a9f0a490a3e1aa54555e4d35eab.png" alt="" title="中型测试图片来源《Google软件测试之道》">
#### 大型测试
大型测试则是从较高的层次运行,把系统作为一个整体验证。会验证系统的一个或者所有子系统,从前端一直到后端数据存储。大型测试也叫系统测试或者端对端测试。
如果说要对用户注册写一个端对端测试的例子,那么看起来会像这样:
<img src="https://static001.geekbang.org/resource/image/73/b0/736f1fc4609ba5d5c408b243b30834b0.png" alt="">
对于大型测试通常会直接使用外部服务比如文件操作、网络服务、数据库等而不会去模拟。比如上面这个例子就是直接访问测试环境的地址通过测试库提供的API操作浏览器界面输入测试的用户名密码点击注册按钮最后检查输出的结果是不是符合预期。
<img src="https://static001.geekbang.org/resource/image/30/af/30ab7a154bc2324f1d4b858e36ad03af.png" alt="" title="大型测试图片来源《Google软件测试之道》">
#### 区分测试类型的依据是什么?
以上就是主要的自动测试类型了。捎带着补充一个测试类型,那就是契约测试,这个测试最近出现的频率比较高,主要是针对微服务的。其实就是让微服务在测试时,不需要依赖于引用的外部的微服务,在本地就可以模拟运行,同时又可以保证外部微服务的接口更新时,本地模拟的接口(契约)也能同步更新。对契约服务更多的说明可以参考这篇文章:《 [聊一聊契约测试](http://insights.thoughtworks.cn/about-contract-test/) 》
那么契约测试,属于大型测试还是中型测试呢?
Google针对这几种测试类型列了一张表根据数据给出了明确区分
[<img src="https://static001.geekbang.org/resource/image/a7/bd/a72fcd3b3f358e4512fa5694ad526dbd.png" alt="" title="图片来源Google Testing Blog">](http://testing.googleblog.com/2010/12/test-sizes.html)
结合上面的表格其实就很好区分了:
- 小型测试,没有外部服务的依赖,都是要模拟的;
- 中型测试,所有的测试几乎都不需要依赖其他服务器的资源,如果有涉及其他机器的服务,则本地模拟,这样本机就可以完成测试;
- 大型测试,几乎不模拟,直接访问相关的外部服务。
所以现在你应该就知道契约测试,也是中型测试的一种了,因为它不需要依赖外部服务,本机就可以完成测试。
为什么中型测试这么看重“能单机运行”这一点呢?因为这样才方便在持续集成上跑中型测试,不用担心外部服务不稳定而导致测试失败的问题。
上面的表中还反映出一个事实:**越是小型测试,执行速度越快,越是大型测试,执行速度越慢。**通常一个项目的小型测试,不超过一分钟就能全部跑完,一个中型测试,包括一些环境准备的时间,可能要几分钟甚至更久,而大型测试就更久了。
**另外越是大型测试,写起来的成本也相应的会更高,所以一般项目中,小型测试最多,中型测试次之,大型测试最少。**就像下面这张金字塔图一样。所以我们也常用测试金字塔来区分不同类型的测试粒度。
[<img src="https://static001.geekbang.org/resource/image/61/cf/616bb4cdb13884dde562b10568ba77cf.png" alt="" title="测试金字塔,图片来源: TestPyramid"> ](http://martinfowler.com/bliki/TestPyramid.html)
如果你对测试类型很感兴趣,可以参考《[测试金字塔实战](http://insights.thoughtworks.cn/practical-test-pyramid/)》这篇文章作为补充。
#### 怎么写好自动化测试代码?
很多人认为写自动化测试很复杂,其实测试代码其实写起来不难,包含四部分内容即可,也就是:准备、执行、断言和清理,我再把第一段代码示例贴一下:
<img src="https://static001.geekbang.org/resource/image/02/61/02aa850792c8fbb3c6bc626b9c944161.png" alt="">
第一步就是准备,例如创建实例,创建模拟对象;第二步就是执行要测试的方法,传入要测试的参数;第三步断言就是检查结果对不对,如果不对测试会失败;第四步还要对数据进行清理,这样不影响下一次测试。
上面还有几个测试代码示例,都是这样的四部分内容。
这是针对写一个自动化测试的代码结构。对于同一个功能,通常需要写几个自动化测试才完整。
一个完整的自动化测试要包括三个部分的测试:
- **验证功能是不是正确:**例如说输入正确的用户名和密码,要能正常注册账号;
- **覆盖边界条件:** 比如说如果用户名或密码为空,应该不允许注册成功;
- **异常和错误处理:**比如说使用一个已经用过的用户名,应该提示用户名被使用。
<img src="https://static001.geekbang.org/resource/image/05/a8/055004435b9bcd81cfa13050a8f42aa8.png" alt="">
所以你看,写一个测试代码并没有你想的那么复杂,那还有什么理由不去写测试呢?
## 如何为你的项目实施自动化测试?
现在你了解了有哪些类型的测试,如何写自动化测试代码,也许迫不及待想在项目中实施自动化测试。
#### 选择好自动化测试框架
要写好自动化测试代码,首先要找对自动测试化框架。不同的语言,不同的平台,测试的框架都不一样。好在现在搜索引擎很方便,根据“你的语言+自动测试框架”的关键字,就能找到很多的结果。这里我也帮你找了一些,供参考。
- Web前端
[Jest](http://github.com/facebook/jest) Facebook的前端测试框架<br>
[Mocha](http://mochajs.org)历史悠久的一个JS测试框架<br>
[Nighwatch](http://nightwatchjs.org): 一个API很简单但是功能很强大可以直接操作浏览器的自动测试框架。
- iOS开发
可以参考这篇文章《[iOS自动化测试框架对比](http://www.jianshu.com/p/047035416095)》。
- 安卓开发
可以参考这篇文章《[Android 谈谈自动化测试](http://juejin.im/entry/59ec4a8f6fb9a0450908a5fd)》。
#### 在持续集成环境上跑你的自动化测试
选好自动化测试框架后,你的自动化测试代码,其中的小型测试和中型测试,最好要能在持续集成环境上运行起来。
**让自动化测试在持续集成上运行非常重要,只有这样才能最大化地发挥自动化测试的作用。**
因为持续集成会强制测试通过才能合并代码在合并代码之前就能知道测试是不是都通过了可以帮助程序员获得最直观的反馈知道哪里可能存在问题这样才能真正做到防患于未然把Bug杀死在摇篮里。
下图描述的就是自动测试配合持续集成的一个标准流程:
- 在提交代码前,先本地跑一遍单元测试,这个过程很快的,失败了需要继续修改;
- 单元测试成功后就可以提交到源代码管理中心,提交后持续集成服务会自动运行完整的自动化测试,不仅包括小型测试,还有中型测试;
- 通过所有的测试后,就可以合并到主分支,如果失败,需要本地修改后再次提交,直到通过所有的测试为止。
[<img src="https://static001.geekbang.org/resource/image/7b/38/7bbc58d82864974ff2f9ec31347fa538.png" alt="" title="图片来源Microservice Testing: Unit Tests">](http://medium.com/@nathankpeck/microservice-testing-unit-tests-d795194fe14e)
#### 新项目和老项目的不同策略
如果是新项目那么可以在一开始就保持一定的自动化测试代码的覆盖率你甚至还可以试试测试驱动TDD的开发模式也就是先写测试代码再写实现代码保证测试通过最后对代码进行重构。
<img src="https://static001.geekbang.org/resource/image/67/66/67f2886f7dee6f24e5a833e6b4c94f66.png" alt="" title="图片来源:郑晔 《10x程序员工作法》专栏">
如果是老项目,短期内要让自动化测试代码有覆盖是有难度的,可以先把主要的功能场景的中型测试写起来,这样可以保证这些主要功能不会轻易出问题。
后面在维护的过程中:
- 增加新功能的时候,同步对新功能增加自动化测试代码;
- 修复Bug的时候针对Bug补写自动化测试代码。
这样一点一点,把自动化测试代码覆盖率加上去。
#### 如果时间紧任务重,来不及写自动化测试怎么办?
确实遇到时间紧的情况我建议你要优先保证中型测试代码的覆盖因为这样至少可以保证主要的用户使用场景是正常的。然后把来不及完成的部分创建一个Ticket放到任务跟踪系统里面后面补上。
## 总结
今天我带你一起学习了关于自动化测试有关的知识。自动化测试,分为三类:
- 小型测试,主要针对函数或者类进行验证,不调用外部服务,执行速度快;
- 中型测试,主要验证两个或多个模块应用之间的交互,可能会调用外部服务,尽可能让所有测试能在本机即可完成,执行速度比较快;
- 大型测试,对服务整体进行验证,执行速度慢。
写好单元测试代码,基本结构就是:准备、执行、断言和清理;基本原则就是:
- 要验证正确性;
- 覆盖边界条件;
- 验证是否有异常和错误的处理。
自动化测试,一定要配合好持续集成,才能最大化发挥其效用。
对于自动化测试的实施,开头是最难的,因为需要花时间选择自动化测试框架,需要针对自动化测试框架搭建环境,甚至要去搭建持续集成环境。但搭建持续集成和搭建自动化测试环境,并且保证持续更新维护自动测试代码,这个技术投资,一定是你在项目中最有价值的投资之一。
搭建持续集成环境和集成自动化测试框架的事情,要作为一个正式的项目任务去做,当作一个很重要的任务去推进。
## 课后思考
你所在项目中,自动化测试代码覆盖如何?保持高覆盖率的主要阻力或者障碍是什么?打算怎么改善项目中自动化测试代码的覆盖?欢迎在留言区与我分享讨论。
感谢阅读,如果你觉得这篇文章对你有一些启发,也欢迎把它分享给你的朋友。

View File

@@ -0,0 +1,256 @@
<audio id="audio" title="30 | 用好源代码管理工具,让你的协作更高效" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/ac/17/acd3b39473f8843cfafc3886d98d1817.mp3"></audio>
你好我是宝玉。在今天源代码管理工具在软件项目中已经是标准配置了几乎每个软件项目都会应用到可以说是最基础的项目开发工具。选择也很多可以自己搭建源代码管理服务也可以直接用网上托管的服务例如GitHub、GitLab、BitBucket等。
但同样是应用源代码管理工具,为什么有的团队就能做到代码质量高,随时能发布新版本,高效开发?而有的团队却不能做到高效开发,拿到的代码也不稳定,合并时冲突很多?
今天,我将带你了解一下源代码管理工具,以及如何才能应用好源代码管理工具,以保证代码质量稳定,协作高效。
## 源代码管理工具发展简史
源代码管理工具也叫版本控制系统,是保存文件多个版本的一种机制。每一次有人提交了修改,这个修改历史都会被版本控制系统记录下来。如下图所示,每一次对内容的修改,都会形成一个当前项目完整内容的快照。
[<img src="https://static001.geekbang.org/resource/image/90/5f/90178c04135e72aecf2bdd262bbf915f.png" alt="" title="图片来源:《什么是版本控制?》">](http://www.git-tower.com/learn/git/ebook/cn/command-line/basics/what-is-version-control#start)
源代码管理工具从诞生到现在已经有40多年的历史了经历了四个阶段。
#### 没有源代码管理工具的时代
早些年开发软件可没有我们这么幸运在1972年之前都没有任何工具可以帮助我们做源代码管理。
这就意味着,当你开发时,必须要告知团队里的其他人,你正在对哪些文件进行编辑,好让他们不要操作相同的文件。当你花了很长时间完成你的修改后,可能这些文件早已经被团队里的其他开发成员修改或者删除了。
除了协作的问题,还有一个问题就是版本问题。没有源代码管理,你得经常性对项目的文件保存备份,很麻烦,而且还是一样有不少问题:
- 很难知道做了哪些修改,你可能需要挨个目录去查看文件修改时间;
- 对版本命名是一个很麻烦的事情,每次备份都得有一个名字;
- 很难知道两次备份之间,做了哪些修改。
#### 本地版本管理
最早的版本控制系统是SCCSSource Code Control System诞生于1972年它实现了对单个文件保留多个版本这就意味着你可以看到每一个文件的修改历史了。
后来又有了RCS Revision Control System它具有更好的文件比较算法通过登录同一台中央大型机可以实现每个人签出自己的拷贝。
但这个阶段只能本机使用,而且一次只能修改一个文件,无法满足好多人协作的问题。
#### 集中式版本管理
1986年问世的CVSConcurrent Versions System是第一个采用集中式的服务器来进行版本库的管理工作所有文件和版本历史都放在服务端每个用户通过客户端获取最新的代码可以多个人编辑一个文件并且能提交到服务器合并在一起。
再后来的SVNSubversion则对CVS进行了很多优化比如支持文件改名、移动、全局版本号等这些优化很大部分程度上解决了CVS存在的一些缺陷所以在2000年后逐步取代了CVS成为主流的源代码管理工具。
[<img src="https://static001.geekbang.org/resource/image/52/72/52f5b217fe0cfb88a24918d755ffb772.png" alt="" title="图片来源How Version Control Systems Work">](http://code.snipcademy.com/tutorials/git/introduction/how-version-control-works)
不过,这类集中式源代码管理工具,过于依赖服务器,如果服务器出问题或者连不上,就没法用了,如果服务器损坏,所有的版本历史也会丢失。
#### 分布式版本管理
分布式版本管理工具的典型代表就是Git分布式版本控制系统的整个代码库的副本都可以存储在用户的本地系统上这样文件和版本控制操作变得非常容易离线也可以操作如果主存储库关闭或者删除可以很容易从本地存储库恢复。
现在Git已经逐步替代了SVN、CVS等源代码管理工具成为最主流的源代码管理工具。
Git的主要问题是学习成本要稍微高一点要花点时间理解它的工作原理和记住主要的命令。
[<img src="https://static001.geekbang.org/resource/image/60/02/603379637ba76d67ddcc21f1d515b202.png" alt="" title="图片来源How Version Control Systems Work">](http://code.snipcademy.com/tutorials/git/introduction/how-version-control-works)
## 如何选择合适的源代码管理系统
现在源代码管理系统已经有很多的选择,你可以选择网上托管的代码管理服务,或者是自己搭建。
自己搭建的好处就是可以有更多的控制,但是需要有自己的服务器,自己搭建环境,还要后续的维护。用网上的托管平台,可以减少运维成本,功能也很强大,但对平台有一定的依赖。
我的建议是如果项目规模不大,隐私要求不高,完全没必要自己搭建,可以直接选择网上的托管平台。这样可以节约很多时间成本,而且还可以方便和一些第三方服务,例如持续集成等进行整合。
如果希望对源代码管理有更多控制,也能接受运行维护上的投入,就可以选择自己搭建。
#### 自己搭建源代码管理系统
- Git
Git本身是开源免费的所以每个人都可以搭建自己的Git Server具体的操作执行我就不在此处展开了网上有很多教程。例如《 [服务器上的 Git - 在服务器上搭建 Git](http://git-scm.com/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E5%9C%A8%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E6%90%AD%E5%BB%BA-Git) 》《[搭建自己的 Git 服务器](http://www.aneasystone.com/archives/2018/12/build-your-own-git-server.html)》
- GitLab
Git自带的Server默认是没有Web界面进行管理的只能用命令行操作交互这在操作上有很多不便利性尤其是不方便做代码审查所以可以安装[GitLab的社区版本](http://about.gitlab.com/install/)开源免费的有Web操作界面可以像GitHub一样提交Pull Request并且和CI 持续集成系统例如GitLab CI、Jenkins都有很好的集成。
网上也有很多安装教程:《[在自己的服务器上部署 GitLab 社区版](http://www.cnblogs.com/restran/p/4063880.html)》《[GitLab的安装及使用教程](http://yq.aliyun.com/articles/74395)》。
- Gerrit
[Gerrit](http://www.gerritcodereview.com)是由Google开发的用于管理Google Android项目源代码的一个系统。它支持Git和代码评审。参考教程《[Gerrit代码审核服务器搭建全过程](http://www.jianshu.com/p/5ae7f5978814)》
#### 网上的代码托管平台
- GitHub
[GitHub](http://github.com)现在已经是全球最流行的代码托管平台功能强大和第三方服务集成非常好。而且私有的代码库如果不超过3个人都是免费的我自己很多个人项目就都是放在GitHub上托管。
[GitHub](http://about.gitlab.com)的Web UI非常强尤其是代码浏览和审查在网站上就可以提交Pull Request和进行代码审查。不过GitHub不提供CI服务需要和第三方CI服务集成。
- GitLab
[GitLab](http://about.gitlab.com)的网上托管服务很多地方和GitHub都很类似但是价格更便宜。例如免费用户可以支持无限的私有项目也内置了CI的支持。
- Coding
[Coding](http://coding.net)是国内一个不错的代码托管平台5人以下的私有库免费内置了CI支持同时还有项目管理工具支持。
其他的服务还有像:[码云](http://gitee.com)、[阿里云 Code](http://crp.aliyun.com)、[百度效率云](http://xiaolvyun.baidu.com)、[腾讯Git代码托管](http://cloud.tencent.com/product/tgit)、[华为云 CodeHub](http://www.huaweicloud.com/product/codehub.html),这里就不一一介绍了。
## 如何用好源代码管理工具?
用好源代码管理工具,有三个简单可行的原则:
#### 原则一:要频繁的提交
很多开发人员不愿意轻易提交代码到源代码管理中心,喜欢“憋个大招”,本地做了大量修改,希望代码能“完美”。但这样做却没能享受到频繁提交带来的好处。
频繁提交这意味着你每次提交的代码变更是比较少的便于Code Review同时如果出现问题也可以迅速定位或者直接回滚。
频繁地提交,也让团队成员可以及时同步最新代码,不至于在最后合并时,产生有大量的合并冲突。
**频繁提交,不意味着提交不完整的内容,而是将要提交的内容分拆,并且保证完整性。**
比如说,有一个涉及前后端的功能,可以拆分成前端和后端两次提交,各自有独立的代码和测试;比如说你开发新功能的时候发现有代码需要重构,那么对于重构的代码单独一次提交,不要和新功能的代码提交放一起。
#### 原则二:每次提交后要跑自动化测试
在前面章节我们学习了自动化测试和持续集成,自动化测试是非常有效的质量保障手段,而持续集成工具,可以让每次提交代码后,能自动地运行相应的自动化测试代码,有效保障提交代码的质量。
源代码管理的第二个原则,就是每次提交,必须要运行自动化测试代码,如果测试不通过就不能合并,要对问题进行甄别和修复,确保提交的代码质量是没问题的。
#### 原则三:提交的代码要有人审查
代码审查是自动化测试之外一种非常行之有效的提高质量的手段通过代码审查可以发现代码中潜在的问题。通过代码审查也可以加强团队的技术交流让水平高的开发人员Review可以帮助提升整体代码水平Review高水平的代码也是一种非常有效的学习方法。
**怎么做好代码审查呢?**
我的经验是,在审查别人代码的时候,先了解清楚这个提交的代码要解决的是什么问题,想象一下如果是自己来写这个代码会怎么写。这样在审查的时候,就能发现一些和自己不一样的地方,别人好的地方我们可以学习,不对的地方应该指出。
对于审查出来的问题,可以分成三个类型:
- 问题:如果对代码有不清楚的地方,可以作为问题提出,进一步澄清确认;
- 建议:原来的实现没有太大问题,但是可以有不同的或者更好的实现;
- 阻塞:代码有明显问题,必须要修改。
这样对于被审查的人可以针对你的问题进行针对性修改。
这三个原则很简单,可以有效提升代码质量,减少合并冲突,及时发现问题,从而让你的协作更高效。
## 我该选择什么样的开发流程?
现在基于源代码管理有三种主要的开发流程:
- [Git flow](http://nvie.com/posts/a-successful-git-branching-model/)
- [GitHub flow](http://guides.github.com/introduction/flow/)
- [GitLab flow](http://docs.gitlab.com/ee/workflow/gitlab_flow.html)
阮一峰老师有一篇文章《[Git 工作流程](http://www.ruanyifeng.com/blog/2015/12/git-workflow.html)》对它们有详细介绍。在这里我重点介绍一下GitHub flow因为它简单易懂另外它也对上面我提到的三个原则有很好的支持。
当然我并不是说你一定要选择GitHub flow而是在理解它后可以基于它的流程衍生出适合自己项目特点的开发流程。
#### GitHub开发流程
GitHub开发流程的关键在于两点
1. 有一个稳定的分支例如master
1. 每次创建新功能或者修复Bug必须创建一个分支。最后通过代码审查和自动化测试后才能合并回稳定分支。
通过这样的开发流程,就相当于把自动化测试和代码审查作为一种强制性要求了,所有的修改必须要通过代码审查和自动化测试通过才能合并,从而保证有一个可以随时部署发布的稳定分支。
我们具体看看基于GitHub flow是如何开发的。
- **第一步:创建一个分支**
分支是Git中的核心概念整个GitHub流程都是基于分支展开的master分支是要一直保持稳定的不能直接在master上开发。
无论你是要开发一个新功能还是修复一个Bug第一件事永远是从master创建一个分支出来。
[<img src="https://static001.geekbang.org/resource/image/ce/1a/ce1be843617e669e47f5bd6f2c2b801a.png" alt="" title="图片来源GitHub网站截图">](http://guides.github.com/introduction/flow/)
- **第二步:提交更新**
当创建好分支后,就可以基于分支开始工作了,这时候就可以按照前面建议的原则,频繁的提交更新。注意每次提交的时候,要加上说明性的信息,让其他人明确知道你这次提交的内容是什么,如果开发过程中,发现错误了,还可以随时回滚之前的更改。
[<img src="https://static001.geekbang.org/resource/image/6f/07/6f54abdcfa102a13eda2bd5329e08707.png" alt="" title="图片来源GitHub网站截图">](http://guides.github.com/introduction/flow/)
- **第三步创建一个Pull Request**
在开发完成后创建一个Pull Request合并请求简称PRGitLab中叫Merge Request创建PR时通常要附上描述性的信息关联上相应的Ticket连接让其他人知道你这个PR要完成什么任务。创建好PR后其他人就可以直观的看到你所有的修改。
[<img src="https://static001.geekbang.org/resource/image/1a/d6/1a665275ab20b3fd3a7711db357271d6.png" alt="" title="图片来源GitHub网站截图">](http://guides.github.com/introduction/flow/)
- **第四步:讨论和代码审查**
当你的PR提交后团队的其他人就可以对PR中的代码修改进行评论。比如说代码风格不符合规范、缺少单元测试、或者很好没有问题。PR的主要目的就是为了方便大家做代码审查。
根据代码审查的结果你可能要做一些修改那么只要继续提交更新到这个分支就可以了提交更新后PR就会自动更新其他人可以基于你的更新进一步的讨论和审查直到通过代码审查。
[<img src="https://static001.geekbang.org/resource/image/9c/97/9c324020e64e963c5d47b4b51ea1fb97.png" alt="" title="图片来源GitHub网站截图">](http://guides.github.com/introduction/flow/)
- **第五步:部署测试**
在合并前,还需要把分支的修改进行测试。理论上来说,需要将修改的内容部署到测试环境测试,但这样效率太低了,所以通常的做法是借助持续集成工具,在每次提交代码后,就运行自动化测试代码,自动化测试代码全部通过后,就可以认为质量是可靠的。
这也意味着你需要让项目中的自动化测试代码保持一定的测试覆盖率,否则质量还是难以保障的。
[<img src="https://static001.geekbang.org/resource/image/13/5f/13236779ae4780cf55ccb3d3cda5065f.png" alt="" title="图片来源GitHub网站截图">](http://guides.github.com/introduction/flow)
- **第六步:合并**
当你的代码通过了代码审查和自动化测试就可以将代码合并到master分支了。合并后之前的分支就可以删除但你之前所有的提交记录在master都可以看到所以完全不用担心丢失历史版本记录。
[<img src="https://static001.geekbang.org/resource/image/0d/35/0da9251ea9b5a791a8b4ff536fee3035.png" alt="" title="图片来源GitHub网站截图">](http://guides.github.com/introduction/flow/)
以上就是GitHub开发流程的主要步骤通过分支开发新功能或者修复Bug强制通过代码审查和自动化测试才能合并master从而保证master的稳定。
#### GitHub开发流程的几个常见问题
基于这个流程我再补充几个常见问题:
- **怎么发布版本?**
要发布版本的话从master上创建一个Tag例如v1.0然后将Tag v1.0上的内容部署到生产环境。
- **怎么给线上版本打补丁?**
如果线上发布的版本例如v1.0发现Bug需要修复那么基于之前的Tag创建一个分支例如hotfix-v1.0-xxx出去在分支上修复然后提交PR代码审查和自动化测试通过后从分支上创建一个新的Tag 例如v1.0.1将新的Tag发布部署到生产环境最后再把修改合并回master。
- **如果我经常需要打补丁有没有比Tag更好的办法**
每次发布后可以创建一个发布版本的分支例如release-v1.0每次打补丁都直接从发布分支release-v1.0而不是master创建新的分支例如hotfix-release-v1.0-xxx修复后提交PR代码审查和自动化测试通过后合并回分支release-v1.0然后基于release-v1.0分支发布补丁。
最后将合并的PR借助git的cherry-pick命令再同步合并回master。
上面的例子其实主要是说明一下GitHub Flow只是一种基础的开发流程你完全可以基于GitHub Flow衍生出适合你自己项目特点的开发流程。
无论你基于哪一种开发流程,最好能做到这两点:
1. 有一个稳定的代码分支;
1. 在合并分支之前,对代码有审查,自动化测试要能通过。
这样你才能做到可以随时发布,质量稳定,高效协作。
## 总结
源代码管理工具也叫版本控制系统,是保存文件多个版本的一种机制,可以记录文件的历史版本。
用好源代码管理工具,有三个简单可行的原则:
- 原则一:要频繁的提交;
- 原则二:每次提交后要跑自动化测试;
- 原则三:提交的代码要有人审查。
基于源代码的开发流程,要保证好两点:
1. 有一个稳定的代码分支;
1. 在合并分支之前,对代码有审查,自动化测试要能通过。
用好源代码管理工具,设计好开发流程,保证好代码质量,你的协作才能更高效。
## 课后思考
你所在项目用的是什么源代码管理工具?你觉得有什么优缺点?你基于源代码管理工具的开发流程是怎么样的?有哪些可以改进的地方?欢迎在留言区与我分享讨论。
感谢阅读,如果你觉得这篇文章对你有一些启发,也欢迎把它分享给你的朋友。

View File

@@ -0,0 +1,322 @@
<audio id="audio" title="“一问一答”第3期 | 18个软件开发常见问题解决策略" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/c9/2c/c90f827ff19cd184316d6230f69d992c.mp3"></audio>
你好,我是宝玉。我们专栏已经完成了架构设计和开发这两个模块的学习。这两个模块都是和技术有很大关系,也是很多人关心的内容。
希望你通过对架构设计内容的学习,能控制好软件项目中技术复杂的问题。遇到技术选型,能心中有数,通过一个科学的过程去完成选型;对于项目中的技术债务,能及早识别,及早应对。
通过对开发模块的学习,可以帮助你在项目中搭建持续集成环境,推行自动化测试,改进基于源代码管理工具的开发流程。借助工具和流程,让你项目的开发质量更上一个台阶。
本篇继续分享同学们的精彩留言,这些问答和同学们的分享都是对专栏内容的最好补充,希望可以帮助你更好地学习和理解软件工程知识。
## 一问一答
No.1<br>
**一路向北:**每次看这些架构的思想方法的时候,总是和实际的应用没能很好的结合起来,原因是不是架构设计的实践不够?或者是对各种实现的分析和思考太少?
**宝玉:**我觉得不仅要有架构实践,还要有不同场景的实践。
举个例子来说,你平时做企业应用架构,没什么流量,没多少数据,复杂的地方都在业务逻辑,这时候你去看那些讲大数据、讲高并发的文章,很难带入到场景去。
还有就是一些架构,不自己搭一遍是很难了解其中的优缺点的,这也是另一个原因。
可以考虑有机会自己尝试,把看到的一些好的架构用一个原型程序搭一遍,造一点数据出来,用工具压测一下,这样会更有感觉。
和实际应用想结合的问题,一方面说明你现有的架构可能并没有什么大问题,没有那么迫切的需求要改造;另一方面可能还是因为缺少实践经验,心里没底,不知道真用上了有没有用。
No.2<br>
**小伟:**比较规范的文档有哪些,他们功能分别是什么?
**宝玉:**对于瀑布模型,每个阶段结束后,都有相应的验收文档,而敏捷开发则没有那么多硬性的要求,而是根据项目需要,写必要的文档。
有些团队对于测试阶段,会有测试用例文档、测试验收报告,发布前还会有部署文档、维护手册,但现在这类文档基本上被测试工具、部署脚本替代了,也没有什么存在必要。
我觉得项目中必要的文档,主要包括这几类:
<li>
<p>设计类文档<br>
这类文档主要用来说明、讨论需求设计、架构设计,可以用来了解、讨论和评审,以及记录后续结果。</p>
</li>
<li>
<p>说明类文档<br>
这类文档用来对规范、API、配置、操作等做说明便于规范和统一。</p>
</li>
<li>
<p>报告类文档<br>
对事情结果的报告和说明,比如说验收报告、故障报告、调研等。</p>
</li>
而这些文档的价值,在于帮助成员了解设计、参与讨论,记录项目成果,减少沟通成本。重要的不是文档多丰富,而是这些文档有没有价值,你能不能及时通过这些文档得到想要的答案。
所以你也可以对照一下你的项目中,现在的文档有哪些地方是可以简化的,哪些地方是要增强的。
比如说,概要设计/接口设计/详细设计是不是可以适当合并减轻文档工作PRD是不是够详细会不会引起歧义不容易理解要不要增加原型设计文档辅助
No.3<br>
**邢爱明:**项目团队的开发人员,基本都是从外包公司临时找的,水平参差不齐,稳定性差,因此技术选型更多考虑技术的普及度的和是否容易学习掌握,从这方面看基本不太可能选择比较小众、但在特定领域很高效的技术。
加上是企业内部管理的系统数据量和用户数量可控因此存在技术瓶颈的可能性很小综合下来看最好的选择就是最成熟和通用的技术比如说选择java技术栈web开发的ssm框架等但这样长远看团队和个人的技术能力很难提升请问老师在这方面有什么建议
**宝玉:**我觉得团队的技术提升和项目的技术选型要分开,不要总想着两个都兼顾,优先保证好项目稳定、低成本运行。
技术提升这种事,需要让一部分人先成长起来,然后带动其他人。我自己工作之外会做一些业余项目,然后在这些项目中体验新的技术,体会其中优缺点,然后再逐步应用到工作的项目中,传授给同事们。
我也鼓励其他同事这么做,去做一点自己的项目。但工作中的项目,我是很保守的。
No.4<br>
**alva_xu**对于开源技术方面,老师有没有什么经验来指导选型?
**宝玉:**开源技术选型,我的经验一般是这样的。
1. 先找朋友推荐,少走一点弯路。
1. 没有推荐的话,就去网上搜索,找几个满足需求的备选。
1. 对比以下几个指标:
- 代码质量、有无测试;
- 文档健全度;
- 看Issue处理情况、最后更新时间无人维护的项目后续恐怕有问题都没法解决
- 看Star数量通过Google和StackOverflow看使用情况。
4.自己按照说明试试看。
No.5<br>
**alva_xu**有没有什么大的原则可以指导技术选型?比如技术成熟度等?
**宝玉:**我认为在满足设计目标的前提下,大的原则还是在于项目约束,尤其是成本和时间,然后就是看技术可行性和风险是不是可控,其他看团队风格,有的偏保守有的追新。
比如说我自己的原则:
1. 成熟的好过新酷的;
1. 流行的好过小众的;
1. 团队熟悉的好过陌生的;
1. 简单的好过复杂的;
1. 开源的好过商业的(有时候也视情况而定)。
No.6<br>
**Charles**有着正常职位或头衔的架构师,对一个全新的项目理解产品需求后进行架构设计,一般会产出哪些“东西”,来满足后续的架构讲解和项目开发过程中的沟通?
**宝玉:**互联网产品特点是用户多,企业产品特点是业务复杂,所以架构的侧重点不一样。
架构师在架构设计后产出首先是架构设计文档让大家理解架构。然后还要写架构开发的文档比如如何基于这个架构开发功能模块有哪些公共API可以调用怎么样是最佳实践要遵守哪些规范等。
再要帮助搭脚手架和基础模块或示例项目,也就是要搭建一个最基础的可运行项目,通过这个项目,大家可以直观地理解你的架构是怎么落地的,通过基础模块或者示例项目,可以知道如何基于框架开发,后面就也可以照葫芦画瓢照着实现。
还有就是在开发过程中,要答疑、解决架构中存在的问题,对架构做优化,还要做代码审查,对于不符合架构规范的地方要指出和修正。
No.7<br>
**Dora**互联网架构要考虑互联网很快的迭代速度所以对于扩展等特别注意。企业架构内部IT系统相对稳定对比互联网架构更简单
**宝玉:**挺好的分析。帮你补充几点:互联网架构不仅迭代会快一些,用户规模通常更大,但业务也会单一些;企业应用通常业务比较复杂,尤其是和行业会有一些结合,但是用户规模要小很多。这些特点,都会影响架构设计的选择。
No.8<br>
**WL**老师能不能具体讲讲重构有哪些原则和要注意的地方,感觉一直得不到要领。
**宝玉:**重构的要领我觉得两点。
第一:你要先写一部分自动化测试代码,保证重构后这些测试代码能帮助你检测出来问题;
第二:在重构模块的时候,老的代码先保留,写新的代码,然后指向新代码,或者用特定开关控制新旧代码的指向(这样上线后可以自己先测试,有问题也可以及时关闭),然后让自动化测试通过,再部署测试,新代码没问题了,删除旧代码。
No.9<br>
**bearlu**有没有事情管理的工具?因为如果不记录下来,一会儿就忘记了。
**宝玉:**留言区McCree同学推荐了滴答清单。我个人的话一般就用系统自带的记事本记一下或者贴一个便签纸在显示器。如果时间跨度长我就记到Calendars上加上提醒。工作中的任务我则会创建成Ticket。
No.10<br>
**W.T**现在还有一种说法:提倡基于主分支开发,效率更高;而不是您提到的每人基于自己的分支开发完再合并回主分支。您怎么看待这个问题?
**宝玉:**我认为对于软件工程来说,很多问题,并不是只有唯一解,即使是最佳实践,也得看适用的场景和团队。
无论是基于主干还是分支开发,有两点需要注意的:
1. 就是一定要有一个稳定的分支可以随时发布的那种至于是叫master还是叫release并不重要。
1. 合并之前要有代码审查和自动化测试配合CI
上面两点才是核心。
No.11<br>
**hua168**如果一个项目有5个开发做持续集成怎么保证不乱比如开发A刚刚修复的bug1开发B把自己修复的bug2上传之前的代码bug1没修复怎么办如果采用分支怎么合并如果是直接更新master分支那A不是白做了
**宝玉:**要注意是“合并”而不是“覆盖”。比如说bug1涉及file1和file3的修改那么开发A合并的时候只合并file1和file3。
等到开发B修复了bug2修改了file1和file2file2直接合并file1需要手动去修复合并冲突才能合并。
每个人开发之前都会从master获取最新版本合并的时候如果出现冲突要先解决冲突才能合并进去。这些其实应该自己去动手试试会体会更深刻。
No.12<br>
**dancer**在微服务架构中一个服务在测试环境的交付验证往往还依赖于其他相关服务的新版本导致新的feature很难独立的交付。对于这种情况有什么好的方法吗
**宝玉:**我觉得对于大部分时候,微服务之间应该是独立的,而不是依赖过于紧密,如果每一个新功能都会这样,那架构设计一定是有问题的,需要重新思考服务划分的合理性。
但你需要有更多上线或者场景我才能针对性提出一些意见。对于有一些确实需要跨服务合作的大Feature这样也是正常的就是需要一起协作实现商量好通信协议分头开发再联调。
No.13<br>
**Gao**老师所讲排查生产问题的案例,首先回滚版本,再看日志。这会引发更多的系统功能不可用吧,两个版本之间的功能差异尚不清楚就直接回滚,系统风险是否被进一步扩大?
**宝玉:**这个确实要具体情况具体看,因为我日常的系统上线,都会有回滚方案,回滚也是自动化的很方便。有些跟数据库相关的,如果数据库结构发生变化又产生了新数据,确实没法直接回滚。
No.14<br>
**kirogiyi**团队成员的能力和素质参差不齐,如何有效的去组织和管理项目的自动化测试,自动化集成?
**宝玉:**首先你要先搭建好自动化测试环境让自动化测试代码能跑起来最好要和CI持续集成工具整合在一起每次提交代码CI都会跑自动测试然后能看到运行结果。
然后把自动化测试作为开发流程的一部分比如说要代码审查和自动化测试通过后才能合并代码。这部分工作如果和CI集成会容易很多。
再有就是要培训比如遇到不会写的开始先带着他写几个确保他学会了自己能写然后下次代码审查的时候看到缺了就要求补上还不会就继续教来不及写的就创建个Ticket跟踪起来。
简单来说,就是代码审查+CI+培训。
No.15<br>
**探索无止境:**各种类型的测试覆盖率你们一般采用什么指标?个人感觉在理想的情况下最好是做到百分百覆盖率。
**宝玉:**100%覆盖,这个我觉得可以作为一种理想追求,但是没必要追求极致,还是要在进度和质量之间有个平衡比较好,毕竟进度也很重要。
另外对于前端业务,我更重视集成测试的覆盖,对于主要业务场景集成测试覆盖到位后,单元测试也就有比较多的覆盖,相对性价比更高,然后再逐步补充单元测试的覆盖率。
No.16<br>
**起而行:**持续集成怎么理解呢?我看知乎上说,有的团队成员在一天内多次进行编译,发布或自动化测试。
**宝玉:**狭义的持续集成不包括发布,主要指集成,持续的(每次提交代码变更都触发,频繁地提交)对代码进行集成(合并到主干),但集成前要确保自动化测试通过。广义的持续集成还包括部署,也就是集成后自动部署测试环境(持续交付)或者生产环境(持续部署)。
No.17<br>
**小小:**请问下有没有介绍开发如何写好测试不错的书?
**宝玉:**推荐《how we test software at microsoft》中文版《微软的软件测试之道》。不过没有书其实你也可以找到很多资料的。比如我平时写前端程序那么我会去GitHub或者Google通过关键字、语言找跟我项目类似的开源项目然后看其中有没有自动化测试写得好的。
找到了(例如reactstrap、electron-react-boilerplate、kitematic)就照葫芦画瓢好了,因为都是真实项目,所以特别简单有效,建议你也可以试试。
另外耐心一点,你也可以看到很多关于测试知识分享的技术文章,多看一看也有收获。
No.18<br>
**hua168**代码审核是纯手工做的吗?没有好的工具?
**宝玉:**代码审查可以参考GitHub上一些开源项目的PR Review通常网页上可以清楚地标记出代码修改针对代码行可以写Review的评论这就已经很方便了。
其他工具主要是Lint检查代码规范、语法错误等这个一般在CI里面就集成了。
## 精选留言
陈珙 <br>
在没有特殊要求的情况下,项目中更加倾向选择更为熟悉的技术,因为我们需要对项目的质量与交付时间负责,可以做到可控的。而新技术有着新的设计思想与强大的功能,同时也伴随着无法预知的“坑”。在后续产品迭代的时间里,有针对性的升级或者选择更换同类技术里更优的。
相关阅读: [ 22 | 如何为项目做好技术选型?](http://time.geekbang.org/column/article/90957)
Y024<br>
Appfuse一个 Web 开发基础平台)的作者 Matt Raible 曾总结了选择 [Web 框架的 20 条标准](http://static.raibledesigns.com/repository/presentations/Comparing_JVM_Web_Frameworks_February2014.pdf)。
同时,他也整理了一份表格,你可以根据自己的权重进行调整,产生自己的[分析](http://docs.google.com/spreadsheets/d/12l0sZNVSnwxcxs3CtcjeaCcI8rXjTrrldfTBZn7grD8/pub?hl=en&amp;output=html#)。
但是现实情况,大家可能更遵循的是“经济适用原则”,比如:很多人提到的,负责人会啥就用啥,或者大公司者业界流行什么就用什么。
有位大佬说过“这个世界是你认为有很多选择其实只是幻觉大多数人只有很少的选项。技术研讨会搞一个选型hadoop + mysql + xx 时髦技术。架构师唾沫四溅吹一下午,结果老老实实上 Oracle 单例。”
相关阅读: [ 22 | 如何为项目做好技术选型?](http://time.geekbang.org/column/article/90957)
kirogiyi <br>
架构师是一个概念性职位没有明确的界定需要具备的能力和素质也是千差万别每个开发人员心目中的架构师画像也都不一样神秘的IT牛人高级的保姆无休的恶魔…
在我看来,一名优秀的架构师应该具备良好的技术思维、产品思维和项目管理思维。技术思维是基础,评估技术难度、分析技术复杂度、准确把握技术方向,这些都是架构师在设计架构时面临的技术决策。
产品思维是骨架,在产品思维上构建起来的整体全面的产品意识,可以对业务、功能、模块进行明确的抽象、分治、迭代等等。
项目管理思维是方向,无论是敏捷管理模型还是瀑布管理模型,都需要在不同的时间、不同的环境条件下去关注金三角理论的取舍所带来的影响,降低技术以外对项目带来的局限性。
不过,架构师也不是想象中的那么神秘。开发人员和架构师的差别,最主要是层次和格局上的差别,导致最终产生了不同的结果而已。
试想两个能力相同的开发人员一个的目标是每年涨工资80%开发人员他会去努力多做事拓展技术的深度一个的目标是CTO20%开发人员),他会去努力多做事,多思考,多学习,多交流,尽力做到面面俱到。几年以后的结果就不言而喻,至少坚定的目标能够推动过程的发展。
相关阅读:[23 | 架构师:不想当架构师的程序员不是好程序员](http://time.geekbang.org/column/article/91312)
alva_xu :<br>
讲到架构我想先得谈一下康威定律。康威在1967年曾说过
>
Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations.
通俗地说,就是组织形式等同于系统设计。所以系统架构设计的进化,是和组织形式的变化结合的。
从ITIL来说BIAbusiness IT alignment是IT的核心所以充分认识组织的业务模式和运营方式才能让架构师设计出适合于企业的系统架构架构设计的最高境界就是适合企业业务的运营。
从单体架构到微服务架构从前后端分离到中台都是架构适应业务功能与非功能需求的体现。所以架构师首先必须要有业务思维、产品思维。TOGAF把企业架构分成业务架构、应用架构、数据架构、技术架构四个子域我觉得相当全面。
从程序员开始,如果能培养好老师讲的架构师能力模型中的四个思维和三个能力,我们可以给自己规划出一个架构师的成长路径,从单个业务应用开始,然后扩展到一个业务领域,最终到达企业架构师,甚至成为跨企业应用架构师的境界。
相关阅读:[23 | 架构师:不想当架构师的程序员不是好程序员](http://time.geekbang.org/column/article/91312)
纯洁的憎恶:<br>
技术债务不全坏,与金融债务一样,需要具体问题具体分析。轻率&amp;有意的债务要避免。谨慎&amp;有意的债务有收益。
轻率&amp;无意的债务要警惕。谨慎&amp;无意的债务要改变。识别债务防患于未然。根据成本收益分析,决定重写(一次性还款)、维持(只还利息)还是重构(分期付款)。
相关阅读:[24 | 技术债务:是继续修修补补凑合着用,还是推翻重来?](http://time.geekbang.org/column/article/91729)
kirogiyi <br>
在研发过程中,产生技术债务的时候,稍微有点技术功底的人,或多或少都会有感觉的。
比如:有重复代码的时候,会意识到好像已经写过了;函数命名的时候,会意识到好像有个相似的名称已经命名过;函数行数过多的时候,自己心里会感觉不舒服等等。
更有甚者,你去整理这些问题还会被同事标上“强迫症”患者的称号,还是放弃吧。技术债务就这样在外部和内部双重压力下自然而然的产生了。
那么如何产生有利的技术债务呢?我觉得应该从公司制度、研发流程、个人素质培养三方面入手。
公司制度实际上是为领导层准备的,领导层以身作则去影响下面的员工,员工就没有冒犯的理由,比如合理的奖惩制度,要做到公平合理,一视同仁;
研发流程主要是让团队成员知道自己什么时候该做什么事情,如何去按照指定的约束去做好自己的事情,除此之外,还应该给予明确的成长上升空间;
员工素质的培养则需要从一个人的职业素质,技能优化,团队协作方面着手,让他们拥有积极努力的心态参与到工作中去,这基本上就能解决最基础的技术债务问题(领导决策错误产生的技术债务另当别论)。
在我遇到过的技术债务中,主要由领导决策、产品业务逻辑、技术最初选型、技术更新换代、团队综合素质中的一种或几种导致。对此,我只能说个人能力达到什么层次就应该去解决什么层次的技术债务,不能去推诿和落井下石,在你手中的技术债务就应该当成自己欠下的技术债务来解决,这样才能持续性的做好自己分内和分外的事情,工作起来才能得心应手。
相关阅读:[24 | 技术债务:是继续修修补补凑合着用,还是推翻重来?](http://time.geekbang.org/column/article/91729)
kirogiyi<br>
我觉得高效,意味着自律,自律的好坏是可以通过你散发出来的气息让周围的人感受到的,比如:说话有没有条理,做事拖不拖延等等。
生活自律,你会发现每一分每一秒都充满了希望和力量,用积极乐观的心态去完成每一件事,知道自己上一步做好什么,下一步才能做好什么。
工作也是一样要想高效完成任务需要利用前辈们总结的思想和方法去长期实际应用在使用的过程中就会体现出你的高效不能说我知道单元测试我知道CI…很少有人讲我一直在用。
如果我们注意观察,会看到身边的同事,有的很少加班(活蹦乱跳),有的经常加班(蔫头耷脑),做了一样的事情用了不一样的时间,此时就能真正的体会到高效做事的魅力了。
我不提倡加班的原因就在于此,但那是针对高效人士的,低效人士不加班,老板是不会答应的。而一般对自己的时间把握比较好的人,在估算工作时间或工作量的时候,都比较果断,不会支支吾吾,还会主动给出具体时间点和阶段性成果,让人觉得这才是真正做事的人应该有的态度。
我的看法是,积极、主动、自律是高效人士的必备素质。
相关阅读:[ 25 | 有哪些方法可以提高开发效率?](http://time.geekbang.org/column/article/92266)
nigel<br>
就学习能力而言,“祭海先河,尤务本原之学”,重要的是对基础知识的掌握。就像侯捷先生说的“基础的东西不易变,不易变的可重用”。
相关阅读:[27 | 软件工程师的核心竞争力是什么?(上)](http://time.geekbang.org/column/article/93062)
_CountingStars<br>
之前看到过一个关于 code review 的观点:在让别人 review 你的代码的之前,你要确保你的代码没有基础的问题,比如单元测试要通过,不能有代码风格问题,首先你要确保你的代码是能正常工作并解决需求的。当然这些基本都可以通过自动化来操作,比如提交 PR 的时候,自动化的检查代码风格,运行单元测试。保证邀请别人 review 你代码的时候,不要为这些小事费精力,提高 review 效率和积极性。
相关阅读:[30 | 用好源代码管理工具,让你的协作更高效](http://time.geekbang.org/column/article/93757)
bearlu<br>
其实我觉得用什么源代码管理工具都没关系,最重要是要了解工具,形成流程,按流程走,然后纠正流程。
相关阅读:[30 | 用好源代码管理工具,让你的协作更高效](http://time.geekbang.org/column/article/93757)
## 思辨时刻
Charles<br>
三四线城市技术选型前期主要考虑当地市场什么人才比较充足比如后端PHP人多那就PHP学习成本也低几人团队协作起来也不是大问题而且前期扩充人员也比较好招人另外前期应该也不会在语言层面出现性能问题。
然后数据库基本就选MySQL够熟悉够成熟。前端的话web、小程序、ios、android之类的都统一MVVM思想进行前后端分离开发这样各个用户端都可以统一API提升效率这个也会从产品角度思考。
如果产品经理就只是需要一个PC网站而且短期也没升级计划就选择传统的后端渲染web页面方案。可能会站在目前项目或经历过的项目经验去思考问题期待老师回复指正。
宝玉:<br>
我觉得你的选型思路在项目发展阶段包括没有很大规模之前都是没有问题的。选最熟悉的、流行的往往也是风险比较低的。包括如果就是一个PC站也不做SPA单页应用也没有必要前后端分离。还是看是不是能低成本满足好项目需求和业务发展。
有一点补充的就是前端除了MVVM像React的Flux和Redux的架构模式也是一种很好的架构模式但在非Rect/Vue的项目中应用不多。
相关阅读:[22 | 如何为项目做好技术选型?](http://time.geekbang.org/column/article/90957)
好,今天的加餐就到这里,非常感谢同学们的用心留言,希望大家都能持续思考与总结,不断精进!
感谢阅读,如果你觉得这篇文章对你有一些启发,也欢迎把它分享给你的朋友。