ฉันควร refactor ฟังก์ชั่นขนาดใหญ่ที่ส่วนใหญ่ประกอบด้วย regex หนึ่งหรือไม่ [ปิด]


15

ฉันเพิ่งเขียนฟังก์ชันที่ครอบคลุมประมาณ 100 บรรทัด ได้ยินว่าคุณอาจถูกล่อลวงให้บอกฉันเกี่ยวกับความรับผิดชอบเดี่ยวและกระตุ้นให้ฉันไปปรับโครงสร้าง นี่คือสัญชาตญาณของฉันเช่นกัน แต่นี่คือปัญหา: ฟังก์ชันทำสิ่งหนึ่ง มันดำเนินการจัดการสตริงที่ซับซ้อนและร่างกายฟังก์ชั่นประกอบด้วยส่วนใหญ่ของหนึ่ง verbose regex แยกออกเป็นหลายบรรทัดที่มีเอกสาร ถ้าฉันแยก regex ออกเป็นหลาย ๆ ฟังก์ชั่นฉันรู้สึกว่าฉันจะสูญเสียความสามารถในการอ่านได้เนื่องจากฉันเปลี่ยนภาษาได้อย่างมีประสิทธิภาพและจะไม่สามารถใช้ประโยชน์จากคุณสมบัติบางอย่างของ regex นี่คือคำถามของฉัน:

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


3
ฉันไม่คิดว่ามีอะไรผิดปกติอะไรกับการทำงานของคุณพิจารณาว่าส่วนใหญ่ของมันเป็นเอกสาร อาจมีปัญหาการบำรุงรักษาด้วยการใช้การแสดงออกปกติขนาดใหญ่ในสถานที่แรกอย่างไรก็ตาม
Joel Cornett

2
คุณแน่ใจหรือไม่ว่า regex ยักษ์เป็นทางออกที่ดีที่สุดสำหรับปัญหาของคุณ? คุณคิดว่าเป็นทางเลือกที่ง่ายกว่าเช่นไลบรารี parser หรือเปลี่ยนรูปแบบไฟล์ที่กำหนดเองด้วยรูปแบบมาตรฐาน (XML, JSON และอื่น ๆ ) หรือไม่?
lortabac

2
มีฟังก์ชั่นอื่น ๆ หรือไม่โดยใช้รุ่นที่แก้ไข / ปรับปรุง / ง่ายของ regex นี้ นั่นจะเป็นตัวบ่งชี้ที่สำคัญที่ควรมีการปรับโครงสร้างใหม่ ถ้าไม่ฉันก็ปล่อยไว้เหมือนเดิม ต้องการการจัดการสตริงที่ซับซ้อนเช่นนั้นเป็นธงสีเหลืองในสิทธิของตนเอง (ดีฉันไม่ทราบบริบทดังนั้นเพียงแค่สีเหลือง) และ refactoring ฟังก์ชั่นลงดูเหมือนว่าฉันเหมือนพิธีกรรมเพื่อไถ่ถอนจากความรู้สึกผิดเกี่ยวกับ มัน;)
Konrad Morawski

8
regexp 100 บรรทัดจะทำสิ่งเดียวได้อย่างไร
Pieter B

@lortabac: ข้อความที่ป้อนเป็นข้อความที่ผู้ใช้สร้างขึ้น (ร้อยแก้ว)
DudeOnRock

คำตอบ:


36

สิ่งที่คุณกำลังเผชิญคือความไม่ลงรอยกันของความรู้ความเข้าใจที่มาจากการฟังคนที่ชื่นชอบการยึดมั่นในแนวทางการปฏิบัติภายใต้แนวทาง "แนวทางปฏิบัติที่ดีที่สุด" ภายใต้หน้ากากของการตัดสินใจอย่างมีเหตุผล

คุณทำการบ้านอย่างชัดเจนแล้ว:

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

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

โหวตครั้งที่สองมาจากการดูตัวเลือกของคุณและสิ่งที่คุณได้รับ (และแพ้) จากแต่ละครั้ง:

  • ปรับปรุงโครงสร้าง. สิ่งนี้ทำให้คุณได้รับการปฏิบัติตามความคิดของใครบางคนว่าควรจะมีฟังก์ชั่นนานเท่าไรและเสียสละความสามารถในการอ่าน
  • ไม่ทำอะไร. สิ่งนี้จะรักษาความสามารถในการอ่านและการเสียสละที่มีอยู่ให้สอดคล้องกับความคิดของใครบางคนว่าควรใช้ฟังก์ชันนานแค่ไหน

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

