因“知道太多”而陷入困境


147

请在http://news.ycombinator.com/item?id=4037794注意更多讨论

我有一个相对简单的开发任务,但是每次尝试攻击它时,我都会陷入深刻的思绪-它如何扩展未来,第二代客户将需要什么,它将如何影响“无功能”方面(例如性能,授权...),如何最好地架构师允许更改...

我记得自己有一阵子,更年轻,也许更渴望。那时我当时不会想到的“我”-他会继续写一些东西,然后重写,然后再次重写(再一次……)。今天的“我”更加犹豫,更加谨慎。

我发现今天坐下来并计划和指导他人如何做比实际自己去做要容易得多-不是因为我不喜欢编码-相反,我喜欢这样做!-但是因为每次我坐在键盘上时,我都会到那个烦人的地方。

这是错的吗?这是自然的演变,还是我让自己陷入了困境?

公开披露-过去我是一名开发人员,今天我的职务是“系统架构师”。祝你好运,弄清楚它的意思-但这就是标题。


哇。老实说,我没想到这个问题会引起如此多的答复。我会尝试总结一下。

原因:

  1. 分析瘫痪/过度工程/镀金/(其他“过多的思考可能会伤害您”)。
  2. 给定任务的经验过多。
  3. 不专注于重要的事情。
  4. 没有足够的经验(并意识到这一点)。

解决方案(与原因不匹配):

  1. 首先测试。
  2. 开始编码(+表示乐趣)
  3. 一个扔掉(+一个API扔掉)。
  4. 设置时间限制。
  5. 剥去绒毛,留在里面。
  6. 编写灵活的代码(有点像“一个扔掉”,不是吗?)。

多亏了所有人-我认为这里的主要好处是认识到我并不孤单。实际上,我已经开始编码了,有些太大的事情自然就消失了。

由于该问题已经关闭,因此,我将以今天最多的票数接受答案。当/如果它发生变化-我将尽力遵循。


47
时间压力可以帮助您停止过度思考。
user281377 2012年

51

49
喝2杯啤酒..
安德鲁·T·芬内尔

6
第二系统效果,有人吗?
比利·奥尼尔

21
您的问题不是“了解太多”,而是分析太多。您现在无需过多地关注性能,将来的功能等,如果客户为您提供了一项难以实施的新功能,这并不是世界即将终结的
Louis Rhys 2012年

Answers:


90

考虑这些事情绝对是件好事,但不要让它阻止您的进步。

一种非常有效的方法(特别是在迭代开发中)是实现一个简单的解决方案,然后在以后进行必要的重构。这样可以使代码尽可能简单,并避免过度设计。您正在考虑的大多数性能或体系结构更改可能根本就不是必需的,因此在正式需要它们之前,不要费心编写它们。例如,在探查器告诉您应该提高性能之前,请不要担心性能。

您可以帮助您进行调整的一件事是,在编写代码之前,对思考某件事的时间设置一个严格的时间限制。在大多数情况下,如果稍​​加思考,编写代码,意识到错误并通过重构来解决,那么代码的结果就会更好。

这里有一个平衡点。您不应该只是急于求成,不考虑后果,而且也不应该尝试过度设计代码。


15
正式名称:YAGNI
马克·兰瑟姆

48

维基百科在软件中将其命名为“ Analysis paralysis”。秘诀是坚持敏捷方法。这意味着任何活动或个人行为比试图建立惯例或政策具有更大的价值。团队中的每个贡献者都是有价值的,无论该人的能力是否符合建筑理想。在敏捷中,个人(例如自我)在第一位,政策在最后。

我最喜欢的答案是“建筑就是动词”。无论您和团队感到多么不完美和效率低下,请停止思考,开始行动。也许第一个行动可能是拆除不合适的政策。



38

这是错的吗?这是自然的演变,还是我让自己陷入了困境?

这取决于。这往往是开发人员的共同步骤。

  1. 开始胡扯在一起,被它咬伤
  2. 开始从一切中过度设计生活的地狱,意识到YAGNI
  3. 安置在一些务实的中间地带,在这里,容易的东西被拍打在一起,而可能进行硬性/变更的东西被给予足够的工程设计,以使其易于使用/改变。

如果您停留在第2位,那只是一种发情。


4
+1当您开始过度设计“ Hello World”时,您会发现自己处于第2位的车辙。
斯派克,2012年

3
@Spoike-或Fizzbuzz。la企业级Fizzbuzz
CraigTP

1
4.意识到3也是错误的,并且只关心满足业务需求而不是技术需求。普遍的业务需求是,一切都会不断变化,无论大小变化。实施细节将与底线驱动程序保持一致,并将在需要时尽快解决。及时开发。

