Vendor Lock In - ce este, cum îl putem evita?

Să continuăm Do Not Learn Frameworks. Learn the Architecture:

Plecăm de aici:

Respectiv

Este posibil să nu fi înțeles ce înseamnă acest vendor lock in; prin urmare, m-am gândit că ar fi util să avem (cel puțin) un exemplu concret cu ce este și un exemplu la fel de concret de cum am putea să evităm acest lucru.

jQuery este un vendor, corect? Cum putem evita vendor lock in pentru situații de genul:

$.get(url, params, callback);
// sau
$('#foo').show();
// sau
var bar = $.map( barObj, mapCallback );
/// etc

Cum putem face ca jQuery să fie, în acest caz, interschimbabil cu… nu știu, Moo sau Prototype? Deoarece presupun că asta înseamnă vendor lock… out (cum se numește opusul lui lock in?), nu? Să poți schimba vendorul fără a-ți schimba codul?

jQuery este un exemplu simplu, digerabil de oricine; sunteți invitați să veniți cu alte exemple concrete, indiferent de limbaj.


Sunt invitați să răspundă (însă fără a ne limita doar la ei) @tekkie și @flavius, pentru că ei au fost cei mai vocali atunci când a fost vorba de medii enterprise.

1 Like

Cel mai banal prim lucru pe care il poti face e sa impachetezi acele instructiuni intr-o functie. Pe langa protejarea de vendor lock-in, ai alte cateva avantaje:

  • poti refolosi functia - daca o parametrizezi cum trebuie
  • numind functia cum trebuie, contribui la dezvoltarea si consolidarea acelui ubiquitous language (vezi DDD)
  • poti testa mai usor; nu am facut in javascript mai mult de smoked tests, dar intr-un alt limbaj e usor sa mock-uiesti acea functie si sa scrii teste subcutane - adica nu mai ai nevoie de DOM in cazul js
  • presiunea cognitiva scade, pentru ca iti e mult mai usor sa te gandesti la “numeFunctieDeBusinessAici”, decat la o anumita secventa de instructiuni; creierul uman e bestial de bun la abstractizari si generalizari, foloseste-i la maxim aceasta capacitate

Bineinteles, elegant este sa creezi un intreg anticorruption layer pentru aceste lucruri, nu functii izolate. Deci clase si metode denumite dupa termeni din UL.

Cu un intreg layer, presiunea cognitiva scade si mai mult. E o placere cand stai cu clientul in fata monitorului si in fata ta incape tot codul relevant problemei despre care discutati, iar clientul intelege perfect tot ce exprima acel cod deoarece folositi acelasi limbaj - chiar daca nu e programator.

Nu sunt cine stie ce pasi mareti pe care trebuie sa ii faci. Sunt pasi mici dar constanti pe care ii poate face oricine incepe un proiect de la zero.

Nu spune nimeni sa fugi de vendor ca de dracu’. jQuery e o librarie buna, ofera productivitate. Dar nu costa nimic sa adaugi o mica protectie acolo, plus ca iti aduce beneficiile pe care le-am enumerat mai sus - deci chiar si facand abstractie de vendor lock-in, tot e ceva ce ar trebui sa faci.

Cand zic

ma refer chiar la cel mai marunt lucru pe care il poate face oricine.

Exista alte strategii mai complexe, dar e un amestec de business logic cu arhitectura si cu stereotipurile limbajului in care programezi. Unele sunt marunte, si despre ele putem vorbi cu usurinta la scara redusa, in exemple sintetice, altele nu le poti deslusi decat cu exemple concrete de business, exemple care sunt complexe, deci nu putem vorbi despre ele intr-un forum.

1 Like

De ce ai evita jQuery intotdeauna, stii sigur ca e ceva ce trebuie evitat?
Orice discutie pe acest topic in afara unui context anume nu are sens in opinia mea, pentru ca sunt multe aspecte: tipul de aplicatie, structura/complexitatea DOM-ului, marimea proiectului, marimea echipei, nivelul tehnic al echipei, ce web-browsers targetezi, deadline-uri, buget, etc
jQuery targeteaza cel mai mic numitor comun din feature-uri din browsere.

Facebook de exemplu nu foloseste jQuery, dar nu din cauza de vendor lock-in.
Au o armata de oameni supercapabili sa preia un code base al oricarui framework si sa-l schimbe si sa-l rescrie la nevoie.

1 Like

Da te rog un exemplu in cod, suntem programatori for god’s sakes.

1 Like

@kilogrammer: jQuery a fost un exemplu; nu cred că e cineva care programează pentru web ce nu a avut tangențe cu jQuery :smile:

@flavius: nu ar strica nici un exemplu concret; tocmai de asta am deschis thread-ul. Chiar dacă nu ești familiar cu JS, nu ne supărăm nici un pseudo JS :wink:

2 Likes

Pai nici eu nu m-am referit la jQuery in special.
Daca tot discutam chestii fine, mi se pare important contextul aplicatiei.
Nu poti vorbi despre a face astfel de alegeri fara un context.

