科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道编写易于理解代码的六种方式

编写易于理解代码的六种方式

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

对于一名开发人员,时间是最宝贵的资源。本文所要介绍的这六种编写可维护代码的方法可以保证让您节省时间和少受挫折:在编写注释上多花一分钟,会让您少受一小时研读代码的痛苦折磨。

作者:Jeff Vogel 来源:CSDN 2007年9月24日

关键字: ghost 易于理解 代码

  • 评论
  • 分享微博
  • 分享邮件

在本页阅读全文(共2页)

我学习编写、改善和维护代码的过程是很艰苦的。在过去的 12 年里,我一直在编写计算机游戏并通过曾红极一时的共享软件技术进行网络销售,并以此为生。这就是说,我常常要从空白的屏幕开始从头编码,当代码达到数万行之后才能拿去销售。

这也就是说,如果我出了错,我必须要自己去解决问题。当我在凌晨三点还在竭力寻找 bug 的时候,看着这些不知所云的晦涩代码,我不禁自问:“我的天啊,这些垃圾代码究竟是哪个笨家伙写的啊?”,很不幸,问题的答案是 “我”。

在学习了良好、正规的编码技巧之后,我大受其益。本文就包括了其中的一些实践。具有丰富经验的资深程序员大都对这些内容烂熟于心。他们可以通过本文优美的散文式的介绍再重温一遍,并可回顾一下在采取清晰编码的理念之前,编码是多么地令人头痛。

但更多的人会如同我一样,是无意间跌跌绊绊地闯入编程领域的,而且没有人为其灌输这些编程技巧和理念。本文所要介绍的这些内容对很多人来说也许很基础,但对于其他人来说却是极为宝贵的资源,因为之前没有人告诉过他。所以,如果您不想走弯路,那么本文将非常适合您。

示例

为了便于解释,本文全篇都将使用一个示例太空游戏程序,称为 Kill Bad Aliens。在这个游戏中,您将通过键盘来控制一个宇宙飞船,它可以在屏幕底端水平向前或向后移动,还可以向上发射子弹。 

游戏发生在称为 Wave 的各个时间段。在每个 wave,外星人都会一个接一个地出现在屏幕顶端。它们到处飞,还会投掷炸弹。外星人将按固定时间间隔出现。在杀死一定数量的外星人之后,一个 Wave 就告结束。

杀死一个外星人会给您加分。当结束一个 wave 时,根据您完成游戏所需时间的长短还会有额外的分数奖励。

如果被炸弹击中,您的当前飞船就会炸毁,另一个飞船继而出现。如果被炸毁超过三次以上,游戏就结束了。如果您的得分很高,就会被晋级为 “人”,如果分数很低,就不能。

现在,我们可以坐下来开始用 C++ 编写这个 Kill Bad Alients 游戏了。首先定义几个对象来分别代表飞船、玩家的子弹、敌人和敌人的子弹。然后再编写代码来绘制这些对象。还需要编写代码来让这些对象可以随着时间的推移而到处移动。另外,也需要编写游戏逻辑、外星人 AI 以及能感知用户击键用意的代码等等。

那么,我们该如何实现这些以便当游戏编制完毕后,代码易懂、易维护,最起码地,不会一团糟呢?

提示 1:经常注释

请经常为代码添加注释。假设您编写了一个过程,但没有为它做注释,几个月后,您再回过头来想对它进行一些修整(您绝对会这么做),将需要花费很多时间去研读这些代码,原因就是因为您之前没有做注释。而时间是您最为宝贵的资源。丢失的时间是永远也找不回来的。

但注释和其他事情一样也是需要技巧的。只要多练习,在这方面的技能就会不断提高。注释有好有坏。

最好不要将注释写得过长。假设为一个函数做了注释,而这个注释在将来可以节省您理解代码所需的时间,比如说 10 分钟。这很好。现在假设所编写的注释过长,您花了 5 分钟编写这个注释,之后还要再花 5 分钟读懂这个注释。这样一来,实际上没有节省任何时间。这不是一种很好的做法。

当然,也不要将注释写得过短。如果在一两页之长的代码中找不到任何注释,那么这段代码最好清晰得 “晶莹剔透”,否则将来研读所需的时间将会很长。

再有,注释的方式不能太死板。当刚刚开始编写注释时,人们往往会头脑一热,写下这样的注释:

// Now we increase Number_Aliens_on_screen by one.
Number_Aliens_on_screen = Number_Aliens_on_screen + 1;
 
这么明显的东西显然不需要注释。如果代码非常混乱以致于需要逐行注释,那么更有利的方式是首先简化代码。在这种情况下,注释并不能节省时间,反倒会消耗时间。因为注释需要时间去研读,而且它们分布于屏幕上的实际代码中的不同位置,所以在显示器上一次只能看少许的注释。

此外,千万不要这么写注释:

