自从改变主意后,您曾经喜欢哪种编程实践?[关闭]


99

当我们编程时,我们都会开发我们使用和依赖的实践和模式。但是,随着时间的流逝,随着我们的了解,成熟度以及技术使用的变化,我们逐渐意识到,一些曾经认为很棒的做法是不可行的(或不再适用)。

我曾经经常使用但最近几年有所改变的一种做法是使用Singleton对象模式

通过我自己的经验和与同事的长期辩论,我逐渐意识到单例并不总是令人满意的 -它们会使测试变得更加困难(通过禁止诸如模拟之类的技术),并且会在系统各部分之间产生不良耦合。相反,我现在使用对象工厂(通常使用IoC容器)来隐藏无关紧要或需要知道的系统部分中单例的性质和存在。相反,他们依靠工厂(或服务定位器)来获取对此类对象的访问权限。

我本着自我完善的精神向社区提出的问题是:

  • 您最近重新考虑了哪些编程模式或实践,现在尝试避免?
  • 您决定用什么取代它们?

Answers:


159


//Coming out of university, we were taught to ensure we always had an abundance 
//of commenting around our code. But applying that to the real world, made it 
//clear that over-commenting not only has the potential to confuse/complicate 
//things but can make the code hard to follow. Now I spend more time on 
//improving the simplicity and readability of the code and inserting fewer yet 
//relevant comments, instead of spending that time writing overly-descriptive 
//commentaries all throughout the code.



+1。我正要发布同样的答案。几周前,我在存档光盘上找到了一些旧的编程作业。看起来都一样。注释行与代码行的比例几乎为1:1。
Michael Moussa,2009年

32
听起来您的评论不正确,不是太多。代码本身并不能说明问题。不,实际上不是。阅读最新的《 NT Insider》,以获取有关此内容的详尽报道。如果您认为评论将是多余的,那么您要么错了,要么您做错了。大学没有教授正确的评论(或错误跟踪或版本控制... *叹*)。那里的评论太少了。(以及更少的好方法)
托马斯(Thomas

5
Code Complete在注释和备份数据方面提供了很好的技巧。
Thomas Thomas

20
注释应该被用来描述为什么代码做它做什么(如果不是很明显),而不是什么代码的功能。可能的例外是疯狂的旋转/语言破解,例如Carmack的魔术数字0x5f3759df。
克里斯·西蒙斯

6
@托马斯:我个人认为问题在于,大学不能向学生展示良好的评论。学校几乎所有的课程都是一次性的。学生没有经验回头看他们一年前编写的代码,甚至根本不了解它。而且,较低级别的类教的是非常简单的编码概念-由于发生了什么,因此在此级别进行注释几乎一定很乏味。换句话说,这就像试图教别人在浅水池里游泳一样。这不是让他们理解动作的正确背景。
丹·卢

117

单返回点。

我曾经为每种方法都选择了一个返回点,因为这样做可以确保例程所需的任何清理都不会被忽略。

从那时起,我开始使用小得多的例程-因此减少了忽略清理的可能性,并且实际上减少了清理的需要 -并且发现早期返回降低了代码的表观复杂性(嵌套级别)。单个返回点的伪像-保留“结果”变量,保留标志变量,未完成情况的条件子句-使代码看起来比实际复杂得多,难以阅读和维护。尽早退出市场和采用较小的方法是可行的方法。


3
我同意,当与数据类型相结合,可自动清洗自己起来,如autoptr,scoped_ptr的,但是CComPtr等
i_am_jorf

3
代码清理是尝试{}最终{}的目的
banjollity

@banjollity:除了最终不支持{}的语言。请注意,即使在支持该语言的语言中,也始终不能保证{}的执行。
克里斯K,2009年

1
@banjollity,Chris:在C ++中,清理是析构函数的作用,除非在极端情况下(exit(),析构函数在堆栈展开时抛出异常,松鼠会降低功率),否则保证运行。
David Thornley,2010年

4
同意 用警卫条款代替嵌套条件 ftw!
Jonik 2010年

111
  • 尝试在第一次尝试时完美地编写代码。
  • 尝试在编码之前创建完美的OO模型。
  • 设计一切以提高灵活性和未来的改进。

一言以蔽之,过度设计


6
等等,我总是在第一次尝试时正确。:)
i_am_jorf

