Python 项目工程实践

Python 项目工程实践

动态语言一时爽,代码重构火葬场

随着公司产品周期迭代和业务发展,使用 python 这种动态语言开发慢慢也暴露出一些问题,比如性能低、易出错、难重构、难维护等。 网上大部分是技术相关文章,工程相关的比较少。笔者就之前几年写 python 和维护 python 后端项目的经验简单介绍下如何提升 python 项目工程质量。


背景

很多创业公司初期为了市场竞争,产品快速迭代,使用了 python,ruby 之类的动态语言开发,动态语言的优势在于表达能力强,比较灵活,初期开发的时候速度比较快。如果公司顺利活下来,之后产品会更加注重性能、稳定性等,这个时候动态语言的缺点也开始慢慢暴露起来。有时候换语言和架构的成本是巨大的,而且很多场景也没必要更换(比如 Instagram 一直用的 python,都优化到了解释器级别,当然国内大部分公司没这个能力),我们尽量通过工程手段来控制项目质量,对动态语言扬长避短,更愉快地做项目。


知乎为什么继续用 python

出于以下几点原因吧:

  • 历史遗留问题,大量 python 项目
  • 写起来爽,做业务初期开发速度快
  • 基础设施支持比较完善
  • 有不少懂 python 的程序员
  • 大部分项目 IO 密集,初期使用 python 不会遇到性能问题

目前来看只有少数非常吃性能的项目用 golang 重写(golang 在并发和工程上非常不错),大部分场景 Python 够用,而且有时候新项目老板给的时间太短,换个技术栈还真不一定快速把业务做出来(少加班)


为什么要重视代码和工程质量

笔者这几年经历过各种 python 项目,见识过很多 python 程序员。之前维护过一些比较难以上手的代码仓库(无文档、无注释、无规范、无单测、风格混乱、逻辑超复杂)等,深知一个恶心的代码仓库多么要人命,离职的心都有。 实际上当初写 python web 入坑指南 并不是出于什么高尚的目的,只是实在受不了难以维护的 python 项目,把很多问题都总结了一下。

  • 方便新手和团队其他成员快速熟悉代码
  • 减少 bug,降低在修 bug 上的时间浪费
  • 方便业务快速迭代,兼顾开发效率(减少无意义加班吧)

很多时候一开始写代码只是很小一块,后来维护、修改 bug、增加新需求等,如果代码写得糙,后期修改成本就会很高,动态语言的优势几乎丧尽。很多使用 python 的中小公司,工程控制不够,流程不规范,很多代码仓库写得真是难以直视。


动态语言做工程的缺点

主要有以下一些比较明显的问题:

  • 解释性语言执行效率低,大部分时间用在 IO 密集场景,比如 web 后端
  • 开发工具支持不够完善,不如 java 有那么完善的 IDE,当然 Pycharm 还是不错的。
  • 难以重构。基本上重构只能依据字符串匹配,老实说每次重构有稍微大一些的改动都会有点担心,怕一上线就跪了
  • 滥用动态特性导致代码不好维护。这是个双刃剑,但是对工程来说还是不要滥用
  • 没有类型声明,看不出一些复杂类型的数据结构(Python、php 都在不遗余力地加上 type hint)
  • 缺少一些最佳实践(技术、小白文章偏多,工程实践文章比较少,很多自学者容易走野路子,不重视规范)

笔者当时选择去做 python 后端也是因为比较喜欢 python 语言,轮子多、生产力高、写起来爽等,但是一旦开始真正项目协作的时候,很多问题也必须要重视(不仅仅是技术问题)。 下面从开发环境、工具、流程、规范等问题上总结下如何提升工程质量吧。


开发环境

