上个月Linus通过Linux内核邮件列表一怒为注释,要求内核开发者“get rid of thebrain-damaged stupid networking comment syntax style”。估计Linus早就对网络协议栈代码里面不伦不类的注释风格颇有微词。当有人存在即合理式的要求沿用这种注释风格时,终于爆发了,火力全开的喷了一顿。最后号召大家看到类似风格怪异的注释,顺手改之。终于找到提交内核代码的捷径!窃喜窃喜:)

窃喜之余,想到匈牙利命名法又是何等的相似。要求弃用匈牙利命名法的固网新规范已推出许久,但匈牙利命名法依然大行其道。新规范遇冷的一个原因正是已有代码大多都使用这种命名法,于是就像协议栈的情况一样,开发者自然而然的沿用匈牙利命名法。如果使用新的命名方式,势必会出现两种命名法共存,这该如何是好?

在寻找破冰的方法之前我们先拨开历史的迷雾,看看匈牙利命名法到底是何方神圣

匈牙利命名法(下文简称为HN,即HungarianNotation)的雏形始于无类型语言BCPL,后经匈牙利裔美国人Charles Simony引入到开发Office的微软应用软件部,因其单词排列顺序类似古怪的匈牙利姓名而得名,后来也称作应用型匈牙利命名法(Apps Hungarian,下文简称为AHN)。而后AHN被曲解引入到系统软件部,形成了系统型匈牙利命名法(SystemsHungarian,下文简称为SHN)。再随着Windows的方兴未艾,四处开花以及各种开发文档的推波助澜特别是广为流传的《Windows 程序设计》第一版大量使用匈牙利命名法SHN逐渐成为Windows开发的事实标准。但是随之而来的也有反对的声浪,并在.net第一次发布时达到了高潮。微软在.net框架的《通用命名约定》中明确说明不建议使用匈牙利命名法(原文为DO NOTuseHungarian notation)。而后Windows 程序设计》第六版已经不怎么使用匈牙利命名法了。

为什么SHN会这么不受待见呢?我们先看看SHN是怎样一种命名方式。它是把变量实际的类型简单的罗列在变量名之前。以C语言为例,如变量iCount中的i表示这个变量的类型是语言内置的intstFooTmp的类型是用户自定义的结构体Foo。这些类型因为是实际的类型,又称之为物理类型。

SHN犹如符在变量身上的咒语。好处在于我们随时随地都可以透过这段奇异的符文看到变量的类型。在以前IDE尚显稚嫩的时代,倒是一用无妨。但是到了如今IDE足够智能之时,SHN就有些时过境迁了。借助IDE的魔法,我们也能随时随地知道变量的类型,甚至更多,比如变量是在哪里定义的,还能提供一些实时的错误检查。

对比之下,SHN更像是一种没有约束力的提示,就像注释一样。就算变量名里面的类型信息跟实际不符,编译器依然是安静的那一个,这时只能依靠人肉检查器,我想没几个人愿意成为肉盾。毕竟这是编译器的领域琐碎的类型检查交给工具去做不是更好?编译器不会眼花,还能给我们更多的提示。

从设计上来看,SHN没有提供有益的抽象,是把类型平铺直叙的列举出来,有时还十分冗长和拗口。例如,下面这个摘自viki上的变量说明:

a_crszkvc30LastNameCol:

a constant reference argument, holding the contentsof a database column LastName of type varchar(30)which is part of the table's primary key.

这个例子中变量的含义淹没在类型中。如果C++模板用上SHN,变量名该有多长。细思极恐。。。KISSKeep It Simple Stupid原则看来是满足不了了。

再看看下面这个赋值语句能不能赋值

ulFoo = ulBar;

单单从变量名上,这两个变量的物理类型是一样的。但是从概念上是不是同一类的就不得而知了。

再则SHN违反了SRPSingle Responsibility Principle原则。变量名聚合了两个不怎么相关又不在同一层次的东西,变量的含义和类型。变量含义在概念层次上,而变量类型是在实现层上。思维在两个层次上来回跳转,一会上天,一会入地,最后头昏眼花。于是我基本上已经养成忽略变量前缀的习惯,一如忽略注释的习惯。我之所以如此,还有因为HN本身的免责声明:本变量名按现状提供,不提供变量名同步于变量类型之保证。自然时不时会遇到变量名跟变量类型不相符的情况修改变量类型时,还得同步修改变量名,而且不只一处!于是DRYDon't Repeat Yourself原则也被打破了。

