Monkey Patching sa Dynamic Programming Languages: Isang Halimbawa ng JavaScript

Javascript
Dynamic na Programming
Monkey Patching sa Dynamic Programming Languages cover image

Panimula

Tuklasin ng artikulong ito ang mga konsepto ng Dynamic at Static na mga programming language, ang mga pangunahing pagkakaiba sa pagitan ng dalawa, at kung ano ang ibinibigay ng bawat paradigm sa mga tuntunin ng mga pakinabang at pitfalls. Ang paggalugad na ito ay higit na tututuon sa mga dynamic na programming language, partikular na ang isa sa mga mahahalagang pattern na pinapagana nito: Monkey Patch, ang pattern na ito ay ipapakita sa tulong ng isang halimbawa sa JavaScript.

Dynamic vs Static Programming Languages

Terminolohiya

Upang maunawaan kung ano ang bumubuo sa isang dynamic na wika o isang static na wika, kailangan naming magtatag ng pag-unawa sa ilang mahahalagang termino na karaniwang ginagamit sa kontekstong ito: Compile time, Runtime, at *Type checking *.

Ang Compile at Runtime ay dalawang termino na tumutugma sa iba't ibang yugto sa lifecycle ng isang computer program, simula sa oras ng Compile.

Oras ng Compile

Ang oras ng pag-compile ay ang unang hakbang sa lifecycle ng isang programa. Ang isang developer ay nagsusulat ng code sa isang partikular na programming language. Mas madalas kaysa sa hindi, hindi naiintindihan ng makina ang code na nakasulat sa isang mataas na antas ng wika kaya ang isang nakatuong compiler ay ginagamit upang isalin ito sa isang mas mababang antas na intermediate na format na magiging handa para sa pagpapatupad.

Runtime

Ang runtime ay karaniwang nagsasama ng dalawang hakbang: ang paglo-load ng program sa memorya sa pamamagitan ng paglalaan ng mga mapagkukunang kailangan para sa pagpapatupad nito kasama ang mga tagubilin nito, at pagkatapos ay isagawa ang programa na sumusunod sa pagkakasunud-sunod ng mga tagubiling iyon.

Ang sumusunod na diagram ay naglalarawan ng prosesong ito:

Pagsusuri ng Uri

Ang type-checking ay isang built-in na feature sa halos lahat ng programming language. Ito ay ang kakayahang suriin kung ang isang halaga na itinalaga sa isang naibigay na variable ay tumutugma sa tamang uri ng variable na iyon. Ang bawat programming language ay may iba't ibang paraan upang kumatawan sa isang halaga ng isang naibigay na uri sa memorya. Ginagawang posible ng iba't ibang representasyong ito na suriin ang mga sulat sa pagitan ng uri ng isang halaga at sa uri ng isang variable na sinusubukan mong italaga sa halagang iyon.

Ngayon na mayroon na tayong mataas na antas ng pag-unawa sa isang lifecycle ng programa at pagsuri ng uri, maaari na tayong magpatuloy upang galugarin ang mga static na programming language.

Static Programming Language

Ang Static Programming Languages, na tinutukoy din bilang mga statically typed na wika ay mga wikang naglalapat ng type checking na binanggit namin sa compile phase. Ito ay epektibong nangangahulugan na pinapanatili ng isang variable ang uri nito mula sa deklarasyon at walang halaga ang maaaring italaga dito maliban sa mga halaga mula sa uri ng deklarasyon nito. Ang mga static na programming language ay nag-aalok ng karagdagang kaligtasan kapag nakikitungo sa mga uri ngunit maaaring makapagpabagal sa proseso ng pag-develop sa ilang partikular na mga kaso ng paggamit kapag ito ay naging isang mahigpit na paghihigpit.

Mga Dynamic na Wika sa Programming

Ang mga dynamic na programming language, sa kabilang banda, ay naglalapat ng type-checking sa runtime. Nangangahulugan ito na ang anumang variable ay maaaring magkaroon ng anumang halaga sa anumang punto sa programa. Maaari itong maging kapaki-pakinabang dahil nag-aalok ito ng antas ng flexibility sa developer na wala sa mga static na wika. Ang mga dynamic na wika ay malamang na mas mabagal sa pagpapatupad kaysa sa kanilang mga static na katapat dahil nagsasangkot sila ng karagdagang hakbang ng dynamic na pag-uunawa sa pagta-type ng bawat variable.

Monkey Patch

