Как стать автором
Обновить

Комментарии 171

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

The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming.

Ключевое тут «wrong places» и «wrong times». Архитектура приложения это «right place», и начало проектирования для неё — самое «right time». Разворачивать циклы раньше времени и отмечать регистровые переменные — это можно (и нужно) потом делать. А выбрать правильные структуры данных и алгоритмы с адекватной сложностью — вот это делать «никогда не рано». Вот такая моя трактовка фразы Кнута.
Ярким примером может быть например такое:
— Программист лепит указатели вместо копий объектов. Потом, сам же, отлаживает эти места
— Тратит основное время на подгонку структур данных, под нетривиальные-алгоритмы. Вроде сортировки, для последующего бинарного поиска
— Использует register, везде где это можно
— Вызывает WinApi'шный код, вместо .NET-овского.
А тем временем, проект-то стоит, основные задачи не решаются…
Методы оптимизации разные, одно их объединяет — поиск ошибок, вместо рабочего код
НЛО прилетело и опубликовало эту надпись здесь
Не скажу ничего относительно

— Использует register, везде где это можно
— Вызывает WinApi'шный код, вместо .NET-овского.

о речь была как раз о том, что вот это:

— Программист лепит указатели вместо копий объектов. Потом, сам же, отлаживает эти места
— Тратит основное время на подгонку структур данных, под нетривиальные-алгоритмы. Вроде сортировки, для последующего бинарного поиска

— как раз то, что надо делать.

Ваш К.О.
Как раз, от этого падать хочет все, что залинковано, и ловишь его по всему коду. Где же она, ошибка?! Да вот же — где ты объект через все пускаешь, и изменяют его все рандомно!
У вас либо глубокие проблемы с проектированием, либо глубокие проблемы с чтением документации. По моему опыту — скорее второе, причем в системе разбирается лучше всех именно тот человек, который везде кладет ссылки.
Меня тоже раздражает, когда эту фразу лепят везде и всюду. Сидишь, прорабатываешь общую архитектуру системы (даже не приложения), а тебя бьют по рукам за «преждевременную оптимизацию», ага. А потом выясняется, что не там сэкономили время и деньги, совсем не там.
А я проверил на себе правдивость этой фразы. Очень часто мои оптимизации были бессмысленными, профилировщик показывал неэффективность пары методов, на которые я бы совершенно не подумал.
Плюс, есть люди, которые реально занимаются преждевременной оптимизацией, которая ускорит функцию, которая вызывается один раз, при инициализации приложения с 0.7мс до 0.4 мс.
Для таких людей и нужна эта фраза.
Т.е. «На практике такого не случится никогда. Ни-ког-да.» — наглая ложь. Такое на практике случается регулярно
Ну почему же ложь? В Вашей практике часто встречалась СамаяЗлаяИНеоптимизированнаяФункция, которую сразу же видно в профайлере и пофиксив которую наступал мир узких мест не оставалось?
Да, в моей практике — встречалось. Потому то, что такое не встречается никогда — ложь.
Я несколько раз натыкался на «один тормозной запрос», на «одну тормозную функцию» (20 строк кода) и т.д.
Из моих последних примеров буквально недельной давности — оптимизация на Букфи. Нагрузку CPU удалось снизить с 80% до 16% посредством добавления всего лишь 1 индекса в таблице бд. Хорошая, согласитесь, оптимизация, полностью противоречащая вашему «ни-ког-да не бывает».
Почему моему? :)
извините, спутал вас с автором статьи

P.S. где, говорите, был юзерскрипт для подсветки комментариев автора топика? ;)
так это еще и перевод
Корень зол в таком случае — перфекционизм. Часто преждевременная оптимизация очень затягивает (:
Есть люди, которые прикрывают этой фразой нежелание писать чистый и эффективный код.
Есть люди, которые любой фразой могуть прикрывать нежелание писать чистый и эффективный код.
И есть люди, которые всегда найдут подходящую фразу, которой можно прикрыть нежелание писать чистый и эффективный код. ;)
И есть люди, которые пишут чистый и эффективный код на месте грязного и тормозного кода. Вот только чтобы отличить одних от других нужно иметь соответствующую квалификацию, и не все Project Manager'ы ей обладают, увы.
чистый != эффективный
оптимизированный код очень часто бывает грязен и неудобопонятен
Практически всегда вначале пишется чистый код, а уже потом на его месте возводят эффективный. При этом чистый код сохраняется хотя бы в виде комментария, чтобы было видно, что чистый код принесен в жертву производительности.
Гы, надо же понимать в чём разница между микрооптимизациями и нормальным проектированием системы. Мя поражают современные cms на похапэ. Скока там гавна выполняется при каждом запросе. Выкинуть бы это всё, или переписать на fcgi.
А меня поражают ява-приложения: в отличие от добротного PHP-кода, перезапускающегося при каждом запросе, и отрабатывающего за 50 мс со всеми объектами, эти уродливые монстры могут только минуту запускаться. Это же как надо кривокодить, чтобы такого монстра получить. Что же он там такое делает, не иначе как четырехмерные белки для лечения от рака рассчитывает. А уж на каждое изменение все перекомпилировать, паковать, деплоить — видимо, специально все замедляют, чтобы программист мог полдня на безделье переводить, пока все деплоится и запускается.
Как я вас обоих понимаю :) Поэтому Django.
А ещё есть NodeJS :)
Что ещё раз доказывает, что язык программирования, операционная система и фреймворк ни разу не причём. На любой платформе можно писать как хорошие, так и плохие программы.
Плавность изгиба рук решает мой юный падаван. :)
Запятые решают.
Даа, оговорочка то по Фрейду :D

