企业级应用与屎一样的代码

最近在部门内组织了一场撕逼大会,几个 golang 组坐在一起聊一聊未来的应用应该怎么写。感觉收获颇丰。 在企业内部做开发的时候,实际上 99% 的程序员都不太在意代码的质量问题。这个比例我没有任何夸大,从上一家公司出来(倒闭)来到滴滴,又转过一次部门。经手了很多系统,个个也都是国内顶级公司(BAT)来的程序员们,但是代码写出来个顶个的垃圾。不管是维护还是阅读,都非常得痛苦。 一年多以来我一直在思考原因,刚开始的时候想法很极端,认为这些程序员就是基础不过关。但是在和很多人沟通的过程中发现,实际上大部分人都还比较聪明,并且务实而理智,分得清优劣,而不像是我刚来的时候想像的那个样子。 那为什么最终的结果却是写出了无数的垃圾代码呢?又经过了一段时间的思考,我大概总结出以下一些原因: 1.

  • Cao ChunHui
11 min read

关于 ofo

昨天看到大佬们讨论摩拜和 ofo 谁会成,马化腾提到 ofo 使用的是 token 锁。又想起来半年前和同事们讨论过 ofo 这种离线的会变化的锁密码是怎么实现的。那时候也没有细想,不过现在看着 token 锁这个词。。想起来之前写过的这一篇:关于token。原理应该都是一样的。 这里我们假装 geek。用上一篇讲的 token 原理可以很简单地设计出一套 ofo 这样的系统。先来看看 ofo 的系统有哪些组成要件: 车牌号 二维码 服务端返回的 token 值

  • Cao ChunHui
3 min read

如何使你的 golang 项目达到 awesome go 的入选标准

这两天想把之前写的工具提交到 awesome go 的 repo 里,所以特意研究了研究 awesome go 的入选 quality standard。 首先你的代码应该要在 goreportcard 上跑个结果: goreport goreportcard 其实就是几种 lint 工具跑出来的一个结果集合。先不说代码必须要过 golint 和 go vet,这两个 lint 大概一般有点节操的程序员都会上。这里面比较有意思而且陌生的主要是 gocyclo。 说到 gocyclo,要先讲讲代码的圈复杂度

  • Cao ChunHui
5 min read

从 information_schema 到自动生成的 web dao

一般的 web 项目大概会被分为这么几层: dao/model service/logic/repository controller view 大多数项目会做前后分离,所以后端作为 api 就剩下了三层。实际上这三层里除了 logic/service 之外都和具体的业务逻辑没什么关系。controller 负责参数绑定/校验,dao 负责和存储打交道。之前在 ast 一文中已经讲了怎么样减少 controller 中的工作。这里来说说怎么能够自动生成 dao 层代码。 可能平常只在固定的框架和 orm

  • Cao ChunHui
7 min read

golang 和 ast

