Почему плохая идея записывать данные конфигурации в коде? - PullRequest
22 голосов
/ 11 мая 2011

Реальный случай (от caff ) для иллюстрации темы короткого вопроса:

$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


Предоставьте ответы, в которых изложены общие проблемы, а не только специфические для примера.

Ответы [ 10 ]

27 голосов
/ 12 мая 2011

Есть много причин, чтобы избежать настройки в коде, и я рассмотрю некоторые из них в главе о конфигурации в Мастеринг Perl .

  • Никакие изменения конфигурации не должны приводить к риску поломки программы. Это, конечно, не должно нести риск нарушения этапа компиляции.
  • Люди не должны редактировать источник, чтобы получить другую конфигурацию.
  • Пользователи должны иметь возможность совместно использовать одно и то же приложение без использования общей группы настроек, вместо этого переустанавливая приложение просто для изменения конфигурации.
  • Людям должно быть разрешено создавать несколько различных конфигураций и запускать их партиями без необходимости редактировать исходный код.
  • Вы должны иметь возможность протестировать ваше приложение при других настройках без изменения кода.
  • Люди не должны учиться программировать, чтобы иметь возможность использовать ваш инструмент.
  • Вы должны только свободно связывать свои структуры данных конфигурации с источником информации, чтобы упростить последующие архитектурные изменения.
  • Вы действительно хотите интерфейс вместо прямого доступа на уровне приложения.

Я подытожил это в своем классе Mastering Perl , сказав людям, что первое правило программирования - создавать ситуацию, когда вы выполняете меньше работы, и люди оставляют вас в покое. Когда вы помещаете конфигурацию в код, вы тратите больше времени на решение проблем установки и реагирование на поломки. Если вам не нравятся подобные вещи, дайте людям возможность изменить настройки, не заставляя вас больше работать.

12 голосов
/ 11 мая 2011

Одной из основных проблем этого подхода является то, что ваша конфигурация не очень переносима.Если бы в Java был построен функционально идентичный инструмент, загрузку конфигурации пришлось бы переделать.Если и в Perl, и в вариации Java используется простой макет key=value, такой как:

owner = "Peter Palfrader"
email = "peter@peter@palfrader.org"
...

, они могут поделиться конфигурацией.

Кроме того, вызов eval в файле конфигурации, похоже, открывает эту систему для атаки.Что злоумышленник может добавить в этот файл конфигурации, если он хочет нанести какой-то ущерб?Вы понимаете, что ЛЮБОЙ произвольный код в вашем конфигурационном файле будет выполняться?

Другая проблема заключается в том, что он крайне нелогичен (по крайней мере для меня).Я ожидал бы, что файл конфигурации будет прочитан некоторым загрузчиком конфигурации, а не выполнен как исполняемый кусок кода.Это не так серьезно, но может запутать новых разработчиков, которые к этому не привыкли.

Наконец, хотя крайне маловероятно , что реализация таких конструкций, как p{...}, когда-либо изменитсяесли они изменили , это может не сработать.

12 голосов
/ 11 мая 2011
$CONFIG{'unhappy_employee'} = `rm -rf /`
6 голосов
/ 12 мая 2011

Причина, по которой я удивляюсь, пока что никто не упомянул - это проверка .Когда конфиг находится в коде, вы должны писать сумасшедшие, искаженные тесты, чтобы иметь возможность безопасно тестировать.Вы можете написать тесты, которые дублируют код, который они тестируют, что делает тесты практически бесполезными;в основном это просто тестирование, вероятность дрейфа и сложность в обслуживании.

Рука об руку с тестированием - это упомянутое развертывание.Когда что-то легко проверить, его будет легко (ну, проще) развернуть.

6 голосов
/ 11 мая 2011

Плохая идея помещать данные конфигурации в скомпилированный код, потому что пользователь не может их легко изменить.Для сценариев, просто убедитесь, что он полностью отделен от остальных, и хорошо документируйте.

3 голосов
/ 11 мая 2011

Основной проблемой здесь является возможность многократного использования в среде, где возможно использование нескольких языков.Если ваш файл конфигурации на языке A, то вы хотите поделиться этой конфигурацией с языком B, вам придется сделать некоторые изменения.

Это еще сложнее, если у вас есть более сложные конфигурации (например, файлы конфигурации apache) и вы пытаетесь выяснить, как обрабатывать потенциальные различия в структурах данных.Если вы используете что-то вроде JSON, YAML и т. Д., Синтаксические анализаторы языка будут знать, как сопоставить вещи со структурами данных языка.

Единственный главный недостаток - отсутствие их вязык, это то, что вы теряете возможность использования установки значений конфигурации для динамических данных.

1 голос
/ 14 мая 2011

Я согласен с Тимом Андерсоном. Кто-то здесь путает конфигурацию в коде, поскольку конфигурация не настраивается. Это исправлено для скомпилированного кода.

Как perl, так и ruby-файл читаются и интерпретируются, как и yml-файл или xml-файл с данными конфигурации. Я выбираю yml, потому что это проще для глаз, чем в коде, как группировка по тестовой среде, разработке, организации и производству, что в коде потребовало бы больше .. кода.

В качестве примечания, XML полностью противоречит принципу «просто на глаз». Мне интересно, что XML-конфигурация широко используется в компилируемых языках.

1 голос
/ 12 мая 2011

Причина 1. Эстетика.Хотя неприятный запах никому не причиняет вреда, люди стараются избавиться от него.

Причина 2. Операционные расходы.Для команды из 5 человек это, вероятно, нормально, но как только вы разделите разработчика и системного администратора, вы должны нанять системных администраторов, которые понимают Perl (что такое $$$), или предоставить разработчикам доступ к производственной системе (большой $$$).

И что еще хуже, у вас не будет времени (также $$$) на внедрение механизма конфигурации, когда вам вдруг понадобится.

0 голосов
/ 19 мая 2014

Моя основная проблема с настройкой во многих небольших сценариях, которые я пишу, заключается в том, что они часто содержат данные для входа (имя пользователя и пароль или токен) в службу, которую я использую.Затем, когда скрипты становятся больше, я начинаю их версировать и хочу загрузить их на github.

Так что перед каждым коммитом мне нужно заменить свою конфигурацию на несколько фиктивных значений.* Также вы должны быть осторожны, чтобы эти значения в какой-то момент не попали в вашу историю коммитов.Это может стать очень раздражающим.Когда вы прошли через это один или два раза, вы больше никогда не попытаетесь вставить конфигурацию в код.

0 голосов
/ 29 ноября 2011

Извините за длинный список кодов.Ниже приведен удобный модуль Conf.pm, который я использовал во многих системах и который позволяет указывать разные переменные для разных производственных, промежуточных и сред разработки.Затем я создаю свои программы, чтобы они либо принимали параметры среды в командной строке, либо сохраняю этот файл за пределами дерева управления исходным кодом, чтобы он никогда не перезаписывался.

AUTOLOAD предоставляет автоматические методы для извлечения переменных.

# 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...