Becomin' Charles

算法 | LNMP | Flutter | Mac

Becomin' Charles

以前,我使用 Windows 作为自己的工作系统,后来,改用 Mac 作为自己的主要工作系统了。

在 Windows 下,快速搭建*AMP 环境,使用 xampp 或者 WAMP 之类的集成包,会一口气装好所有需要的软件,而在 Mac 下,相应的,做得比较好的是 MAMP,我选用的是与之对应的收费版本 MAMP Pro,总体差别不大。

阅读全文 »

前言

程序员圈子里流传着一个段子,说编程只有两个难题:缓存失效和变量命名。而我们中国有句古话,说:名不正则言不顺。这里面都提到了一个至关重要的问题,就是“取名字”。我认为,名字问题之所以如此重要,是因为,“名字”其实是对客观世界中实体的符号化表示。而这些符号,成为人类语言描述和思维的主要原料。如果名字有问题,就会严重干扰人类的思维。

目前的计算机,还只能按照完全确定性的方式去运行,而与之相对,人类的思维运转却存在极大的不确定性和任意性,如果说,编程实践总是由一个人完成,写出来的代码即可以运行,而不再需要阅读和与人合作,各种各样的规范,根本不需要存在;而事实恰恰相反。约束是为了更大程度的自由,所以,编码规范、命名规范,就是为了给所有共同合作的程序员一个基础。这个基础,可以帮助大家去提高效率,促进理解。

在最近两年的编码实践中,我感受到,数据库因为其特殊性(主要是总以服务形式出现,通过SQL语句操纵),其命名规范,别具一格,并不完全遵循一般编码规范的命名规则。而且,有时候,特意分开,反倒可以提高效率和促进理解。后面,我就展开列举一下,我们在实践过程中,习得的一些经验,这些做法未必是大家实践的准绳,但是希望可以给读者提供一个有效的参考。

通用

规范:全部使用小写字母

  • 编程一般都在计算机上,使用印刷体,小写字母有着很好的辨识度,而实际上,大家对小写字母的反应也比较快
  • 小写字母输入速度比较快,下文列举的一些规则,可能会导致字段名字比较长,都使用小写可以提高输入速度
  • 使用SQL语句操作数据的时候,我们喜欢大写SQL语句中的保留字(SELECT FROM WHERE等),使用小写命名表名、字段名,可以有效区分开

规范:使用下划线分隔而不是空格或者别的什么

  • 下划线可以分隔单词
  • 下划线在各种语言或系统中,一般都是有效的标识符的组成部分
  • 下划线是可见字符,不容易引起误会

规范:避免在名字中使用数字

  • 看起来很不好看

规范:尽量不要使用缩写、简写

  • 比如不要用addr,而是使用address
  • 做到顾名思义,避免误会和不必要的记忆负担

表名

规范:一般不使用前缀

  • 我之前待过的团队,曾有一种习惯,表名前加tbl_前缀,可能是为了与字段名区别开来,或者自动转化成变量名的时候,可以清楚地知道这个变量名来自于数据库,当然,实际上,这个前缀并没有显示出过多的价值,因为表名直接自动转化为变量名的机会比较少(分库分表的时候,表名容易成为变量名),另有一些方法,使得表名很容易区别于字段名和变量名
  • 对于视图(View),使用v_作为前缀,有助于程序员对数据库的理解和预防错误(比如,看到v_就不必尝试去update其中的字段了)

规范:采用单数名词

  • 一种争辩是:一张表,是一个集合,用复数更为符合客观实际,然而,实际上,并不能产生太好的效果,很简单,中国人对英语的掌握,以及英语本身作为一门自然语言的不确定性,都让复数表名变得麻烦重重,连英美人士都不认可,不要提中国人了,是 es 结尾,还是 s 结尾,特殊变形如 y 变成 ies,更有甚者,有些单词不可数,如何处理?
  • 很多框架,都设置了ORM层,单数的表名,比较有利于框架自动生成代码

规范:尽量短,最好不要超过两个单词,不要使用冷僻词

  • 主要是因为我们采用了用表名前缀字段名,表名短很重要
  • 容易记忆和书写
  • 写业务时候,不要用网络汉英字典去找名词,可以多看些业务相关的技术文章,或者找外国友人帮忙
  • 中国人理解和拼写较弱,如果选用难的、少见的词汇,容易给代码引入bug