Codul postat de tine nu are valoare de business, are “foo” in el si e exclusiv pentru exemplificare. Nu am de exemplu cum sa gasesc un nume de functie bun pentru cele trei (depinde cum numeri) instructiuni ale tale.

Deci daca iau cele 3 linii de jQuery si le mut intr-o functie, asta inseamna protejarea de vendor lock-in?

1 Like

Uite care e treaba

a. eu nu pot formula mai clar de atat [quote=“flavius, post:2, topic:2376”]banal prim lucru[/quote]
b. eu nu explic aici pentru tine, pentru ca nu lasi impresia ca esti dornic de schimb de idei; eu explic pentru altii care vor citi si vor considera ca e util ce am scris

2 Likes

@kilogrammer: mi-am dat seama că cele trei linii par a face parte din același cod. Sunt trei exemple diferite de cod care folosește funcții/metode de la un vendor. :smile:


jQuery este doar un exemplu. Ideea e să dăm exemple pe chestii simple, banale, ce pot fi înțelese de toată lumea. Dacă nu e OK, o să te rog să vii tu cu un exemplu dintr-un limbaj preferat de tine.

Poți explica te rog ce înseamnă „valoare de business”?

Uite exemple fără „foo” :smile:

$('div').on('click', function(){
  alert('Click!');
});
$('select').on('change', function(e){
  $(e.currentTarget).addClass('is-changed');
});
var mapped = $.map([0, 1, 3, 5], function(i){
  return i > 3;
});

PS: aș aprecia discuții mai calme, fără înțepături. Chestiile astea, pe lângă că sunt copilărești, nu au nici o valoare constructivă. Mulțumesc.

1 Like

Protejarea la vendor lock in nu inseamna sa “impachetezi” 3 call-uri de API al unei librarii intr-o alta functie.

ok, so?
intreb serios, am spus ceva legat daca sunt sau nu din acelasi cod?

E dificil sa gasesti exemple bune dar la scara mica, deoarece aici vorbim despre ubiquitous language, acel limbaj comun pe care il ai cu toate partile implicate, de la client la end-user.

“Valoare de business” aduc acele lucruri care produc bani, care au o semnificatie in compania respectiva, care reprezinta nucleul activitatii centrale, unicitatea, inovatia.

De exemplu, o valoare de business a unei companii de e-commerce poate fi algorimtul care optimizeaza preturile, producatorii, timpii de livrare, etc.

O non-valoare de business e framework-ul folosit, de exemplu.

Daca de exemplu acele instructiuni vor sa afiseze un pop-up (da, enervant din punct de vedere UX, vorbim acum despre un exemplu sintetic) care recomanda produse, numesti functia respectiva showAwesomeProducts(), pentru ca in toate intalnirile cu toate partile implicate asa au fost numite acele produse “awesome products”, in discutiile ca de la om la om.

Cand un non-programmer va vedea showAwesomeProducts(), va sti despre ce e vorba, iar tu nu va trebui sa te gandesti de fiecare data la ce inseamna codul si sa “ii traduci” celui cu care vorbesti. Tu pur si simplu citesti codul, si el intelege.

Revenind la vendor lock-in, ti-am spus deja, acesta cu impachetarea in functii e un lucru banal pe care oricum il faci in multe locuri din cod. Nu e nimic deosebit sau complex. Trebuie doar facut consecvent.

Daca vrei sa construiesti un intreg layer, atunci nu putem vorbi pe exemple sintetice, deoarece devine mai complex.

2 Likes

Nu știu :smile:

Faza e că până acum câteva săptămâni trăiam foarte confortabil în bula mea, auzind ocazional de vendor lock in. Știam ce este, știam de ce nu e OK, dar cam atât. De câteva săptămâni însă, doar despre asta se discută aici și simt ori că nu am înțeles bine ceva, ori nu dau destulă importanță, ori e overrated ori… nu știu.

Și problema e că până acum s-au purtat doar discuții abstracte despre acest subiect; ceea ce înseamnă că, dacă în teorie sunt doxă, în practică stau și mă uit la cod fără să știu ce și cum.

Și dacă nu știu, întreb și încerc să întreb cât mai clar, subliniind lucrurile care consider că ar avea importanță, în încercarea de a-mi însuși mai bine anumite lucruri. O căutare pe google ajută doar la descoperirea de și mai multă teorie, fără nici un exemplu concret și simplu.

Eu aș vedea codul ăsta:

$('div').on('click', function(){
  alert('Click!');
});

scris fără vendor lock in, cam așa:

var vendor_jQuery = {
  bindEvent : function(el, eventName, callback){
    $(el).on(eventName, callback);
  }
};

Și rescris în felul următor:

var jsVendor = vendor_jQuery;
function alertaLaClick() {
  alert('Click!');
}

jsVendor.bindEvent('div', 'click', alertaLaClick);

În felul ăsta aș putea schimba jQuery cu orice altă bibliotecă (cât timp implementez toate metodele corespunzător), iar asta presupune să scriu câte un wrapper pentru fiecare metodă jQuery:

