第3部分 软件研发工作总结
首先是为人编写程序,其次才是计算机
“首先是为人编写程序,其次才是计算机”,这是软件开发的基本要点,软件的生命周期贯穿于产品的开发、测试、生产、发布、用户使用、版本升级和后期维护等长期过程中,只有易读、易维护的软件代码才具有生命力。
在实际的软件开发过程中,可能是由于工作很忙的原因,很多开发人员只注重实现程序的基本功能,而忘记了编程规范,因此写出来的代码只能让计算机看懂,人要看懂很不容易。更有甚者,有些项目组为了赶进度,明确要求组员以实现产品功能为主,代码能够运行起来就可以了。低要求产生低质量的代码,既然“上头”都这样要求了,那还有必要写出“让人能够读懂”的代码吗?
进度是赶上了,产品也交付出去了,一切看来是OK的,但问题也就来了。前方频发产品故障的消息,后方开发人员不停地扑火。这个时候,他们才发现之前别人写的代码很难读懂,甚至连阅读自己写的代码都十分的困难,真是悔不当初。如果当时能够将代码写规范一点,文档配备齐全一点,何至于此?
大家先来看下面这段代码:
#include <stdio.h>
void main()
{
float fun(int n);
int n;
float y;
printf("input an integer number: ");
scanf("%d", &n);
y = fun(n);
printf("%d!=%10.0f\n", n, y);
}
float fun(int n)
{
float y;
if(n<0)
{
printf("n<0, dataerror!");
}
else
if(n == 0 || n == 1)
f=1;
else
f= fun(n-1)*n;
return(f);
}
大家发现了哪几处问题?
对于以上程序,至少存在以下问题:
第一,变量命令不规范,而且没有初始化。对于该程序,main函数里的变量n、y,fun函数里面的变量f的命名均不规范,不能让人一眼就看出它是什么意思、要做什么操作。这对于一小段程序来说,影响还不是很大,但如果代码行数达到数千行,那么阅读起来就比较的费力。另外,以上说的三个变量只是定义了,并没有初始化,这在实际项目中也是不允许的。
第二,函数的命名不规范,且没有在主函数开始之前进行声明。本程序中的fun函数表示什么意思?如果你没有看程序开始之前的文字,那么只有通过阅读函数里面的代码才能知道。在实际项目中,函数命名非常的重要,因为一般涉及到函数个数较多,如果不能通过函数名称来了解其作用,而必须通过阅读代码才能获悉,那么工作效率是很低的(而且让你有打人的冲动)。此外,我们一般不在调用该函数的函数的内部来对被调函数进行声明,而是应该将声明放在外部,最好新建一个头文件来对程序里面出现的函数进行声明。
第三,程序代码排版不工整,“if…else”语句书写不规范。在fac函数中,存在排版不工整的情况。第一个if语句下面的大括号应该与“if”的“i”保持在同一列上,第二个“else”应该与第二个“if”保持在同一列上,“f=1;”和“f=fac(n-1)*n;”应该再缩进4个空格。另外,“if”和“else”下面的执行语句不管有多少行,都应该用“{}”括起来,以方便阅读。
第四,程序注释过少,函数开头没有注释。一般说来,在程序的关键语句的前面或右边,都应该添加适当的注释,这对程序的理解有辅助的作用。函数fac的前面应该加注释,说明此函数的功能、输入/输出参数、返回值、修改记录等。在整个程序的开头处,也要添加版本信息、修改记录等注释信息,以方便日后查阅。
第五,“main”函数的返回值类型不规范且无输入参数。在《C陷阱与缺陷》一书中,作者建议为main函数提供返回值。因此,最好将“void”修改为“int”,以提供返回值,满足编程规范的要求。此外,对于无输入参数的函数,尽量用“void”来表示输入参数。
第六,程序中出现了“printf”、“scanf”和“main”函数。这是大家都习以为常的,但在实际的项目中,几乎不可能出现这三个函数。因为公司都有自己的开发平台,而且代码都达到数千行,甚至上万行,很多都不是基于VC开发的,你在哪里去输入,又在哪里去看输出呢?我一进公司,最开始看到程序,就想去找“printf”、“scanf”和“main”,但这是徒劳无功的,因为根本就没有。关于输入/输出,开发中会有专门的消息处理流程来处理,大家需要知道的就是一个完整的程序不一定非要有上面的三个函数。
短短几十行代码,就有如此多的问题。如此书写代码,只能让计算机看懂,“人”是很难看懂的。
那么,我们如何写出让“人”能够看懂的代码呢?这个过程不能一蹴而就,要循序渐进,要从我做起,从身边做起,不断地提升个人编程的境界。
可以考虑从以下几个方面入手:
第一,对新入职的员工进行软件编程规范的培训,在刚开始工作中的时候,让他们严格参照编程规范来编写代码。越是早地开展编程规范的训练,越是能够早地养成编写规范代码的习惯,写出的代码也就越清晰。顺便说句题外话,很多IT公司没有这方面的意识,只顾对企业文化进行培训,以为这样就能够让员工的忠诚度增加。实际上,这只是个异想天开的做法。
第二,定期在项目组开展编程规范方面的主题讨论,强化大家的意识。老员工写出的代码对新员工有示范的作用,如果老员工写出的程序都是可读性很差的,那么新员工会怎么想呢?他们又会怎么做呢?很多开发人员每天只顾埋头苦干,却忽略了一些最基本的东西,因此能力很难再次得到提升。在编写完代码之后,不要就以为事情做完了,还要编写一些项目文档,如版本详细设计文档等。在这些文档里面,把自己的思路写清楚,方便以后自己或他人查阅起来能够很快理解程序思路。
第三,开发人员严格按照公司制定的编程规范来书写代码。变量如何命名?函数如何命名?注释如何写?代码如何排版?这些都有严格的要求,作为一个合格的软件开发工程师,编写规范的代码是基本的要求。当我们阅读到书写优美的代码的时候,是不是心里面会觉得很爽?从某种程度上来说,代码编写的规范程度可以体现一个程序员的态度和专业素养。
第四,项目组要严格执行同行评审流程。大部分IT公司为了提高产品的质量,都有一个叫做“同行评审”的流程,也就是让项目组成员相互检查各自的成果,大家相互学习、取长补短、共同提高。但是,可能是中国文化的影响,大家都比较顾及面子,因此不愿意将对他人真实的想法表达出来,也使得“同行评审”流于形式。当然,也许你对别人的程序确实没有意见,那就另当别论了。对他人开诚布公地提意见并不是冒犯,而是大家相互学习的一种很好的方式。
第五,最重要的是,个人要有编写规范代码的意识,要不断地学习各种提高编程能力的技术。不管别人对你怎么说,如果你本人不想把程序写好,那么纵使万般外力,又如何?程序员虽然工作很忙,但也要抽时间来学习新的技术,这样才不会被新技术淘汰掉。“活到老,学到老”,这句话尤其适用于现在这个大数据时代。
“长风破浪会有时,直挂云帆济沧海”,对于很多人来说,编写出能够让计算机读懂的程序就已经足够了,但如果想要成为一位优秀的软件开发工程师,那么就要力求写出让“人”能够很容易看懂并领会的代码。这是一个长期的过程,大家要有“万里长征”的准备,要有“愚公移山”的精神。
最后,附上之前代码规范化后的样式:
/***************************************************************
*版权所有 (C)2014, company name。
*
*文件名称:example.c
*内容摘要:用于示范如何给变量和函数做规范的命名
*其它说明:无
*当前版本:V1.0
*作 者:周兆熊
*完成日期:20140813
*
*修改记录1: // 修改历史记录,包括修改日期、版本号、修改人及修改内容等
* 修改日期:
* 版本号:
* 修改人:
* 修改内容:
***************************************************************/
#include <stdio.h>
typedef signed int INT32; // 重定义数据类型
float ProcessFactorial(INT32 iInputValue); // 函数声明
/****************************************************************
*功能描述:主函数
*输入参数:无
*输出参数:无
*返 回 值:无
*其它说明:无
*修改日期 版本号 修改人 修改内容
* --------------------------------------------------------------------------------------------
* 20140813 V1.0 周兆熊 创建
***************************************************************/
INT32 main(void)
{
INT32 iInputValue = 0;
float fResult = 0.0;
printf("input an integer number: ");
scanf("%d", &iInputValue);
fResult = ProcessFactorial(iInputValue); // 调用求阶乘的函数
printf("%d!=%10.0f\n", iInputValue, fResult);
return 0; // 注意有返回值
}
/****************************************************************
*功能描述:求一个数的阶乘
*输入参数: iInputValue-输入值
*输出参数:无
*返 回 值:求阶乘后的结果
*其它说明:无
*修改日期 版本号 修改人 修改内容
* ---------------------------------------------------------------------------------------------
* 20140813 V1.0 周兆熊 创建
***************************************************************/
float ProcessFactorial(INT32 iInputValue)
{
float fResult = 0.0;
// 先判断输入值是否小于0
if (iInputValue < 0)
{
printf("iInputValue < 0, dataerror!");
return -1;
}
else
{
if (iInputValue == 0 || iInputValue == 1) // 0和1的阶乘是1
{
fResult = 1;
}
else
{
// 执行递归调用
fResult = ProcessFactorial(iInputValue-1)*iInputValue;
}
return(fResult);
}
}
(本人微博:http://weibo.com/zhouzxi?topnav=1&wvr=5,微信号:245924426,欢迎关注!)