18
真正的钱是第一次就把它巧妙地弄错了,然后放到野外。然后,当人们习惯了简陋的版本时,请以傲慢的表演技巧进来,并修复错误/效率低下以获得额外的荣耀!;)
Eric

7
@jeffamaphone-不,只有Jon Skeet第一次正确。
乔丹·帕默

我喜欢这个词“过度设计”
Neilvert诺瓦尔

@jeffamaphone-我总是在第一次尝试时也正确。但是,进一步的尝试满足了我的需求:)
umbr'9

78

匈牙利表示法(形式和系统)。我曾经给所有内容加上前缀。strSomeString或txtFoo。现在,我使用someString和textBoxFoo。对于新来的人来说,它更具可读性,也更容易上手。作为额外的好处,保持一致很容易-camel选中控件并附加一个有用的/描述性的名称。Forms Hungarian的缺点是不能始终保持一致,而Systems Hungarian并不能真正为您带来很多好处。将所有变量集中在一起实际上并不是那么有用-尤其是对于现代IDE。


动态类型语言(例如Python或JavaScript)呢?我仍然发现在这些语言中使用匈牙利表示法会有所帮助,这样,在查看变量时,我知道期望使用哪种类型的变量(如果期望使用某种类型,当然,对待动态类型的语言将很困难就像静态类型的语言一样。)
Dan Lew,2009年

4
我做类似的事情,除了:fooTextBox和字符串只是希望出现:numberOfEntries => int,isGreat => bool等
。– rball

+1用于摆脱匈牙利符号。我同意rball;fooTextBox,fooService,fooString何时确实需要。
blu

3
@ wuub:我认为使用适当的命名,您不需要添加任何前缀。
肯尼·曼恩,2009年

4
顺便说一句,您提到的不是真正的匈牙利。
安东尼·卡西,

67

“完美”的架构

几年前,我想到了THE体系结构。从技术上尽我所能,使存在100%松散耦合的层,大量使用委托和轻量级对象。那是技术天堂。

真是胡扯。该体系结构的技术纯度使我的开发团队放慢了速度,他们追求的是完美而不是结果,而我几乎完全失败了。

现在,我们有了更简单,技术上不太完美的体系结构,并且交付率猛增。


57

使用咖啡因。它曾经使我保持清醒,并充满了光荣的编程情绪,其中代码从我的手指间飞奔而来,流淌着狂热。现在它什么也没做,如果没有,我会头疼。


55
您需要喝更多的咖啡。如果那不起作用,请吸烟。
MusiGenesis

7
布拉德:有了Python,您就不需要这些了:xkcd.com/353
彼得

不错的圣诞节故事参考!:-)
史蒂夫·埃科尔斯

2
我打破了习惯,然后再次习惯了几次(这是我的第三个周期)。没有什么比在寒冷的早晨喝一杯温暖的咖啡来编码更好的了!
马修·伊瑟林2009年

15
“看来我选错了一周来戒除苯丙胺。”
ShreevatsaR

50

注释掉代码。我曾经以为代码很宝贵,您不能仅仅删除自己制作的那些美丽的宝石。现在,我删除遇到的任何注释掉的代码,除非附加了TODO或NOTE,因为它太危险而无法保留。断言,我遇到了带有大量注释掉的部分的旧类,这确实使我感到困惑,为什么他们在那里:他们最近被评论了吗?这是开发环境的变化吗?为什么要执行此无关的块?

认真考虑不要注释掉代码,而只是删除它。如果需要,它仍在源代码管理中。虽然YAGNI。


6
我在重构期间将旧代码注释掉,但是直到我确认替换代码有效为止。新版本完全可用后,我将删除旧的注释行。
muusbolla

确实-我也注释掉了代码,但只持续了几天。如果我回来并且意识到有些遗漏,那么在处理新代码之前,它将被删除。
科林·麦凯

