Стратегія передачі аргументів - змінні середовища проти командного рядка


77

Більшість програм, які ми розробники пишемо, повинні бути зовнішніми параметризовані під час запуску. Ми передаємо шляхи до файлів, назви каналів, TCP / IP-адреси тощо. Дотепер я використовував командний рядок, щоб передати їх запущеному додатку. Мені довелося проаналізувати командний рядок mainі направити аргументи туди, де вони потрібні, що, звичайно, є гарним дизайном , але важко підтримувати для великої кількості аргументів. Нещодавно я вирішив використати механізм змінних середовища . Вони є загальнодоступними та доступними з будь-якого місця, що є менш елегантним з архітектурної точки зору, але обмежує кількість коду .

Це моє перше (і, можливо, досить неглибоке) враження щодо обох стратегій, але я хотів би почути думки більш досвідчених розробників - якими є злети та падіння використання змінних середовища та аргументів командного рядка для передачі аргументів процесу? Я хотів би взяти до уваги наступні питання:

  1. якість дизайну (гнучкість / ремонтопридатність),
  2. обмеження пам’яті,
  3. портативність рішення.

Примітки:

Оголошення. 1. Це головний аспект, який мене цікавить.

Оголошення. 2. Це трохи прагматично. Я знаю деякі обмеження для Windows, які на даний момент величезні (понад 32 кБ як для командного рядка, так і для блоку середовища). Думаю, це не проблема, оскільки вам просто потрібно використовувати файл для передачі маси аргументів, якщо вам це потрібно.

Оголошення. 3. Я майже нічого не знаю про Unix, тому не впевнений, чи обидві стратегії настільки ж придатні для використання, як у Windows. Розкажіть про це, якщо хочете.


Чи не могли б Ви дати більше конкретних даних, як у фактичній кількості параметрів? і якщо для них існують групування, чи вони всі випадкові? а для якої мови це? java, c ++ тощо ... Причина, за якою я запитую такий рівень деталізації, полягає в тому, що хоча це може спричинити проблему будь-якою мовою, може існувати конкретне рішення щодо реалізації мови, про яке ви не знаєте.
James Drinkard,

Тільки щоб згадати ОС * nix, вони не мають нічого подібного до "глобальної змінної середовища", і кожна env var успадковується від батьківського процесу до дочірнього процесу під час розгалуження. Отже, "глобальний" не є професіоналом для env var над командним рядком, принаймні для Тих ОС.
shr

Привіт, @jamesDrinkard. Мене цікавить загальний підхід. Якби ви хотіли передати 20 різних мічених аргументів рядка / інтегралу / реального числа із скрипта Python, що виконується 32-розрядним інтерпретатором, у 64-розрядну програму, написану на C ++, який би ви використали метод?
Януш Ленар,

Привіт, @shr. Дякую за примітку * nix. Як зазначив Реймонд нижче, для цього завдання така глобальність взагалі не є плюсом.
Януш Ленар,

1
Це може бути актуальним і захищає змінні оточення: devcenter.heroku.com/articles/config-vars
eyeApps LLC

Відповіді:


77

1) Я б рекомендував якомога більше уникати змінних середовища.

Плюси змінних середовища

  • прості у використанні, оскільки їх видно з будь-якого місця. Якщо багато незалежних програм потребують інформації, цей підхід набагато зручніший.

Мінуси змінних середовища

  • важко використовувати правильно, оскільки вони видно (з можливістю видалення, встановлення) з будь-якого місця. Якщо я встановлю нову програму, яка покладається на змінні середовища, чи будуть вони наступати на мої існуючі? Я ненароком зіпсував свої екологічні змінні, коли вчора мавпував?

Моя думка

  • використовувати аргументи командного рядка для тих аргументів, які, швидше за все, будуть різними для кожного окремого виклику програми (тобто n для програми, яка обчислює n!)
  • використовувати конфігураційні файли для аргументів, які користувач міг би розумно захотіти змінити, але не дуже часто (тобто розмір дисплея, коли спливає вікно)
  • економно використовуйте змінні середовища - бажано лише для аргументів, які, як очікується, не зміняться (тобто розташування інтерпретатора Python)
  • Ваша думка They are global and accessible from anywhere, which is less elegant from architectural point of view, but limits the amount of codeнагадує мені обґрунтування використання глобальних змінних;)

