一个月前的今天,我应该还在和队友们肝 Wiki Freeze……虽然时间过去这么久 了,但是,还是想写一些东西。

况且许久不写文字的话,语言能力是会退化的(笑)。已经不知道多少次打开编 辑器、写了多少半成品,但因为组织不好内容而放弃了。以后还是要多写写呀。

唔,从哪开始写起呢?感觉千头万绪的,就写一篇流水帐吧。

我为什么要参加 iGEM?其实可算是追随传统吧。之前很多很厉害的学长都参加 了这个比赛,虽然我并不厉害,但抱着想要变得厉害的想法,东施效颦般地也报 名了 iGEM 2018。准确地说,是本校的软件队。毕竟我对 21 世纪学科一窍不通 嘛,就不敢去实验队。

Giant Jamboree

可能有人要问了:什么是 iGEM 呢?iGEM 本体其实算是一个合成生物学的竞赛, 全称是 International Genetic Engineering Machine(国际遗传工程机器)。 其实我至今没弄明白,为什么 i 要小写,哪里有 machine……合成生物学是什 么?我自己就没怎么搞懂,懒得解释了。大概就是拿大肠杆菌玩基因工程吧。

那么就有趣了,iGEM 这样一个合成生物学的竞赛,竟然有纯软件队参赛!其实 动机倒不难理解,就是想让码工码农给合成生物学做些软件,让这些生物学家日 子好过一点。

但是,每年软件队要做什么,那是完全没有任何的限制,自然也没有任何提示。 看起来就像是一场大型 Hackathon。软件队的评奖标准是什么呢?抱歉,主要看 评委口味啦。技术很先进?不重要。队员们都很努力?也不重要。

对软件队来说,iGEM 既不是技术比赛,也不是看谁更努力。一个好的项目点子、 一个美观的用户界面、一次有深远影响的 Human Practice,可能比用了什么最 先进深度学习模型更能影响评分。

不过说了这么多,印象最深的还是做项目。iGEM 是我第一次参加如此「大型」 的团队项目。是的。第一次。大概十几二十几个人都有 commit 代码。呜哇,别 笑了,确实是第一次嘛。连带去年、前年的开发者,整个代码库其实不小,大概 有几万行代码量?

我在团队中大概是边缘地位,贡献也不是很大。本身隶属于后端组,主要任务是 写 CRUD 接口和前端对接。啊哈,听着就很无聊对吧?事实嘛,其实差不了多少, 确实是挺没意思的。本身我们技术栈用的是 Python 和 Django 这种听着就很省 心的组合,但过程中还是有一些风波和挑战。

第一个挑战:理解并维护遗留代码。 我们为了省一些精力,决定在去年软件 队项目的基础上做今年的项目,虽然前端是完全重写了(甚至连技术栈都从 Vue 变成了 Angular),但后端还是在去年的基础上写的。这时候就遇到了一个问题: 由于每年队员交集为空,我们对代码基完全陌生。好消息:代码基是 Python + Django,我们开发者都了解。坏消息:去年的开发者过于强大,把 Django 自己 又搞了一层封装。把整个项目框架弄清,成功加进去一个 app,大概就花了我几 天到一周时间。不过,感谢前任开发者,他的代码写得相当不错。

第二个挑战:对相关技术不熟悉。 出于「不知为什么但我个人觉得是跟风」 的目的,我们选用了 RESTful Web API 设计。这就造成了很多我个人觉得完全 是莫名其妙的问题。现列举一些个人想法:

  1. 前端是用 Angular + TypeScript 写的,后端是 Python 写的。前端和后端 要分别写一遍接口规格,分别处理序列化和反序列化。这在我看来完全是不 必要的重复劳动。由于需求经常变动,前后端要同步改变接口又比较麻烦。
  2. 很难设计一个看起来很漂亮的接口。POST, PUT, DELETE 的概念好吗?挺好 的,看起来也很漂亮。但有的时候,你就是不知道应该把哪个接口放在哪个 URL 上。「获取活跃用户」,看起来放在 /user/active 没啥问题?获取 流行的文章,/article/popular 好像也行。然后「获取当前用户文章」、 「获取所有用户文章」、「获取当前用户流行文章」呢?注意,这里还要考 虑权限和可能不同的响应格式!一开始我还会安排一下接口位置,后来索性 放弃了,前端说在哪就在哪,反正是前端用不是我用,而且从前端的封装来 看,全部用 POST 对他们来说反而更简单。
  3. 由于第 2 点原因,我们经常需要 hack Django Rest Framework 的默认工作 流程、路由之类的,导致很多工作做起来很丑陋。工作中 DRF 文档的缺乏也 让我很难受,我经常需要追踪到 DRF 源码里面来了解其逻辑,然后逐个试验 可能的解决方案。花去几个小时的时间、最后只改动十几行代码、实现一个 看起来非常简单的功能。当然,不排除是 DRF 本身太不灵活(对非默认逻辑 没多少支持)的缘故,我随口就能说好几个:(a) 没有能创建数据库表项的 SlugField; (b) 很难写一个能给数据库插入数据的 SlugField;(c) serializer 的一些细节不好控制,比如 field 处理顺序什么的。 (d) 稍微 改动一下 mixin 就用不了了,然后你需要把 DRF 的代码拷贝过来。最后, 你大概率会放弃使用它自带的 ModelSerializer 一类的东西,选择一切负担 自己扛。
  4. 为了优化网络请求,不得不把接口设计得不正交。而为了能返回漂亮的响应、 解析各种各样可能错误的请求,当然是选择使用 DRF 的 serializer 和 validator 一类的东西。这样就会产生一大堆看着差不多的 serializer 类, 看着很心烦。还有一些归属上的争议,比如某个 app 需要特殊的 User 信息, 这个 user 信息依赖于当前 app 的信息和功能,那么这个 UserInfoSerializer 是应该放到这个 app 下面,还是 user 那个 app 下面?

