Monkey Patching у мовах динамічного програмування: приклад JavaScript

Javascript
динамічне програмування
Monkey Patching у мовах динамічного програмування cover image

Вступ

У цій статті розглядатимуться поняття динамічної та статичної мов програмування, основні відмінності між ними та переваги та недоліки кожної парадигми. Це дослідження буде далі зосереджено на динамічних мовах програмування, зокрема на одному з основних шаблонів, які вони ввімкнуть: Monkey Patch, цей шаблон буде продемонстровано за допомогою прикладу в JavaScript.

Динамічні та статичні мови програмування

Термінологія

Щоб зрозуміти, що таке динамічна або статична мова, нам потрібно зрозуміти кілька ключових термінів, які зазвичай використовуються в цьому контексті: Час компіляції, Виконання та *Перевірка типу *.

Компіляція та час виконання — це два терміни, які відповідають різним етапам життєвого циклу комп’ютерної програми, починаючи з часу компіляції.

Час компіляції

Час компіляції - це перший крок у життєвому циклі програми. Розробник пише код певною мовою програмування. Найчастіше машина не може зрозуміти код, написаний на мові високого рівня, тому спеціальний компілятор використовується для перекладу його в проміжний формат нижчого рівня, який стає готовим до виконання.

Час виконання

Середа виконання зазвичай інкапсулює два етапи: завантаження програми в пам’ять шляхом виділення ресурсів, необхідних для її виконання разом із її інструкціями, а потім виконання програми, дотримуючись порядку цих інструкцій.

Наступна діаграма ілюструє цей процес:

Перевірка типу

Перевірка типів є вбудованою функцією майже всіх мов програмування. Це можливість перевірити, чи значення, присвоєне даній змінній, відповідає правильному типу цієї змінної. Кожна мова програмування має свій спосіб представлення значення певного типу в пам’яті. Ці різні представлення дають змогу перевірити відповідність між типом значення та типом змінної, якій ви намагаєтесь призначити це значення.

Тепер, коли ми маємо глибоке розуміння життєвого циклу програми та перевірки типів, ми можемо перейти до вивчення статичних мов програмування.

Статичні мови програмування

Статичні мови програмування, які також називають статично типізованими мовами, — це мови, які застосовують перевірку типу, про яку ми згадували на етапі компіляції. Фактично це означає, що змінна зберігає свій тип із оголошення, і їй не можна призначити жодне значення, окрім значень із її типу оголошення. Статичні мови програмування забезпечують додаткову безпеку при роботі з типами, але можуть уповільнити процес розробки в певних випадках використання, коли це стає суворим обмеженням.

Мови динамічного програмування

Динамічні мови програмування, з іншого боку, застосовують перевірку типу під час виконання. Це означає, що будь-яка змінна може містити будь-яке значення в будь-якій точці програми. Це може бути корисним, оскільки пропонує рівень гнучкості для розробника, якого немає в статичних мовах. Динамічні мови, як правило, повільніші при виконанні, ніж їхні статичні аналоги, оскільки вони включають додатковий крок динамічного визначення типу кожної змінної.

Мавпячий патч

Статична проти динамічної типізації є фундаментальною властивістю мови програмування, якщо використовувати одну парадигму над іншою, можна використовувати безліч різних шаблонів і практик, які можуть значно покращити якість і швидкість розробки. Це також може відкрити двері для багатьох обмежень і антишаблонів, якщо під час прийняття дизайнерських рішень не врахувати ретельних міркувань.

Зокрема, відомо, що мови програмування з динамічними типами пропонують вищий рівень гнучкості, оскільки вони не обмежують змінну одним типом. Ця гнучкість пов’язана з додатковою відповідальністю розробника під час впровадження та налагодження програм, щоб переконатися, що не відбувається непередбачуваної поведінки. Візерунок «мавпяча нашивка» походить від цієї філософії.

Monkey Patch стосується процесу розширення/зміни роботи компонента під час виконання. Компонент, про який йде мова, може бути бібліотекою, класом, методом або навіть модулем. Ідея та сама: частина коду створюється для виконання певного завдання, і мета monkey patching полягає в тому, щоб змінити або розширити поведінку цієї частини коду, щоб вона виконувала нове завдання, і все це без зміни самого коду. .

Це стало можливим у динамічній мові програмування, оскільки незалежно від того, з яким типом компонента ми маємо справу, він все одно має ту саму структуру об’єкта з різними атрибутами, атрибути можуть містити методи, які можна перепризначити для досягнення нової поведінки об’єкта. не вдаючись у його внутрішні особливості та деталі реалізації. Це стає особливо корисним у випадку сторонніх бібліотек і модулів, оскільки їх, як правило, важче налаштувати.

У наступному прикладі буде продемонстровано звичайний випадок використання, який може виграти від використання техніки monkey patch. Для реалізації тут було використано Javascript, але це все одно має широко застосовуватися до будь-якої іншої мови динамічного програмування.

Приклад

Реалізуйте мінімальну структуру тестування за допомогою рідного HTTP-модуля Node

Модульне та інтеграційне тестування може підпадати під випадки використання Monkey patching. Зазвичай вони включають тестові випадки, які охоплюють кілька служб для інтеграційного тестування, або залежності API та/або бази даних для модульного тестування. У цих двох сценаріях і для досягнення цілей тестування в першу чергу ми хотіли б, щоб наші тести були незалежними від цих зовнішніх ресурсів. Спосіб домогтися цього — насмішка. Мокінг — це імітація поведінки зовнішніх служб, щоб тест міг зосередитися на фактичній логіці коду. Monkey patching тут може бути корисним, оскільки він може змінювати методи зовнішніх служб, замінюючи їх методами-заповнювачами, які ми називаємо «заглушками». Ці методи повертають очікуваний результат у випадках тестування, щоб ми могли уникнути ініціювання запитів до виробничих служб лише заради тестів.

Наступний приклад є простою реалізацією виправлення Monkey на рідному http-модулі NodeJ. Модуль http — це інтерфейс, який реалізує методи протоколу http для NodeJ. Він в основному використовується для створення barebone 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 новим методом, який просто повертає масив ідентифікаторів. Тепер ми викликаємо новий виправлений метод у тестовому прикладі та отримуємо новий очікуваний результат.

~/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 Всі права захищені.