聊聊代码的质量

程序员、工程师用不同的编程语言写出源代码,去实现项目的需求、功能,为客户带来价值。极少客户会直接看到源代码,但源代码却是程序员的重要产出,可以视为产品的一部分。代码的质量自然会影响最终产品的质量。好的代码是好产品的基础,将来产品维护、更新升级都从中获益;差代码则绝对是定时炸弹,即使短期没有发作,公司或组织在未来也很可能付出高昂的代价。

代码质量很容易被组织所忽略。第一,“老大”往往只关心功能是否实现,客户又不看代码;第二,代码质量提高很难立竿见影,“老大”看不到明显的产出(作用体现在将来,团队的能力也需要一定时间培养,如设计能力、组织架构能力等);第三,质量的量化有些困难,工具往往只能是辅助。因为这些原因,公司或组织只有在质量问题非常严重时,才会给予高度关注。可往往此时已为时已晚,代码已然“臭不可闻”,维护成本高企,团队苦不堪言。如果这时产品还有维护价值,组织自然会拨出更多人力物力,原来一个人的代码,可以5个人一起改。如果没价值,那就推倒重来。表面看很爽,可烂代码对新写代码的贡献可能也不大,无奈之举背后实则是大量成本的损耗(以前的资源白花了)。

代码质量一定是开发团队的问题吗?我觉得不全是。开发团队成员的素质自然很重要,可如果老大一定要把2个月的活,压到一个月来完成,工程师是怎样一种状态,想想也知道,能把功能做完就好,还谈什么思考高可扩展的设计;如果需求老是改来改去,工程师早上写的测试用例,晚上就要废掉,那还有什么动力去写新的测试。总之,”老大“或管理层要知道有代码质量这回事,它也不是免费的,要给足重视。

代码质量的标准是可调整的,而且允许”补交作业”。对一个初创公司,当某项目一个月不完成,公司就死了,代码质量的优先级当然就很低。公司这时要让团队知道,相信工程师也会理解此时是所谓非常时期,手法自然也要”非常“。但如果之后,继续忽视代码质量,没有把前期的技术债务清掉,当一个个隐患被相继埋下。等未来再遇到”2个月的活需一个月赶完“的危机,可能就无论如何都完成不了的了。优秀的团队会未雨绸缪,在项目开始时就把合适的代码质量的要求写进项目规约中,如多少单元测试覆盖,多少新增Major静态分析问题,多少平均函数复杂度。项目经理也要时常的监督质量的看板。

以下结合平时工作,总结几条团队如何提高”代码质量“的要点,

统一的代码书写规范

有时挺形式,可团队要共同遵守的规矩很多,书写的规矩就是起点。要在以前,我绝想不到书写规范会统一。可我们团队经过很长时间的努力,现在人人可以遵守,旧代码也在不断改进中。有了规矩,就似某种共同的价值观,作用潜移默化,不单单只是代码规整了,好读了这些简单。

一个题外话,书写习惯真是可以改变的,我在前面的博客就说过,现在看到”4字节Tab“就觉得不舒服,相信很多人看到“2字节Tab”也很不爽吧。

架构与设计

众所周知,好的设计非常重要,未来的好扩展性、好维护性很多来自好的设计。架构设计源于对需求的理解,根据项目需要,选择合适的主架构。架构定了,代码的主布局(大的职责划分)就被箍住了。功能细节的设计也要重视,多开几次评审会议讨论UML图,仔细分析类的职责和类与类的联系,多想想使用时的场景,并引入合适的设计模式。

代码重构

多年的经验告诉我,随着需求的变迁,像自然规律一样,代码会慢慢变烂发臭。可以与之对抗就是重构(Refactory)。Refactory并不是要把代码“重回工厂”,而是时常运用各种技巧对代码进行自省和改进,不断将对产品功能新的理解注入到代码模型中。详见《重构》。重构有时是小步快走,如重写的名字,提个函数啥的,这种最安全;有时动结构时,要大踏步,这时要小心,依靠团队找出好的方案。这时你也会看到高覆盖度Unit Test Cases的强大支撑。没Unit Test,那你要更小心了。

团队培训

团队人员经验不同,素质也参差不齐,没什么好办法,要加强培训。