Мої шрами від переживання власних жахів від надмірного використання екологічних змінних

  • дві необхідні нам програми на роботі, які не можуть працювати одночасно на одному комп’ютері через екологічні зіткнення
  • кілька версій програм з однаковою назвою, але різними помилками - годинами ставив на коліна цілу майстерню, оскільки місце розташування програми було витягнуте із середовища і було (мовчки, тонко) неправильним.

2) Межі

Якби я пересував межі або того, що може містити командний рядок, або того, що може обробляти середовище, я б негайно рефакторував.

Раніше я використовував JSON для програми командного рядка, яка потребувала багато параметрів. Було дуже зручно мати можливість користуватися словниками та списками, поряд із рядками та цифрами. Програма взяла лише пару аргументів командного рядка, одним з яких було розташування файлу JSON.

Переваги такого підходу

  • не потрібно було писати багато (болючого) коду для взаємодії з бібліотекою CLI - це може бути болем змусити багато загальних бібліотек застосовувати складні обмеження (під сложним я маю на увазі більш складний, ніж перевірка на наявність конкретна клавіша або чергування між набором клавіш)
  • не потрібно турбуватися про вимоги до бібліотек CLI для порядку аргументів - просто використовуйте об'єкт JSON!
  • легко представити складні дані (відповіді What won't fit into command line parameters?), такі як списки
  • легко використовувати дані інших програм - як для створення, так і для програмного аналізу
  • легко розмістити майбутні розширення

Примітка : Я хочу відрізнити це від підходу .config-file - це не для зберігання конфігурації користувача. Можливо, мені слід назвати це підходом `` файл параметрів командного рядка '', тому що я використовую його для програми, яка потребує безлічі значень, які не підходять для командного рядка.


3) Переносимість рішення: Я не знаю багато про відмінності між Mac, PC та Linux щодо змінних середовища та аргументів командного рядка, але я можу сказати вам:

  • всі троє мають підтримку змінних середовища
  • всі вони підтримують аргументи командного рядка

Так, я знаю - це не дуже допомогло. Вибачте. Але ключовим моментом є те, що ви можете розраховувати на розумне рішення, яке буде портативним, хоча ви точно хочете перевірити це для своїх програм (наприклад, чи чутливі до регістру аргументи командного рядка на будь-яких платформах? На всіх платформах? Я не знаю ).


Останнє:

Як згадував Томаш, для більшості додатків не повинно бути важливо, звідки походять параметри.


Дякую, Метте. Це якась думка, яку я шукав. Найважливіша ваша порада - використовувати змінні середовища для опису середовища виконання, яке майже не змінюється, та cmd-файл для фактичного виконання простих / складних аргументів. Дуже раціонально, дякую. Зверніть увагу, що ви могли використовувати "локальні" змінні середовища, які лише могли зіпсувати дочірні процеси. Це дуже схоже на передачу аргументів командного рядка, за винятком того, що Реймонд зазначив під відповідь Томаша.
Януш Ленар,

1
Дуже приємна відповідь! Щодо недоліку того, що змінні середовища можна змінювати з будь-якого місця: Існує також можливість встановлювати змінні середовища локально із початкового сценарію (наприклад, Bash або Batch script) для програми. У цьому випадку може існувати загальносистемне значення за замовчуванням, але програма може за необхідності змінити значення за замовчуванням на власне значення. Які ваші думки з цього приводу?
Lii

Чи є плюси та мінуси при розгляді питання про те, як передавати секрети / дані?
iamyojimbo

Я погоджуюсь з настільними програмами та програмами CLI. Для хмарної системи, яка має багато розгортань, змінні env є гарною альтернативою і, наприклад, рекомендовані в посібнику 12factor
Ларс Граммель

7

