将外部数据转换为您正在编程的语言


39

我不确定该怎么做:

我们从自己工具中的外部工具获取数据。该数据用荷兰语编写。我们正在用英语编写Java代码。然后我们应该将此荷兰语翻译为英语还是保留为荷兰语?例如,我们有两个部门:Bouw(英语建筑)和Onderhoud(英语维护)。

创建逻辑是否合理:

public enum Department { BOUW, ONDERHOUD }

要么:

public enum Department { CONSTRUCTION, MAINTENANCE }

甚至:

public enum Afdeling { BOUW, ONDERHOUD }

(在荷兰语中系部门)


3
可能重复的非英语命名约定
蚊蚋

3
我猜这不是重复的,因为我说的是外部数据,而不是我们自己的应用程序数据,它是用英语命名的。
耶尔

1
如果通常使用非英语的数据对象或来源,则为每个功能和数据对象提供一个具有大致英语等效功能的翻译参考表会有所帮助。这与使用多个单词的函数和对象名称特别相关,这在某些语言中非常普遍。我不得不在绝对不了解该语言的情况下,用母语而不是母语来修复错误,但是由于该程序具有翻译词典,因此显得微不足道。通常,程序翻译库仅包含在正确本地化其软件的项目中。
kayleeFrye_onDeck

3
除标准库外,程序的其余部分是否使用英语或荷兰语标识符?
user253751 '16

目前,我们仅使用英语,但是Departments是唯一的硬编码用户数据,因为某个项目的Department在我们的应用程序中起着重要作用。其他荷兰语值保存在我们的数据库中,因此不会进行硬编码。
耶尔

Answers:


33

在这种情况下,我将枚举保留为荷兰语:

public enum Department { BOUW, ONDERHOUD }

因为使用这些常量的逻辑将与荷兰语中的数据匹配。例如,如果输入为“ bouw”,则比较代码如下所示:

if (Department.BOUW == input.toUpper())

当值匹配时,我发现更容易调试(即使我不知道值是什么意思)。翻译只是增加了一个心理障碍,作为开发人员,我不必跳过以证明其正确性。

但是,如果代码可以帮助其他人理解数据的上下文,则可以对其进行注释:

public enum Department { 
    BOUW, /* build */
    ONDERHOUD /* maintenance */
}

3
@Jelle当然,如果您最终走向国际市场,那么无论如何您可能会对翻译逻辑感到高兴。YAGV上的YMMV。
Williham Totland

6
无论如何,您都不应直接将枚举与字符串进行比较。如果您必须将字符串与带有枚举值的多个单词进行比较,该怎么办?
约根·

25
永远不会使用.toUpper()和==比较字符串,尤其是在处理用户输入的字符串和本地化的字符串时。教科书示例就是土耳其语“ i”字符。
Adriano Repetti

4
@ABoschman行尾注释通常指的是他们所在的行。我已经看到这种评论类型数百次了,
只是

13
在我们的商店中,我们执行与此处建议相反的操作:枚举/常量名称为英语(或英语中为pass的名称),并且注释为“本地化”。哪个好 否则,我们将拥有所有这些名称为的const PAAMAYIM_NEKUDOTAYIM
sq33G '16

59

出于某种原因,英语是通用语/最低公分母。即使从概念上讲,该原因与“每个人都做”一样脆弱,但这仍然是一个相当重要的原因。

违反常规做法意味着您必须了解荷兰语才能理解软件中的数据结构。荷兰语并没有错,但是任何必须与代码库进行交互的工程师说出来的概率仍然低于英语。

因此,除非你是荷兰唯一的商店,并且不打算拓展国际市场曾经,它几乎总是一个好主意,让你的代码和英语,并使用最流行的编码语言。

注意:此建议仅适用于程序代码。用户数据绝对不应翻译,而应按原样进行处理。即使您有客户“ Goldstein”,显然也不应将其名称存储为“金石”。

问题在于“用户提供的,请勿触摸”和“代码片段,始终使用英语”之间存在连续的术语。客户名称非常接近频谱的前端,Java变量接近后端。enum值的常数稍远一些,特别是如果它们表示众所周知的唯一外部实体(例如您的部门),则尤其如此。如果您组织中的每个人都对部门使用荷兰语术语,则您不打算与没有代码库的人打交道,并且现有部门的集合很少发生变化,那么使用可接受的部门名称可能会带来更多枚举常量比局部变量有意义。不过,我仍然不会这样做。


3
+1,在这种情况下使用英语可为您提供代码的可读性和可重用性,此答案中对此进行了披露。尽管做到了这一点,荷兰人还是在某种程度上破坏了他们。
Mikhail Churbanov

4
@Jelle名称对代码有语义意义吗?如果是,请翻译它-无论如何,您都需要翻译该概念。如果没有,为什么要这么做enum呢?那可能只是表明您正在尝试在代码中对数据建模,这可能不是一个好主意。
a安

29
我强烈不同意通常翻译领域特定术语的想法。在某些领域,例如铁路行业,不同语言甚至地区的词汇表差异如此之大,以至于任何翻译一个术语的尝试都将扭曲含义,以至于您阻止任何人理解它。除非您绝对确定应用程序域允许无损翻译,否则请不要翻译域术语
Rhymoid

6
我还从项目负责人那里听说,在另一个项目中,开发人员正在将某些领域对象从荷兰语翻译成英语,并且在项目后期,由于这些自定义翻译,这些对象的含义还不清楚。
耶尔

4
再次阅读@Rhymoid和Jelle的评论。切勿自己翻译域名术语!如果您决定对以荷兰语命名的实体使用英文术语,请确保使用官方翻译而非您自己的翻译。
古兰经

15

尽可能避免翻译,因为每次翻译都是额外的工作,并且可能会引入错误。

“域驱动设计”对现代软件工程的关键贡献是通用语言的概念,该语言是项目所有利益相关者使用的一种语言。根据DDD的说法,翻译不应该在团队内部(包括领域专家,即使仅通过规范文档的代理人出现)也不能在团队内部进行翻译(进一步阅读:Eric Evans的“域驱动设计”,尤其是各章)关于无处不在的语言和策略设计)。

也就是说,如果您的业务专家(或您的规范文档)说荷兰语,则在源代码中表达业务问题时,请使用其(荷兰语)术语。不要不必要地翻译成英文,因为这样做会给业务专家和程序员之间的交流造成人为的障碍,这会花费时间并且可能(通过歧义或错误的翻译)导致错误。

相比之下,如果您的业务专家可以用英语和荷兰语来谈论他们的业务,那么您就可以选择该项目的普遍语言,这是一种幸运的情况,并且有一些偏爱英语的正当理由(例如“国际上可以理解和更有可能被标准所使用”),但这样做并不意味着编码人员应翻译商务人士正在谈论的内容。相反,商务人士应切换语言。

如果需求很复杂并且必须精确地实现,那么拥有无处不在的语言就显得尤为重要,如果您只是在进行CRUD,那么内部使用的语言就没有那么重要了。

个人轶事:我在一个项目中,我们将一些业务服务公开为SOAP端点。该业务完全用德语指定,因此不太可能像英语一样重复使用,因为它涉及特定司法辖区的法律事务。但是,一些象牙塔建筑师要求SOAP接口为英语,以促进将来的重用。这种翻译是临时发生的,在开发人员之间几乎没有协调,而只是一个共享的词汇表,导致同一业务术语在Web服务合同中具有多个名称,而某些业务术语在Web服务合同中具有相同的名称。哦,当然,在分隔线的任何一边都使用了一些名称-但含义不同!

如果您仍然选择翻译,请在词汇表中将翻译标准化,在您的完成定义中添加符合该词汇表的内容,然后在评论中进行检查。不要像我们以前那样粗心。


5
商业专家会说英语。在受过良好教育的荷兰人中,英语水平为100%。
MSalters

4
说英语是一回事。能够将荷兰语领域的术语高质量翻译成英语是另一回事。
古兰经

1
@MSalters:精通什么水平?在我所谈论的项目中,每个人都能说英语,但他们的德语水平还不如英语。例如,有一种getAdminRoll检查管理员角色的方法...(德语单词为“ Rolle”,他们输入了错误的字母:-)
meriton –在罢工中罢工

@古兰:实际上,通常是相反的情况:您的领域专家可能会破坏英语语法,并且在闲聊中会遇到挑战,但是他们会用英语知道他们的领域术语。程序员可能是更大的问题:他们的域名软件,这意味着他们知道的是词汇量,但不一定是商业词汇。
MSalters '16

@meriton:考虑到“ roll”是法文rolle的英文后缀,例如payroll,这实际上不是一个奇怪的错误。平均而言,荷兰的英语流利程度明显高于德国。例如,II不会期望德国大学转用英语作为口语。我认为用德语提交论文仍然被认为是正常的吗?
MSalters '16

9

正确的解决方案是根本不对部门进行硬编码:

ArrayList<String> departments = (... load them from a configuration file ...)

或者,如果您绝对需要部门类型:

class Department { String name; Department(String name) { this.name = name; } ... }
HashMap<String, Department> = (... generate from configuration file ...)

如果发现需要对代码中的特定部门进行测试,则必须更一般地询问该部门的特殊之处,并接受将该部门配置为具有该属性。例如,如果一个部门有每周的工资单,而这正是代码所关心的,那么应该有一个WEEKLY_PAYROLL属性,该属性可以通过配置附加到任何部门。


这个。分开或合并出发的航班或新的出发表格时会发生什么?该代码或多或少会自动适应;将其转换为枚举意味着您需要一个新的版本,否则它将爆炸。
jpmc26 2016年

1
如果部门在我们的应用程序中没有发挥如此重要的作用,那将是一个解决方案。我们有很多if (project.getDepartment().equals(Department.XYZ))陈述。
耶尔

@Jelle怎么样project.isForDepartment("XYZ"),又使用丹尼尔的HashMap(这是在项目注入,或东西)
周六

2
@SáT,说实话,这只是问错字...
Jelle

@Jelle是的,但是可以在运行时捕获它。测试也可以在编译时捕获它们。(尽管我知道您来自哪里,但我确实同意。)
SáT16年

3

对于任何想知道的人:我们选择了第一个选项,主要是因为我们认为您不应该为了翻译而编造术语。但是,如果某个时候有国际开发人员来从事该项目,我们会添加一些文档来说明:

/** The possible departments of a project, given in the Dutch language. */
public enum Department { BOUW, ONDERHOUD }

很高兴您找到了令人满意的方法。though但是,可接受的答案似乎与您选择的方法不同。请考虑将接受的答案更改为与您选择的方法相匹配的其他答案。
主教

我更改了接受的答案。但是,考虑到投票的范围,我认为这也是个人选择,因此我选择了这种方法。
耶尔

2

如果您担心要使用字符串表示形式来显示用户或其他内容,只需在枚举内部定义一个descriptions数组并公开一个方法。
例如:Department.BUILD.getDescription();将输出“ BOUW”

public enum Department { 
    BUILD,
    MAINTENANCE;

    private String[] descriptions = new String[] {
        "BOUW",
        "ONDERHOUD"
    };

    public String getDescription() {
        return descriptions[ordinal()];
    }
}

我知道您选择了其他方式,但以防万一Google涡流意外将人们扔到了这里。

编辑:如Pokechu22所述,您可以使用枚举构造函数和私有属性,如下所示:

public enum Department {
    BUILD("BOUW"),
    MAINTENANCE("ONDERHOUD");

    private final String description;

    private Department(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }
}

这也将达到这种效果。


1
您不需要数组。在Java中,枚举可以具有(私有)构造函数和字段。
Pokechu22 '16

1
@ Pokechu22,但是在构造函数中是否可以使用值或序数将其与描述匹配?我的意思是,您仍然需要在de构造函数中使用数组以获得正确的描述,对吗?
SparK's

1
不,您可以这样操作:public enum Department { BUILD("BOUW"), MAINTENANCE("ONDERHOUD"); private final String description; private Department(String description) { this.description = description; } public String getDescription() { return description; } }
Pokechu22年

@ Pokechu22已添加到答案。我还注意到,如果数组增加,我的实现可能会中断并每次增加2行,而您的实现将增加1行并且不会中断引用。
SparK's

0

您的代码的某些不变量应保持不变。这些不变量之一是重命名标识符时程序的行为不会有所不同。特别是在这种情况下,当您拥有一个枚举并重命名该枚举的任何成员并更新该成员的所有用法时,您不会期望代码开始以不同的方式运行。

解析是读取数据并从中获取数据结构的过程。当您获取外部数据,读取它并创建枚举的实例时,您正在解析数据。该解析过程是程序的唯一部分,负责维护数据表示形式的接收方式与数据类型成员的形状和命名之间的关系。

因此,为枚举成员分配什么名称都没有关系。它们恰好与您读取的数据中使用的字符串一致是偶然的。

当您设计用于对域建模的代码时,成员名称不应与数据的序列化格式相关。它们既不应该是荷兰语术语,也不应该是荷兰语术语的翻译,但它们应该是您认为最适合领域模型的内容。

解析器然后在数据格式和域模型之间转换。那是数据格式应该对您的代码产生的最后影响。

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.