关于语言不可知:你曾经喜欢的编程练习让你改变了主意?

What programming practice that you once liked have you since changed your mind about?

当我们编程时,我们都会开发我们使用和依赖的实践和模式。然而,随着时间的推移,随着我们的理解、成熟度甚至技术使用的变化,我们逐渐意识到,我们曾经认为很好的一些实践并不是(或不再适用)。

我过去经常使用的一个例子,但近年来发生了变化,就是使用单体对象模式。

通过我自己的经验和与同事的长期争论,我逐渐认识到,单例测试并不总是可取的——它们会使测试变得更困难(通过抑制模拟等技术),并且会在系统的各个部分之间产生不必要的耦合。相反,我现在使用对象工厂(通常带有IOC容器),从系统中不关心或不需要知道的部分隐藏单例的性质和存在。相反,他们依靠工厂(或服务定位器)来获取对这些对象的访问权。

我以自我完善的精神向社会提出的问题是:

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

1
2
3
4
5
6
7
//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.


单个返回点。

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

从那时起,我已经转移到更小的例程上——因此忽略清理的可能性降低了,事实上清理的需求也减少了——并且发现早期返回会降低代码的明显复杂性(嵌套级别)。单个返回点的工件——保留"result"变量,保留标志变量,用于尚未完成的情况的条件子句——使代码看起来比实际复杂得多,使代码更难读取和维护。早期的出口,以及较小的方法,都是可行的方法。


  • 尝试在第一次尝试时完美地编码事物。
  • 尝试在编码之前创建完美的面向对象模型。
  • 为灵活性和未来的改进设计一切。

总之,过度工程。


匈牙利符号(形式和系统)。我以前给所有东西加前缀。strsomestring或txtfoo。现在我用了一些字符串和文本框。对于新来的人来说,它的可读性要高得多,而且更容易被人接受。作为一个额外的好处,保持它的一致性是很简单的——camelcase控件并附加一个有用的/描述性的名称。形式匈牙利语有不总是一致的缺点,系统匈牙利语并没有真正获得你很多。把所有的变量放在一起并没有什么用处——尤其是在现代的IDE中。


"完美"的建筑

几年前我提出了这个建筑。在技术上尽可能地推动自己,因此有100%的松散耦合层、广泛使用代理和轻量级对象。这是技术天堂。

那是废话。架构的技术纯粹性使我的开发团队在追求完美的同时放慢了速度,我几乎完全失败了。

我们现在有了更简单、技术上更不完善的架构,我们的交付率也大幅上升。


咖啡的使用。有一次,它让我保持了清醒,在一种美妙的编程气氛中,代码从我的手指上飞出,流动性极强。现在它什么都不起作用,如果我没有它,我就会头疼。


commenting退出代码。我过去认为,代码和什么你不能只是删除那些美丽的宝石,你制作的。我现在退房该删除任何代码来做,除非有一个附加或债券,因为它太perilous到离开它。我已经走到一起,在一个巨大的老班推出的该部分,它真的我很困惑:为什么该是他们最近推出的?这是a dev的环境变化?为什么它这样做unrelated块?

需要认真考虑commenting代码和代码信息及时而出。如果你需要它,它仍然在源控制。yagni虽然。


滥用/滥用地区指令。这只是一个小问题,但是在C中,我以前会在整个地方使用区域指令来组织我的课程。例如,我将一个区域中的所有类属性分组在一起。

现在我回顾一下旧代码,主要是对它们感到恼火。我不认为这真的使事情更清楚的大多数时间,有时他们只是简单地放慢你。因此,我现在改变了主意,认为布局良好的类在没有区域指令的情况下更干净。


瀑布式开发通常,具体来说,是编写完整的、全面的功能和设计规范的实践,这些规范在某种程度上是规范的,然后期望这些规范的实现是正确的和可接受的。我看到它被Scrum取代了,我说,很好地摆脱了它。简单的事实是,客户需求和需求的不断变化使任何固定的规范实际上都无用;真正正确处理问题的唯一方法是使用迭代方法。当然,这不是银弹,我见过它被滥用和滥用过很多次。但它胜过瀑布。


永不崩溃。

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

现在,我更倾向于认为,如果它不起作用,就不应该假装它起作用。尽快失败,并显示良好的错误消息。如果您不这样做,您的程序将在稍后的几条指令中崩溃得更厉害,但是由于一些难以描述的空指针错误,您需要一个小时来调试。