4
我说一次检查注释的代码,然后将其删除。很多时候,您测试各种不同的代码位,并且您不想签入损坏的代码...
DisgruntledGoat 2009年

更不用说版本控制是您的朋友。
David Thornley,2010年

+1我和一位程序员合作,他坚持评论他重构或重写的所有代码。这会让我发疯,因为有时我必须翻阅1k +行废话,才能找到我正在做的事情。
Evan Plaice 2010年

46

#region指令的过度使用/滥用。只是一件小事,但是在C#中,我以前会在各处使用#region指令来组织我的类。例如,我将所有类属性分组到一个区域中。

现在,我回头看看旧的代码,大部分只是被它们烦恼了。我认为大多数情况下这并不能使事情变得更清晰,有时它们只是会使您慢下来。因此,我现在改变了主意,觉得布置良好的类在没有区域指令的情况下通常更干净。


31
我讨厌地区的。我们团队中的人轻率地使用它们。我称它们为“错误的代码隐藏器”。
rball

9
它们绝对是代码气味。
Frank Schwieterman

3
我讨厌地区。我目前正在维护功能接近500行的代码,并且要对其进行管理,聪明的开发人员已将代码块放置在10到15个区域中。
解决方案

6
@解决方案瑜伽士:我不认为您遇到的真正问题是区域:-)
Ed S.

9
我认为,如果谨慎使用区域可能会很好。
格雷戈里·希格利2009年

39

总体而言,特别是瀑布式开发的实践是编写完整且全面的功能和设计规范,这些规范和规范在某种程度上应该是规范的,然后期望这些规范的实现是正确且可以接受的。我说,我已经看到它被Scrum取代了,对此我感到很高兴。一个简单的事实是,客户需求和欲望的不断变化的性质使得任何固定的规范实际上都无用;真正正确解决问题的唯一方法是采用迭代方法。当然,并不是说Scrum是灵丹妙药。我已经看到它多次滥用和滥用。但是它胜过瀑布。


3
告诉我的客户...我正在写一些没用的文章:“我是一个有水晶球的程序员,所以我确切地知道我的底层设计在6个月后会是什么样子”规范文档:)
Igor Brejc

36

永不崩溃。

似乎是个好主意,不是吗?用户不喜欢崩溃的程序,所以让我们编写不会崩溃的程序,而用户应该喜欢该程序,对吗?我就是这样开始的。

如今,我更倾向于认为如果它不起作用,就不应假装它正在起作用。尽快失败,并显示一条错误消息。如果不这样做,您的程序将在以后的几条指令中崩溃甚至更加严重,但是由于存在一些无法描述的空指针错误,您将需要花费一个小时来调试。

我最喜欢的“不要崩溃”模式是这样的:

public User readUserFromDb(int id){
    User u = null;
    try {
        ResultSet rs = connection.execute("SELECT * FROM user WHERE id = " + id);
        if (rs.moveNext()){
            u = new User();
            u.setFirstName(rs.get("fname"));
            u.setSurname(rs.get("sname"));
            // etc
        }
    } catch (Exception e) {
        log.info(e);
    }
    if (u == null){
        u = new User();
        u.setFirstName("error communicating with database");
        u.setSurname("error communicating with database");
        // etc
    }
    u.setId(id);
    return u;
}

现在,您不必要求用户复制/粘贴错误消息并将其发送给您,而是必须深入研究日志以查找日志条目。(由于他们输入了无效的用户ID,因此不会有日志条目。)


用户向您提供实际错误消息的可能性有多大,与您的日志产生问题的可能性有多大?(在这种情况下非常低,但是用户几乎从不引用错误消息!)他们甚至读过它们吗?
Arafangion

1
我承认随机用户向您发送错误消息的机会很小,但机会不为零(简单的例子:有时您使用自己的应用程序),并且一些用户会随着时间的流逝真正学习要复制/粘贴的内容。我并不是说您不应该(应该)登录,但是当应用程序损坏时,它就会损坏。与显示用户的名字是“与数据库通信时出错”(或更糟糕的是,null或空字符串)相比,显示错误消息要好得多,对用户来说更诚实。
gustafc

