用共享的编码范例就好像用语言Y编写程序一样,用语言X编写内容为什么不好?


25

不久前,我在SO上问了一些用C ++编写的东西,但是并没有得到解决这个问题的答案,而是对我的编码风格发了疯,即使当我指出这是WIP的一段代码时那是我打算在运行基本案例时清理它。(我的否决票太多了,因此我决定提出这个问题,因为我在SO上的代表已经非常糟糕了)

这让我想知道为什么人们会采取这样的强硬态度:“你是菜鸟,自己去他妈的”。我被指控像编写Java一样编写C ++。我无法理解的东西仍然让我感到困惑。

我已经用很多OOP语言编程了很多年了,尽管有时是间隔的。我会根据可用的库和最佳的执行环境选择要使用的语言。我在OOP代码中采用了设计模式,并且我非常有信心自己对模式的使用是正确的,并且在OO方面,我可以坚持自己的想法。我了解OOP工具箱,但仅在我认为确实需要时才选择使用这些工具,而不仅仅是使用整洁的技巧来展示我的编码才智。(我知道这不是一流的,但我认为也不是n00b级别)。

在写一行之前,我先设计代码。为了定义测试,我列出了某个类的目标及其必须遵守的测试标准。因为创建序列图然后编写代码对我来说比较容易,所以我选择在界面变得明显之后编写测试。

我必须承认,在我在问题中发布的代码段中,我仍在使用指针,而不是使用智能指针。我会尽可能使用RAII。我知道适当的RAII意味着要防范空指针,但是我会逐步工作。这是一项正在进行的工作,我打算稍后对其进行清理。强烈谴责这种工作方式。

我认为,首先应该有一个可行的示例,这样我才能确定基本案例是否是可行的思维方式。我也碰巧认为,在证明了基本情况之后,清理代码是敏捷重构阶段的典型操作。我必须承认,尽管我慢慢地了解Cxx标准,但我更喜欢使用自己了解的内容,而不是冒着使用尚未在生产代码中掌握的概念的风险。我偶尔会尝试一些新东西,但通常是在我为此而做的游戏项目中。

[edit]我想澄清一下,在我开始提出问题之前,我的搜索结果中并未显示的建议[1]。但是,尽管他的建议确实涵盖了该问题的一个方面,但他所链接的问题并没有回答我问题的核心,只是一部分。我的问题更多是关于我对编码风格的反应以及处理不同编码风格和(明显)技能水平的专业方面。关于我之前关于SO的问题,它就是一个恰当的例子。[/编辑]

然后的问题是:为什么嘲笑不使用您的编码风格的人?

我手头的事务/细分是:

  • 如果重构使重构后的代码更健壮,为什么在原型情况下使用更多容易出错的代码将是不好的编程习惯呢?
  • 用C ++编写的程序如何像用Java编写的一样?是什么使它成为不好的程序,(考虑到我指出了当前风格的意图以及计划中的改进工作)?
  • 如果选择使用某种编程范例(例如OOP / DP)中使用的构造,我将如何成为一名糟糕的专业人员?

[1] 快速发展,然后修正错误或缓慢,注意每一行代码?


5
您最好向C ++ Lounge中的人们问这个问题。首先穿上防火服。
罗伯特·哈维

48
C ++人士是程序员中不常见的人。您的Java工具箱是一个明智的,易于理解的工具箱,其熟悉的工具位于带衬垫的皮革盒中,可在任何工具店中使用。C ++是一个带有裂锯,电钻和一些没人能识别的工具的完整工具集,C ++人群可以像忍者一样处理所有这些工具。当有人进来并将某些工具放回错误位置的架子上时,它们会使他们感到苦恼。他们是程序员的“两次测量,一次剪切”。
罗伯特·哈维

13
也许这与对像FORTRAN这样编写的Java代码的反应相同:所有代码都在一个类中,没有集合,只有固定大小的数组,并带有单独的int变量来跟踪实际长度。
凯文·克莱恩

14
如果您像Java一样编写C ++,最终可能会得到太多的堆分配,这将使您的程序执行得比其差。语言往往会经过设计和优化以促进某些模式,如果您破坏了这些模式,对您来说情况将会变得更糟。
2014年

5
您在线发布了代码以获得某种形式的帮助。我知道您不希望/不希望收到关于您的款式的所有反馈,但是您是否希望完全没有帮助?善与恶。程序员必须寻找代码中的错误;这就是我们所做的。
JeffO 2014年

Answers:


26