Учите, русский, и, программирование, чтобы, альт+таб, не привел, к, ядерной, войне. :)
Давно у вас кривизну рук просчитывают падаваны? ;)
Покажите мне хоть одну быструю программу на Java. Чорд, да там helloworld стартует секунды — хоть на писи, хоть на андроиде.
В холивар вступать не буду. Но специалисты, которые умеют её готовить, утверждают, что она по производительности зачастую не уступает C++. К скорости загрузки это, наверное, не относится. «Зато уж если нащупает, ...» ©
Но специалисты, которые умеют её готовить, утверждают, что она по производительности зачастую не уступает C++.


Исполняется на компьютере в результате всегда бинарный код.
Если из программы на Java получился бинарный код аналогичный или даже более оптимизированный, чем бинарный код из программы на C++ — то, без сомнений, «уступать» она не будет.
А вот что за бинарный код получится и почему именно такой — для программы на Java есть масса интересных вариантов… Например, «классическая Java-машина» — это, вообще-то интерпретатор байт-кода, со всеми вытекающими. Но если, например, использовать JIT-компиляцию — то уже совсем другой коленкор получается…
Опять же, компиляторы C++ тоже разные бывают, как и используемые кодом библиотеки. Нет универсального ответа на вопрос «что быстрее?».
Нет универсального ответа на вопрос «что быстрее?».
Есть. И ответ этот — ассемблер.
Его обогнать по производительности невозможно. Любую программу на любом языке можно переписать на ассемблер без потери производительности.
PS. Правда, у ассемблера есть другие небольшие недостатки)
Да-да-да. Все программы, написанные на ассемблере — идеальны. Ассемблерные программисты — поголовно гении и не лажают. Алгоритмы, реализованные на ассемблере — всегда самые лучшие. Нельзя на ассемблере написать два разных кода, реализующих одинаковую функциональность.

Конечно, ассемблерные программы всегда быстрее.
Простите, я, возможно, неудачно выразился в первой части поста.
Основная мысль — «любую программу на любом языке можно переписать на ассемблер без потери производительности».
Разумеется, это не отменяет возможности написать сколь угодно тормозную программу на ассемблере.
Для любой пары (задача, язык) есть некоторая максимальная скорость, с которой может работать программа на этом языке, решающая эту задачу. Для любой задачи для ассемблера эта максимальная скорость не хуже, чем для любого другого языка.
Впрочем, на практике этот оптимум почти никогда не реализуется)
Любую программу на любом языке можно переписать на ассемблере без потери производительности на конкретном процессоре/семействе процессоров.
Ассемблер не является «универсальным» средством, к сожалению.
теоретически можно.
практически же языки более высокого порядка возникли не оттого что кому-то было скучно, а оттого что сложность абстракций не могла быть выражена более простыми языками. Или могла быть но слишком большими усилиями.
Боюсь, что скоро вас закидают. И причина этого в том, что правильный компилятор (icc) компилирует C таким образом, чтобы максимально использовать кеш процессора. В результате чего такие программы могут работать гораздо быстрее, чем ассемблерные.
Кстати, пруф.
Теоретическая возможность написания идеального кода на ассемблере все равно существует. Подчеркиваю — теоретическая!
Инструкция по получению программы на ассемблере, работающей не медленнее данной программы на С при компиляции ее icc:
  1. Взять программу на С
  2. Скомпилировать ее с помощью icc
  3. Дизассемблировать машинной код, полученный в предыдущем пункте
  4. Предъявить программу на ассемблере
НЛО прилетело и опубликовало эту надпись здесь
Штука еще в том, что JIT может менять набор инструкций в зависимости от конкретной ситуации, а код на ассемблере всегда статичный. Так что даже тут не все однозначно.
НЛО прилетело и опубликовало эту надпись здесь
Не, я думал речь о том, чтобы на ассемблере именно писать. Если программу просто дизассемблировать, непонятно, откуда у нее возьмется выигрыш в производительности?
Ниоткуда. Более того, не исключена возможность, что сгенерированный компилятором код нельзя улучшить вообще.
Я утверждал, что при оптимальном использовании ассемблер никогда не даст проигрыша в производительности по сравнению с любым другим языком. Иногда он может дать выигрыш. То есть ассемблер не медленнее («нестрого быстрее») любого другого языка.
Ассемблер (по определению) — это всего лишь удобочитаемый машинный (бинарный) код.
Если писать на ассемблере, то можно написать фигню, как и на любом другом языке.
Если фигню, написанную на другом языке, транслировать в машинный код и отобразить в виде ассемблера — то это будет все таже фигня, ничем не лучше и не хуже.
Вывод: ассемблер ничем не превосходит другие языки в плане быстродействия программ. Просто с его помощью иногда удобно «шлифовать» результат работы компиляторов вручную.
Но, поскольку с помощью компилятора высокоуровневого языка не всегда можно получить произвольный машинный код, то вполне возможна ситуация, когда код на языке высокого уровня не отобразится компилятором в оптимальный машинный код. В таком случае ассемблер даст ускорение.
Только 0.1 % людей умеют писать код на ассемблере лучше, чем код выдаваемый компилятором. Это как раз те люди, что пишут компилятор :)
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
0.1% — не подскажете источник, из которого получена данная цифра? Или это ваше предположение?
НЛО прилетело и опубликовало эту надпись здесь
Это не так. Попробуйте как-нибудь преобразовать в ассемблерный листинг любой небольшой функции на C или C++, скомпилированной под процессор ARM. Почти наверняка (если вы, конечно, хоть немного знакомы с ассемблером) вы сразу увидите, что можно оптимизировать.
Я не гений программирования и не пишу компиляторы за завтраком, но несколько своих функций я переписал на ассемблере, ускорив их выполнение в 4-8 раз.
Ну. Это просто означает, что эти функции были криво написаны на Си или компиляция была без оптимизации. Современный оптимизирующий компилятор C/Fortran очень сложно победить в эффективности кода, если и исходный текст вменяемый.

Причина банальна — просто в этих компиляторах формализована офигенская куча опыта по ручной оптимизации кода.
>>Современный оптимизирующий компилятор C/Fortran очень сложно победить в эффективности кода

