Цикломатическая сложность кода. Как её снизить?

แชร์
ฝัง
  • เผยแพร่เมื่อ 22 ม.ค. 2025

ความคิดเห็น • 172

  • @venan5245
    @venan5245 2 หลายเดือนก่อน +18

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

    • @VladimirNerby
      @VladimirNerby 2 หลายเดือนก่อน +1

      Я при описании функции в самом начале уже поставил себе условие: если больше 20 строк, то попробовать сократить/упростить

  • @gi9ex70
    @gi9ex70 3 หลายเดือนก่อน +6

    Дружище, огромное спасибо за видеоролик. Очень информативно и интересно. Продолжай в том же духе) Жду следующего видева

  • @Dadadadam999
    @Dadadadam999 2 หลายเดือนก่อน

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

  • @happy_cutman
    @happy_cutman 3 หลายเดือนก่อน +19

    Спасибо большое за видео, особенно, за два последних концепта, поддержите автора, человек бесплатно делает очень полезный контент

  • @АлександрКнязев-ю1в
    @АлександрКнязев-ю1в 2 หลายเดือนก่อน +2

    Классно, приятно слушать человека который сам понимает то, что говорит👍Спасибо!

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน +1

      Спасибо, за добрые слова!

  • @holypowerenjoyer6059
    @holypowerenjoyer6059 2 หลายเดือนก่อน +1

    Годный видос, своей подачей и типажем чем то напоминаешь ulbi tv, продолжай пилить видосы, друг

  • @billgrover3130
    @billgrover3130 2 หลายเดือนก่อน

    Классно всё разжевано. Подробно. Огонь!

  • @thats_embarrassing_JS
    @thats_embarrassing_JS 3 หลายเดือนก่อน +8

    Очень классное видео, которое будет полезным для начинающих. Автор красава.
    Единственный недочёт - последний пример не является реализацией паттерна Состояние. Данный паттерн предполагает, что состояние объекта может меняться. Логика изменения состояния описывается либо в классе, реализующий конкретное состояние, либо же в основном классе, в котором состояние меняется. А данный пример корректней было бы назвать реализацией паттерна Стратегия, только вместо функции, которая требует, чтобы класс реализовывал конкретный интерфейс(в нашем случае, классы наследуются от абстрактного класса ShapeState), используется класс Shape.

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      Спасибо!

  • @vividbw
    @vividbw 2 หลายเดือนก่อน +2

    26:58 вы описали паттерн «Стратегия», а не «Состояние».
    Их легко спутать, так как диаграммы классов у них похожи.
    Различие между ними в том, что стратегию передает клиент снаружи (как у вас), а состоянием управляет сам объект. В случае паттерна «состояние» объекты состояний обычно хранят ссылку на контекст, чтобы переходить между состояниями, либо принимают контекст в качестве параметров своих методов (если один и тот же экземпляр состояния может использоваться разными контекстами).

  • @shvedovdanil
    @shvedovdanil 2 หลายเดือนก่อน +45

    Есть легенда, что светлые программисты для замены цепочки if придумали switch, но перешедшие на тёмную сторону тимлиды стали распространять грязные слухи о безвкусии переключателя и о нём уже мало кто помнит. Я же скажу "Switch жив!"

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน +4

      Тоже верно. В определённых ситуациях switch вполне хорош

    • @ПавелФомин-ъ4с
      @ПавелФомин-ъ4с 2 หลายเดือนก่อน +4

      switch хорош только до тех пор, пока возможно его применить. и кто сказал, что switch не является ветвлением? разница какая? 😊

    • @ПавелФомин-ъ4с
      @ПавелФомин-ъ4с 2 หลายเดือนก่อน +2

      а вообще конечно стейты рулят 😅

    • @shvedovdanil
      @shvedovdanil 2 หลายเดือนก่อน +7

      @@ПавелФомин-ъ4с Все инструменты хороши, пока их можно применить. Никогда не видел код, который был бы хорош там, где его невозможно применить. В видео автор не избавлялся от ветвления, а делал его более читабельным для человека и более рациональным. Про return из разных мест рассказал, а вот про continue и break в циклах не стал упоменать.

    • @БоряДикий
      @БоряДикий 2 หลายเดือนก่อน +1

      В питоне лучше словарь юзать

  • @roman-berezkin
    @roman-berezkin 2 หลายเดือนก่อน

    Классное видео, крайне лаконичное. Спасибо!

  • @cliffa-net
    @cliffa-net 2 หลายเดือนก่อน +7

    Данное сообщение НЕ является критикой видеоматериала автора, но является попыткой углубить понимание автора в суть программирования на примере конкретного его видео. Ну и пожалуй, я не претендую на истину в последней инстанции, это всего-лишь выкладки на основе многолетнего опыта программирования.
    ____________
    Сначала по поводу читаемости кода. Дело в том, что лично я бы выделил всего-лишь один постулат читаемости - это всегда компромис между двумя параметрами:
    1. Размер кода - как длина строки, так и количество строк - чем меньше, тем лучше. Сюда же можно отнести - чем меньше всяких синтаксических обвязок, которые не несут никакой логической нагрузки, а только оформляют код, тем лучше.
    2. Понимаемость записанного кода.
    Эти два пункта противоречат друг другу. И читаемость кода - это выверенный баланс между ними. И все пляски вокруг читаемости - они все вокруг этого.
    Когда вы приводите пример преобразования одного варианта написания в другой - попробуйте оценить, с т.з. какого из этих двух пунктов стало легче. И насколько итоговый баланс стал лучше. Я в видео почти не встретил таких примеров.
    __________
    Теперь о сути ваших примеров. Везде вы приводите примеры с т.з. борьбы ЯП с самим собой. И так же везде вы приводите код, который не соответствует логике задачи, который мы потом исправляем, приближая её именно к логике задачи. А я как раз пропагандирую опираться не на инструменты ЯП в первую очередь, а как раз исходить из логики задачи, а потом уже смотреть, какой инструмент для реализации лучше использовать.
    И на примере самого последнего вашего примера давайте рассмотрим, что я имею ввиду. Вот у вас есть по сути два объекта (в человеческом понимании, в отрыве от ООП), с которыми надо что-то сделать. По сути - это банальное двух-уровневое дерево условий. На одном из уровней мы определяем, что за фигура (круг/треугольник), на другом - какое действие мы с этим будем делать (рисовать/изменять). А вот, какой уровень первый, а какой второй - это определяет задача!!! Не ЯП и его методы.
    Есть всего два варианта условных переходов: статический (перебор if-else) и динамический (когда мы выполняем переход к метке, которая хранится в переменной). Первый вариант - это все свитч-кейсы, циклы, любые условные операторы. Второй вариант - это полиморфизм, указатели на функции. Объекты "ключ-функция" - это гибрид первого и второго. В вашем примере оба уровня (выбор фигуры или действия) можно представить обоими способами. И опять же - эффективность выбора зависит в первую очередь от задачи, а так же от сложности реализации в конкретном ЯП. В общем случае state-вариативность всегда эффективнее выражать динамическим вызовом - т.е. вы машине предлагаете не перебрать кучу вариантов, которые заранее известны, а сразу в код закладываете, куда пойти, без перечислений. Это и с т.з. восприятия кода обычно проще, но тут индивидуально. А вот статическая вариативность гораздо лучше работает на любых других условных операторах, кроме == (например a

    • @DobinSergei
      @DobinSergei 2 หลายเดือนก่อน

      "... Вы прослушали лекцию профессора МГУ Васи Галушкина, об особенностях грамотной речи во время секса." 👏😃

    • @cliffa-net
      @cliffa-net 2 หลายเดือนก่อน

      @@DobinSergei цель моего "высера" я сразу же обозначил. А цель вашего?

    • @-unity-
      @-unity- 2 หลายเดือนก่อน +1

      Сразу чувствуется многолетний опыт работы! Я тоже голосую обеими руками за читаемость кода, даже в ущерб различным паттернам проектирования/программирования, которые стало модно пихать куда не попадя. Одного взгляда на функцию должно быть достаточно, чтобы понять, ЧТО она делает. Возможно, этого будет недостаточно, чтобы понять, КАК она это делает, но это уже вторично. Когда приходит время вносить какие-то изменения в код, нужно первым делом понять, а куда их вносить? Поэтому почти всегда читаемость превыше всего.
      Бывают, конечно, куски кода, которые должны работать очень быстро. И тут приходится применять приёмы, которые могут быть трудны для восприятия, но именно здесь критична скорость. Однако, такие куски встречаются далеко не всегда.
      P.S. высером ваш текст я не считаю. Изложены довольно глубокие мысли. А кому трудно читать объёмные тексты - пусть проходят мимо. Видимо, ещё созрели.

  • @МирославМилаев
    @МирославМилаев 3 หลายเดือนก่อน +1

    Спасибо! Оказывается паттерны в JS можно применять чаще чем кажется )

  • @sergeysoprunovvv9656
    @sergeysoprunovvv9656 2 หลายเดือนก่อน

    Спасибо за видео!

  • @DobinSergei
    @DobinSergei 2 หลายเดือนก่อน +1

    16:08 - можно было в данном примере, вместо интерфейса, сделать наследование всех трёх классов от общего.
    Куда вынести виртуальный метод send.
    И заодном конструктор, который в данном случае одинаковый. Чтобы 3 раза не писать одно и то же.
    И в функцию передавать общий класс, где вызывать его метод send.
    В принципе делает то же самое. Если помимо этого у интерфейса не будет другого функционала, требующего именно возможности интерфейса.

    • @enosunim
      @enosunim 2 หลายเดือนก่อน

      А функцию вообще убрать и просто вызывать send у объекта = )))))
      Мы изобрели объектно-ориентированное программирование = )))))

  • @trypophobia7497
    @trypophobia7497 2 หลายเดือนก่อน

    Спасибо за видео! Конечно это специально простые примеры, но смешно смотреть, когда ради одной функции, нужно создать интерфейс и класс, чтобы реализовать стратегию)))) Думаю, для такого случая лучше подойдёт функция, которая принимает
    callback. Вот вам и стратегия на минималках)

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน +1

      Это просто пример. Чтобы не терять время. И не засорять внимание зрителя.

    • @trypophobia7497
      @trypophobia7497 2 หลายเดือนก่อน

      @@easydev1205 хорошо😁

  • @wylysypydystyshky
    @wylysypydystyshky 2 หลายเดือนก่อน

    7:35 для ясности кода несколько возвратов return должны выглядеть однородно, стоять на одном уровне вложенности, возвращать одинаковый тип, а ещё лучше будет, если множество значений функции конечно.

  • @88coolv
    @88coolv 2 หลายเดือนก่อน +22

    1. цикломатическая сложность определена только для структурных программ. Если в программе есть хоть что-то из: ФВП, виртуальные вызовы, указатели на функции, вычисляемые переходы и т.п. конструкции, то цикломатическая сложность становится неопределенной. Поэтому невозможно снизить цикломатическую сложность при помощи всяких filter/reduce, полиморфизма и других таких вещей.
    2. цикломатическая сложность от использования ранних возвратов не уменьшается, а растет. Поэтому практически всегда ранние возвраты не рекомендуются - они существенно снижают читабельность кода и усложняют его поддержку.
    3. Использование хештаблиц и любых других подобных подходов, естественно, ни как не снижает цикломатическую сложность.

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน +1

      Приняли. Будем иметь в виду.

    • @maxlight4321
      @maxlight4321 2 หลายเดือนก่อน +9

      Согласен почти со всем. Перечисленные вещи не понижают циклометрическую сложность, а повышают читаемость кода.
      А вот насчет early return я не согласен. Early return помогает убирать «гнезда» из вложенных условий, что очень сильно помогает при чтении кода

    • @88coolv
      @88coolv 2 หลายเดือนก่อน

      @@maxlight4321 > Early return помогает убирать «гнезда»
      он при этом усложняет семантику.
      вот код:
      if (predicate()) {
      ...
      }
      doSomething();
      не зная, что стоит вместо многоточия, ответь - выполняется или нет doSomething()? Это нельзя сделать. Если же код не имеет ранних возвратов, то он структурирован так что мы всегда можем узнать все условия выполнения, не заглядывая внутрь самих иф-блоков, что существенно снижает когнитивную нагрузку при чтении.

    • @enosunim
      @enosunim 2 หลายเดือนก่อน

      Никто не заставляет вас делать гнезда, можно просто сделать перменную условно re_turn и так же навешать вагон ифов, как и в примере с ретернами и проверять, если !re_turn то выполнять следующий блок кода.
      Зато если функцию нужно будет доработать. Например в конце нужно фильтровать как-то результат или изменить его формат вывода или еще что-то, нужно будет исправить только один return, а не переписывать всю функцию с миллионом ретурнов. Или еще веселее, когда там всего пара ретурнов и есть ретурн в конце. Вот это ржака бывает, если не проверил, что оказывается какой-то умник добавил там ранние возвраты в середине.

  • @azzzn-m8h
    @azzzn-m8h 2 หลายเดือนก่อน +1

    а чем полиморфизм отличается от State pattern?

  • @serb1146
    @serb1146 2 หลายเดือนก่อน

    Пример с фигурами лучше было использовать для объяснения полиморфизма подтипов! Многоформенность! Формы фигур же! А вот способ доставки можно было использовать для State pattern, за исключением что там еще добавлен static Factory method (зачем?). С Value Object - придется вам перечитать теорию снова, и обратить внимание на слово equality и задуматься почему это так важно. Лайк, однозначно!

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน +1

      Спасибо! И почему же важно?

    • @pinkierar_real
      @pinkierar_real 2 หลายเดือนก่อน

      @@easydev1205 возможно, для сравнения объектов не по полю, а по ссылке

  • @Emagnarium
    @Emagnarium 2 หลายเดือนก่อน

    Хорошо раскрыл тему. Да, опустил многое, но, в целом, ревьювить код таких джунов стократ проще, а ошибок в десять раз меньше (обычно)
    Что опустил, если вдруг кому нинтересно:
    Тут не упомянуто, что подход функц.программирования, строго говоря, повышет цикломатическую сложность
    Не объяснил, а зачем вообще битва за чистые функции и почему на практике юзают "условно" чистые функции
    Не упомянуто, почему цикл это +1, а не +бесконечность (ведь из первого определения звучит так, что если есть цикл, то есть бесконечно путей пробежать по графу алгоритма)
    Ну и опасности использования .reduce/.map/.filter в высоконагруженных модулях системы (например, отрисовка графиков на бирже, там за цепочки пальцы отрубать должны)
    И да, использование тернарника (?:), равно, как использования switch ц.сложность алгоритма не снижает, а демки в первую очередь про читаемость и уменьшение вероятности ошибки
    Но опять таки база есть, две предметные области раскрыты. Понимание дано, а если не приплести одно к другому, то и на собесе не провалитесь.

  • @enosunim
    @enosunim 2 หลายเดือนก่อน +1

    Как снизить цикломатическую сложность и запутать код еще больше = ))))
    Особенно люблю всякие ехал мап через мап, видит мап в мапе мап, сунул мап мап в мап, мап за мап мап мап!
    И потом клиент просит доработку, где если бы код был цикломатически сложным, т.е. на нормальных ифах и циклах, то просто вставить строчку в нужное место. А тут, надо сначала код переписать, потом вносить правку. = ))))
    Тоже самое касается всяких стрелочных функций, вопросиков с двоиточиями и т.д. Да где-то уместно, но универсальной пилюлей не является.
    Конечно те или иные подходы могут найти своё применение. Но по сути, снижение этой самой сложности это скорее оптимизация. А оптимизируют приложение только в том случае если оно не укладывается в ТЗ и только те модули которые не укладываются, а оптимизация ради оптимизации это уже от лукавого!

  • @yarikv4133
    @yarikv4133 2 หลายเดือนก่อน

    по поводу раннего выхода конечно тоже есть разные мнения. есть такие товарищи которые утверждают что точка выхода должна быть одна потому как множественные ухудшают читаемость кода. и не брезгуют для этого использовать goto)

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน +1

      Да, много разных товарищей есть) Не на всех внимание обращать стоит

  • @tontontonic
    @tontontonic 3 หลายเดือนก่อน

    последний пример я чет не особо и понял)
    например в первом варианте, где внутри класса иф-елсе в зависимости от передаваемого типа - так я могу например массив типов запустить в цикле и получить нужные значения, так как все ветвления в классе
    в решении же мне нужно создать класс под каждый тип и все равно нужно понимать какого класса передо мной объект, чтоб получить нужное значение
    типа в первом варианте я могу сделать так
    let result = {}
    types.forEach(type=>{
    result[type] = new Shape(type)
    })// let a = result.circle.draw() ну или что то подобное
    во втором же мне придется делать то же самое ветвление, только не внутри класса, а уже внутри цикла, типа (if type == 'circle') result[type] = new Shape(new CircleState())
    то есть ветвление ни куда не делось, а просто переходит на уровень выше?) и кода больше, мне как-то не ясна выгода
    хотя скорее всего я просто что-то не понял)

  • @fuad2069
    @fuad2069 3 หลายเดือนก่อน

    Спасибо))

  • @geoffreycollins6627
    @geoffreycollins6627 2 หลายเดือนก่อน

    Спасибо за видео.
    в блоке с полиморфизмом/стратегией мне не понятно вот что:
    в изначальной "плохой" реализации сущность сообщения у нас объект, что заставляет думать, что мы изначально не знаем, какой тип сообщения мы должны отослать, поэтому и пишем условия внутри функции.
    а во второй "правильной" реализации мы как будто уже знаем, какой тип сообщения хотим отослать, "оборачивая" строку нужным классом.
    Но как быть все-таки если мы не знаем тип сообщения заранее? Например, если нам пришел ответ с вот таким объектом, как в изначальном примере, и исходя из того, что у него внутри, нужно выбрать необходимую стратегию отсылки? Получается, опять те же if-ы использовать?

    • @MrDerReiter
      @MrDerReiter 2 หลายเดือนก่อน

      Это распространённая проблема. Так или иначе нам всё равно где-то в коде нужно будет сделать выбор (выбрать конкретную стратегию, конкретную реализацию интерфейса, составить пары ключ-значение и т.д.), вопрос лишь в том где именно это сделать, и насколько аккуратно и читаемо это будет оформлено.
      Обычно решается паттерном "Фабричный метод" (т.е. по сути if/else все переносятся в одно место; инкапсулируются, чтобы не мозолить глаза по всему коду); или через внедрение зависимостей и DI-контейнеры (более сложное в плане реализации, но более изящное и поддерживаемое в долгосрочной перспективе решение).
      Подробности реализации обьяснять не буду, много текста выйдет. Просто погуглите Factory Method и Dependency Injection.

  • @ne4to777
    @ne4to777 หลายเดือนก่อน

    А где решение первой задачи?

  • @aleks_versus
    @aleks_versus 2 หลายเดือนก่อน

    То есть цикломатическая сложность кода - это визуальная сложность кода? А когда я засуну цикл в функцию и потом буду эту функцию юзать, то цикломатическая сложность кода типа уменьшится?

  • @AlekseiBleile
    @AlekseiBleile 2 หลายเดือนก่อน

    только хотел сказать что где же она чистая если у нее руки в 26 строке испачканы, а ты сам подправил.
    люблю когда возникает замечание, а автор сам тут же отвечает. как будто интерактив)0

  • @user-PZXhgp9wft293
    @user-PZXhgp9wft293 2 หลายเดือนก่อน

    Сказки для самых маленьких.
    Есть сложность предметной области. Если к примеру у вас 3 типа договоров и 3 типа клиентов, то рано или поздно эти типы и связи между ними будут где-то фигурировать. Или в программе вы их внесете или в базу данных или в текстовый файл.
    Но есть принципиальные вещи, которые делают программу дурако-устойчивой или неустойчивой.
    Например если программист пишет
    if( type==1){
    code1
    }
    if( type==2){
    code2
    }
    то программа получается неустойчивой к появлению новых типов. Если админ добавит type==3, то программа посыпится с большой вероятностью. А когда кодовая база будет несколько гигабайт, то дырку найдут только через месяц, когда у какого нибудь клиента что-нибудь отвалится.

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      Обозначил

    • @slaval5088
      @slaval5088 2 หลายเดือนก่อน

      Почему добавление 3 вызовет осыпание кода ? Допустим, что последовательность проверок правильная.
      Как добавить 3 правильно ?

    • @user-PZXhgp9wft293
      @user-PZXhgp9wft293 2 หลายเดือนก่อน

      @@slaval5088 потому что обычно пишут
      что-то типа
      select type
      from person
      where person=:id
      if( type==1){
      action=1;
      }
      if( type==2){
      action=2;
      }
      ну и при появлении нового типа тут будет неопределенное поведение
      Правильно писать
      if( type==1){
      action=1;
      }else if( type==2){
      action=2;
      }else{
      error('unknown type');
      }

    • @user-PZXhgp9wft293
      @user-PZXhgp9wft293 2 หลายเดือนก่อน

      @@slaval5088
      если написать
      if( type==1 ){
      premium = 100 руб;
      }
      if( type==2 ){
      premium = 200 руб;
      }
      тогда когда админ добавит новый тип работников, то эти новые премию не получат
      Лучше сразу глушить непонятные для программы варианты
      if( type==1 ){
      premium = 100 руб;
      }else if( type==2 ){
      premium = 200 руб;
      }else{
      error('premium not defined');
      }

  • @DobinSergei
    @DobinSergei 2 หลายเดือนก่อน +1

    14:47 - плохая идея использовать строковый тип для проверки условий. Если изначально это не функция для работы со строковыми данными.
    Не знаю есть ли в JS, но во многих языках для этого есть перечисляемый тип (enum). Который по сути числовая константа на уровне компилятора.
    Тогда просто сравниваются 2 числа. Что работает быстрее, в космических масштабах!
    Чем сравнение 2 строк, где цикл в цикле для сравнения познаково.

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      в js нет enum. Есть в TS - но его использование никак не влияет на скорость работы. Как и во многих других языках

    • @DobinSergei
      @DobinSergei 2 หลายเดือนก่อน

      @easydev1205 ну нифига себе "не влияет"! Вообще-то выше подробно объяснено, как именно влияет.

    • @enosunim
      @enosunim 2 หลายเดือนก่อน +1

      Сишник никогда не поймёт питониста = )) Хотя сишники пишут для него модули = ))))

    • @kaiuandrey
      @kaiuandrey 2 หลายเดือนก่อน

      @@enosunim сишник понимает как это выглядит на уровне ассемблера. Для си++ передав тип уже компилятор знает, с какой функцией связать и проверок лишних не будет. Ну и if else f else все же приходится применять в сложных случаях, когда входные данные не из множества предопределенного, но тогда более вероятное событие обрабатываем в первом if... но проблема в том, что более вероятное может и поменяться :), так что иногда все не просто, как и при обработка данных в БД или в ИИ.

    • @enosunim
      @enosunim 2 หลายเดือนก่อน

      @@kaiuandrey сишник понимает как это выглядело бы на уровне ассемблера если бы было написано на си = ))) Забывая, что в скриптовых языках за счет магии тумба-юмба совершенно не оптимальный с точки зрения сишника код, с множественными вызовами всяких методов будет работать быстрее, чем "правильный" с точки зрения сишника код, написанный разумеется на этом же тормозном языке.

  • @nataliepodgainova6582
    @nataliepodgainova6582 3 หลายเดือนก่อน

    || "unknown command" что значит? Что на все другие команды, которых нет в ключах, будет давать результатunknown command? Что в это случае значит || ? Я думала это or, но не знала, что ее можно засунуть в print? Или я неправильно поняла?

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      не понял

    • @nataliepodgainova6582
      @nataliepodgainova6582 2 หลายเดือนก่อน

      12:22 9 строка что означает || ?

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      а, ну это просто значит что если левая часть от || будет undefined то вернётся правая. Типа return commandActions[command] ? commandActions[command] : "Unknown command"; и тд по-разному можно это записать

  • @DobinSergei
    @DobinSergei 2 หลายเดือนก่อน +1

    5:07 - по этой причине, мы имеем то что имеем 😏
    Страдает оптимизация в угоду читаемости.
    Программы с одним и тем же функционалом, раньше летали на старом железе. А на новом тормозят и глючат...
    При том что мощь самого железа постоянно увеличивается.
    И занимаемое на диске место раздувается.
    Железо со временем развивается, а софт деградирует.
    Пора бы менять подход к разработке.

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      а какие именно программы тормозят и глючат? Я не замечал. И там ссылка на пример с разбиением на функции. Из-за того что одну огромную функцию разбили на несколько маленьких программа глючить начинает?

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      какие именно программы тормозят и глючат? программы разные бывают. Я в целом не замечал такого. И ссылка на пример с разбиением на функции. Из-за того что одну гигантскую функцию разбивают на несколько маленьких программа глючить начинает?

  • @MaxPV1981
    @MaxPV1981 2 หลายเดือนก่อน

    Уже самое начало не соответствует действительности - по приведённому определению: "... количество линейно независимых маршрутов через программный код".
    В приведённом графе в википедии с двумя циклами это три, потому что один маршрут без выполнения условий для циклов, и ещё два на каждый цикл (подразумевается, что условный по определению), которые могут выполняться, а могут нет. Это элементарная комбинаторика.
    И тут Вы говорите, что ЦС алгоритма с двумя условными операторами - 3.
    Но Вы ведь сами до этого прочитали: "если исходный код не содержит никаких точек ветвления или циклов, то сложность равна единице, поскольку есть только единственный маршрут через код.
    Если (!) код имеет единственный оператор IF, содержащий простое условие, то существует два пути через код: один если условие оператора IF имеет значение TRUE и один - если FALSE."
    Вы вообще понимали то, что читали?
    Итого ЦС представленного алгоритма 4 - это элементарно считается вручную (количество сочетаний из 4 по 2). "Сама функция" никак не может быть независимым маршрутом через программный код", если там нет условного оператора, который делает выполнение указанных двух условных операторов невозможным.

  • @_M.i.h.a.i.l._
    @_M.i.h.a.i.l._ 2 หลายเดือนก่อน

    Я понимаю, что видос полезный, но где в заголовке наименование языка?

  • @MrTruth2
    @MrTruth2 2 หลายเดือนก่อน +1

    Все это баловство заканчивается в embedded

    • @JingoBo
      @JingoBo 2 หลายเดือนก่อน

      Не заканчивается. Ранний выход, тернарный оператор. Полиморфизм даже на Си адекватно реализуется.

    • @MrTruth2
      @MrTruth2 2 หลายเดือนก่อน

      @JingoBo никто и не спорит , что реализуется. Другой вопрос какой ценой и есть ли на это ресурсы.

  • @FDsagizi
    @FDsagizi 2 หลายเดือนก่อน +1

    Да, только многие примеры будут работать сильно медленнее 😉

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      Не страшно. Прямо сильно медленнее будут если там гигантские объемы данных будут. Для большинства разработчиков это неактуально

    • @enosunim
      @enosunim 2 หลายเดือนก่อน

      Для большинства разработчиков неактуальна цикломатическая сложность кода = ))))

  • @dmitriydobrynin9528
    @dmitriydobrynin9528 3 หลายเดือนก่อน

    Сам реализовывал паттерн Стратегия, чтобы рендерить ячейки сложной таблицы в зависимости от входных данных, а потому пример со Стратегией понял, естественно, легко. Но вот чем точно отличается паттерн Состояние от Стратегии вообще не осознал :(
    UPD: Наверное, понял. Отличается тем, что в Состоянии мы прокидываем конкретный экземпляр класса в конструктор, а в Стратегии мы ВЫЗЫВАЕМ функцию, которая дергает нужный метод у экземляра того класса, который в эту функцию прокинут.
    Но вообще очень похожи два эти паттерна, вот прям когда лучше один, а когда другой не понимаю. Подскажите?

    • @alekseyilin6605
      @alekseyilin6605 3 หลายเดือนก่อน +1

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

    • @dmitriydobrynin9528
      @dmitriydobrynin9528 3 หลายเดือนก่อน

      @@alekseyilin6605 примерно разобрался, спасибо. Как я понял, с вызовом метода, Состояние меняет объект от которого может вызывать дальнейшие методы определенного ранее общего интерфейса.

  • @baileysli6235
    @baileysli6235 3 หลายเดือนก่อน +2

    7:55 код с методами массива хуже, потому что дважды идёшь по массиву

    • @easydev1205
      @easydev1205  3 หลายเดือนก่อน

      да, тоже верно, но наверно в 99% случаев это нестрашно

    • @thats_embarrassing_JS
      @thats_embarrassing_JS 3 หลายเดือนก่อน

      Это некритично, если сам массив небольшой.

    • @rshirkhanov
      @rshirkhanov 3 หลายเดือนก่อน

      Можно использовать итераторы, в таком случае обход коллекции будет единственным

    • @nataliepodgainova6582
      @nataliepodgainova6582 3 หลายเดือนก่อน

      ​@@rshirkhanovа как их использовать?

    • @sacinandan_kisor
      @sacinandan_kisor 2 หลายเดือนก่อน

      А можно юзать reduce()

  • @vlad3c
    @vlad3c 2 หลายเดือนก่อน +1

    по ролику:
    "return" да, когда что то не прошло условие смысл выполнять дальнейшие проверки. Профит однозначно.
    "подходы функционального программирования" вообще не профит. внезапно метод filter с условием под капотом оказывается тем же циклом, который проверяет условие, т.е. тот же for и тот же if, других инструментов работы с массивом нет в принципе, если в нем надо что то найти надо пройти по нему циклом и никак иначе. Более лаконичная запись - да, удобочитаемость - нет(что делает цикл понятно с ходу, что делает метод, надо смотреть), быстродействие - тоже нет, сначала мы проходим по массиву чтобы найти нужные элементы, узнаем их индексы или копируем, потом проходим вторым циклом по этим элементам +память +время.
    "хэш-таблицы" - возможно да, НО только при больших объемах разносортных данных или строковых параметрах, если у вас 1-3 if то быстрее будет работать if, если данные числовые и по порядку лучше взять switch. В случае с хэш таблицей, подаются данные на вход хэш функции, которая вычисляет индекс в массиве и мы переходим по этому индексу, узнаем какую функцию выполнить, выполняем. В случае со switch, данные проверяются, что они укладываются в интервал значений switch'a и в таблице переходов(массив меток) выбирается переход под этим индексом, без каких либо вычислений, выполняются операции. Очень спорно зачем это прятать в хэш-таблицы? Лучше уж добавить числовой параметр и по нему в свиче определять переход, это будет работать быстрее, чем хэш-таблица.
    "тернарный оператор" однозначно нет, это тот же if просто в другой записи, никакой сложности он не снижает. да более лаконичная запись получается, но по факту это тот же if написанный в другой форме, ни больше ни меньше. (вообще смотря ролики python или js программистов создается впечатление, что они считают более короткая запись = быстрее выполняется, но увы это не всегда так, и может быть вполне наоборот)
    "полиморфизм" - да, по сути вызываются разные функции в зависимости от типа данных аргумента. суть полиморфизма
    "value objects" - да, снижение за счет использования дополнительной памяти. По сути мы к классу добавляем значение, которое уже используется в вычислениях.
    "state pattеrn" - да, разные классы для разных типов, значит разные методы. то же самое что с полиморфизмом, но другим способом

    • @enosunim
      @enosunim 2 หลายเดือนก่อน

      По поводу фильтров и прочего. Нечитаемость согласен. Быстродействие не согласен.
      Во всяких скриптовых языках типа пейтона (да я знаю что пайтона) писать цикл это капец как долго. Вызывать тридцать три цикла, но через методы написанные на сях - супер быстро. = )))

  • @alexperemey6046
    @alexperemey6046 3 หลายเดือนก่อน +4

    Ты нмкак не уменьшаешь цикломатическую сложность переписыванием синтаксиса. 1) 1) Цикломатическую сложность определяется количеством тестов, которые тебе придется написать для твоего кода. Это написано в той статье, которую ты цитировал.
    Количество тестов, покрывающих все варианты у тебя не меняется.
    2) Циклы не имеют никакого отношения к цикломатическую сложности, поскольку не создают новых вариантов выполнения.

    • @easydev1205
      @easydev1205  3 หลายเดือนก่อน +1

      Спасибо за комментарий и за мнение.

    • @alexperemey6046
      @alexperemey6046 3 หลายเดือนก่อน +4

      @@easydev1205 Прочти внимательно ту статью в википедии, которую ты же сам и цитировал в видео. До конца и внимательно... Вместо того, чтобы упражняться в лже-вежливости.

    • @easydev1205
      @easydev1205  3 หลายเดือนก่อน +3

      Ладно, хватит хейта. Я смотрю тебя ролик задел) Заблокирую-ка я тебя наверно

    • @vit3060
      @vit3060 2 หลายเดือนก่อน

      ​@@easydev1205хотел было подписаться, но увидел этот комментарий

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      спать не буду теперь

  • @DobinSergei
    @DobinSergei 2 หลายเดือนก่อน

    28:36 - к чему было делать ещё один класс, который сам по себе ничего не добавляет, а только вызывает методы базового класса? 😏
    Лучше вместо него, использовать непосредственно базовый класс.
    За счёт полиморфизма будет автоматом вызвана реализация из правильного наследника, без проверок типа.

  • @ТимофейЧерников-щ2х
    @ТимофейЧерников-щ2х 2 หลายเดือนก่อน

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

  • @agicotech
    @agicotech 2 หลายเดือนก่อน

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

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      Абстракций вы не избежите ни в одном реальном проекте. И далеко не так уж они и ресурсоемки. Главное разумное использование. Как и со всем остальным.

    • @agicotech
      @agicotech 2 หลายเดือนก่อน

      @easydev1205 я не говорю что их нужно избегать как тотальное зло) я говорю что в вычислительных частях кола надо постараться делать что-то максимально низкоуровневое, а в реализации основной логики проекта абстракции это очень даже замечательно

  • @ДенисЛюбченко-л4о
    @ДенисЛюбченко-л4о 3 หลายเดือนก่อน +2

    3:58 что тут сложного?😂
    Обычный индусский код )

    • @easydev1205
      @easydev1205  3 หลายเดือนก่อน

      Ну это стереотип просто)

    • @ДенисЛюбченко-л4о
      @ДенисЛюбченко-л4о 3 หลายเดือนก่อน

      @@easydev1205 я сейчас на таком проекте, код один в один. Все шутки про индусов - не шутки)

  • @dgdarkking266
    @dgdarkking266 2 หลายเดือนก่อน

    так погодь - так какая будет стратегия таким и будет поведение, тоже самое и у состояния

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      Логично

    • @dgdarkking266
      @dgdarkking266 2 หลายเดือนก่อน

      @@easydev1205 а в чем разница паттернов? Да и если смотреть, то фигура зависит от стратегии рисования, почему вв назвали её состоянием

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      Это не я так назвал. Не я это придумал) Разница между этими двумя паттернами незначительная. По сути паттерн состояние это продолжение паттерна стратегия. О тонкостях различия может сниму отдельное видео

  • @alexperemey6046
    @alexperemey6046 3 หลายเดือนก่อน +6

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

    • @easydev1205
      @easydev1205  3 หลายเดือนก่อน

      Спасибо за комментарий и за мнение. Да, на понимание кода паттерны тоже конечно влияют. Нужно использовать разумно

    • @alexperemey6046
      @alexperemey6046 3 หลายเดือนก่อน

      @@easydev1205 Не паттерны, return...

    • @AndroidsReview
      @AndroidsReview 3 หลายเดือนก่อน +1

      Это делает код более плоским

    • @КириллЧе-я5ы
      @КириллЧе-я5ы 3 หลายเดือนก่อน +1

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

    • @enosunim
      @enosunim 2 หลายเดือนก่อน

      Я просто делаю переменную типа "ерор" и если где-то при валидации не валидируется, то устанавливаю её тру. И таким образом никакого ветвления и ретурн в конце один. Хотя иф это вообще говоря ветвление по определению, даже если нет другой ветки. Т.к. это будет ветвление между деланием чего-то (вызова ретурн) и не деланием чего-то (не вызываем ретурн) = )))))

  • @mariospaghetti8710
    @mariospaghetti8710 2 หลายเดือนก่อน

    плохо слышно

    • @lankryf
      @lankryf 2 หลายเดือนก่อน

      Купи норм навушники

    • @mariospaghetti8710
      @mariospaghetti8710 2 หลายเดือนก่อน

      @@lankryf у меня нормальные наушники

  • @TheBypasser
    @TheBypasser 2 หลายเดือนก่อน

    "Что, соответственно, минус" - ну и тут я уже слушать и перестал: во-первых, ну главное-то в коде всё ж не примитивность, а оптимальность, и - во-вторых - всё равно автомат на кучу состояний читаем куда лучше пятка раскиданных по коду IFов. Разбить функцию на кучу мелких - можно, конечно, заинлайнить пару-тройку совсем уж логически отвязанных от остального кода вещей (что нечасто и имеется) - но скорее всего у тебя просто получится убогое опенсорсное спагетти. Помните, дети: функции, классы и т.п. сделаны для того, чтобы применяться в разных частях программы по многу раз, и правя любую подобную штуку, редактирующий будет всё время отвлекаться на то, что же эта правка затронет - и всё ради того, чтоб увидеть (желательно, вообще в другом файле), что функция эта - очередной такой вот изврат. Едем дальше. Твоё "функциональное программирование" вообще к функциональному программированию отношения не имеет, вот совсем и никак. Почему ж вы все обычные процедуры обзываете "функциональным программированием" ?..
    А так - да тут половина примеров была б нормальными, если б уже все поняли, что скобки после кондишнов надо на новую строчку переносить (тогда сразу видно, скоуп там, или просто одиночный вызов), и всякой чуши типа return; else не писали... Или (я просто на скриптах не писал давно) в отличае от нормальных C/С++, тут IF без скобок не работает?

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      Ничего не понятно, но очень интересно) Спасибо за комментарий

    • @enosunim
      @enosunim 2 หลายเดือนก่อน

      А я вот очень люблю скобочки, и терпеть не могу этих "нормальных" когда одна команда без скобок. И начинается. Садишься дорабатывать этот "спагетти" код и сначала везде скобки пишешь, чтобы понять что вообще где выполняется. И уже потом добавляешь пару строчек которые нужно.
      Хотя в целом согласен, что мешать в кучу ООП, функциональное программирование и структурное это уже не спагетти, а макароны по флотски = )))

    • @TheBypasser
      @TheBypasser 2 หลายเดือนก่อน

      @@enosunim Про скобки - "ну такое". Иногда помогают читабельности, иногда же попросту захламляют код. Вообще, если нет жёсткого требования, предпочитаю стандартам выборочно следовать: бывает, когда код с кучей goto и макрокода отлично читается, а бывает, что всё прям по MISRA, но хуже, чем после обфускатора :) А вот функционального программирования я так и вообще немного видел, а C/C++ его в явном виде и не поддерживают вовсе ;)

  • @andreysemykin5879
    @andreysemykin5879 3 หลายเดือนก่อน +1

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

    • @easydev1205
      @easydev1205  3 หลายเดือนก่อน

      Приняли. Будем иметь в виду.

    • @niklan333
      @niklan333 2 หลายเดือนก่อน

      @@easydev1205 Человек выразился не очень красиво и корректно, но в целом он прав. Функции с несколькими return ещё сложнее поддерживать и отлаживать, чем функции с многими if-else. Иначе говоря, Вы предложили избавляться от плохого подхода с помощью ещё более плохого подхода.

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน +1

      Мнение имеет место быть. Я с ним скорее не согласен. Я не считаю ранний выход плохим подходом.

    • @andreysemykin5879
      @andreysemykin5879 2 หลายเดือนก่อน

      @@easydev1205 да считайте что угодно, но вы вряд ли потянете с ваши мнением на ученого-математика в области информатики и тому подобное, кому-то знаете ли и goto написать не зазорно. Советую ознакомиться с термином структурное программирование. А по поводу ранних выходов, если метод грубо говоря в десяток строк умещается, это еще терпимо, но многие их лепят черти знает как на несколько экранов, поэтому чем строже правила, тнм чище резкльтат в общем случае. И кстати return не в конце метода это тоже разновидность goto

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      Так вы то на моём канале) и во всех видео исключительно мое мнение. Я не считаю ранний выход плохой практикой - поэтому так и говорю в видео.

  • @DaB00gieW00gie
    @DaB00gieW00gie 2 หลายเดือนก่อน

    к тернарному оператору и конкретному примеру с голосованием напрашивается такое:
    let age = 18
    let canvote = age >= 18 && true
    console.log(canvote)
    не обзывайтесь только!

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน

      Слишком замудрёно

    • @DaB00gieW00gie
      @DaB00gieW00gie 2 หลายเดือนก่อน +1

      @@easydev1205 а что тут мудрого? вместо тернарного оператора тут простое логическое "и" - всегда возвращает или true или false,
      это удобнее, если тебе эти [yes,no] нужны не на вывод, а для дальнейшего использования.

    • @easydev1205
      @easydev1205  2 หลายเดือนก่อน +1

      Да, просто для такой простой логики должно быть каждому разработчику с первого взгляда понятно как это работает. Если это кого-то заставит призадуматься - я откажусь от такого решения. Это именно у меня такой подход. По крайней мере стараюсь так делать. Поэтому я, например, в своём коде такого точно использовать не буду. А там каждый сам решает

    • @DaB00gieW00gie
      @DaB00gieW00gie 2 หลายเดือนก่อน +1

      @@easydev1205 т.е. не все разработчики знают как работает "&&" и для чего нужен булев тип данных?
      в JS (да и в других языках) ведь очень много всего, что возвращает true или false.
      это простая, понятная и универсальная штука. разве нет?

    • @enosunim
      @enosunim 2 หลายเดือนก่อน

      чот не понял, а тру для чего? age>=18 может вернуть что-то еще кроме true и false ? = )))))))))