我最喜欢的"不要崩溃"模式是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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无效,因此不会有日志条目。)


我认为在我识别出设计模式时应用它们是有意义的。

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

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


强迫性测试。我曾经是测试优先开发的狂热支持者。对于某些项目来说,这是很有意义的,但我逐渐意识到,这不仅不可行,而且对许多项目不利,因为它们都要遵循为每一个功能块编写单元测试的原则。

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


这是一件很小的事情,但是:关心支撑的位置(在同一行还是下一行?),建议的最大代码行长度、变量的命名约定和其他样式元素。我发现每个人似乎都比我更关心这个问题,所以我现在只关注和我一起工作的人。

编辑:当然,这是一个例外,当我是最关心的人(或者是在一个位置上为一个组设置样式的人)。在这种情况下,我想做什么就做什么!

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


也许我改变主意后最重要的"编程实践"就是我的代码比其他人的代码更好。这对于程序员(尤其是新手)来说是很常见的。


设计超过我编码的。过了一会儿,就变成了分析瘫痪。


实用程序库。我过去常常带着各种各样的辅助方法和类进行组装,理论上我可以在某天在其他地方使用它们。

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

现在,我将它们留在创建它们的项目中。很可能我不需要它,如果需要的话,我可以在以后将它们重构成可重用的东西。有时我会用//TODO标记它们,以便将它们提取到公共程序集中。


abbreviating变量/法/表/……名称

我过去这样做所有的时间,甚至当工作在没有语言限制在执行长的姓名(或他们的东西可能是好的255)。一个侧效果是很多评论在littered代码解释abbreviations(非标准)。和当然,如果名称是改变的任何理由……

现在我很喜欢的东西,他们真的是什么调用,一个良好的描述性名称。包括标准abbreviations只读。不需要包括管理的评论,和代码更可读和什么是远。


使用数据集执行业务逻辑。这将代码与数据库绑定得太紧,而且数据集通常是由SQL创建的,这使得数据集更加脆弱。如果SQL或数据库发生更改,则会滴入数据集涉及的所有内容。

在对象构造函数内执行任何业务逻辑。通过继承和创建重载构造函数的能力,维护起来很困难。


使用自定义的辅助方法层包装现有的数据访问组件,如企业库。

  • 这不会让任何人的生活更轻松
  • 更多的代码可能包含错误
  • 很多人都知道如何使用EnLIB数据访问组件。除了本地团队外,没有人知道如何使用内部数据访问解决方案。

我第一次听说面向对象编程,在1984中阅读SimultTalk,但是直到1992我使用Cfc++编译器才有机会访问O-O语言。我终于在1995使用SimalTalk了。我急切地期待O-O技术,并认为它可以节省软件开发。

现在,我把O-O看作一个有一些优点的技术,但它只是工具箱中的一个工具。我用Python做我的大部分工作,我经常编写独立的函数,而不是类成员,我经常收集元组或列表中的数据组,在过去我会创建一个类。当数据结构复杂时,我仍然创建类,或者我需要与数据相关的行为,但我倾向于抵制它。

当我有时间的时候,我实际上感兴趣的是在CuljEJE中做一些工作,虽然它不能提供O-O设施,但是如果我能正确理解的话,它可以使用Java对象。我还没准备好说什么,比如说O O已经死了,但我个人不是以前的粉丝。


在c_中,使用_notation表示私有成员。我现在觉得很难看。

然后我改为私人会员的this.notation,但发现我使用它不一致,所以我也放弃了。


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

当然,我仍然会做代码研究,尤其是当我即将接触到以前从未接触过的代码时,但通常我会尽量集中在尽可能小的实现上,以便先完成一些事情。这是首要目标。然后逐步完善逻辑,让设计自己出现。编程是一个迭代的过程,使用敏捷的方法和大量的重构非常有效。

代码不会完全按照您最初认为的样子进行查看。每次都发生:)


我以前对合同设计很感兴趣。这意味着在所有函数的开头都要进行大量的错误检查。从关注点分离的角度来看,契约仍然很重要,但我尝试使用单元测试来验证它的功能,而不是强制执行我的代码不应该执行的功能。


检查违例

