硬编码永远不变的字符串


39

因此,在我为法语编写一个用于共轭动词的程序(通过算法,而不是通过数据集)的过程中,我遇到了一个小问题。

对于动词的大约17种情况,使动词共轭的算法实际上非常简单,并且针对每种情况在特定模式下运行;因此,这17个类的共轭后缀是静态的,并且(很可能)不会很快改变。例如:

// Verbs #1 : (model: "chanter")
    terminations = {
        ind_imp: ["ais", "ais", "ait", "ions", "iez", "aient"],
        ind_pre: ["e", "es", "e", "ons", "ez", "ent"],
        ind_fut: ["erai", "eras", "era", "erons", "erez", "eront"],
        participle: ["é", "ant"]
    };

这些是法语中最常见的动词类的屈折后缀。

还有其他动词类别(不规则动词),其动词变位也很可能在下一两个世纪保持不变。由于它们是不规则的,因此它们的完整共轭必须静态地包含在内,因为它们不能从某个模式中可靠地进行共轭(据我的统计,也只有32个不规则)。例如:

// "être":
    forms = {
        ind_imp: ["étais", "étais", "était", "étions", "étiez", "étaient"],
        ind_pre: ["suis", "es", "est", "sommes", "êtes", "sont"],
        ind_fut: ["serai", "seras", "sera", "serons", "serez", "seront"],
        participle: ["été", "étant"]
    };

我可以将所有这些内容放入XML甚至JSON中,并在需要使用时反序列化,但是有一点吗?这些字符串是自然语言的一部分,自然语言确实会发生变化,但是速度较慢。

我担心的是,通过以“正确”的方式处理并反序列化某些数据源,我不仅使不需要复杂的问题变得复杂,而且我还完全追溯了整个目标。算法方法:不要使用数据源!在C#中,我可以在namespace Verb.Conjugation(例如class Irregular)下创建一个类来将这些字符串以枚举类型或类似的方式容纳,而不是将它们填充到XML中并创建一个class IrregularVerbDeserializer

因此,问题是:对在应用程序生命周期不可能更改的字符串进行硬编码是否合适?当然,我不能保证 100%不会改变,但是在我看来,风险与成本几乎是微不足道的-硬编码是更好的主意。

编辑建议的副本询问如何存储大量的静态字符串,而我的问题是何时应该这些静态字符串进行硬编码


26
您将来是否可能要将此软件用于法语以外的其他语言?

10
是否采用算法方法,很明显,您只需要对这32 * 20的字符串进行硬编码(添加更多语言时就需要更多),唯一真正的问题是将它们放在哪里。我会选择您觉得最方便的地方,这听起来好像暂时在代码中。您以后可以随时将它们随机播放。
Ixrec

1
@ChrisCirefice对我来说听起来很理想。去吧。
Ixrec

2
@Gusdor我想您没有读清楚-我说过,共轭模式可能永远不会改变,或者改变得很少,以至于每100年左右重新编译一次就可以了。当然,代码会发生变化,但是一旦字符串放入其中,我将如何使用它们,除非我要重构,否则在接下来的100年中它们将是静态的。
克里斯·西里菲斯

1
+1。更不用说在60至100年内,这种成本要么不存在,要么完全被更好的版本所取代。
HarryCBurn 2015年

Answers:


56

用硬编码在应用程序生命周期内极不可能更改的字符串是否合适?当然,我不能保证100%不会改变,但是在我看来,风险与成本几乎无关紧要- 硬编码是更好的主意

在我看来,您回答了自己的问题。

我们面临的最大挑战之一是将可能更改的内容与不会更改的内容区分开。有些人发疯,将所有可能的东西都转储到配置文件中。其他人则走到了另一个极端,即使是最明显的变化也需要重新编译。

在找到令人信服的理由使其变得更复杂之前,我将采用最简单的方法来实施。


谢谢丹,这就是我的想法。考虑到没有那么多的字符串,为此编写一个XML模式,要跟踪另一个文件,以及必须编写一个接口来对数据进行反序列化似乎是过大的考虑,因为它是自然语言,因此不可能大幅度地更改在未来的100年中。幸运的是,如今在编程语言中,我们有许多花哨的方法可以在一个漂亮的界面后面提取这些原始数据,例如French.Verb.Irregular.Etre,其中将包含我的问题中的数据。我认为效果不错;)
Chris Cirefice

3
+1在Ruby阵营中,我将开始进行硬编码,然后根据需要将其移动到config。不要通过使事情可配置来过早地设计您的项目。它只会减慢您的速度。
2015年

