Я думаю, что мультипарадигменное программирование и знание нескольких языков программирования — это ключ к тому, чтобы не стать чудовищем. Человек с парадигмальным и языковым шовинизмом среди программистов выглядит как фанатик и всегда сделает решение хуже, чем человек, умеющий свободно использовать в одном коде приемы процедурного, структурного, объектно-ориентированного, функционального, автоматного, реактивного и других парадигм, таким образом, чтобы они не мешали друг другу, а органично сочетались. Это примерно как на эфирах на Альфе сочетаются разные языки и мировоззрения, от чего их смотреть интереснее, чем пропаганду на зомбоящике.
Есть еще техники программирования, как асинхронное программирование и параллельное, или обобщенное, потому, что они не бывают сами по себе, для них нужна парадигма-носитель, например для асинхронного нужно или ооп с шаблоном Observer (наблюдатель, но можно сделать на другом шаблоне), или Callback (прием процедурного программирования). Вообще, есть люди, что и ООП не признают отдельной парадигмой и говорят, что это всего лишь расширение процедурной парадигмы, но нет, ООП все же отдельная парадигма, потому, что оно предлагает свой подход к решению основных вопросов: организация последовательности операций (control flow), организация работы с состоянием (app state), способы связывания или зацепления кода (coupling and cohesion).
Для программистов очевидно, что языковые экстремисты, почитатели одного фреймворка и зацикленные на нескольких приемах и паттернах — это пример пещерного мышления, а не имея возможности сравнить, они и свою парадигму хуже понимают, никогда не могут сказать, какие у нее есть сильные и слабые стороны и всегда рассматривают ее как единственно правильную, в которой все хорошо и нет изъянов.
Есть еще техники программирования, как асинхронное программирование и параллельное, или обобщенное, потому, что они не бывают сами по себе, для них нужна парадигма-носитель, например для асинхронного нужно или ооп с шаблоном Observer (наблюдатель, но можно сделать на другом шаблоне), или Callback (прием процедурного программирования). Вообще, есть люди, что и ООП не признают отдельной парадигмой и говорят, что это всего лишь расширение процедурной парадигмы, но нет, ООП все же отдельная парадигма, потому, что оно предлагает свой подход к решению основных вопросов: организация последовательности операций (control flow), организация работы с состоянием (app state), способы связывания или зацепления кода (coupling and cohesion).
Для программистов очевидно, что языковые экстремисты, почитатели одного фреймворка и зацикленные на нескольких приемах и паттернах — это пример пещерного мышления, а не имея возможности сравнить, они и свою парадигму хуже понимают, никогда не могут сказать, какие у нее есть сильные и слабые стороны и всегда рассматривают ее как единственно правильную, в которой все хорошо и нет изъянов.
⚡️ Это случилось! 🎉 Впервые ChatGPT смог сделать код лучше и быстрее меня. Уже более 6 месяцев я время от времени применяю ChatGPT, Bard, Copilot, просто на тех задачах, которые сам пишу, и все это время они или вообще не могли решить их или делали в 10-20 раз медленнее, с моими долгими объяснениями и подсказками. Даже три доклада за это время сделал, но максимум, что я мог взять для себя в работе от нейросетей, это исправления в тайпингах и доках, формирование ченджлогов и небольшие идеи, например: заменить
.on('close', callback)
на .once('close', callback)
не более. Скорее всего, в более простой и типичной работе нейросети более полезны. И вот вчера ночью нейросеть GPT-4 переписала код лучше меня, самый некрасивый код во всей моей кодовой базе, коду чуть меньше года и весь год я о нем думал с грустью. Конечно, код не стал супер красивым, но он стал как минимум не уродским. На вход я дал старый код, тесты из которых можно взять все требования и кейсы и Please review and propose optimizations in diff format. I'd like to avoid if-nesting and improve readability
: https://github.com/metarhia/metautil/commit/b385d6667789e0fbecdca051f8b4edda5841acd9GitHub
Optimize `nextEvent` · metarhia/metautil@b385d66
PR-URL: https://github.com/metarhia/metautil/pull/161
Forwarded from Metarhia/NodeUA - Node.js Ukraine Community
YouTube
🧑💻 Node.js: Как избавиться от пачки require или import для CommonJS и ECMAScript модулей
Примеры кода из видео: https://github.com/HowProgrammingWorks/Modularity/tree/master/NodeJS
Оглавление нового курса по Node.js: https://github.com/HowProgrammingWorks/Index/blob/master/Courses/NodeJS-2022-2023.md
Видео обзор курса: https://youtu.be/UGGzSEfCjPU…
Оглавление нового курса по Node.js: https://github.com/HowProgrammingWorks/Index/blob/master/Courses/NodeJS-2022-2023.md
Видео обзор курса: https://youtu.be/UGGzSEfCjPU…
Forwarded from Metarhia/NodeUA - Node.js Ukraine Community
Не только ChatGPT лучше работает, если ему задавать роль, попробуйте задавать роль себе, когда работаете, и вы сильно улучшите результат. Например, представьте себе, что пишете прикладной код и держите в голове внимание на этом, чтобы опять не начать в прикладном коде изобретать обход дерева в ширину, писать свой роутинг, логгер, фаервол, систему кеширования запросов или реализовывать свой механизм для отмены асинхронных операций. Все это нормальные задачи, но их не должно быть в высокоуровневом продуктовом коде. Если появляется необходимость и вы не можете найти нужной функциональности в платформе, то сначала поищите распространенный контракт для этой задачи (например, AbortController) или разработайте контракт (например, RoundrobinQueue), и пишите прикладной код, опираясь на этот контракт, а потом переключите роль, представьте, что вы системный программист, реализуйте этот контракт в отдельном модуле. И вуаля, все работает вместе, а кодовая база разделена на уровни абстракции, есть переиспользуемость, можно заменить реализацию контракта, тесты писать удобнее, а реализация контракта может появиться в платформе позже и со временем, вы удалите свою из проекта, если контракт не совпадает, то сделаете обертку, но главное - системный и прикладной код будут разделены. Два слоя - это минимум, но в 90% случаев два слоя решают проблему. А вы говорите: давайте роль ChatGPT... себе роль давайте :)
Forwarded from Metarhia Chief Level
На этой неделе релиз техстека Metarhia 3.0 и в пятницу 30 июня доклад на конференции FlowMates
Если Вы учите программирование и рассчитываете работать в типичном продукте или аутсорсе, в стартапе или фрилансе, то вот на чем можно сэкономить. Но это не касается тех, кто хочет стать системным программистом и работать в технологической компании. Так вот, чтобы быстрее учиться и что скорее всего никогда не понадобится в реальном продуктовом коде:
1. Алгоритмы и задачи с литкода или кодеварс вам не нужны. Но нужен навык простого процедурного и ООПшного кода + GRASP и SOLID.
2. Всякие учебные задачи, типа todo листа, калькулятора, крестики-нолики. Нужно делать более комплексные вещи, полноценный проект.
3. Бесконечное смотрение видео тоже ни к чему не приведет, нужно получать ревью кода, желательно от наставника или от друзей.
4. Задачи на системный дизайн не нужны, Это знания, которые нужны лиду, архитектору и CTO и валидны только при закреплении на практике.
5. Микрооптимизация, типа сравнения по производительности object[key], obejct.key и Object.assign. В начале пути одна задача - понятность кода.
6. Не нужно заучивать все паттерны (GoF и еще сотню), в зависимости от языка и фреймворка вам понадобится всего 2-3 шаблона проектирования.
7. Не старайтесь изучить внутреннее устройство event loop, garbage collection, goroutine scheduler, это спрашивают на собесах, но не нужно в работе.
8. Не ведитесь на крутые темы, типа высоконагруженных, распределенных и супер-защищенных приложений, вас к ним еще долго не допустят.
9. Не зацикливайтесь на языке, язык гораздо проще тулинга, поднажмите на git, github, линтеры, ide, docker, ci и тестирование, тулы для отладки.
10. Ничто так не отвлекает от изучения программирования, как ВУЗ и не внушает ложного чувства уверенности, как ИТ-курсы от инфожуликов.
1. Алгоритмы и задачи с литкода или кодеварс вам не нужны. Но нужен навык простого процедурного и ООПшного кода + GRASP и SOLID.
2. Всякие учебные задачи, типа todo листа, калькулятора, крестики-нолики. Нужно делать более комплексные вещи, полноценный проект.
3. Бесконечное смотрение видео тоже ни к чему не приведет, нужно получать ревью кода, желательно от наставника или от друзей.
4. Задачи на системный дизайн не нужны, Это знания, которые нужны лиду, архитектору и CTO и валидны только при закреплении на практике.
5. Микрооптимизация, типа сравнения по производительности object[key], obejct.key и Object.assign. В начале пути одна задача - понятность кода.
6. Не нужно заучивать все паттерны (GoF и еще сотню), в зависимости от языка и фреймворка вам понадобится всего 2-3 шаблона проектирования.
7. Не старайтесь изучить внутреннее устройство event loop, garbage collection, goroutine scheduler, это спрашивают на собесах, но не нужно в работе.
8. Не ведитесь на крутые темы, типа высоконагруженных, распределенных и супер-защищенных приложений, вас к ним еще долго не допустят.
9. Не зацикливайтесь на языке, язык гораздо проще тулинга, поднажмите на git, github, линтеры, ide, docker, ci и тестирование, тулы для отладки.
10. Ничто так не отвлекает от изучения программирования, как ВУЗ и не внушает ложного чувства уверенности, как ИТ-курсы от инфожуликов.
Есть два типа людей:
1. Научился писать круды — устроился формошлепом.
2. Научился делать масштабируемые, надежные, высоконагруженные распределенные системы — устроился формошлепом.
1. Научился писать круды — устроился формошлепом.
2. Научился делать масштабируемые, надежные, высоконагруженные распределенные системы — устроился формошлепом.
Forwarded from Metarhia/NodeUA - Node.js Ukraine Community
💡 Паттерны проектирования для JavaScript и Node.js (самые распространенные)
🧩 EventEmitter (он же Observer), встроен в ноду, а на фронте полифил или EventTarget,
🧩 Proxy - встроен в язык, перехват обращений к объекту,
🧩 Strategy - у нас это просто Object или Map - коллекция функций, классов, прототипов, замыканий и т.д.,
🧩 Facade - упрощенный интерфейс к сложной системе, много где используется, например http2.createSecureServer скрывает от нас как TLS, так и HTTP, потоки, сессии и другие механизмы,
🧩 Adapter - обычно функция-обертка, wrapper, примеры: promisify, callbackify, или можно написать полифил fetch, использующий внутри XMLHttpRequest, это будет адаптер, скрывающий сложность, но не фасад, потому, что за фасадом скрывается не один интерфейс, а несколько или целая подсистема,
🧩 Factory - Фабрика, это паттерн, который создает экземпляры класса, но в JS фабрика может порождать экземпляры прототипов, замыканий,
🧩 ChainOfResponsibility - обычно используется его псевдо-аналог Middleware, который приводит к конкуренции за шареный стейт и так ведет нас к состоянию гонки, про оригинальный ChainOfResponsibility всем стоит почитать, чтобы перестать использовать Middleware,
🧩 Decorator - встроеный в язык, при чем в JavaScript и в TypeScript, спецификации отличаются, но суть так же, добавляет поведение без наследования, за счет метаданных,
🧩 Singleton - это у нас просто объект, для этого даже класс создавать не нужно, а глобальная уникальность экземпляра может достигаться при помощи экспорта из модуля,
🧩 Revealing constructor - открытый конструктор, например, передавая метод write в конструктор Writable через options мы можем получить Writable с переопределенным методом без наследования, так же и с передачей функции в конструктор Promise, мы так привыкли к этому, но в других языках это традиционно делается через наследование.
🧩 EventEmitter (он же Observer), встроен в ноду, а на фронте полифил или EventTarget,
🧩 Proxy - встроен в язык, перехват обращений к объекту,
🧩 Strategy - у нас это просто Object или Map - коллекция функций, классов, прототипов, замыканий и т.д.,
🧩 Facade - упрощенный интерфейс к сложной системе, много где используется, например http2.createSecureServer скрывает от нас как TLS, так и HTTP, потоки, сессии и другие механизмы,
🧩 Adapter - обычно функция-обертка, wrapper, примеры: promisify, callbackify, или можно написать полифил fetch, использующий внутри XMLHttpRequest, это будет адаптер, скрывающий сложность, но не фасад, потому, что за фасадом скрывается не один интерфейс, а несколько или целая подсистема,
🧩 Factory - Фабрика, это паттерн, который создает экземпляры класса, но в JS фабрика может порождать экземпляры прототипов, замыканий,
🧩 ChainOfResponsibility - обычно используется его псевдо-аналог Middleware, который приводит к конкуренции за шареный стейт и так ведет нас к состоянию гонки, про оригинальный ChainOfResponsibility всем стоит почитать, чтобы перестать использовать Middleware,
🧩 Decorator - встроеный в язык, при чем в JavaScript и в TypeScript, спецификации отличаются, но суть так же, добавляет поведение без наследования, за счет метаданных,
🧩 Singleton - это у нас просто объект, для этого даже класс создавать не нужно, а глобальная уникальность экземпляра может достигаться при помощи экспорта из модуля,
🧩 Revealing constructor - открытый конструктор, например, передавая метод write в конструктор Writable через options мы можем получить Writable с переопределенным методом без наследования, так же и с передачей функции в конструктор Promise, мы так привыкли к этому, но в других языках это традиционно делается через наследование.
Forwarded from Metarhia/NodeUA - Node.js Ukraine Community
По паттерну Middleware нужно отдельно пояснить, он не только приводит нас к race condition, а точнее и к конфликтам по данным и к конфликтам по control flow, но еще и всячески усиливает зацепление (coupling) кода:
⚠️ Провоцирует практику примесей (mixins), например: res.sessionStarted = true; и потов в куче мест if res.sessionStarted или res.userName = 'idiot';
⚠️ Провоцирует протекание абстракций - когда мы залезаем во внутренности req и res и правим их состояние, а также состояние их частей, сокетов, заголовков и т.д. не через внешний интерфейс, т.е. методы, не по контракту, а патчами, обертками, в общем, таким образов, например, ws (библиотека вебсокетов) патчит http сервер и внедряется в его середину для перехвата апгрейда до вебсокетов. Очень хорошо, что так можно сделать в JavaScript, это позволяет быстро решить любую проблему, но такое решение нужно хорошо продумать, покрыть тестами, и вероятность, что оно развалится все же велика. В системном коде это еще ок, а вот в продуктовом нужно максимально снижать протекание, полностью, конечно, его вообще невозможно уничтожить, см. "Закон дырявых абстракций".
⚠️ Провоцирует reference pollution и использование шаренного состояния: ссылки на req и res расползаются по разным частям программы, например: serviceName.method(req, res, ...); или на части req и res, пример: serviceName.method(req.socket, ...); или так: outside.emit('request', req); много есть способов: const f1 = method.bind(req); или const f2 = method(req)(res); и еще сотни.
⚠️ Провоцирует состояние гонки (race condition): через использование структуры данных за пределами middleware и потом использование такой структуры внутри нескольких middleware сразу или за счет того, что ссылки на req и res попали в другие части программы и оттуда меняется их состояние уже без привязки к next, например по setTimeout кто-то сделал таймаут отправки результатов или на по приходу какого-то события из стримов req и res кто-то хеадеры пишет, а потом другой мидлвар уже не может хеадеры записать. Это только самые частые проблемы, вы разве не сталкивались, когда мидлвары переставляют местами, чтобы найти такую последовательность, чтобы оно таки запустилось, так вот это плохая практика, она только скрывает гонку, но при нагрузке она может вылезти.
⚠️ Провоцирует писать толстые контроллеры и смешивать в них разные слои, ну мы видели все, такой эндпоинт, в котором все сразу, и работа с http протоколом, и бизнес-логика и обращение к базе данных через SQL и запись кеша в redis и отправка задачи в очередь и работа с файловой системой, да что угодно, все простыней... нет, конечно, никто так писать не заставляет, просто не все в курсе, что нужно делать слои, и выделять работу с базой в репозиторий и т.д., точнее, знают многие, но мало кто может так делать.
⚠️ Повышает зацепление (code coupling) - все части кода становятся более зависимы друг от друга благодаря всему вышеописанному, и пошевелишь одно, а ломается в другом месте.
⚠️ Провоцирует практику примесей (mixins), например: res.sessionStarted = true; и потов в куче мест if res.sessionStarted или res.userName = 'idiot';
⚠️ Провоцирует протекание абстракций - когда мы залезаем во внутренности req и res и правим их состояние, а также состояние их частей, сокетов, заголовков и т.д. не через внешний интерфейс, т.е. методы, не по контракту, а патчами, обертками, в общем, таким образов, например, ws (библиотека вебсокетов) патчит http сервер и внедряется в его середину для перехвата апгрейда до вебсокетов. Очень хорошо, что так можно сделать в JavaScript, это позволяет быстро решить любую проблему, но такое решение нужно хорошо продумать, покрыть тестами, и вероятность, что оно развалится все же велика. В системном коде это еще ок, а вот в продуктовом нужно максимально снижать протекание, полностью, конечно, его вообще невозможно уничтожить, см. "Закон дырявых абстракций".
⚠️ Провоцирует reference pollution и использование шаренного состояния: ссылки на req и res расползаются по разным частям программы, например: serviceName.method(req, res, ...); или на части req и res, пример: serviceName.method(req.socket, ...); или так: outside.emit('request', req); много есть способов: const f1 = method.bind(req); или const f2 = method(req)(res); и еще сотни.
⚠️ Провоцирует состояние гонки (race condition): через использование структуры данных за пределами middleware и потом использование такой структуры внутри нескольких middleware сразу или за счет того, что ссылки на req и res попали в другие части программы и оттуда меняется их состояние уже без привязки к next, например по setTimeout кто-то сделал таймаут отправки результатов или на по приходу какого-то события из стримов req и res кто-то хеадеры пишет, а потом другой мидлвар уже не может хеадеры записать. Это только самые частые проблемы, вы разве не сталкивались, когда мидлвары переставляют местами, чтобы найти такую последовательность, чтобы оно таки запустилось, так вот это плохая практика, она только скрывает гонку, но при нагрузке она может вылезти.
⚠️ Провоцирует писать толстые контроллеры и смешивать в них разные слои, ну мы видели все, такой эндпоинт, в котором все сразу, и работа с http протоколом, и бизнес-логика и обращение к базе данных через SQL и запись кеша в redis и отправка задачи в очередь и работа с файловой системой, да что угодно, все простыней... нет, конечно, никто так писать не заставляет, просто не все в курсе, что нужно делать слои, и выделять работу с базой в репозиторий и т.д., точнее, знают многие, но мало кто может так делать.
⚠️ Повышает зацепление (code coupling) - все части кода становятся более зависимы друг от друга благодаря всему вышеописанному, и пошевелишь одно, а ломается в другом месте.
🙊🙈🙉 Ещё остались люди, которые думают, что у middleware есть правильное и неправильное использование и при правильном все хорошо. Отличие мидлваров от цепочки ответственности в том, что в цепочке только одно звено берет всю ответственность, а в мидлварах в случае его правильного использовния все по очереди мутируют состояние, ну это тоже небезопасная практика. Это как взять сделать объект parameters и передавать его из функции в функцию по цепочке, каждая функция будет из объекта читать параметры, изменять и удалять, а потом передавать этот объект дальше. Если вы думаете, что никто в здравом уме так не сделает, то посмотрите в Node-RED это обычная практика программирования.
В кодовой базе Метархии теперь будем использовать void для консистентности возврата. Это системный код, в прикладном я не советую использовать void, он непривычен людям, лучше пишите длинный вариант.
Forwarded from Metarhia/NodeUA - Node.js Ukraine Community
Хорошее запоминание знаний, сигнатур методов, паттернов, алгоритмов, не делает вас автоматически профессионалом. Знания в современном мире под ногами валяются и что... значение знаний сильно преувеличено, а чем же тогда отличаются профессионалы? Только опытом и гибкостью ума, т.е. способностью переносить опыт из одной области в другую, проще в смежную, а чем выше профессионализм, тем более дальние области он может связывать. Например, перенос знаний между языками программирования — просто, между парадигмами — чуть сложнее, а вот брать из механики и электроники в программирование и обратно — это уже существенно сложнее, связывать архитектуру зданий и программ — еще сложнее, но гораздо более плодотворно, а ведь есть общие принципы у мифологии и эстетики, которые хорошо применимы в программной инженерии. Вот как вы отличаете красивый код? Как вы строите свой рассказ о шаблоне проектирования? Вас поймут и поверят только если вы обратитесь к символам и архетипам, человек так устроен, он не понимает явления иначе как через сказку, историю, миф о явлении, пусть даже в форме рационального, инженерного и научного повествования. Например, мы слышим про "блокировки" (locking api) и сразу возникают ассоциации, даже без зная теории, мы уже начинаем как-то думать про "объект" перекрывающий путь к "цели" (ресурсу), а слыша "конкурентность", "параллельность", "асинхронность" мы уже подсознательно начинаем представлять себе это в пространстве, в динамике, прям иллюстрации возникают, думать про это, как про электроны в полупроводниках совершенно непродуктивно, а как про конкретные вызовы api в платформе — слабо переносимо в другие проекты, вот мы и думаем про это единственным универсальным способом — разделяя общее на части, давая названия, создавая классификацию (объединяя в группы) и устанавливая связи между этими именами.
— Предлагаете переписать все с нуля?
— Просто переписывание не решит проблему, предлагаю переписать все два раза
— А можно делать это параллельно?
— Нет, только последовательно, первый раз мы поймем в чем проблема, а второй — уже сделаем хорошо
— Просто переписывание не решит проблему, предлагаю переписать все два раза
— А можно делать это параллельно?
— Нет, только последовательно, первый раз мы поймем в чем проблема, а второй — уже сделаем хорошо