偶然地,我偶然发现了Linus Torvalds的以下引文:


“糟糕的程序员担心代码。好的程序员担心
数据结构及其关系。“


最近几天我一直在考虑它,但我仍然感到困惑(这可能不是一个好兆头),因此我想讨论以下内容:


对此可能/有意义的解释是什么?
可以从中学到什么?


评论

我认为这个问题可能有多个同样有效的答案。但这还是个好问题。我喜欢那句话。它表达了为什么我不理解担心切换语言的程序员的原因。程序中很少使用语言,而是数据结构及其之间的关系。

也许,如果您花时间使数据结构“优雅”,那么不必费解代码即可处理这些数据结构?我可能很愚蠢,无法真正了解Torvalds报价的含义。 :}

@RyanKinal当然,语言确实很重要,因为它使处理和考虑某些数据结构变得相当容易。例如,考虑所有专门用于LISt解析的语言,或者对必须入侵其他语言的数据结构提供本地支持的语言(会想到集合和稀疏数组)。

顺便说一下,Torvalds并不孤单:“向我展示您的流程图并隐藏您的表,我将继续感到困惑。向我展示您的表,我通常将不需要您的流程图;这很明显。 ” –弗雷德·布鲁克斯(Fred Brooks),《神话人月》。 “向我展示您的代码并隐藏您的数据结构,我将继续感到困惑。向我展示您的数据结构,我通常不需要您的代码;这很明显。”和“智能数据结构和哑代码比其他方法要好得多。” –埃里克·雷蒙德(Eric S. Raymond),大教堂和集市。

这解释了为什么Linux内核是一团糟:)

#1 楼

考虑一下Torvalds在此之前所说的内容可能会有所帮助:


git实际上具有简单的设计,具有稳定且合理记录的数据结构。实际上,我非常支持围绕数据设计代码,而不是相反地设计代码,并且我认为这是git相当成功的原因之一[...]实际上,我将声称两者之间的区别一个不好的程序员和一个好的程序员之间的关系是,他是否认为自己的代码或数据结构更重要。


他的意思是,好的数据结构使代码非常容易设计和维护,而最好的代码无法弥补不良的数据结构。

如果您想了解git示例,许多版本控制系统会相对定期地更改其数据格式以支持新的功能。升级以获得新功能时,通常还必须运行某种工具来转换数据库。

例如,当DVCS首次流行时,很多人都无法想象相比于集中式版本控制,使分布式模型的合并要干净得多。答案是绝对没有,除了分布式数据结构必须要好得多才能完全有希望工作。我相信集中式合并算法已经赶上了,但是花了很长时间,因为它们的旧数据结构限制了它们可以使用的算法种类,而新的数据结构破坏了很多现有代码。


评论


最好的代码不能弥补不良的数据结构

–康拉德·弗里克斯(Conrad Frix)
2012年8月31日在18:38

他是从程序员的角度对git本身进行更改的。最终用户的观点与该讨论完全正交,除了易于维护的代码制作(减少错误和增加功能)之外。

–卡尔·比勒费尔特(Karl Bielefeldt)
2012年8月31日19:07

@James:他是说软件更好(因此更易于使用,并且被更多的人使用),因为数据结构更好。当然,您不需要了解所使用软件的数据结构,但是即使您没有意识到它,也确实会间接地关心它们,因为数据结构是驱动您实现自己的事物的驱动力关心。

–ruakh
2012年8月31日19:09

+1。此答案将上下文放在声明上,否则可以解释为表示非常不同的含义。读过文件的5000行怪物的人都知道我的意思。

–riwalk
2012年8月31日20:16



“首先担心数据结构,您的代码自然会更干净。”:罗马政治家Cato(en.wikipedia.org/wiki/Cato_the_Elder)曾经说过“ Rem tene,verba sequentur” =“请在你的想法,这些话自然会随之而来。”与编程相同:首先了解数据结构和设计,然后再实际编写代码。

–乔治
2012年9月23日上午8:37

#2 楼

算法+数据结构=程序

代码只是表达算法和数据结构的方式。

评论


最新版本ethoberon.ethz.ch/WirthPubl/AD.pdf

–dchest
2012年9月23日在11:13

对于过程编程而言,这是正确的。在OOP中有点不同。

–随机42
2012-09-24 17:21

从根本上来说没有什么不同。您有数据并对其进行了一系列操作。成员变量和方法。完全一样。自从50年代以来,整个计算的本质就是建立在一个非常简单的规则上,即程序由修改数据结构的算法组成,并且在60年后一直保持不变。您也可以将程序视为函数。他们接受输入,然后对其进行操作以产生输出。就像数学函数一样。

– zxcdw
2012年9月24日在18:10

#3 楼

这句话对“ Unix编程的艺术”中的规则之一非常熟悉,这是Torvalds的强项,他是Linux的创造者。该书位于此处的网上