在纸上的一个惊人的想法-明确定义合同,没有错误的空间或忘记检查一些异常情况。当我第一次听说它的时候,我就被卖掉了。

当然,它在实践中变成了一团糟。到了像Spring JDBC这样的库的时候,Spring JDBC已经将遗留检查的异常隐藏为其主要特征之一。


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


这是什么价值是唯一的编码在一个特定的语言。我相信在我的案例是最好的C语言有任何理由去和我从来没有在任何其他语言代码的东西……有。

我自从来到到许多不同的语言和他们的福利/功能提供。如果我想快一点小的代码是使用Python。如果我想我会的工作在大型项目的代码在C + +或C #。如果我想我会发一脑肿瘤在Perl代码。


也许最大的东西已经改变的编码实践的工作人员,在接受他人,是学院外的类和库下载从互联网为基础的行为和功能中的应用。在大学时我参加了学校在鼓励我们找出如何更好的通过自己的化妆的东西和我们的代码依赖于语言的解决我们的问题。在酒店的所有方面的用户界面和服务的数据,这是确定的消费观念不再一。

有一些东西是永远不会改变的语言,这是有一个图书馆和一个换行代码和交易代码在他们的线,我要写的是一个祝福。连接到一个数据库将永远是相同的。选择DOM元素在不改变。发送电子邮件通过一个服务器端的脚本不会变更。有写这一次又一次的废物时,我可以提高我的核心逻辑中使用的应用程序。


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


初始化所有类成员。

我曾经用一些东西显式地初始化每个类成员,通常是空的。我开始意识到:

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


和您一样,我也支持IOC模式来减少应用程序各个组件之间的耦合。它使维护和部件交换变得更简单,只要我能尽可能地保持每个组件的独立性。我还使用了更多的对象关系框架(如nhibernate)来简化数据库管理工作。

简言之,我正在使用"迷你"框架帮助更快、更高效地构建软件。这些微型框架节省了大量时间,如果做得好,可以使应用程序非常容易维护。即插即用!


编写docblock方法描述,简单地重复方法名已经告诉您的内容。过去糟糕的日子:

1
2
3
4
5
6
/**
 * Returns the logger obj
 * @return log_Core
 */
public function getLogger()
{ ... }

现在:

1
2
3
4
5
/**
 * @return log_Core
 */
public function getLogger()
{ ... }

当然,有名的函数有帮助。


在IDE中进行原型设计。像所有的新手一样,我已经知道跳到代码里是个坏主意。现在,在使用键盘之前,我倾向于放弃一些愚蠢的想法。


要求所有代码都是干净的代码,即使它已经工作了。

在学术环境中,人们对干净的代码的关注如此之深,以至于当你遇到丑陋的代码时,总会有很大的诱惑去清理它。但是,清理工作代码有很多缺点:

  • 清理它所花费的时间在当时并没有为产品增加任何价值,而在调试或进行功能开发的同时也增加了价值。
  • 有可能破坏已经运行的代码。没有人会如此惊讶,以至于他们在重构时从不引入错误。(当我的虫子被运到客户那里时,我不得不吃一些卑微的馅饼。)

当然,一旦这段丑陋的代码需要新的特性,重构它通常不是一个坏主意。但关键是:重构和清理应该只与特征开发相结合。


在我作为软件开发人员的职业生涯中,我在学校和大学任教,经历了两次思想上的转变。

像生活中的许多事情一样,这些变化来自经验和观察,而这两者是矛盾的(就像生活!).

或多或少,第一个描述了为什么/何时使用"大系统"而不是"小系统",第二个描述了为什么有时"专有系统"比"标准系统"具有优势。

我知道这是一个有点冗长/富有哲理的答案,但你可以跳到"总结"部分!

一是:"小/独立"软件与"大牌/标准"软件同等优秀。

我一直在想,为什么公司会使用像微软、SAP、甲骨文等大牌软件,这些软件的开发和许可费都很高。

我从一个为使用Oracle DBMS而不是MySQL付出了很多钱的人身上学到了宝贵的经验,因为它是为软件项目存储在数据库中的非常少量的数据。

基本上,当你使用"大名/标准"软件,如SAP,Oracle或微软,你想购买"安全",这是最好的总结在"30年后,我仍然会发现开发人员的SAP"。

