作者简介:叶顺平,现在是国内某个著名的创业公司的技术总监,毕业于北京大学。他是待字闺中特邀作者。我们也希望有更多的作者投稿。
与Google相似,我所在的创业公司也是信仰“工程师文化”的团队,研发团队由Google前科学家、人工智能专家领衔,团队成员来自哈佛、MIT、斯坦福、剑桥、清华北大等名校名企。因为我们公司有谷歌的投资背景,和谷歌也有很多合作,加之主要创始人的谷歌背景,使得我们的工程文化与谷歌有相似之处。在此,我想谈谈我们公司的工程文化,希望能起到管窥谷歌工程文化的作用。
基础代码库
我们公司的很多基础代码,是从很多谷歌著名的开源项目的基础代码发展而来,包括chromium,re2,grpc等。强大简单的基础代码,既保证了工程质量和开发效率,又保证了我们使用和整合谷歌代码的高便捷性和一致性。我们的基础代码经常更新,以保证各个组所需要的相似需求,能够被高效实现和被良好地测试。我们在平时代码审查的时候,如果发现某个代码实现的不错,并且这个代码(函数,类,或者文件级别的代码)可能组内的其他同学,或者是其他组的同学可能会使用到,那么reviewer就会建议开发者将这段代码放置在基础代码目录下,并进行适当的重构和范化,提高测试的覆盖率。如果需要的话,也考虑在codelab中添加一些example代码演示如何使用。我们的基础代码库,会保持与时俱进。比如,gcc,g++等编译器会定时升级,以跟进语言的最新发展,同时也享受新编译器带来的性能改进收益。同时升级了新版本的编译器,我们会花时间解决在高版本编译器编译时带来的新的编译警告,保持基础代码的零编译报警(没错,在编译警告级别最高的情况下)。与时俱进的地方还在于,如果语言有新发展,我们会跟进,并及时重构基础代码。比如我们基础代码里,长期存在Thread,Mutex,MutexLock之类的代码,C++11推出后,这些都有了标准的实现,我们也及时重构了我们的这些代码,该重构的重构,该删除的删除,该添加deprecated编译警告的就添加上。相关的代码,也及时跟进。与时俱进的地方还在于,如果我们发现基础代码库的里函数,有了更高效的实现,我们就会重构相关代码,提高效率。比如有一些开源项目,比如stringencoders就对很多高效的C字符串操作的实现,假如我们基础库本来存在StringToLowerASCII的实现,但是实现方法很普通,那么我们就会考虑移植stringencoders,然后使用其内部实现重构我们的StringToLowerASCII函数,保持接口不变,但是性能却得到了很大的提升。第三方谷歌项目
我们内部使用了大量的第三方库,充分拥抱开源社区。其中第三方库里,谷歌开源出来的项目占比最多,在内部使用也最为频繁。以下简单列举一些谷歌的开源项目。RPC通信使用grpc对象序列化和反序列化使用protobuf压缩解压使用snappy简单的对象存储使用或扩展leveldb正则表达式使用re2日志使用glog命令行解析使用gflags单元测试使用gtestgmockCpuprofileHeapprofile使用gperftools有限状态转换机使用openfst机器学习平台使用tensorflow总之,谷歌有什么好用的最新开源项目,我们就会跟进使用。除了谷歌开源项目的优秀品质外,和公司内部统一的代码风格,也使得移植进来的成本比较低。另外,这些开源项目如果有一些新的版本出来,我们也会及时跟进。比如protobuf之前我们一直使用的是proto2,后来proto3出来了,我们也迅速跟进,老代码能迁移的就迁移,不能迁移的暂时使用proto语法,但是新代码强制要求使用新语法。像语音识别领域使用非常广泛的openfst,最新两年也推出了不少新版本,每个版本也会有一定程度的改动,甚至是接口不兼容。但是我们内部的态度一直是,如果是新版本,尤其是稳定版本,我们会尽可能跟进同步,哪怕需要解决一些编译失败问题。因为我们相信,花费的这些升级版本的时间,相比带来的好处,显而易见是利大于弊。我们早期使用百度的pbrpc作为protobufrpc框架,但是百度只开源了C++的实现,并没有其它语言的bindings,因此虽然pbrpc的代码我们虽然稳定运行了两三多,我们也在Grpc开源后,第一时间跟进迁移,因为grpc有几乎所有主流语言的bindings,方便我们跨语言交互,比如Java和C++,比如C++实现server,python实现debugclienttool。上面介绍的一些开源项目,后面如果有时间的话,笔者也希望有机会能做更进一步的介绍和分享。
编译工具
我们最开始使用的是国内的一个开源编译工具blade,后来年的时候,Googlebazel开源,我们第一时间将内部几乎所有C++代码都迁移到bazel进行编译。包括语音识别,搜索,语音合成,计算机视觉等所有AI相关项目。此外,我们的Java代码和python等语言的代码,也在慢慢迁移到Bazel。我们相信,统一的、简洁的编译工具,可以帮助工程师专注在功能实现上,而不需要纠结在编译过程中。统一各个语言的编译工具,也会促成前后端的协作,促成Java和C++的跨语言交互。最终的目标,当然是打造全栈工程师的环境,不管你写C++还是Java,还是python,你都可以使用统一的编译方式,部署上线也几乎毫无差别。我们公司里,一个写既写网页前端代码,也写Java和C++的后端代码,写安卓或者iOS代码的工程师不在少数,我想这也和公司追求的简单编译的开发环境和编译环境有关。我们内部实现了很多不同的bazel扩展,以更好地服务不同组的编译需求。比如语音组对GPU比较有需求,我们就研究怎么更好地在bazel中支持gpu,将GPU支持相关的编译都隐藏到编译工具内部,普通开发者基本不需要浙江最牛的医院专科医生名单都在这了,喜报:我校网球代表队再创佳绩