มันถือว่าเป็นรูปแบบการต่อต้านการอ่านจาก STDIN จากภายในห้องสมุดหรือไม่?


39

ในขณะที่เขียนห้องสมุดสำหรับโครงการขนาดใหญ่ที่ฉันกำลังทำงานอยู่มีปัญหาเกิดขึ้นซึ่งต้องใช้โทเค็นเพื่อส่งไปยังที่อยู่อีเมลจากนั้นส่งกลับไปยังรหัสที่สามารถใช้เพื่อการใช้งานต่อไป

เพื่อนร่วมงานของฉันบอกว่าให้อ่านจาก STDIN (โดยใช้ Python:) code = input("Enter code: ")จากนั้นให้ผู้ใช้ส่งมันมาให้ฉัน แต่สำหรับฉันนี่เป็นวิธีปฏิบัติที่ไม่ดีเนื่องจากห้องสมุดอาจใช้ (ในกรณีนี้จะ) ใช้ในงานแบ็คกราวน์บนเซิร์ฟเวอร์ .

ฉันสงสัยว่าสิ่งนี้ถือเป็นรูปแบบการต่อต้านหรือไม่


45
ไม่ใช่ทุกสิ่งที่ไม่ดีคือ "รูปแบบการต่อต้าน" แต่สิ่งนี้ไม่ดีอย่างแน่นอน
Phoshi

4
"รูปแบบ" หมายถึงสิ่งที่โปรแกรมเมอร์มักทำ มันเป็นเพียงรูปแบบการต่อต้านถ้าทั้งคู่ (A) เป็นความคิดที่ไม่ดีและ (B) สิ่งที่คุณเห็นนักพัฒนาทำอยู่ตลอดเวลา
โซโลมอนช้า

20
นี่มันโง่เกินกว่าที่จะเป็นรูปแบบการต่อต้าน รูปแบบการต่อต้านเป็นสิ่งที่ดูเป็นธรรมชาติและมีเหตุผล แต่กลับกลายเป็นว่าไม่ดีเมื่อคุณขุดเข้าไป สิ่งที่คุณกำลังอธิบายที่นี่เป็นที่น่ากลัวอย่างเห็นได้ชัด
Evan Harper

ฉันไม่เห็นประเด็นของคำตอบใด ๆ จุดของการฝึกอบรมโทเค็นของผู้ใช้จะต้องพิสูจน์ว่าที่อยู่อีเมลของผู้ใช้นั้นใช้งานได้ หากไม่ใช่จุดนั้นจะง่ายกว่ามากในการจัดเก็บโทเค็น
emory

2
มันแย่มาก หากผ่านโทเค็นแบบที่จำเป็นอย่างยิ่งคุณอาจสร้างไฟล์สั่งแยกต่างหากโดยใช้ไลบรารีและส่งโทเค็นของคุณไปยัง stdin แต่การไฮแจ็ค stdin ของการเรียกใช้งานได้นั้นไม่น่าจะเป็นไปได้
GrandmasterB

คำตอบ:


78

ตามแนวทางทั่วไปห้องสมุดควรถูกตัดการเชื่อมต่อจากสภาพแวดล้อมโดยสิ้นเชิง ซึ่งหมายความว่าพวกเขาไม่ควรดำเนินการกับสตรีมมาตรฐานไฟล์เฉพาะหรือมีความคาดหวังเกี่ยวกับสภาพแวดล้อมหรือบริบทที่ใช้

แน่นอนว่ามีข้อยกเว้นสำหรับกฎนี้ แต่ต้องมีเหตุผลที่ดีสำหรับมัน ในกรณีของการใช้stdinฉันไม่สามารถหาเหตุผลใด ๆ (เว้นแต่ห้องสมุดของคุณมีรูทีนสำหรับการอ่านจาก stdin เช่นstd::cinจาก C ++) นอกจากนี้การใช้สตรีม I / O จากพารามิเตอร์แทนที่จะให้ฮาร์ดโค้ดนั้นเพิ่มความยืดหยุ่นมากจนไม่คุ้มที่จะไม่ทำ


36
ข้อยกเว้นคือไลบรารีที่มีเป้าหมายเฉพาะในการโต้ตอบกับสภาพแวดล้อม แม้กระนั้นรายละเอียดของสภาพแวดล้อมก็ควรถูกแยกออกไป ตัวอย่างเช่นไดรเวอร์กราฟิกต้องสื่อสารกับบัส PCIe แต่ควรมีการระบุ ID รถบัสผ่านการกำหนดค่า

