为什么说选择正确的编程语言很重要,以及如何正确的选择

几个月前,一个同事问我,应该如何选择编程语言,或者有没有什么固定的选择模式,当时我便打算写点什么。上周在硅谷开会,这我是第一次跟 “hack3rs”的创业狂以及技术狂们打交道。我学会了很多前所未闻的脏话,也有所得–即便是追求精简的初创企业也倾向于把问题过份复杂化。

将真正领悟精简精神的人甄别出来并不困难。谷歌,Facebook以及Akamai的程师们的讲座魅力十足。他们从一个更宏观的角度思考和解决问题。这跟公司的财力,规模没有关系,他们特意剪除细枝末节,以便将注意力集中在问题的根本。

我自己也曾一味要求手下考虑使用高级编程语言甚至全面向对象语言,我发现许多的新时代初创企业也还没领悟其精髓。他们用Javascript、Python和Ruby编程,却不明白为什么要用这些语言。

不可否认,把循环写得紧凑或者避免使用模板固有其道理。但如果这是你选择一门编程语言的唯一理由,那么你就大错特错了。日常工作中,与其用基于深度 优化的向量化C++语言构建的多核并行异步map-reduce架构去做一个卷积离散傅立叶变换(correlation-DFT),我宁愿用BASIC 来做一个快速傅立叶变换(FFT)。

那么到底应该根据什么来选择编程语言呢?唯一检验标准:是否言而达意。

抛开语言的执行效率和功能等等不谈,一门语言必须能够让你描述自己的意图,不光是对编译器而言,更是对未来的读者而言。我相信软件维护中99%的问 题都是由于最初写代码的人没能准备表述他们的意图造成的。如果言不达意,文档就不叫文档。如果言不达意,UML图就不是UML图。如果无法描述某种数据型 适用于哪些操作符的话,面向对象编程就不是面向对象编程。言而达意不是指C风格的ModifyWindowEx(HWND wnd)不易读而Window.modify()告诉了你和编译器这个window可以和不可以做什么。关键是要表明你的意图。

Fortran如今已大大落后,因为它用下面这种方式描述一个算式:

MOV AX, $5D
ADD AX, $6F
MOV $7F, AX

其实完全可以写成这样:

c = a + b

如此你就知道是a加上b,结果存到c,即便你不懂计算机也能看懂。

一个常见的误解是:函数式编程语言表达你要什么(what you want)而命令式编程语言表达你想怎样(how you want)。

这是一种糟糕的理解。因为有时候“你想怎样”恰恰是你想表达的意思。

按照我一贯的博文风格,请你问自己一个基本问题,当面临语言的选择时:

“我是否把意思说清楚了?”

如果你无法回答这个问题,那么你没有用最佳语言。如果你不得不写文档或者做注释,这说明你的代码没能描述你的意图。看看这个函数原型:

char* reverseString(const char *foo);

在缺少关于空指针,空字符串以及其他异常处理文档的帮助下,根本没法理解作者到底想干什么。这不太好。当然,函数内部可能对输入做了无数的验证,但你必须写一堆针对各种特定输入的单元测试以确保你的假设是正确的。

我所指的“把意思说清楚”是什么意思呢?假设C++在原型中支持以下虚拟语法:

char* @Nullable reverseString(@NonNullable const char *foo);

函数原型中加上这些注解有两个好处:

  1. 你不需要事先测试foo是不是null。编译器保证会给你一个非null。
  2. 明确地告诉调用者你不容忍null。这种表述方式编译器能够明白,优秀的静态分析工具可以检测到这类bug,这是C语言做不到的。

虽然这看起来只不过是增强了一下语法,实际不仅如此,它还增强了语义。如此不论是人或是机器就明白foo这个变量不可为null,否则函数很生气,后果很严重。而且,你给这个函数划定了界限,再不用担心foo可否为null了。

函数式编程并不是万金油:

大家对我的另外一个常见误解是我推崇纯函数式语言。我的确有理由喜欢它们。看到上面那个式子了吗?

c = a + b

如果我想把expr1和expr2的值相加该如何表达呢?