大多数编译型的语言都逃不开词法分析,语法分析(语义分析)、编译链接几个阶段。学生时代如果学习过编译原理,啃过龙书,接触过 lex 或者 yacc 的话,一定还对当初要求一周做出一个编译器这种任性大作业的噩梦记忆犹新。编译原理这个领域本身有一定的门槛,随便给你一段程序,你也不太好说就能很快地给出一个可用的词法分析器语法分析器(里面还有相当的体力活成分)。 幸运的是,我们抱到了亲爹 google 的大粗腿。在 golang 里官方已经提供了一套非常友好的词法分析和语法分析工具链。可以很方便地帮助你得到你想要的语法分析的结果:ast。有了 ast 我们就可以上天了(笑。正经点说,是我们可以基于 ast 做很多静态分析、

  • Cao ChunHui
15 min read

分布式锁

大多数应用开发人员(特别是php开发人员,不是我黑php orz)对锁可能都没什么概念,如果说有,那大概也只知道数据库 transaction 里的锁。即使是知道 db 的锁,了解也非常得粗浅(比如去年的我)。 实际上数据库的锁非常的复杂,和 os 的锁的概念完全不是一回事,具体实现还和存储引擎、事务的隔离级别相关。所以这里还是不谈这个orz。等我有机会总结了之后再说。 我们这里要说的是分布式锁。分布式锁是什么呢? 在分布式系统中,某个任务可能会因为正确性或者效率两方面的考量,在同一个时刻内只允许一个实例执行。 正确性:例如有个游戏,每天凌晨0点,向所有玩家发放20金币的奖励,防止玩家输光了家当对游戏失去性趣。注意了,

  • Cao ChunHui
12 min read

业务系统错误设计

最近和同事讨论了几句错误设计的问题,感觉有必要写写自己的看法。 举几个例子,一般你的系统在运行的时候可能会有下面这些种类的错误/失败发生: 依赖组件挂了,可能是 db,可能是 mq,可能是 cache 依赖服务挂了,可能是别人给你提供的 http/rpc 服务挂了 可能是你的依赖方超时了 可能是调用方的参数有问题 可能是调用方的参数无法正确地通过校验 可能是用户的某种操作在业务逻辑上不具有合理性,不能够接着让他执行下去(例如你就给他一天一次抽奖机会,他不知道从哪里拿来的链接或者api又向你发送请求 还可能是程序自身出错了,比如数组越界,对字符串和数字进行加和操作,或者是把 null 当成了某种合法的数据结构,通过点或者下标来获取某种属性 上面这些情况都是有很大概率发生的,当这种情况发生的时候,

  • Cao ChunHui
9 min read

[译]Kafka Replication

某个群里因为消息队列和丢消息吵起来了,有人觉得 kafka 没有 ack,所以客户端缓冲会导致丢消息。 这理论有点牵强,即使真的丢消息也不会是因为客户端的缓冲问题。刚好之前仔细读过官方讲 Replication 的一篇 Kafka Replication 的 wiki,不是很长,但很详细地介绍了 Kafka 在做 producer ack 和 replication 的一些折衷。周末无事也就顺便翻译如下吧~以后查着也方便。 Kafka Replication High-level Design 为 kafka 加上副本是基于更强的持久性和高可用的考虑。

  • Cao ChunHui
13 min read

周末

周末本来准备窝在家里打游戏,惊闻b站大佬要来北京分享,赶紧起床去听课。期间也和其它公司的人聊了聊,感觉收获不少。 B站现在作为国内二次元的门户,聚集了大部分的动漫爱好者,因为业务模型和日本的 niconico 比较像,所以早期也肯定从n站的产品上学到了不少东西(这句是我说的)。从文化衍生出的直播、周边、游戏服务又能够帮助这个站点进一步地造血赚钱,比如现在非常火的FGO。因为这一两年B站关注度变高,所以即使是对二次元没什么兴趣的人也会感觉和b站有关的新闻越来越多了。比如去年在知乎上先后有 flv.js、2233娘竞拍的事情,也是把他们推上了风口浪尖。 很多70后80后可能都不一定会上B站,但是你可能想不到B站也是一个亿级用户的站点了。从09年创立到现在,在技术上他们也经历了从一个创业公司到越来越正规的过程。有很多方面我觉得做得比现在的公司还要好。挑几个值得说的总结一下吧~ Code Review 首先是我来了现在的公司一直头痛的 Code

  • Cao ChunHui
23 min read

[译]redis通信协议

Redis 客户端和 Redis 服务器使用 RESP 协议通信,RESP 是 REdis Serialization Protocol 的简称。尽管该协议是为redis设计的,你仍然可以把他用在其它的 client-server 架构的软件项目中。 RESP 协议是下面一些设计原则的折衷: 实现简单 解析(Parse)迅速 可读(Human Readable) RESP 协议支持 integer、string、array 等类型的序列化,同时对错误也设计了特殊的类型来进行支持。请求从

  • Cao ChunHui
14 min read

如何与低水平web开发联调

说实话这个标题可能比较欠扁。不过在这种辞旧迎新的气氛里还是觉得应该不吐不快吧。 从入职新公司到现在为止一年过去了,新公司的工作能发挥自己主观能动性的任务非常之少,除了年初在公司没有任何可用的垂直搜索方案的时候就自告奋勇地给自己部门搭了一套 es 集群,到年后将这个方案接入到公司公用的 binlog 信息流之中。再到后来为了接入方便开发了简单的 SQL 解析,以及工作时间处理各种集群查询、删除之类的操作导致的 OOM/GC 之类的问题啊什么的(感觉自己已经负责了不少运维的工作233)。其余的工作大多还是搬砖居多。 称之为搬砖一点都不为过吧,就是写写 CRUD ,写写 api ,然后和前端和其它系统和外部门的人来各种联调。 大公司么,总是会花多余的钱让稍微高级一些的人去干低级的事情。反正有钱。 话虽然是这么说,写写简单的 api ,过程也不是那么一帆风顺,

  • Cao ChunHui
7 min read

一次kafka 0.9的重复消费问题排查

部门的一个新项目使用了kafka 0.9来进行开发,不得不说目前公司的kafka版本真是够混乱,从0.8~0.10三个版本都存在,而我们部门在选择版本的时候则更加不慎重,追新追时髦,0.9刚出就直接开始使用了。还依赖一个不成熟的spring-kafka库来做开发,开发到快要上线遇到了消费hang住的情况,没有去深查源码,选择了去第三方库的方式。。。用官方的原生sdk来规避这个问题。说来运气不错,这个问题竟然被成功地规避掉了(233。 然后就遇到了紧接着的重复消费的问题,同事遇到了问题首先的疑惑是,为什么我使用了别人的demo代码,但在我的场景里才出现了重复消费呢? 嗯,好吧,我们来查一查。 一个kafka 0.9比较典型的消费一般是长这样的 main: for(int

  • Cao ChunHui
4 min read

重新探讨middleware

前面写过一篇中间件与责任链模式,最近被同事揪出来打了脸,感觉有必要再做一次学习和分析,下面就是新的学习成果~ 中间件 让我们从例子开始,我们发现网站的评论系统中有人恶意进行xss攻击,因此想要对用户的请求做简单的xss过滤,简单地来做的话可以对所有用户提交内容中的尖括号进行过滤。那么可以完成形如下面的函数: // input = `<script>alter(1)</script>script>` func XSSClean(input string) { input = strings.Replace(a, `<`, `[filtered]`, -1) input

  • Cao ChunHui
6 min read

后端程序员面试题

这些问题来自于github项目: https://github.com/monklof/Back-End-Developer-Interview-Questions 我整理了一些自己的答案,之后要是有想法了大概会陆陆续续更新吧(大概 说明 这篇文章翻译自一位外国友人的关于面试后端程序员的文章,我比较喜爱这篇文章。一是因为它极大的拓宽了我的视角,另一方面是其中的一些问题非常具有启发性。不仅对于面试者,对于面试官来说也是个不错的参考。于是迫不及待的翻译了一下,给各位看官做个参考。 这篇文章中,许多问题我并没有完全理解,所以翻译可能存在不准确的地方。如果有读者发现有一些翻译有误或者不好的地方,请不吝赐教。 原文参见 @arialdomartini的: Back-End Developer Interview Questions 以下是原文翻译。 后端开发面试题 在面试的时候,我并不特别喜欢问一些技术性的问题。

  • Cao ChunHui
25 min read

关于我们每天都在用的token

最近公司迁移机房,不知道为何用google authenticator来做验证。这下直接导致我们在这个公司有三种形式的token。。。实体token、宁盾和ga。真够麻烦。 不过迁移机房之后至少我们可以不用登陆windows server来做跳板,所有过程在终端完成。那么就可以直接用expect脚本来实现自动化了。问题就剩下怎么生成这个随时会变的token。 去github上找了找,结果发现离线生成ga的token竟然是可行的。这点和我当初想的不太一样。之前道听途说,token在服务端和客户端都用了非常牛逼的加密算法,所以才导致其破解不了。但实际上看来加密算法竟然是可以直接公开的。。对于这种算法而言,必须的条件就只有一个,就是分发给你的独一无二的key。用这个key在服务端和client端每30s进行一次计算,然后就可以得到一个六位数字,关心具体算法的可以看这里: https://github.com/cch123/googleAuthenticator 两边进行匹配即可。而在服务端识别key和用户身份则是通过当初把这个key分发到哪一个账户下了,也就是把key发给了哪一个人。

  • Cao ChunHui
2 min read

es stack升级5.0了

elastic官方为了统一混乱不堪的技术栈版本号直接来了个大跃进,把logstash/kibana/elasticsearch之类的东西统统变成5.0。 说起来我们用es也有一段时间了,感觉一路用下来总结的话,最坑的还是数据同步和各种深度翻页导致的full gc问题。再回头看看当初在博客上写的es相关的文章,感觉真是水orz,哪天有闲就删掉吧。。 这次升级5.0,官方把原来的marvel搭配了几方新药(security、alerting、graph等)作为一个新的组件x-pack进行发布。如果想要用x-pack的话,需要在es和kibana里分别用plugin进行安装。然后,因为穷逼们付不起一年好多好多刀的license,所以可以用最简单的free license凑乎一下。free license里只包括了monitoring,其实就是以前的marvel了吧。 要说对于使用方最大的变化嘛,就是什么head、kopf之类的插件这次全都不能用了。。。。官方表示site plugin有安全性问题,

  • Cao ChunHui
2 min read

初级程序员常犯错误一览

最近接手其他人做的项目,导致之前的一些幻想破灭了。因为刚工作的时候做项目是php,而php本身的web框架一般只简单区分mvc,稍微麻烦一些的会多个library或者helper之类的。这样分层很少有优点同时也有缺点。当然了,现代的框架一般支持namespace,你也完全可以借鉴其它语言来做自己的内部框架。这里先不说这个。 mvc的优点自然是简单,无论一个新人有没有做过相关的工作,你只要跟他简单说明每一层的职责是什么,马上就可以开始工作。缺点也非常明显,因为太简单,所以代码在累积到一定量以后会变得难以控制复杂度。同时容易让没什么经验的程序员把代码写得难以维护。 所以之前听说java的框架这方面做得好一些,然后对部门的java项目抱有一些幻想。不过在实际接手后,发现理想和现实真是有比较巨大的鸿沟。所以先来总结一下共通的初级程序员比较容易犯的错误吧。如果哪天自己带团队了,面试别人也可以拿这些题作为区分人的一种界限。做项目的时候有思考的人和不思考的人还是会有不小的区别的。 命名太啰嗦,或者不规范 这个问题其实挺普遍的,即使是科班出身的人,工作了很多年的人,写程序也可能冒出来一堆var a/

  • Cao ChunHui
23 min read

关于迅雷

刚毕业的时候在迅雷工作了半年,因为一些特殊原因,还是回北京工作了。中间乱七八糟的东西就不说了。 因为只在这个公司待了半年。。所以可能也不算学到了什么东西,只是大概地对这个公司的业务流程有了一些了解,写下来做个记录吧。 对于一般的用户来说,迅雷就只是个简单的下载工具。当年迅雷能干掉网络蚂蚁和快车成为最流行的下载软件,主要还是因为自身做的比较好(其实上市的时候ceo说是因为快车作者沉迷魔兽世界顾不上维护软件我会跟你讲? 作为一个从共享软件年代一路走到互联网时代的工具,迅雷还是有自己的一些创新点的。里面最重要的大概就是用base64加密磁力链接转成thunder链接了(误)。说正经的,其实是自称的p2sp。P2SP(Peer to Server & Peer),看全称,其实就是在p2p里加入了server来参与用户的下载流程。当然有人会说,一般的bt服务也会有tracker服务参与啊,你这个好像不算创新。那还是不一样的。tracker服务器实际上并不会存储具体的文件内容存储。只会存一些torrent的元信息。

  • Cao ChunHui
6 min read

使用sql来查询es

es的DSL实在是过于难用,相信使用过的同学都会有这种感受。而sql对于99%的程序员来说没有什么学习成本。 所以在工作需要的情况下,完成了这么一个简单的项目: https://github.com/cch123/elasticsql 把sql转换为es的DSL,这样你就不用每次都去写那个痛苦的DSL了。 这个库可以用来做什么呢?嗯,比如你在业务中用到了es,又不想去为了这套es培训所有人学会es的dsl,那么你可以使用它。再比如你想要实现一个支持sql的es的proxy,也可以把它当成你的一个模块来使用。 当然目前项目还在初期阶段,只实现了取数据部分。就是指定where条件,获取数据这种逻辑。count/sum/min之类的聚会还没有做,回头会加上。 不过where条件的话自我感觉支持还算完美,虽然目前还有点纠结sql里的equal应该用match phrase还是用term来做(因为match phrase要涉及到分词之类的逻辑,

  • Cao ChunHui
3 min read

谈一谈es的优势和限制

企业内部使用的elasticsearch是提供垂直搜索的一种方案,什么是垂直搜索呢。 先抄个百度百科: 垂直搜索引擎是针对某一个行业的专业搜索引擎,是搜索引擎的细分和延伸,是对网页库中的某类专门的信息进行一次整合,定向分字段抽取出需要的数据进行处理后再以某种形式返回给用户。垂直搜索是相对通用搜索引擎的信息量大、查询不准确、深度不够等提出来的新的搜索引擎服务模式,通过针对某一特定领域、某一特定人群或某一特定需求提供的有一定价值的信息和相关服务。其特点就是“专、精、深”,且具有行业色彩,相比较通用搜索引擎的海量信息无序化,垂直搜索引擎则显得更加专注、具体和深入。 其实说白了就一句话,垂直搜索是在企业内部使用的搜索引擎。这种搜索引擎的特点是,内容可能是一些结构化的数据,而不像大搜索那样都是杂乱的内容。 一般被拿来解决一些什么样的问题: 1.数据库字段太多,查询太慢,索引没有办法再做优化 2.数据库一个count就拖死全表。 3.

  • Cao ChunHui
14 min read

关于灰度发布

几个月前部门内容组织了一次系统设计的议题,分到我们头上的题目是设计一套灰度发布系统。嗯,然后我们就精心设计(参考公司现有系统)了一番,不过鉴于滴滴现在大部分的人都是百度来的(误,所以这种系统大概也都是差不多的思路实现而来的。所以感觉应该算是一种通用系统吧~ 为什么要有灰度发布系统?灰度发布是现代互联网公司比较必然的一种需求,像滴滴这种规模的公司,千万级的司机和亿级的用户,如果不经小规模实际业务场景测试(代码本身的测试流程先不算)就对线上流程贸然修改、重构并且上线,必然会造成群体性事件,影响到公司的形象,伤害到终端用户,并最终波及到码农可怜的年终奖。而灰度发布能带来什么样的好处呢?可以让你少伤害一部分用户啊~如果出了问题,回滚或者对影响到的用户进行补偿都很方便(毕竟钱能解决的问题都不是问题,但规模太大的时候补偿手段就不好使了。 实际上在一个系统的灰度策略执行期间,老的逻辑和新的逻辑的代码在线上系统都是存在的。这样说的话可能有些人会提出异议,我们在做代码发布的时候先发布一台机器,然后再发布十台,

  • Cao ChunHui
7 min read

beanstalkd 源码剖析

beanstalkd是一个使用还算广泛的开源消息队列,由c语言编写。因为本身功能简单,代码也不多,所以阅读可以帮助我快速复习一下网络编程,并且麻雀虽小,五脏俱全,一个c语言项目的方方面面它也都包含了。 ---入口 万事先从main函数开始: int main(int argc, char **argv) { //用来存储服务端生成的socket的fd int r; //job的链表 struct job list = {}; //程序名字 progname = argv[0]; //设置为行buffer模式,具体参见man手册,遇到换行即发送到目标 setlinebuf(stdout); //解析输入参数

  • Cao ChunHui
8 min read