没有看到有问题的代码,有几种方法可以用C ++编写Java代码,有些方法比其他方法差。

  1. 在一种极端情况下,您的布局就像Java一样:所有内容都放在一个文件中,类定义内的所有内容,等等:
    class HelloWorldApp {
    public:
        void main() {
            cout << "Hello World!" << endl;
        }
    };
    这就是Java源代码的布局方式。在C ++中,从技术上讲这是合法的,但是将所有内容放在头文件中以及将所有内容都内联(通过在类声明中定义)都是可怕的样式,并且会破坏您的编译性能。不要这样
  2. 过度面向对象-为了简化起见,在Java中,它是名词王国,所有事物都是对象。好的(即惯用的)C ++代码更有可能使用自由函数,模板等,而不是尝试将所有内容塞入对象。
  3. 没有RAII-您已经提到了这一点-使用指针和手动清除而不是智能指针。C ++为您提供了RAII和智能指针之类的工具,因此好的(即惯用的)C ++代码使用这些工具。
  4. 没有高级C ++-Java和C ++的基础知识足够相似,但是一旦您获得了更高级的功能(模板,C ++的算法库等),它们就会开始发生分歧。

除了#1之外,没有一个使C ++程序成为不良程序,但这也不是我更喜欢作为C ++程序员工作的那种代码。(我也不会喜欢使用非惯用的或C风格的Perl,非惯用的Python等。)语言具有自己的工具,习语和哲学,好的代码会使用这些工具和习语,而不是尝试使用最低公分母或试图重现另一种语言的方法。用特定的语言/问题域/任何事物编写非惯用的代码并不会使某人成为不好的程序员,这仅意味着他们有更多的知识可以学习该语言/问题域/任何事物。这没什么不对的。有很多事情我需要进一步学习,特别是C ++有很多东西要学习。

关于编写易于出错的代码以便稍后进行清理的特定问题,它不是黑白的:

  • 如果某些原型代码无法处理所有可能的异常和每种可能的极端情况,那么这是可以预期的。使它正常工作,然后使其稳健运行。没问题。
  • 如果某些原型代码是用糟糕的样式糟糕的设计编写的(对于给定的语言及其习语是糟糕的,对于问题的根本上是糟糕的设计,等等),那么除非您将它作为一次性物品编写概念验证,您没有获得任何收益。

以原始指针与智能指针为例,如果您要在C ++中工作,则使用RAII和智能指针已经足够基础了,以这种方式编写代码应该比返回并稍后进行清理更快。再一次,不这样做并不意味着某人是一个不好的程序员,不专业的人等等,但这确实意味着还有很多东西要学习。


11
有惯用的perl吗?
棘轮怪胎

21
@Onno当您问“如何在不弯曲的情况下将此螺钉锤入墙壁”?每个人都会告诉您不要使用锤子。
Sjoerd 2014年

9
@Onno在C ++中,指针和new被视为动力工具。自动存储是手动工具。
Sjoerd 2014年

9
@Onno:您必须认识到C ++编程课程在采用现代习语方面往往会滞后,自从C ++发明以来,被认为是好的C ++也已经发生了巨大的发展。
Bart van Ingen Schenau 2014年

7
由于C ++的历史,以及大量的程序员在该语言的许多高级功能出现之前就已经学习了该语言,所以仍然有很多糟糕的C ++的编写者像十年前一样编写过。RAII之类的棘手问题是要让每个人都使用现代方法,这样我们就可以停止看到相同的可预测的故障。
2014年

42

每种编程语言都有一组惯用法和最佳实践,通常会产生优美,正确和高效的代码。以下是一些在其他语言下完全可以解决的最坏做法:

  • 如果您for ($i = 0; $i < 42; $i++) { … }使用Perl而不是PHP 编写,我会大喊
    (在Perl中,应声明变量,并且此类循环应在一定范围内迭代)
  • 如果您new Foo()在没有充分理由的情况下使用C ++ 编写代码,而在Java中却没有,我会哭泣
    (C ++没有垃圾回收,因此应使用RAII。Noobs会泄漏内存)
  • 如果在C89,Pascal或JavaScript之外的函数顶部声明所有变量,我将不为所动。
  • 如果将所有函数放入Python类中,而不是Java中,则将面对Facepalm
    (Python是一种多范式语言,而是强制使用“ OOP”并在顶层支持函数)
  • 如果您return null使用Scala,但不会使用任何类似C的语言,我会哭
    (因为Scala具有Option类型)
  • 如果您使用Java而不是OCaml编写递归算法,我会抱怨
    (因为Java的堆栈快速溢出,而OCaml具有尾调用优化功能)

使用一种新语言很容易,就好像它是您所知道的一样,幸运的是,它甚至可以工作。“您可以用任何语言编写Fortran”。但是,您确实不想忽略X语言提供的特定功能,因为X很有可能比U提供一些优势。

我会根据可用的库和适合手头工作的最佳执行环境来选择要使用的语言 ” –但是,这种语言X实际上是否比手头工作的语言U更好,还取决于对该语言的熟悉程度,或者充分熟悉才能使用它需要多长时间。当您实际上想要旧的笔刀,因为它可以完美地适合您的手时,您不会因为它能最快地砍伐木材而产生沉重的链锯。除非你真的想倒下一棵树。

