软件工程实践之 django/python

栏目: Python · 发布时间: 5年前

内容简介:软件工程实践系列文章, 会着重讲述实际的工程项目中是如何协作开发软件的。 本文主要介绍了 django/python 系列的工具链。本文包括以下内容:

软件工程实践系列文章, 会着重讲述实际的工程项目中是如何协作开发软件的。 本文主要介绍了 django/python 系列的 工具 链。

outline

本文包括以下内容:

  • outline
  • django: 一个搭建后端服务的工具箱。
    • framework: django vs flask/tornado/spring/laravel
    • restful: django/restframework/swagger
    • worker: django/uwsgi/gevent/celery/channels
    • database: django/mysql/sqlite/migrations
  • python: 一门依赖开发者的语言。
    • developing: gitlab/pipenv/docker
    • quality: unittest/pytest/flake8/pylint/yapf
    • deploy: fabric/aws/nginx
  • conclusion

django

django 是一个大名鼎鼎的后端开发框架, 它自己的口号是 the web framework for perfectionists with deadlines.

在我用 django 开发的这几年来, 我觉得它是一个逻辑上自洽, 并且为了逻辑自洽甚至舍弃了一部分功能的框架。

framework

软件工程实践之 django/python

search google for django vs

讲框架避免不了的是同行竞争, 比如到网上搜一下 django vs ... 就有一大堆搜索结果。 其实框架之间的比较是很难的, 每种框架都有自己适合的业务场景。

软件工程实践之 django/python

xkcd-927: standards

django 最大的特点就是 Model 是一等公民 。 在 django 中的所有的操作都会跟 Model 相关, 比如它提供了自带的强大 ORM, 也有一系列挂载在 Model 上的校验等。

个人感觉在项目的业务需求达到了某种程度的多样化以后, 基础框架用什么并不重要, 适合开发团队才是最重要的。

鉴于本文的标题是 django, 所以我们只讲 django。

restful

我参与的项目基本都是前后端分离的项目, 后端提供的接口都是用 djangorestframework 写的。 虽然像 HATEOAS 这样的高级属性还没用到, 但接口是遵循 restful 风格的, 比如像用 http method+status 表达语义, 对资源的定义等。

接口文档我们选用了 drf-yasg 来生成符合 swagger 规范的文档。 曾经我们也试过 django-rest-swagger 这个库,不过……

软件工程实践之 django/python

another help-wanted project…

使用现成框架的好处是语言表达力极强, 最终我们实现一个“解密微信提供的手机号”接口的~~伪~~业务代码大概如下:

class WeChatVS(BaseVS):

    @with_response(empty=True)
    @with_request(DecryptionSiri)
    @action(methods=['post'], detail=True, url_path='decryption/phone')
    def decrypt_wechat_phone(self, request, uid):
        """ 解密并修改用户的手机号
        - https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html
        """
        self.check_account_request(request, uid)
        openid, encrypted_data, initial_vector = self.request_data
        phone = WeChatManager(openid).decrypt_safely(encrypted_data, initial_vector)
        # TODO(ldsink): 找产品问一下外国手机号怎么处理
        hutils.check_error(not hutils.is_chinese_phone(phone), 'o(╥﹏╥)o 目前只支持国内的手机号')
        self.account.modify(phone=phone)
        return self.empty_response()

这样的十行代码包含了文档、外链、错误检查、写库, 让写业务代码本身也有种施法的快感。

worker

最开始服务器上我们跑的是 django+uwsgi 的普通模式, 用 wrk 去压一个小接口, 测试环境 4G 内存的机器 QPS 只有 40 左右。 后来加上了 gevent, monkey patch 一下,改到了协程模式 同样的接口同样的机器 QPS 上升到了大概 600。 调优一下效果会更好。 (需要更高性能的业务可能就根本不用 python 了 Orz)

celery 充当了我们的定时任务+异步任务框架, 我们也拆分了 读写密集型/计算密集型 的两类队列以处理不同的事情。 对于业务中的即时通知部分, 我们用了 channels 库来实现 web socket 的功能。

对于这些大型的框架,其实我们选择余地并不大。 比如虽然 django 开发者有说在 3.0 会考虑大幅度重写异步调用, channels 项目会逐渐弃坑…… 但毕竟 perfectionists with deadlines. 不能说人家功能不完美,我们就不干活了嘛…

database

我们用到的数据库也是 mysql/mongo/redis 这御三家, 所以就是每个选取对应的连接库就是了。

值得一提的是在单元测试里, 我们用 sqlite(in-memory) 替代了 mysql 数据库。 sqlite 里缺失了 mysql 的函数的问题, 也可以用 connection.create_function 的方法来规避掉。

在上线时,还有一个很好玩的东西是 database migration , 这个基本上跟“给行驶中的火车换轮子”一样刺激。 详细的细节以后会专门开篇文章讲一下(挖坑预警), 从结果上来说我们做到的是 利用 Django Migration 做到数据库结构变更全兼容

python

上面一小节中,我们基本上是走马观花地过完了 django 相关的三方库。 到了真正用 python 开发的时候, 我们遇到的更多的是框架之外的奇遇。