บรรทัดล่าง: ถ้ามันไม่ได้หักอย่าแก้ไข


10
+1 สำหรับ "หากยังไม่พังอย่าแก้ไข"
Giorgio

จริง กฎแซนดี้เมตซ์ ( gist.github.com/henrik/4509394 ) เป็นสิ่งที่ดีและดี แต่ที่youtube.com/watch?v=VO-NvnZfMA4#t=1379เธอพูดถึงว่าทำไมพวกเขาถึงเป็นเช่นนั้นและทำไมผู้คนถึงพากันมา พวกเขาอย่างจริงจังเกินไป
Amadan

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

19

สุจริตฟังก์ชั่นของคุณอาจ "ทำสิ่งหนึ่ง" แต่ตามที่คุณระบุด้วยตัวเอง

ฉันสามารถเริ่มแบ่ง regex ออกเป็นหลาย ๆ ฟังก์ชันได้

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

แต่รู้สึกว่าฉันจะสูญเสียความสามารถในการอ่านได้จริงเนื่องจากฉันเปลี่ยนภาษาได้อย่างมีประสิทธิภาพ

และนี่คือจุดหลัก - คุณมีชิ้นส่วนของโค้ดที่เขียนในภาษาอดีต reg ภาษานี้ไม่ได้ให้วิธีการที่ดีในการกำหนดเอง (และฉันไม่คิดว่า "การจับภาพกลุ่มชื่อ" เพื่อทดแทนฟังก์ชั่น) ดังนั้นการ refactoring "ในภาษา reg ex" จึงเป็นไปไม่ได้จริง ๆ และการผสมผสาน exps reg ที่เล็กลงกับภาษาโฮสต์อาจไม่สามารถปรับปรุงการอ่านได้ (อย่างน้อยคุณก็รู้สึกเช่นนั้น แต่คุณมีข้อสงสัยมิฉะนั้นคุณจะไม่ได้โพสต์คำถาม) . ดังนั้นนี่คือคำแนะนำของฉัน

  • แสดงรหัสของคุณต่อผู้พัฒนาขั้นสูงอื่น ๆ (อาจจะเป็น/codereview// ) เพื่อให้แน่ใจว่าคนอื่น ๆ คิดว่าการอ่านง่ายเหมือนที่คุณทำ เปิดรับแนวคิดที่คนอื่นอาจไม่พบ 100 reg reg exp เท่าที่อ่านได้เช่นเดียวกับคุณ บางครั้งความคิดของ "มันไม่แตกง่ายเป็นชิ้นเล็ก ๆ " สามารถเอาชนะได้ด้วยตาที่สอง

  • สังเกตการเปลี่ยนแปลงที่เกิดขึ้นจริง - ประสบการณ์อันน่าทึ่งของคุณยังคงดูดีอยู่เสมอเมื่อมีข้อกำหนดใหม่เข้ามาและคุณต้องนำไปใช้และทดสอบมัน? ตราบใดที่ประสบการณ์การทำงานของคุณฉันจะไม่แตะต้องมัน แต่เมื่อใดก็ตามที่มีการเปลี่ยนแปลงฉันจะพิจารณาอีกครั้งว่ามันเป็นความคิดที่ดีจริงๆที่จะให้ทุกคนเข้ามาในบล็อกขนาดใหญ่นี้ - และ (จริงจัง!) ชิ้นเล็ก ๆ จะไม่เป็นตัวเลือกที่ดีกว่า

  • สังเกตการบำรุงรักษา - คุณสามารถ debug exp อย่างมีประสิทธิภาพในรูปแบบปัจจุบันได้เป็นอย่างดีหรือไม่? โดยเฉพาะอย่างยิ่งหลังจากที่คุณต้องเปลี่ยนอะไรบางอย่างและตอนนี้การทดสอบของคุณบอกคุณว่ามีอะไรผิดปกติคุณมีดีบักเกอร์ exp exp ช่วยให้คุณค้นหาสาเหตุที่แท้จริงหรือไม่ หากการดีบักยากขึ้นนั่นอาจเป็นโอกาสที่จะพิจารณาการออกแบบของคุณอีกครั้ง


ฉันจะบอกว่าชื่อกลุ่มการดักจับ (โดยทั่วไปแล้วกลุ่มการจับ) จริงๆจะคล้ายกับตัวแปรสุดท้าย / เขียนครั้งเดียวหรืออาจเป็นมาโคร มันช่วยให้คุณสามารถอ้างอิงส่วนที่เฉพาะเจาะจงของการแข่งขันไม่ว่าจะเป็นจากวัตถุที่จับคู่ส่งคืนจากหน่วยประมวลผล regex หรือในภายหลังในการแสดงออกปกติ
JAB

4

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

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

ครบรหัสการทำงานที่เป็นง่ายๆที่คุณสามารถมีเหตุผลที่ทำให้มันเป็นเป้าหมาย

อย่าเปลี่ยนเพียงเพราะความยาว


3

คุณสามารถแยก regex ออกเป็น sub-regexes และค่อยๆเขียนนิพจน์สุดท้าย วิธีนี้จะช่วยให้เกิดความเข้าใจในรูปแบบที่มีขนาดใหญ่มากโดยเฉพาะถ้ารูปแบบย่อยซ้ำหลายครั้ง ตัวอย่างเช่นใน Perl;

my $start_re = qr/(?:\w+\.\w+)/;
my $middle_re = qr/(?:DOG)|(?:CAT)/;
my $end_re = qr/ => \d+/;

my $final_re = $start_re . $middle_re . $end_re;
# or: 
# my $final_re = qr/${start_re}${middle_re}${end_re}/

ฉันใช้ธง verbose ซึ่งสะดวกกว่าสิ่งที่คุณแนะนำ
DudeOnRock

1

ฉันจะบอกว่าแตกถ้ามันเปราะบาง จากจุดการบำรุงรักษาในมุมมองและความสามารถในการ resuability มันสมเหตุสมผลที่จะทำลายมัน แต่แน่นอนว่าคุณต้องคำนึงถึงธรรมชาติของหน้าที่การใช้งานของคุณและวิธีรับอินพุตและสิ่งที่จะกลับมา

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

นอกจากนี้ฉันสามารถแบ่งแต่ละส่วนหลักออกเป็นฟังก์ชั่นที่เล็กลงและเจาะจงมากขึ้นในตอนท้ายฉันมี 5 ฟังก์ชั่นที่แตกต่างกันในการทำสิ่งทั้งหมดและฉันสามารถนำฟังก์ชั่นบางอย่างมาใช้ใหม่ได้


1

สิ่งหนึ่งที่คุณอาจพิจารณาหรือไม่ได้พิจารณาคือการเขียนโปรแกรมแยกวิเคราะห์ขนาดเล็กในภาษาที่คุณใช้แทนการใช้ regex ในภาษานั้น การอ่านทดสอบและบำรุงรักษาอาจทำได้ง่ายกว่า


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

1
หาก regex สามารถแยกมันคุณสามารถแยกมัน คำตอบของคุณทำให้ฉันดูเหมือนว่าคุณอาจไม่คุ้นเคยกับการแยกวิเคราะห์ หากเป็นกรณีนี้คุณอาจต้องการติดกับ regex ไม่ว่าจะเป็นหรือเรียนรู้ทักษะใหม่
Thomas Eding

ฉันชอบที่จะเรียนรู้ทักษะใหม่ แหล่งข้อมูลที่ดีที่คุณสามารถแนะนำได้? ฉันสนใจในทฤษฎีที่อยู่เบื้องหลังมันเช่นกัน
DudeOnRock

1

ยักษ์ใหญ่เป็นทางเลือกที่ดีในกรณีส่วนใหญ่ จากประสบการณ์ของฉันพวกเขามักจะใช้เพราะนักพัฒนาไม่คุ้นเคยกับการแยกวิเคราะห์ (ดูคำตอบของ Thomas Eding )

อย่างไรก็ตามสมมติว่าคุณต้องการติดกับโซลูชันที่ใช้ regex

เนื่องจากฉันไม่ทราบรหัสจริงฉันจะตรวจสอบสถานการณ์ที่เป็นไปได้สองแบบ:

  • regex นั้นง่าย (มีการจับคู่ตามตัวอักษรและทางเลือกน้อยมาก)

    ในกรณีนี้คุณสมบัติขั้นสูงที่นำเสนอโดย regex เดียวจะไม่ขาดไม่ได้ ซึ่งหมายความว่าคุณจะได้รับประโยชน์จากการแยกมัน

  • regex นั้นซับซ้อน (มีตัวเลือกมากมาย)

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

ฉันอาจขาดจินตนาการ แต่ฉันไม่สามารถนึกถึงสถานการณ์ในโลกแห่งความจริงที่ซึ่ง regex 100 บรรทัดเป็นทางออกที่ดี

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