有两行的的NullReferenceException
oɔɯǝɹ

谢谢,我已经解决了。(尽管在那里有点笨拙:避免异常和其他“崩溃”的所有麻烦,但仍然无条件地崩溃了。)
gustafc 2009年

33

我认为每当我识别出设计模式时就应该应用它们。

我几乎不知道我实际上是在从外国编程语言复制样式,而我所使用的语言允许使用更优雅或更简单的解决方案。

使用多种(非常)不同的语言使我大开眼界,使我意识到,我不必将别人的解决方案错误地应用于并非属于我的问题。现在,当我看到将工厂模式应用到像Ruby这样的语言中时,我就发抖了。


2
请原谅我对红宝石的无知,但是为什么我们不使用它来使用工厂模式呢?
Mike Chamberlain

这里不是红宝石主义者,但是工厂要避免依赖于实现,但是红宝石是动态的,您可以对任何内容进行模拟或存根。因此,您实际上并不依赖于实现。
斯特凡

27

强迫症测试。我曾经是测试优先开发的狂热拥护者。对于某些项目来说,这很有意义,但我已经意识到,这不仅不可行,而且不利于许多项目坚持为每个功能编写单元测试的学说。

确实,盲目地坚持任何事情都是有害的。


22
对于藤壶来说效果很好。
MusiGenesis

测试覆盖范围必须与收益成正比。您所做的任何事情实际上都必须显示出好处。100%的覆盖率不会给您那么多。与80或90的区别在于不在生命支持/导弹发射场景中。
斯彭斯

+1依赖于单元测试,而不是测试。
Preet Sangha,2009年

25

这是一件小事,但是:关心括号的位置(在同一行还是下一行?),建议最大代码行长,变量的命名约定以及其他样式元素。我发现,每个人似乎都比我更关心此事,因此,我随和与之共事的人。

编辑:当然,这是一个例外,当我是最在意的人(或者是能够为组设置样式的人)时。在这种情况下,我会做我想做的!

(请注意,这与没有一致的样式不同。我认为代码库中的一致的样式对于可读性非常重要。)


5
有人对此表示反对,但我认为这是实际的观点。最好的代码样式是什么?不重要。在同一文件中上下查找并重复。
Frank Schwieterman,2009年

12
最好的代码样式是该商店的标准是什么。
David Thornley,2009年

这就是为什么我喜欢Visual Studio中的自动格式选项。不管其他开发人员如何编写代码,我只是做一个快速的格式,以及它到底是我自己喜欢的样子……大多数时候。
corymathews

5
@cory:这不会破坏版本控制软件向您显示刚格式化的文件版本之间的区别的能力吗?
史蒂夫·梅利尼克诺夫

这就是为什么我很喜欢学习python的原因……以为我只需要担心我的tabstops设置为什么,而不必担心样式。令人信服。
克里斯K,2009年

24

从那以后,我改变主意的最重要的“编程实践”是,我的代码比其他人的代码更好。这对于程序员(尤其是新手)来说很常见。


20

实用程序库。我曾经带着各种辅助方法和类进行组装,其理论是有一天可以在其他地方使用它们。

实际上,我只是创建了一个巨大的名称空间,其中包含许多功能组织不善的功能。

现在,我将它们留在创建它们的项目中。很可能我将不再需要它,而且如果需要,我可以随时将它们重构为可重用的东西。有时我会用// TODO标记它们,以便可能提取到通用程序集中。


12
有一个很好的报价(目前我找不到原始报价),这类似于“在您需要解决3次相同的问题之前,不要考虑创建泛型例程。”
DaveR

9
“三击而你重构” -Martin Fowler 重构第三规则,第58页
。–尼克·丹杜拉基斯

20

设计超出我的编码范围。一段时间后,它变成了分析瘫痪。


44
我偶尔会引用这样的短语:“如果发现自己想得太多,那就停下来做。如果发现自己做得太多,就停下来思考。”
尼尔N