每门语言都有自己的味道。 我很喜欢 python 的一点是: 这门语言有着非常强的表达张力。 就像上面举的那段典型业务代码一样, 在实际的开发中, python 是能完美表达开发者心中所想的。

但假如开发者自己都没想清楚自己要写啥, 这就有点不妙了。

所以我们有一系列的开发工具来保持清醒。

软件工程实践之 django/python

强制清醒.jpg

quality

软件工程实践之 django/python

贺师俊在《如何引导 程序员 新人按正确的流程开发?》下面一段我很欣赏的回答

除了开发流程上的类似要求, 我们对代码本身也执行了类似的严格要求:

  • 单元测试覆盖率必须得在 96% 以上 (unittest/pytest/coverage)
  • 代码的逗号、换行、引号的使用都必须符合规范 (flake8)
  • 代码强制经过 linter 检验,禁止多种黑魔法 (pylint)
    • 代码的各个模块之间必须符合特定的拓扑顺序 (pylint-topology)
  • 代码风格(如字典的复制、长列表、换行与空行)强制统一 (yapf)

其中 单元测试覆盖率必须得在 96% 以上 值得被单独拎出来表扬一下。

业务代码的 96% 的覆盖率是什么概念呢? 这意味着代码里只有那种真正的边缘情况是没被测到的。 (比如为了兼容微信 SYSTEM ERROR -1000 写的代码)

为了达到了这么高的覆盖率, 我们也专门强化过单元测试的表达力, 比如一段测试创建用户接口的~~伪~~代码可能如下:

def test_create_account(self):
    """ 测试创建用户 """
    with self.assert_model_increase(Account, delta=1):
        response = self.client.post(self.account_url(), {'username': 'hulucc'})
        self.ok(response, username='hulucc', tags__length=0)
    with self.assert_model_increase(Account, delta=0):
        response = self.client.post(self.account_url(), {'username': 'hulucc'})
        self.bad_request(response, message=AccountErrors.DUPLICATE.value)

软件工程实践之 django/python

所有这些限制都在 CI 中检查了,不通过的话是不让 merge into master 的

developing

我们的合作方式是用 gitlab 作为代码托管平台。 为了团队的开发效率, 我们还自己写了个小机器人来处理各种如分支合并、有效性检查、贴标签之类的杂活。

gitlab ci 不仅被用来做开发阶段的质量保证, 最终我们的构建上线也走的是 gitlab ci (以前我们用的是 jenkins)

软件工程实践之 django/python

对于 python 的依赖管理, 我们用的是 pipenv, pip list 一下大概有了 181 个库。 (关于 pipenv 的介绍可以参见 《Python 依赖管理的未来 - ldsink》 )

也因为我们线上用的是 docker, 所以不想装依赖的也可以直接用 docker 的环境开发。

deploy

部署这一块我们暂时还没上 k8s, 目前走的是 gitlab ci 中调用 fabric + aws(boto3) 直接操作裸 docker 的方式。 aws 的负载均衡器提供了基础的流量切换服务, 我们也是借用了现成的服务达到灰度发布、无缝发布的效果。

软件工程实践之 django/python

用 GitLab CI 部署的步骤图

conclusion

至此,本文介绍了一遍我们在 Python 业务后端的实践。

对于高可用、容器化、数据库等屠龙技, 业界其实有非常多的探讨, 大家也很容易找到现成的文章。

但具体到业务后端的工程化实践, 能借鉴的大型项目并不多。 我读过的也只有 两年前的 reddit 代码sentry 这个 django 项目符合要求了。

总的来说,我们用 django 在开发中遵循的约定跟共识有这些:

  • 做正确的事情。
    • 比如我们在讨论过后,一致觉得“线性的 Commit 历史是最干净的”,从当天开始我们的 Commit 历史就是干净的线性历史了。
  • 自动化一切能自动化的工作。
    • 用 swagger 自动化生成文档,用 gitlab ci 自动化质量保证。
  • 尽可能使用最新的特性,让代码时刻保持崭新。
    • 我们每隔一阵就会把所有依赖升到最新的稳定版。
    • 不过因为这个我们也踩了不少坑。
    • 不少时候三方库会引入全新的用法,动辄改动 100+ 的文件数。
    • 这个时候就到了 Vim Macro 展现魔法的时候了。

假如你也在用 Django 作为后端框架的话, 不防尝试一下上面提到的各类工具, 绝对物超所值噢 :)


以上所述就是小编给大家介绍的《软件工程实践之 django/python》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

大型网站系统与Java中间件开发实践

大型网站系统与Java中间件开发实践

曾宪杰 / 电子工业出版社 / 2014-4-24 / 65.00

本书围绕大型网站和支撑大型网站架构的 Java 中间件的实践展开介绍。从分布式系统的知识切入,让读者对分布式系统有基本的了解;然后介绍大型网站随着数据量、访问量增长而发生的架构变迁;接着讲述构建 Java 中间件的相关知识;之后的几章都是根据笔者的经验来介绍支撑大型网站架构的 Java 中间件系统的设计和实践。希望读者通过本书可以了解大型网站架构变迁过程中的较为通用的问题和解法,并了解构建支撑大型......一起来看看 《大型网站系统与Java中间件开发实践》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具