编写可维护的代码 (一)

本贴最后更新于 2561 天前,其中的信息可能已经渤澥桑田

可维护性我认为主要由两个方面构成, 一是可读性, 也就是代码要能让人看懂; 二是可调试性, 出了问题可以很快的找到原因. 市面上讲设计的书很多, 但大部分侧重于灵活性和可复用性, 比如面向对象设计和设计模式等. 灵活和可复用并没有什么错, 但我认为可维护要更重要一些, 试想如果一个模块非常灵活并被大量复用, 却不可维护, 岂不是不出问题则已, 一出就是灾难性的吗?

再看 C++ 语言, C++ 是一个提供了太多特性的语言, 每一件事情都可以用好几种可选的特性去实现, 但我们应该选择哪一种呢? 显然应该是最合适, 最实用的, 而不是最新最酷的.

从 05 年末到 09 年初, 我得到了一个非常难得的机会: 把一个项目做了两遍. 第一遍的时候用了很多 C++ 的高级特性, 也有意无意的引入了一个设计模式的思想, 项目也还成功, 但后续的维护却越来越难. 后来在做第二遍的时候, 受《UNIX 编程艺术》等的影响(也就是在这时候我成了把 C++ 当 C 用的程序员), 开始学习用最简单直接的方法解决问题. 而结果也相当好, 不光项目成功, 整个系统的可维护性也不错. 而且虽然设计时完全没考虑面向对象, 设计模式, 但最终的系统却又带着这些东西的影子, 只是实现方法和书上写的不完全一样(呵呵, 吹大了 欢迎大家对这一段扔几个西红柿鸡蛋之类的).

现在由于工作变动开始维护另一个系统, 这是一个很 C++, 很面向对象, 也很设计模式的系统, 可是维护起来却无比困难, 出问题后简直无从下手. 所以更体会到了可维护性的重要, 进而想到应该把自己的这点经验总结一下, 写出来. 目前总共有四五篇的题材, 都是很细节的问题, 希望自己能坚持写完. 我的方法也许不那么漂亮, 但应该还实用, 毕竟也算是真刀真枪的实战中总结出来的.

因为一发出来就被批了个体无完肤, 所以加上了这些文字, 说明一下背景. 不太喜欢口水仗, 后续的批评我将不再回复, 因为软件开发是工程而不是艺术, 工程讲究实用, 没有绝对的对和错, 一切都应该根据实际情况具体问题具体分析. 我写的东西只是供大家参考, 没有也无法强迫大家一定要用.

下面开始正题. 如果我们要实现一个类, 用于从流式缓冲区读出数据(典型应用是网络通讯中的数据包分析), 你会用下面哪种实现呢(错误处理用的是异常, 与主题关系不大, 故不详述)?

// A实现 class CBufferReaderA { ... template<class T> CBufferReaderA& operator>>( T& v ); ... }; // B实现 class CBufferReaderB { ... char ReadChar(); short ReadShort(); int ReadInt(); ... };

我想不少人会选择 A, 因为看起来更酷一些, 而且只写了一个模板函数就可以处理一大堆数据类型了, 但实际上, 如果从可维护性和实用性来说, B 却更好一点. 下面就来对比分析一下.

1. 像 cin/cout 一样, A 实现能把多个操作写在一起.

CBufferReaderA br; br >> a >> b >> c >> d;

这一点 B 是作不到的, 因为它的返回值被用来返回实际读取的内容了. 可是当我们调试 A 实现支持的那一串代码时, 问题就出现了, 整个代码虽然是好几个函数调用, 但一下就执行过去了, 根本没法看到中间结果(VC 是这样, 其他调试器不清楚). 为了避免这个问题, 只好把这一串操作拆成单个的, 但这样一来 A 和 B 也就没什么区别了.

2. 如果需要跳过一段数据, 需要怎么做呢? 如果用 A 实现, 肯定是类似下面的方法:

int tmp; br >> tmp;

而 B 实现则可以直接:

br.ReadInt();

对比可见, A 实现不光多用了一个没有什么实际用处的变量, 而且多写了一行代码. 只看这一点也许没多大问题, 但如果程序很大, 类似需求很多, 它带来的混乱就不可忽视了.

3. 缓冲区中是 char 型, 但我想用 int 保存读出的数据, 应该怎么办?

// A实现: char c; int i; br >> c; i = c // B实现: int i = br.ReadChar();

我想 B 的优势不用我说了吧.

4. 前面说到的 A 缺点也许还不算太严重, 下面这个应该就有足够的说服力了.

// A实现: br >> a; br >> b; br >> c; br >> d; br >> e; // B实现: a = br.ReadChar(); b = br.ReadShort(); c = br.ReadChar(); d = br.ReadInt(); e = br.ReadInt();

