DOOM团队代码复审报告

DOOM团队代码复审报告

1 代码规范性

1.1    变量命名规范性

在所有的类中,所有的变量都按照“驼峰大小写”的命名规范,且变量名称基本为变量意义的英文缩写,同时,重要的变量附有注释,方便理解。

如下面的截图:

1.2    函数命名规范性

Doom团队的代码,类的所有方法,采用的也是首字母为小写的驼峰大小写的规则,但根据C#的编码规范,公有方法,最好首字母大写,私有成员,首字母小写。例如如下的代码:

这是一个被‘public static’修饰的方法,根据C#编码规范,最好将其命名为DeleteLog

1.3    sql语句书写规范性

所用的sql语句都采用了“关键词大写,其他量小写”的sql语句书写规范,合乎标准。

2 代码可读性

在Doom组提交给我们的代码片段里,AntiAbuse类的所有公有方法都做了详细的注释。而且对函数签名的注释采用VS的注释模板,这样可以被Intellisense识别,方便进行函数调用时自动提示各个形参的意义。

         同时,在函数体内,有对于方法意义的足够注释

         美中不足的是,在提交给我们的所有代码中,只对有AntiAbuse的类做的注释比较详尽,而其他类的注释较少。

3  具体代码部分

3.1    错误处理

在AntiAbuse类里,所有的数据库访问都没有进行相应的错误处理,如下图所示的这一方法。

这里使用了Using语句包围Connection,是一种很好的习惯,但是,对于connection.Open()方法可能抛出的异常(数据库连接失败等),并没有进行相应的处理。SqlCommand cmd的相应方法也是这样。

3.2    代码书写的统一性

在复审过程中,我们发现了一个问题,在数据库的操作逻辑上,有的代码使用的using方法(如上图),有的则是调用的DbHelper类里的相关方法。

这样,对数据库的操作的编码并不统一,在进行修改的时候可能会造成混乱,建议统一采用一种格式。最好能够统一使用DbHelper类提供的封装好的方法对数据库进行操作。

3.3    重复代码

在复审过程中,我们发现了许多重复的代码,比如,在每一个对数据库进行操作的方法上,都硬编码了connectionString。

 

这样做,一旦connectionString需要进行修改,则需要动到源代码,更何况connectionString在代码中出现了许多次,改起来会十分的麻烦,在这里,还是建议将connectionString从代码中剥离出来,保存在xml文件中,并通过特定的类,如DbHelper,在runtime将其获取,这样做,使得程序与自身所在的运行环境(不同的环境需要不同的数据库连接字符串)解耦度更高。

4 效能问题(关于部分代码的算法改进)

在AntiAbuse类中,有一个关键的函数isSensitiveWords(string content),其作用是判断content里是否包含系统内设置的敏感词。为了便于分析,在此贴上其代码。

 

    /// <summary>
    /// 判断一个回答或者评论是否为敏感词
    /// </summary>
    /// <param name="content">回答内容或评论内容</param>
    /// <returns>是敏感词就返回true,否则返回false</returns>
    protected static Boolean isSensitiveWords(string content) {
        /*
         *按数据库里的敏感词表中的敏感词对content进行分析
         *设计一个算法判断content是否为敏感的
         *如果是敏感的,就返回true,否则返回false
         */
        Boolean isSensitiveWords = false;           //是否为敏感词

        /*从数据库中读出所有的敏感词到一个hash表里面*/
        SqlConnection conn = DbHelper.getConnection();
        HashSet<String> senWordsSet = new HashSet<string>();
        SqlDataReader reader = DbHelper.ExecuteReader(
                    "SELECT * FROM [SensitiveWords]"
                    , conn
                );
        while (reader.Read()) {
            senWordsSet.Add(reader.GetString(1));
        }

        /*判断content是否为敏感的算法实现*/
        int contentLen=content.Length;           //content的长度
        int start = 0;                    //子字符串的开始位置
        int step = 10;                    //步长

        if (step > contentLen) {                //如果步长大于content的长度,调整步长
            step = contentLen;
        }

        while (start < contentLen) {
            string word;

            if ((step = (contentLen - start)) >= 10) {        //设置步长step
                step = 10;
            }

            word = content.Substring(start, step);

            while (step > 0) {
                if (senWordsSet.Contains(word)) {           //如果word是敏感词,那么说明content是敏感的
                    isSensitiveWords = true;
                }

                step--;
                word = content.Substring(start, step);
            }

            if (step == 0)
            {
                start++;
            }
            else {
                start += step;
            }
        }

        return isSensitiveWords;
    }

可以预见,在生产环境下,该方法的调用次数非常高(每当产生一个User Generated Content就调用一次),然而,在该方法的逻辑内,可以看到,每调用一次该方法,就要从数据库里读取一次senWordsSet(敏感词列表),而在生产环境下,该列表的变动可能比较小,因此可以将senWordsSet变为AntiAbuse类里的一个静态数据成员,在类初始化时,也将其初始化。但考虑到这里的isSensitiveWords(string content)是静态型的,需要在使用senWordList之前判断其是否为null,如果是则加载,这样就避免了不必要的数据库IO开销。

另外,再来看它的关键逻辑:找敏感词,其大致思路是——把content分成n段,每一段使用string的isContains方法检测,由于不清楚isContains()的具体算法,我对该方法的效率还持有怀疑。如果不放心其效率,可以自己编码实现KSP算法。另外,考虑到很多垃圾评论都非常短,而且严重同质化,如“好”,“顶”,“楼主好人”等,我们可以再按照content的长度分类,如果content较短,就让它跟小于自己长度的敏感词比较,提高效率。

另外,在这里,不知敏感词是否有英文,如果有,则应该先进行大小写转换,方便比较。

另外,可以参考博文

http://www.cnblogs.com/wude/archive/2008/05/15/1941622.html

5. 设计模式

该小组的代码没有采用任何设计模式,而且大量的方法都是static的,static有static的好处,特别是对于只专注于业务逻辑的代码,但建议采用某些设计模式,如简单工厂模式,比如上面的senWordsSet,可以放在工厂初始化的业务逻辑里,一次初始化即可。

 综合评分,经过权衡各方面因素,我们为DOOM提交的代码打分为:92

posted @ 2012-12-16 16:49  MagicCode1023  阅读(574)  评论(0编辑  收藏  举报