我如今是这样编程的

注:文中图片均来自网络程序员

 

我在作什么

曾经,我试过接到一些需求。一眼带事后,脑壳立刻随着高昂的斗志沉溺在代码的世界中 ,快马加鞭地敲着键盘直到最后测试的完成。我从思绪中恢复过来,乍一看本身写的功能,和需求差了十万八千里,我TM都在干吗?数据库

除此以外,我还见过相似的很可笑的事情。有一个程序员,经理提了需求,而后他在那里折腾了一天。结果不但没作出来,并且和实际需求都是彻底搭不上调。通过询问发现,他不知道经理说了什么,也不知道本身到底在作什么。编程

代码的世界多是昏天暗地的,可是咱们的思惟不能这样随之混乱,不然一切都会前功尽弃。因此我如今编写程序的时候,常常会想一下:我要作什么,我在作什么。更好的方法是把详细需求落实到文档,并时刻核对文档。设计模式

 

 

大局为重

2-8法则告诉咱们,一个项目核心的功能只有不多,其它大部分都是对核心功能辅助或加强的。但当任务分发下来,我手头总有一些本身很想开发的模块,不过它们不属于那20%。我之前常常会在这些感兴趣的模块上花费不少时间和精力。缓存

结果项目快要到上线期限,主要的功能却没开发完成,其它一些不起眼的功能却作得很好,但为此项目不得不延期了。若是反过来,只要对总体功能预期不会有太大误差,能够将就的先上线。重要一点是:即便功能还有遗漏,但项目能够上线了,老板天然不会太追究,本身工做也能图个安心。若是不知道那些功能模块是最重要的,先问问经理。网络

人老是喜欢作一些本身感兴趣或者有挑战的事。不过在这方面,为了项目和团队着想,应该尽可能压制这种诱惑。编程语言

 

 

性能永远不是优先考虑的问题

我历来不会一开始就考虑性能问题。若是项目成本很低,甚至到项目结束时,若是没有感受到明显的性能问题,也不会去管。要知道如今已经不是DOS的年代,CPU的计算能力很高,但成本很低了。重要一点是,若是只针对提高性能对代码作改动,很容易破坏代码的复用性和可维护性。而返过来,提升了代码的复用性和可维护性,则很容易提升性能。函数

 

下面有一个PHP的代码实例,功能是帮助用户重置密码(代码为了简单说明问题,请不要太在乎一些无关的细节)工具

requestResetPassword是接收用户重置密码的请求而且作了相应的检查。为了更好的复用性,我将重置密码的操做单独分配到一个新的resetPassword的函数,更改完密码的后再调用sendEmail向用户发送一封通知邮件。性能

/**
 * 用户请求重置密码的接收器
 */
function requestResetPassword() {
    //检查用户是否存在
    if( !checkUserExists( $_GET['userid'] ) ) {
        exit('抱歉,用户不存在,请确认用户账号。');
    }
    resetPassword( $_GET['userid'] );
    //最后向用户发送一封邮件
    sendEmail( $_GET['userid'], '重置密码成功', '新的密码是xxxx' );
    exit('新密码已经发送到你的邮箱。');
}


/**
 * 帮助用户重置密码
 */
function resetPassword( $userid ) {
    //检查用户是否存在
    if( !checkUserExists( $userid ) ) {
        return false;
    }

    //进行重置用户密码的操做
    //略...
    return true;
}


/**
 * 向用户发送一封邮件
 */
function sendEmail( $userid, $title, $content ) {
    //检查用户是否存在
    if( !checkUserExists( $userid ) ) {
        return false;
    }

    //发送邮件操做
    //略...
    return true;
}


/**
 * 检查某个用户是否存在
 */
function checkUserExists( $userid ) {
    $user = getUserInfo( $userid );
    return !empty( $user );
}


/**
 * 获取某个用户的数据
 */
function getUserInfo( $userid ) {
    //假设我有一个query的函数,它用来查询数据库并返回数据
    $user = query( "SELECT * FROM `user` WHERE `uid`=" . intval( $userid ) );
    return is_array( $user ) ? $user : array() ;
}

  

如今问题是,这三个函数都同时使用checkUserExists这个函数来检查用户不存在,数据库查询了三次,这样带来了一些额外的开销。

若是要去掉三者之间任意一个checkUserExists,看上去是可能的。可是若是以后有某些功能要调用resetPassword或者sendEmail,用户不存在时,系统可能会发生错误。

还有一个解决方法是,将resetPassword的逻辑写到requestResetPassword里,再过一点,把sendEmail的逻辑也写进去。这样函数调用减小,数据库查询也变成一次了,性能获得了提升。可是重置密码和发送邮件的功能将不能获得复用,而且违背了单一责任的原则,代码复杂度也提升了。

 