c = (expr1) + (expr2)

如果expr1有附加操作而且会影响expr2的值又该如何表达呢?这并不罕见:

c = (a++) + (a + b);

这里的问题不是你想的那样。我知道你在想什么:“天知道这门语言会如何解释这个式子。万一计算的顺序反了怎么办?”

你想错了。正是由于人们会产生那样的想法,编程语言才会有这样的特点。要解答你的疑问很简单,看看编译手册就知道了。

上面式子的根本问题是我无法知道那样的计算顺序是偶然的还是有意的。我确切地知道上面式子的会做什么,但我无法确定的是,它的计算顺序是不是有意 的?我能不能优化那个式子,放到一个循环里去?我能不能在多核多线程的情况下调用它?假设有人问我,如果给z赋值10而不是20,会不会影响c的值,我无 法回答。

理论上是无法回答上面那个问题的。当然了我们可以根据经验做加一些断言(assertion)。在断言出了一堆或者一个警告后,理性地说,我们仍然不知道z会不会影响a或者b,最终影响到c。

为什么这很重要

代码的可维护性是建立在代码的可阅读性的基础上的。你知道为什么CSS不好吗?如果仅仅是程序员写错了或者设计者把字体和布局规则混淆了,地球人都知道那还不算太坏。CSS坏就坏在如果不加上大量的注释,人们就无法通过字面上的意思来理解代码的意图。

别忘了基于规则的声明式语言并不是新概念,更不是革命。50年前Prolog就提供了类似CSS的声明方式。今天的Erlang也提供了这类方式,并在业界得到广泛应用。

请看下面这行代码:

div .title #subtitle {color: blue}

如果不加载试一下的话,我敢打赌你完全想不到这会对页面产生怎样的效果。字面上完全看不出跟其它规则的关系,也看不出它如何处理匹配冲突。

因此对于汝等Ruby/Python/Node.js程序员而言,我的建议是,如果你真想超凡脱俗的话,学学谷歌和Facebook。他们使用一些 实验性技术,并不是为了取代for-loops,而是用来表明for-loops的意图。快速原型的话选择简单的语言就可以了,当需要准确描述意图的时候 才考虑更换编程语言。

**命令式语言的必要性:
**
最后,我想解释一下为什么命令式语言是必要的。看看下面这个驱动程序例子:

setlpt1(00000000b);

setlpt1(00010000b);

setlpt1(00000000b);

这是我假想的串口命令协议。这几行代码是按照先后顺序排列的。哪怕200年以后,它们的意图也不会发生什么变化。必要的时候使用命令型语言,明确地 告诉读者不要打乱这些代码。你不应该改变它们的顺序。你也不会把他们用在某些抽象的端口上,它们只适用于串口或者所谓打印机口。

用函数式语言来实现上面的功能,并且加上同步原语来保证它们按照顺序运行,是愚蠢的。

结论:

如果说这篇文章有一点点值得总结的东西的话,那便是:下次你写任何代码/规范/程序的时候,问问自己,意图是否清楚表达?未来的维护者看到你写的东西,是否能明白它

时间: 2024-09-16 00:23:57

为什么说选择正确的编程语言很重要,以及如何正确的选择的相关文章

李彦宏回顾百度十年创业:很庆幸生在正确时代

导读:李彦宏表示,百度乔迁新居是百度十年历史上重要时刻.百度很庆幸生在了一个正确的时代,赶上了很好的机会.李彦宏回顾百度十年创业:很庆幸生在正确时代 ( 腾讯科技配图) 腾讯科技讯11月17日消息,百度CEO李彦宏今日在百度乔迁新居典礼上发表演讲时表示,百度乔迁新居是百度十年历史上重要时刻.他表示,百度很庆幸生在了一个正确的时代,赶上了很好的机会. 今日上午,百度举办了盛大的乔迁典礼,庆祝公司正式迁入位于上地信息产业基地的新办公和研发大厦--百度大厦. 李彦宏透露,十年前他怀着梦想来到中关村创业

c语言-以下叙述正确的是()以下叙述正确的是()

