สำหรับพวกคุณที่โชคดีที่ไม่ได้ทำงานในภาษาที่มีขอบเขตแบบไดนามิกให้ฉันขอทบทวนเล็กน้อยเกี่ยวกับวิธีการทำงาน ลองนึกภาพภาษาเทียมที่เรียกว่า "RUBELLA" ซึ่งมีลักษณะดังนี้:
function foo() {
print(x); // not defined locally => uses whatever value `x` has in the calling context
y = "tetanus";
}
function bar() {
x = "measles";
foo();
print(y); // not defined locally, but set by the call to `foo()`
}
bar(); // prints "measles" followed by "tetanus"
นั่นคือตัวแปรแพร่กระจายขึ้นและลงสแต็กการโทรได้อย่างอิสระ - ตัวแปรทั้งหมดที่กำหนดในfoo
นั้นสามารถมองเห็นได้ (และกลายพันธุ์โดย) ผู้โทรของมันbar
และสิ่งที่ตรงกันข้ามก็เป็นจริงเช่นกัน สิ่งนี้มีความหมายอย่างร้ายแรงต่อการ refactorability ของรหัส ลองนึกภาพว่าคุณมีรหัสต่อไปนี้:
function a() { // defined in file A
x = "qux";
b();
}
function b() { // defined in file B
c();
}
function c() { // defined in file C
print(x);
}
ตอนนี้โทรไปจะพิมพ์a()
qux
แต่สักวันคุณตัดสินใจว่าคุณต้องเปลี่ยนb
นิดหน่อย คุณไม่รู้บริบทการโทรทั้งหมด (ซึ่งบางอันอาจอยู่นอก codebase ของคุณ) แต่มันก็ไม่เป็นไรการเปลี่ยนแปลงของคุณจะต้องอยู่ภายในอย่างสมบูรณ์b
ใช่มั้ย ดังนั้นคุณเขียนมันใหม่แบบนี้:
function b() {
x = "oops";
c();
}
และคุณอาจคิดว่าคุณไม่ได้เปลี่ยนแปลงอะไรเลยเนื่องจากคุณเพิ่งกำหนดตัวแปรท้องถิ่น แต่ที่จริงแล้วคุณเสียแล้วa
! ตอนนี้a
พิมพ์มากกว่าoops
qux
การนำสิ่งนี้กลับออกมาจากขอบเขตของภาษาเทียมนี่คือสิ่งที่ MUMPS ทำงานแม้ว่าจะมีไวยากรณ์ที่แตกต่างกัน
MUMPS รุ่น Modern ("modern") รวมNEW
คำสั่งที่เรียกว่าซึ่งช่วยให้คุณสามารถป้องกันตัวแปรจากการรั่วไหลของผู้โทรไปยังผู้โทร ดังนั้นในตัวอย่างแรกข้างต้นถ้าเราได้ทำNEW y = "tetanus"
ในfoo()
แล้วprint(y)
ในbar()
จะพิมพ์อะไร (ในคางทูม, ชื่อทั้งหมดชี้ไปที่สตริงว่างเว้นแต่กำหนดอย่างชัดเจนเป็นอย่างอื่น) แต่ไม่มีอะไรที่สามารถป้องกันตัวแปรจากการรั่วไหลของผู้โทรไปยังผู้ถูก: ถ้าเรามีfunction p() { NEW x = 3; q(); print(x); }
สำหรับสิ่งที่เรารู้ว่าq()
สามารถกลายพันธุ์x
แม้จะไม่ได้รับอย่างชัดเจนx
เป็นพารามิเตอร์ นี้ยังคงเป็นสถานการณ์ที่เลวร้ายที่จะอยู่ใน แต่ไม่เป็นไม่ดีเท่าที่มันอาจเคยเป็น
เมื่อทราบถึงอันตรายเหล่านี้แล้วเราจะสร้างรหัสอย่างปลอดภัยใน MUMPS หรือภาษาอื่นที่มีการกำหนดขอบเขตแบบไดนามิกได้อย่างไร
มีบางปฏิบัติที่ดีอย่างเห็นได้ชัดสำหรับการทำ refactoring ง่ายขึ้นอย่างที่ไม่เคยใช้ตัวแปรในฟังก์ชั่นอื่น ๆ ที่นอกเหนือจากที่คุณเริ่มต้น (มีNEW
หรือ) ตัวเองจะถูกส่งผ่านเป็นพารามิเตอร์ที่ชัดเจนและการจัดเก็บเอกสารอย่างชัดเจนพารามิเตอร์ใด ๆ ที่จะผ่านไปโดยปริยายจากสายที่ฟังก์ชั่นของ แต่ในทศวรรษที่ผ่านมา ~ 10 8 -LOC codebase เหล่านี้เป็นของฟุ่มเฟือยที่มักจะไม่มี
และแน่นอนว่าหลักปฏิบัติที่ดีทั้งหมดสำหรับการปรับโครงสร้างใหม่ในภาษาที่มีขอบเขตศัพท์ยังสามารถใช้ได้ในภาษาที่มีขอบเขตแบบไดนามิก - การทดสอบการเขียนและอื่น ๆ จากนั้นคำถามก็คือสิ่งนี้: เราจะลดความเสี่ยงที่เกี่ยวข้องโดยเฉพาะกับความเปราะบางที่เพิ่มขึ้นของโค้ดที่กำหนดขอบเขตแบบไดนามิกเมื่อทำการปรับโครงสร้างใหม่ได้อย่างไร?
(โปรดทราบว่าในขณะที่คุณนำทางและ refactor รหัสที่เขียนในภาษาแบบไดนามิกได้อย่างไรมีชื่อที่คล้ายกันกับคำถามนี้มันไม่เกี่ยวข้องทั้งหมด)