2
注意:某些组对“硬编码”有不同的定义,因此请注意,该术语表示多种含义。有一个公认的反模式,您可以在其中将值硬编码到函数的语句中,而不是像使用(if (num == 0xFFD8))那样创建数据结构。if (num == JPEG_MAGIC_NUMBER)由于可读性的原因,该示例在几乎所有情况下都应类似。我只是指出这一点,因为“硬编码”一词经常会在人们的脖子上(例如我的脖子)扬起头发,因为该词具有替代含义。
Cort Ammon

@CortAmmon JPEG有很多魔术数字。当然可以JPEG_START_OF_IMAGE_MARKER
user253751

@immibis您选择的恒定命名可能比我的更好。
Cort Ammon 2015年

25

您在错误的范围内进行推理。

您并没有只对单个动词进行硬编码。您已经对语言及其规则进行了硬编码。反过来,这意味着您的应用程序不能用于任何其他语言,并且不能使用其他规则进行扩展。

如果这是您的意图(例如,仅将其用于法语),则由于YAGNI,这是正确的方法。但是您承认自己也想稍后再将其用于其他语言,这意味着很快您将不得不将所有硬编码部分移至配置文件。剩下的问题是:

  • 您会在不久的将来确定将接近100%的应用程序扩展到其他语言吗?如果是这样,则应该立即将内容导出到JSON或XML文件(用于单词,单词的一部分等)和动态语言(用于规则),而不是强迫自己重写应用程序的主要部分。

  • 还是应用程序将来会扩展到某个地方的可能性很小,在这种情况下,YAGNI指示最简单的方法(您现在正在使用的方法)更好?

作为示例,请使用Microsoft Word的拼写检查器。您认为有几件事是硬编码的?

如果您正在开发文本处理器,则可以从一个简单的拼写引擎开始,该引擎具有硬编码的规则甚至硬编码的单词:if word == "musik": suggestSpelling("music");。迅速地,您将开始移动单词,然后在代码外部进行规则管理。除此以外:

  • 每次必须添加一个单词时,都必须重新编译。
  • 如果您学习了新规则,则必须再次更改源代码。
  • 更重要的是,如果不编写大量代码,就无法使引擎适应德语或日语。

当您突出显示自己时:

法语的规则很少适用于日语。

一旦对一种语言的规则进行硬编码,彼此之间就将需要越来越多的代码,特别是考虑到自然语言的复杂性。

另一个主题是如何表达这些不同的规则(如果不是通过代码)。最终,您可能会发现编程语言是实现此目的的最佳工具。在这种情况下,如果您需要扩展引擎而不进行重新编译,则动态语言可能是一个不错的选择。


1
好吧,当然不是所有的东西都在这里硬编码:P,所以我想这实际上取决于确定我想要界面的外观,以便可以将其应用于多种语言。问题是我还不太了解所有语言,因此实际上是不可能的。我认为也许您会遗漏的一件事是,共轭模式(这就是我在说的全部)在一种语言中是非常静态的,而且确实是个案的。动词法语中大约有17种共轭模式。它不会很快延长...
Chris Cirefice

4
我不同意-我认为在通过重构自然而然地将任何内容移出代码之外没有任何意义。从一种语言开始,添加其他语言-有时,ILanguageRule的实现将共享足够的代码,以XML(或其他文件)参数化单个实现的效率更高。但是即使那样,您最终还是可能会拥有结构完全不同的日语。从将接口推为XML(或类似接口)开始,只是乞求在接口而不是在实现中进行更改。
ptyx

2
注意:如果要添加更多语言,并不意味着将语言移动到配置文件中!您同样可以拥有一个LanguageProcessor包含多个子类的类。(实际上,“配置文件”实际上是一个类)
user253751

2
@MainMa:为什么在添加单词时认为重新编译是一个问题?无论如何,在对代码进行任何其他更改时,您都必须重新编译,单词列表可能是代码的一部分,随时间变化的可能性最小
JacquesB 2015年

3
我怀疑,能够在子类中编写每种语言的非常具体的语法规则的灵活性最终比通过某种方式从配置文件加载相同规则的能力更方便(因为您基本上是在编写自己的代码自己的编程语言来解释配置)。
David K

15

当值可以独立于程序逻辑进行更改时,应将字符串提取到配置文件或数据库中。

例如:

  • 将UI文本提取到资源文件中。这允许非程序员编辑和校对文本,并允许通过添加新的本地化资源文件来添加新的语言。

  • 将连接字符串,外部服务的URL等提取到配置文件中。这使您可以在不同的环境中使用不同的配置,并且可以动态更改配置,因为由于应用程序外部的原因可能需要更改它们。

  • 拼写检查器,具有要检查的单词字典。您可以添加新的单词和语言,而无需修改程序逻辑。

但是,提取到配置还会带来复杂的开销,而且并不总是很有意义。

如果不更改程序逻辑就无法更改实际字符串,则可以对字符串进行硬编码

