如果把程序员比作中世纪的骑士,那编程bug就好比是中世纪的恐龙,不过如今的程序员可比中世纪的骑士要文明的多,但这并不意味着互联网时代就不存在“恐龙”了,可能这些大难题就在暗处等着我们自投罗网呢。
晚上对大多数人来说,就是好好休息,享受生活。但对程序员来说,经常是和Bug艰苦卓绝地作斗争,即便是数以亿计的程序员日夜努力,问题仍然像灌木丛中的杂草一样多,即便再强大的程序员有时也给跪了。以下列出的这些编程黑洞,即便是经验丰富的程序员也可能会掉进去。
多线程
多线程听起来是个不错的想法:将程序分解成几个独立的部分,让操作系统像运行单独的小程序一样工作。如果处理器有四个、六个、八个或者更多核,为什么不改写代码使程序可以分成四个、六个、八个或更多线程,以分开独立使用每个核呢?
当程序的各部分之间完全独立,彼此之间没有联系的情况下,这种方法是奏效的。一旦它们需要访问相同的变量或者读写同一个文件时,一切都将不一样。你无法预测最先获取数据的是哪个线程。
因此,我们创建监控机制、信号量和其他防止多线程混乱的工具。当线程开始工作,这些工具也开始工作。它们仅仅增加了一点复杂度,并且将在变量中存取数据的行为转化为一个需要多级思考的事情。
当这些监控工具不工作的时候,就会相当混乱。数据会变得没意义,列也不再增加,这就是在内存中会发生的事情。大多数时候,开发者最终会锁定庞大的数据结构,只允许一个线程接触它。这可能阻止混乱的继续,但要杀死很多操作同一个数据的线程,你不妨直接都改写成单线程。
闭包
有些人认为数据传送功能很实用,在简单情况下确实如此,当情况越来越复杂,程序员就开始意识到问题所在了。当函数向外调用或者需要访问外部变量时,通常叫做自由变量,数据是在函数调用时启动还是函数运行时启动呢?这一点对Java来说十分重要,这中间的差距可不是一星半点。
至于解决方案,闭包是Java(现在还加上了Java和Swift)程序员最头疼的问题之一。许多新手或者是许久没编程的老手都弄不明白到底什么是闭包,如何确定闭包的边界。
Java每次定义一个函数,都会产生一个作用域链(scope chain)。当Java寻找变量varible时(这个过程称为变量解析),总会优先在当前作用域链的第一个对象中查找属性varible ,如果找到,则直接使用这个属性;否则,继续查找下一个对象的是否存在这个属性;这个过程会持续直至找到这个属性或者最终未找到引发错误为止。简单地说,Java中的闭包,无非就是变量解析的过程。
数据过多
当RAM开始填满时,一切都开始向错误的方向发展。不管你是正在对用户数据进行分析还是正在对电子表格的数据进行操作。当机器的RAM消耗完之后,就会占用虚拟内存,硬盘运行速度会非常慢,基本是崩溃或停止工作的状态。问题是硬盘至少比RAM和大众磁盘驱动器慢20到30倍。如果其他进程也在努力地从磁盘上写或者读,一切都会变得很糟糕,因为驱动器一次只能做一件事。
激活虚拟内存会加剧软件其他的隐藏问题,如果存在线程问题,崩溃的会更加快,因为线程会跑到硬盘的虚拟内存中运行,速度会十分缓慢。但这只会持续一小段时间,一旦内存中有地或其他线程挂起,线程马上就会交换到内存中运行。如果代码是比较完美的,结果只是会比正常情况下出的慢一些,但可以保证是正确的。如果代码很一般,很有可能会快速导致线程崩溃。
这对程序员来说是个真正的挑战,代码中任何一点粗心造成的数据结构浪费最终可能都会降低整个算法效率,可能对付几个测试用例是没问题的,但真正高负载运行时就很容易失败。
NP完备
任何一个受过大学教育的计算机本科生都知道这个首字母缩写的全名:nondeterministic polynomial complete,缩写就是NP-complete。可能在大学课堂上,要想学明白这其中的奥妙需要花费一学期的时间,所以许多计算机的学生对此只有一个模糊的概念,认为它很难。
如果你只用蛮力攻击,NP问题确实不简单。比如著名的“旅行商问题”,是指一名推销员要拜访多个地点时,如何找到在拜访每个地点一次后再回到起点的最短路径。规则虽然简单,但在地点数目增多后求解却极为复杂。以42个地点为例,如果要列举所有路径后再确定最佳行程,那么总路径数量之大,几乎难以计算出来。
尽管如此,一些NP问题很容易通过近似的方式来解决,算法不给出具体的解决方案,但结果非常接近事实。可能没办法得出完美的旅行商推销员的路线,但可能在百分之八九十的点上都是正确的。
安全
布什在任期间的国防部长Donald Runsfeld曾在一次新闻发布会上说,这个世界上有很多已知的东西,我们知道我们自己知道。但也有很多未知的东西,我们可能还不知道我们不知道。
Rumsfeld认为伊拉克战争同样适用于计算机安全。最大的问题是我们甚至不知道哪里有漏洞。每个人都知道应该使用让外人难以猜测的密码,但可能没有人察觉到计算机软硬件里可能存在的漏洞。一切都是未知的,又如何预防。
对安全漏洞攻击的可能性不在于你知不知道,你可以设置复杂的密码,但你可能还是会被攻击,编程中的安全思想正在变得越来越重要。
加密
加密听起来似乎很高深,很令人费解。大多数加密问题都来自于建立在一个模糊的不确定的云上。我们会有很多不确定的假设,就好像面对着一大堆晦涩难懂的数字计算一样。这些问题真的很难解决吗?至今没有人公开表示哪个算法可以打破这一切难题,但并不意味着不存在解决方案。如果你发现了一种窃听和进入世界任何一家银行后台的方式,你会告诉全世界,以帮助银行修补漏洞吗?还是说你会保持沉默,等待东窗事发呢?
真正的挑战其实是我们给自己的代码加密,即便我们认为我们使用的算法足够安全。一旦你马虎,犯了一个错误,留下一个未保护的密码遭到攻击,整个程序就被撕开了入口,暴露给攻击者。
身份管理
每个人都很喜欢《纽约客》那幅漫画的标题“在互联网上,没有人知道你是一条狗”,这句话甚至被收录进了维基百科。
互联网时代的好消息是,任何人都可以匿名。坏消息是因为匿名可能会让很多人做事失了规则。一些程序员可能会说可以采用“双重验证”,但聪明的程序员往往会想到“N重验证”,除了密码,也可以使用手机验证码,或者指纹。现在的电子货币十分火热,因比特比而大火的区块链技术备受瞩目,我们依然无法解决这方面的身份验证问题。
衡量难度
在编程时,如果遇到困难,我们该如何衡量呢?没有人知道。我们只知道有些问题很容易解决,但有些问题不是你多努力就可以攻克的,NP问题就是一个例子,编写一个NP问题就可以尝试到复杂的算法和数据分析了。学会衡量困难的复杂度,找到合适的方法,脑子还要学会转弯。
编程是痛并快乐着的,很多程序员大多很认同这句话。虽说日夜与bug奋战,但看到代码顺利运行,结果出现在黑框上的那一刻,是十分有成就感的。希望广大程序员在编程时可以认真考虑以上七点,免得被套路了。
如果把程序员比作中世纪的骑士,那编程bug就好比是中世纪的恐龙,不过如今的程序员可比中世纪的骑士要文明的多,但这并不意味着互联网时代就不存在“恐龙”了,可能这些大难题就在暗处等着我们自投罗网呢。
晚上对大多数人来说,就是好好休息,享受生活。但对程序员来说,经常是和Bug艰苦卓绝地作斗争,即便是数以亿计的程序员日夜努力,问题仍然像灌木丛中的杂草一样多,即便再强大的程序员有时也给跪了。以下列出的这些编程黑洞,即便是经验丰富的程序员也可能会掉进去。
多线程
多线程听起来是个不错的想法:将程序分解成几个独立的部分,让操作系统像运行单独的小程序一样工作。如果处理器有四个、六个、八个或者更多核,为什么不改写代码使程序可以分成四个、六个、八个或更多线程,以分开独立使用每个核呢?
当程序的各部分之间完全独立,彼此之间没有联系的情况下,这种方法是奏效的。一旦它们需要访问相同的变量或者读写同一个文件时,一切都将不一样。你无法预测最先获取数据的是哪个线程。
因此,我们创建监控机制、信号量和其他防止多线程混乱的工具。当线程开始工作,这些工具也开始工作。它们仅仅增加了一点复杂度,并且将在变量中存取数据的行为转化为一个需要多级思考的事情。
当这些监控工具不工作的时候,就会相当混乱。数据会变得没意义,列也不再增加,这就是在内存中会发生的事情。大多数时候,开发者最终会锁定庞大的数据结构,只允许一个线程接触它。这可能阻止混乱的继续,但要杀死很多操作同一个数据的线程,你不妨直接都改写成单线程。
闭包
有些人认为数据传送功能很实用,在简单情况下确实如此,当情况越来越复杂,程序员就开始意识到问题所在了。当函数向外调用或者需要访问外部变量时,通常叫做自由变量,数据是在函数调用时启动还是函数运行时启动呢?这一点对Java来说十分重要,这中间的差距可不是一星半点。
至于解决方案,闭包是Java(现在还加上了Java和Swift)程序员最头疼的问题之一。许多新手或者是许久没编程的老手都弄不明白到底什么是闭包,如何确定闭包的边界。
Java每次定义一个函数,都会产生一个作用域链(scope chain)。当Java寻找变量varible时(这个过程称为变量解析),总会优先在当前作用域链的第一个对象中查找属性varible ,如果找到,则直接使用这个属性;否则,继续查找下一个对象的是否存在这个属性;这个过程会持续直至找到这个属性或者最终未找到引发错误为止。简单地说,Java中的闭包,无非就是变量解析的过程。
数据过多
当RAM开始填满时,一切都开始向错误的方向发展。不管你是正在对用户数据进行分析还是正在对电子表格的数据进行操作。当机器的RAM消耗完之后,就会占用虚拟内存,硬盘运行速度会非常慢,基本是崩溃或停止工作的状态。问题是硬盘至少比RAM和大众磁盘驱动器慢20到30倍。如果其他进程也在努力地从磁盘上写或者读,一切都会变得很糟糕,因为驱动器一次只能做一件事。
激活虚拟内存会加剧软件其他的隐藏问题,如果存在线程问题,崩溃的会更加快,因为线程会跑到硬盘的虚拟内存中运行,速度会十分缓慢。但这只会持续一小段时间,一旦内存中有地或其他线程挂起,线程马上就会交换到内存中运行。如果代码是比较完美的,结果只是会比正常情况下出的慢一些,但可以保证是正确的。如果代码很一般,很有可能会快速导致线程崩溃。
这对程序员来说是个真正的挑战,代码中任何一点粗心造成的数据结构浪费最终可能都会降低整个算法效率,可能对付几个测试用例是没问题的,但真正高负载运行时就很容易失败。
NP完备
任何一个受过大学教育的计算机本科生都知道这个首字母缩写的全名:nondeterministic polynomial complete,缩写就是NP-complete。可能在大学课堂上,要想学明白这其中的奥妙需要花费一学期的时间,所以许多计算机的学生对此只有一个模糊的概念,认为它很难。
如果你只用蛮力攻击,NP问题确实不简单。比如著名的“旅行商问题”,是指一名推销员要拜访多个地点时,如何找到在拜访每个地点一次后再回到起点的最短路径。规则虽然简单,但在地点数目增多后求解却极为复杂。以42个地点为例,如果要列举所有路径后再确定最佳行程,那么总路径数量之大,几乎难以计算出来。
尽管如此,一些NP问题很容易通过近似的方式来解决,算法不给出具体的解决方案,但结果非常接近事实。可能没办法得出完美的旅行商推销员的路线,但可能在百分之八九十的点上都是正确的。
安全
布什在任期间的国防部长Donald Runsfeld曾在一次新闻发布会上说,这个世界上有很多已知的东西,我们知道我们自己知道。但也有很多未知的东西,我们可能还不知道我们不知道。
Rumsfeld认为伊拉克战争同样适用于计算机安全。最大的问题是我们甚至不知道哪里有漏洞。每个人都知道应该使用让外人难以猜测的密码,但可能没有人察觉到计算机软硬件里可能存在的漏洞。一切都是未知的,又如何预防。
对安全漏洞攻击的可能性不在于你知不知道,你可以设置复杂的密码,但你可能还是会被攻击,编程中的安全思想正在变得越来越重要。
加密
加密听起来似乎很高深,很令人费解。大多数加密问题都来自于建立在一个模糊的不确定的云上。我们会有很多不确定的假设,就好像面对着一大堆晦涩难懂的数字计算一样。这些问题真的很难解决吗?至今没有人公开表示哪个算法可以打破这一切难题,但并不意味着不存在解决方案。如果你发现了一种窃听和进入世界任何一家银行后台的方式,你会告诉全世界,以帮助银行修补漏洞吗?还是说你会保持沉默,等待东窗事发呢?
真正的挑战其实是我们给自己的代码加密,即便我们认为我们使用的算法足够安全。一旦你马虎,犯了一个错误,留下一个未保护的密码遭到攻击,整个程序就被撕开了入口,暴露给攻击者。
身份管理
每个人都很喜欢《纽约客》那幅漫画的标题“在互联网上,没有人知道你是一条狗”,这句话甚至被收录进了维基百科。
互联网时代的好消息是,任何人都可以匿名。坏消息是因为匿名可能会让很多人做事失了规则。一些程序员可能会说可以采用“双重验证”,但聪明的程序员往往会想到“N重验证”,除了密码,也可以使用手机验证码,或者指纹。现在的电子货币十分火热,因比特比而大火的区块链技术备受瞩目,我们依然无法解决这方面的身份验证问题。
衡量难度
在编程时,如果遇到困难,我们该如何衡量呢?没有人知道。我们只知道有些问题很容易解决,但有些问题不是你多努力就可以攻克的,NP问题就是一个例子,编写一个NP问题就可以尝试到复杂的算法和数据分析了。学会衡量困难的复杂度,找到合适的方法,脑子还要学会转弯。
编程是痛并快乐着的,很多程序员大多很认同这句话。虽说日夜与bug奋战,但看到代码顺利运行,结果出现在黑框上的那一刻,是十分有成就感的。希望广大程序员在编程时可以认真考虑以上七点,免得被套路了。