🧩 Паттерн Adapter может быть реализован в JavaScript множеством разных способов, на примерах для Node.js и браузеров. Все они имеют одну главную концепцию - обертка абстракции и связывание обернутого интерфейса с внешним. Но враперы для реализации адаптера можно делать на базе разных идей:
- Расширение адаптирруемого класса при помощи extends
- Боксирование адаптирруемого класса или функции
- Обертка адаптирруемого класса или функции в замыкание
- Использование композиции для боксинга адаптирруемого класса
- Использование аггрегации для боксинга адаптирруемого класса
- Реализаци обертки как широко известного контракта или интерфейса
- Применение открытого конструктора вместо наследования
Я думаю, что из примеров кода это проще понять, чем из текста, но после кода все же хорошо вернуься к обобщению. Примеры кода тут: https://github.com/HowProgrammingWorks/Adapter
- Расширение адаптирруемого класса при помощи extends
- Боксирование адаптирруемого класса или функции
- Обертка адаптирруемого класса или функции в замыкание
- Использование композиции для боксинга адаптирруемого класса
- Использование аггрегации для боксинга адаптирруемого класса
- Реализаци обертки как широко известного контракта или интерфейса
- Применение открытого конструктора вместо наследования
Я думаю, что из примеров кода это проще понять, чем из текста, но после кода все же хорошо вернуься к обобщению. Примеры кода тут: https://github.com/HowProgrammingWorks/Adapter
💥 Шок! Названа возможная дата КОНЦА Node.js, JavaScript и С++, эксперты раскрыли тайну TypeScript ☠️ https://youtu.be/bRlUtzQPOhA
Скандал в твиттере, все, что вы знали про программирование — скоро не будет стоить ничего!!! Когда наш CTO узнал это, то он три раза сбросился с унитаза и съел свою копию "Книжки с кабанчиком". Но я вас полюбил и я вас научу — тут статья «Самые важные знания для программиста» https://x.com/tshemsedinov/status/1809633457754034433
Скандал в твиттере, все, что вы знали про программирование — скоро не будет стоить ничего!!! Когда наш CTO узнал это, то он три раза сбросился с унитаза и съел свою копию "Книжки с кабанчиком". Но я вас полюбил и я вас научу — тут статья «Самые важные знания для программиста» https://x.com/tshemsedinov/status/1809633457754034433
YouTube
💥 Шок! Названа возможная дата КОНЦА Node.js, JavaScript и С++, эксперты раскрыли тайну TypeScript ☠️
Скандал в твиттере, все, что вы знали про программирование — скоро не будет стоить ничего!!! Когда наш CTO узнал это, то он три раза сбросился с унитаза и съел свою копию "Книжки с кабанчиком". Но я вас полюбил и я вас научу — тут статья «Самые важные знания…
💡 Начиная Chrome 119 и Node.js 22 у нас есть
Для чего оно нужно? Представьте, что у нас есть какое-то callback-returning API или EventEmitter/EventTarget или другие абстракции, поведения которых нужно подождать. И вот нужно сделать адаптер, обертку с внешним Promise-returning интерфейсом.
Пример:
Раньше это могло выглядеть так:
Или так:
Но теперь withResolvers позволяют это написать проще
‣ Значит ли это, что иначе писать уже плохо?
Это достаточно редкая и специфическая штука, ее нужно использовать в библиотеках и коде платформ с надеждой на то, что движки будут это как-то дополнительно оптимизировать, а в продуктовом коде нет на вас вины, если пишете по старинке.
‣ Значит ли это, что оно всем нужно?
Нет, но если знаете, это плюс.
Promise.withResolvers();
Для чего оно нужно? Представьте, что у нас есть какое-то callback-returning API или EventEmitter/EventTarget или другие абстракции, поведения которых нужно подождать. И вот нужно сделать адаптер, обертку с внешним Promise-returning интерфейсом.
Пример:
const sumAsync = (a, b, callback) => {
if (typeof a !== 'number') return;
if (typeof b !== 'number') return;
setImmediate(() => {
callback(a + b);
});
};
Раньше это могло выглядеть так:
let resolve, reject;
const promise = new Promise((resolved, rejected) => {
resolve = resolved;
reject = rejected;
});
setTimeout(reject, 1000, new Error('Timed out'));
sumAsync(2, 3, resolve);
const result = await promise;
console.log({ result });
Или так:
const promise = new Promise((resolve, reject) => {
sumAsync(4, 5, resolve);
setTimeout(reject, 1000, new Error('Timed out'));
});
const result = await promise;
console.log({ result });
Но теперь withResolvers позволяют это написать проще
const { promise, resolve, reject } = Promise.withResolvers();
setTimeout(reject, 1000, new Error('Timed out'));
sumAsync(6, 7, resolve);
const result = await promise;
console.log({ result });
‣ Значит ли это, что иначе писать уже плохо?
Это достаточно редкая и специфическая штука, ее нужно использовать в библиотеках и коде платформ с надеждой на то, что движки будут это как-то дополнительно оптимизировать, а в продуктовом коде нет на вас вины, если пишете по старинке.
‣ Значит ли это, что оно всем нужно?
Нет, но если знаете, это плюс.
Если кто хочет лучше понять о чем был ШОК-контент про конец TypeScript: тут лекция в академическом виде, без стеба https://youtu.be/9JUY3prnCQ4
YouTube
Мономорфный и полиморфный код, инлайн-кэш, скрытые классы в JavaScript
Примеры: https://github.com/HowProgrammingWorks/Monomorphism
Структура курса: https://github.com/HowProgrammingWorks/Index/blob/master/IP9X.md
Структура курса: https://github.com/HowProgrammingWorks/Index/blob/master/IP9X.md
🧩 Пока я готовлю курс по паттернам GoF, SOLID, GRASP с адаптацией для Node.js и JavaScript, собрал тут ссылки на все старые материалы, видео, примеры кода, задачи, если по ссылке github репозиторий, то часто там и примеры и видео: https://github.com/tshemsedinov/Patterns-JavaScript
Программирование, как и любая человеческая деятельность насквозь мифологично, более того, мы решительно ни о чем не можем поговорить, чтобы не опереться на тот или иной миф, то у нас Node.js однопоточный (хоть никогда не был), то мы говорим о нетипизированном языке программирования (хоть таких не бывает), то переменные иммутабельные (хоть это оксюморон), то микросервисы ускоряют ответ (хоть могут только замедлять), и даже, если мы понимаем неточность терминов, и пытаемся говорить точнее, то рассказ растягивается на бесконечность, потому, что все нужно уточнять, а уточнения тоже уточнять, и к каждому факту в уточнениях можно придраться и оспорить. Так что, быстро общаться можно, но только понимая друг друга между строк. Выйти за рамки мифа можно, но только создавая новый миф. Ошибки исправить можно, но только делая новые и новые ошибки. Да и учиться сразу правильно не выйдет, мы осваиваем частично ложные знания еще и плохо осваиваем, сталкиваемся с опытом и благодаря ошибкам, можем делать следующий шаг.
Почему нужно избегать union-тайпов?
1. Каждый раз, когда юнион куда-то приходит аргументом, нужно делать if, чтобы понимать, как с ним работать, кроме случая, когда все классы/типы, входящие в юнион имплементируют один и тот же интерфейс и нас интересует обращение именно через этот интерфейс, зачем тогда юнион, используйте этот интерфейс вместо него, ну если в юнион не входит undefined, null, unknown и т.д.
2. Юнионы приводят к мегаморфной форме обращения к объектам в V8, и это замедляет код, не сметртельно, но это неприятно и проще всего всего забыть их. Но для чего же они тогда вообще нужны? Для совместимости с JS, если в нем можно передать что-угодно аргуметом, то это нужно меть возможность как-то выразить. Это не значит, что это хорошо и так нужно писать кода, это добавили как возможность, а не как обязанность )
3. Это часто ведет к нарушению SOLID:SRP (принципа единственной ответственности), потому, что как может метод, например, получать сокеты или таймеры на выбор и делать разные вещи в зависимости от этого, это же маразм, нарушает SOLID:LSP (принцип подстановки), иногда нарушает GRASP:InformationExpert, явно повышает Coupling.
Вместо этого нужно всегда использовать маленькие интерфейсы, заточенные под узкую задачу, помним про SOLID:ISP (принцип разделения интерфейсов) и могут быть optional аргументы, для этого не нужно делать union с null.
1. Каждый раз, когда юнион куда-то приходит аргументом, нужно делать if, чтобы понимать, как с ним работать, кроме случая, когда все классы/типы, входящие в юнион имплементируют один и тот же интерфейс и нас интересует обращение именно через этот интерфейс, зачем тогда юнион, используйте этот интерфейс вместо него, ну если в юнион не входит undefined, null, unknown и т.д.
2. Юнионы приводят к мегаморфной форме обращения к объектам в V8, и это замедляет код, не сметртельно, но это неприятно и проще всего всего забыть их. Но для чего же они тогда вообще нужны? Для совместимости с JS, если в нем можно передать что-угодно аргуметом, то это нужно меть возможность как-то выразить. Это не значит, что это хорошо и так нужно писать кода, это добавили как возможность, а не как обязанность )
3. Это часто ведет к нарушению SOLID:SRP (принципа единственной ответственности), потому, что как может метод, например, получать сокеты или таймеры на выбор и делать разные вещи в зависимости от этого, это же маразм, нарушает SOLID:LSP (принцип подстановки), иногда нарушает GRASP:InformationExpert, явно повышает Coupling.
Вместо этого нужно всегда использовать маленькие интерфейсы, заточенные под узкую задачу, помним про SOLID:ISP (принцип разделения интерфейсов) и могут быть optional аргументы, для этого не нужно делать union с null.
🙊 The Law of Demeter (LoD): Don’t talk to strangers
If you see something like this:
👉
👉
👉
You have technical debt! It's time to plan refactoring.
Each entity (unit/instance) should have only limited knowledge about others (only "closely" related to the current one).
Each entity should only talk to its friends (immediate friends): don’t talk to strangers!
Вut don't do it in a panic and do not mix refactoring with other issues (like new features implementation).
Just note that and plan resource allocation.
If you see something like this:
👉
connection.parent.service.storage.db.saveRecord
👉
this.action.scenario.bot.telegram.sendMessage
👉
service.find('logger').kind('error').stream.write
You have technical debt! It's time to plan refactoring.
Each entity (unit/instance) should have only limited knowledge about others (only "closely" related to the current one).
Each entity should only talk to its friends (immediate friends): don’t talk to strangers!
Вut don't do it in a panic and do not mix refactoring with other issues (like new features implementation).
Just note that and plan resource allocation.
✅ План стримов по паттернам:
08 августа - четверг - ITBeard
09 августа - пятница - Деми Мурыч
10 августа - суббота - Илья Климов
08 августа - четверг - ITBeard
09 августа - пятница - Деми Мурыч
10 августа - суббота - Илья Климов