Под ARM особо нет выбора — либо унылый gcc либо фирменный компилятор за многобабла. Даным давно я переписывал GSM декодер на асм — он стал работать в ~8 раз быстрее по сравнению с GCC 3.x

Под PPC ещё хуже. Там даже IBM-овский компилятор генерит отвратительный код. Gcc вообще беспомощен.
А Clang? Весьма приличный компилятор для ARM. Да и про GCC не понятны заявления. Покомпилировал свои программы сейчас — вполне приличный код.

Фишка может быть ещё и в том, что на Си Вы писали один алгоритм, а на ASM — другой. Компилятором, обычно, тоже надо уметь пользоваться.
Ы, это ты неписал под МК. Зачастую компиляторы такую херню выдают, что хочется разработчиков убить. Например, к обработчику прерывания, состоящему из двух полезных инструкций, одна из которых — выход из прерывания, компилятор добавляет десяток мусорных инструкций сохранения регистров, которые вообще не юзаются.
Во-во, я однажды столкнулся с ещё большей тупизной компилятора, который с какого-то перепугу решил выделять по два регистра на однобайтные беззнаковые переменные.
И подобные вещи происходят очень часто при кодинге под МК. А ведь всё просто: компиляторы пишут, внезапно, люди. А люди имеют свойство ошибаться, тупить, лениться и т.д. Что они и делают постоянно, и я тоже, и разработчики компиляторов — все! Нельзя слепо надеяться и верить в мифическую «мудрость» компиляторов, которые основаны на несовершенных алгоритмах.
которые основаны на несовершенных алгоритмах. людях!

fixed
Вообще-то это не компилятор. Это стандартный Си, у которого нет 8-битного режима работы. Стандарт предписывает, что все арифметические операции должны выполняться с типом int, если он достаточен по размеру. А размер int бывает либо 16, либо 32 битов в длину.

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

Компиляторы не достигли ещё уровня ИИ, поэтому им таки некоторые вещи надо подробно объяснять:

uint8_t reverse8bits(uint8_t bits)
{
        bits = (uint8_t)((bits & 0x55) << 1)
                | (uint8_t)((bits & 0xAA) >> 1); // меняем местами биты попарно

        bits = (uint8_t)((bits & 0x33) << 2)
                | (uint8_t)((bits & 0xCC) >> 2); // следом пары битов

        bits = (uint8_t)((bits & 0x0F) << 4)
                | (uint8_t)((bits & 0xF0)) >> 4; // и чертвёрки битов

        return bits;
}

Will do the trick for you :)

А вообще, AVR не является POSIX-платформой, и не разрабатывался, чтобы работать вместе с Си. Поэтому такие вот нестыковки и случаются. Народ, вроде, для C-проектов уже активно переходит на Cortex-M3.
Ой. В предпоследнем операторе последняя ) не там стоит. Но смысл, я думаю, понятен.
Вообще-то, предложенный вами вариант я опробовал сразу же — более того, я пошёл дальше и не только привёл к uint8_t всё, включая bits (на всякий случай), но и поставил постфиксы после числовых констант: (uint8_t)0x55u и т.п.
Компилятор всё равно не понял.
А какой у Вас компилятор? avr-gcc 4.6.1 понимает. Да и вообще, это древний приём, работал ещё во времена Turbo C.
В таком случае ассемблер даст ускорение.


В таком случае фиг знает сколько человеко-часов неплохого программиста, потраченные на шлифовку кода на ассемблере, могут дать ускорение. А могут и не дать.

Что характерно, в 99% случаев шлифовка кода на исходном «высокоуровневом языке» даст заметные результаты гораздо быстрее.

Еще раз: ассемблер — это просто один из инструментов, а не панацея. Универсального ответа на вопрос «что быстрее?» по-прежнему нет, увы.
Смотря как воспринимать этот вопрос. Если учитывать квалификацию программистов, время на разработку и т.д. — то нужно как-то определять вес разных параметров и оптимизировать сумму (скажем, за увеличение быстродействия на 10% мы готовы пожертвовать лишней неделей на разработку или нанять программиста не за 50к, а за 80 (считая, что качество программиста определяется зарплатой)). В этом случае оптимум все равно достигается на некотором языке программирования (в силу конечности их числа), но на каком именно — зависит от задачи и весов.
Если же мы забиваем на время разработки и считаем всех программистов сверхгениальными, то ассемблер точно окажется не хуже любого другого языка. А возможно и лучше.
Если мне будут платить всего 80к, то я ради Бобра и оптимизации к вам работать не пойду
Нифига у вас зарплаты в Уфе-то :)
Кстати, а знаете почему от ассемблера в конце-концов отказались? Нет, на тот момент преимущество С было еще под большим вопросом. Но начали появляться куски кода, которые С выполнял быстрее, чем программа сходу написанная на ассемблере. Да, впоследствии ее можно было оптимизировать и догнать или даже перегнать.
И именно для этого в Си есть возможность вставлять ассемблерные вставки? :) По-моему основная причина массового отказа от ассемблера, что Си позволяет писать быстрее без значимого уменьшения скорости, за исключением особо тяжких случаев, которые пишутся на асме.
По-моему, вы оба правы:
— Одна часть ассемблерщиков перешла на С, когда сишные программы стали ДОГОНЯТЬ их ассемблерные.
— Другая часть (более поздняя) перешла на С, когда сишные программы стали ПЕРЕГОНЯТЬ их ассемблерные. Ибо появилась внутрипроцессорная оптимизация потоков, которую очень хлопотно учитывать вручную (при написании кода), но которую легко учитывает компилятор при генерации кода.
Нет в стандарте Си ассемблерных вставок.
В стандарте нет (и быть не может), а в жизни есть!
НЛО прилетело и опубликовало эту надпись здесь
Вот очень интересный разбор от Фаулера The LMAX Architecture. На таких скоростях решает там, внимание, понимание работы современного железа.
НЛО прилетело и опубликовало эту надпись здесь
Гы-гы-гы :) deusex.com — Deus Ex: Human Revolution на Си++ :)
Вы путаете запуск приложения и его жизненный цикл. Джава приложения могут быть запущены месяцами и при этом каждую секунду обставлять конкруентов в производительности. Вот и где после этого выигрыш? Какой смысл моментально запускаться, если уже через секунду работы начинаешь отставать?
Если жизненный цикл 100мс? Я пробовал Java для веба. Даже презираемый многими PHP в CGI режиме обходит Яву. Про Си вообще молчу.
А зачем вы Яву с CGI режиме пытались использовать?
А почему не спрашиваете зачем PHP в этом же режиме? Я счёл априори некорректным сравнивать CGI-Java в CGI и PHP в mod_php с Apache (или fcgi с nginx). Поставил любимый язык (путь к сердцу мужчины лежит через его желудок, а PHP меня худо-бедно кормит) в заведомо невыгодное положение и в те же условия поставил изучаемый язык. Сравнение было некорректно? Надо было mod_java ставить?
PHP в любом режиме работает как CGI приложение, если только это не phpDaemon. С каких пор последний уже стал активно использоваться в веб-девелопменте и фреймворках?

