相比于“一门语言”,
“一门程序语言”更多时候是“一门规范”。
(当然,“语言”本身就是“规范”。)

上次讲到了写代码想偷懒的话,
搞明白、想清楚再写是解决根源的一个办法。
但是凡人(没打错字)的需求始终不是重点,
写程序要偷懒,
最终还是在代码上偷懒的。
Best Practice
外国程序员很喜欢念叨一个词,
叫Best Practice。
比如说Java里面JSON要怎么处理,
就可以搜Java JSON Best Practice;
比如我对数据库一窍不通,
但我就是要学,
可以搜Database Best Practice;
比如我是甲方,
我不知道我自己想要什么,
我也可以搜Requirements Best Practice。
这种英文单词一般会有一个直译的中文,
叫最佳实践,
听起来巨蠢。
但是用来举例子就很好用。
我加入再惠的时候,
只写过一点Python,
代码习惯也是不加encoding,
不知道from __future__,
写print不写括号的,
所有要用到的第三方库都装在全局的site-packages下面。
来了以后我知道了virtualenv。
后来张总玩Lucene的时候我给他配了下Gradle,
并解释了一下:“这个东西很简单的,跟virtualenv是类似的概念。”
张总感慨道:
“其实学一门语言就是从这些工具开始啊,
这样才有一种我上手了的感觉啊!”
还有就像Go语言的gofmt命令,
这个命令会强制执行统一的代码风格调整,
不能配置、不能定制化、缩进统一使用Tab。
我十分痛苦,
不过也十分认可这里的思想:
“语言风格就是林黛玉哈姆雷特,千人千面。
相比于完美的风格,统一的风格更科学。”
Best Practice就是实际操作时的指南,
了解、掌握、实践Best Practice可以少些很多代码少走很多弯路,
用精妙的方法解决实际问题。
精妙的方法
按照套路,接下来应该讲一段精妙的方法。
不过小弟我没啥精妙的方法,
就只能举自身当反例了。
在写API的时候,
经常要处理URL,
处理URL实际上是字符串拼接。
比如Python里面把一个dict转换成query string格式,
我以前会这么写:
params = {'name': 'afu', 'action': 'take a plane'}
query_string = '&'.join(['{}={}'.format(k, v) for k, v in params.items()]) # 'name=afu&action=take a plane'
当时自我感觉良好,
觉得Python不愧是Python啊,List Comprehension真优雅,真好看。
然而这段代码不仅有Bug,
其实Python有专门的库urllib来处理这类问题,urllib也已经考虑了各种边界情况(比如带非法字符等):
# 举Python3为例
import urllib
params = {'name': 'afu', 'action': 'take a plane'}
query_string = urllib.parse.urlencode(params) # 'name=afu&action=take+a+plane'
后来又学到了urlencode函数在Python2和Python3的位置都不一样,
一般是用six这个库去处理兼容性的。
下面这段代码就不需要额外说明_举Python3为例_了:
import six
params = {'name': 'afu', 'action': 'take a plane'}
query_string = six.moves.urllib.parse.urlencode(params) # 'name=afu&action=take+a+plane'
虽然有很多种方法都能达到同样的效果,
但软件工程中,
大家往往都定下一个Best Practice然后遵守它。
这样不仅能省下写程序的功夫,
也能省下沟通争辩的功夫。
就像Zen of Python里说的一样:There should be one-- and preferably only one --obvious way to do it.
之前我一直很好奇大部分人在用Python写datetime类型的时候,
都是用import datetime+datetime.datetime(), datetime.date()的写法,
我就一直不解,from datetime import datetime, date+datetime(), date()这样感觉更好啊?
而且后续的代码更短。
后来读到Kenneth Reitz的Hitchhiker's Guide to Python的时候我才明白,Explicit is better than implicit的体现就是显式指定包名,
这样代码表现力就会更强,也更易读。
## Very bad
[...]
from modu import *
[...]
x = sqrt(4) # Is sqrt part of modu? A builtin? Defined above?
## Better
from modu import sqrt
[...]
x = sqrt(4) # sqrt may be part of modu, if not redefined in between
## Best
import modu
[...]
x = modu.sqrt(4) # sqrt is visibly part of modu's namespace
从学到这一点以后,
我就下定决心再也不用from datetime import datetime了。
总结
Best Practice这种东西,
看起来很美好,
用好了可以大大偷懒减少工作量。
但它有一个重要特性:Best Practice从来不是试出来的,
而是思索、学习、择优得到的。
多加一个if,多加一个机器,多招一个人,多加一点班
可能只能解决当下的问题。
平时多学习一个,
才能到了要解决问题的时候,
面临技术、业务、上线时间的多重压力,
优雅地使用Best Practice解决问题。
总的来说,
为了偷懒 少干活提高效率,
我们又定下了这么些小目标:
- 多学习一个
Best Practice - 学到了就用,能用精妙的方法就不用愚蠢的方法
- 通过思考来学习,而不是完全通过试错反馈机制来学习
毕竟编程风格可不能是散弹枪编程呀。