Ви повинні абстрагувати параметри читання, використовуючи шаблон стратегії . Створіть абстракцію з іменем ConfigurationSourceмає readConfig(key) -> valueметод (або повертає якийсь Configurationоб'єкт / структуру) з наступними реалізаціями:

  • CommandLineConfigurationSource
  • EnvironmentVariableConfigurationSource
  • WindowsFileConfigurationSource - завантаження з конфігураційного файлу з C:/Document and settings...
  • WindowsRegistryConfigurationSource
  • NetworkConfigrationSource
  • UnixFileConfigurationSource завантаження з конфігураційного файлу з /home/user/...
  • DefaultConfigurationSource - за замовчуванням
  • ...

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

Оголошення 1. Цей підхід дозволяє не лише абстрагувати конфігурацію читання, але й легко змінити базовий механізм, не впливаючи на код клієнта. Також ви можете використовувати кілька джерел одночасно, відступаючи назад або збираючи конфігурацію з різних джерел.

Оголошення 2. Просто виберіть, яка з варіантів реалізації підходить. Звичайно, деякі записи конфігурації не вписуються, наприклад, в аргументи командного рядка.

Оголошення 3. Якщо деякі реалізації не є портативними, використовуйте дві, одна мовчки ігнорується / пропускається, коли не підходить для даної системи.


Дякую, це взагалі гарна ідея. Але це не допомагає при прийнятті рішення про використання середовища або командного рядка. Докладним буде розроблення Вашого Ad.2. "Деякі записи конфігурації не вписуються, наприклад, в аргументи командного рядка" . Що не впишеться в рядок? Якщо він не підходить, його, мабуть, слід передавати опосередковано у своєрідний файл, чи не так?
Януш Ленар,

Я хочу сказати: не змушуйте користувача використовувати параметри командного рядка або змінні середовища. Будьте гнучкими (і при цьому збережіть код, що підтримується). Я вважаю, що конфігураційний файл є найкращим місцем для зберігання конфігурації (він може бути довільно довгим, містити коментарі тощо), проте іноді корисно замінити конфігурацію файлу за допомогою параметрів командного рядка. Що не вписується в параметри командного рядка? Якщо вам потрібно пройти кілька шляхів до файлів, це, мабуть, спрацює, але надто довгі командні рядки ніхто не любить.
Томаш Нуркевич,

Файл конфігурації найкращий для аргументів - це цінна думка, і підтримка коментарів є вагомою підставою для його використання, дякую. Якщо ви використовуєте змінні середовища під час запуску програми із пакетного сценарію, ви можете мати дуже читабельну форму, використовуючи remта set. Якщо ви породжуєте процес, ви лише setenvте, що хочете, перед тим, як spawnlрозпочати. Це зручно, читається та гнучко. Чому ви використовуєте .config замість середовища? Це питання.
Януш Ленар,

3
Пам'ятайте, що змінні середовища успадковуються. Припустимо, ваша програма має два параметри ACTIONта необов’язковий NOTIFY. Program A встановлює, ACTION=if owner=nobody set owner=bobа NOTIFY=sendпотім запускає вашу програму. Ваша програма оновлює елемент, а потім бачить, що NOTIFYвстановлено та працює send. sendПрограма посилає електронну пошту Бобу , а потім запускає програму знову, установка ACTION=set last_send = today. Він не хоче жодного сповіщення, тому не встановлює NOTIFY. Але вона успадкувала NOTIFY програму А, тому ваша програма оновлює останню запуску до сьогодні, а потім запускається send. Нескінченна петля.
Raymond Chen

1
Дякую, @Raymond. Сфера дії змінних середовища є небезпечно широкою. Влучне зауваження.
Януш Ленар,

4

Я думаю, що на це запитання вже досить добре відповіли, але я відчуваю, що воно заслуговує оновлення 2018 року. Я відчуваю, що не згадувана перевага змінних середовища полягає в тому, що вони, як правило, потребують менше коду котлової плити для роботи. Це робить чистіший і читабельніший код. Однак головним недоліком є ​​те, що вони видаляють шари ізоляції від різних програм, що працюють на одній машині. Я думаю, що тут Docker справді блищить. Мій улюблений шаблон дизайну - використовувати виключно змінні середовища та запускати програму всередині контейнера Docker. Це усуває проблему ізоляції.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.