问题描述 以下叙述正确的是()以下叙述正确的是() 以下叙述正确的是(). A:do-while语句构成的循环不能用其它语句构成的循环来代替. B:do-while语句构成的循环只能用break语句退出. C:用do-while语句构成的循环,在while后的表达式为非零时结束循环. D:用do-while语句构成的循环,在while后的表达式为零时结束循环 解决方案 d,为0表示false 解决方案二: 选择D,这是while循环的基础知识,当条件为真时执行循环体,知道条件为假. 计算机世界中

求 商品规格选择-求JQ或JS仿淘宝商品详情选择规格颜色等功能

问题描述 求JQ或JS仿淘宝商品详情选择规格颜色等功能 选择要求:有几个属性,如 尺寸和颜色,尺寸:M.L.XL.XXL 等,颜色:黑色.白色.黄色.红色等,其每个属性都有关联,如 首选M,颜色除黑色或其他外都能选择:如首选 黄色,尺寸除XXL或其他外都能选择. 自己写的有问题.代码放上一部分.已生成的数组求值. HTML:↓ <div class="sys_item_spec"> <dl class="clearfix iteminfo_parameter

关于link环境下对象的选择是怎么实现的?如何实现对象的选择?

问题描述 关于link环境下对象的选择是怎么实现的?如何实现对象的选择? 关于link环境下对象的选择是怎么实现的?如何实现对象的选择? 解决方案 对象选择?你说的是控件选择么? control.Active()

gcc vc++6.0-同样代码VC6.0结果正确,GCC编译运行结果不正确,原因是什么呢?谢谢!

问题描述 同样代码VC6.0结果正确,GCC编译运行结果不正确,原因是什么呢?谢谢! #include int main() { char deno[1000]={''},num,i=0,remain=0; scanf("%s %d",deno,&num); //获取被除数.除数 if(!num) return (-1); while(deno[i]!='') deno[i++]-='0'; //转换成数字 deno[i]='#'; //结束标志 i=0; while(deno

急!!申请企业开发者帐号应该选择哪个啊?,299$的那个到底应该选择哪个啊?!!

问题描述 急!!申请企业开发者帐号应该选择哪个啊?,299$的那个到底应该选择哪个啊?!! 解决方案 个人开发者选第一个 公司组织选第二个 政府选第三个 企业选择第二个.

js代码放到浏览器正确运行,放到ready里面不能正确运行

问题描述 js代码放到浏览器正确运行,放到ready里面不能正确运行 function outpic() { var outs = $('.out') for (i=0;i<outs.length;i++){ var inputText = outs[i].innerText; try { $('.out')[i].innerHTML = AnalyticEmotion(inputText); }catch(err) { console.log('x') outpic() } } } outpi

如何根据你想要的生活选择第一门编程语言

程序员的生活轻松.工作机会众多,而且薪资也不错. 即使你不想从事程序员这个职业,学点编程仍然是没错的.尤其是对于那些网页设计.数字营销.企业和IT行业的工作岗位来说. 但是你应该学习哪门语言呢? Udacity网站制作了一张很棒的信息图(见下文),有助于你选择.但是我还想讲得更深入一点. 在它们那张信息图的基础上,我会根据你的愿望,分门别类地给出我的建议.比如,我会针对于旅行爱好者.设计师.IT人员或者其他职业的人员给出建议. 过去一年中,我面试了很多人,面试的岗位也不一样.我经常和其他也在招聘

经典算法(4) 直接选择排序及交换二个数据的正确实现

直接选择排序和直接插入排序类似,都将数据分为有序区和无序区,所不同的是直接播放排序是将无序区 的第一个元素直接插入到有序区以形成一个更大的有序区,而直接选择排序是从无序区选一个最小的元素直 接放到有序区的最后. 设数组为a[0-n-1]. 1. 初始时,数组全为无序区为a[0..n-1].令 i=0 2. 在无序区a[i-n-1]中选取一个最小的元素,将其与a[i]交换.交换之后a[0-i]就形成了一个 有序区. 3. i++并重复第二步直到i==n-1.排序完成. 直接选择排序无疑是最容易实现