Ang Static vs Dynamic na Pag-type ay isang pangunahing katangian sa isang programming language, ang pagsama sa isang paradigm sa kabila ay maaaring paganahin ang isang host ng iba't ibang mga pattern at kasanayan na maaaring makabuluhang mapabuti ang kalidad at ang bilis ng pag-unlad. Maaari rin itong magbukas ng pinto para sa maraming limitasyon at anti-pattern kung walang maingat na pagsasaalang-alang na ibibigay kapag gumagawa ng mga desisyon sa disenyo.

Lalo na, ang mga dynamic na na-type na programming language ay kilala na nag-aalok ng mas mataas na antas ng flexibility dahil hindi nila nililimitahan ang isang variable sa isang uri. Ang kakayahang umangkop na ito ay kasama ng karagdagang pananagutan sa developer kapag nagpapatupad at nagde-debug ng mga programa upang matiyak na walang mga hindi inaasahang pag-uugali na nagaganap. Ang pattern ng monkey patch ay nagmula sa pilosopiyang ito.

Ang Monkey Patch ay tumutukoy sa proseso ng pagpapalawak/pagbabago sa mga gumagana ng isang bahagi sa runtime. Ang bahaging pinag-uusapan ay maaaring isang aklatan, isang klase, isang pamamaraan, o kahit isang module. Ang ideya ay pareho: ang isang piraso ng code ay ginawa upang magawa ang isang tiyak na gawain, at ang layunin ng pag-patch ng unggoy ay upang baguhin o pahabain ang pag-uugali ng piraso ng code na iyon upang magawa nito ang isang bagong gawain, lahat nang hindi binabago ang code mismo .

Ito ay ginawang posible sa dynamic na programming language dahil kahit anong uri ng bahagi ang ating kinakaharap, mayroon pa rin itong parehong istraktura ng isang bagay na may iba't ibang mga katangian, ang mga katangian ay maaaring magkaroon ng mga pamamaraan na maaaring muling italaga upang makamit ang isang bagong pag-uugali sa bagay. nang hindi pumasok sa mga panloob nito at mga detalye ng pagpapatupad. Ito ay nagiging partikular na kapaki-pakinabang sa kaso ng mga third party na aklatan at mga module dahil malamang na mas mahirap i-tweak ang mga iyon.

Ang sumusunod na halimbawa ay magpapakita ng isang karaniwang kaso ng paggamit na maaaring makinabang mula sa paggamit ng monkey patch technique. Ginamit ang Javascript para sa kapakanan ng pagpapatupad dito ngunit dapat pa rin itong malawak na naaangkop sa anumang iba pang dynamic na programming language.

Halimbawa

Magpatupad ng Minimal Testing Framework gamit ang Native HTTP Module ng Node

Ang pagsubok sa unit at integration ay maaaring nasa ilalim ng mga kaso ng paggamit ng Monkey patching. Karaniwang kinasasangkutan ng mga ito ang mga kaso ng pagsubok na sumasaklaw sa higit sa isang serbisyo para sa integration testing, o API at/o database dependencies para sa unit testing. Sa dalawang senaryo na ito, at upang maisakatuparan ang mga layunin ng pagsubok sa unang lugar, nais naming maging independyente ang aming mga pagsubok sa mga panlabas na mapagkukunang ito. Ang paraan para makamit ito ay sa pamamagitan ng pangungutya. Ang panunuya ay ginagaya ang gawi ng mga panlabas na serbisyo upang ang pagsubok ay makakatuon sa aktwal na lohika ng code. Maaaring makatulong ang patching ng unggoy dito dahil maaari nitong baguhin ang mga pamamaraan ng mga panlabas na serbisyo sa pamamagitan ng pagpapalit sa mga ito ng mga paraan ng placeholder na tinatawag nating "stub". Ibinabalik ng mga pamamaraang ito ang inaasahang resulta sa mga kaso ng pagsubok upang maiwasan natin ang pagsisimula ng mga kahilingan sa mga serbisyo sa produksyon para lang sa mga pagsubok.

Ang sumusunod na halimbawa ay isang simpleng pagpapatupad ng Monkey patching sa native http module ng NodeJs. Ang http module ay ang interface na nagpapatupad ng mga pamamaraan ng http protocol para sa mga NodeJ. Pangunahing ginagamit ito upang lumikha ng mga barebone na http server at makipag-ugnayan sa mga panlabas na serbisyo gamit ang http protocol.

