Обновить
6
0
Александр Данилов@gen1lee

13 лет опыта коммерческой разработки

Отправить сообщение

Ок, за мной самая комментируемая статья по программированию в 2025 году. Значит не зря выбрал хабр!

Единственное что не очень радует - жалоба на низкий технический уровень статьи обычно идет без конструктивных комментариев, либо вместе с комментарием очень низкого технического уровня.

Понимаю что многим сложно думается и уточню - приведен пример с классом, и там подписок нет.

Я уже знаю куда пойдет диалог - в конструирование хелловорлд велосипедов на классах, участвовать в этом не хочу, тем более с таким «архитектором».

  1. Процедурному программированию не свойственны замыкания, функций первого порядка и иммутабельность, это во-первых. Тут прокол.

  2. Фабрика это по определению класс, а в ФП их нет. Еще прокол.

В конструктив вы не могете, советы попридержите 👍

У вас очень слабое понимание архитектуры, ваш пример даже не реактивный / событийный.

В эпл только ОС умеют писать, весь остальной софт лютый кал.

Примеры кода взяты из реальных проектов где он рефакторил. Так вот для большинства людей этот "чистый" код куда сложнее, чем можно написать что сейчас, что в то время.

И это одинаково плохо как для небольшого скрипта, так и для огромного монолита на миллионы строк.

Очевидно что плохими они были уже на момент написания книги. На С можно переписать намного проще, на фортране и паскале, и даже на java.

Нельзя писать сегодня хорошо, а завтра плохо. Ты либо крутой разработчик, либо нет. Его код - кал, который не пропустили бы на код ревью ни в одном нормальном проекте.

А надо воспринимать «как делать не нужно».

Сначала пишешь крутой код, потом уже книги. Дядя боб начал с конца.

Очередная обучалка от некомпетентного кодера, и не ленятся же еще статьи писать.

Использование классов, методов и this (особенно в JS) - антипаттерн. Выкиньте этот мусор и код станет намного проще, как сделали во всех современных библиотеках.

Кому интересно подробнее - есть статья https://habr.com/ru/articles/885980

Становиться тем кто принимает решения, аргументированно спорить.

Ответ почему они это делают есть в статье https://habr.com/ru/articles/885980

Это ждёт все ООП языки. Как говорится, «будет хуже» (с).

Нигде в статье я не предлагал избавиться от замыканий и складывания функций в мапы, хоть и процедурный подход во многих случаях - самый лучший вариант. Это все ваши фантазии. Я предлагал избавиться от классов, на что мне пытались привести примеры якобы нереализуемого кода, включая ваш, но так и не привели ни одного, потому что их не существует. А если такая уродливая конструкция как класс ничем не лучше и обладает множеством недостатков, значит ее быть не должно.

Он занимает ровно те же 78 строк

Удобно не реализовывать полностью интерфейс и конструктор сделать пустым и однострочным, что еще удалили?

И это на элементарном примере, заточенном для "У вас это не получится. В этом был весь смысл примера с кодеками."

Вы согласились написать полный пример для демонстрации вашего процедурного подхода? Согласились.

Я согласился переписать ваш код на ФП, что без проблем сделал. Про процедурный подход это вообще ваша выдумка - в статье ясно говорится в начале что такое ФП и ПП, и статья про ФП.

Ну попробуйте заменить swEncoder.requestKeyFrame() на вызов процедуры. У вас это не получится. В этом был весь смысл примера с кодеками.

Я ее заменил на вызов функции, без классов и без проблем из статьи. Хотя даже и на вызов процедуры заменить не проблема, и самое смешное что вы далее сами это делаете. Не зря статью читали (с).

Глобальные функции можно вызывать и с ООП

Во-первых функция может быть необязательно глобальная, а создана в функции конструкторе или еще где то.

Во-вторых, я рад что вы в итоге пришли к ФП и когда нужно сделать что то гибко и просто - будете его использовать, вызывая глобальные функции. Жаль только не во всех языках это можно делать, и придется создавать нетестируемые статические классы.

User.getDisplayName() из вашего примера в статье. У него тоже нет ссылок на другие методы,

Вы видимо таки не поняли о чем речь, попробую объяснить еще проще: this - это объект класса где есть все из этого класса. А значит метод жестов завязан на тип этого класса, и его нельзя переиспользовать для данных, у которых нет всего, что есть в this. То есть если в User есть метод goFckYourself, то чтобы переисолзовать getDisplayName из User нужно будет добавить в мои данные, например Dog, этот же метод, иначе никак. Более того, единственный способ их добавить это отнаследовать Doc от User, добавив таки эти методы. Надеюсь теперь понятно, если нет - тут уже ничем не помогу.

Это можно сделать и с ООП, но вы в статье все равно это указали как проблему ООП.

В статье речь про то, что в методах класса выбора нет, а в ФП выбор есть, и даже пример есть с getDisplayName - советую почитать еще раз.

В итоге ни одно ваше утверждение не доказано, ни про "у вас это не получится", ни про "у метода нет ссылок на другие методы", ни то что можно сделать this опциональным в ООП, и даже переписать на классы JS без читинга ваш собственный, якобы заточенный на превосходство ООП пример.

