Более того, лидер показывает результат всего на 20% лучше, чем example.js
Конечно, при реальных переговорах, 20% в денежном выражении совсем не мало, но от конкурса алгоритмов интуитивно ожидаешь большего результата
Ну, понимаете, это примерно как вопрос о том, стоит ли читать художественную литературу в оригинале, или достаточно ознакомиться с подборкой «кратких изложений».
Любая мысль, сформулированная в словах, уже теряет часть первоначального смысла, поэтому зачастую бывает полезно ее выразить в двух-трех различных формулировках, чтобы зацепить различные ассоциативные слои в мозгу читателя.
А базовых мыслей/идей в тексте больше чем одна, отсюда и объем.
Я не к тому, что данный текст прям идеален и является образчиком изложения, но все-таки бОльшая часть слов в нем использована не просто так, на мой взгляд.
Текст вполне внятный
Большинство программистов значительно больше интересует процесс программирования, чем пользователи, для которых пишется программа, и тем более чем другие программисты, которые потом будут ее поддерживать. А должно быть наоборот )
Можно написать 10 тысяч строк кода на Java, чтобы смоделировать изначально кривой и нестабильный бизнес-процесс, или пользовательский сценарий например, а можно поправить процесс или сценарий и вообще обойтись без написания кода. Но для этого надо выйти за рамки IDE и вообще за рамки представлений о программисте, как о том-кто-пишет-код.
Действительно хороший программист — он как Нео в Матрице, программирует мир вокруг себя, а не программы. Для этого даже не обязательно знать языки программирования :) Об этом и статья
Вот теперь, после вашего комментария, он вобьет эту строчку в гуглояндекс (во время скайп собеседования) и выдаст чужой ответ за свой
Можно начинать придумывать новый пример :)
ОК, давайте по порядку:
1. Насчет договоренностей в команде — вопросов нет, можно договориться хоть в LISP-стиле писать, если это нужно для решения задачи. Только помимо членов вашей команды есть еще масса людей, которые могут ваш код читать потом — если результат вашей работы передается дальше как часть большого проекта, если вы пишете общую либу, если вы используете ваш код в качестве примеров в документации, докладах или вот в статье на хабре. Ну или вот вы написали все прекрасно, сдали заказчику, потом решили чем-то другим заняться, а через 3 года ему другая уже команда должна доработать это все. Возможно за другие деньги совсем. Я понимаю что как программисту вам на это пофиг, но это не значит, что так надо делать. Есть еще такое слово как ответственность.
2. Не надо, пожалуйста, валить в кучу тернарные операторы, побитовые операторы, а также (это к комментарию от RubaXa выше) замыкания, области видимости и т.д. У вас какой-то бинарный программист получается — он либо знает только if-else и все (видимо только вчера basic изучил в школе), либо знает и активно использует все операторы и конструкции языка, которые в нем только есть. Это крайности.
Если посмотреть объективно, то можно выстроить некоторую шкалу встречаемости различных конструкций в коде (в любом JS коде, усредненно), где var-if-else-for будут на первых местах где-то, замыкания и тернарники на 5-10, а побитовые операторы и возврат значения после запятой (return expression, bar) — на 100 по частоте использования.
Опять же, если вы действительно пишите какой-то математический алгоритм или активно работаете с числами, можно и нужно использовать побитовые операторы. Они для этого и сделаны в таких языках как JS. Но без реальной нужды их лучше не вставлять в код, если вы не пишете just for fun и только для себя.
К rock и RubaXa у меня вопрос — вы веб программистов нанимали когда-нибудь на работу? собеседование проводили? искали подрядчиков на аутсорсе? какой процент из соискателей (или потенциальных исполнителей) готов сходу разобраться в ~indexOf или разглядеть XOR оператор в (ret ^ not)? и за какие деньги они готовы потом работать?
а то у меня ощущение что мы с разных точек зрения на это смотрим
Приравняйте «экзотические» к «редко используемые», и ответ найдется сам собой. Усредненный «JS программист в вакууме» за 3, например, года своей карьеры с такими конструкциями может сталкиваться пару раз, даже с учетом кода сторонних плагинов и библиотек. Не надо только говорить, что такому в программировании не место, что надо развивать кругозор и т.д. — по состоянию рынка труда на текущий день у нас таких спецов все равно большинство, и это надо всегда учитывать при написании кода.
Естественно reduce не так быстр, как плоский цикл, не говоря уже о том, что конкретно для uniq$viaReduce в момент вызова indexOf будет перебираться весь массив в поисках нужного элемента, что раздувает количество шагов цикла в квадрат раз.
Однако, все это может быть совершенно не заметно на массивах размером до, например, 1000 элементов (ну или 10 000, я не знаю). Т.е. разница в несколько десятков миллисекунд, либо меньше.
Очень странно слышать комментарии про фигурные скобки и разнесение ветвей на разные строчки в контексте обсуждения
Т.е. понятно, что это чисто синтетический пример, но я и про свой код могу то же самое сказать.
Основная моя претензия была (и есть) к слову, которое вы еще раз употребили в этом комментарии — «джедайский», и смысл которого в контексте приведенного фрагмента кода мне не понятен. Этот фрагмент просто плохой по всем параметрам, т.к. привносит излишнюю сложность для чтения и изменения, которая не компенсируется вообще ничем — ни лаконичностью (мой пример короче), ни скоростью выполнения, не уменьшением количества языковых конструкций. Ничего из этого в коде нет.
И комментарий я написал именно ради того, чтобы этот ваш термин не вводил никого в заблуждение.
Ну в том и смысл, что до приведения типов дело не доходит, когда мы сравниваем заведомо два числовых значения.
Предлагаю не обсуждать дальше разницу в поведении === и == в общем случае — все это давно обсуждено и всем известно. Я специально указал в первоначальном своем комментарии, что он относится только к конкретному фрагменту кода и ни к чему больше.
Ну, на вкус и цвет…
На мой субъективный взгляд "-1" выглядит чуть более «магическим» числом чем «0», для тех кто не знает, что в точности должен возвратить indexOf в случае отсутствия элемента в массиве.
Только в данном случае ===-1 не надо, достаточно == -1
Ведь метод indexOf нам заведомо (согласно спецификации) не может вернуть ничего кроме числа, поэтому нет нужды в дополнительной проверке типа.
— хочется обратиться ко всем начинающим (или «продолжающим») JS разработчикам — не пишите так никогда. Совсем никогда. Вы можете подумать, что это какой-то крутой, «джедайский» код — который позволяет очень лаконично выразить вашу бизнес-логику, используя доступные только «гуру» «экзотические» операторы и конструкции.
Это абсолютно не так.
Есть разные специализации frontend-программистов.
Если нужен «продвинутый» верстальщик, способный к HTML каркасу прикрутить 3-4 плагина jQuery и вывалить с их помощью результат пары ajax запросов — можно не знать разницу между call и apply.
Если надо писать что-то с нуля, разрабатывать API, полностью кастомный UI и т.д. — нужно знать все упомянутое в статье и еще много чего сверху.
Зачем вы мне пишите то, о чем я сам писал в соседней ветке обсуждения habrahabr.ru/post/206868/#comment_7133274 в ответ на ваш же комментарий?
Мне начинает казаться, что я сам с собой веду беседу :)
Если резюмировать мое мнение по этому вопросу — дубликаты всегда выносим в функцию/метод, т.к. проблем от проверки мест вызова функции меньше, чем от проверки изменений и возможных ошибок при несогласованном изменении дубликатов. А если у нас неповторяющийся кусок кода, который теоретически можно обособить и спрятать за абстракцией в виде функции — серьезно подумаем, стоит ли это делать, т.к. в этом случае выигрыш далеко не столь очевиден.
Почитал. Согласно терминологии статьи, при удалении дубликатов мы повышаем «структурную сложность», зато сильно понижаем «количественную» и «сложность изменений» (нет проблем с несогласованной правкой дубликатов), а также частично «алгоритмическую сложность» (за счет вынесения дублирующихся частей алгоритмов в абстракции в виде функций и методов). Моя субъективная оценка — оно того стоит, т.к. сумма трех понижаемых сложностей выше, чем одной повышаемой. В итоге общая сложность проекта уменьшается.
У вас может быть другая субъективная оценка. Доказать свою правоту математически, измерив количественно повышение/понижение сложности, я не берусь.
Насчёт методов из трёх строк. Всегда (почти) предпочту метод из трёх строк методу из 20. Чаще всего, когда ты читаешь чей-то код, ты пытаешься понять смысл того, что делает этот код, а не детализированную имплементацию, поэтому, если программист писал множество мелких функций, то функции верхнего уровня читаются действительно как «хорошо написанная проза», а если нужны детали — всегда можно заглянуть в детали.
У меня вот наоборот как-то получается — понять смысл написанного обычно просто, а дальше нужно в коде что-то поменять, потому что мы его не ради развлечения же читаем, а с какой-то целью. И вот на этом этапе — слишком много маленьких методов и функций создают проблемы, т.к. надо в каждую заглянуть и потом еще половину из них поменять. Что тянет за собой кучу зависимостей из тех мест, где эти функции еще используется. Либо надо все выкидывать и переписывать метод заново.
Поймите правильно, я не за методы по 100-500 строк, которые пытаются делать все на свете. Но и не за методы, в которых вызывается 30 других методов, которые внутри себя вызывают еще в сумме 50-100 функций по 1-3 строки. Я за разумную середину.
Я поясню насчет функции — в том примере который вы привели, типа array_sum, конечно можно и нужно выносить, т.к. это универсальная, библиотечная по сути функция. И как раз маловероятно, что она будет использована только один раз во всем приложении.
Речь про неповторяющийся кусок бизнес-логики, который специфичен для того конкретного участка кода (функции, метода, не важно), который мы пишем/читаем в данный момент. И проблема с функцией в том, что она обычно (хотя зависит от языка конечно) имеет глобальную область видимости. Соответственно, если мы оформляем фрагмент в функцию, мы автоматически создаем вопрос для читающего код — а где эта функция еще используется? Если мне надо ее поменять, не сломается ли программа где-нибудь еще? Конечно, есть IDE, тесты и т.п., но эту проблему можно просто не создавать, чтобы потом не приходилось ее решать.
Насчет двух функций — то же самое, нам надо устранять дублирование, а не просто переносить его в другое место. Было 2 похожих куска кода, стало 2 похожих функции — смысл?
Насчет тернарного оператора — я не первый раз уже слышу про то, что какой-то там средний программист не может это прочитать и воспринять, и каждый раз тихо фигею. Это что, какой-то «know how» прием или хакерский финт — тернарный оператор? Или все-таки стандартная задокументированная конструкция языка? Такие тезисы мне напоминают разговоры пятилетней давности о том, что «у пользователя в браузере может быть отключен яваскрипт». Может быть отключен, да, только он тогда не сможет 90% сайтов пользоваться, и это — нормально.
P.S. За лайфхак кстати спасибо, сыну в школу идти через полтора года, опробую на нем.
Я тут писал уже habrahabr.ru/post/206868/#comment_7129502 — правильное устранение дубликатов не усложняет код. Если у вас есть конкретный пример кода, где устранение дубликатов может привести к неоправданному усложнению — можете сюда выложить или ссылку дать. Вместе подумаем над этим, в качестве разминки для мозга.
Ну вообще в статье шла речь про код в рамках одного проекта, а в вашем случае это скорее «подключаемая библиотека» (использую такой термин, чтобы не привязываться к конкретному языку), если код одинаков, либо просто «повторное использование наработанного решения», если он все-таки отличается в разных проектах. Если же подключение библиотеки приводит к проблемам типа Dependency_hell, то это уже не к коду вопрос, и решать его надо на другом уровне.
Понятное дело, если всю систему за пару дней не изменить, а релиз завтра — можно просто скопировать код, да. Но надо помнить, что можно сделать лучше.
Конечно, при реальных переговорах, 20% в денежном выражении совсем не мало, но от конкурса алгоритмов интуитивно ожидаешь большего результата
Любая мысль, сформулированная в словах, уже теряет часть первоначального смысла, поэтому зачастую бывает полезно ее выразить в двух-трех различных формулировках, чтобы зацепить различные ассоциативные слои в мозгу читателя.
А базовых мыслей/идей в тексте больше чем одна, отсюда и объем.
Я не к тому, что данный текст прям идеален и является образчиком изложения, но все-таки бОльшая часть слов в нем использована не просто так, на мой взгляд.
Большинство программистов значительно больше интересует процесс программирования, чем пользователи, для которых пишется программа, и тем более чем другие программисты, которые потом будут ее поддерживать. А должно быть наоборот )
Можно написать 10 тысяч строк кода на Java, чтобы смоделировать изначально кривой и нестабильный бизнес-процесс, или пользовательский сценарий например, а можно поправить процесс или сценарий и вообще обойтись без написания кода. Но для этого надо выйти за рамки IDE и вообще за рамки представлений о программисте, как о том-кто-пишет-код.
Действительно хороший программист — он как Нео в Матрице, программирует мир вокруг себя, а не программы. Для этого даже не обязательно знать языки программирования :) Об этом и статья
Можно начинать придумывать новый пример :)
1. Насчет договоренностей в команде — вопросов нет, можно договориться хоть в LISP-стиле писать, если это нужно для решения задачи. Только помимо членов вашей команды есть еще масса людей, которые могут ваш код читать потом — если результат вашей работы передается дальше как часть большого проекта, если вы пишете общую либу, если вы используете ваш код в качестве примеров в документации, докладах или вот в статье на хабре. Ну или вот вы написали все прекрасно, сдали заказчику, потом решили чем-то другим заняться, а через 3 года ему другая уже команда должна доработать это все. Возможно за другие деньги совсем. Я понимаю что как программисту вам на это пофиг, но это не значит, что так надо делать. Есть еще такое слово как ответственность.
2. Не надо, пожалуйста, валить в кучу тернарные операторы, побитовые операторы, а также (это к комментарию от RubaXa выше) замыкания, области видимости и т.д. У вас какой-то бинарный программист получается — он либо знает только if-else и все (видимо только вчера basic изучил в школе), либо знает и активно использует все операторы и конструкции языка, которые в нем только есть. Это крайности.
Если посмотреть объективно, то можно выстроить некоторую шкалу встречаемости различных конструкций в коде (в любом JS коде, усредненно), где var-if-else-for будут на первых местах где-то, замыкания и тернарники на 5-10, а побитовые операторы и возврат значения после запятой (return expression, bar) — на 100 по частоте использования.
Опять же, если вы действительно пишите какой-то математический алгоритм или активно работаете с числами, можно и нужно использовать побитовые операторы. Они для этого и сделаны в таких языках как JS. Но без реальной нужды их лучше не вставлять в код, если вы не пишете just for fun и только для себя.
а то у меня ощущение что мы с разных точек зрения на это смотрим
Однако, все это может быть совершенно не заметно на массивах размером до, например, 1000 элементов (ну или 10 000, я не знаю). Т.е. разница в несколько десятков миллисекунд, либо меньше.
Очень странно слышать комментарии про фигурные скобки и разнесение ветвей на разные строчки в контексте обсуждения
Т.е. понятно, что это чисто синтетический пример, но я и про свой код могу то же самое сказать.
Основная моя претензия была (и есть) к слову, которое вы еще раз употребили в этом комментарии — «джедайский», и смысл которого в контексте приведенного фрагмента кода мне не понятен. Этот фрагмент просто плохой по всем параметрам, т.к. привносит излишнюю сложность для чтения и изменения, которая не компенсируется вообще ничем — ни лаконичностью (мой пример короче), ни скоростью выполнения, не уменьшением количества языковых конструкций. Ничего из этого в коде нет.
И комментарий я написал именно ради того, чтобы этот ваш термин не вводил никого в заблуждение.
Предлагаю не обсуждать дальше разницу в поведении === и == в общем случае — все это давно обсуждено и всем известно. Я специально указал в первоначальном своем комментарии, что он относится только к конкретному фрагменту кода и ни к чему больше.
На мой субъективный взгляд "-1" выглядит чуть более «магическим» числом чем «0», для тех кто не знает, что в точности должен возвратить indexOf в случае отсутствия элемента в массиве.
Только в данном случае ===-1 не надо, достаточно == -1
Ведь метод indexOf нам заведомо (согласно спецификации) не может вернуть ничего кроме числа, поэтому нет нужды в дополнительной проверке типа.
Это абсолютно не так.
Сравните
и
Второй вариант на порядок читабельнее, не использует ничего кроме банального if, и (вот где профит-то :-)) — короче на 6 символов.
Он же в виде целой функции, чтобы можно было сразу проверить работоспособность (перенос строки перед return — по желанию)
Если нужен «продвинутый» верстальщик, способный к HTML каркасу прикрутить 3-4 плагина jQuery и вывалить с их помощью результат пары ajax запросов — можно не знать разницу между call и apply.
Если надо писать что-то с нуля, разрабатывать API, полностью кастомный UI и т.д. — нужно знать все упомянутое в статье и еще много чего сверху.
Мне начинает казаться, что я сам с собой веду беседу :)
Если резюмировать мое мнение по этому вопросу — дубликаты всегда выносим в функцию/метод, т.к. проблем от проверки мест вызова функции меньше, чем от проверки изменений и возможных ошибок при несогласованном изменении дубликатов. А если у нас неповторяющийся кусок кода, который теоретически можно обособить и спрятать за абстракцией в виде функции — серьезно подумаем, стоит ли это делать, т.к. в этом случае выигрыш далеко не столь очевиден.
У вас может быть другая субъективная оценка. Доказать свою правоту математически, измерив количественно повышение/понижение сложности, я не берусь.
Поймите правильно, я не за методы по 100-500 строк, которые пытаются делать все на свете. Но и не за методы, в которых вызывается 30 других методов, которые внутри себя вызывают еще в сумме 50-100 функций по 1-3 строки. Я за разумную середину.
Речь про неповторяющийся кусок бизнес-логики, который специфичен для того конкретного участка кода (функции, метода, не важно), который мы пишем/читаем в данный момент. И проблема с функцией в том, что она обычно (хотя зависит от языка конечно) имеет глобальную область видимости. Соответственно, если мы оформляем фрагмент в функцию, мы автоматически создаем вопрос для читающего код — а где эта функция еще используется? Если мне надо ее поменять, не сломается ли программа где-нибудь еще? Конечно, есть IDE, тесты и т.п., но эту проблему можно просто не создавать, чтобы потом не приходилось ее решать.
Насчет двух функций — то же самое, нам надо устранять дублирование, а не просто переносить его в другое место. Было 2 похожих куска кода, стало 2 похожих функции — смысл?
Насчет тернарного оператора — я не первый раз уже слышу про то, что какой-то там средний программист не может это прочитать и воспринять, и каждый раз тихо фигею. Это что, какой-то «know how» прием или хакерский финт — тернарный оператор? Или все-таки стандартная задокументированная конструкция языка? Такие тезисы мне напоминают разговоры пятилетней давности о том, что «у пользователя в браузере может быть отключен яваскрипт». Может быть отключен, да, только он тогда не сможет 90% сайтов пользоваться, и это — нормально.
P.S. За лайфхак кстати спасибо, сыну в школу идти через полтора года, опробую на нем.
Понятное дело, если всю систему за пару дней не изменить, а релиз завтра — можно просто скопировать код, да. Но надо помнить, что можно сделать лучше.