规模较小的公司可能破产,你的软件系统维护时间较长。也许"小/独立"软件会做这项工作,但你不能肯定它会在明年得到支持。

我见过很多次一家软件公司(甚至更大的公司)陷入困境,你突然遇到了一些问题,无法在市场上为你的软件系统获得支持和/或开发人员(以合理的价格)。

综上所述:使用"大名鼎鼎/标准"软件有很好的安全性或支持方面的原因,即使这些软件很昂贵而且有自己的问题。

第二:软件语言/概念/系统x是唯一正确的方法。

在我年轻的时候,我是一个纯粹主义者。一切都必须是这样或那样,中间没有灰色区域。例如,我做了所有的东西在C++(MS Windows),然后Java(Windows / Web),然后PHP(Linux / Web)等。即使是ColdFusion(Windows/Web)或ABAP(SAP)。

现在我不认为有唯一的"正确的方法"去做事情。我现在更像是一个通才,而不是一个纯粹主义者。另外,我非常怀疑Java等提供的大型图书馆。或者系统,比如PHP等的软件层。

另外,我也非常怀疑"oo"这句话在任何地方都被接受。OO本身就很好,但并不是解决所有问题的方法。我生活在亲吻(保持简单,愚蠢)的原则,我经常发现很难学习某种语言的所有课程/功能,只为一个小网站项目做简单的事情。例如,我一直在想为什么JSP用于小的简单项目,而这些项目可以在很短的时间内用PHP完成。

所以今天我非常怀疑大型/慢速/开销软件系统…通常情况下,为小项目做些事情总比用一个大的功能过度杀戮所有东西要好,而这个功能又必须根据您的需要进行定制。

大多数时候,我从零开始开发具有数据库连接的网站(如php)比使用昂贵的!)和复杂而庞大的库(例如jsp),因为大多数特性甚至都不有用。

例如:你想在你的网站上使用weblog软件x,这很酷,因为它内置了rss导出、web服务等功能。但是在学习weblog软件的所有库功能和约定方面有一个严重的开销…是的,当你终于明白了,你可以使用所有的功能和特点…但在大约一半的时间内,您可以从头开始构建您真正需要的10%功能。

总之:保持简单,愚蠢的工作。很多时候,一个简单的(即使是"cruder")解决方案比一个复杂的(但更好的)解决方案更好。使用最适合情况的工具,而不是固定的咒语。


TDD和单元测试。在某种程度上,我是工作场所TDD的倡导者,但随着时间的推移,我了解到它确实不会给桌面带来任何东西,至少使用静态类型的语言是这样的。

别误会,我仍然认为自动化功能测试非常重要。


不要评论代码,希望总是依赖于代码应该描述自己的概念。

当我第一次开始编程时,我很快采纳了这样一个观点:大量的注释是无用的,相反,代码应该以这样的方式编写,以便自我描述。然后我把它推向了极端,在那里我从不评论代码。对于表示业务域的代码,这有时很有效,因为详细的文档需要放在其他地方(如DSL或文档),并且类成员的含义是显而易见的。然而,当开发更多的"框架"代码时,就变得更难推断其含义。这是真的,我回头看我自己的代码,而不是说其他人需要使用它。我当然会使用.NET框架类和其他框架的注释,为什么不为自己的框架编写它们呢?通常,我只评论类或方法,如果它们有不明显的特征,或者对参数有某种依赖性,并且具有特殊类型的行为。

此外,我意识到评论某些类型的课程有助于我的思考过程。当我能够描述一个类的目的和特征时,我也可以重新思考它的整个存在。

实际上,在对每个代码块的文章都没有评论的范围内,我已经慢慢地从没有评论转向合理有效地使用它们。将来,当语言本身允许声明更多的规则、用例等时,例如dbc,更多地使用表达式而不是语句,则对注释的需求将进一步减少。与此同时,评论仍然有用。


我所做的最重要的改变是我对n层的方法。我一直相信沿着物理层分离逻辑,并构建中间层的"应用服务器"。使用DCOM、MTS和COM+返回Windows DNA,然后使用.NET远程处理。当时,从安全性和可扩展性的角度来看,以这种方式构建系统似乎是合理的。但是,在做了足够的时间之后,我发现增加的复杂性(这很重要)、网络通信开销、部署问题、开发人员培训,以及从未增加安全性的现实(因为我们实际上从未在服务器之间锁定防火墙),这让我得出结论,它很少有理由或保证。

