• 分析一套源代码的代码规范和风格并讨论如何改进优化代码——高级软件工程课第三次作业


    结合工程实践的选题,我选择的是一个开源的C++轻量级网络框架——ZLToolKit。下面按照所给的要求依次展开(以下均以Google的C++编码规范为标准)

    1.根据其编程语言或项目特点,分析其在源代码目录结构、文件名/类名/函数名/变量名等命名、接口定义规范和单元测试组织形式等方面的做法和特点

      src文件夹下的源代码目录结构如下:

    src
    |
    |-- NetWork				# 网络模块
    |	|-- Socket.cpp			# 套接字抽象封装,包含了TCP服务器/客户端,UDP套接字
    |	|-- Socket.h
    |	|-- sockutil.cpp		# 系统网络相关API的统一封装
    |	|-- sockutil.h
    |	|-- TcpClient.cpp		# TCP客户端封装,派生该类可以很容易实现客户端程序
    |	|-- TcpClient.h
    |	|-- TcpLimitedSession.h 	# 派生于TcpSession,该模板类可以全局限制会话数量
    |	|-- TcpServer.h			# TCP服务器模板类,可以很容易就实现一个高性能私有协议服务器
    |	|-- TcpSession.h 		# TCP服务私有协议实现会话基类,用于处理TCP长连接数据及响应
    |
    |-- Poller				# 主线程事件轮询模块
    |	|-- EventPoller.cpp		# 主线程,所有网络事件由此线程轮询并触发
    |	|-- EventPoller.h
    |	|-- Pipe.cpp			# 管道的对象封装
    |	|-- Pipe.h
    |	|-- PipeWrap.cpp		# 管道的包装,windows下由socket模拟
    |	|-- SelectWrap.cpp		# select 模型的简单包装 
    |	|-- SelectWrap.h
    |	|-- Timer.cpp			# 在主线程触发的定时器
    |	|-- Timer.h
    |
    |-- Thread				# 线程模块
    |	|-- AsyncTaskThread.cpp		# 后台异步任务线程,可以提交一个可定时重复的任务后台执行
    |	|-- AsyncTaskThread.h
    |	|-- rwmutex.h			# 读写锁,实验性质的
    |	|-- semaphore.h			# 信号量,由条件变量实现
    |	|-- spin_mutex.h		# 自旋锁,在低延时临界区适用,单核/低性能设备慎用
    |	|-- TaskQueue.h			# functional的任务列队
    |	|-- threadgroup.h		# 线程组,移植自boost
    |	|-- ThreadPool.h		# 线程池,可以输入functional任务至后台线程执行
    |	|-- WorkThreadPool.cpp		# 获取一个可用的线程池(可以加入线程负载均衡分配算法)
    |	|-- WorkThreadPool.h
    |
    |-- Util				# 工具模块
    	|-- File.cpp			# 文件/目录操作模块
    	|-- File.h
    	|-- function_traits.h		# 函数、lambda转functional
    	|-- logger.h			# 日志模块
    	|-- MD5.cpp			# md5加密模块
    	|-- MD5.h
    	|-- mini.h			# ini配置文件读写模块,支持unix/windows格式的回车符
    	|-- NoticeCenter.h		# 消息广播器,可以广播传递任意个数任意类型参数
    	|-- onceToken.h			# 使用RAII模式实现,可以在对象构造和析构时执行一段代码
    	|-- ResourcePool.h		# 基于智能指针实现的一个循环池,不需要手动回收对象
    	|-- RingBuffer.h		# 环形缓冲,可以自适应大小,适用于GOP缓存等
    	|-- SqlConnection.cpp		# mysql客户端
    	|-- SqlConnection.h
    	|-- SqlPool.h			# mysql连接池,以及简单易用的sql语句生成工具
    	|-- SSLBox.cpp			# openssl的黑盒封装,屏蔽了ssl握手细节,支持多线程
    	|-- SSLBox.h
    	|-- TimeTicker.h		# 计时器,可以用于统计函数执行时间
    	|-- util.cpp			# 其他一些工具代码,适配了多种系统
    	|-- util.h
    	|-- uv_errno.cpp		# 提取自libuv的错误代码系统,主要是为了兼容windows
    	|-- uv_errno.h

     可以看到,源码的模块划分主要以原作者设计实现时的功能模块划分为导向。
     文件名:按照Google的C++编码标准,文件名应当全部使用小写。而该源码文件命名较为随意,一些采用大写,一些采用小写,不符合规范要求
     类型名:按照Google的C++编码标准,类型命名应当每个单词首字母大写,不含下划线,以名词形式,且所有类型命名 —— 类, 结构体, 类型定义 (typedef), 枚举等均使用相同约定。
     该源码一些类型的代码如下所示,可以看出类型命名基本依照现有的标准。
      
    class SocketFlags{
    public:
        SocketFlags(int flags):_flags(flags){};
        ~SocketFlags(){}
        int _flags;
    };
    
    class MutexWrapper {
    public:
        MutexWrapper(bool enable){
            _enable = enable;
        }
        ~MutexWrapper(){}
    
        inline void lock(){
            if(_enable){
                _mtx.lock();
            }
        }
        inline void unlock(){
            if(_enable){
                _mtx.unlock();
            }
        }
    private:
        bool _enable;
        Mtx _mtx;
    };
    
    typedef enum {
    	Err_success = 0, //成功
    	Err_eof, //eof
    	Err_timeout, //超时
    	Err_refused,//连接别拒绝
    	Err_dns,//dns解析失败
    	Err_shutdown,//主动关闭
    	Err_other = 0xFF,//其他错误
    } ErrCode;
    

      函数名:按照标准,常规函数每个单词首字母大写,使用命令式语气,比如:OpenFile()   CheckFileName(),而存取函数或短小的内联函数使用小写加下    划线,且与访问变量相吻合,比如 set_num_errors()。该源码的部分函数声明或调用如下

      

    void Socket::setOnErr(const onErrCB &cb);
    void Socket::setOnAccept(const onAcceptCB &cb);
    
    void Socket::setOnFlush(const onFlush &cb);
    
    //设置Socket生成拦截器
    void Socket::setOnBeforeAccept(const onBeforeAcceptCB &cb);

    setsockopt(sockFd, IPPROTO_IP, IP_DROP_MEMBERSHIP,  (char*)&imr, sizeof (struct ip_mreq));

      可以看到,该源码中函数的命名主要依据的时驼峰式的命名法,但并未统一,时而依照驼峰命名法,时而全部小写,不符合标准。

      变量名:按照标准,变量名一律小写,单词用下划线相连,例如:int player_id; string table_name;特殊的是类成员变量,后跟下划线区别普通变量,比     player_name_   player_id_。该源码的变量命名基本按照了小写的要求,类中的变量命名也通过下划线与普通变量区别开来:

      

    class SockException: public std::exception {
    public:
    	SockException(ErrCode errCode = Err_success,
                       const string &errMsg = "",
                       int customCode = 0) {
            _errMsg = errMsg;
            _errCode = errCode;
            _customCode = customCode;
    
        }
    
        //重置错误
    	void reset(ErrCode errCode, const string &errMsg) {
    		_errMsg = errMsg;
            _errCode = errCode;
    	}
        //错误提示
    	virtual const char* what() const noexcept {
    		return _errMsg.c_str();
    	}
        //错误代码
    	ErrCode getErrCode() const {
    		return _errCode;
    	}
        //判断是否真的有错
    	operator bool() const{
    		return _errCode != Err_success;
    	}
        //用户自定义错误代码
        int getCustomCode () const{
            return _customCode;
        }
        //获取用户自定义错误代码
        void setCustomCode(int code) {
            _customCode = code;
        };
    private:
    	string _errMsg;
    	ErrCode _errCode;
        int _customCode = 0;
    };
    

     

    2.列举哪些做法符合代码规范和风格一般要求 

     根据上面的分析,我们可以看出:

     2.1 该源码文件名的命名规则不符合Google的C++标准中规定的——文件名应当全部使用小写。

     2.2 该源码的类型名的命名规则基本符合Google的C++标准中规定的——类型命名应当每个单词首字母大写,不含下划线,以名词形式,且所有类型命名 —— 类, 结构体, 类型定义 (typedef), 枚举等均使用相同约定。

     2.3 该源码函数的命名不符合一致性的要求

     2.4 该源码变量名基本符合Google的C++标准 

    3.列举哪些做法有悖于“代码的简洁、清晰、无歧义”的基本原则,及如何进一步优化改进

     1.源码整体注释较少,远低于注释要占代码20%的要求,尤其是对宏的注释,基本没有。改进:添加注释——每一条宏都要加注释;在函数定义的开头添加注释以说明该函数的作用

     2.源码中部分使用了宏定义函数,这是C++不提倡的做法。改进:使用内联函数代替宏函数

    4.总结同类编程语言或项目在代码规范和风格的一般要求

     代码风格因人而异,最重要的是保持自己代码风格从一而终的一致性。但无可厚非,有一些出自大厂的且大家都认可代码风格规范是值得借鉴和学习的,因为它符   合大多数人的阅读习惯,以下根据相关代码规范对代码的基本书写列出一些一般要求:

     1.命名:

      文件名全部小写;函数名全部按照单词首字母大写;普通变量名一律小写;成员变量名小写且以_为结束作为标记。

     2.空行

      定义变量后要空行

      每个函数定义结束之后都要加空行

      两个相对独立的程序块之间要空行

     3.空格

      函数名之后不要留空格

      (向后紧跟;),;这三个向前紧跟;紧跟处不留空格  

      值运算符、关系运算符、算术运算符、逻辑运算符、位运算符等前后应当加空格

      单目运算符前后不加空格

     4.缩进

      如果地位相等,则不需要缩进;如果属于某一个代码的内部代码就需要缩进。

     5.注释

      注意注释的数量,注释太多会让人眼花缭乱

      当代码比较长,特别是有多重嵌套的时候,应当在段落的结束处加注释

     每一条宏定义的右边必须要有注释,说明其作用  
  • 相关阅读:
    Samba 基础搭建
    HBuilder 打包流程和遇到的坑
    js 字符串查找相同字母最长子串
    web前端简单的H5本地存储
    rem响应式JS
    JS洗牌算法
    Js 常用正则表达式
    JS_DOM_鼠标、键盘事件合集
    SE 2014年4月3日
    SE 2014年4月2日
  • 原文地址:https://www.cnblogs.com/hhssqq9999/p/11649314.html
Copyright © 2020-2023  润新知