É considerado um antipadrão para ler o STDIN de uma biblioteca?


39

Enquanto escrevia uma biblioteca para um projeto grande em que estou trabalhando, surgiu um problema que exigia que um token fosse enviado para um endereço de e-mail e depois passado de volta para o código, onde poderia ser usado para uso posterior.

Meu colega diz para ler apenas o STDIN (usando Python:) code = input("Enter code: ")e depois fazer com que um usuário o passe, no entanto, para mim, isso parece uma prática ruim, pois a biblioteca pode (neste caso definitivamente será) ser usada em uma tarefa em segundo plano em um servidor .

Fiquei me perguntando se isso era ou não considerado antipadrão ou não.


45
Nem tudo de ruim é um "anti-padrão", embora isso certamente seja ruim.
Phoshi

4
"padrão" significa algo que os programadores costumam fazer. É apenas um antipadrão se for (A) uma má ideia e (B) algo que você vê desenvolvedores fazendo o tempo todo.
Solomon Slow

20
Isso é burro demais para ser um anti-padrão. Um antipadrão é algo que parece natural e sensato, mas acaba sendo ruim quando você o explora. O que você está descrevendo aqui é obviamente horrível.
Evan Harper

Não estou vendo o objetivo de nenhuma das respostas. O objetivo do exercício de token do usuário deve ser provar que o endereço de e-mail do usuário funciona. Se esse não fosse o ponto, seria muito mais simples simplesmente armazenar o token.
Emory 25/02

2
Isso é horrível. Se for absolutamente necessário transmitir um token como esse, você pode criar um executável separado usando a biblioteca e passá-lo ao stdin. Mas seqüestrar o stdin do executável de chamada, é um não-não.
GrandmasterB

Respostas:


78

Como orientação geral, as bibliotecas devem ser totalmente desconectadas do ambiente. Isso significa que eles não devem executar operações em fluxos padrão, em arquivos específicos ou ter qualquer expectativa sobre o ambiente ou o contexto em que são usados.

Obviamente, há exceções a essa regra, mas deve haver uma boa razão para isso. No caso de usar stdin, não consigo encontrar nenhum motivo (a menos que sua biblioteca realmente forneça rotinas para leitura do stdin, como std::cindo C ++). Além disso, pegar os fluxos de E / S de um parâmetro em vez de codificá-los adiciona tanta flexibilidade que não vale a pena não fazê-lo.


36
A exceção é uma biblioteca que possui um objetivo específico de interagir com um ambiente. Mesmo assim, os detalhes do ambiente devem ser abstraídos. Por exemplo, um driver gráfico precisa se comunicar com o barramento PCIe, mas o ID do barramento deve ser fornecido via configuração.

Este é o tipo de exceção que pensei: minha ideia estava mais próxima de ncurses - geralmente, uma biblioteca de interface de usuário para ambiente de texto. Se seu objetivo é ler a entrada do usuário e fornecer a saída do usuário, esse é um bom motivo.
SF.

5
@SF. Mesmo uma biblioteca como ncurses deve usar um par de descritores de arquivo como argumentos, em vez de codificar o uso de 0 e 1. Você pode escrever um programa em que stdin e stdout possam ser redirecionados e, em vez disso, deseja abrir /dev/ttypara se comunicar com o do utilizador. O programa pode até ser iniciado sem um terminal e abrir seu próprio terminal usando xterm -S.
kasperd

3
@kasperd: A melhor abordagem é fornecer padrões sensatos e capacidade de substituí-los.
SF.

1
Nesse caso em particular, não vejo razão para exigir um fluxo como entrada. Por que não aceitar apenas o token como parâmetro?
Jpmc26

16

Eu consideraria isso não necessariamente um antipadrão, apenas uma biblioteca mal projetada. Deve ser trivial solicitar uma string como parâmetro de método, onde a entrada pode ser passada diretamente.

Se isso não se encaixa nesse uso, um parâmetro de método pode ser um fluxo, com STDIN passado para o método.

Se isso não se encaixa nesse uso, a biblioteca não é flexível o suficiente.


4

Talvez considere ter em sua biblioteca a capacidade de definir um retorno de chamada para uma função fornecida pelo usuário que lerá as entradas de qualquer lugar e, em seguida, retorne o valor apropriado para qualquer parte da biblioteca que esteja usando essa função.


1

Se ler do stdin, significa que gostaria de assumir a propriedade do stdin no nível do programa. Provavelmente não é compatível com nenhuma outra biblioteca que leia a partir de stdin, protocolo menos específico de como eles compartilham o uso. Pelo menos no meu próprio glossário pessoal, isso tornaria a biblioteca uma estrutura , o que é uma troca cara.

Mas, nesse caso, a biblioteca provavelmente deve apenas usar um descritor de arquivo de entrada.


0

A resposta de @ Paul92 é uma boa discussão geral, mas eu gostaria de oferecer uma possível solução limpa (ish) para isso:

Como uma biblioteca, esse código precisa ser adaptável a qualquer ambiente de tempo de execução; portanto, você não pode realmente solicitar STDINalguns dados cruciais. Por um lado, os usuários da sua biblioteca podem não ter o stdin disponível por vários motivos. Em vez disso, convém usar alguma forma de padrão de estratégia para personalizar como o token deve ser recuperado.

No Python, provavelmente a melhor opção é passar a estratégia de busca de token como um parâmetro de função. Algo parecido:

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")

Pense nisso assim. O token que você precisa é um argumento para a função de biblioteca. Como o valor do token pode não ser conhecido estaticamente no site da chamada, você não pode realmente solicitar o valor como argumento. Em vez disso, o chamador deve fornecer uma função que será responsável por fornecer o token quando chamado.

Toda a responsabilidade de fornecer a mecânica exata do token agora é externalizada a partir da função de biblioteca. O consumidor da função agora é responsável por adquirir o token por quaisquer meios disponíveis em tempo de execução. Pode perguntar ao STDIN, mas também pode funcionar como um gateway de email, aguardar a mensagem aparecer na caixa de entrada, ler, extrair o token e automatizar completamente o processo. Pode ser um diálogo da GUI ou um formulário baseado na Web. Qualquer coisa realmente - todas as opções estão agora nas mãos do consumidor da biblioteca.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.