SHN依赖过甚,部分是由于变量定义和使用隔得太远导致的。换言之,函数过长。如果函数动辄上百行,再加上C89要求变量定义必须放在代码块开头(再加上有的同学把代码块开头误解为函数开头),于是乎,变量的定义和使用不在一屏里面就只能借助额外的手段来查变量类型了。如果函数很短,比如十行,还需要这样煞费苦心吗?

相比SHNAHN做了一层抽象,放在变量名前面不是物理类型,而是逻辑类型。例如如下代码:

int rwWidth, colWidth;

……

rwWidth = colWidth;

rw表示行(row),col表示列(column)。行跟列虽然物理类型是一样的,但是逻辑类型不一样(一个是行,一个是列)。把列赋给行,跨越了逻辑类型,可能存在问题。

从上可以看出,AHN构建了一个薄层,将物理类型转换为逻辑类型。逻辑类型将对象分门别类,紧随其后的名字有时候像是个属性。一般来说,逻辑类型跟名字要像X轴和Y轴一样尽量正交。

AHN的问题在于这一层只对人有意义,编译器不在乎,运行时也不关注。当然,这也有好处--几乎没有编译和运行的开销。但是坏处也显而易见没有编译器的支持,约束力有限,就算将两个不同概念的变量赋值也能编译通过,又得人肉编译器出马了。。。Coder表示不开心,压力山大。

到了面向对象的时代,逻辑类型的约束可以通过自定义的类来展现出来。比如以前例子中的行和列,可以分别定义一个RowColumn类,重载算操作符,再禁止RowColumn相互的赋值。这种约束方式既可以借助编译器的检查,也能通过代码显式的表达出来。

搞清楚匈牙利命名法之后,下一个问题是怎么破冰?让我们先看看Linus是怎么号召大家清理注释呢?他在邮件最后说道:So just get rid of the(no-no) and (no-no-no) forms. Not in one big go, but as people touch the code,just fix that mess up.

同样的,我们也不需要发起一次大扫荡,而是按需重构。那些本来就很稳定而又没有新需求的代码可以保持不变。新增文件和函数就按新规范来,不要再用匈牙利命名法了。至于修改已有代码,建议顺手重构。慢慢的,代码就变得更简洁了。

后记

最近听闻又冒出一个有望取代C++的新语言Rust。好吧,我只想说C++ will never die""字说明了一切。再加上C++11的进化步幅是如此之大。说话回来,Rust的名字由来众说纷纭而十分有趣。其中一个版本的解释来源于其字面意思--铁锈。话说一直以来编程语言领域有许多"老旧"的技术本是某些问题的灵丹妙药,却止步于实验室,随即束之高阁,无人问津。例如最近火起来的两种通用并发模型--actor模型和CSPCommunicating Sequential Process模型,本是上个世纪70年代的老古董。值得一提的是CSP是由Tony Hoare提出的,Tony的一句名言对我影响很大,详见附录。所以,Rust不引入闪闪发亮的新技术,而是将生锈的老技术付诸实践,化腐朽为神奇。我们也莫不如是三分热情的关心最新出炉的黑科技,以期找到银弹,结果却陷入死循环当中。高手之路看似高冷,其实一方面是打破已有的知识结构学习吸收新的编程范式;另一方面把知识化整为零(就像迭代开发一样),不断的重复练习小小的“零”。我们如果把已有的优秀编码方式和习惯真正践行起来,效果将是巨大的。借用《周易》上的一句话:那将是积善之家,必有余庆”。

附录

  1. Linux咆哮邮件,里面他列举了正确和错误的注释方法: http://lkml.iu.edu/hypermail/linux/kernel/1607.1/00627.html
  2. 微软.net框架的命名约定: https://msdn.microsoft.com/zh-cn/library/ms229045.aspx
  3. Joel Spolsky的《软件随想录》第十三章“让错误的代码显而易见”对于匈牙利命名法有更详细的介绍
  1. Tony Hoare的名言:构建软件有两种方式:一种是使其足够简单,以至于明显没有错误;另外一种是使其非常复杂,以至于没有明显的错误。原文为:There are two ways of constructing a piece of software: One is to make it so simple that there are obviously no errors, and the other is to make it so complicated that there are no obvious errors.

