Monkey Patching ในภาษาการเขียนโปรแกรมแบบไดนามิก: ตัวอย่าง JavaScript

จาวาสคริปต์
การเขียนโปรแกรมไดนามิก
Monkey Patching ในภาษาการเขียนโปรแกรมแบบไดนามิก cover image

การแนะนำ

บทความนี้จะสำรวจแนวคิดของภาษาการเขียนโปรแกรมแบบไดนามิกและแบบคงที่ ความแตกต่างหลักระหว่างทั้งสอง และสิ่งที่แต่ละกระบวนทัศน์ให้ในแง่ของข้อดีและข้อผิดพลาด การสำรวจนี้จะเน้นเพิ่มเติมที่ภาษาการเขียนโปรแกรมแบบไดนามิก โดยเฉพาะอย่างยิ่งหนึ่งในรูปแบบที่จำเป็นที่เปิดใช้งาน: Monkey Patch รูปแบบนี้จะถูกจัดแสดงด้วยความช่วยเหลือของตัวอย่างใน JavaScript

ภาษาการเขียนโปรแกรมแบบไดนามิกและแบบคงที่

คำศัพท์

เพื่อทำความเข้าใจว่าอะไรคือภาษาไดนามิกหรือภาษาคงที่ เราจำเป็นต้องสร้างความเข้าใจเกี่ยวกับคำศัพท์สำคัญสองสามคำที่ใช้กันทั่วไปในบริบทนี้: เวลาคอมไพล์ รันไทม์ และ *การตรวจสอบประเภท *.

การคอมไพล์และรันไทม์เป็นคำสองคำที่สอดคล้องกับขั้นตอนต่างๆ ในวงจรชีวิตของโปรแกรมคอมพิวเตอร์ โดยเริ่มจากเวลาคอมไพล์

เวลาเรียบเรียง

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

รันไทม์

โดยปกติรันไทม์สรุปสองขั้นตอน: การโหลดโปรแกรมลงในหน่วยความจำโดยการจัดสรรทรัพยากรที่จำเป็นสำหรับการดำเนินการพร้อมกับคำสั่ง จากนั้นจึงรันโปรแกรมตามลำดับของคำสั่งเหล่านั้น

แผนภาพต่อไปนี้แสดงให้เห็นถึงกระบวนการนี้:

กำลังตรวจสอบประเภท

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

ตอนนี้เรามีความเข้าใจในระดับสูงเกี่ยวกับวงจรชีวิตของโปรแกรมและการตรวจสอบประเภทของโปรแกรมแล้ว เราก็สามารถสำรวจภาษาการเขียนโปรแกรมแบบคงที่ต่อไปได้

ภาษาการเขียนโปรแกรมแบบคงที่

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

ภาษาการเขียนโปรแกรมแบบไดนามิก

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

แพทช์ลิง

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

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

Monkey Patch หมายถึงกระบวนการขยาย/เปลี่ยนแปลงการทำงานของส่วนประกอบในขณะรันไทม์ ส่วนประกอบที่เป็นปัญหาอาจเป็นไลบรารี คลาส วิธีการ หรือแม้แต่โมดูล แนวคิดก็เหมือนกัน: มีการสร้างโค้ดขึ้นมาเพื่อทำงานบางอย่างให้สำเร็จ และเป้าหมายของการแพตช์ลิงคือการเปลี่ยนแปลงหรือขยายพฤติกรรมของโค้ดนั้นเพื่อให้งานใหม่สำเร็จ ทั้งหมดนี้โดยไม่ต้องเปลี่ยนโค้ดเอง .

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

ตัวอย่างต่อไปนี้จะแสดงกรณีการใช้งานทั่วไปที่สามารถได้รับประโยชน์จากการใช้เทคนิค Monkey Patch Javascript ถูกใช้เพื่อการนำไปใช้ที่นี่ แต่ยังคงควรนำไปใช้กับภาษาการเขียนโปรแกรมไดนามิกอื่นๆ ในวงกว้าง