Так что, сравнение совершенно корректное.
Не в любом. В рекомендуемых режимах интерпретатор не грузится при каждом запросе. При наличии кэшера опкодов, то и интерпретация исходников в опкоды не производится. Вроде всё как в Java, кроме того, что интерпретация в байт-код не ручками вызывается.
Помимо интерпретатора есть еще само приложение. Которое и работает в PHP в режиме CGI, каждый запрос заново читает конфиги, инициализирует объекты, выстраивает цепочку обработки запроса. И хорошо если хотя бы в используемом драйвере БД есть поддержка постоянных соединений, в противном случае еще и установка\закрытие соединения на каждый запрос.

Для маленьких приложений это не существенно, а для серьезных проектов с фреймворками, кучей классов, развернутой конфигурацией, модульной структурой, такая инициализация может добавлять солидный оверхэд на каждый запрос.
Java приложение в этом режиме работает также. И, почему-то, медленнее, не смотря на сильную типизацию, предварительной компиляции в байт-код и т. п.
Мартышка к старости слаба глазами стала;
А у людей она слыхала,
Что это зло еще не так большой руки:
Лишь стоит завести Очки.
Очков с полдюжины себе она достала;
Вертит Очками так и сяк:
То к темю их прижмет, то их на хвост нанижет,
То их понюхает, то их полижет;
Очки не действуют никак.
«Тьфу пропасть! — говорит она,- и тот дурак,
Кто слушает людских всех врак:
Всё про Очки лишь мне налгали;
А проку на-волос нет в них».
Мартышка тут с досады и с печали
О камень так хватила их,
Что только брызги засверкали.

К несчастью, то ж бывает у людей:
Как ни полезна вещь,- цены не зная ей,
Невежда про нее свой толк все к худу клонит;
А ежели невежда познатней,
Так он ее еще и гонит.
Поражаюсь вашим познаниям. Рассказали бы ещё к чему вы решили ими блеснуть?
Ну не знаю, у вас вообще никаких ассоциаций? Подсказка: Java — Очки.
Какая разница сколько оно стартует-то? :)
А зачем им быстро запускаться? Им надо быстро работать.

>А уж на каждое изменение все перекомпилировать, паковать, деплоить

Ну да, а в чём проблема?
Вы, видимо, «программируете» в стиле, поменял строчку — перезапустил всё нах, чтобы посмотреть что же такое в результате получилось и получилось ли что-то вообще? Ну, это, батенька, не там виновных ищите. Это что-то в консерватории поправить надо…
Тут явно не хватает этой картинки:
На такие отмазки можно отвечать так:

«А ну-ка покажите, что вы накоммитили в такую тучу мест, что инкрементальный make так долго всё собирает!?
Кого премии лишить за редкие коммиты?
А остальная команда как должна про ваши правки узнавать?!»
Хм, не вижу ничего зазорного в применении такой вещи, если возможности языка позволяют быстро перезапускать программу. А обратное — профдеформации на фоне невозможности таких операций.
Вы еще наверное в исполняющейся программе быстро докликиваете/дотыкиваете клавиши до нужного места, чтобы его проверить? :)
А вы, батенька, недооцениваете всех плюсов возможности быстро перекомпилировать и протестировать код.
Ну, компиляция у меня, положим, происходит по факту сохранения файла, а тестирование вы, по-моему, путаете с «посмотреть что получилось и получилось ли что-нибудь вообще». Манки кодинг, какой-то.

Иногда случаются, конечно, казусы, в стиле, — «Семён Семёныч, а схера ли здесь плюс вместо минуса», тогда, да, медлительность вставания сервисов несколько раздражает, но это ж еденичные случаи. Ни о каком ожидании по пол-дня ежедневно и речи быть не может.
Вот я и говорю, что недооцениваете.