นี่คือข้อยกเว้นที่ฉันคิดว่า: ความคิดของฉันอยู่ใกล้กับncurses - โดยทั่วไปแล้วไลบรารีอินเทอร์เฟซผู้ใช้ของสภาพแวดล้อมข้อความ หากวัตถุประสงค์คือเพื่ออ่านอินพุตของผู้ใช้และจัดเตรียมเอาต์พุตของผู้ใช้นั่นเป็นเหตุผลที่ดี
เอสเอฟ

5
@SF แม้แต่ไลบรารี่อย่างncursesก็ควรใช้ file descriptors คู่หนึ่งเป็นอาร์กิวเมนต์แทนที่จะใช้ hardcoding ในการใช้ 0 และ 1 คุณอาจต้องการเขียนโปรแกรมที่สามารถเปลี่ยนเส้นทาง stdin และ stdout แทนคุณต้องการเปิด/dev/ttyเพื่อสื่อสารกับ ผู้ใช้งาน xterm -Sโปรแกรมอาจแม้จะเริ่มต้นโดยไม่มีขั้วและเปิดสถานีของตัวเองโดยใช้
kasperd

3
@kasperd: วิธีที่ดีที่สุดคือการให้ค่าเริ่มต้นที่สมเหตุสมผลและความสามารถในการลบล้างพวกเขา
เอสเอฟ

1
โดยเฉพาะอย่างยิ่งในกรณีนี้ฉันไม่เห็นเหตุผลใด ๆ ที่ต้องการสตรีมเป็นอินพุต ทำไมไม่ยอมรับโทเค็นเป็นพารามิเตอร์เท่านั้น
jpmc26

16

ฉันจะพิจารณาสิ่งนี้ไม่จำเป็นต้องเป็นแบบต่อต้าน แต่เป็นเพียงห้องสมุดที่ออกแบบมาไม่ดี มันควรจะเป็นเรื่องเล็กน้อยที่จะขอสตริงเป็นพารามิเตอร์ method ซึ่งอินพุตสามารถส่งผ่านโดยตรงได้

หากไม่ตรงกับการใช้งานนี้พารามิเตอร์ method อาจเป็นสตรีมโดยที่ STDIN ส่งผ่านไปยังเมธอด

หากไม่เหมาะสมกับการใช้งานนี้แสดงว่าไลบรารีไม่ยืดหยุ่นเพียงพอ


4

อาจลองพิจารณาความสามารถในไลบรารีของคุณเพื่อตั้งค่าการเรียกกลับไปยังฟังก์ชันที่ผู้ใช้ให้ซึ่งจะอ่านอินพุตจากที่ใดก็ได้จากนั้นส่งคืนค่าที่เหมาะสมกลับไปยังส่วนใด ๆ ของไลบรารีที่ใช้ฟังก์ชันนั้น


1

หากอ่านจาก stdin หมายความว่าต้องการเป็นเจ้าของระดับโปรแกรมของ stdin มันอาจเข้ากันไม่ได้กับห้องสมุดอื่น ๆ ที่อ่านจาก stdin ซึ่งเป็นโปรโตคอลที่เฉพาะเจาะจงน้อยลงสำหรับวิธีการใช้งานร่วมกัน อย่างน้อยในอภิธานศัพท์ส่วนตัวของฉันเองนี่จะทำให้ห้องสมุดเป็นกรอบซึ่งเป็นการแลกเปลี่ยนที่มีราคาแพง

แต่ในกรณีนี้ไลบรารี่ควรใช้ไฟล์อธิบายไฟล์อินพุต


0

คำตอบโดย @ Paul92 เป็นการสนทนาทั่วไปที่ดี แต่ฉันต้องการเสนอวิธีแก้ปัญหาที่สะอาด (ish) ที่เป็นไปได้ต่อไปนี้:

ไลบรารีรหัสนี้จะต้องปรับให้เข้ากับสภาพแวดล้อมรันไทม์ใด ๆ ดังนั้นคุณจึงไม่สามารถขอSTDINข้อมูลสำคัญบางอย่างได้ สำหรับผู้ใช้ไลบรารีของคุณอาจไม่สามารถใช้ 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 แต่มันอาจทำหน้าที่เป็นเกตเวย์อีเมลรอให้ข้อความปรากฏขึ้นในกล่องจดหมายอ่านอ่านแยกโทเค็นและทำให้กระบวนการโดยอัตโนมัติสมบูรณ์ อาจเป็นไดอะล็อก GUI หรือแบบฟอร์มบนเว็บ อะไรจริง ๆ - ตัวเลือกทั้งหมดอยู่ในมือของผู้บริโภคห้องสมุด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.