培训并不是说一定要去找外部机构,便宜的公开课很多是套话,和实际情况有距离;高级的订制课又太贵。还是应该多依靠团队自身,老员工帮新员工,新员工请教老员工,没有比这再自然的作法了。新员工得到了知识,老员工也会有更多的思考,两者都加强了。时间长了,大家的能力都会提高。

团队Lead则应鼓励大家的加强沟通,组织各种形式的交流分享会。

代码评审

现在我对Code Review的理解,学习和交流为主,找BUG和问题在次。一个简单的道理,你的代码每天被一个有20年经验的人看,那会是种什么感觉,你肯定期待着一些高级的反馈。就是经验相当的人相互Review代码也会有帮助,想想当你把很烂的代码让别人看,难道不觉得丢人吗?

代码评审费时吗?当然。如果团队中所有人都找那个最牛的人看代码,估计再牛的人也扛不住。那就分散开好了,有些关键的、拿不准的、有技术难点的改动找牛人看,其它的就分散开,反正时间找了,牛人的经验总会慢慢流到组里所有人,不要急于求成,把牛人累死在半道上。一次代码提交就找一个Partner帮你看看。

杜绝Copy/Paste

不再累述,详见绝不要拷贝代码

TDD

单元测试无数次的帮助我们找到代码中的BUG、没有改全的地方、糟糕的设计(设计的不好,往往不好写测试)等等。Unit Test绝对值得每个团队拥有。

代码质量平台

Sonarqube是各种数据参数集成的地方。我时常把它比成一个苦口婆心的教练,只要你一上传有问题的代码他就在你背后絮叨,想不烦就老实改了吧。此外,Sonarqube还有很多很多强大的功能,详见它家主页吧。

在我们团队的引领下,公司很多团队都要使用Sonarqube,去检测Python,C/C++的代码。好工具就是好用。

 

以上文字皆有感而发,可能也没有总结全,以后想起来再补上吧! :grin:

 

How to migrate ReviewBoard database from sqlite to MySQL

About 3 years ago, I introduced Review Board into our team with a great help from RB group and replaced CodeStrike. We deployed RB on a WinXP VM and the backend database is sqlite. I can’t remember the reason. Maybe I just wanted to save some time. Actually, it has spent a lot of time of our team.

Why? Because sqlite is a lightweight DB and it have bad performace in concurrency scenario. For our team, we have about 20 developers and RB is the most popular daily tools. Now we have to say, we highly depend it to control the quality of team’s code.

Recently, the dababase issue was getting worse. RB pages can’t be created well and there are many warnings/errors on it. And yesterday, the database was dead finally-“The database is locked!”. That’s a message from Django. I googled and the best solution is to use better database to avoid such issues in future.

I took about 3 hours to migrate database to MySQL 5.1. Maybe my experience can help you to save some time.

Step 1. sqlite bump

Go to sqlite.com and download a command line. For window version, you can find it here.

Unzip it and use command to dump sqlite database.

reviewboard.db is the database file of sqlite.

Step 2. Convert to MySQL dump

Now we have the sqlite dump file. But you can’t import it into a MySQL database directly. Because some syntax is not supported by MySQL.

I googled and got a free converter to do that. You can find it here and download sqlite3_mysql.zip.

In the deep of the zip , you can find a executable file – sqlite_mysql.exe. Run it and convert the sqlite dump file to a MySQL one.

Step 3. Import MySQL dump

Before that, please create a database in your MySQL database.

In my case, the dump is about 180M and I waited very long time. (And there may be some warning messages. I don’t know why but for now the migrated server works well. So maybe we can’t ignore them.)

Step 3.1 Alter database structure

Actually, this issue was found when I finished Step 4 and restarted RB. At the beginning, RB worked well. But a minute later, a guy said he could’t submit any comments.

The root cause was the “id” field of some tables lost the property of “AUTO_INCREMENT”. I didn’t know why and SQL in dump file was right. Then I write a very simple .py script to fix this issue.

I just went through all tables and alter the property of “id” field if the table has one.

Step 4. Change RB configuration file

Change rb_site_root/conf/settings_local.py to:

Make sure MySQLdb is installed or there will be error when restart RB.

The best moment came finally! RB restarted successfully and all review request/comment/diff were there. And the performance was improved. You can feel the page is loaded fast. Cheers! :grin:

If you have the same problem with me, I hope this post can help and save some time.