现在想来,很多问题来自于我当时没想到用 query param ……

**第三个挑战:赶时间。**我个人对代码质量要求其实……挺高的吧?(这是主 观感觉,不接受反驳!)每次写代码都会尽量把代码写得漂亮好懂一点。但是在 做这样一个团队项目,我们经常会要赶时间,不管是赶最终的各种 freeze,还 是要赶快修问题、实现功能让前端能继续做下去。很多时候就顾不得那么多了, 能把 bug 修了、把功能做出来比什么都强。事后就完全不想去改了,甚至连看 都不想看……如果您去看了我今年写的一些代码,一定能发现不少令人惊异的丑 陋之处,不举例子了,要脸……

**第四个挑战:Python。**是的,你没看错。我已经数不清 Python 本身的动态 性给后端造成了多少细小的问题。这越发坚定了我静态类型语言支持者的立场! 当然这里也有我自己的一些锅,就是没写单元测试。其实我当然是明白写单元测 试的重要性的,但是,但是,但是就是不想写啊!我希望以后的项目中会有初级 程序员专门来编写单元测试,这样大家都好。

这中间还有很多奇妙的问题。如果代码不是我自己写的,单凭我自己去观察恐怕 debug 不出来。

我们想要支持用户通知,在用户评论时会给被评论用户发送一条通知。此外,在 用户删除评论时,这条通知也会被删掉(不然岂不是很尴尬?)。这个通知系统 基本是 Django 的信号系统。不过,队友在写评论支持时,发现每次删除都会报 错,调试了两三天没有搞明白。这里我要点名批评 Django 的 backtrace,80% 以上都是我不关心的东西。这个案例里,Django 的 backtrace 甚至是在帮倒忙: 只能看到出错在 template 系统里,但是……我们的项目根本没有用 template! 两三天过去了评论功能还没上线,于是我去和他一起看了一下问题,仔细观察了 backtrace 终于从一大堆没有用的信息中找出了我个人觉得非常重要的几个字节, 于是我立马想起了我写的通知:原来是我删除通知时写错了一个关键字参数,而 当时我忘记了测试删除。当然最后的 fix 只有几个字节而已。那么 BUG 是怎么 产生的,而我们又为何看不出来问题呢?很简单,这个通知系统的基础架构是去 年写的,今年我只是复用了 model 和一些 send notice 这样的功能。而 send notice 会使用各种奇妙的 Python 动态特性把关键字参数插到字符串里面(其 实我确实用到了),这个插就用了 template,另外也会用在数据库操作上,于 是导致了报错并不在第一现场,backtrace 也就和问题的本身相去甚远了。

总之,关于做项目本身的感受就是,去年的代码写得是很不错的,今年的后端代 码中我写的部分,我个人觉得是狗尾续貂了。如果有人要维护这个代码,那我只 能表示心疼……最大的教训是,写动态语言一定要写测试,一定要写测试啊!

说点别的,就是 GitHub Issues 上看到一排排 Assigned 栏中我的头像,而且 这些 Issue 都被我 Close 了,感觉就很爽。不过,在 close 之前呢,看着就 很恐怖了,不建议 13 岁以下儿童和心理素质较差者尝试。

虽然我花费这么多笔墨在项目开发上,完全是因为我个人对这些事情比较敏感, 所以想说的有点多。其实,可说的还有很多,比如,值得再强调一遍的,iGEM 不是技术比赛,对应地,我们软件队也不全是写代码的。整个软件队大概分成这 么几个组:

  1. 管理组(队长、经理)
  2. 美工组(海报、视频、UI 设计)
  3. 码农组(前后端和 Wiki)
  4. 生物组(提供生物技术支持)

说了「大概」了,别打我……当然码农占大多数啦,不过,这也是我第一次接触 到一个这样不纯粹在搞技术的团队,也是第一次亲身体验到做技术重要是重要, 但绝不是唯一值得考虑的,其他如管理和推销也是非常重要的,甚至可能比技术 本身更重要。比如 iGEM 很强调的 Human Practice,有一个非正式但很中二的 说法是,「告诉世界,你的项目将改变世界。」这是很有道理的,哪怕做的东西 再好,不被人知道就相当于白做了!

我觉得,iGEM 是个很不错的比赛,特别是对满脑子搞技术的业界小白来说,是 一次不错的体验,推荐给所有还有想法参加的朋友们。想做实验的,就去实验队, 我觉得合成生物学还挺有意思的(?)

最后呢,不知道说什么好了,给大家拜个早年吧。