我仍然非常喜欢分层,并且这样做的方式可以使分层成为一种需求,我一直在寻找,但很少这样做。


紧凑代码。

我以前喜欢把任何给定的函数简化为绝对的基本内容,并且经常有嵌套的函数调用来减少行数。

在维护了几年的代码之后,我意识到减少行数只会使代码的可读性变差,而且走捷径只会让代码走下坡路。


少许:

  • 开始在同一行中使用大括号,而不是在新行中使用大括号(if (... ) {)
  • 使用camel case而不是非camel
  • 已停止使用printf()进行调试
  • 开始依赖第三方库而不是从头开始写

JRH


匈牙利符号-它只是增加噪音。使用现代的IDE和编写好的、紧凑的代码,这是不必要的,至少在静态类型语言中是不必要的。不幸的是,我与之合作的大多数团队仍然坚持以某种形式使用它。


用西班牙语编写代码


没有重复/代码重用,这一次我失败了。如果复制所产生的总体工作少于删除复制所需的工作,则复制是可以的。在某些方面,这是一种过度体系结构。


创建用于访问数据的存储过程。地狱要维护(特别是如果你在测试服务器上开发,并且必须维护其他服务器),那么你就结束了名为NeWiSertStulePudioTueReNeX的NeWiSertSturialPuffice程序的GASILLIN存储过程…现在,它很高兴地驻留在应用程序硬编码,使我成为一个快乐的露营者。


头文件不应包括其他头文件。

我曾经强烈反对头部包括其他头部的想法-基于我工程生涯早期的一个不好的经验。在源文件中按需要的顺序显式地包含头文件似乎效果更好。

现在,总的来说,我认为每个头文件都是自给自足的,也就是说,不需要在源文件中包含其他.h文件。特别是在C++开发时…


用大量的内联代码注释记录代码。现在,我按照Bob叔叔的观点,代码应该是自记录的:如果您觉得有必要对某段代码写注释,那么应该重构代码,而不是使其更清晰。

此外,代码注释往往与它们应该描述的实际代码不同步。引用叔叔的话:"真理在法典中,而不是评论。"

强烈推荐的书:《清洁代码:敏捷软件工艺手册》


只捕获您在高可用性服务中知道的异常。

这是一个我不同意自己公司建议的地方。理论上,你应该只抓住你知道的例外情况,因为你无法保证发生的"坏"事情是什么。如果内存被破坏或者clr本身被楔入,您将无法恢复。

然而,当我研究高可用性服务时,我发现经常有这样的情况,我想表达"尽可能多地捕捉错误并继续前进"。是的,理论上,我们可以看到我们无法处理的异常,但是在您控制的环境中使用经过良好测试的代码(除了系统提供的代码之外,混合中没有太多本机代码),这比只捕获您知道的异常更好。

CLR团队对此的立场是"不要让线程在未知状态下执行",而我的立场是"如果您知道您的场景,这可能是正常的"。如果你正在运行一个银行网站可能不太好,但在大多数情况下,这会给你更好的可用性,而不是强迫你想知道为什么你的应用程序如此频繁地重新启动。

你可以在http://blogs.msdn.com/clrteam/archive/2009/02/19/why-catch-exception-empty-catch-is-bad.aspx上看到争论的双方。


我过去写的一些程序。每个例程是一堆东西。现在我为你打破任务,短程序,在做每一件事情(一次常规性的可能)。

因此,常规的参数声明一个风格,龙精。列表:之前

1
int foo (char arg1, int arg2, float arg3, double arg4)

现在

1
2
3
4
5
6
int
foo (
  char arg1,
  int arg2,
  float arg3,
  double arg4  )

这是,当然,()键。


直接访问数据库。在我以前的代码中,我广泛使用查询和数据集。现在我对大多数事情都使用ORM。它给了我更多更清晰的代码和更好的可重用性。通常我现在只在小程序中直接访问数据库,或者在需要性能时访问。


总的来说,思考就是一个坏主意。我发现对于CRUD应用程序来说,这是一条前进的道路。将开发时间缩短一半,并且能够在很少代码更改的情况下将更改从数据库流到ORM。请查看此链接了解一些好的.NET链接:https://stackoverflow.com/q/3505/323548