但是您的问题更多是关于文化问题:学习所有最佳实践需要花费大量时间,而新手会提出最多的问题,而专家会回答这些问题。但是,对于上师而言显而易见的对新手而言并不明显,而大师有时会忘记这一点。作为新手,解决方案是不要停止提出问题。但是,人们可以表现出学习和应用最佳实践的开放性,例如通过在尝试将代码展示给他人之前尽可能多地清理代码。大多数语言都有一些易于学习的核心最佳实践,即使整个学习过程实际上很长。

一个常见的问题是,刚接触编程的人会忽略任何缩进或其他格式,然后由于他们的程序无法工作而感到困惑。我也会感到困惑,理解程序的第一步就是确保其布局完美。然后,一些简单的错误突然变得很明显,例如被遗忘的结尾引号或逗号丢失。我相信您已经练习了良好的格式设置,这里是对其他最佳实践的隐喻:最佳实践可以防止错误,最佳实践可以使发现错误更加容易,应用最佳实践是发现问题之前就可以

说“我稍后再修复”太便宜了,现在修复它可以解决您的问题(而且,寓言中的“清理阶段”可能永远不会到来,因此唯一负责任的选择是正确解决第一次)。至少,在寻求他人帮助之前尽可能使您的代码更好,这使他们更容易推理出您的代码,这也是有礼貌的事情。


您在某些观点上说得很对,但是最后我认为您并没有达到目标。您要先获得知识,然后再获得可以获取知识的经验。
2014年

4
@Onno我的主要观点(确实回答了您所提出的问题)是,您不能沿用一种语言的习惯,并认为这是另一种语言的最佳实践,并且从一开始就尝试编写干净的代码胜于清理以后再说。在寻求他人帮助之前,必须尽最大努力清理代码(有关良好代码段的提示,请参见sscce.org)。用“请解决此问题”将垃圾代码倾倒在SO上是不可接受的,尤其是如果您了解得更多。
阿蒙2014年

2
但是关于您所暗示的问题:jm666的答案包含一个关键点:大师认为“如果您不想自己成为X大师,您为什么要问X?”我发现自己经常在这种无助的心态中。化解这种情况的一种可能方法是,您仍然处于学习曲线的最开始,以后会对此进行研究,但是目前手头有这个更直接的问题。但是,这是通信问题,而不是编程问题。
阿蒙2014年

6
C ++和C#分别具有optional<T>Nullable<T>。同样,几乎每个人都在没有RAII的情况下泄漏了C ++中的内存,无论是否没有。
DeadMG 2014年

我发现在块的开头声明变量通常会使您的代码在大多数语言中更易于阅读。这样,您就可以确切地知道何时需要帮助,以记住所有变量的类型。
津津乐道

12

我不是核心C ++开发人员,但是...

如果重构使重构后的代码更健壮,为什么在原型情况下使用更多容易出错的代码将是不好的编程习惯呢?

要记住的一件事是,C ++中的错误通常表示“未定义的行为”。用安全的语言,可能发生的最坏情况是立即终止程序的异常。在C ++中,遇到段错误会很幸运。您的程序完全有可能继续做一些细微的错误。它也可能会在一段时间内正常运行并在很长一段时间内显示错误,或者可能一直在正确运行,但最终会耗尽所有内存。

无论如何,将程序执行完全脱离常规并进入未知领域仅需犯一个错误。对于全职的C ++开发人员来说,“基本情况”意味着“没有可能发生未定义的行为或内存泄漏”。

用C ++编写的程序如何像用Java编写的一样?是什么使它成为不好的程序?

我认为对此没有答案不会在很大程度上是投机和自以为是的。但是,如果您希望我对此付诸实践,Java往往会关联一些反模式,例如所有东西都必须是一个对象。凡在其他语言中你传递一个指针,仿函数或函数,在Java中,你通常会发现吨的空虚和狭义有用的ThingDoersFooFactoriesIFrobnicators这是变相的只是功能。

同样,在其他语言中,您可能会传递一个简单的元组或无名结构,而在Java中,即使仅将2个对象捆绑到一个简单的数据容器中,也要求您使用setter,getter和Javadocs预先定义30行以上的NamedThing类。Java相对缺乏功能,迫使程序员有时需要进行面向对象的两次反向翻转来完成任务。最终的代码在Java之外很少是惯用的。

事实是,在C ++中,您需要一个非常简化的对象图来手动管理内存。通常一个对象完全由另一个对象拥有。在Java中,您不需要遵循如此严格的约束,因为垃圾收集器可确保在不再有引用时对它们进行清理。因此,如果只是将代码从Java音译为C ++,肯定存在错误的内存管理风险。