14

我一直想记住的一件事是说:“未来不再是过去。”

有了一定的经验,就很容易相信您可以预测未来,但是您不能。可以轻松想象将来的客户/用户/任何人想要的功能,但这并不意味着他们会立即想要它们。这也不意味着他们会希望他们超越其他一些相互矛盾的功能。因此,您确实确实需要限制今天花费的时间来规划未来。您特别需要限制您花费多少时间来构建今天只会在将来使用的东西。

我要问的一个问题是,“比现在建立对该功能的支持要困难得多?通常,答案是未来的工作量大约是现在的两倍或两倍。在那种情况下,因为我无法预测未来,所以现在不构建它没有问题。如果答案达到10倍或更多,那么我将开始询问人们认为在未来一两年内我们将需要这个答案的可能性。即使那样,除非达成广泛共识,否则我只会将自己限制在确保没有必要撤销我们今天正在做的事情以实现将来的目标。

例如,我在一些项目中工作,我们花了很多时间来抽象出我们后来将Hibernate用作数据访问这一事实。(我从未见过基于Hibernate构建的项目停止使用它,因此一开始就很浪费时间,但我们将其搁置一旁。)即使有合理的可能性,我们以后可能想更改它,因为我们还使用了数据访问对象模式,就比从一开始就更加灵活地建立了Hibernate以便在需要时同时更改它的灵活性。面对现在这样的情况,我会推迟拥有这种灵活性,直到我们真正需要它为止。

除非您正在为一家大公司进行战略规划,否则考虑两三年以上的架构问题甚至根本不值得,因为技术日新月异。您可能正在考虑构建的功能可能会在两三年内以开源形式免费提供。几乎可以肯定,成本效益分析将发生变化。

限制自己构建一个系统,该系统可以满足您今天所需要的,令您感到自豪的问题,并且无论下一轮变革带来什么,您都将在几个月内满意地工作。确实,这是您可以做的最好的事情。


在我们当前的代码库中,过早的泛化是造成大多数背叛的原因。
Benjol 2012年

10

这是我个人消除疯狂的,令人敬畏的设计的过程,这些设计(在他们的第一个版本中)最终可能不切实际,并且从业务角度来看破坏了一个项目。

  1. 确定震中:将您的项目视为一个热狗摊位,震中就是热狗。您可以从摊位上拿走其他所有香料/服饰/蔬菜,但仍然可以出售热狗。您的软件的主要目的是什么?从中隔离其他所有附加项和/或附加值,并首先关注震中。
  2. 不断对自己重复“以后做就意味着做得更好”:看看有什么意义,并在其上贴上一点“以备后用”。如果做得好并考虑其实际用途,您将获得相同的设计,但会在路线图中获得优先权。
  3. 减少-分离-丢弃:无论您采用哪种模块设计,都可以使其尽可能简单/基本/纯/通用(有时甚至不删除功能就可以实现)。当您无法进一步简化它时,请开始将可能自己存在并有目的的元素去耦。最后,如果您仍然有一些脂肪,则可以将其切断。
  4. 将“库代码”与“生产代码”分开:始终存在无法重复使用的代码,但始终会给设计带来噪音。此代码是包含业务规则的代码。您会发现有时某些业务规则比健壮的设计更容易,更快捷地更改(极其重要)。您将找到可以依靠的代码,并为客户将来更改或重新实现所需的代码。您将希望将它们尽可能地分开。

顺便说一句,第0步是:“为设计疯狂”。这有助于我将其从系统中脱颖而出,并经常发现新的含义,隐藏的需求甚至是新兴功能。

我从返工中获得了1和2 。


9

编写测试。测试全部通过时,您就完成了:在过度设计的史诗阶段之前,而且肯定不会在不久之后。对正在编写的代码进行一组测试,将为您提供一个独立,公正的观察者,告诉您何时可以停止。


6
(不是我的不赞成意见)您什么时候停止编写测试?您只是将问题放在间接级别的后面。
MSalters 2012年

2
@MSalters我认为Graham指的是TDD,您在代码之前编写了一组测试。然后,编写使这些测试通过的最简单的代码。然后您重构。遵循此技术可能会阻止您过度思考您的初始开发,因为您的目标是使测试通过而不是编写完美的代码。
Oleksi 2012年

2
测试永远不能证明没有错误。仅仅因为您的吐司通过并不意味着您就完成了。您的测试充其量只能表明,程序可能输入的统计意义的非常小子样本非常小,可以产生您认为应该的输出。甚至还不能证明程序是正确的。无论如何,编写测试并不能帮助您构建可扩展且可维护的解决方案。
老职业