很好,但是多少钱太多了?
Hamish Grubijan

对UML(无用的建模语言)的依赖过多。它偶尔会有用途。但是,一旦我看到有人开始绘制类图并宣扬“从这些图生成代码将是多么棒”的好处,我便把跑步鞋系紧了。另外,Visual Studio具有内置的交互式类图生成器,该生成器可以自动完成所有工作,并且像破解对象浏览器一样工作。
Evan Plaice 2010年

15

使用DataSet执行业务逻辑。这将代码过于紧密地绑定到数据库,而且DataSet通常是从SQL创建的,这使事情变得更加脆弱。如果SQL或数据库发生更改,则它会滴流到数据集所涉及的所有内容。

在对象构造函数内执行任何业务逻辑。继承和创建重载构造函数的能力往往使维护变得困难。


15

缩写变量/方法/表/ ...名称

我过去一直都这样做,即使使用的语言对名称的长度没有强制性的限制(也可能是255个左右)。副作用之一是在整个代码中乱七八糟的注释,解释了(非标准)缩写。当然,如果由于任何原因更改了名称...

现在,我更喜欢用好的描述性名称来称呼它们的真实含义。仅包括标准缩写。无需包含无用的注释,并且代码更易于阅读和理解。


是的,必须喜欢以下类型的声明:void Foo(x1,y,x2,y2,p,r,j)... WTF ?!
Ed S.

或更糟糕的是(是的,我实际上已经看到了),Foo(int arg0, String arg1, float arg2)等等
Mac

14

用自定义的帮助程序方法包装现有的数据访问组件(例如企业库)。

  • 它并没有使任何人的生活更轻松
  • 它的更多代码可能包含错误
  • 很多人知道如何使用EntLib数据访问组件。除了当地团队,没人知道如何使用内部数据访问解决方案

14

我在1984年阅读Smalltalk时就第一次听说了面向对象的编程,但是直到1992年我使用cfront C ++编译器后,我才可以使用oo语言。我在1995年终于使用了Smalltalk。技术,并认为这将节省软件开发。

现在,我只是将oo视为具有某些优势的一项技术,但这只是工具箱中的一种工具。我的大部分工作都是使用Python进行的,而且我经常编写不是类成员的独立函数,而且我经常在过去创建类的元组或列表中收集数据组。当数据结构复杂,或者我需要与数据相关联的行为时,我仍然创建类,但是我倾向于抵制它。

我有空的时候实际上对在Clojure中进行一些工作很感兴趣,尽管我理解正确,但是它不提供oo设施,尽管它可以使用Java对象。我还不想说oo已经死了,但就我个人而言,我不是以前的粉丝。


13

在C#中,_notation用于私有成员。我现在认为这很丑。

然后,我改为this.notation使用私有成员身份,但发现我在使用它时前后不一致,因此我也删除了它。


29
我仍在使用_notation并认为它很棒。
阿尼斯·拉普萨09年

3
我讨厌_notation; 我对公共成员使用ThisNotation,对私人成员使用thisNotation。
卡伦·罗杰斯

