Python Web入坑指南一

作者: QingLeiLi | 来源:发表于2018-05-16 17:33 被阅读10次

    小白的踩坑记录

    Python->You need it

    文档化

    团队项目开发前的统一三要素:统一需求/开发文档,统一代码规范,统一环境(编译/测试/发布)。 很多程序员是懒得写文档的,仿佛牛逼的程序员不需要写。但是看人家真正牛逼的开源项目比如flask和tornado等,无论是代码还是文档都做得相当棒。对于一些项目,有些东西如部署步骤;常用命令等还是可以记录下来的,可以使用wiki或者readthedoc,gitbooks等文档工具记录一下,方便新人上手。如果不知道记录啥,就把你发现不止一次会用到的东西文档化。个人认为需求文档也应该有历史记录,方便接手的人可以快速了解业务和需求变更。数据库字段的含义也应该及时记录和更新。

    只有少数很复杂的系统需要详细的文档,架构图、UML、数据模型、处理流程、业务逻辑等需要整理成文档。Write the minimum viable system documentation.

    代码分支与代码管理

    做好代码分之管理,分清楚开发、特性、bugfix等代码分枝,不要在同一个分之上一下修改太多功能,导致修复问题不好定位。比如经常和同事做一个需求,结果一个人把几个需求堆到一个分之改了,把不该上的功能也给上了,这种小细节还是需要注意的,否则就会给测试、上线等带来严重麻烦。命名分之的时候注意使用有意义的命名,比如附带上task的号码,jira号等等,把分之和你要解决的问题关联起来。

    注释

    有经验的人都知道看别人的代码是一件很痛苦的事情,尤其是没有任何注释的代码。代码除了完成需求外,最重要的就是维护和协作,除非你觉得你做的项目活不过仨月(或你自己玩玩的项目随便你怎么艹),否则就一定要重视代码质量,防止代码腐化(破窗)以至难以协作和维护。有时候比写注释更难的是知道何时写,写什么注释?python里有规范的docstring用来给类和函数进行注释,除了说明功能外,关于github,stackoverflow链接、复杂的传入传出参数(比如嵌套字典作为参数这种你都不注释就很不合适了),类型说明、需求文档和bug的jira地址等都可以注释。凡是你回头看代码一眼看不出来干啥的,都应该有适当的注释,方便自己也方便别人。

    当然,最重要的是代码清晰易读,好的命名和编写风格的代码往往是自解释的,看代码大致就可以看出功能。建议就是给所有的模块、类和函数都加上注释,除非一眼能看出来这个东西干啥,否则都应该简洁注释下,让别人不用一行行看你的代码就大概知道你这个东西是干啥的。最后注意的就是一旦函数更改及时更新注释。qiniu的sdk写得就不错,可以去github看看。总之,”Explicit is better than implicit.”, 代码里不要有隐晦的东西,一时偷懒将来可能会付出几倍的维护代价,请对将来的自己和他人负责。

    日志与异常记录

    一定要有良好的日志记录习惯。良好的日志对于记录问题至关重要。python有方便的日志模块帮助我们记录,日志输出的代价是比较小的,python的日志模块尽量做到对函数功能没有性能影响,可以在线上和开发环境设置不同的log等级,方便开发调试。注意别再日志语句里引入了bug或异常。有时候需要判断什么时候需要日志,记录哪些东西方便我们排查问题,分析数据。 对于异常,一定『不要吞掉任何异常』,常有新手上来就try/except,也不区分非退出异常,也没有日志记录(坑啊......)。请先阅读python文档的异常机制,可以使用Sentry等工具记录异常。同时发生异常时候的时间,调用点,栈调用信息,locals()变量等要注意记录,给排查错误带来便利。有些错误的复现是比较困难的,这时候日志和异常的作用就凸显出来了。

    《每个 Python 程序员都要知道的日志实践》

    《日志的艺术(The art of logging)》

    调试

    调试也是个很重要的问题,不可能保证代码没bug,要命的是有时候写代码完成功能的时间还没调试的时间多。注意复现是排错的第一步,之后通过各种方式确定原因(访问日志、邮件报的异常记录)等,通过走查代码、断点调试(二分法等)确定错误位置,确定好错误原因了就好改了。修复后最好反思下问题的原因、类型等,哪些地方可以改进,争取下次不犯一样的错,慢慢减少错误才能越来越高效。

    《调试九法》

    尽量写出对自己也对其他人负责的代码,上边费了牛劲都是在阐述这个显而易见但是没多少人严格遵守的东西。用动态语言写大型项目维护起来要稍麻烦, 很多新手写代码不注重可维护性,甚至自己写的代码回头自己看都一脸懵逼,问了一句这代码TM是干啥的? 一开始的负责会为以后协作和维护带来极大便利(当然你想干两天就走让其他人擦屁股就当我没说)。 最后,很多东西我也在摸索,上面的玩意你就当小白的踩坑记录,随着理解和经验的加深我会不定期更新本篇内容。另外我发现网上大部分是教程性的东西,对于python相关的工程性的东西很少,我很疑惑难道大部分公司的python项目都写得相当规范?没人吐槽?反正我是踩过坑,希望看到过本章的人能把python代码质量重视起来。

    第一步是复现,偶尔才复现的代码是很难排查错误的。如果不好复现但是有 sentry 之类的记录工具也是极好的,sentry 会记录当前栈信息和变量信息,非常有利于排错。

    看日志,各种日志(logging, nginx),看 sentry 异常信息

    问同事,让同事帮忙 review 审查代码。有时候人有思维定势,你自己看不出来的别人可能一眼就看出来了。小黄鸭调试法

    断点调试。看变量值。二分法排查代码位置,快速试错定位。比如一个地方很有隐秘的错误,但是又不好快速确定位置,我们就可以用二分加断点的方式快速定位到具体哪一块出了问题。

    不要死磕,一个法子不行换一个。死磕可能会耗费太长时间并且容易进入死胡同,在一个大型复杂系统中定位 bug 原因是对技术、经验、毅力、灵感、心理素质的很大考验,休息一会可能就解决了。

    极难排查和复现的 bug 可以无限期搁置。

    找到 bug 修复以后增加相应单元测试用例,这样对回归测试非常有利,同时避免重复犯一样的错误。tricky 的地方要加上注释。

    留心非代码因素:比如代码是否正确部署上线等(比如之前脑残查一个 bug 无解最后发现是部署到线上没成功,根本没起作用)。如果实在没发现代码级别错误,单测也比较完善,可能就要考虑下非代码因素。

    bug 总结:建立错误检查表(核对清单),哪些可以避免的记录下来,防止以后再犯。(团队的知识财富)

    大多数 bug 都可以通过设计复审、代码审查、代码静态分析、测试等找出来,我们可以综合利用以上手段尽量减少代码缺陷。

    重构与维护

    不知道你有没有这种感觉,看那些知名代码库flask等,人家写的代码水平是比较高的,但是自己的项目确实一团糟。我觉得代码要经常去重构,想着怎么写更优雅,更容易理解和维护。我个人感觉好的代码就是不断修改出来的,实现一个需求的时候,适当想想怎么设计更加优雅易维护,编写代码的时候注意想着可读性。完成需求了如果代码可以设计更优雅,可以尝试重构下,慢慢代码水平就上来了。如果总是直来直去堆砌需求代码,业务逻辑写再多依然不会有进步(我个人感觉写python有时候反而会降低编程能力)。牛人和计算机高手很多,能写出良好的工程代码的人却很少(试想一下让你维护一个『牛人』的『精巧』代码)。代码一次编写,却可能被无数次查看、修改和维护,在可读性和可维护性上的努力长远来看是值得的,编写代码只是整个软件项目中很小的一部分。写代码的时候最好也从维护者的角度思考一下。 Code Quality: Simple, Well-tested, Bug free, Clear, Refactored, Documented, Extensible, Fast.

    重构:在不改变代码功能的情况下优化代码设计。修改功能和优化代码不要同时做。优化应该以可读性为标准。

    接手老项目的时候不要盲目大规模重构,但要保证代码仓库越来越『干净』,不要破罐子破摔。

    可以通过设计(需求)归档、代码规范、静态检测工具、单元测试、必要的注释和文档、code review(代码复审)、重构、服务化等手段增加项目的可维护性。

    动态语言的重构工具支持不够完善,重构的时候要注意别改坏了逻辑,要十分谨慎。

    Python 做业务后端的优缺点分析

    笔者从实习开始做 Python 后端,经历过一些新项目、老项目,以及和很多 python 工程师(豆瓣、知乎)协作过,大概总结下 python 做 web 业务后端的优缺点吧,尽量客观, 总得来说就是用动态语言写项目在追求高生产力的同时要严格把控工程质量。先说优点:

    多面手。python 可以写方便地写爬虫、网站、数据分析、运维脚本等,都有比较成熟的框架,目前比较火,TIOBE 里脚本语言排第一。

    轮子多。python 发布时间比 java 还早,大量现成的轮子可以用。我觉得即使是 web 之王 php 做网站开发体验和效率上来说并不比 python 强。这可能也是 Instagram 和 Quora 等选择 Python 的原因。

    表达能力强,语法糖多,生产力高。笔者喜欢动态语言的一个原因就是表达能力强,用更少代码完成功能。(代码行数越少意味着高生产力和低出错率,当然不一定对可读性有帮助)

    缺陷:

    解释性语言执行效率低,大部分时间用在 IO 密集场景,比如 web 后端。不过大部分公司不用担心性能问题,除非真到了一定用户量级。

    开发工具支持不够完善,不如 java 有那么完善的 IDE,Pycharm 还不错,但是依然解决不了滥用动态特性导致的补全和跳转等问题

    易编写,但难以重构和维护,易出错,工程上不够友好,较难写出 clean code(笔者基本上会强制上 pylint and autopep8, 模仿 gofmt 吧)。基本上重构只能依据字符串匹配,老实说每次重构有稍微大一些的改动都会有点担心

    滥用动态特性导致代码不好维护。这是个双刃剑,但是对工程来说还是不要滥用。有时候会利用一些动态特性使用黑魔法来快速完成需求,但是工程上来说这是很不利于维护的。这是很多人抨击动态语言不适合大型项目的原因,一般需要在编码规范里明确说明哪些能用,哪些不能用。

    没有类型声明,看不出一些复杂类型的数据结构(Python、php 都在不遗余力地加上 type hint),代码写糙了维护起来很累(看不出复杂变量的类型和结构,阅读代码吃力,我都是给复杂类型加上类型注释),命名和编码习惯很重要

    缺少一些最佳实践(技术、小白文章偏多,工程实践文章比较少),以很多 python 的中小公司在软件工程上管理不够,无规范、无文档、无注释、无单测、无持续集成的尿性,还是慎用动态语言瞎胡搞,后期维护成本会很高。

    python2,3 不兼容,迁移有成本。我个人觉得 python 敢于抛弃当初的设计是值得赞赏的,但是很多企业并没有足够的资源来去迁移

    招人不好招,这两年 python 雷声大,雨点小,而且基本都是在 AI 领域。有经验的 python 后端远没有 Java 好招(往往很多人学得还是半吊子写代码很随意,不重视工程质量),更多是创业公司、中小公司使用

    技术选型都是在权衡吧,因为灵活性与工程性、开发效率和运行效率很多时候无法兼得。

    开发习惯

    认识和熟悉所在团队中的成员(笔者之前一直做得不够好,这一条远比想象中重要,内向性格有时候会比较吃亏),良好的沟通和协调能力能帮助你更快完成(或者委托)任务。

    确保正确了解需求,确保熟悉所做的业务;需求分析;适当设计。流程图或者文档有时候可以帮助理清楚业务。比如知乎有 rfc 机制,每次做一个稍微大点的需求都需要写设计文档。

    番茄工作法,劳逸结合(working smart rather than working hard),一次只做一件事(do one thing and do it well)。长时间专注写代码是非常消耗精力的。确保编码期间足够专注。快速迭代。

    注释先行,意图导向,表达明确,牢记可读性可维护性,可追溯(附上需求文档地址,方便维护者查看)。写一个模块、类或者函数之前先想好它的功能,按照功能命名,之后写简单的注释描述其意图和功能,通常不超过三句话,虽然大部分时间只有一句话(只做一件事) ,但是能快速让后来的维护者了解你的意图。别看人代码最头疼的就是看不出代码究竟是要干啥。

    结对编程。结对编程和TDD是极限编程中大力提倡的,国内似乎没有多少公司在实践,一般帮助新人了解项目或者带实习生的时候,结对能帮助新人快速上手。有时候两个人一起边讨论边写代码要比写完后在 gitlab 一条条评论快很多。

    平常可以留心下周围优秀的同事都有哪些好习惯,我们可以学习并改善下自己的开发流程。

    Think more, type less. Aim for minimalism, fewer states, less mutability, and just enough code for the known, relevant parts of the problem.

    欢迎来公众号:PythonEco 进行骚扰~

    《The Zen of Python》 - Tim Peters

    Beautiful is better than ugly.

    Explicit is better than implicit.

    Simple is better than complex.

    Complex is better than complicated.

    Flat is better than nested.

    Sparse is better than dense.

    Readability counts.

    Special cases aren't special enough to break the rules.

    Although practicality beats purity.

    Errors should never pass silently.

    Unless explicitly silenced.

    In the face of ambiguity, refuse the temptation to guess.

    There should be one-- and preferably only one --obvious way to do it.

    Although that way may not be obvious at first unless you're Dutch.

    Now is better than never.

    Although never is often better than *right* now.

    If the implementation is hard to explain, it's a bad idea.

    If the implementation is easy to explain, it may be a good idea.

    Namespaces are one honking great idea -- let's do more of those!

    >>> 

    相关文章

      网友评论

        本文标题:Python Web入坑指南一

        本文链接:https://www.haomeiwen.com/subject/oacmdftx.html