为毛没有效果?! 为了乐趣和收益怒写代码

February 25, 2016

原文链接: https://medium.com/google-developers/why-won-t-this-work-coding-angry-for-fun-and-profit-1ef38a2b7196#.8l4l3whz8 大部分地方都是直译的,有些地方读起来可能没有那么通畅。

为什么用错误的方式来构建app是正确的呢?

写出好的代码很难,但是如果连用最简单、最容易的方式来构建App都令人泄气,那当你只是想试验一下时,如果告诉你要用正确的方式来构建,那对你来说只能是一种额外的负担,并不会有什么效果。

我认识一些人,他们在自己的代码里找到了安宁,还认识一些工程师,他们在处理一个复杂问题的时候找到了“禅”(Zen)。每一个新的方法实现,bug的解决,谜团的揭开都是给混乱的宇宙带来秩序的道路上的一步。一种和谐、满足、快乐的感觉油然而生。

我不是这样的人。

pic

我不是说我没有找到写代码的快乐。我有快乐。

当你用全新的API并且操纵它们让你的设备完成一些它原本无法完成的事情时,那种感觉是醉人的。

你感觉自己就是凡人中的上帝,简直能随意弯曲宇宙。你感觉一切皆有可能。

其实也就仅仅是那一瞬间会有这种感觉。其他大部分时候我的情绪会在无比的兴奋和欲哭无泪的沮丧之间徘徊。

沮丧是我们最普遍的同感

虽然我们工程师很少和非工程师谈论它,但是下图是经过20分钟调试一个问题之后的我: pic

经过20分钟的Debug之后发现我只是忘了调用Toast的.show()的表情

我最近和一个同事聊天,他是资深工程师,但是对Android不是很熟,他想写一个App,当他离家近时,自动打开他的联网的智能灯,他学了一个Android课程,然后他了解Android的基础。

他跟我说了很多他的挫败感。

我说这可能会花费我1小时时间,如果从0开始构建的话。我并没有坐在他旁边结对编程,我录下来我自己写代码的过程(还切掉了那些“非常”烦人的部分)

https://youtu.be/mvhKjh5D1WQ

这段视频展示了最简单快速、也是最“错误”的构建app的方式。16分钟里展示了接近两小时真实coding和debugging的时间。并且在一个Activity里实现所有的功能。这种实现方式有成百上千的错误的地方,我在视频的结尾花了一些时间来解释哪些地方需要换一个方式实现。

开发真正的移动app是复杂的

很多人(包括我自己)花了很多时间来编写完美的代码示例、步骤、教程和培训课程,所以当新的开发者准备编写她们的第一个app 时,他们已经拥有了所有需要的工具来正确地搭架构和高效地实现。

但是如果你是试图感受一下Android开发,以及尝试一下一个idea是不是可能的,那去想是不是要用Fragment、Service、和Intent Receiver来实现是不是值得呢?需不需要去理解Activity和app生命周期里的细节呢?

如果你想写的是一个受用户喜爱,受投资人青睐的app,那么答案就是响亮的YES。但是,那并不意味着你必须学习上面所提到的所有东西。

写一些用来娱乐的或者用来证明你的idea的又hacky又丑陋的代码也很有意思。我觉得这可以是你学习一些困难的东西的动力。

写这种“可以扔掉的东西”,我们可以学一些真正有价值的东西,并且证明了我们想要的——当我靠近家里时,自动打开我的互联网智能灯是可以实现的。

这样也很酷,不是吗?

当我想学习如何用一个新的平台,新的API或者框架来编程时,我会通过实验、尝试和失败来开始,直到我有进步或者感到厌烦。

第一天,我只想下载SDK,打开IDE然后开始试验。

我会投入几个小时感受一下如何让这些东西跑起来,而不会去太多理会是不是正确的方法。那样会产生一些恶心、很多bug、架构很差并且完全无法扩展的东西,但是作为原型它能跑就可以了。

要注意入门体验是很重要的。如果我的前几个小时都花在了安装和配置环境上了,那我甚至可能在开始前就放弃了。