我也讨厌 它让我感到困惑:(
Broken_Window

4
我不同意。它使管理名称变得非常容易。对于属性或公共/内部成员,请使用PascalCase;对于通过属性公开的成员,请使用_UnderscorePascalCase;对于方法/构造函数和私有成员中的参数名称,请使用camelCase。仅当您需要在类之外传递当前类的引用或需要访问该类中的自动生成的成员(例如名称,控件等)时,才需要使用'this'关键字。
Evan Plaice 2010年

@Evan:除了最后一部分,我完全按照您的描述进行操作。在调用方法和属性时,我倾向于使用thisMe(分别为C#和VB.NET)。IMO,这使我的代码更易于阅读和理解,尤其是当该特定范围内有四个或更多对象时。
Alex Essilfie 2011年

11

在实施之前,我不再遵循大学推荐的设计方法。在混乱而复杂的系统中工作迫使我改变了态度。

当然,我仍然会进行代码研究,尤其是当我要接触从未接触过的代码时,但是通常我会尝试着眼于尽可能小的实现,以使某些事情先行。这是主要目标。然后逐步完善逻辑,让设计自己出现。编程是一个反复的过程,并且在使用敏捷方法和大量重构的情况下非常有效。

该代码不会查看您最初认为的样子。每次都会发生:)


10

我曾经非常注重合同设计。这意味着在我所有功能的开始处都要进行很多错误检查。从关注点分离的角度来看,合同仍然很重要,但是我不尝试强制执行我的代码不应该执行的操作,而是尝试使用单元测试来验证其执行的操作。


我被教导像这样编程。当然,我是由HS数学老师教的,所以我认为他希望自己的功能全部自我验证是有道理的。
亚历克斯

10

我会在很多方法/类中使用static,因为它更简洁。当我开始编写测试时,实践很快发生了变化。


10

检查异常

在纸上的一个奇妙的想法-清楚地定义合同,没有错误的余地或忘记检查某些例外情况。第一次听说时我就被卖了。

当然,实际上这真是一团糟。到目前为止,拥有像Spring JDBC这样的库,该库将隐藏的经过检查的异常作为其主要功能之一。


9

有价值的东西仅用一种特定的语言编码。就我而言,我相信C是有史以来最好的语言,而且我从来没有任何理由用其他任何语言编写任何代码。

从那以后,我开始欣赏许多不同的语言以及它们提供的好处/功能。如果我想编写一些小代码-快速-我会使用Python。如果我想从事大型项目,则可以使用C ++或C#进行编码。如果我想发展脑瘤,我会用Perl编写代码。


8

当我需要进行一些重构时,我认为直接开始并实施新设计,修复连接直到工作起来是更快,更干净的方法。然后我意识到最好进行一系列小的重构,以缓慢而可靠地向新设计发展。


记得这让我
难受

8

在我和其他人的编码实践中,也许最大的变化是接受了从Internet下载的外部类和库,将其作为应用程序行为和功能的基础。我上大学时在学校里,我们被鼓励去思考如何通过我们自己的代码使事情变得更好,并依靠语言来解决我们的问题。随着用户界面和服务/数据消耗各个方面的进步,这已不再是现实的概念。

有些事情永远不会改变一种语言,拥有一个可以将此代码包装在一个更简单的事务中并且我必须编写的代码行更少的库是一件幸事。连接到数据库将始终相同。在DOM中选择一个元素不会改变。通过服务器端脚本发送电子邮件永远不会改变。不得不一遍又一遍地写,这浪费了我可能用来改善应用程序中核心逻辑的时间。


7

初始化所有班级成员。

我曾经用某种东西(通常为NULL)来显式地初始化每个类成员。我已经意识到这:

  • 通常意味着每个变量在被读取之前都要初始化两次
  • 之所以愚蠢,是因为在大多数语言中,自动将变量初始化为NULL。
  • 实际上在大多数语言中对性能都有轻微的影响
  • 可以在大型项目上膨胀代码

4
有时,未初始化所有班级成员的后果确实会在a $$中给您带来痛苦。
muusbolla

除非您使用基于原型的语言通过克隆创建新实例。初始化所有成员确实可以为您节省很多麻烦。
Wojciech Bederski 09年

6

像您一样,我也采用了IoC模式来减少应用程序各个组件之间的耦合。只要我可以使每个组件尽可能独立,它就使维护和零件更换变得更加简单。我还利用更多的对象关系框架(例如NHibernate)来简化数据库管理工作。

简而言之,我正在使用“微型”框架来帮助更快,更有效地构建软件。这些微型框架可以节省大量时间,而且如果操作正确,可以使应用程序的维护变得非常简单。即插即用,取胜!


-1我无法忍受IoC和框架的泛滥。良好的解耦,IoC和框架=不必要的复杂性
Paul Hollingsworth 2009年

您如何称赞去耦,却又讨厌IoC和其他框架?这就是许多IoC框架和设计模式要做的。
ajawad987
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.