大数据

一只Android猿的编辑器之路

点、崩、撩、劈、刺、拦、挂、托、绞、削、压、云、抹、截、带、斩、架。

对剑客来说,基本剑法练不好,不仅打架打不了,就算是教授传说中的独孤九剑也无从学起。

对俺们程序猿来说,对代码进行增、删、改、查、剪、拷、贴,是我们的日常工作。这些外功没练好,结果只能是加班、通宵、延期、炒鱿鱼、过劳死。

好的编辑器,可以帮助程序员更快、更好地做出编辑的基本操作。犹如剑客手中的剑,必须千锤百炼、顺手合挈。

我谈谈自己在编辑器上的那些经历,其实也是我作为程序员的成长经历,以供参考。

学习机

在我小的时候,老爸买了个XXX学习机。它就是个可以插卡的键盘,附带的卡带里面有些学习用的小软件。在电脑未普及的时代,这是俺们落后地区穷人家庭唯一的学打字方式……然而并没什么用。那时折腾的五笔打字法,我现在只会打姓名。后来,我在大学有了电脑,跟着最好的打字学习软件学会了拼音输入法——QQ。

学习机最终变成了游戏机,而那个没什么游戏的卡带也早已不知扔哪儿去了。学习卡中,最让我不解的,是一个黑乎乎的界面。我根据说明书,敲了一段不认识的英文、字符、数字进去,然后出来一个结果:5050。我把数字100改成1000后,它卡了一会儿,出来一个新结果:500500。我把数字改成10000,它5分钟后给了个结果:50005000。而当我改成10000后,再也没有等到过结果。

最终,我仍然不知道说明书上写的BASIC是什么东西,直到上大学。

高中时,有个同学有一台可以编程的XXX文曲星(电子词典)。他写了个小游戏在里面,我很羡慕。借过来后,没有任何参考书籍,只能通过学习他的代码,揣摩其中规律,依葫芦画瓢。

我花了很长时间,写了个简单的文字游戏,以及一个很复杂的地图。地图的复杂最终导致碰撞检测的复杂,所以这个地图游戏没有完成。不过,我对其中海量的IF THEN GOTO仍然记忆犹新。

最终,我仍然不知道这种语言就是BASIC,直到上大学。

这两个场景,其实并没有用到真正的编辑器。如此简陋的编程环境,已经堪比早年的那些程序员了。

Notepad

大学一年级C语言课程后,我用Notepad(记事本)写了一些自娱自乐的C代码。

然而并没有编译过,因为Notepad不能编译。

╮(╯▽╰)╭

Visual Studio

和很多非科班出身的人一样,我也是用Visual Studio写C/C++小程序,逐渐走上程序员这条不归路。当年C语言上机课时,有Turbo C++和VC++ 6.0可选。由于Turbo C++实在太丑,如蓝屏死机一般,于是我选了后者。

现在看来,turbo_c其实也没那么不可接受。

什么是编程?先安装一个Visual Studio,然后新建一个解决方案(Solution)。

怎么编译程序?点击那个向右的箭头啊!

怎么运行程序?点击那个向右的箭头啊!

怎么调试程序?点击那个向右的箭头啊!

我那时对写代码的了解非常粗浅,Visual Studio对我来说,也就是个带箭头的记事本,其它的高级功能完全没用过。而且,一旦离开了这个IDE,我什么也不会。

每次换了系统,我总是下意识地安装一个Visual Studio,然后找破解。完全搞定后,多数情况下,我再也没打开过,直到下一次换系统。

当时不仅为IDE所苦,也被C语言所限,更被Windows所惑。我一心认为程序首先就该先有个图形界面,而C语言又做不出界面(实际上当然是可以的,只是当时的我不行),常常盯着IDE不知道该干啥。

精通各种模板……的Hello world创建。