我会通过我的直觉来看哪些东西是可能的,就跟我学习使用一个新的电器一样。我会使用Stack Overflow,因为,讲真的,我们要现实一点。

当然,就像我的新电器一样,实际上我可能会读一下手册或者书,学习个教程,看个视频,或者查看一下示例——当然我不会一上来就这么做(which is more than a little ironic given how much time I spend creating those things for other developers.)。

构建取悦用户的app是一种艺术

然而如果只是想做出一个能工作的东西,感觉coding应该要是可预测的。一个移动app,从根本上来说只是操作晶体管来创造AND门、OR门和NOT门,然后用来创造出更加复杂的逻辑,我们其实只是在和逻辑电路打交道,如果你从从根本上看,只是一系列的true和false。

这些基本的最基本的构建单元可以用来组成日益复杂的API,框架和平台,然后用来为用户创造出功能日益丰富的app。沿着这条道路的每一步都有效封装了最佳实践的实现细节,从而让我们没有必要从定义对象、创建链表或者写出快排算法来开始我们的项目。

我们可以从概念上将一个极复杂的系统转化成简单的状态机

我在手机上划两下点两下,然后就可以录像,再操作两下就可以在电视上播放我的录像。当你不需要思考做成这件事所需要涉及的可交互系统时(electricity, power distribution, digital-analog conversion, video recording, video broadcasting, LCD display, Chromecast, …)——更不用说它们每一个系统是如何作用到硬件层的(),这很快就变成了复杂度和可怕的代名词了。

作为工程师,难度,挫折和胜利的最终快感来自解开我们代码中由于多层抽象、这些组件之间的交互、用户和这些系统之间的体验交互带来的复杂度。

为了高效地编写和(特别是)调试代码,你要在脑海中关注重要的部分(如果不是每部分都重要的话)。那就意味着从高层架构上各个组件之间的组合到每个部件内部的工作,甚至直到物理层。

痛苦来源于被拖往底层了

我们不停地在系统如何作为一个整体工作的大概念和每一个部分实现时的痛苦细节之间切换。

pic

调试“感觉应该已经能跑了”的代码时典型的流程图

假如说你想结合Wifi和蓝牙信号到一个自学习系统来更高效地触发“地理围栏”。如果它没有用,那问题可能出在对蓝牙API的理解上、蓝牙信号的误读、或者仅仅是你测试是否有用时忘记了调用Toast.show()。

最小化你的问题栈的深度和复杂度

为了减少我的挫败感——提升我的成就感——我试图让我做一个东西的时候涉及的范围越小越好。一旦它能工作了,我才会退出来然后加入一些复杂度,然后快速迭代从而使我在解决困难的问题和实现更好的app版本之间有一个紧密的循环。

在实践中,它可能看起来是这样的: pic

每一个波峰表示我可以存储的潜在动力,然后在编码和调试的任务中消磨掉,同样的通用原则也支撑着大多数敏捷方法:快速迭代,并保持灵活性。

当你将抛弃原型路程,再次构建您的app,利用这些高点作为动力,这一次要用更健壮,精心设计的,可扩展的方式。

写出好的app很难

很遗憾写app没有什么简便方法。无论你是要从0开始,用正确的方式构建,还是从一个粗糙的东西开始逐渐打磨,你实际上都要解决同样的问题,遭受同样的挫败感。

这些挫败感是你为了胜利时刻付出的代价,那种你亲手将一大堆0和1转变成了神奇的东西。

一个漫长而开心的职业生涯的秘密就是寻找到一个适合自己的方法,一种可以使你沐浴在波峰的阳光处而不是在波谷的黑暗里挣扎的方法。

对我来说那意味着构建一个app的正确方式就是从“错误方式”开始。

你是一个快乐的程序员吗?你开始新项目的方法是什么呢?

本文里的视频是一个全新系列的原型,在这个系列里我会录制我更新一个老的基于地理位置的app的全过程,给它加上很多全新的Android特性,你们会看到我犯很多错误,调试它,然后犯更多错误。敬请期待。