Подтвикать коэффициенты, поменять плюс на минус, подогнать гуй за пол-минуты, и через 3 секунды посмотреть на результат — это очень удобно.
Как правильно сказали, коду на Java надо быстро работать, а не запускаться.
Код на C тоже должен компилироваться, но почемуто драйверы, сложные игровые движки, можделирование каких-нибудь биологических процессов на PHP никто не пишет в связи с этим.
Какая разница как быстро оно запускается, если оно запускается раз в неделю, а то и реже. Главное, чтобы быстро работало. А по второму пункту — далеко не всегда нужно на каждое изменение все паковать и деплоить. Например, (вы только никому не рассказывайте) есть class hot-swapping, который позволяет на лету заменять байткод без перезапуска приложения и JVM.
Так веть для хот-своппинга нужно и совместимость писать, данные-то не захотсвопишь.
А какие современные, а не тащущие BC чуть ли не с PHP3. У каких CMS минимальные требования 5.3.2?
У еще не написанных. А вы считаете, использование новых конструкций определяет качество кода?
Ну, как мне кажется, именно для этого их вводят. Позволяют писать более лаконичный код, без лишних сущностей типа функции из одной строки вызывамой в одном месте. Улучшают инкапсуляцию. Позволяют без проблем использовать циклические ссылки.
как минимум использование новых встроенных функций вместо самописных велосипедов увеличивает скорость
Главное что улучшает читаемость, имхо.
Ну да, это какие-то крайности. Сначала архитектура, диаграмма классов, взаимосвязей. В результате, имеем продуманную архитектуру и методы, которые уже надо заполнять кодом. И тогда встает вопрос — писать полотно с ручным распределением памяти, ассемблерными вставками и битовыми операциями, или же вызвать стандартный метод Merge() и не заморачиваться. Для начала, ИМХО, подойдет второй вариант. А если заказчика устроит, то вообще думать не надо. Иначе — да, открывать профилировщик и смотреть что/как/где/сколько.
Сначала архитектура, диаграмма классов, взаимосвязей. В результате, имеем продуманную архитектуру и методы, которые уже надо заполнять кодом.


И у вас этот подход действительно работает? Особенно с детализацией до уровня описания методов, которые «только осталось заполнить кодом»?
В моих проектах (не очень больших) — работает.
ТЗ по ходу проекта ни разу не менялось?
Менялось, были проблемы, работаю над этим. Основная мысль моего комментария — про использования более простых и понятных, но медленных алгоритмов и их реализаций, вместо сложных, трудоемких, но быстрых. А архитектура — другая тема, в моем комментарии просто для примера.
Неудачный, имхо, пример.
Только правильную архитектуру можно оптимизировать.
Если в общий подход и схематику закралась ошибка, или, так даже точнее, недодумка — сколько конечные функции не оптимизируй — всеравно ничего не получиться.
Хорошо это можно поняв переписав простейшую пхп страничку с 100 запросами к БД на node.js.
Время работы не измениться, код, по сути, тоже не измениться.
Вот только одновременно можно будет в 10, а то в и в 100 раз больше потоков обратывать.
Самый яркий пример опмитизации на моем опыте — ускорение голосового кодека melp. Исходный вариант был ускорен в 600 раз исключительно изменением архитектуры, так как принципы математической части для меня были туманны, а посему и не прикосновенны.
НЛО прилетело и опубликовало эту надпись здесь
Имхо везде нужен баланс. И оптимизировать всю программу/архитектуру непозволительная роскошь.

Как на этапе проектирования так и на этапе оптимизации можно предположить узкие или перенагруженные места. И строить архитектуру/оптимизацию под них. Остальной код можно писать не парясь, быстродействием, а парясь скоростью разработки и фунуционалом.

Естественно часто жизнь показывает, что «угадали не все буквы». Но в таком случае и сплошная оптимизация не спасла бы.

У меня был случай, когда вылизанная программа на асемблере решала задачу по обработке хитровыраженных массивов раз в 20 медленнее написанной левой ногой на С. Разница между этими программами несколько лет, за которые появился новый, более простой алгоритм.

Другое дело что в первом случае мне не жалко было времени (увлеченый студент, было прикольно все заоптимизировать).
На редкость хороший перевод, большое спасибо!

По поводу преждевременной оптимизации, выше уже были комментарии про разницу между оптимизацией архитектуры и локальных алгоритмов. К этому хочется добавить еще один критерий, помогающий решить: оптимизировать или нет.
Этот критерий — время, которое нужно затратить на оптизацию. Ведь зачастую бывает, что нужно просто выбрать: использовать ли массив, или словарь, или хэш-сет. И тогда это просто вопрос здравого смысла и опыта — при практически нулевых временных затратах на такую оптимизацию.
А вот если вы знаете, что на оптимизацию алгоритма или набора запросов к БД нужно потратить пару недель, в то время как написание простого алгоритма/запроса займет всего пару часов… тогда стоит задуматься: узкое ли это место? стоит ли того время, затраченное на оптимизацию? Ответив на эти вопросы, уже можно принять осознанное решение: оптимизировать или не оптимизировать.
Спасибо, приятно слышать, что качество перевода для кого-то имеет значение.
Не улавливаю смысл всей этой возни вокруг преждевременной оптимизации. Если есть опыт разработки хотя бы два-три года и маломальская теоретическая база в голове, то с современными средами-фреймворками писать неэффективный код это ещё постараться надо — почти все необходимые среднестатистические алгоритмы-структуры уже в фреймворке. А если для разработки выбран низкоуровневый язык, скажем С, где с фреймворками не так всё гладко, то наверное его и выбрали для того чтобы этими «преждевременными» оптимизациями заниматься.
Программирование чем-то похоже на писательство (не даром авторские права на программный код рассматриваются аналогично таковым на литературные произведения). И когда я читаю подобные универсальные советы (не важно — «избегайте преждевременной оптимизации» или «оптимизируйте на этапе проектирования»), мне сразу приходит в голову аналогия: универсальный рецепт по написанию бестселлера.
Т.е., если следовать духу этой статьи, надо сесть, расписать сюжетные ходы, составить список персонажей, каждого подробно описать (внешность, характер и т.п.), добавить в нужных местах всякие там описания природы, погоды и т.п., немножко юмора — и на выходе получится правильная, качественная книжка, которую будут с удовольствием читать миллионы!

Агатеперь. (с) «Учим слесарный язык»

Вы можете слабать программу на коленке, с помощью оптимизации кода расширить пару «узких мест» и получить шедевр. А можете — тормозное УГ.
Вы можете потратить полгода на проектирование и прототипирование, сделать все «по уму» и получить ровно такое же тормозное УГ (а можете и шедевр, кстати). Как мы все знаем, ошибки в проектировании обходятся куда дороже, чем ошибки в кодировании — и что, описанный метод гарантирует от ошибок? А если «узкое место» образовалось совсем не там, где вы его ожидали на этапе проектирования?