快毕业时,最后一次换系统,第一次安装一个正版(免费)的Visual Studio Community 2013(目前最新是2015)。那一次,虽比不上九阳神功大成却无外功可用的张无忌在光明顶后山看到乾坤大挪移典籍,也相当于张小凡终于克服了太极乾坤道与大梵般若的互锁,我忽然把之前所学的那一星半点编程知识融会贯通,开始写真正的Windows程序。

这次开窍,虽然避免了回家乡啃老造人的命运,但也来得太晚了。移动互联网时代才刚会写Windows单机程序,光明顶早已被六大门派血洗,青云山也已经轮到萧逸才当掌门了。

这段经历还给我留下了一个不可磨灭的印象——用盗版会走霉运!

我哪次不是安装最新的Visual Studio旗舰(破解)版?结果却什么也没学出来。这次安装了一个功能不全的Community版,竟然就顿悟了。

后来,连毕业论文都是用免费的WPS写。

(不过,这并不意味着我是好人,因为书除外。我一直信奉一句先贤的话:『窃书不能算偷!』是哪位先贤,无需赘言。)

Eclipse + ADT

理所当然,在想学习编写Android应用时,首先想到的也是Visual Studio。在当年,这完全无法着手。(那时的我,当然无法找到初创的Xamarin。)于是跟随着当时的网络教程,我自然而然地安装了Eclipse。

首次接触Android时,主流配置都是Eclipse + ADT + Java6。

当时,我其实对Java一知半解,Eclipse从未用过。ADT是Eclipse的一个插件,可我当时连插件都不知是什么概念。而Android,更是在学校图书馆里连本书都找不到!本来就没多少,还被借光了,于是我只能无奈地傻瞪着几书柜的塞班。

还好,最终还是折腾出了一个Android的小APK,总算没白费这段光阴。最终,也因此而得到了现在的这份工作,险险地赶上了移动互联网的末班车。

可不曾想,我用ADT的历史就已经到头了。

2014年,Google停止了对ADT的更新,2年后完全停止了支持。

Gedit

我所在的,是一家做Android平台开发的公司。由于要编译整个定制后的Android源码,所以真正的开发环境,不在眼前的笔记本上,而是在远程的Ubuntu工作站。因此,当我配置完笔记本上的Windows环境后,完全傻眼,根本用不上!

怎么看代码?打开Ubuntu的文件管理器(Nautilus),进入代码所在目录,双击某.java文件。这时,一个自带语法高亮的编辑器弹了出来——Gedit

“哇塞!比Windows上的记事本强多了!”

怎么查找变量、跳转函数?ctrl+f搜索。

怎么跳转到本文件以外的地方?在Nautilus里人肉搜索该文件,然后双击,ctrl+f

找不到文件怎么办?问同事。

……往事不堪回首月明中。

现在才知道,其实Gedit远比它看上去要强大,也是一个可扩展的编辑器。不过,我已经不需要它了。

Source Insight

我从来没用过Source Insight这东西,但是我的工作环境里,大多数人都在用。在交流时,经常看他们用它来演示。

这是一个非等宽字体的Windows编辑器,在Ubuntu下用Wine来运行。

看上去好像很不错的样子

如果让我强行心平气和地说,那么这也是一个不错的编辑器。它兼容C/C++和Java,在导入了Android(造tag)后,代码的跳转与查看非常方便。函数名和类名可以变得异常地粗大,非常显眼。虽然不支持查询一个函数的所有调用位置,但也可以通过一个替换预览的方式来hack。

然而,当我导入整个Android代码后,呃,准确说是导入的过程中,我就放弃了。看别人用都是好好的,为什么在我这儿卡得不能动呢?

后来知道,因为他们只导入Android的部分库。通常是frameworks/base/,加上他们自己负责的库,这当然不会卡。可是,我当时怎么知道我要导入哪个库?

现在想想,当时也挺混得失败的。不过,现在的我很庆幸这次失败。

与我同时进公司的程序员,他们无一例外地随着大环境而成为了Source Insight用户。结果,他们现在虽然也能很好地完成工作,但仍然搞不清一些Linux、Android、Java的基本常识,与老员工一样。