看出问题了吗? 没错, 在 B 实现中, 我们很容易的知道每步操作从缓冲区中读了多少数据. 而如果用 A 实现, 这些信息就不那么明显, 必须去检查各个变量的定义, 也许你会说 VC 里面把鼠标放上去就能看到定义, 但也别忘了一次只能看一个, 而 B 则可统观全局. 如果是个很大的程序, 那 B 的可读性和可调试性要高很多.

5. 对 B 的一个批评是暴露了实现细节, 把读了几个字节清晰的写出来了. 但我认为这恰恰是它的优点, 因为只有应该隐藏的细节才需要隐藏, 而这里, 知道读几个字节对缓冲区分析来说非常重要的, 是不应该被隐藏掉的. 无限制的隐藏细节只会给自己找麻烦. 打个比方, 把路的细节隐藏起来, 方法之一是把眼睛蒙上, 我们又怎么走路呢?

6. B 相对于 A 也有一个缺点, 就是 A 可以通过重定义 >> 运算符, 让自定义类型和原生类型使用看起来完全相同的方法被读出来, 但一般来说, 这一点的艺术性远大于实用性, 而且考虑到前面所有的缺点, 它不足以成为我们选择 A 的理由.

  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1063 引用 • 3455 回帖 • 165 关注
  • 技术

    到底什么才是技术呢?

    88 引用 • 179 回帖 • 4 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    286 引用 • 248 回帖 • 13 关注
  • Kotlin

    Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,由 JetBrains 设计开发并开源。Kotlin 可以编译成 Java 字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在 Google I/O 2017 中,Google 宣布 Kotlin 成为 Android 官方开发语言。

    19 引用 • 33 回帖 • 76 关注
  • Swagger

    Swagger 是一款非常流行的 API 开发工具,它遵循 OpenAPI Specification(这是一种通用的、和编程语言无关的 API 描述规范)。Swagger 贯穿整个 API 生命周期,如 API 的设计、编写文档、测试和部署。

    26 引用 • 35 回帖 • 3 关注
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖
  • webpack

    webpack 是一个用于前端开发的模块加载器和打包工具,它能把各种资源,例如 JS、CSS(less/sass)、图片等都作为模块来使用和处理。

    41 引用 • 130 回帖 • 250 关注
  • SEO

    发布对别人有帮助的原创内容是最好的 SEO 方式。

    35 引用 • 200 回帖 • 20 关注
  • V2EX

    V2EX 是创意工作者们的社区。这里目前汇聚了超过 400,000 名主要来自互联网行业、游戏行业和媒体行业的创意工作者。V2EX 希望能够成为创意工作者们的生活和事业的一部分。

    16 引用 • 236 回帖 • 269 关注
  • Angular

    AngularAngularJS 的新版本。

    26 引用 • 66 回帖 • 543 关注
  • Typecho

    Typecho 是一款博客程序,它在 GPLv2 许可证下发行,基于 PHP 构建,可以运行在各种平台上,支持多种数据库(MySQL、PostgreSQL、SQLite)。

    12 引用 • 67 回帖 • 445 关注
  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 176 关注
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 639 关注
  • Follow
    4 引用 • 12 回帖 • 9 关注
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    85 引用 • 165 回帖 • 1 关注
  • InfluxDB

    InfluxDB 是一个开源的没有外部依赖的时间序列数据库。适用于记录度量,事件及实时分析。

    2 引用 • 87 关注
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    200 引用 • 120 回帖
  • RYMCU

    RYMCU 致力于打造一个即严谨又活泼、专业又不失有趣,为数百万人服务的开源嵌入式知识学习交流平台。

    4 引用 • 6 回帖 • 53 关注
  • Excel
    31 引用 • 28 回帖
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 783 关注
  • SSL

    SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS 与 SSL 在传输层对网络连接进行加密。

    70 引用 • 193 回帖 • 415 关注
  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    1440 引用 • 10067 回帖 • 493 关注
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 702 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖 • 1 关注
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    66 引用 • 114 回帖 • 198 关注
  • 宕机

    宕机,多指一些网站、游戏、网络应用等服务器一种区别于正常运行的状态,也叫“Down 机”、“当机”或“死机”。宕机状态不仅仅是指服务器“挂掉了”、“死机了”状态,也包括服务器假死、停用、关闭等一些原因而导致出现的不能够正常运行的状态。

    13 引用 • 82 回帖 • 84 关注
  • Lute

    Lute 是一款结构化的 Markdown 引擎,支持 Go 和 JavaScript。

    28 引用 • 197 回帖 • 26 关注
  • Access
    1 引用 • 3 回帖 • 4 关注
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    76 引用 • 258 回帖 • 630 关注