ตัวอย่าง

ใช้กรอบการทดสอบขั้นต่ำกับโมดูล HTTP ดั้งเดิมของโหนด

การทดสอบหน่วยและการรวมระบบอาจตกอยู่ภายใต้กรณีการใช้งานของ Monkey patching โดยปกติแล้วจะเกี่ยวข้องกับกรณีทดสอบที่ครอบคลุมมากกว่าหนึ่งบริการสำหรับการทดสอบการรวม หรือการพึ่งพา API และ/หรือฐานข้อมูลสำหรับการทดสอบหน่วย ในทั้งสองสถานการณ์นี้ และเพื่อที่จะบรรลุเป้าหมายของการทดสอบตั้งแต่แรก เราต้องการให้การทดสอบของเราเป็นอิสระจากทรัพยากรภายนอกเหล่านี้ วิธีที่จะบรรลุสิ่งนี้คือการเยาะเย้ย การเยาะเย้ยเป็นการจำลองพฤติกรรมของบริการภายนอก ดังนั้นการทดสอบจึงสามารถมุ่งเน้นไปที่ตรรกะที่แท้จริงของโค้ดได้ Monkey patching สามารถมีประโยชน์ได้ที่นี่ เนื่องจากสามารถปรับเปลี่ยนวิธีการของบริการภายนอกได้โดยการแทนที่ด้วยวิธีตัวยึดตำแหน่งที่เราเรียกว่า “stub” วิธีการเหล่านี้จะคืนผลลัพธ์ที่คาดหวังในกรณีทดสอบ เพื่อให้เราสามารถหลีกเลี่ยงการส่งคำขอไปยังบริการการผลิตเพียงเพื่อการทดสอบเท่านั้น

ตัวอย่างต่อไปนี้คือการใช้งาน Monkey patching อย่างง่ายบนโมดูล http ดั้งเดิมของ NodeJs โมดูล http เป็นอินเทอร์เฟซที่ใช้วิธีการโปรโตคอล http สำหรับ NodeJs ส่วนใหญ่จะใช้เพื่อสร้างเซิร์ฟเวอร์ http แบร์โบนและสื่อสารกับบริการภายนอกโดยใช้โปรโตคอล http

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

วิธีนี้ทำให้เราสามารถนำฟังก์ชันต่างๆ ของเราไปใช้ และเขียนการทดสอบสำหรับแต่ละฟังก์ชัน ในขณะเดียวกันก็รับประกันความปลอดภัยของบริการด้านการผลิตของเรา

// import the http module
let http = require("http");

// patch the get method of the http module
http.get = async function(url) {
  return {
    data: ["1234", "1235", "1236", "1236"]
  };
}

// example test suite, call new patched get method for testing
test('get array of user ids from users api', async () => {
  const res = await http.get("https://users.api.com/ids");
  const userIds = res.data;
  expect(userIds).toBeDefined();
  expect(userIds.length).toBe(4);
  expect(userIds[0]).toBe("1234");
});

โค้ดด้านบนนั้นตรงไปตรงมา เรานำเข้าโมดูล http แล้วกำหนดวิธี http.get ใหม่ด้วยวิธีใหม่ที่เพิ่งส่งคืนอาร์เรย์ของ id ตอนนี้เราเรียกเมธอด patched ใหม่ภายใน test case และเราได้รับผลลัพธ์ใหม่ที่คาดหวัง

~/SphericalTartWorker$ npm test

> nodejs@1.0.0 test
> jest

PASS  ./index.test.js
  ✓ get array of user ids from users api (25 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.977 s, estimated 2 s
Ran all test suites.

ข้อผิดพลาดและข้อจำกัดทั่วไป

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

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

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

บทสรุป

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


Career Services background pattern

บริการด้านอาชีพ

Contact Section background image

มาติดต่อกันกันเถอะ

Code Labs Academy © 2024 สงวนลิขสิทธิ์.