欣赏一下“秀色可餐”的代码
前段时间,EA公司开源了红警1的部分代码,大家都在赞叹其代码规范性。周末闲来无事,正好可以欣赏一下所谓“秀色可餐”的代码到底长啥样。
红警1是一款1995年发售的游戏,也就是说,这些代码距今已经25年了。游戏代码是用C++写的,而且现如今C++依然是TIOBE排行榜前五名中的常客,这不仅让人感叹c++这门语言的生命力。
好了,闲话少叙,咱们马上进入正题。首先从github上clone下红警1的代码,打开代码目录,是下面这样式的:
嗯,文件名都是大写,还挺另类的,至少我没有见过其他的C++项目是这样文件命名的。
我们选择其中一个文件,看看它们到底有何特殊之处。好的,就选这个“CONNECT.CPP”和“CONNECT.H”来一探究竟。
首先,从名字来看,这两个文件的代码应该是负责连接功能,但具体是什么类型的连接,谁连接谁,还不得而知。
打开CONNECT.H,映入眼帘的是copyright声明,没啥毛病。
继续往下浏览,是文件的作者,日期和功能说明,非常的规整。
功能说明部分比较长,大概有60行。这么长的文件功能说明倒是比较少见。
通读说明部分,可以得知该文件实现了如下功能:
可以看到,把功能说明部分读了一遍,差不多对该文件的设计意图,实现内容,注意事项全部都清楚了,注意,这时候我还一行代码没有看。
我认为这部分的注释是非常值得我们借鉴的,不用费力去看源码就知道了整体逻辑,非常的省时省力。我想如果你在你的代码中加入这部分注释,后续维护你代码的人会对你感激涕零。
只看我的文字你们还感受不到代码结构的赏心悦目,我整理了下头文件的模板,你们感受一下:
//
// Copyright xxxxxx.
// .....
//
/* $Header: /CounterStrike/CONNECT.H 1 3/03/97 10:24a Joe_bostic $ */
上面这行是指这个文件从反恐精英里copy的吗,擦
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
***************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : CONNECT.H *
* *
* Programmer : Bill Randolph *
* *
* Start Date : December 19, 1994 *
* *
* Last Update : April 1, 1995 [BR] *
* *
*-------------------------------------------------------------------------*
* *
* DESCRIPTION: *
* This class represents a single "connection" with another system. It's *
* a pure virtual base class that acts as a framework for other classes. *
* *
* ...... *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef CONNECTION_H
#define CONNECTION_H
/*
********************************* Includes **********************************
*/
#include "combuf.h"
/*
********************************** Defines **********************************
*/
#define CONN_DEBUG 0
/*
***************************** Class Declaration *****************************
*/
class ConnectionClass
{
/*
---------------------------- Public Interface ----------------------------
*/
public:
/*.....................................................................
Constructor/destructor.
.....................................................................*/
ConnectionClass (......);
virtual ~ConnectionClass ();
/*.....................................................................
Initialization.
.....................................................................*/
virtual void Init (void);
/*.....................................................................
Send/Receive routines.
.....................................................................*/
xxxxxx
/*
-------------------------- Protected Interface ---------------------------
*/
protected:
......
};
#endif
/**************************** end of connect.h *****************************/
下面继续浏览CONNETC.CPP的代码,文件开头的声明和CONNETC.H的一样,并且列出了当前文件所有的函数:
/*-------------------------------------------------------------------------*
* Functions: *
* ConnectionClass::ConnectionClass -- class constructor *
* ConnectionClass::~ConnectionClass -- class destructor *
* ConnectionClass::Init -- Initializes connection queue to empty *
* ...... *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
每一个函数和方法都有固定结构的说明注释,这个结构目前的很多开源代码都在用,而且有文档生成工具,比如doxgen,可以非常方便的从注释生成说明文档。建议大家也采用这样的结构注释,下面是ConnectionClass类的构造函数的说明注释:
/***************************************************************************
* ConnectionClass::ConnectionClass -- class constructor *
* *
* INPUT: *
* numsend desired # of entries for the send queue *
* numreceive desired # of entries for the receive queue *
* maxlen max length of an application packet *
* magicnum the packet "magic number" for this connection *
* retry_delta the time to wait between sends *
* max_retries the max # of retries allowed for a packet *
* (-1 means retry forever, based on this parameter) *
* timeout the max amount of time before we give up on a packet *
* (-1 means retry forever, based on this parameter) *
* extralen max size of app-specific extra bytes (optional) *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/20/1994 BR : Created. *
*=========================================================================*/
方法实现的几乎每行都有注释,而且注释比代码还多。我觉得这部分做的有点过了,有些简单的赋值一眼就能看出意图的没必要添加注释,我猜红警代码的提交检查里应该有注释量/代码量的限制。
通读了整个文件,绝大部分函数都在50行以内,这还包括了空行和注释。函数名定义也非常清晰,知名达意。
说实话,读这些代码让我有种读SQL的感觉,这些代码都是用清晰的函数和变量名,以及间接的逻辑在告诉别的程序员自己在做什么,而不是在堆砌逻辑,只告诉机器该做什么。我想这也是区分优秀程序员和一般程序员的一个标准,优秀程序员是面向程序员,而一般程序员则是面向机器。
总结
最后,来总结下红警代码的优秀风格:
- 清晰的代码注释:注释完整且有统一的结构,极大节省了维护者的阅读成本;
- 声明式编码:以类SQL的方式,声明要做什么,而不是堆砌怎么做;
- 小而精的函数实现:函数只做一件事,并控制函数长度;
我已经打算采用这些风格了,你心动了吗?