В чем прелесть программирования, как области человеческой деятельности, так это в непредсказуемости результата. Следуйте здравому смыслу — вот это, наверное, и есть единственный универсальный совет (который, кстати, тоже успеха не гарантирует)… На этапе проектирования применяйте разумные алгоритмы и структуры данных… Оптимизируйте только работающий код, нуждающийся в оптимизации… И (возможно!) результат вас порадует.

P.S. А вообще, к сожалению, большинство программистов наслаждаются процессом, а не результатом…
Предсказуемость результата есть признак профессионализма. Программа, действительно, может не выстрелить. Ее успех, действительно, не зависит от качества кода внутри. Но это не означает, что не надо уметь и писать, насколько умеешь, хороший код.
А Вы, простите, под «результатом» что именно понимаете? «Хороший код» — это не саомоцель. Вашим клиентам все равно, насколько хорош код в приложении, если оно их не удовлетворяет.
Если человек программист, то результатом его труда является код. И на этом фронте он должен сделать все, что может. Хороший код, как минимум, гарантирует гибкость и сопровождаемость. Ну, как от сапожника, вы же не ждете, что он вас жизни научит, а ждете, что он ботинок починит. Женитесь вы в этом ботинке или нет — гораздо более важный вопрос, конечно, но сапожник-то тут причем?
Если человек программист, то результатом его труда является программа. Код — это всего лишь инструмент, а не результат.
Так рассуждать, то и у сапожника ничего не понятно — кто-то в его ботинках пойдет на работу, а кто-то в луже уснет.

Пожалуйста, не могли бы вы сформулировать свою мысль прямо и недвусмысленно? Я абсолютно серьезно, пытаюсь и не могу понять, к чему вы клоните. Программист должен отвечать за все аспекты создания программы? Хорошие программисты никому не нужны, потому что для успеха программы качество кода не важно? Или что?
Пожалуйста, прямо и недвусмысленно:
Если программа получилась хорошей (т.е. удовлетворяет потребности пользователей, приносит деньги, выигрывает призы на конкурсах, распространяется миллионными тиражами и т.п.), то пофиг, насколько плох или хорош исходный код, а ее программисты — молодцы.
И, наоборот, если исходный код — произведение искусства, а программа нафиг никому не нужна — программисты не молодцы.

Программист, конечно, должен отвечать за все аспекты создания программы, находящиеся в его зоне ответственности. Если это «быдлокодер», которому дают задание сгенерить «черный ящик», удовлетворяющий определенным формальным параметрам, то уж качество его кода вообще мало кого волнует, лишь бы юнит-тестирование было успешно пройдено.
«Хорошие программисты» нужны, потому что это те, кто пишут хорошие и успешные программы, а не идеальный код.
Спасибо, понятно.
Программист, конечно, должен отвечать за все аспекты создания программы, находящиеся в его зоне ответственности.

«Хорошие программисты» нужны, потому что это те, кто пишут хорошие и успешные программы, а не идеальный код.

представьте себе что программист это писарь, которому нужно записать текст за писателем. Вы будете обвинять писаря в том что писатель надиктовал чушь?
Да часто попадаются писари, которые пишут с ашипками, коверкают слова, ставят кляксы на старницах… но порой содержимое текста так увлекательно что читатель старается этого не замечать.
Однако следует отметить — что лишь те тексты которые продиктованы талантливым писателем хорошему писарю — лишь они добиваются наивысшего успеха.
Вы, очевидно, очень хорошо умеете отделять свой труд от общего результата (см. А.Райкин — «к пуговицам претензии есть?»). Я вот так не умею, увы.

Опять же, если Вас удовлетворяет роль писаря, всего лишь переводящего чей-то устный текст (да еще и «чушь») в грамотный письменный, то я завидую Вашему отсутствию амбиций. Мне вот всегда было жаль тратить время на идеальное исполнение никому не нужных функций.
«тратить время на идеальное исполнение никому не нужных функций»
Так смените работу. Зачем вы исполняете никому не нужные функции?
Программист, конечно, должен отвечать за все аспекты создания программы, находящиеся в его зоне ответственности.
Увы, успех/неуспех программы часто зависит от факторов, лежащих именно ВНЕ зоны ответственности программиста.
Вы привели пример «программа нафиг никому не нужна». Это ошибка маркетинга. Конечно, если программист заодно еще и маркетингом занимался, то он и в этом тоже виноват. Но виноват уже как хреновый маркетолог, а не как хреновый программист.

Скажу более: в крупных проектах нет такого единого понятия, как «программист программы». Аналитики, методологи, постановщики задач, кодеры, тестировщики и т.д. Чьим из них результатом труда является «программа»? Кого ругать, если она провалилась?
А причем тут вообще какая-то «вина»? Если Вас волнует только вопрос «кого ругать?», то ответ очевиден — ругайте всех.

Если программа «нафиг никому не нужна» — то какая разница, насколько качественный в ней код и насколько хорошо она оптимизирована?
По сути, качество кода вообще не имеет никакого значения, если только оно не является основной причиной неуспеха программы.

Вы перечитайте эту ветку. Дискуссия началась с тезиса, что даже если программа «не выстрелила», то главное — что программист код хороший написал… Ну, типа, тоже утешение, да…

А причем тут вообще какая-то «вина»?
Так вы же сами говорили «ответственность», «должен отвечать». Какая же это ответственность, если в случае провала ответственные за проваленный участок работ (=виновные в провале) продолжают сидеть на попе так же ровно, как и в случае успеха?
Если вас коробит слово «виноват», то спокойно можете заменить его на «отвечает за провал» — смысл моих слов не изменится.