Sa halimbawa sa ibaba mayroon kaming isang simpleng kaso ng pagsubok kung saan tumawag kami ng isang panlabas na serbisyo upang kunin ang listahan ng mga user id. Sa halip na tawagan ang aktwal na serbisyo ay tina-patch namin ang paraan ng http get kaya ibinabalik lamang nito ang inaasahang resulta na isang hanay ng mga random na user id. Maaaring hindi ito masyadong mahalaga dahil kumukuha lang kami ng data ngunit kung magpapatupad kami ng isa pang kaso ng pagsubok na kinasasangkutan ng pagbabago ng ilang uri ng data, maaari naming aksidenteng mabago ang data sa produksyon kapag nagpapatakbo ng mga pagsubok.

Sa ganitong paraan maipapatupad namin ang aming mga functionality, at magsulat ng mga pagsubok para sa bawat functionality habang tinitiyak ang kaligtasan ng aming mga serbisyo sa produksyon.

// 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");
});

Ang code sa itaas ay diretso, ini-import namin ang http module, muling italaga ang http.get na paraan gamit ang isang bagong paraan na nagbabalik lamang ng hanay ng mga id. Ngayon ay tinatawag namin ang bagong naka-patch na paraan sa loob ng test case at nakuha namin ang bagong inaasahang resulta.

~/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.

Mga Karaniwang Pitfalls at Limitasyon

Hindi na dapat ikagulat na ang paglalagay ng unggoy ay may sariling mga depekto at limitasyon. Sa konteksto ng mga module sa node module system, ang pag-patch ng isang pandaigdigang module tulad ng http ay itinuturing na isang operasyon na may mga side effect, ito ay dahil ang http ay naa-access mula sa anumang punto sa loob ng codebase at anumang ibang entity ay maaaring magkaroon ng dependency dito. Inaasahan ng mga entity na ito na gagana ang http module sa karaniwan nitong gawi, sa pamamagitan ng pagpapalit ng isa sa mga pamamaraan ng http na epektibo nating sinisira ang lahat ng iba pang mga dependency ng http sa loob ng codebase.

Dahil kami ay tumatakbo sa loob ng isang dynamic na na-type na wika, ang mga bagay ay maaaring hindi agad mabigo at mas gugustuhin na mag-default sa isang hindi mahuhulaan na gawi na ginagawang ang pag-debug ay isang napakasalimuot na gawain. Sa iba pang mga kaso ng paggamit, maaaring mayroong dalawang magkaibang mga patch ng parehong bahagi sa parehong katangian, kung saan hindi namin mahuhulaan kung aling patch ang mauuna kaysa sa iba na magreresulta sa isang mas hindi mahulaan na code.

Mahalaga rin na banggitin na ang pag-patch ng unggoy ay maaaring may kaunting pagkakaiba-iba sa pag-uugali sa pagitan ng iba't ibang mga programming language. Ang lahat ay nakasalalay sa disenyo ng wika at mga pagpipilian sa pagpapatupad. Halimbawa, sa python, hindi lahat ng pagkakataon na gumagamit ng naka-patch na paraan ay maaapektuhan ng patch. Kung ang isang instance ay tahasang tumatawag sa naka-patch na paraan, makakakuha ito ng bagong na-update na bersyon, sa kabaligtaran, ang iba pang mga pagkakataon na maaaring may mga katangian lamang na tumuturo sa naka-patch na paraan at hindi tahasang tumatawag dito ay makakakuha ng orihinal na bersyon, ito ay dahil sa kung paano python gumagana ang binding sa mga klase.

Konklusyon

Sa artikulong ito, ginalugad namin ang mataas na antas ng mga pagkakaiba sa pagitan ng static at dynamic na mga programming language, nakita namin kung paano makikinabang ang mga dynamic na programming language mula sa mga bagong paradigm at pattern na gumagamit ng likas na kakayahang umangkop na inaalok ng mga wikang ito. Ang halimbawang ipinakita namin ay nauugnay sa Monkey patching, isang pamamaraan na ginagamit upang palawigin ang gawi ng code nang hindi binabago ito mula sa pinagmulan. Nakita namin ang isang kaso kung saan ang paggamit ng diskarteng ito ay magiging kapaki-pakinabang kasama ang mga potensyal na disbentaha nito. Ang pagbuo ng software ay tungkol sa mga tradeoff, at ang paggamit ng tamang solusyon para sa problema ay nangangailangan ng detalyadong pagsasaalang-alang mula sa developer at isang mahusay na pag-unawa sa mga prinsipyo at pangunahing kaalaman sa arkitektura.


Career Services background pattern

Mga Serbisyo sa Karera

Contact Section background image

Manatiling nakikipag-ugnayan tayo

Code Labs Academy © 2024 Lahat ng karapatan ay nakalaan.