书中的以下引文阐述了Torvalds在说什么。


表示法则:将知识汇总为数据程序逻辑可能是愚蠢且健壮的。

即使最简单的过程逻辑也很难被人类验证,但是相当复杂的数据结构也很容易建模和推理。要看到这一点,请将(例如)五十节点指针树的图与五十行程序的流程图的表现力和解释力进行比较。或者,将表示转换表的数组初始化程序与等效的switch语句进行比较。透明度和清晰度上的差异是巨大的。请参阅Rob Pike的规则5。

数据比程序逻辑更容易处理。因此,如果您在数据结构的复杂性和代码的复杂性之间做出选择,请选择前者。更多:在设计的演变过程中,您应该积极寻求将复杂度从代码转换为数据的方法。

Unix社区并不是产生这种见解的,但是很多Unix代码显示了它的影响力。特别是C语言在处理指针方面的便利性鼓励从内核开始在所有编码级别上使用动态修改的引用结构。在这种结构中进行简单的指针追逐经常会执行职责,以其他语言的实现则必须体现在更复杂的过程中。


评论


我也记得这个!

– Jesvin Jose
2012年9月24日上午11:04

OTOH,请查看有关int **的所有StackOverflow问题。那应该使您确信数据实际上并不明显。只有将含义附加到数据上,情况才会如此。意思就是代码。

– MSalters
2012-09-27 14:36

#4 楼

代码很简单,这是复杂代码背后的逻辑。

如果您担心代码,这意味着您还没有掌握这些基础知识,并且很可能会迷失在复杂的代码(即数据结构及其关系)上。

评论


嘿,我想知道下一代程序员是否会问:“ Morons曾经说过代码很简单,但是代码背后的逻辑很复杂,这是什么意思?”

– yannis
2012年8月31日18:19



@YannisRizos当人们不确定是白痴的人还是以白痴的名字说一个人时,这会特别令人困惑。

– KChaloux
2012年8月31日19:06

#5 楼

为了进一步扩展Morons的答案,我们的想法是理解代码的细节(语法,在较小程度上,结构/布局)非常容易,因此我们构建了可以做到这一点的工具。编译器可以理解所有关于代码的知识,以便将其转变为可运行的程序/库。但是编译器实际上无法解决程序员所遇到的问题。

您可以将参数更进一步,说“但是我们确实有生成代码的程序”,但是它生成的代码是基于

因此,无论采用哪种途径获取代码,都是通过某种配置或其他通过工具生成代码的输入,或者如果您是从头开始编写的,那么与代码无关紧要。至关重要的是对获得该代码所需的所有部分的批判性思考。在Linus的世界中,主要是数据结构和关系,尽管在其他领域可能是其他部分。但是在这种情况下,Linus只是说“我不在乎您是否可以编写代码,我在乎您能够理解可以解决我正在处理的问题的事物”。

评论


每个程序员都使用生成代码的程序。它们通常被称为“编译器”,有时与“链接器”结合使用。它们采用(相对)人类可读和人类可写的输入,通常(但并非总是)以某种文本格式提供输入,并将其转换为计算机可以理解为指令并执行的数据。

–用户
2012-09-27 7:54



#6 楼

Linus的意思是:


向我展示您的流程图[代码],并隐藏表格[模式],并且
我将继续被迷惑;向我显示您的表格[模式],而我
通常不需要您的流程图[代码]:它们将很明显。


-弗雷德·布鲁克斯,“神话《月刊》,第9章。

#7 楼

我想他是说总体的高层设计(数据结构及其关系)比实现细节(代码)重要得多。我认为他重视那些可以设计系统的程序员,而不是只专注于系统细节的程序员。

两者都很重要,但我同意获得总体了解并拥有更好的机会细节方面的问题比其他方法要差。这与我试图表达的将大功能分解为小功能密切相关。

评论


+1:我同意你的看法。另一个方面是,程序员通常更担心他们将使用什么炫酷的语言功能,而不是专注于他们的数据结构和算法以及如何以简单明了的方式将其写下来。

–乔治
2012年9月1日19:34在

我也同意。事实是,更改孤立的代码段很容易,但是更改代码段之间的数据结构或接口比较困难(因为这些类型的更改可能会影响很多事情,而不仅仅是一件事情)。

–布伦丹
2012年9月23日14:05

#8 楼

好吧,我不能完全同意,因为您必须担心所有这些。就此而言,我最喜欢编程的一件事是通过不同级别的抽象和大小进行切换,这些切换从思考纳秒迅速转变为思考月数,然后又回到过去。

更高的事情就更重要。

如果我在一系列会导致不正确行为的问题上存在缺陷,则可能不太难解决。如果导致性能不佳,甚至可能都没有关系。

