È considerato un anti-pattern da leggere da STDIN all'interno di una libreria?


39

Mentre scrivo una libreria per un grande progetto a cui sto lavorando al lavoro, è emerso un problema che richiedeva l'invio di un token a un indirizzo e-mail, quindi il codice veniva restituito per un ulteriore utilizzo.

Il mio collega dice di leggere da STDIN (usando Python:) code = input("Enter code: ")e quindi far passare un utente, tuttavia per me questa sembra una cattiva pratica poiché la libreria potrebbe (in questo caso sicuramente) essere utilizzata in un'attività in background su un server .

Mi chiedevo se questo fosse o meno considerato un anti-pattern.


45
Non tutto ciò che è male è un "anti-pattern", anche se questo è certamente negativo.
Phoshi,

4
"pattern" significa qualcosa che i programmatori fanno spesso. È solo un anti-pattern se è (A) una cattiva idea e (B) qualcosa che vedi gli sviluppatori fare continuamente.
Solomon Slow

20
Questo è troppo stupido per essere un anti-schema. Un anti-pattern è qualcosa che sembra naturale e ragionevole ma si rivela male quando ci si scava dentro. Quello che stai descrivendo qui è ovviamente raccapricciante.
Evan Harper,

Non vedo il punto di nessuna delle risposte. Il punto dell'esercizio del token utente deve essere quello di dimostrare che l'indirizzo e-mail dell'utente funziona. Se non fosse questo il punto, sarebbe molto più semplice memorizzare semplicemente il token.
emory

2
È terribile. Se è assolutamente necessario passare un token del genere, è possibile creare un eseguibile separato utilizzando la libreria e passare il token al suo stdin. Ma dirottare lo stdin dell'eseguibile chiamante, è un no-no.
GrandmasterB,

Risposte:


78

Come linea guida generale, le biblioteche dovrebbero essere totalmente disconnesse dall'ambiente. Ciò significa che non dovrebbero eseguire operazioni su stream standard, su file specifici o avere aspettative sull'ambiente o sul contesto in cui vengono utilizzati.

Naturalmente, ci sono eccezioni a questa regola, ma ci deve essere una ragione molto valida per questo. Nel caso dell'uso stdin, non riesco a trovare alcun motivo (a meno che la tua libreria non fornisca effettivamente routine per la lettura da stdin, come std::cinda C ++). Inoltre, prendere i flussi I / O da un parametro piuttosto che averli codificati in modo rigido aggiunge tanta flessibilità che non vale la pena non farlo.


36
L'eccezione è una libreria che ha un obiettivo specifico di interagire con un ambiente. Anche allora, i dettagli dell'ambiente dovrebbero essere sottratti. Ad esempio, un driver grafico deve comunicare con il bus PCIe, ma l'ID bus deve essere fornito tramite la configurazione.

Questo è il tipo di eccezione che ho pensato: la mia idea era più vicina a ncurses - in genere, una libreria di interfaccia utente di testo-ambiente. Se il suo scopo è leggere l'input dell'utente e fornire l'output dell'utente, questa è una buona ragione.
SF.

5
@SF. Anche una libreria come ncurses dovrebbe prendere una coppia di descrittori di file come argomenti piuttosto che codificare hardcando l'uso di 0 e 1. Potresti voler scrivere un programma in cui stdin e stdout possono essere reindirizzati e invece vuoi aprire /dev/ttyper comunicare con il utente. Il programma potrebbe anche essere avviato senza un terminale e aprire il proprio terminale utilizzando xterm -S.
Kasperd,

3
@kasperd: l'approccio migliore è fornire impostazioni predefinite ragionevoli e la capacità di ignorarle.
SF.

1
In questo caso particolare, non vedo alcun motivo per richiedere un flusso come input. Perché non accettare semplicemente il token come parametro?
jpmc26,

16

Considererei questo non necessariamente un anti-pattern, solo una libreria mal progettata. Dovrebbe essere banale chiedere una stringa come parametro del metodo, in cui l'input potrebbe essere passato direttamente.

Se ciò non si adatta a questo utilizzo, un parametro di metodo può essere un flusso, con STDIN passato nel metodo.

Se ciò non si adatta a questo utilizzo, la libreria non è abbastanza flessibile.


4

Forse prendere in considerazione la possibilità nella propria libreria di impostare un callback su una funzione fornita dall'utente che leggerà l'input da qualsiasi luogo e quindi restituirà il valore appropriato a qualunque parte della libreria stia utilizzando quella funzione.


1

Se legge da stdin, significa che vorrebbe prendere la proprietà a livello di programma di stdin. Probabilmente non è compatibile con qualsiasi altra libreria che legge dallo stdin, protocollo meno specifico per il modo in cui condividono l'uso. Almeno nel mio glossario personale, questo renderebbe la biblioteca un framework , che è un costoso compromesso.

Ma in questo caso, la libreria dovrebbe probabilmente semplicemente prendere un descrittore di file di input.


0

La risposta di @ Paul92 è una buona discussione generale, ma vorrei offrire una possibile soluzione pulita (ish) a questo:

In una libreria, questo codice deve essere adattabile a qualsiasi ambiente di runtime, quindi non puoi davvero chiedere STDINalcuni bit cruciali di dati. Per uno, gli utenti della tua libreria potrebbero non avere stdin disponibile per una serie di motivi. Invece potresti voler usare una qualche forma di modello di strategia per personalizzare il modo in cui il token deve essere recuperato.

In Python, probabilmente l'opzione migliore è passare la strategia di recupero dei token come parametro di funzione. Qualcosa del genere:

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

Pensala in questo modo. Il token richiesto è un argomento per la funzione di libreria. Poiché il valore per il token potrebbe non essere staticamente noto nel sito di chiamata, non è possibile richiedere il valore come argomento. Al contrario, il chiamante deve fornire una funzione che sarà responsabile di fornire il token quando viene chiamato.

Tutta la responsabilità di fornire la meccanica esatta del token è ora esternalizzata dalla funzione di libreria. Il consumatore della funzione è ora responsabile dell'acquisizione del token con qualsiasi mezzo disponibile in fase di esecuzione. Potrebbe chiedere STDIN, ma potrebbe anche fungere da gateway di posta, attendere che il messaggio compaia nella posta in arrivo, leggerlo, estrarre il token e automatizzare completamente il processo. Potrebbe essere una finestra di dialogo della GUI o un modulo basato sul Web. Qualsiasi cosa in realtà - tutte le opzioni sono ora nelle mani del consumatore della biblioteca.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.