例子:

  • 用于编程语言的编译器。关键字不会提取到配置中,因为每个关键字具有特定的语义,编译器中的代码必须支持这些语义。添加新关键字将始终需要更改代码,因此将字符串提取到配置文件中没有任何价值。
  • 实施协议:例如。HTTP客户端将具有诸如“ GET”,“ content-type”等的硬编码字符串。这里的字符串是协议规范的一部分,因此它们是代码中更改可能性最小的部分。

在您的情况下,我认为这些单词显然是程序逻辑的一个组成部分(因为您要为特定单词构建具有特定规则的共轭器),并且将这些单词提取到外部文件中没有任何价值。

如果您添加了一种新语言,则每种方式都需要添加新代码,因为每种语言都有特定的共轭逻辑。


有人建议您可以添加某种规则引擎,使您可以为任意语言指定共轭规则,因此可以纯粹通过配置来添加新语言。在走那条路之前,请仔细考虑,因为人类语言非常奇怪,因此您需要非常具有表现力的规则引擎。基本上,您会发明一种新的编程语言(共轭DSL)以获得可疑的收益。但是您已经拥有可以使用的编程语言,可以完成您需要的任何事情。无论如何,YAGNI。


1
实际上,在对MainMa的评论中,我提到为此编写DSL是没有意义的,因为很少有自然语言的相似性足以使其值得付出努力。也许法语/西班牙语/意大利语足够接近了,但是考虑到规则数量在任何给定语言中都是高度静态的,因此值得付出额外的努力并不值得。您提到的有关复杂性的其他要点是我的确切担心,我想您很好地理解了我在问题中提出的内容,并举例说明了很好的答案,所以+1!
克里斯·西里菲斯

5

我100%同意Dan Pichelman的回答,但我想补充一件事。您在这里应该问自己的问题是“谁来维护/扩展/更正单词列表?”。如果总是由谁来维护特定语言的规则(我想是特定的开发人员),那么使用外部配置文件就没有意义了,如果这样做会使事情变得更复杂-您将不会从中受益。这个。从这个角度来看,即使您需要不时更改它们,只要将新列表作为新版本的一部分提供就足够了,对这些单词列表进行硬编码也是有意义的。

(另一方面,如果将来有少许机会其他人必须能够维护列表,或者如果您需要在不部署应用程序新版本的情况下更改单词列表,请使用单独的文件。)


这是一个好点-但是,至少在接下来的几年中,我很可能将是唯一真正维护代码的人。这样做的好处在于,即使字符串是硬编码的,也只是一小部分字符串/规则,不太可能很快改变(因为它是自然语言,所以从现在开始不会有太大的变化) -年)。也就是说,共轭规则,动词终止字符串等在我们的一生中很可能是相同的:)
Chris Cirefice 2015年

1
@ChrisCirefice”:正是我的意思。–
布朗

2

即使在硬编码似乎在这里很好,而且比动态加载配置文件更好,我还是建议您不要严格分开你的数据从(动词词典)算法。您可以在构建过程中将它们直接编译到您的应用程序中。

这将使您在维护列表时省去很多麻烦。在您的VCS中,您可以轻松确定提交是否确实改变了算法,或者只是修复了共轭错误。此外,将来可能会在您未考虑的情况下追加该列表。特别是,您计算出的32个不规则动词的数量似乎并不准确。虽然这些内容似乎涵盖了常用的内容,但我发现其中有133个甚至350个引用。


Bergi,我确实计划过从算法中分离数据。您对法国不规则物品的注意事项-对不规则物品的定义充其量只能被误解。当我说不规则动词时,我指的是无法“计算”或仅从其不定式形式共轭的动词。不规则动词根本没有特定的模式,因此需要明确列出它们的共轭(例如在French.Verb.Conjugation.Irregular`下)。从技术上讲,-ir动词是“不规则的”,但实际上它们具有固定的共轭模式:)
Chris Cirefice

0

重要的是分离关注点。您如何实现这一目标并不重要。即Java很好。

与规则的表达方式无关,您是否需要添加一种更改规则的语言:您需要编辑多少代码和文件?

理想情况下,应该可以通过添加“ english.xml”文件或新的“ EnglishRules实现ILanguageRules”对象来添加新语言。如果您想在构建生命周期之外进行更改,则文本文件(JSON / XML)会为您带来优势,但它需要复杂的语法,语法分析,并且更难调试。使用代码文件(Java),您可以以更简单的方式表达复杂的规则,但需要重新构建。

我将从一个干净的语言不可知的接口后面的简单Java API开始-两种情况都需要。如果愿意,您以后总是可以添加由XML文件支持的该接口的实现,但是我认为没有必要立即(或曾经)解决该问题。

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.