Считается ли это анти-паттерном для чтения из STDIN из библиотеки?

39

Во время написания библиотеки для большого проекта, над которым я работаю на работе, возникла проблема, которая требовала, чтобы токен был отправлен на адрес электронной почты, а затем возвращен в код, где он может быть использован для дальнейшего использования.

Мой коллега говорит, что нужно просто читать из STDIN (используя Python:), code = input("Enter code: ")а затем передать его пользователю, однако для меня это кажется плохой практикой, поскольку библиотека может (в этом случае определенно будет) использоваться в фоновом режиме на сервере. ,

Мне было интересно, считается ли это анти-паттерном или нет.

Paradoxis
источник
45
Не все плохое - это «антишаблон», хотя это, безусловно, плохо.
Фоши
4
«шаблон» означает то, что часто делают программисты. Это только анти-паттерн, если это (A) плохая идея и (B) то, что, как вы видите, делают разработчики все время.
Соломон Слоу
20
Это слишком глупо, чтобы быть анти-паттерном. Анти-паттерн - это то, что кажется естественным и разумным, но оказывается плохим, когда вы копаетесь в нем. То, что вы описываете здесь, просто ужасно.
Эван Харпер
Я не вижу смысла ни в одном из ответов. Смысл использования токена пользователя должен состоять в том, чтобы доказать, что адрес электронной почты пользователя работает. Если бы это было не так, то было бы гораздо проще просто сохранить токен.
Эмори
2
Это довольно ужасно. Если передача токена, подобного этому, абсолютно необходима, вы можете создать отдельный исполняемый файл с использованием библиотеки и передать свой токен в его стандартный ввод. Но перехватить стандартный код вызывающего исполняемого файла - это нет-нет.
GrandmasterB

Ответы:

78

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

Конечно, есть исключения из этого правила, но для этого должна быть очень веская причина. В случае использования stdinя не могу найти никакой причины (если ваша библиотека на самом деле не предоставляет подпрограммы для чтения из stdin, как std::cinиз C ++). Кроме того, взятие потоков ввода-вывода из параметра вместо их жесткого кодирования добавляет столько гибкости, что не стоит этого делать.

Paul92
источник
36
Исключением является библиотека, которая имеет конкретную цель взаимодействия со средой. Даже тогда, детали окружающей среды должны быть абстрагированы. Например, графический драйвер должен взаимодействовать с шиной PCIe, но идентификатор шины должен быть предоставлен через конфигурацию.
Я подумал, что это исключение: моя идея была ближе к ncurses - как правило, к библиотеке пользовательского интерфейса в текстовом окружении. Если его целью является чтение пользовательского ввода и предоставление пользовательского вывода, это веская причина.
SF.
5
@SF. Даже такая библиотека, как ncurses, должна принимать пару файловых дескрипторов в качестве аргументов, а не жестко кодировать использование 0 и 1. Возможно, вы захотите написать программу, в которой stdin и stdout могут быть перенаправлены, и вместо этого вы хотите открыть их /dev/ttyдля связи с пользователь. Программа может даже быть запущена без терминала и открыть свой собственный терминал с помощью xterm -S.
kasperd
3
@kasperd: лучший подход - предоставить разумные значения по умолчанию и возможность их переопределить.
SF.
1
В этом конкретном случае я не вижу причин требовать поток в качестве входных данных. Почему бы просто не принять токен в качестве параметра?
jpmc26
16

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

Если это не подходит для этого использования, то параметром метода может быть поток, с STDIN, переданным в метод.

Если это не подходит для этого использования, то библиотека недостаточно гибкая.

Брайан Бетчер
источник
4

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

FrustratedWithFormsDesigner
источник
1

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

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

djechlin
источник
0

Ответ @ Paul92 - это хорошее общее обсуждение, но я хотел бы предложить возможное чистое (ish) решение этого:

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

В Python, вероятно, лучшим вариантом является передача стратегии извлечения токена в качестве параметра функции. Что-то такое:

def stdin_prompt():
    return input("Enter code: ")

def my_library_function(arg1, arg2, ... argn, token_provider = stdin_prompt):
    ...
    token = token_provider()
    ...
    return stuff

# somewhere in the user code
stuff = my_library_function(a1, a2, ... an, lambda: "123456")

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

Вся ответственность за предоставление точной механики токена теперь не связана с библиотечной функцией. Теперь пользователь функции отвечает за получение токена любыми доступными во время выполнения средствами. Он может запрашивать STDIN, но он также может выступать в качестве почтового шлюза, ждать, пока сообщение войдет в папку «Входящие», прочитать его, извлечь токен и полностью автоматизировать процесс. Это может быть графический интерфейс или веб-форма. Что-нибудь действительно - все варианты теперь находятся в руках потребителя библиотеки.

Роланд Тепп
источник