var vendor_jQuery = {
  bindEvent : function(el, eventName, callback){
    $(el).on(eventName, callback);
  },
  get: function(url, params, callback){
    $.get(url, params, callback);
  },
  addClass: function(el, className){
    $(el).addClass(className);
  },
  // etc, etc, etc
};

Am înțeles bine?

1 Like

Da. Daca urmezi sistematic acest pattern, miroase deja a un inceput bun de anticorruption layer.

In JS e mai dificil sa vezi layerul, cel putin mie imi e dificil, deoarece e un limbaj prea “hackish”; nu ai interfete de exemplu, pentru a forta contracte de comunicare intre obiecte (in momentul compilarii, cum e in alte limbaje).

Mi-am editat primul raspuns:

Uite un exemplu la scara redusa despre care putem vorbi.

Sa zicem ca folosesti un wrapper pentru PDO in PHP. In mod clasic, ai avea un cod de genul

while($wrapper->fetch()) {
  //do stuff
}

Cu un layer, codul ar fi ceva de genul:

while($productRepository->getNext()) {
 // do stuff
}

Repository ar folosi intern acel wrapper (vendorul), deoarece el intr-adevar aduce momentan multe beneficii, dar nu vrem sa depindem direct de acel vendor.

Citirea o poti face cu consum optim de memorie folosind un generator. Overhead-ul este minim, si daca in viitor vrei sa schimbi vendorul, nu e nevoie sa modifici codul client (care depinde de Repository, nu de vendor direct), ci doar Repository-ul.

Acum introdu cate un Repository (cu o interfata comuna) pentru fiecare entitate cu valoare de business si ai un intreg layer. (Nota: nu e musai sa aiba valoare de business, dar daca urmezi DDD, este sanatos)

Sau cum ar zice Uncle Bob: vendorul e impachetat intr-un plug-in. Ma rog, doar din codul prezentat nu se vede ca poate fi plug-in, dar e usor sa injectezi repository-ul in biblioteca centrala (cea vendor-free si cu business value in ea).

Tangential cu “injectezi”, eu unul prefer injectarea manuala a dependintelor in biblioteca centrala, fara DiC, ci prin constructor. Avantajul e o documentare mai clara a business-ului; i.e. vezi direct din cod “pentru a construi conceptul A, trebuie sa construiesti mai intai conceptele B si C”.

2 Likes

Abordarea mi se pare simplista. Da sigur, putem sa-i dam inainte si sa tot scriem un layer care duplica jQuery.

Dar daca trebuie sa folosesti de exemplu, promises in viitor? Nu va mai functiona prin parametrul “callback”.
Daca apoi folosesti async / await din ES7?

Daca o alta librarie nu are un corespondent 1 la 1 functiile din layerul ala? Daca poate noua librarie are alta logica in API decat cea din layer?
Daca la un moment dat, nativ in web-browser vor fi suportate o gramada din ce folosesti in acest layer? Mai are sens sa rescrii layer-ul folosind implementarea nativa si sa-l folosesti?

Problema asta e veche, s-a scris mult pe aceasta tema, si e greu sa vorbesti in general.
In practica uneori, overhead-ul adus in adaugararea de diverse layere si abstractizari ajunge sa fie foarte mare in aplicatiile mari si unii (mai destepti decat mine) s-au intrebat atunci, la ce bun? Chiar e folositor intotdeauna?

Eu nu spun va vendor lock-in nu exista. Sigur exista.
Dar nu poti vorbi in general. Si nu poti vorbi cu nici o certitudine. Dar unii pot :smile: ca e destepti

2 Likes

De aceea am accentuat din start importanta numirii functiilor conform cu ubiquitous language.

Nu am sustinut niciodata duplicarea codului. Nu stiu cum citesti tu ce scriu.

1 Like

@flavius: deci practic ar trebui să „dublez” toate metodele folosite într-o bibliotecă în acest wrapper al meu, corect? (Iar acest pattern se numește repository)

@kilogrammer: încerc să înțeleg cum stau lucrurile la cel mai de bază nivel.

Presupun că ăsta ar fi avantajul unei astfel de abordări: faci o implementare în acest layer al tău. În exemplul meu, voi folosi în cod doar asta:

jsVendor.bindEvent('div', 'click', alertaLaClick);

În layerul meu pot face această implementare oricum, inclusiv nativ, cu document.addEventListener


PS: încă o dată vă rog să încercăm să păstrăm un nivel civilizat al discuției. Suntem aici pentru a învăța unii de la alții, nu pentru a ne înțepa reciproc.

1 Like

Nu, nu duplici nimic, dai nume functiilor folosind ubiquitous language. Nu mi-am dat seama ca tu scriai un exemplu atat de concret, ma gandeam ca doar scrii exemplu de mapare in js.

Ceva de genul:

var vendor_jQuery = {
  showAwesomeProducts : function(...){
    $vendor.doStuff(...);
    $vendor.doEvenMoreStuff(...)
  },
  // etc, etc, etc
};

Numirea functiei in termeni de ubiquituous language (showAwesomeProducts) nu e un detaliu, e un punct central.

DESI REPET: acesta nu este sfarsitul evitarii vendor lock-in-ului, e doar un inceput simplu pe care il poate face oricine.

1 Like