对了,需要解释一下为什么我难以心平气和地谈论Source Insight。这是我见过的唯一一个非等宽字体代码编辑器,绝大多数同事使用默认配置,这导致他们:

  1. 连Tab(制表符)和Space(空格符)都分不清!
  2. 连缩进都对不齐!
  3. 行尾到处都是空字符!

这三点虽然不影响编译,但是违反了公司明文规定的编程规范,也影响了协作效率。而作为一个能肉眼分辨出空字符、有代码洁癖的人,我完全不能忍!

那以后,不仅是代码编辑器,Source Insight也让我对所有非等宽字体的纯文本编辑器,都产生了恶感。

天秤的最后一块砝码是,我们公司的Source Insight,是盗版的!

log的查看器

我一开始的工作,并没有写很多代码,主要是看log、解bug。

log文件的查看器,不需要很强的编辑功能,但是需要很强的查看、裁剪功能。

我的同事们分两大派系,一是UltraEdit,二是Notepad++

UltraEdit官网自称:The world’s best text editor for 20 years.

Notepad++是开源软件,遵循GPL协议。

Notepad++我从未安装过,了解不深。偶尔在别人的电脑上使用,发现功能也很强大。如果我先接触的是它,那么也许未来会有所改变。

教我看log的同事推荐的是UltraEdit。我安装后,发现竟然是盗版的!前面说过,我临毕业前开始迷信『盗版是会走霉运的』,所以这里果断放弃了。

再想切换时,忽然想起了Vim。大学二年级时,有一个师兄推荐了这款编辑器。我安装后,立即迫不及待地打开,噼里啪啦地随机敲了一会儿键盘,竟然发现一个字符也没输入!(Vimer应该都知道我恰好漏了哪些键。)顿时玻璃心破碎,点了右上角的红叉。直到换系统,此后再没打开过;换系统后,也再没安装过。

这次想起,也是机缘巧合。

Vim的学习曲线非常陡峭,所幸看log的要求却不高。hjkl是移动光标左下上右(←↓↑→);*是搜索当前单词;/后手动输入搜索关键字;n向下搜索;N向上搜索;:v/KeyWord/d截取包含KeyWord的行,并且可以在结果中再截取其它关键字;u是撤销上次操作,ctrl+r是撤销上次的u……

自此,我查看log的效率已在众人之上。而且,逐渐习惯了模态切换与全键盘操作。

Terminal + Vim

写到这里,终于到了正题。(读者:明明都已经准备关了。)

Android源码的编译,只能依赖于Terminal(终端)中的命令。(如果我一开始是应用层的程序员,也许会走上另一条更弱的世界线吧。)为了工作,我只能硬着头皮,面对以前避之而不及的黑屏界面。

一开始,我和大多数人一样,在Ubuntu桌面用一个文本文件,保存着常用命令,需要的时候就复制粘贴过去,非常麻烦。后来发现,Terminal内执行的多条shell命令,可以放到一个文件里去,一起执行。这件事,让我对Terminal的态度有了180度的转变。

用鼠标这么多年,每次遇到机械化的操作时,只能耐着性子,锻炼手速。而如果些操作可以用Terminal完成——这在Linux下几乎是必然可行的——我就可以把这些命令汇总到一个shell script文件中,可以一起执行!

当我的第一个script完成并运行的那一瞬间,犹如张小凡初遇天书的震撼——天地不仁,以万物为刍狗!我耳边也似乎也有了一阵轰鸣:

万!事!皆!可!自!动!化!

从默认白底黑字,到喜欢黑底白字。

此后,打开Ubuntu工作站的第一件事就是打开Terminal,第二件事就是令其全屏。

受此影响,在编辑器的选择上,我更倾向于一个在Terminal中直接运行的。多方了解后,要想满足工作需要,只能在EmacsVim中二选一。

由于前缘,我在看log时先学会了Vim的基本操作,所以顺理成章地成为了一个Vimer。

Vim