6
@OldPro测试是一种手段,而不是目的。它们鼓励良好的设计和集中的工作流程,并且具有适度减少错误的副作用。一般来说。不总是。
菲尔(Phil)

2
测试有助于定义项目的范围和权限。无论您使用TDD还是另一种方式,@ Graham都在想这样的想法:先拒绝测试,然后执行直到满足这些测试。
Preet Sangha

4

当您年轻时,您不会看到风险(这可能是初级政治人物感到恐惧的原因),但是随着年龄的增长,糟糕的经历会在每次机会中使您瘫痪(可能是高级政治人物停滞的原因)。采用Occam的剃须刀引导方法-寻求需求最少的解决方案,然后从那里发展。


4

编写和设计软件时,实际上只需要记住两件事:可维护性和正确性。

正确性是最重要的短期方法,可以通过测试轻松证明。

可维护性将在以后的开发中提供帮助,但更难确定。

我当前的策略是首先获得完整的概念证明,然后在对UI感到满意之后将其与模型分离(确保模型对UI一无所知)。如果我等待太久,就无法维护。如果我从分离的层开始,那么我似乎无法开始,因为我陷入了UI需要了解的关于模型的知识。


3

当我陷入这种情况时,我发现顽固地想象我是使用该假设程序来完成一些琐碎事情的最终用户。然后,我尝试着眼于支持这些操作所需的编程入口点,并尽可能地忽略系统的其他方面。从这里通常可以构建完成系统功能的(小的!)“清单”,并编写一些不切实际的代码来开始实现该功能。完成该练习后,我通常会开始工作,然后系统的其余部分将变得更加清晰。这一切都是关于切入点的,而所有软件中绝大多数的切入点都是最终用户对程序的初始操作。


3

我认为正在执行的任务对您来说太容易了,这是一个综合症。

几年前,您面临的挑战是编写将完成给定任务的代码。这就是您全神贯注的地方。现在,您的思想(您的经验等)正在更加有效地工作,并且完成同一任务仅需要以前需要的部分精力。这就是为什么您会陷入深刻的思想漩涡。您的思想正在为日常工作辩护,正在为挑战而战。

我认为您应该考虑更改工作。也许您应该学习一种新的编程语言。


3

15年前,我遇到了同样的问题。我想编写完美,可重用,通用的....代码,使解决方案变得比必需的复杂得多。今天,我将其视为镀金。对我帮助很大的是一位同事的建议:

  • 如果您有什么想法可以改善功能,请使其更通用,...将这个想法写下来放在单独的文本文件“ ideas.txt”中,但现在不要实现
  • 继续执行紧急任务。
  • 六个月后,请查看您的“ ideas.txt”并分析其中哪些更改确实可以使项目受益。

2

这只是分析而瘫痪。它发生在许多领域的许多人身上。您可以突破。

答案是-刚开始就可以;-)

我在健身论坛上发帖,很多人都在发布有关不同例程的文章,试图为他们找到最合适的例程。因此,我们告诉他们只是开始训练并按照自己的意愿进行工作。您想变得更强壮,进行一些强度练习,然后在进行过程中进行调整。

当您有一个大型程序并且您的大脑需要加班时,请首先为简单情况编写代码。最初,程序必须运行,然后必须接受输入等。
您的挑战是让事情易于更新和稍后重构,但是代码一定不要比执行手头的任务复杂。

请记住,将来可以重构代码以满足新的优先级。您无法预先预测所有指标,因此请勿尝试。

仅用于下一个任务的代码。代码简单而又好,因此如果需要,很容易进行重构。确保程序正常运行。重复。


1

由于您正在“陷入困境”,过度思考可能的最终用户用例场景,因此,如果您要发布API并希望您不认识的人会使用该API,那么这里需要考虑一些事情。一旦发布了API,即使您后来意识到您的第一个发行版有多糟糕,您也必须继续支持它,或者您必须破坏针对您编写的每个人(可能是您所不知道的)的代码,从而有可能疏远他们所有未来的时间。

标准解决方案是发布该API,并规定API可以随时以任何方式更改,直到您了解用户需要什么以及API使用者正在做什么。

在这种解决方案中,我认为是您自己的解决方案。只写一些做一两件事的小事,也许做就好,让自己明白自己做的任何事情将来都会改变。

当您开始时,不可能完全正确,或者在某些情况下甚至不可能正确,因为设计确实是一次发现之旅。它是最后出现的,不是要做的第一件事。

您不能立即设计API,也永远不必将其破坏给消费者。你明白为什么。同样,您不能编写软件,也不必扔掉所有软件并以新方法重新开始。

我不认为您有问题,因为您不小心演变成了创造性,生产性或吸引力不足的事物。我认为您的标准很高,却无意间将其不适用于您的情况,这是每个人都认为的普遍错误。