Полный провал.

Но хотя бы пришли к тому, что в С++ тоже можно использовать процедуры если нужно гибко и просто. Хоть что то хорошее.

PS. Сложность кода оценивается не только строчками, а в том числе количеством символов языка (типа class со всеми вытекающими из них this, наследованием, модификаторами доступа и тп), багоемкостью (типа попытки передать метода класса как параметр, получая вместо this undefined) и прочими проблемами, перечисленными в статье. Тут у вас тоже полный провал.

Все различия связаны с синтаксисом языков JavaScript/CPP

Нет, в JS тоже есть классы и вся эта ерундистика. Я использовал более лаконичный и простой подход без лишних символов. И по сторчкам, и в целом по символам вышло меньше. Даже на специально выбранном вами примере и с точно таким же подходом без особого рефакторинг.

Методы encode и requestKeyFrame в вашей реализации тоже приколочены к this. Например если вы захотите вызывать один метод из другого, вы будете использовать this

  1. Они вообще никуда не приколочены и там нет ни одного символа this.

  2. Более того у стрелочных функций что я использую в принципе нет this.

  3. Этот пример полная копия вашего, только без классов.

Эти функции можно без проблем вынести в процедуры если возникнет такая необходимость, например:

// Аргументы только те, что используются, ничего лишнего
const encodeVp9S = (frame: Frame) => {
  // ...
}

const makeVp9SWEncoder = (): Encoder => ({
  encode: encodeVp9S
});

У вас эти методы зависят даже не от класса, а вообще от конкретного объекта.

Ограничений здесь нет, см. пред. пример.

У вас то же самое, методы encode и requestKeyFrame "требуют для работы" все методы, которые есть в объекте где они объявлены.

Опять ошибка - где они это требуют? У них даже ссылки нет друг на друга))

У вас аналогично, нельзя использовать метод без создания объекта где он содержится.

И тут ошибка - если нужно то можно - см. пред. пример.

Сможете обработать в ваших методах ситуацию, когда encoder null или undefined? Я в этом сомневаюсь.

const encodeVp9S = (frame?: Frame) => {
  if (!frame) return null
  // ...
}

encoder?.encode()
encoder?.requestFrame?.()

А в замыкании ситуакция когда оно null невозможна.

Итого, написанное калькой ваше же решение, которое лично я бы писал по другому, более лаконичное и не имеет никаких ограничений.

Какой то детский сад а не код)) Даже не буду рефакторить, выложу то же самое (78 строк).

type Encoder = {
  encode: (frame: VideoFrame) => BitStream;
  requestKeyFrame?: () => void;
};

const makeVp9SWEncoder = (): Encoder => ({
  encode: (frame) => {
    // кодируем через libvpx
  },
});

const makeVp9HWEncoder = (): Encoder => ({
  encode: (frame) => {
    // Вызываем функции ОС чтобы драйвер видеокарты что-то закодировал
  },
});

const makeSoftwareFallbackEncoder = (swEncoder: Encoder, hwEncoder: Encoder): Encoder => {
  let isFallback = false;
  
  return {
    encode: (frame) => {
      if (!isFallback) {
        const encoded = hwEncoder.encode(frame);
        if (!encoded.isError) return encoded;
        isFallback = true;
      }
      return swEncoder.encode(frame);
    },
    requestKeyFrame: () => {
      if (isFallback) swEncoder.requestKeyFrame?.();
      else hwEncoder.requestKeyFrame?.();
    }
  };
};

const makeEncoder = (codec: Codec): Encoder => {
  switch (codec) {
    case 'vp9f': return makeSoftwareFallbackEncoder(
      makeVp9SWEncoder(), makeVp9HWEncoder()
    );
    case 'vp8f': return makeSoftwareFallbackEncoder(
      makeVp9SWEncoder(), makeVp9HWEncoder()
    );
    case 'vp9s': return makeVp9SWEncoder();
    case 'vp9h': return makeVp9HWEncoder();
    case 'vp8h': return makeVp9HWEncoder();
    case 'vp8': return makeVp9SWEncoder();
    case 'vp9': return makeVp9SWEncoder();
    case 'h264': return makeVp9HWEncoder();
  }
};

const main = () => {
  // ...
  const codecs = getCodecs(); 
  const encoders = codecs.map(makeEncoder)

  while (true) {
    const event = getEvent();
    if (!event) break;
    
    switch (event.type) {
      case 'gotFrame': {
        for (const encoder of encoders) {
          encoder.encode(event.getFrame());
        }
        break;
      }
      case 'requestedKeyFrame': {
        for (const encoder of encoders) {
          encoder.requestKeyFrame?.();
        }
        break;
      }
    }
  }
};


Вы сами скинули ссылки на два куска кода, и плюс еще просите учесть свой кусок кода. У меня аналогичные куски кода.

Приведите сами ВЕСЬ код а не несколько кусков, потом поговорим.

1
23 ...

Информация

В рейтинге
6 537-й
Откуда
Санкт-Петербург, Санкт-Петербург и область, Россия
Зарегистрирован
Активность

Специализация

Фронтенд разработчик, Разработчик мобильных приложений
Ведущий