之前说过,我是『一个能肉眼分辨出空字符的人』。这当然不是因为我左眼写轮、右眼阴阳、正中还竖着一只没被亮瞎的高达尼姆合金,而是因为Vim可以令其可见。

然而,纵使Vim是一个可扩展的编辑器,当代最先进的配置加起来,也不足以令其媲美专业的Java IDE。Java,这是一个Spec超越了C++(98)的复杂语言。即使把《Java编程思想》倒背如流,也不敢说在没有语法检查的编辑器中,编程效率超过IDE。

正是由于初出茅庐的无知,而且我当时已经没有任何其它方法,只能用Vim强上。每次修改完代码,看见mm(Android里特有的单模块编译命令,本质是Makefile)后满屏幕的编译错误,只能瞪着眼一条条地修改。

这段时间,很像少时看的『少林寺』类电影中,刚入门的弟子背着沙包,提着两个尖底的木桶去打水。上山下山本就劳累,中途还不能休息,否则水就撒了。虽然艰苦,不过效果也同样显著。电影中的新弟子,解开沙包后一跃上树、健步如飞。而我也是进步神速,不仅了解了很多Java的细节,也和javac结下良缘。

再后来,我在Vim里写完代码,就自然可以通过编译;只要觉得没有问题的代码,就真的没有问题。

这段裸奔的日子,有近一年时间,痛苦地飞速成长。

Vim + Eclipse + Eclim

只有裸奔过的人,才知道内裤的重要性。

如果我早在Android的源码中,发现./development/ide/这个目录,也许世界线又会发生改变。

$ ls development/ide/
eclipse  emacs  intellij  xcode

早知如此,我说不定会选Emacs

Eclipse导入Android的Java层源码,32核64G的工作站,大概需要半小时。此后,Eclipse在使用过程中也经常卡顿,尤其是在跳转到没打开过的文件时,代码甚至会从白色缓慢地逐行着色。

要论跳转,Eclipse虽然有精准的语法解析,但有时还没有基于正则表达式的ctags+cscope来得快;要论补全,只要打开对应源码,仅仅是自带的Ctrl+n就已更快(基于buffer中所有文件中出现过的word),因为这样不会卡。

我从纯Vim,切换到连接Eclipse的Vim,是因为三件事:EclimYouCompleteMe与《代码整洁之道》。

Eclim大致包含三个部分。一是Eclipse插件,二是Vim插件,三是连接二者的eclimd。它可以令用户在Eclipse中使用gVim,或者在Vim、gVim中使用Eclipse的部分功能。

在一个断外网、无root权限的工作站上,要成功编译YouCompleteMe可不是一件容易的事。而当我成功后,它多少拯救了Eclim补全带来的卡顿,从而让我能忍受错误提示、修复建议等功能带来的卡顿。

《代码整洁之道》这本书,在当时给了我一记重击。当我能用Vim,快速写就一个Android项目后,却为代码质量而苦恼。虽然应用本身没有什么问题,但是代码不好看,降低了我的成就感。在读了这本书后,对高可读性的代码有了更多的理解与追求。鉴于Vim连整理import都比较费劲,也无法自动删除无用import,于是开始寻求额外的工具。在发现Android lint之前,我发现了导入Android平台源码到Eclipse的方法。

要提高Java代码的质量,使用IDE是一条必经之路。Java lint、Android lint等这些工具,凝结了大量的前辈经验。如果你读了《Effective Java》,却并不怎么会用,那么IDE可以帮助你。

Android Studio

正是由于Eclipse的使用经验,让我的视界从Vim中扩展开来。在开发下一个系统应用时,我坚持使用Android Studio来做开发。

在v2.x版本时,Android Studio已经是当之无愧的Android最好IDE。然而在v1.x版本及以前时,我的评价是:史上最渣IDE!

除了这货,我就没见过哪个IDE如此傲娇。自己生成个Hello world程序,自己都编译不了,这让新手怎么活?

还有,明明上一个版本好好的,更新到下一个版本就无法编译了!