不过,由于函数分离和复用性都很好,若是实际性能受到影响,可能考虑用缓存的方法减小数据库查询,我改动了它们共用的checkUserExists函数:

/**
 * 检查某个用户是否存在
 */
function checkUserExists( $userid ) {
    //增长一个缓存,用以记录检查用户的结果
    static $cache = array();

    //检查当前用户是否已经检查过一次
    if( isset( $cache[ $userid ] ) ) {
        return $cache[ $userid ];
    }

    $user = getUserInfo( $userid );
    //把结果记录到缓存中
    $cache[ $userid ] = !empty( $user );

    return $cache[ $userid ];
}

 

也能够用一样的方法改动getUserInfo函数。

 

这里能够看到,当代码的复用性提升时,想提升性能是很简单的,性能的瓶颈也很容易被发现和修改。

尽管这个例子对性能影响还不够大,还有一些影响更大的,好比说遍历,我可能为了复用而将遍历封装到一个函数中,而且屡次使用它。这些开销对个人项目根本没有预想中那样有太大的影响,或者说是微乎其微的。因此我更愿意把时间花在如何提升代码的复用性和维护性方面,而不是纠结于浪费多这一点性能。实际性能若是真的达不到要求,也能够权衡增长硬件配置。

 

 

名字长一点好

函数名和变量名等除了给机器看,也要给人看的,有时一个简单直接的好名字实在是很难想,这时不妨用长一点的名字更好。可读性更好:

//好名字
class ErasedTypeEquivalence {
}

//坏名字
class ErdTypeEqe {
}

//好名字
function checkUserExists () {
}

//坏名字
function ckUserExt() {
}

//好名字
$result;

//坏名字
$ret;

 

我见过一些代码,因为简单写过多,整遍代码不少都是4个字母或如下的,可读性很是差,固然不排除是为了偷懒。

但若是想有更多的时间腾出来偷懒,不该该在这上面玩小聪明,不然这时我如今应该在思考前几天的代码是在写什么。

 

什么?短名字会让代码执行得更快? 那证实给我看,若是真的快,快了多少?

 

 

自说明代码很重要,但注释一样重要

代码自己能够说明问题的确是很棒的,但并非说注释不重要,有时候我更喜欢先看注释,由于它总比我看代码更快的了解这程序是作什么的。

若是我把本文前面说性能的例子去掉注释,哪一个能让你更快了解代码的意图?或者说,你更愿意看哪一个?

function requestResetPassword() {
    if( !checkUserExists( $_GET['userid'] ) ) {
        exit('抱歉,用户不存在,请确认用户账号。');
    }
    resetPassword( $_GET['userid'] );
    sendEmail( $_GET['userid'], '重置密码成功', '新的密码是xxxx' );
    exit('新密码已经发送到你的邮箱。');
}


function resetPassword( $userid ) {
    if( !checkUserExists( $userid ) ) {
        return false;
    }

    //进行重置用户密码的操做
    //略...
    return true;
}


function sendEmail( $userid, $title, $content ) {
    if( !checkUserExists( $userid ) ) {
        return false;
    }

    //发送邮件操做
    //略...
    return true;
}


function checkUserExists( $userid ) {
    static $cache = array();

    if( isset( $cache[ $userid ] ) ) {
        return $cache[ $userid ];
    }

    $user = getUserInfo( $userid );
    $cache[ $userid ] = !empty( $user );

    return $cache[ $userid ];
}


function getUserInfo( $userid ) {
    $user = query( "SELECT * FROM `user` WHERE `uid`=" . intval( $userid ) );
    return is_array( $user ) ? $user : array() ;
}

 

因此,即便代码自己很清晰,可是加上注释的话,可读性也能提升不少!

 

 

适当抽象

编程就是为了解决实际中的问题,在思考如何编码的时候,把问题抽象到必定的高度去思考,更容易把握问题所在。不过更多时候,我发现从代码抽象到现实的例子是有必定难度的,同时我也相信,编程高手也是抽象高手,他们很容易把问题反映到真实生活中去。

不过若是常常留意和思考生活中的细节,会提高本身的抽象能力。

举一个螺丝刀的例子,若是叫你造一个螺丝刀,你会作成什么样子?我这里有三把不一样的螺丝刀:

 

显然第一种螺丝刀是最简单的,比较中规中矩。

第二种螺丝刀中间能够旋转刀柄,让刀柄和刀头成90度,这样的设计让拧螺丝更加轻松。

第三种螺丝刀则能够更换刀头,若是之后有其它类型的螺丝,则只要造一个适合这种螺丝的刀头就能够了。

 