最后,这可能只是精英主义。我不会假装他们占了大多数,但是我确实看到一些C ++开发人员的观点:“我不需要一种能握住我的手,不会让我做愚蠢的事情的语言”。在他们看来,C ++是一种“真正的”语言,如果您无法处理其特质,那么您就不是“真正的程序员”。


1
Java 8缓解了很多这种情况-Lambdas可以节省大部分时间:-)
Martijn Verburg 2014年

@MartijnVerburg同意,向前迈进了一大步。但是技术问题很容易解决!旧习惯很难消亡,污名甚至更难。哎呀,有些人甚至抱怨Java不需要这些“新”功能中的任何一个,而且Java正在成为下一个C ++。
2014年

是的,我总是在动摇我的头-的Java 刻意总是比演变更慢其他语言,因为它是一个长期的主力。但是,JVM可以以更快的速度跳跃,这使诸如Lambdas之类的东西最终成为语言。
Martijn Verburg 2014年

6

稍微偏离主题答案...

不用担心-这是任何专家社区中常见的“行为”。老实说,如果您精通任何一种语言,并且会遇到“奇怪”的代码,那么您可能也会批评它。(因为要教)。

我在perl世界中-什么时候会看到类似以下内容的信息:

$imax=$#array;
$str=""
for($i=0; $i<$imax; $i++) {
    $str = "$str" . $array[$i];
}

代替:

my $str = join '', @array;

一定会对此功能发表评论-(请参阅:教作者)有关该join功能的信息。

无论如何,太多的批评根本适得其反,最好的例子之一就是下一个:(摘自:http : //perl-begin.org/humour/#How_can_I_switch_off_the_T.V..3F

(此位在2011年3月23日匿名发布到粘贴机器人。经过一些编辑后,放置在此处以供后代使用。)-也进行了少量编辑

问题:如何打开电视?

OP希望听到什么?

例如:找到电视遥控器的开/关按钮,然后按一下。该按钮通常为红色,位于遥控器的最上方。

#perl专家的答案:首先,“打开”是什么意思?首先定义它。不要粘贴您的电视,电视遥控器和客厅。

... nopaste后:

你的房间很丑。电视看起来糟透了。在屏幕上使用清洁先生,然后首先清洁您的客厅。使用三个而不是两个的清洁拖把。除非确实要使用HDMI,否则切勿使用Scart(?)连接器。电视遥控器的按钮不可读,请先清理。您是新手,请阅读:

http://experts.blog/how_to_design_a_future_3D_TV.html http://experts.blog/the_basics_of_tv_repairing.html http://experts.blog/viruses_in_living_room_short_essay.html http://experts.blog/global_chip_replacement_guide.html

IRC嘉宾:但是,我不想当电视专家。

答案:那您为什么要打开电视?!


1
这个答案不是题外话。它准确地解释了为什么有人会批评一种语言的非常规用法,以及为什么有时自动批评会变得过分。我喜欢。
trichoplax

1

如果重构使重构后的代码更健壮,为什么在原型情况下使用更多容易出错的代码将是不好的编程习惯呢?

如果以后要写一些东西而又写又脏又快,那么就有忘记要修复的东西的危险。

用C ++编写的程序如何像用Java编写的一样?是什么使它成为不好的程序,(考虑到我指出了当前风格的意图以及计划中的改进工作)?

在Java中,您不必考虑谁拥有某个对象,您只需传递引用并忽略它就好了,因为它什么都没有。但是在C ++中,需要明确定义谁拥有对象以及谁负责清理对象。

如果我选择使用某种编程范例(例如,OOP / DP)中的构造,那我将如何成为一名糟糕的专业人士?

你不会的 C ++是一种多范式语言,它恰好很好地支持OOP,但是它也可以做很多其他事情。但是,大多数情况归结为使用正确的工具完成工作,而不是每次需要将尖刺钉入木材时都拉出锤子。

您反应不佳的原因是,大多数SO人士倾向于根据您所要求的语言的惯用语言来判断技能。熟悉C ++的人在看到错误的代码看起来像是在过去咬住了他们的东西时,往往会knee之以鼻。


我可以看到,对于某些人来说,忘记改进可能是个问题,但是我的任务清单很长,而且我非常乐于为这类工作添加待办事项标签。(这就是为什么我喜欢VS,它在工作管理方面非常擅长)。文档也是如此。在编写文档之前,我不会编写任何代码。至于所有权问题,由于有顺序图,我认为我确实知道谁与谁链接。
2014年

1
@Onno:坦率地说,没有人知道或关心您个人对这些东西的掌握程度。绝大多数编写类似于Java或C的C ++的人甚至都不那么细致。对于他们来说,第一次学习正确做事要比给自己写笔记回去以后再修复要好得多,因为经验表明他们实际上从来没有真正做过。
cHao 2014年
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.