Cleaner, more elegant, and harder to recognize

更整洁,更优雅,但更难识别

看来,有些人把我几个月前一篇文章的标题“Cleaner,more elegant,and wrong”解释成了对异常通用处理的引用。(参见参考文献【35】,注意到电文甚至为我改变了文章的标题)

该文章的标题是对我从一本书中复制的特定代码段的引用,该书的作者声称他提供的代码“更整洁,更优雅”。我指出 ,代码片段不仅更更整洁,更优雅,也是错误的。

你可以编写正确的基于异常的程序

你要记住,这很难。

另一方面,虽然一些事情是很难的,但并不意味着不应该做。

下面是细节:

很容易                             难                        很难

写不好的基于错误码的代码      写好的基于错误码的代码    写好的基于异常的代码

写不好的基于异常的代码

编写差的代码很容易,无论用什么错误模型

编写好的基于错误码的代码比较难,因为你必须检查每个错误码,并考虑发生错误时应该如何做。

编写好的基于异常的代码非常难,因为你你必须检查每一行代码(实际上是每个子表达式),并考虑它可能引发什么异常以及代码对异常如何进行反应。(在C++中,这并不是那么糟糕,因为C++异常只在执行过程中的特定点抛出,在C#中,可以随时抛出异常)

但是没有关系,就像我说的那样,虽然一些事情很难但不意味着不应该做。写一个设备驱动程序很难,但是人们做了,这是一件好事情。

下面是另外一个表

很容易

很难

认识到基于错误码的代码写得差劲

认识到基于错误码的代码写得不差

认识到基于异常的代码写得差

认识到差的基于错误码的代码和不差的

基于错误码的代码之间的差别

认识到基于异常的代码写得不差

认识到差的基于异常的代码与不差的基于异常的代码间的差别

下面是一些虚构的基于错误码的代码。看看你把它划分为“差”或“不差”

BOOL ComputeChecksum(LPCTSTR pszFile, DWORD* pdwResult)

{

HANDLE h = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ,

NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

HANDLE hfm = CreateFileMapping(h, NULL, PAGE_READ, 0, 0, NULL);

void *pv = MapViewOfFile(hfm, FILE_MAP_READ, 0, 0, 0);

DWORD dwHeaderSum;

CheckSumMappedFile(pvBase, GetFileSize(h, NULL),

&dwHeaderSum, pdwResult);

UnmapViewOfFile(pv);

CloseHandle(hfm);

CloseHandle(h);

return TRUE;

}

这段代码显然不好。没有检查错误码。这是你匆匆忙忙时可能写的那种代码,意思是稍后再来修改。而且很容易发现,这个代码在成为好代码前需要进行大量的改进。

下面是另外一个版本:

BOOL ComputeChecksum(LPCTSTR pszFile, DWORD* pdwResult)

{

BOOL fRc = FALSE;

HANDLE h = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ,

NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (h != INVALID_HANDLE_VALUE) {

HANDLE hfm = CreateFileMapping(h, NULL, PAGE_READ, 0, 0, NULL);

if (hfm) {

void *pv = MapViewOfFile(hfm, FILE_MAP_READ, 0, 0, 0);

if (pv) {

DWORD dwHeaderSum;

if (CheckSumMappedFile(pvBase, GetFileSize(h, NULL),

&dwHeaderSum, pdwResult)) {

fRc = TRUE;

}

UnmapViewOfFile(pv);

}

CloseHandle(hfm);

}

CloseHandle(h);

}

return fRc;

}

这段代码仍然是错误的,但它看起来像是试图达到正确。这正是我说的“不差”。

下面是一些基于异常的代码,你可能在匆忙中写下:

NotifyIcon CreateNotifyIcon()

{

NotifyIcon icon = new NotifyIcon();

icon.Text = "Blah blah blah";

icon.Visible = true;

icon.Icon = new Icon(GetType(), "cool.ico");

return icon;

}

(这是一段关于任务栏通知图标的文章中摘录的真实程序的实际代码。轻微的变化是掩盖来源的徒劳无益的尝试)

下面的代码像是你修改之后的样子,能够在异常情况下正确处理,

NotifyIcon CreateNotifyIcon()

{

NotifyIcon icon = new NotifyIcon();

icon.Text = "Blah blah blah";

icon.Icon = new Icon(GetType(), "cool.ico");

icon.Visible = true;

return icon;

}

微妙的,不是吗?

很容易发现差的基于错误码的代码和不差的基于错误码的代码之间的差异:不差的基于错误码的代码检查错误码。 差的基于错误码的代码从不检查错误码。诚然,很难判断错误是否被正确处理,但至少你可以答出差的代码和不差的代码之间的差异。(这可能不是很好,但至少不差)

另一方面,看出差的基于异常的代码与不差的基于异常的代码之间的区别是非常困难的。

因为,当我编写基于异常的代码时,我没有奢侈地先写差的代码然后再将它们修改成不差的,如果我这样做,我无法找到差的代码,因为它看起来几乎与不差的代码相同。

我的观点并不是异常是差的。我的观点是异常太难了,我不够聪明处理他们。(同样地,好像,书籍的作者也是,即使他们试图教你如何使用异常编程)

(是的,有一些编程模型,如RAII和事物,但很少看到使用这些代码的示例)。

Cleaner, more elegant, and harder to recognize(翻译)的更多相关文章

  1. Cleaner, more elegant, and harder to recognize (msdn blog)

    It appears that some people interpreted the title of one of my rants from many months ago, "Cle ...

  2. Cleaner, more elegant, and wrong(msdn blog)

    Cleaner, more elegant, and wrong Just because you can't see the error path doesn't mean it doesn't e ...

  3. Cleaner, more elegant, and wrong(翻译)

    Cleaner,more elegant,and wrong 整洁,更优雅,但是错的 并不是因为你看不到错误的产生路径就意味着它不存在. 下面是C#编程书中的一个片段,摘自关于异常处理的章节. try ...

  4. Go 开发关键技术指南 | 敢问路在何方?(内含超全知识大图)

    作者 | 杨成立(忘篱) 阿里巴巴高级技术专家 Go 开发关键技术指南文章目录: 为什么你要选择 Go? Go 面向失败编程 带着服务器编程金刚经走进 2020 年 敢问路在何方? Go 开发指南大图 ...

  5. Go 开发关键技术指南 | Go 面向失败编程 (内含超全知识大图)

    作者 | 杨成立(忘篱) 阿里巴巴高级技术专家 关注"阿里巴巴云原生"公众号,回复 Go 即可查看清晰知识大图! 导读:从问题本身出发,不局限于 Go 语言,探讨服务器中常常遇到的 ...

  6. C# Development 13 Things Every C# Developer Should Know

    https://dzone.com/refcardz/csharp C#Development 13 Things Every C# Developer Should Know Written by ...

  7. 【转载】Gradle学习 第六章:构建脚本基础

    转载地址:http://ask.android-studio.org/?/article/11 6.1. Projects and tasks 项目和任务Everything in Gradle si ...

  8. PEP8中文翻译(转)

    原文:https://github.com/zgia/manual PEP 8 -- Style Guide for Python Code PEP Index > PEP 8 -- Style ...

  9. LLVM 编码规范 - 中文翻译

    LLVM 编码规范 导论 语言.库和标准 C++ 标准版本 C++ 标准库 Go 代码准则 机械的代码问题 代码格式化 注释 头文件 类概述 method information 注释格式化 使用Do ...

随机推荐

  1. IOS 修改UIImage大小

    在iOS中,uiimage没有用于修改大小的属性,要在代码中改变uiimage图片的大小,需要扩展UIImage类,如下: 头文件: #import<UIKit/UIKit.h> @int ...

  2. python并发编程之多进程二

    一,multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程.P ...

  3. caffe+opencv3.3dnn模块 完成手写数字图片识别

    最近由于项目需要用到caffe,学习了下caffe的用法,在使用过程中也是遇到了些问题,通过上网搜索和问老师的方法解决了,在此记录下过程,方便以后查看,也希望能为和我一样的新手们提供帮助. 顺带附上老 ...

  4. 模块化编程node

    众所周知,Node.js 的出现造就了全栈工程师,因为它让 JavaScript 的舞台从浏览器扩大到了服务端 而 Node.js 的强大也得益于它庞大的模块库,所以学习 Node.js 第一步还得从 ...

  5. Js特殊字符转义之htmlEscape()方法

    为了防止XSS攻击,常常需要将用户输入的特殊字符进行转义,原生js貌似还没有直接对其专业的方法,最近再读Js高级程序设计的时候刚好看到,碰巧项目中也刚好需要使用次方法,于是就之家搬来用了. 网上关于转 ...

  6. 51Nod 1293 球与切换器 DP分类

    基准时间限制:1 秒 空间限制:131072 KB   有N行M列的正方形盒子.每个盒子有三种状态0, -1, +1.球从盒子上边或左边进入盒子,从下边或右边离开盒子.规则: 如果盒子的模式是-1,则 ...

  7. 算法提高 9-3摩尔斯电码 map

    算法提高 9-3摩尔斯电码 时间限制:1.0s   内存限制:256.0MB     问题描述 摩尔斯电码破译.类似于乔林教材第213页的例6.5,要求输入摩尔斯码,返回英文.请不要使用"z ...

  8. Windows下安装solr步骤详解

    Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口.用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引:也可以通过Http Get操 ...

  9. 三十天学不会TCP,UDP/IP网络编程-ARP -- 连接MAC和IP

    继续来做(da)推(guang)介(gao)我自己的!由于这两年接触到了比较多的这方面的知识,不想忘了,我决定把他们记录下来,所以决定在GitBook用半年时间上面写下来,这是目前写的一节,目前已完成 ...

  10. loadrunner 参数存储在data.ws、paralist、globals.h 中区别(参数与变量额区别于使用)

    1.如果变量数据只有一个值,可以直接放在data.ws 中    2.如果变量要根据循环取随机值.序列值等(参数存在一组值),放在paralist中     3.如果是申明全局变量,且要在代码中用到参 ...