一、数据库设计过于注重范式,导致业务查询困难,速度慢,优化难。
原因:项目刚开始,每个人都想把公共的逻辑进行抽取,在数据库设计上追求不冗余。
具象:一个资源表完整查询要连4张表,为什么会有4张?一张是公共的文件表,业务中所有的文件都存放在这一张表中;一张是资源主表,负责存储资源业务的字段,两张是资源表标签表!标签表为什么要两张?因为不想有冗余数据。大家很容易接受一个资源有多个标签,资源标签表单独一张无可厚非。
恶果:在根据业务建立好索引,联表查询4张表的时候,40W数据,没有用group by(distinct)进行去重的时候是0.03s,一用就变成了9s。主要是在用group by(distinct)的时候,出现了万恶的filesort。
查询列表时临时性优化的策略:因为要用group by或者distinct进行去重,所以根据查询条件,进行动态联表。查询结果返回主键ID和结果总数。列表需要的字段,用ID单独查询后组成返回。但是一旦要联4张表的时候,优化失效,查询还是很慢。
后期优化方案:1、待业务稳定后,将其整合为2张表即可。2、第三方搜索引擎:ES或者sphinx等
二、PHP小版本的差异
出现错误:PDOStatement::execute(): Unknown type 245 sent by the server
原因:MySql用到了json字段,PHP版本无法解析不了MySql数据库的json结构,导致查询一直没有完成。
出现现象:我本地环境PHP版本为5.6.16,程序没有报错。开发环境上的版本是5.6.14报错。搜索出来的答案是5.6.13。
解决方案:让运维把全部环境的PHP版本给升级了。(希望不要被运维的同学拿刀砍)
结论:环境的统一真的很重要,哪怕是差别两个最小版本的PHP也会出现问题,对环境不相同,必然会发生因为环境的差异的错误。
三、对程序语言细节的特性的忽视
现象1:var_dump("kkk"===0);
会输出 bool(true);当PHP字符串与数字进行比较的时候,若字符串中首位有数字,则用首位数字与数字进行比较,否则将字符串将转为0。
现象2:php用curl 传递参数,多维数组要用用http_build_query,但是build后,发现传递是整形的数字变成了string类型。
示例:$post_data = http_build_query(["key" => ['integer' => 10]]); 接收后json化输出:{"key":{"integer":"10"}}
对于PHP这点,如果要严格字段类型,只能通过事先约定进行避免。虽然phper的我们不会太在意这点细小的差异。但是有时对于我接收方要求严谨类型的时候,这就成了我们的灾难
现象3:有两个类分别为A、B。在A中有个方法实例化了B,在调用B中方法时,无法再实例化A。
现象4:PHP无法通过http访问本地IP共享的文件夹,却可以通过CLI的形式去访问
这个问题找了挺久,实在是找不到原因。而且通过CLI已经实现了功能,工作上并没有更多时间让人去深究这样的原因。
现象5:c++在客户端传空格给php,要将空格转换成+号,PHP无法识别
原因:
意外收获:这个我是刚在搜索http_build_query函数时,发现的。之前我也不清楚是什么原因。
现象6:c++开发问题,请求PHP接口,搜索时传递三个汉字无法返回结果
原因:由于两个汉字为3字节一个 加上一个空 为奇数,转码时可以找到尾部,3个是为偶数,找不到尾部,故而PHP无法解析。
现象7:用Python脚本上传文件到OSS时,出现文件为空的现象
原因:python 用 file open a,当a.read()只能读一次,再读第二次为null。我们想象中的是多次读是一样有内容的。
恶果的解决方案:把OSS上的文件遍历一遍,发现空的,重新上传吧。
四、惯性思维的盲区
现象:开发时是只用一个账号进行调试,或者只按照自己设计的程序思路去调试
后果:自己跑的时候完全没有问题,一到其他人手上就出现了问题(bug)
对于这个问题,是不能有明确的界限定义的。因为程序即使是通过了测试,上线后的程序也会出现bug。谁也不能保证没有bug的程序出现。
举个例子:我在Yii里面用了seaslog插件,默认的路径是按照“模块/控制器/方法”的规则去设置的,而Yii无论是跑http请求还是跑cli请求都会有经过模块-控制器-方法,但是单元测试的时候,就不会有这些,所以程序必然报错。
其实我们在设计程序的时候,是基于需求下进行设计的,而对于需求之外(边界之外)的情况,我们的程序就要给出合理的回应,而异常是我们惯用的手段。
在我举的这个例子中,如果我不写单元测试,可能我永远都不会发现自己的程序有漏洞。所以有些bug,只是潜伏在你的代码里面,但一旦爆发就会是灾难性的。如果要避免自己少惯性思维的错误,还是对自己的程序对多测试,或者进行的code review。
五、多人协助,缺乏架构和统一的指导
现象:我们目前是开发一个平台,平台中有许多应用。一个开发者可以要开发几个应用,而多个开发者共同维护一份代码
目前暴露的问题:
1、应用之间的耦合度高,许多应用无法进行单独部署。直接导致公司在做销售策略上无法灵活应变。因为我们只能做捆绑销售,必然导致客户的成本提高。试问哪个客户会是傻子?
2、代码重复,应用间存在业务性的重复,但是在代码上没有人将其进行整合。重复工作是必然的。一方面,无形间是增加了公司的开发成本。另一方面是各个开发者无法感知其他其他开发者做的事,即是无法站在全局高度上去思考的问题,:最终限制了开发者自身的发展。
目前解决方案:目前我们的技术经理担当起了统领全局的职责。将平台的公共模块专职交由一个人进行负责,让一个人将各个应用的开发者进行联系起来。“代码集体所有,个人负责到应用”,这是技术经理的提倡的思想。
六、总想搞事情,但是总搞不好!!!
现象1:在10月份的时候,平台会出一个重大的功能版本,作为一个里程牌。但是在开发重大功能的同时,前端对其架构进行根本性的调整。导致平台的新功能延期了一个多月才能进行交付。
原因:而前端对其架构做了根本性的调整的时候,并没有做好全面性的测试,再者根本没有人去评估风险。即是除了前端的负责人,跟他关联的人压根没有收到任何评估的通知,只能被动的配合。
在我看来,一次迭代只做一件事,永远比一大堆功能扎堆上线要稳妥。同时,作为一个项目的负责人,更加要兼顾全局,不能自嗨!
现象2:在7、8月前,我们规划出了一个支撑平台。目的是:1、作为业务应用的数据来源;2、将业务应用的公共功能进行抽取为公共服务,转由支撑平台提供。进而实现快速生产业务应用的效果。但是直到现在支撑平台还没有能全面的落实。
原因:开发支撑平台的人,想做的事情太多了。按照公司现阶段的业务,支撑平台就是做一个Auth验证和一个路由器的功能即可,其实就是一个企业服务总线(ESB),因为公司已经存在提供数据来源的应用和一些公共服务。至于负载均衡、日志和统计分析的事情,可以设计留白,往后慢慢再实现。
我的观点是,从小变大,做好框架,随时应变。
小结
坑,总是令人成长的,多么痛的领悟。但是,无论是做什么,生存下来才是硬道理!