首次启动卡半天!

断网后,有时sync不停!

……

最最糟糕的是,一旦打开这货,我工作用的8G内存、4核i7的ThinkPad竟然卡得鼠标都不连续了!

后来了解多了才发现,这是我的打开方式不对。在Windows上开,不仅内存要足,还至少得加装固态硬盘;在Linux上也无此问题,同一台电脑换Linux后立即顺畅无比,同时开三、四个项目也没问题;就连在MacBook Air上也表现出色,开关顺畅、使用无碍。

Android Studio是基于IntelliJ IDEA而开发的。除了继承来的Java lint、代码格式化、Copyright、以及其它海量插件以外,还添加了Android lint、Instant Run等特有功能。

Android有很多设计问题,最大的莫过于为了掩盖设计问题而导致的设计问题——不考虑向前兼容的API快速迭代。写普通的系统应用还好,因为只需要兼容当前系统,API level固定;而如果要写兼容多个系统版本的应用,没有成熟的IDE,连某个接口是何时添加、何时废弃、何时开始丢异常的都不知道,需要浪费大量时间去研究源码,否则会有不可知的错误。Android Studio就可以自动检测出这些,并且给出修改提示。另外,还有源码查看、文件模板、代码生成等功能,也非常省时间,体现了Google定制开发IDE的功力。

不过,IDE都是有通病的,Android Studio也不例外。IDE通常有过度计算的毛病,体现为占据了大量的计算机资源,而提供的功能却大部分都没有被使用。

另外,模板有误。之前说的,自己生成的代码却无法编译,这一点早已修复,2.0版本后没再出现。然而,自己生成的代码,在Android lint下却有一堆warning,这一点却不见改。更糟糕的是,我只是生成一个hello world,编译下来却有几MB大,都是v4、v7、design这几个包闹的,这估计只能愈演愈烈,改不了了。

还有,如果发生配置文件缺失、Gradle sync失败等疑难杂症,有时连Rebuild都无效,只能git clean -fdx,然后重新导入。

总之,如果不够了解其背后的运行原理,就会浪费大量时间在『确保IDE能正常工作』上,把省下来的时间还回去。

Editor与IDE

这是一个很大的话题,可以单开一篇万字文;这也是绕不开的一个话题,只要同时提到了双方。

IDE是集成开发环境(Integrated Development Environment),而其中最核心的工具,仍然是正中的Editor。我还是个愣头青时,认为IDE就是带编译运行按钮的记事本,回头来看,其实也没错。编辑是一切的核心,其余功能都是为了辅助编辑。

如果可以笼统地归类,那么程序员在任何一门编程语言上都有初、中、高三重境界。

  • 在初级时,适合用Editor。
    初学者什么都不懂,所以什么都需要学。IDE掩盖了初学者的缺点,让他们提前进入了舒适区。从此只会写代码,而对代码以外毫无了解,不知道自己缺什么,从而无法提高。
    其实,在命令行编译Hello world程序,并不是太难,而随着代码的复杂,对环境配置的需求也会逐渐提高。在这种刚需的驱动下,初学者会自然找到学习的正确方向。
  • 在中级时,适合用IDE。
    初学者不需要在意效率,因为他们的代码基本不可用。而中级程序员则不行,他们往往是中坚力量,需要高效地写代码,IDE是最好的选择。
    在熟练使用某一Editor后,程序员可以快速地上手任意IDE。因为他们对IDE在屏幕后面干什么,已经了然于胸。
  • 在高级时,无所谓用什么。
    用IDE时,是别人定制的集成开发环境;用Editor时,是自己定制的集成开发环境。而且,无论出什么问题,都可以快速地自行解决。

并不是所有使用IDE的,都是中级程序员。很多直接使用IDE的初学者,如学生时代的我,其实连初级也不是,完全不入流。在IDE不出错时,好像也能写代码的样子;而一旦IDE罢工,就只能干瞪眼。这种形式的效率损失,比什么都可怕。