经验永远不会对您不利,除非您成为一个愤世嫉俗的“万事通”,“万事俱备”,而且听起来确实与您的情况相反。

当我变大时,我会记住一些图像。一种是与乐高玩。我将其放在一起并随意拆开。我开始做的可能不是我最终做的。我正在冲浪并为自己着迷,随着时间的流逝,我常常想到的就是完全重新创造我的目标……这就是创造力。

另一幅图片是我听到的一个类比,描述了做真实的科学。您在黑暗的房间里摸索着可能没有的黑猫。仅当您将自己视为找不到那只猫的失败时,才会感到不安。没有其他方法可以找到黑猫。那是找到他们的唯一活动。其他一切就是已经拥有您正在寻找的东西的某种形式。


0

你不太了解;你还不够了解!而且您直到最近才意识到这一点。

不要将您的设计选择视为必须获得“正确”的东西,因为没有“正确”,有很多“错误”,但也存在一些折衷(在执行速度,完成编码的时间上)任务,可扩展性等)。如果您编写的代码构想很好,那么它仍然具有各种优点和缺点。

目的应该是使了解当前和将来使用和维护方面的这些优点和缺点并不比编写代码困难得多。

因此,不要回避深刻的思想,但要记住,您需要经验,而不仅仅是思想,才能成为这种设计的大师。进行思考,直到您对某个特定选择没有信心为止,然后实施您希望的最佳选择,尝试一下,然后从中学习。


-1

练习编码。提出练习或在线找到它们,并尝试尽快正确完成它们。当您加快速度时,请添加诸如可维护性和性能之类的注意事项。您将意识到,将不会投入生产的代码变得令人耳目一新,这可能会帮助您摆脱对编码的恐惧。


-2

用您的业余时间编码,就像十年前一样,减少烦恼,享受乐趣。

成为团队经理和直接的年轻开发人员-他们现在的精神状态与您10年前一样。


-2

不,您还不够了解。

通过以下简单规则来丰富您的知识:

  • 吻:保持小而简单。
  • YAGNI:您将不需要它。
  • 越差越好:从维护性的角度讲,一些较差的解决方案实际上更好。

不要过度设计。通过具有重构技能来为更改做好准备,但不要对代码中所有可能的更改进行编码。如果您发现随着时间的流逝,类或函数会变得太大,请对其进行更改。分而治之。使用界面,使用更多功能。如果您觉得分歧太大(即,它变得有点怪异,但可读性较差),请撤消上一次更改。

总结:使您的代码足够灵活,但不能更多。相反,要使自己变得灵活一些,买一本有关重构的书。


-2

两件事情:

  1. 仅仅了解很多是不够的。您必须对什么值得实施有意见。我个人认为TDD是导致不良架构的拐杖。考虑到在这方面不利于我的大量民意,我可能错了,但是我没有考虑过是否要在JavaScript中实现TDD,因为调试从未使我感到头疼,嘿,数年后,这在开发社区中并不是第一次被大众认为是有缺陷的。因此,学习成为一个傲慢的人。至少在里面。您可能是错的,但至少是您对适用于您的东西的承诺,而不是对可能不适用的东西进行了过度思考。

  2. 听起来您是从micro开始的。从宏开始。首先,您需要使用工具来完成应用程序所需的工作。这部分应该足够容易。然后从架构/接口问题开始。管道的连接方式和连接方式实际上应该只是脆弱的部分,而这一切您只需滑动一下即可更换即可。同样,有关如何完成工作的细节。正确包装后,即可轻松进行替换/编辑。


-2

但是每次我尝试攻击它时,我都会陷入沉思

没有任何错误。您仅注意到该是时候改进流程了:在这种情况下,您是在思考流程。

许多人在分析中迷失方向或以其他方式陷入困境,甚至从未注意到它。您已经注意到,因此您可以更改自己的思维过程以保持正轨。

有很多解决方案,我上面看到的最好的解决方案是设置时间限制。在开始之前,请确定要花多长时间(1小时?)来进行分析和思考。设置一个计时器。

然后,当计时器关闭时,开始编码。如果您发现自己考虑时间太久了,那就立即做出决定。那时您做出的决定都是正确的决定。您以后总是可以进行更改和改进。

此外,我们的环境总是在变化。我们经常需要更新代码以处理新要求,新技术,新硬件,语言和系统更新等。


-2

是的,这种编码恐怖甚至发生在我身上。被堆栈溢出惊呆了。小型应用程序的详细编码。但是,当它是一个外包项目时,由于时间限制,它不会花费很多时间。我觉得与一群新人一起工作也可以克服这个问题。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.