上一篇以微信朋友圈为例解释了一下要写好一个软件是非常复杂的。这篇再接着从编程语言的角度去讨论这个问题。
软件是由编程语言组成的。编程语言是一种由逻辑生成的语言,由数据和函数组成。可以想像一个计算器,加减乘除是函数,各种数字就是数据。写一段复杂的程序就像用计算器写一段复杂的运算,得通过各种函数把数据串起来。每一种编程语言都提供了非常多的函数,所以能做的事情也比计算器多多了,但相应的写出来的程序也会比计算器复杂许多。一般一个程序能有上千上万行代码,而写一个带十几次运算的计算器已经非常复杂了。
除了编程语言提供的函数和数据以外,其实这个世界上有很多可以共用的函数和数据。比如普通计算器不会提供一元二次方程的求根公式,因为世界上有太多类似的常用函数可是计算器上没有那么多按键。编程语言也是一样,因容量限制,不可能包含所有常用的函数和数据。不过有一些人会把一些函数组装起来分享给大家使用,作为软件的库(可以理解为通过某种方式把普通计算器改成高级计算器)。然而,很多人并不会写很多文档来解释这些函数是什么和怎么用,于是会遇上“我以为它是一元二次方程求根公式但其实它居然是二元二次方程组求根公式”的情况。很有可能类似函数是用在一段非常复杂的计算当中,所以当整个程序跑起来的时候你会发现结果错了,但想要找出哪儿错了是非常难的。所以错误的使用别人写的函数也让写软件这件事变得非常复杂,因为在一段程序中你可能会用到十几个别人写的函数。
刚刚提到就算知道程序错了,但想要找出哪儿错了是非常难的。寻找错误的过程我们称为debug。在程序员的世界流传着这样一句话,coding一时爽,debug火葬场。对于一个普通程序员来说,coding和debug的投入时间比是小于1比1的,也就是说debug花的时间会更长。这是因为在正常情况下程序是自动跑的,不会哪里跑错了就停在那儿告诉你。如果不理解,同样可以想想计算器,假如你输错了一个数据从而导致结果错误,你就得从头开始一步一步查究竟错在哪儿。而这非常消耗时间和精力,比写一段计算要麻烦得多。
在有些情况下程序跑错了会返回一个错误的结果,但大部分情况下程序会崩溃,就是一段程序跑着跑着突然就退出不跑了,然后返回一些信息。你可能会觉得让程序崩溃还不如让它返回一个错误答案呢,事实上并非如此。程序在崩溃的时候返回的信息会告诉我们它是在哪儿崩溃的,这样debug起来就非常容易。而返回一个错误结果的话我就得从头开始看,一段几千几万行的代码去从头开始看,看得头大可能都找不到错误究竟在哪儿。然而崩溃也有崩溃的问题,用户体验不好。所以如何平衡崩溃和返回错误答案也是一个难点。好的程序员会找到一个比较合理的平衡点。
最后重新回到编程语言,它的逻辑其实是不自然的。比如计算1加到10,自然的想法是一个数一个数去加,简单的方法是套用公式,而程序员的思维有时候是这样的:
1+2+3+……+10就是10加上剩下的数相加的结果,那剩下的数相加的结果就是9加上剩下的数相加的结果……剩下的数相加的结果就是2加上剩下的数相加的结果,剩下的数就剩1了,好现在可以开始倒推计算剩下的数了。2加上剩下的数(1)等于〈3〉,3加上剩下的数相加的结果〈3〉等于[6]……9加上剩下的数相加的结果[36]等于{45},10加上剩下的数相加的结果{45}等于55。你可能会想,这不就是从头开始一个一个加么,确实是这样。但计算机的计算过程不仅可以一个一个加(这个计算过程叫循环),也可以像上面这样先拆开再计算(这个计算过程叫递归)。循环和递归并不等价,虽然这个例子里用循环和递归效果差不多,但在写软件的过程中有时候必须得用递归。所以程序员经常需要去站在编程语言的角度去思考问题,想法会变得和普通人不一样,但也只有这样才能写出高效率的程序。这里有个例子,如果你没学过编程,你可能根本看不懂这个答案在说什么:https://www.zhihu.com/question/31855632/answer/54367825
这一篇试着从编程语言的角度去解释了为什么写软件很难。如果以后有机会,希望可以从更多角度去思考这个问题。
网友评论