如果我在子系统的数据结构选择方面存在缺陷,会导致不正确的行为,那是更大的问题,更难解决。如果它导致其性能不佳,则可能会很严重或尚可忍受,但仍然比竞争对手的方法差很多。

如果我在最重要的数据结构之间的关系中存在缺陷在一个应用程序中,这会导致不正确的行为,我现在面临着巨大的重新设计。如果它导致其性能不佳,则可能会很糟糕,以至于如果它表现出错误,就会更好。

这将使发现那些较低层次的问题变得困难(修复低级错误通常很容易,发现它们很难。)

低级内容很重要,而其剩余的重要性通常被低估了,但是与大东西。

#9 楼

知道代码的人会看到“树”。但是了解数据结构的人会看到“森林”。因此,优秀的程序员将更多地关注数据结构而不是代码。

评论


但是只关注森林或树木而将其排除在外可能是有害的,因此我认为这种比喻不合适。

– kojiro
2012年9月1日0:17在

@kojiro:在表达式中看不到森林的树木,假设可以看到森林的人也会看到树木(请参阅en.wiktionary.org/wiki/see_the_forest_for_the_trees)。因此,我认为这是一个很好的类比。

–特雷布
2012年9月1日4:07



#10 楼

知道数据将如何流动非常重要。了解流程要求您设计良好的数据结构。

如果您回溯二十年,这是使用SmallTalk,C ++或Java的面向对象方法的最大卖点之一。至少是在C ++中,因为这是我首先学到的,这是设计类和方法的最大基调,然后其他所有方法都应付诸实践。

Linus无疑是在用更广泛的术语进行讨论,但是设计不良的数据结构通常需要对代码进行额外的重做,这还可能导致其他问题。

#11 楼


可以从中学到什么?


如果可以的话,我在过去几周的经验。前面的讨论澄清了我的问题的答案:“我学到了什么?”

我重写了一些代码并反思了我不断看到的结果,并说“结构,结构...”如此巨大的差异。现在,我看到是数据结构使一切有所不同。而且我的意思是全部。


测试我的原始交付后,业务分析师告诉我它不起作用。我们说“增加30天”,但我们的意思是“增加一个月”(结果日期中的日期不变)。添加离散的年,月,日;例如,对于18个月来说,不是540天。
解决方法:在数据结构中,将一个整数替换为包含多个整数的类,将其构造更改限制为一种方法。更改实际的日期算术语句-全部为2。

支付



新实现具有更多功能,但算法代码更短且更简单。

在修复代码行为/结果中:


我更改了数据结构,而不是算法。
代码中的任何地方都没有触及控制逻辑。
未更改任何API。
数据结构工厂类完全没有改变。


#12 楼

我想想象一个非常聪明的图书馆员团队,在一个精美的图书馆中,拥有一百万本随机且精采的书籍,这真是愚蠢。

#13 楼

我完全不同意莱纳斯。关注数据有助于极大地提炼出针对给定问题的简单而灵活的解决方案。 Git本身就是一个证明性的例子-在多年的开发中提供了如此多的功能支持,核心数据结构在很大程度上保持不变。太神奇了! --2c

#14 楼

我已经看到了很多领域。

思考业务分析...假设您正在分析像高露洁这样的消费品公司支持市场营销的最佳方法。如果您从花哨的窗口或最新技术入手,那么您对企业的帮助就不会比首先考虑企业的数据需求,然后再担心展示会有所帮助。数据模型比演示软件更耐用。

考虑制作网页。最好先考虑要显示的内容(HTML),然后再考虑样式(CSS)和脚本编制(选择工具)。

这并不是说编码就是“也很重要。您需要编程技巧才能最终获得所需的东西。数据是基础。不良的数据模型反映了过于复杂或未考虑的业务模型。

#15 楼

我发现自己编写新功能和更新现有功能的频率要比向我的数据库模式添加新列或表的更多。
对于所有设计良好的系统来说,这可能都是正确的。如果您每次需要更改代码时都需要更改架构,那么这显然是一个非常糟糕的开发人员。

代码质量指标= [代码更改] / [数据库架构更改]

“向我展示您的流程图并隐藏您的表格,我将继续感到困惑。向我展示您的表格,我通常不需要您的流程图;它们将显而易见。” (弗雷德·布鲁克斯)

#16 楼

似乎这个想法在各种类型的编程中都有各种解释。它适用于系统开发,也适用于企业开发。例如,有人可能会争辩说,在域驱动设计中,关注点向领域的急剧转移很像对数据结构和关系的关注。

#17 楼

这是我对此的解释:您使用代码创建数据结构,因此重点应放在后者上。这就像建造一座桥梁-您应该着手设计一种坚固的结构,而不是看起来很吸引人的结构。碰巧的是,由于其高效的设计,编写良好的数据结构和桥看起来都很不错。