最好统一每个开发人员的开发环境,当然我们不能强制要求所有人都用一样的操作系统和编辑器、IDE 等,但是有些小问题还是比较麻烦的,比如不同系统的编码、编辑器的 tab 空格、自动换行等。笔者当初实习的时候团队里所有人都是登录到服务器上用 vim 写代码的,环境比较统一,现在基本大家都是 mac,一致的环境。当团队每个人用不同的工具的时候,可以采用以下一些工具来构建统一开发和编辑环境。

  • EditorConfig: 用来统一编辑器配置。如果成员用不同的操作系统和编辑器,建议使用。尤其是对于 python 这种使用缩进的语言。需要编辑器安装相应的插件,并且配置一个共同的配置文件加入到版本库(可以配置编码、缩进等)
  • Vagrant: 一款用于构建及配置虚拟开发环境的软件,基于Ruby, 主要以命令行的方式运行(没实战过)。不过感觉用 docker 打包成一致的开发时环境,减少各种奇奇怪怪的安装问题,能大大提升开发体验。
  • buildout: 知乎在用,把依赖包等安装到当前项目下。这样可以不用 virtualenv 之类的环境
  • pyenv/virtualenv/Pipenv: 构建 python 虚拟环境,之前没用 buildout 之前都是使用 virtualenv 构建本地开发环境。还是推荐用 docker 来构建一直的运行环境。
  • cookiecutter: 项目模板生成工具,每个项目最好用统一的模板生成,防止各个项目都是不同的风格,维护起来心累,同时也能快速启动新项目。(知乎内部有自己的生成模板)

开发规范

一般来说都是遵守 pep8,适当放宽下行长度限制,比如 120 列。如果有成员不使用 IDE,应当在其编辑器里加上对应的 pep8 检测插件,防止别人打开代码仓库后一堆语法警告。我至今还忘不了之前维护的代码仓库打开后,满屏幕飙红,一堆语法警告的恐怖场景。

  • autopep8: 可以集成在很多开发工具里,尽量都用工具来格式化,避免风格不一致的问题。
  • isort: 整理 python 包导入顺序,支持自定义配置,不用每次都费劲想着如何按照 pep8 顺序导入
  • pylint: 静态检测,能检测出很多代码缺陷和不合规范的地方,笔者强烈推荐。最好集成到 CI 构建工具里。默认的 pylint 检测过于严格,我们可以自定义忽略一些提示,可以参考这个 pylintrc 文件。我们的小项目里就在 CI 加上了 pylint,并且忽视了一些无伤大雅的警告(比如行长度等),帮助写出更 clean 的代码,当然如果有人不遵守规范,直接 CI 就不让你过。

我个人的想法就是尽量能用工具做的就不要让人去做,工具能保证风格统一,减少出错可能,人反而是最容易出疏漏的,这样就能把更多精力放在业务逻辑而不是调整格式上。项目大了以后代码的格式和排版等是很能影响开发心情的。

笔者个人用的是 neovim + python-mode 插件,基本上这些工具都支持,笔者写代码的时候格式也比较随意,只是改完文件后执行下 autopep8 和 isort (在vim里映射了快捷键),一切就又整洁了(类似于 golang 的 gofmt,js 的 prettier 工具)。感兴趣的可以自己试试,如果所有人的代码都像是从一个模子里刻出来的,维护起来无疑是最好的。

可能一开始制定各种规范、集成各种工具有些繁琐,但是长期来看绝对是值得的。代码除了快速实现需求外,最多的就是修改、维护、优化、增加功能、控制复杂度等,良好的代码质量很重要。而且一旦规范和工具成型,后续项目和其他团队都能受益。编码规范、静态检测、代码复查、单元测试是提升项目质量的几个有效方式。


开发工具

这个之前总结过很多用过和没用过的工具,感兴趣的看看 开发和编程工具


开发流程

很多公司慢慢把版本控制迁移到了 git,使用 gitlab 管理代码项目。一般我们的 git 开发流程是这样的:

  • fork 一份代码到自己的仓库
  • 本地新建代码分支开发新功能、修 bug 等
  • 开发完成后提交 merge request,有其他成员进行 code review。注意 commit 信息不能太随意,一般我们有一些提交模板。说明新增了哪些功能(需求文档链接)?修复了什么 bug(jira 链接附上并说明如何避免类似问题)?
  • 确认代码没问题合并到主干,每次构建都会执行单测、pylint 检测等

基本上这套 git 工作流程比较简单,目前也没有过什么大问题。


总结

每种语言都有自己的优势劣势,适用场景,通过规范、流程、工具等尽量提升我们的开发、协作效率、工程质量,争取更愉快地开发,减少无意义的加班。

Life is short, You need Python

Ref:

编码之前碎碎念(工程实践)

Python + Django 如何支撑了 7 亿月活用户的 Instagram?

编辑于 2018-03-16 18:19