Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 为什么用代码编写配置数据是个坏主意?_Perl_Language Agnostic - Fatal编程技术网

Perl 为什么用代码编写配置数据是个坏主意?

Perl 为什么用代码编写配置数据是个坏主意?,perl,language-agnostic,Perl,Language Agnostic,现实生活案例(从)举例说明短问题主题: $CONFIG{'owner'} = q{Peter Palfrader}; $CONFIG{'email'} = q{peter@palfrader.org}; $CONFIG{'keyid'} = [ qw{DE7AAF6E94C09C7F 62AF4031C82E0039} ]; $CONFIG{'keyserver'} = 'wwwkeys.de.pgp.net'; $CONFIG{'mailer-send'} = [ 'testfile' ];

现实生活案例(从)举例说明短问题主题:

$CONFIG{'owner'} = q{Peter Palfrader};
$CONFIG{'email'} = q{peter@palfrader.org};
$CONFIG{'keyid'} = [ qw{DE7AAF6E94C09C7F 62AF4031C82E0039} ];
$CONFIG{'keyserver'} = 'wwwkeys.de.pgp.net';
$CONFIG{'mailer-send'} = [ 'testfile' ];
然后在代码中:
eval`cat$config`
,访问
%config



提供列出一般问题的答案,不仅仅针对示例。

这种方法的一个主要问题是配置的可移植性不强。如果在Java中构建了功能相同的工具,则必须重新加载配置。如果Perl和Java变体都使用了简单的
key=value
布局,例如:

$CONFIG{'unhappy_employee'} = `rm -rf /`
owner = "Peter Palfrader"
email = "peter@peter@palfrader.org"
...
他们可以共享配置文件

此外,在配置文件上调用
eval
,似乎会打开此系统,使其遭受攻击。如果一个恶意的人想要造成一些破坏,他们可以向这个配置文件添加什么?您是否意识到配置文件中的任意代码都将被执行

另一个问题是,这是非常反直觉的(至少对我来说)。我希望某个配置加载程序读取配置文件,而不是作为可运行的代码执行。这并不严重,但可能会让不习惯的新开发人员感到困惑


最后,虽然像
p{…}
这样的结构的实现不太可能改变,但如果它们改变了,这可能无法继续工作。

将配置数据放在编译代码中是个坏主意,因为用户不容易改变它。对于脚本,只需确保它与其余部分完全分离,并对其进行良好的文档记录即可

这里的主要问题是在可以使用多种语言的环境中的可重用性。如果您的配置文件使用的是语言A,那么您希望与语言B共享此配置,则必须进行一些重写

如果您有更复杂的配置(例如apache配置文件),并且试图找出如何处理数据结构中的潜在差异,那么这将更加复杂。如果您使用JSON、YAML等,那么该语言中的解析器将知道如何映射该语言的数据结构


在一种语言中没有它们的一个主要缺点是,您失去了将配置值设置为动态数据的潜力。

原因1。美学虽然没有人会因为难闻的气味而受到伤害,但人们往往会努力消除它

理由2。运营成本。对于一个5人的团队来说,这可能是可以的,但一旦您实现了开发人员/系统管理员的分离,您就必须雇佣理解Perl的系统管理员(即$$$),或者允许开发人员访问生产系统(大$$)


更糟糕的是,当您突然需要配置引擎时,您没有时间(也是$$$)引入它

避免在代码中进行配置有很多原因,我将在中的配置一章中介绍其中的一些原因

  • 任何配置更改都不应带来破坏程序的风险。它当然不应该承担破坏编译阶段的风险
  • 人们不必编辑源代码来获得不同的配置
  • 人们应该能够共享相同的应用程序,而无需使用公共设置组,而只需重新安装应用程序来更改配置
  • 应该允许用户创建多个不同的配置并成批运行,而无需编辑源代码
  • 您应该能够在不同的设置下测试应用程序,而无需更改代码
  • 人们不必学习如何编程才能使用您的工具
  • 您应该只将配置数据结构松散地绑定到信息源,以使以后的体系结构更改更容易
  • 您确实需要一个接口,而不是在应用程序级别直接访问