字段名

规范:使用表名作为字段名的前缀

  • 以前我们团队里,给所有的字段前面加F,感觉没什么用
  • 使用表名作为字段前缀名,可以有效防止保留字冲突,比如order
  • 在联表查询时候,几乎不需要表名的alias,例如,很多表都有id、type、status等等字段,在联表写SQL语句时候,为了防止它们的混淆,经常要做额外的工作

规范:特殊字段类型添加后缀

  • 比如,在日期(Date)字段后面加_on,在时间(DateTime)字段后面加_at,也可以是加date或time作为后缀,关键是全团队的认可和保持一致
  • 可以有效提醒SQL撰写者字段的内涵,防止混淆

规范:外键前面也要灌上表名前缀

  • 比如,博客文章(表名为post),里面需要有一个作者id,命名为 post_author_id,而author_id是作者表(表名为author)的主键,post和author联表的时候,完全不会爆出任何字段名混淆(field name ambiguous)的错误

总结

我试图去搜索或寻找一些所谓的数据库命名方面的最佳实践,有些网友会推荐,采用微软SQL Server的范例数据库中的命名规范,并作出了相应的分析,但是我简要阅读了一下,凭直觉是无法比我们现在的做法带来更多的好处的。

另外也参考了一些StackOverflow上面高支持率的答案内容,感觉国外这个领域,也没有一个相对权威的说法,所以,我个人觉得,这个里面是如人饮水冷暖自知的一个情况,各个团队,还是要找到跟自己团队比较契合的一个规范。

不过,有一点我是相当确定的,就是有规范一定好于没有规范,现在一般都是团队作战了,规范的约束,可以提高整个团队的效率,避免了一些没有必要的学习成本。

参考:

http://justinsomnia.org/2003/04/essential-database-naming-conventions-and-style/

Git——以及所有一切的版本库——的核心目标,就是保证代码不会丢失。我所熟知的两个版本控制工具——SVN和Git——都是通过提交代码(commit)来实现这个目标的。

虽然我反对使用SVN来类比Git,但是,如果仅是为了强调它们的“不同”,而进行比较,我觉得还是有助于理解的。

SVN使用过程中,版本仓库是在云端的,程序员的个人电脑上,只是一个工作副本,或者叫代码暂存,如果写好的代码,没有被送到云端的版本库,就意味着有潜在丢失的风险。所以,SVN的提交(commit),其本质,就是将代码从本地电脑传送到云端服务器,这个过程,我们称之为“入库”。

阅读全文 »

说实在的,Git我已经学习了很久很久,从最开始的,零星的学习,然后偶尔使用,到现在成为公司的唯一版本控制方式,断断续续没有两年,也有三年。Git官网上写着,简单易用(easy to learn),我就是被这四个字骗了,开始用上了Git。现如今,它已经成为一种避无可避的工具了,必须学会。

要开始上手使用Git,可能真的是很简单的事情,如果你翻开一些成体系的文档或者书籍,可能上来会教你使用git init命令。这个命令的目的是创建一个新的git版本库。但是,就我个人的经验来看,一个新人,接触版本控制系统,可能第一件事情,往往是融入一个开发团队,接手一块业务,然后开始贡献代码,不太会是上来先建立一个版本库。

阅读全文 »

Git是目前世界上最为炙手可热的版本控制系统。它是如此的流行和重要,以至于全世界程序员的工作和生活,都可能因之而改变。

Git是一个版本控制系统,帮助程序员管理自己的源代码的版本变化,保证它们不会丢失。它只是开发工作中的一个工具。但是,一个“工具”,为什么可以重要到足以改变这个“工作”本身?我们可以以政治经济学范畴的概念,来理解一下这个问题,Git就相当于是生产工具,生产工具的发展,可以进一步解放生产力,从而推动了社会的进步。Git不是历史上第一个版本控制工具,显然也不会是最后一个,为什么到了Git出现的时候,就产生了近乎变革般的变化?

阅读全文 »

学习使用PHP怎么也有7年的时间了,竟然也没有注意到有个函数是array_replace_recursive,之前只知道array_merge_recursive,而且,这两个函数的返回结果,都非常地出人意料,不怎么符合直觉,而使用了Yii框架若干年,竟然也不知道有个CMap::mergeArray()方法,这个方法,如果跟前面两个函数混同起来看,竟然也显得有点离奇。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