那些离不开IDE的中级程序员,工作效率全靠经验的堆积,很可能连IDE也用不好,永远也到不了高级。

这还只是对一门编程语言而言。如果需要与多门编程语言打交道,精通一门Editor是快速成功的必要前提。因为,专用性越强的东西,通用性就越差;IDE定制得越成功,就越是不能很好地处理其它语言。

就拿Android Studio、以及IntelliJ IDEA来说,他们连同为JVM语言的Groovy都处理不好(Kotlin和Scala我不清楚)。如果在编译时做更多的事,把build.gradle写得复杂些,那么IDE就开始捣蛋了。设想一下,你平时赖以为生的语法警告如果是错的,还怎么愉快地写代码?

对IDE程序员来说,学一门新语言往往要学一个新的IDE,连快捷键都不顺手;而对Editor程序员来说,学一门新语言,也就是多安一两个插件,保留了绝大部分编程习惯。

一些Editor程序员,自以为剑法无双,就用剑来劈柴、砍树、敲钉子;而很多IDE程序员,工作若干年后,遭遇瓶颈,技术难有寸进。这两条支线必须都通关,才能向Perfect Ending迈进。

总论

其它如EmacsSublime TextVisual Studio Code,我只安装体验过,没有在工作中遇到,就不多说了。Atom用过一段时间,它帮我做的那些事,最终都被Vim接过去了。

神之编辑器Emacs:Esc+Meta+Alt+Ctrl+Shift

Sublime Text是主流编辑器中唯一可以免费使用的付费软件,颜值爆表。

微软的良心之作VS Code,不知是否能在群雄割据的开源世界打出一片天。

我曾经有一段时间用Atom来写Markdown,后来也用Vim替代了。

最终,我成为了一个Vimer。

即使在现在,主要开发工作都在Android Studio中,我也仍然是一个Vimer。大部分时间,我都在用插件IdeaVim工作。

在做一些Git操作、Gradle操作、文件操作时,我会把底部窗口的Terminal拉至大半屏。这时再遇到编辑操作,往往直接打开Vim解决。有时,大半个下午,我都在Android Studio的Terminal里,于Vim与Bash间无缝切换——想想也是蛮尴尬的。

Vim就像一把玄铁重剑,初时无锋,却可磨砺出绝世锋芒,削铁如泥。在我身体羸弱时,它能和我一起成长;当我武功大成后,它也不逊于任何神兵。

后记

女士应该都没撑到这里,否则也可以退场了。

我要说点渣男才会欣赏的隐喻。


如果我遇到过的编辑器都是女人……

Visual Studio是我青梅竹马的初恋,可惜我已经离开了家乡。历经红尘之后发现,其实当年这个邻家小妹,不仅家室显赫,也是一位难得的美人。

Vim是一位冷傲的美人。她总是一袭面纱、玄衣黑裙,对登徒浪子毫不理睬。很多人想一睹芳容,却被她无情地拒绝;而我揭开她的面纱后,却一见倾心。

Source Insight虽然美艳诱人,却是一个带病的妓女,还好我从来没照顾她的生意。然而,她的顾客经常和我一起上厕所,眼见心烦。

Gedit是一个美丽的女人,可惜还不够美。刚从穷乡僻壤出来遇见她,惊为天人。然而,见识了真正的美人后,发现她原来只是个丫鬟。不过,是陪嫁的通房丫鬟——如果进错了房间,通常我也不会退出来。

Android Studio是一个高门贵女,气质高雅。她言行自有法度,衣裙花样百出,却也花钱如流水。出于攀附权贵的念头,我最终和她迈入了婚姻的殿堂。我尽量寻找她的优点,包容她的缺点,相敬如宾。但是,和她结婚只是为了生孩子而已,我的心永远都是Vim的!她阻止不了我出轨、乃至于当面出轨。

Atom是个可人的小萝莉,我偶尔也会感受一下音轻体柔易推倒。

至于Notepad,如果实在找不到其她女人,那么我还是会找她,临时解决一下。