HowProgrammingWorks - JavaScript and Node.js Programming
6.33K subscribers
308 photos
7 videos
1 file
749 links
Программная инжененрия для JavaScript, TypeScrip, Node.js 👉 Group: https://t.me/MetarhiaHPW 👉 Node.js channel: https://t.me/metarhia 👉 Node.js group: https://t.me/nodeua
Download Telegram
Вот кейс как Хамид из Пакистана с 4 годами опыта с ИИ обогнал... https://twitter.com/tshemsedinov/status/1664975963564769280
Я думаю, что мультипарадигменное программирование и знание нескольких языков программирования — это ключ к тому, чтобы не стать чудовищем. Человек с парадигмальным и языковым шовинизмом среди программистов выглядит как фанатик и всегда сделает решение хуже, чем человек, умеющий свободно использовать в одном коде приемы процедурного, структурного, объектно-ориентированного, функционального, автоматного, реактивного и других парадигм, таким образом, чтобы они не мешали друг другу, а органично сочетались. Это примерно как на эфирах на Альфе сочетаются разные языки и мировоззрения, от чего их смотреть интереснее, чем пропаганду на зомбоящике.

Есть еще техники программирования, как асинхронное программирование и параллельное, или обобщенное, потому, что они не бывают сами по себе, для них нужна парадигма-носитель, например для асинхронного нужно или ооп с шаблоном 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/b385d6667789e0fbecdca051f8b4edda5841acd9
Не только 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. Научился писать круды — устроился формошлепом.
2. Научился делать масштабируемые, надежные, высоконагруженные распределенные системы — устроился формошлепом.
💡 Паттерны проектирования для 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, мы так привыкли к этому, но в других языках это традиционно делается через наследование.
По паттерну 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) - все части кода становятся более зависимы друг от друга благодаря всему вышеописанному, и пошевелишь одно, а ломается в другом месте.