Short get_current_score()
{
 [insert a whole bunch of code here.]

 return [some value];

 // Now we're done.
}
 
“We're done” 这样的注释有何用处呢?真是感谢您让我知晓。注释下面的这个大括号以及其后跟随的大片空白难道还不足以让我明白这是一段代码的结束么?同样,在返回语句之前也不需要使用类似 “Now we return a value” 这样的注释。

那么,如果您正在编写代码,而又没有上司或公司的规定可以做指导,这时,又该如何注释呢?我的做法是:对于由我自己维护的代码,我会写一个简介。这样一来,当我返回一个我很久以前编写的过程时,我就可以查看对它的解释。一旦我了解了其工作原理之后,我就可以很容易地理解实际的编码了。这通常会涉及:

过程/函数之前写几句话,说明其功能。
对传递给它的数值的一个描述。
如果是函数,对其返回结果的一个描述。
在过程/函数内部,能将代码分解为更短小的任务的注释。
对于看起来有些难懂的大块代码,对其成因给与简短的解释。
总之,我们需要在开始时给出一个描述,然后再在整个代码内部的几个位置加以注释。这种做法需时不多,但却可在将来节省大量的时间。

如下所示是另一个取自假想的 Kill Bad Alients 游戏的例子。考虑代表玩家子弹的那个对象。需要频繁地调用函数来将其向上移动以便检查该子弹是否会击中任何目标。我可能会按如下所示编写实现这个功能的代码:

// This procedure moves the bullet upwards. It's called
//NUM_BULLET_MOVES_PER_SECOND times per second. It returns TRUE if the
//bullet is to be erased (because it hit a target or the top of the screen) and FALSE
//otherwise.
Boolean player_bullet::move_it()
{
 Boolean is_destroyed = FALSE;

 // Calculate the bullet's new position.

 [Small chunk of code.]

 // See if an enemy is in the new position. If so, call enemy destruction call and
 // set is_destroyed to TRUE

 [small chunk of code]

 // See if bullet hits top of screen. If so, set is_destroyed to TRUE

 [Small chunk of code.]

 // Change bullet's position.

 [Small chunk of code.]

 Return is_destroyed;
}
 
如果代码足够清晰,如上所示的注释应该就已经足够。对像我这样需要不时地返回这个函数来修复错误的人来说,这将能够节省大量时间。

提示 2:大量使用 #define。没错,是要大量使用。

假设,在我们这个假想的游戏中,希望玩家在射中一个外星人时即可获得 10 分。有两种方法可以实现这个目的。如下所示的是其中一个比较糟糕的做法:

// We shot an alien.
Give_player_some_points(10);

 This is the good way: In some global file, do this:

#define  POINT_VALUE_FOR_ALIEN 10
 

之后,当我们需要给出一些分数时,我们很自然地会这么写:

// We shot an alien.
Give_player_some_points(POINT_VALUE_FOR_ALIEN);

在某种程度上,大多数程序员都知道该这么做,但是需要遵守一定之规,才能将其做好。比如,每次在定义常数时,都需要考虑在某个中心位置对其进行定义。假设,要将玩游戏的区域设置成 800 * 600 像素,请务必这么做:

#define PIXEL_WIDTH_OF_PLAY_AREA 800
#define PIXEL_HEIGHT_OF_PLAY_AREA 600

如果,在某个日期,又想更改游戏窗口的大小了(您很可能需要这么做),若在此处就能更改数值将会节省您双倍的时间。这是因为:第一,无需在全部代码中查找所有提到游戏窗口是 800 像素宽的地方(800!我当时是怎么想的?)第二,无需总要修复那些由于漏掉了引用而引起的无法避免的 bug。

当我制作 Kill Bad Aliens 游戏时,我要决定需要杀掉多少外星人一个 wave 才算结束、屏幕上一次能有多少外星人、这些外星人又以多快的速度出现。例如,如果我想让每个 wave 中的外星人的人数相同,并且他们都以相同的速度出现,我可能会编写如下所示的代码:

#define  NUM_Aliens_TO_KILL_TO_END_WAVE 20
#define  MAX_Aliens_ON_SCREEN_AT_ONCE  5
#define  SECONDS_BETWEEN_NEW_Aliens_APPEARING 3

这段代码很清晰。此后,若我觉得这个 wave 太短或外星人相继出现的时间间隔过短,我就可以立即调整相应的值并立即让游戏重新生效。

如此设置游戏值的一个妙处是能快速地做出更改,这种立竿见影的施控感觉实在是很好。比如,如果将上述代码改写成如下所示:

#define  NUM_Aliens_TO_KILL_TO_END_WAVE 20
#define  MAX_Aliens_ON_SCREEN_AT_ONCE  100
#define  SECONDS_BETWEEN_NEW_Aliens_APPEARING 1
 

那么,您就无法享受上述的快感和兴奋了。 
 

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章