我眼中的匈牙利命名法相关推荐

  1. 骆驼命名法,帕斯卡命名法和匈牙利命名法(转)

    一.匈牙利命名法:广泛应用于象Microsoft Windows这样的环境中.       Windows 编程中用到的变量(还包括宏)的命名规则匈牙利命名法,这种命名技术是由一位能干的 Micros ...

  2. 【转】匈牙利命名法(Hungarian Notation)

    http://www.hudong.com/wiki/%E5%8C%88%E7%89%99%E5%88%A9%E5%91%BD%E5%90%8D%E6%B3%95 匈牙利命名法 匈牙利命名法是一种编程 ...

  3. c++ 请抛弃匈牙利命名法 - 变量命名代码风格的建议。

    我只针对c++码农们讲,其他语言不了解不过应该大同小异.曾几何时翻开21天学通c++系列等脑残入门书,都以匈牙利命名法示人(DWORD dwXXX, int nXXX, string strXXX). ...

  4. C++编程(一):匈牙利命名法

    匈牙利命名法 许多 Windows 程序员都使用"匈牙利标记法"作为变量命名约定.这是为了纪念具有传奇色彩的微软程序员 Charles Simonyi.这种标记法非常简单,其基本原 ...

  5. mfc编程淘汰了吗_四种基本的编程命名规范(匈牙利命名法、驼峰式命名法、帕斯卡命名法、下划线命名法)...

    匈牙利命名法 匈牙利命名法是早期的规范,由微软的一个匈牙利人发明的,是 IDE 还十分智障的年代的产物.那个年代,当代码量很多的时候,想要确定一个变量的类型是很麻烦的,不像现在 IDE 都会给提示,所 ...

  6. 匈牙利命名法、骆驼命名法、帕斯卡(pascal)命名法 C#命名规范

    一.匈牙利命名法:广泛应用于象Microsoft Windows这样的环境中. Windows 编程中用到的变量(还包括宏)的命名规则匈牙利命名法,这种命名技术是由一位能干的 Microsoft 程序 ...

  7. [摘抄] 匈牙利命名法

    匈牙利命名法中常用的小写字母的前缀: 前缀 整数类型 i 整型int l 长整型long int n 短整型short int w Word dw Double Word h Handle(句柄本身其 ...

  8. PHP书写规范 匈牙利命名法+驼峰法命名

    2019独角兽企业重金招聘Python工程师标准>>> PHP书写规范 PHP Coding Standard 变量命名规范这里感觉 打算采用 匈牙利命名法+驼峰法命名,因为 PHP ...

  9. 匈牙利命名法鼻祖---查尔斯·西蒙尼

    生平简介 1948年9月10日,查尔斯•西蒙尼(Charles Simonyi)出生于匈牙利布达佩斯.上高中时,他开始接触计算机和编程,父亲安排他给一名从事计算机工作的工程师当助手,当时计算机在匈牙利 ...

最新文章

  1. 如何在Spring Boot中玩转智能合约【修订版】
  2. 20165301第十周课下补做
  3. Django多进程中的查询错乱问题以及mysql gone away问题
  4. 【剑指offer】二叉树的深度_solution2
  5. python 全文搜索 句子_python新玩法:用python进行文章摘要拿取,只需要一行代码
  6. Java开发者必备:超全的Java问题排查工具单
  7. 端口冲突,可爱的8080
  8. VUE小需求——旋转小图标
  9. 3个月测试员自述:4个影响我职业生涯的重要技能
  10. fileReader学习-前端展示本地图片
  11. 内网服务器(不通外网)访问高德在线地图服务的方法
  12. Mysql组复制(MGR)——前提及限制
  13. MobaXterm连接虚拟机Ubuntu
  14. 小米球ngrok 给你惊喜
  15. 一切都是最好的安排之hibernate00
  16. 语音信号的同态处理、倒谱分析和Mel频率倒谱系数
  17. python批量循环图片识别_批量识别图中文字自动命名,让你1秒找到骚图
  18. unity 照片墙 流动 排斥 引力
  19. RegexBuddy、RegexMagic、EditPad官方绿色版
  20. 蚂蚁金服天街:蚂蚁双11大促OceanBase核心技术全解析

热门文章

  1. 【Java】创建文件夹
  2. 50部经典影片,你看过哪些?
  3. C语言的除法运算:整除/和求余%
  4. Problem D: 四阶多项式
  5. 英文名字大全解释 (详)
  6. 常见支持linux平台的应用软件
  7. 刨根问底 HTTP 和 WebSocket 协议(上)
  8. 什么是模块化?模块化有哪些优缺点
  9. Navicat 直接修改查询数据
  10. JS常用的输出内容的方式详解(5种输出方式)