Если программа «нафиг никому не нужна» — то какая разница, насколько качественный в ней код и насколько хорошо она оптимизирована?
Для покупателя программы — никакой.
А вот для руководителя проекта, который обязан оценивать труд в т.ч. и программистов, — разница огромнейшая. Если ему это без разницы — гнать надо в шею таких руководителей!

Вы перечитайте эту ветку. Дискуссия началась с тезиса, что даже если программа «не выстрелила», то главное — что программист код хороший написал…
Еще раз перечитал. Ничего нового не обнаружил.
Ваша ошибка в том, вы пытаетесь свалить на программиста ответственность за неудачи на всех участках работ. А программист — всего лишь один из многих и отвечает только за свой участок работ.

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

Некоторые работают «на отвяжись», но это просто плохие работники. Или они попали не на ту работу.
>свою работу он должен сделать максимально хорошо

А что такое хорошо?
Вот допустим программист Петя написал гибкий и сопровождаемый код, цитаты из которого можно в учебники вносить, и при этом почти уложился в срок, ну запоздал процентов на 5-10, да положим даже сдал работу точно вовремя. Он хорошо сделал свою работу?
А программист Вася из конторы-конкурента, которому дали похожее задание с тем же сроком, он «набыдлокодил» по-быстрому результат, сдал задачу на 50% раньше срока, благодаря чему его компания успела выпустить продукт раньше конкурентов, в том числе и Петиной компании.
Так кто по-Вашему лучше выполнил свою работу, Петя или Вася?
От рынка зависит.
Вот именно. Поэтому и программист, пишущий к примеру web-приложения, должен применять к своему коду несколько другие критерии качества, нежели программист, создающий ПО для космических аппаратов.
Попробовали пользователи этот продукт, поплевались от глюков и тормозов, а тут раз, уже и Петина версия готова, на нее все и перешли. А Вася тем временем вынужден половину переписывать заново.

Это в лучшем случае, в худшем, Вася допустил такую ошибку, через которую хакеры проникли в компьютер пользователей (или на сервер компании) и утащили от туда личную информацию, а то и номера кредитных карт.

Но все это так, сказки-сказками. На которые сбегутся маркетологи и нараскажут мне своих, и что я не прав.

А обычно все проще. Если нужно быстро, нанимают дешевых Code Monkeys, они все сделают. А если надо качественно, нанимают Петю.

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

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

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

ЮТак же, как и чьим продуктом хотел бы пользоваться.

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

Если программу Васи пользователи будут материть, а программу Пети советовать знакомым, то и с маркетинговой точки зрения, в долгосрочной перспективе Петина работа лучше.
Вижу вариант — сначала Васину программу вбрасывают быстро на рынок и, не смотря на маты, получают достаточно денег, чтобы перекупить Васю, дав ему карт-бланш (или не дав).
*перекупить Петю
Петя в профите, как не крути! =D
Но не фирма, которая ему платила деньги за гибкий и сопровождаемый код.
Это уже вопросы к руководству фирмы, не сумевшему все спланировать и рассчитать. Точно так же перекупив Петю, у фирмы, в которой работал Вася, магическим образом не появится сразу гибкий и сопровождаемый код.

Опять все сводится к тому, а что изначально делали? Для написания быстрого прототипа, чтобы просто проверить бизнес-модель, в самом деле высокооплачиваемый Петя с гибким и сопровождаемым кодом не нужен.

Точно так же, и код, который вы пишите чтобы проверить какую-то теорию, провести тесты и принять решение, наверняка отличается по качеству от того кода, что будет закоммичен в мастер/транк.
У фирмы, в которой работал программистом Вася уже есть пускай и негибкий, и не сопровождаемый, но, главное, рабочий продукт, который приносит деньги и на Петю, и на его начальника Васю :)

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

Вообще на современном рынке ПО очень редко когда скорость разработки не имеет значения. А проектирование, оптимизация, тестирование — это всё небесплатно, это занимает время. И программисту надо быть на связи с реальностью и трезво оценивать, имеет смысл потратить дополнительное время например на оптимизацию, или нет.
Это тоже мастерство: уметь писать совершенный код, но когда надо — написать быстро, пускай и не очень красиво. А ещё большее мастерство — уметь определять тот самый момент «когда надо».

И примерно это, на мой взгляд, имел в виду dzhe, когда писал, что ориентироваться лучше на результат, а не на процесс.
Уважаемый, вам сегодня код какой написать? Очень хороший (12ч), хороший (8ч), средне-хороший (4ч), средний (2ч), хуже среднего (1ч), или совсем плохой (10мин)?

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

Вы думаете вот, например я, оптимизирую код? Да нет же, я его просто пишу.

Результат работы программиста — код. dzhe почему-то пологает, что программисты делают продукт. Может быть в каких-то маленьких фирмах, или при работе на самих себя они и делают программы, которые являются конечным продуктом. Но на самом деле программный продукт — это результат работы множества людей, начиная от топ-менеджмента, бухгалтеров, HR-отделов, отделов маркетинга, менеджеров и еще кучей народу, заканчивая столовой и бабкой уборщицей. Все прямо или косвенно влияют на процесс.

А задача менеджеров заключается в обеспечении программистам комфортных условий работы, в которых они будут выдавать код такого качества, на который они способны, с той скоростью, с которой способны.
няда, куда-то торопился…
— если только он не *торопится
— *полагает
Один и тот же разработчик в основном выдает всегда одинакового качества код

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