[
'apple',
'orange'
],
'nested' => [
'A' => 'xx',
'B' => 'yy'
],
'single' => 1,
];
$b = [
'fruite' => [
'penapple',
],
'nested' => [
'A' => 'zz',
],
'single' => [
'string'
],
];
echo "array_merge_recursive: ", PHP_EOL;
var_export(array_merge_recursive($a, $b));
echo PHP_EOL, "array_replace_recursive: ", PHP_EOL;
var_export(array_replace_recursive($a, $b));
echo PHP_EOL, "CMap::mergeArray: ", PHP_EOL;
var_export(CMap::mergeArray($a, $b));

然后,我们来看一下这个用例输出的结果,相当神奇哦~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

array_merge_recursive:
array (
'fruite' =>
array (
0 => 'apple',
1 => 'orange',
2 => 'penapple',
),
'nested' =>
array (
'A' =>
array (
0 => 'xx',
1 => 'zz',
),
'B' => 'yy',
),
'single' => //注意这个东西的处理,简直莫名其妙!
array (
0 => 1,
1 => 'string',
),
)
array_replace_recursive:
array (
'fruite' =>
array (
0 => 'penapple',
1 => 'orange',
),
'nested' =>
array (
'A' => 'zz',
'B' => 'yy',
),
'single' =>
array (
0 => 'string',
),
)
CMap::mergeArray:
array (
'fruite' => //这里选择了array_merge_recursive的行为
array (
0 => 'apple',
1 => 'orange',
2 => 'penapple',
),
'nested' =>
array (
'A' => 'zz',
'B' => 'yy',
),
'single' => //这里却选择了array_replace_recursive的行为
array (
0 => 'string',
),
)

实在是没有心力去把所有的用例想完整,只能随便写几个,从中可以看出来,这些函数的处理规则,不是简单可以说清楚的。

  1. 对于包含了字符串键的数组,是逐个键去做merge或者replace的
  2. merge:对于键的值都是纯数组的情况,单纯合并
  3. merge:对于键的值都是非数组的情况,创建数组添加两者作为元素
  4. merge:对于键的值一边是数组,另一边是非数组,结果就匪夷所思了,将数组降维后,按上一条规则处理
  5. 相比之下,replace的行为更具被一致性,就是纯替换
  6. CMap::mergeArray 则跟两者的行为都有所不同,我也是跪了

当然,问题绝不止这么几个,只是我懒得想全所有用例而已。

之前已经写了蛮多的跟这个事件驱动特性有关的内容了。比如我今天发现,Yii 框架支持的事件驱动,只能支持对对象实例进行事件绑定。简单来说,当你要绑定某个事件的时候,这个事件的触发者的对象,必须已经建立好了。

阅读全文 »

Yii框架的特性列表里,有一项叫“Event Driven”,所谓的事件驱动,但是在实际业务开发实践中,我发现即便有应用场景,大家也倾向于不用,究其原因,还是不熟悉。

当然,我认为,作为Yii框架的官方开发团队,没有在这方面给出充足的,合适的例子,来说明这个特性的使用场景,也有着不可推卸的责任。

生搬硬套,为了使用event而去使用event,这种是我们坚决要杜绝的行为,那么到底在哪里使用这个特性才显得恰如其分呢?当然,笔者也没有一个非常好的标准去判断,只是偶有所得,在此跟大家分享一下。

阅读全文 »

故事是这样的,在我的业务模型里,有些东西是常态并且固定化的,比如User,这是一个网站的用户,有一张用户表与其对应。但是有些东西,却不是那么常态,比如我们的网站要经常搞活动,搞活动的时候,临时开发一个功能,加一个表来存储活动数据,日后,活动下线了,这个表也就没有用了,可能会被删除。活动频次非常高,所以不同的开发都会快速地进行开发,于是出现了命名不一致的情况,比如大家都是要关联User(活动跟用户有关,非常自然),在表A中,代表用户的字段叫user_id,表示User的主键,但是在表B里面,因为习惯使然,代表用户的字段叫uid,然后问题就产生了,当表A和表B需要联表查询时候,怎么设置这个relations呢?

阅读全文 »