那反映到编程中的问题,若是项目要增长一个工具类库。

第一种方法,能够直接把类库的所需功能写出来就能够了。

第二种方法,不但把类库写出来,并且针对项目的一些状况作特殊改进,使得在这个项目中更好用。

第三种方法,根据类库的特性,把公共部分的逻辑作成接口,特殊的部分分离出来单独实现,若是之后要增长相同类型的类库,则实现特殊部分的逻辑,而后接入接口便可。

 

可是在抽象的时候,要避免不合理的抽象,有时也可能形成过渡设计,如今只须要一种螺丝刀,但你却把更多类型的螺丝刀都作出来了(并且仍是瑞士军刀的样子。。):

 

 

一致性

团队开发中,可能每一个人的编程风格都不同,拿花括号来讲,有些人喜欢和代码在同一行,而有些喜欢独自一行

//例一
function func() {
}

//例二
function func()
{
}

 

命名风格也都不同,好比说声明变量接收一个函数返回的数据,有些喜欢用result,有些喜欢用data。

它们可能都很好,不过在团队开发中,尽可能统一用同一种风格可以很好的减小交叉开发的成本。

 

将错就错

面对项目一些可有可无的分歧或错误,应该要接受和理解。承接上面的问题,若是团队中已经有人大量用了data的变量命名,但你认为result的更符合当前情况的描述。这种状况,我优先选择data命名,由于若是再使用result的话,会破坏项目的一致性,对开发没有任何好处。

这只是不多的一方面,若是项目规范没有很好的落实,实际工做中会有大量的一致性问题,必须靠团队每一个人的决心和责任心去把它作好。一般,加入一个正在开发中的项目,编写功能前,我都会首先看项目以前的相似的代码,并尽可能模仿他们的写法。不过,若是有明显的错误,应该及时指出和修正。

只要坚持把一致性作好,不少方法会成为团队甚至业界的标准,即便它们不是最好的,可是有什么关系呢?

 

 

适当休息

编程的时候若是没有思路或者感到混乱,到外边休息10分钟,或者看一下风景,让脑壳清醒一下是很好的。这招很管用,亲测。

 

 

至少把代码完整运行一次

有时函数的逻辑过于简单,以致于会认为这个不可能发生错误,但事实上最容易发生错误的一般就是这些代码,常见的单词拼写错误,参数错误,还有一些意料以外的问题。因此不管什么状况,我都会把代码完整运行一遍。

固然更好的作法是用一些系统的测试方法,好比说单元测试。

 

 

编程不是艺术 

从一开始,编程语言的出现和发展,都是为了解决现实生活中的问题,包括它自身产生的问题。

面向对象、设计模式的出现,是用来解决编程语言自身带来的可读性和维护性等问题,而不是为了让编程语言上升到艺术的层面。尽管编程中有‘优雅’一词,但我更认为它只是用来形容代码更容易让人读懂和维护。

我拒绝一切看起来很‘优雅’,却不能为编程工做带来一点好处的代码。若是你喜欢玩弄语言,应该去看成家。 

 

 

甘于平凡

程序员真的很高傲,在我接触过的人中,包括我本身也是。我之前常常对一些简单的代码感到不屑,而总想在项目中写一些犀利的代码,让人看起来很NB,但结果老是和想象差太远,代码老是写的不好,逻辑也不够清晰。归根到底,是我带着这样的思想去写代码,而忽略了编程的根本:解决问题。如今我改掉了这个坏毛病,以解决问题为目的去编程,以简单为主。出乎意料的是别人有时会对我说,这里的代码写得很棒。

踏实的作事,会有意想不到的收获。

 

 

认可错误

不要怀疑,当别人用本身的程序或者代码没法运行时,首先考虑是不是本身的逻辑哪里有问题。一来别人会以为我谦虚,二来实际大多数状况的确是本身的问题。

 

 

有原则,有决心

作任何事情都坚持原则,并有决心是最好的。有不少道理咱们都明白,但常常作不到,没有任何人能帮到本身,将来也是本身争取的。

因此,若是知道什么是好,就尽可能去作,什么是很差,就尽可能避免。

即便是在公司面对经理和领导,也要坚持本身的作法,一些不合理的需求应该指出或拒绝。我还年轻,大不了换一家公司,而不肯意作一个受欺压的码农。

 

 

我在作什么

文章写完了,如今来回想一下,我是在分享本身如今编程的一些习惯,总算没偏离开始的主题。本文的思想都是来自实际工做和一些书籍,想了解更多的话,推荐阅读《整洁代码之道》《代码大全》《重构》这几本书。

若是你有一些认为好的编程方法,不妨拿出来和你们分享一下。

相关文章
相关标签/搜索