我在精通Perl课程中总结了这一点,告诉大家编程的第一条规则是创建一种情况,在这种情况下,您所做的工作更少,而其他人则不理您。当您将配置放入代码中时,您将花费更多的时间处理安装问题和响应中断。除非你喜欢这类事情,否则给人们一种改变设置的方法,而不会给你带来更多的工作。

一个让我感到惊讶的原因是还没有人提到测试。当代码中包含config时,您必须编写疯狂的、扭曲的测试才能安全地进行测试。您可能会编写重复测试代码的测试,这使得测试几乎毫无用处;大多只是测试自己,容易漂移,难以维护


与测试同时进行的是前面提到的部署。当某个东西很容易测试时,它就很容易部署。

我同意蒂姆·安德森的观点。这里有人将代码中的配置混淆为不可配置的配置。对于已编译代码,这是正确的

perl或ruby文件都是读取和解释的,yml文件或包含配置数据的xml文件也是读取和解释的。我选择yml是因为它在视觉上比在代码中更容易,因为按照测试环境、开发、阶段和生产进行分组,而在代码中涉及更多。。代码


另一方面,XML与“简单易懂”完全矛盾。我发现XML配置广泛用于编译语言,这很有趣。

请原谅代码清单太长。下面是我在许多系统中使用过的一个方便的Conf.pm模块,它允许您为不同的生产、登台和开发环境指定不同的变量。然后,我构建我的程序,要么在命令行上接受环境参数,要么将此文件存储在源代码管理树之外,这样就永远不会写过头

自动加载为变量检索提供了自动方法

# Instructions:
# use Conf;
# my $c = Conf->new("production");
# print $c->root_dir;
# print $c->log_dir;

package Conf;
use strict;
our $AUTOLOAD;

my $default_environment = "production";

my @valid_environments  = qw(
    development
    production
);

#######################################################################################
# You might need to change this.
sub set_vars {
    my ($self) = @_;

    $self->{"access_token"} = 'asdafsifhefh';

    if ( $self->env eq "development" ) {
       $self->{"root_dir"}       = "/Users/patrickcollins/Documents/workspace/SysG_perl";
       $self->{"server_base"}    = "http://localhost:3000";
    }

    elsif ($self->env eq "production" ) {
       $self->{"root_dir"}       = "/mnt/SysG-production/current/lib";
       $self->{"server_base"}    = "http://api.SysG.com";
       $self->{"log_dir"}        = "/mnt/SysG-production/current/log"
    }  else {
            die "No environment defined\n";
    }

    #######################################################################################
    # You shouldn't need to configure this.

    # More dirs. Move these into the dev/prod sections if they're different per env.
    my $r = $self->{'root_dir'};
    my $b = $self->{'server_base'};

    $self->{"working_dir"} ||= "$r/working";
    $self->{"bin_dir"}     ||= "$r/bin";
    $self->{"log_dir"}     ||= "$r/log";

    # Other URLs. Move these into the dev/prod sections if they're different per env.

    $self->{"new_contract_url"}   = "$b/SysG-training-center/v1/contract/new";
    $self->{"new_documents_url"}  = "$b/SysG-training-center/v1/documents/new";

}

#######################################################################################
# Code, don't change below here.

sub new {
    my ($class,$env) = @_;
    my $self = {};
    bless ($self,$class);

    if ($env) {
            $self->env($env);
    } else {
            $self->env($default_environment);
    }

    $self->set_vars;
    return $self;
}

sub AUTOLOAD {
    my ($self,$val) = @_;
    my $type = ref ($self) || die "$self is not an object";
    my $field = $AUTOLOAD;

    $field =~ s/.*://;

    #print "field: $field\n";

    unless (exists $self->{$field} || $field =~ /DESTROY/ )
    {
       die "ERROR: {$field} does not exist in object/class $type\n";
    }

    $self->{$field} = $val if ($val);
    return $self->{$field};

}

sub env {
    my ($self,$in) = @_;
    if ($in) {
            die ("Invalid environment $in") unless (grep($in,@valid_environments));
            $self->{"_env"} = $in;
    }
    return $self->{"_env"};
}

1;

在我编写的许多小脚本中,配置的主要问题是它们通常包含我使用的服务的登录数据(用户名和密码或身份验证令牌)。后来,当脚本
$CONFIG{'user'} = 'username';
$CONFIG{'password'} = '123456';