Но Ваша точка зрения понятна.
Есть кодинг, и к нему прилагается тестирование и багфиксинг.
Есть архитектура, к ней прилагается профилирование и оптимизация.
Это разные по сути процессы и не надо переживать о глобальной оптимизации во время кодинга класса или метода. Естественно при этом писать здоровый. рациональный и красивый код, который не будет страдать излишествами, которые потом придется вычищать.
Полностью согласен с dzhe (http://habrahabr.ru/blogs/programming/126818/#comment_4184524).
Нужен элементарный здравый смысл. А это знание базовых алгоритмов обработки данных, понимание того, что такое память и указатель. Знание языка, которым пользуешься, знание его фреймворка, библиотеки классов, и то как эти классы работают с памятью. Еще обязательно надо знать зависимость времени выполнения тех или иных операций от объёма данных.
Если этих знаний не иметь, то ничего хорошего не выйдет в любом случае. И часто под понятием оптимизация подразумевают замену не к месту используемых классов и алгоритмов на более подходящие. Лично я это считаю исправлением грубых ошибок, а не оптимизацией. По моему оптимизация — это процесс не замены неверного на верное, а процесс замены верного кода, на верный код, который выполняет ту же задачу, но лучше по определенному параметру. Как правило это или время выполнения, или объём потребляемой памяти.
Ну, если неверно использованный класс, паттерн или алгоритм всё же выдают правильный результат, то это не ошибка, по-моему. И замена его на более подходящий более лёгкий по какому-то параметру без изменения результата будет как раз оптимизацией.
Это не всегда так. По вашей логике, если нужно сложить 2 числа можно сделать так:

int a = 2;
int b = 2;
string expr = a.ToString() + "+" + b.ToString();
ExpressionCalculator calc = new ExpressionCalculator();
int c = calc.Eval(expr);

А потом переписывание этого кода в «int c = 4;» назвать оптимизацией. Замена конструкций, которые явно противоречат здравому смыслу это никак не оптимизация.
Время от времени копаюсь в коде менее опытного коллеги. Типичные ошибки — использование List<T> вместо T[], в местах, где требуется буфер статического, заранее известного размера. LinkedList<T> когда операций доступа к списку 99%, а операций модификации 1%. Пару раз натыкался на использование Dictionary<int, T> в местах где можно было бы использовать линейный индекс, т.е. List<T>. И еще много чего, не говоря уже про полный бардак в обработке исключений, выделение жуткого количества ненужных объектов, использование LINQ где только можно и т.д. Т.е. вещи, которые явно противоречат здравому смыслу.
А потом переписывание этого кода в «int c = 4;» назвать оптимизацией.
Увы, в русском языке это будет называться именно оптимизацией (см. gramota.ru или википедию).

Замена конструкций, которые явно противоречат здравому смыслу это никак не оптимизация.
В определение понятия «оптимизация» не входит понятие «здравый смысл».

Да, ваша пример будет считаться оптимизацией. А каким образом или с какой целью был создан начальный, неэффективный исходный код — по глупости или предумышленно — это дело десятое.
Не понял, что за язык, но смысл понятен. Да это решение можно назвать нормальным, если ExpressionCalculator не пишется самостоятельно, а используется готовым и является достаточно универсальным, чтобы не только складывать, и не только целые (какой разрядности?) числа.

Имхо, задача программиста решена, если программа выдаёт правильный результат и соответствует другим не взаимоисключающим (включая себестоимость) требованиям. Опытный программист найдёт противоречия на этапе сбора инфы для чтения ТЗ. Его менее опытный коллега гораздо позже, а может и не заметит вовсе.
Нужно писать, в первую очередь, понятный код, а оптимизации обычно сильно вредят читаемости. Лучше в конце изуродовать в угоду скорости 5% кода, и получить 80% возможной оптимизации. А вот ошибки в архитектуре это совсем другая тема
Просто вы предпочитаете оптимизировать читаемость за счёт ресурсов компа :)
Если переписать код на ассемблере можно ускорить еще раз в 3-10, но читабельность станет нулевой. В наше время практически нет такого кода, который можно один раз написать и больше не трогать. И да, с темпами роста производительности читабельность — главная ценность.
Из-за такого подхода мы и видим, что современный аналог программы 10-летней давности с примерно тем же функционалом на современном железе тормозит так же, как старая версия на старом железе.
Да, рост производительности позволяет не гоняться за мелочами.
Но вот недавний пример из моей практики. Некоторый проект на python, занимающейся определенной обработкой текстов. На 500 000 текстов отрабатывал где-то за час. После замены 40 строк на питоне 10 строками на питоне и 150 строками на С++ на тех же 500 000 текстов стало работать за ~3 минуты. Никаких принципиальных изменений в коде не происходило — там list (в питоне так называются массивы, если что), тут vector, там set, тут set.
Читаемость сильно пострадала, зато появилась возможность проводить эксперименты.
Если что в python аналогом C-массивов является не list, а, сюрприз, arrayю Основное отличие — строгая типизация элементов.
Простите, а как сделать массив объектов через array?
Про объекты вы ичего не говорили.
Читабельность ассемблерного кода я считаю далеко не нулевой. Вот его писабельность очень к нулю близко. Есть, правда, ещё HEX?OCT. А ещё представление в виде горящих светодиодов — вот это самое трудночитаемое на моей практике.
НЛО прилетело и опубликовало эту надпись здесь
На практике такого не случится никогда. Ни-ког-да. Если вы не ставили производительность во главу угла с самого начала, то неэффективные решения будут появляться повсюду, заражая каждый квадратный килобайт кода в вашем проекте.
Такая категоричность справедлива лишь для бестолковых программистов.

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

По крайней мере, у меня сейчас практически всегда так. Мне не надо СПЕЦИАЛЬНО заниматься оптимизацией ДО ТОГО, как я напишу код, — в подавляющем большинстве случае он у меня получается вполне удовлетворительным с точки зрения производительности. А в тех редких случаях, когда «не угадал», как правило, приходится переписывать лишь отдельные узкие места и чаще всего их не угадаешь ДО НАПИСАНИЯ КОДА.
Автор конечно написал очень цветисто и эмоционально, но хочется отметить несколько деталей.
1) профилировать надо уметь
2) попытки оптимизации без реальных замеров очень часто делают код медленнее
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории