18

我听说过最小化代码和最大化数据的概念,并且想知道其他人可以给我什么建议,告诉我在构建自己的系统时应该如何/为什么要这样做?

4

6 回答 6

23

通常,数据驱动的代码更易于阅读和维护。我知道我已经看到数据驱动被极端化并且最终变得非常不可用的情况(我正在考虑我使用过的一些 SAP 部署),但是编写自己的“领域特定语言”来帮助你构建您的软件通常可以节省大量时间。

在我看来,务实的程序员是我读过的编写小语言的最生动的倡导者。运行很少输入语言的小型状态机可以用很少的空间完成很多工作,并且可以很容易地进行修改。

一个具体的例子:考虑一个累进所得税制度,税级为 1,000 美元、10,000 美元和 100,000 美元。低于 1,000 美元的收入是免税的。1,000 美元至 9,999 美元之间的收入按 10% 征税。10,000 美元至 99,999 美元之间的收入按 20% 征税。超过 100,000 美元的收入按 30% 征税。如果您将这一切都写在代码中,它看起来就像您怀疑的那样:

total_tax_burden(income) {
    if (income < 1000)
        return 0
    if (income < 10000)
        return .1 * (income - 1000)
    if (income < 100000)
        return 999.9 + .2 * (income - 10000)
    return 18999.7 + .3 * (income - 100000)
}

添加新的税级、更改现有的税级或更改税级中的税负,都需要修改代码并重新编译。

但如果它是数据驱动的,您可以将此表存储在配置文件中:

1000:0
10000:10
100000:20
inf:30

编写一个小工具来解析这个表并进行查找(不是很困难,对吧?),现在任何人都可以轻松地维护税率表。如果国会决定 1000 个括号会更好,任何人都可以使表格与 IRS 表格对齐,并完成它,无需重新编译代码。相同的通用代码可用于一个括号或数百个括号。

现在来做一些不太明显的事情:测试。AppArmor项目对加载各种配置文件时系统调用应执行的操作进行了数百次测试。一个示例测试如下所示:

#! /bin/bash
# $Id$

#   Copyright (C) 2002-2007 Novell/SUSE
#
#   This program is free software; you can redistribute it and/or
#   modify it under the terms of the GNU General Public License as
#   published by the Free Software Foundation, version 2 of the
#   License.

#=NAME open
#=DESCRIPTION 
# Verify that the open syscall is correctly managed for confined profiles.  
#=END

pwd=`dirname $0`
pwd=`cd $pwd ; /bin/pwd`

bin=$pwd

. $bin/prologue.inc

file=$tmpdir/file
okperm=rw
badperm1=r
badperm2=w

# PASS UNCONFINED
runchecktest "OPEN unconfined RW (create) " pass $file

# PASS TEST (the file shouldn't exist, so open should create it
rm -f ${file}
genprofile $file:$okperm
runchecktest "OPEN RW (create) " pass $file

# PASS TEST
genprofile $file:$okperm
runchecktest "OPEN RW" pass $file

# FAILURE TEST (1)
genprofile $file:$badperm1
runchecktest "OPEN R" fail $file

# FAILURE TEST (2)
genprofile $file:$badperm2
runchecktest "OPEN W" fail $file

# FAILURE TEST (3)
genprofile $file:$badperm1 cap:dac_override
runchecktest "OPEN R+dac_override" fail $file

# FAILURE TEST (4)
# This is testing for bug: https://bugs.wirex.com/show_bug.cgi?id=2885
# When we open O_CREAT|O_RDWR, we are (were?) allowing only write access
# to be required.
rm -f ${file}
genprofile $file:$badperm2
runchecktest "OPEN W (create)" fail $file

它依赖一些辅助函数来生成和加载配置文件,测试函数的结果,并向用户报告。扩展这些小测试脚本比不使用一点语言编写这种功能要容易得多。是的,这些是 shell 脚本,但它们与实际的 shell 脚本相去甚远;)它们实际上是数据。

我希望这有助于激发数据驱动的编程;恐怕我不像其他写过它的人那样雄辩,而且我当然没有擅长它,但我尝试了。

于 2011-01-26T08:40:53.060 回答
18

在现代软件中,代码和数据之间的界限会变得非常细和模糊,而且区分两者并不总是那么容易。毕竟,就计算机而言,一切都是数据,除非由现有代码(通常是操作系统)确定,否则。甚至程序也必须作为数据加载到内存中,然后 CPU 才能执行它们。

例如,想象一个计算订单成本的算法,订单越大,每件商品的价格就越低。它是商店中更大的软件系统的一部分,用 C 语言编写。

该算法用 C 语言编写,并读取一个文件,该文件包含管理层提供的输入表,其中包含各种单品价格和相应的订单大小阈值。大多数人会争辩说,具有简单输入表的文件当然是数据。

现在,假设商店将其策略更改为某种渐近函数,而不是预先选择的阈值,以便它可以容纳疯狂的大订单。他们可能还想考虑汇率和通货膨胀——或者管理层提出的任何其他因素。

商店聘请了一位称职的程序员,她在原始 C 代码中嵌入了一个很好的数学表达式解析器。输入文件现在包含一个带有全局变量、函数(如log()和)的表达式tan(),以及一些简单的东西,如普朗克常数碳 14降解率。

cost = (base * ordered * exchange * ... + ... / ...)^13

大多数人仍然会争辩说,即使不像表格那么简单,表达式实际上也是数据。毕竟,它可能是由管理层按原样提供的。

这家商店收到了大量客户的投诉,这些客户在试图估算他们的费用时脑残,会计人员对大量零钱的投诉。商店决定返回表处理小订单并使用斐波那契数列处理大订单。

程序员厌倦了修改和重新编译 C 代码,因此她嵌入了 Python 解释器。输入文件现在包含一个 Python 函数,该函数轮询一屋子Fib(n)猴子的大订单成本。

问题:这是输入文件数据吗

从严格的技术角度来看,没有什么不同。表和表达式都需要在使用前进行解析。数学表达式解析器可能支持分支和函数——它可能不是图灵完备的,但它仍然使用自己的语言(例如 MathML)。

然而现在很多人会争辩说输入文件只是变成了代码

那么将输入格式从数据转换为代码的显着特征是什么?

  • 可修改性:必须重新编译整个系统才能进行更改,这很好地表明了以代码为中心的系统。然而我可以很容易地想象(嗯,更像是我实际看到的)软件的设计不够完善,例如在编译时就内置了一个输入表。我们不要忘记,许多应用程序仍然在其可执行文件中内置了图标——大多数人会认为这些图标是数据。

  • 输入格式:在我看来,这是人们考虑的最常见的因素:“如果它是编程语言,那么它就是代码”。好吧,C 是代码——毕竟你必须编译它。我也同意 Python 也是代码——它一门成熟的语言。那么为什么不是XML/XSL 代码呢?XSL本身就是一种相当复杂的语言——因此L得名。

在我看来,这两个标准都不是真正的区别特征。我认为人们应该考虑其他事情:

  • 可维护性:简而言之,如果系统用户必须聘请第三方来提供修改系统行为所需的专业知识,那么系统应该在一定程度上被视为以代码为中心。

当然,这意味着一个系统是否是数据驱动的,至少应该考虑到与目标受众的关系——如果不是根据具体情况与客户相关的话。

这也意味着区别可能会受到可用工具集的影响。UML规范是一场噩梦,但现在我们有所有这些图形 UML 编辑器来帮助我们。如果有某种第三方高级 AI 工具可以解析自然语言并生成 XML/Python 等,那么即使对于更复杂的输入,系统也会变成数据驱动的。

一家小商店可能没有聘请第三方的专业知识或资源。因此,允许员工根据普通管理课程(数学、图表等)所获得的知识来修改其行为的东西,对于这些受众来说,可以被认为是充分的数据驱动的。

另一方面,一家价值数十亿的国际公司通常在其工资单中拥有一群 IT 专家和网页设计师。因此,XML/XSL、Javascript,甚至 Python 和 PHP 都可能很容易处理。它还具有足够复杂的要求,以至于更简单的东西可能无法解决它。

我相信,在设计软件系统时,应该努力在所使用的输入格式中实现良好的平衡,目标受众可以做他们需要做的事情,不必经常调用第三方。

应该指出的是,外包更加模糊了界限。有很多问题,对于这些问题,当前的技术根本不允许外行人可以接近解决方案。在这种情况下,解决方案的目标受众可能应该被认为是外包操作的第三方。预计该第三方将雇用相当数量的专家。

于 2011-01-28T18:32:02.587 回答
5

Rob Pike提出的Unix Philosophy下的五个格言之一是:

数据占主导地位。如果您选择了正确的数据结构并将事物组织得很好,那么算法几乎总是不言而喻的。数据结构,而不是算法,是编程的核心。

它通常缩写为“编写使用智能数据的愚蠢代码”。

于 2011-02-01T06:16:20.643 回答
5

其他答案已经深入探讨了您如何经常使用仅对其特定输入模式做出反应的简单代码来编写复杂行为。您可以将数据视为特定领域的语言,并将您的代码视为解释器(可能是一个微不足道的解释器)。

给定大量数据,您可以走得更远:统计数据可以为决策提供动力。Peter Norvig在Beautiful Data中写了一个很棒的章节来说明这个主题,文本、代码和数据都可以在线获取。(披露:感谢致谢。)在第 238-239 页:

数据驱动的方法与程序员编写显式规则的更传统的软件开发过程相比如何?...显然,手写规则很难开发和维护。数据驱动方法的一大优势是数据中编码了如此多的知识,只需收集更多数据就可以添加新知识。但另一个优点是,虽然数据可能很大,但代码简洁——大约 50 行correct,而 ht://Dig 的拼写代码则超过 1,500 行。...

另一个问题是便携性。如果我们想要一个拉脱维亚语拼写校正器,那么英语变音位规则就没什么用了。要将数据驱动的correct算法移植到另一种语言,我们只需要大量的拉脱维亚语语料库;代码保持不变。

他使用在 Google 收集的数据集用 Python 代码具体展示了这一点。除了拼写更正之外,还有用于分割单词和破译密码的代码——在短短的几页中,Grady Booch 的书又花了几十页甚至没有完成。

“数据的不合理有效性”更广泛地发展了相同的主题,没有所有的具体细节。

我在另一家搜索公司的工作中采用了这种方法,我认为与表驱动/DSL 编程相比,它仍然没有得到充分利用,因为我们大多数人直到最近一两年才开始大量使用数据。

于 2011-02-01T22:05:00.697 回答
4

在可以将代码视为数据的语言中,这不是问题。您可以根据解决方案的需要使用清晰、简短和可维护的内容,并倾向于数据、代码、功能、OO 或过程。

在过程中,区分是有区别的,我们倾向于将数据视为以特定方式存储的东西,但即使在过程中,最好将数据隐藏在 API 后面,或者 OO 中的对象后面。

Alookup(avalue)可以在其生命周期内以多种不同的方式重新实现,只要它从一个函数开始。

...我一直在为不存在的机器设计程序并补充说:“如果我们现在有一台包含这里假设的原语的机器,那么工作就完成了。” ...在实际实践中,当然,这台理想的机器将不存在,所以我们的下一个任务——在结构上与原来的相似——是对“上层”机器的模拟进行编程......但这一堆程序是为一台很可能不存在的机器编写的,所以我们的下一个工作是根据下一个较低级别机器的程序来模拟它,等等,直到最后我们有一个可以执行的程序我们的硬件...

EW DijkstraNotes on Structured Programming ,1969 中,由John AllenAnatomy of Lisp中引用,1978。

于 2011-02-02T03:06:20.427 回答
3

当我想到我相当同意的这种哲学时,首先想到的是代码效率。

当我编写代码时,我确信它并不总是接近完美甚至完全知识渊博。了解足够多的知识以在需要时接近机器的最高效率,并在其余时间保持良好的效率(也许为更好的工作流程进行权衡)使我能够生产出高质量的成品。

以数据驱动的方式编码,您最终会使用代码来实现代码的用途。将每个变量“外包”到文件将是愚蠢的极端,程序的功能需要在程序中,内容、设置和其他因素可以由程序管理。

这也允许更多动态应用程序和新功能。

如果您甚至有一个简单的数据库形式,您就可以将相同的功能应用于许多状态。您还可以做各种创造性的事情,例如根据文件头数据或目录、文件名或扩展名更改程序正在执行的操作的上下文,尽管并非所有数据都必须存储在文件系统上。

最后,将您的代码保持在一个只处理数据的状态,让处于一种更接近于设想实际情况的心态。这也使大量代码远离您的代码,从而大大减少了臃肿软件。

我相信它使代码更易于维护、更灵活、更高效,我喜欢它。

也感谢其他人对此的意见!我觉得非常鼓舞人心。

于 2011-01-29T07:40:20.777 回答