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

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

Разработчик.

Я бы не назвал причину потребности в рефакторинге «огрехами» программистов.

Рефакторинг является неотъемлемой частью современных подходов к разработке (вроде Behavior Driven Development). В упрощенном виде цикл выглядит так:

1. Напиши проваливающиеся тесты для новой фичи.
2. Разработай фичу так, чтобы тесты выполнялись.
3. Рефакторинг!

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

Какое-то время назад я думал что это самое правильное сначала писать тесты и потом писать код который будет работать как задумывалось. И переодически пробовал заставлять себя так делать. Но потом посмотрел это видео www.confreaks.com/videos/3315-railsconf-keynote-writing-software и обдумал этот момент еще раз.

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

Я пришел к подходу делить код на части, это как предприниматель малого бизнеса, по началу делает все сам, и когда задач становится слишком много — поручить их другим людям. Так-же в коде, если один кусок становится слишком большим или начинает решать более чем одну задачу — значит нужно его распилить на части в следующий этап рефакторинга. Тогда код получается легче читаемый и логичный, с проектирован с целью выполнения задачи и быть легко обслуживаемым (maintenance www.youtube.com/watch?v=c-kav7Tf834)

Так-же и тесты писать, тестировать как каждый элемент решает поставленную им задачу, и как все это работает вместе (integration test)

Еще интересное видео об абстракциях www.confreaks.com/videos/3852-rdrc2014-magenta-is-a-lie-and-other-tales-of-abstraction
> Тогда у вас получается код который написан с целью озеленения тестов, спроектирован чтобы его было легко тестировать. Я считаю что код должен решать бизнес задачи, тесты проверять код и помогать разработчиками быть увереными в их коде (экономить время и нервы на тестирование).

Не вижу, как юнит-тесты противоречат тому, чтобы код решал бизнес-задачи.

> Какое-то время назад я думал что это самое правильное сначала писать тесты и потом писать код который будет работать как задумывалось.

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

> Так-же сталкивался с тестами которые тестируют слишком много, например stub каждый метод внутри тестрируемого компонента, это приводит к тому, что когда код подвергся рефакторингу все эти тесты ломаются

Как раз в этом видео и рассказывается, как решить эту проблему, не отказываясь от тестов.

> Я пришел к подходу делить код на части

Какой же из этих принципов вы для себя открыли? Разделение ответственности, инкапсуляция, абстракция, слабая связность.
Посмотрел ваши ссылки и пришел к выводу что разница между теорией и практикой на практике больше чем в теории :)
Думаю вы имеете ввиду «Разделение ответственности», я не открыл принцип для себя, я понял как правильней для меня разделять эти ответственности.
И как же это событие навело вас на мысль, что test-driven development (и вообще юнит-тесты) вредят проекту?
Потому-что «test-driven development» подразумевает что тесты первичны, и код вторичен. Как-бы тесты определяют какой должен быть код.
Возможно если вы пишите код с целью научится писать тесты — то это верно, они первичны, если пишите код с целью развлечься и попробовать новые технологии — тогда это можно назвать «fun-driven development». На недавней конференции red dot кто-то упоминул что у них бывает «conference-driven development» (код пишут чтобы показать на конференции и не выглядеть бездельником), разработчики языка ruby говорили об chrismas-driven development :)

Я считаю что обычно первичны бизнес требования, т.е. делать что-то, быть решением для какой-то проблемы и в том числе, быть легко поддерживаемым, это одно из бизнес требований.

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

Я не считаю что тесты вредят проекту, ни в коем случае, но концентрироваться только на тестах и ставить их выше первоначальной задачи может привести к затратам времени. Еще есть мнение что scrum и tdd (или bdd) делают разработку более гибкой, это не всегда так. Вывает что н ужно иногда писать код чтобы посмотреть будет ли это работать и хорошо выглядеть, тогда написание тестов будет тратой времени, и в этом случае включается еще один менеджер или технический руководитель который следит чтобы весь код был покрыт тестами, и пытается доказать что passing тесты и соблюдение scrum важнее.
Тесты нужны чтобы упрощать жизнь нам, разработчикам. Мне, например, лучше спится, когда я добавляю новую фичу в код покрытый тестами и сохраняю их при этом зелеными. Не на 100%, но близко к тому я обеспечиваю себе гарантию, что старый функционал не рассыпался частично или полностью. Без тестов можно писать небольшие программы, либо тестировать руками, что совсем не айс.

Я стараюсь писать тесты первыми, когда это возможно. И тут дело не в методологии, а в том, что я буду тестировать новую фичу в любом случае. Руками либо автоматически. Со вторым проще. Но если протестировать автоматически сложно, или долго, или сроки реализации поджимают, то, конечно, нужно писать код, и потом по возможности покрыть его. Очень сомневаюсь, что существуют команды, применяющие TDD без исключений по обстоятельствам.
Тестами все не покроешь. Асинхронный код очень сложно покрывается тестами.
Исключительные ситуации (например в какой-то момент времени отваливается подключение к интернету, или пользователь выдернул флешку) — сложно покрыть.
Код рендера — еще сложнее покрыть тестами.
Вот и выходит, что TDD оно конечно хорошо, но применимость его очень ограничена. А если внедряя новую фичу (без рефакторинга старого кода), ломается основной функционал — то явно что-то не так с архитектурой. Ну а если с архитектурой все так, то получается, что тесты нужны только при рефакторинге. А значит нужны только к уже написанному коду.
Я пытался когда-то освоить этот TDD, но увы, он как то перпендикулярен практике. Я тесты все равно делаю, ибо во многих вещах без них никак, но они у меня вторичны.
Про код рендера — в гугле работают автоматические тесты, которые проверяют что рендеринг сайтов не сломался.

Тесты, в частности и нужны, чтобы с архитектурой было все так.

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

У вас новые фичи никогда не требуют изменения общих кусков кода? Как вы этого добиваетесь без рефакторинга и дублирования кода?
Вы сами практически ответили на свой вопрос. Рефакторинг должен быть отдельно, фича — отдельно. Рефакторинг — это очень сложно, и в момент рефакторинга может поменяться логика. Тут хорошо бы тесты. Но возьмем например паттерн MVC. Тестами реально покрыть только Model. А controller, и тем более view покрыть тестами практически нереально.

Мое личное мнение, тесты обязательно нужны, но не такой фанатизм как TDD.
>>>Тут что-то добавили, или тут переместили. В результате тесты упали (как и должны), и надо обновлять все тесты?

Это зависит от того, что есть System under test, следуя Пути Тестовой Пирамиды у вас не должно быть много тестов тестирующих страницу целиком.

>>>Рефакторинг — это очень сложно, и в момент рефакторинга может поменяться логика.

В момент рефакторинга не должна меняться логика. Это достигается использованием автоматических инструментов (типа Resharper) и тестами. Потребность в конкретном рефакторинге часто возникает при имплементации конкретной фичи. Для этого сначала делают рефакторинг, потом проверяют его результат, потом имплементируют фичу на рефакторенном коде. Или как в TDD (red->green->refactor) пишут новую фичу копипастом, потом объединяют получившиеся куски. С точки зрения управления продуктом рефакторинг в этом случае промежуточный этап при выполнении фичи.

Цытата:

www.jamesshore.com/Agile-Book/test_driven_development.html

«How can I use TDD when developing a user interface?

TDD is particularly difficult with user interfaces because most UI frameworks weren't designed with testability in mind. Many people compromise by writing a very thin, untested translation layer that only forwards UI calls to a presentation layer. They keep all of their UI logic in the presentation layer and use TDD on that layer as normal.

There are some tools that allow you to test a UI directly, perhaps by making HTTP calls (for web-based software), or by pressing buttons or simulating window events (for client-based software). These are essentially integration tests and they suffer similar speed and maintainability challenges as other integration tests. Despite the challenges, these tools can be helpful.
»
В момент рефакторинга не должна меняться логика.
Допустим функция раньше возвращала только номера домов. После рефакторинга она может возвращать структуры, в которых есть номера домов. Логика поменялась? Я думаю да. Но никто пока еще не использует новую информацию. Это еще рефакторинг или уже фича?

TDD is particularly difficult with user interfaces because most UI frameworks weren't designed with testability in mind.
Это один из примеров, когда TDD не может покрыть часть кода. Туда же еще можно смело добавить исключительные ситуации (не установлены драйвера, юзер выдернул флешку, оборвалось соединение и т.п.). Туда же во многих случаях можно добавить асинхронный код. И того на моей практике TDD может покрыть мизерный объем кода, т.к. я разрабатываю прикладное ПО.

p.s. Не исключаю, что TDD будет полезно разработчикам библиотек.
1. Если есть новая информация, то это скорее добавление мертвого кода, чем рефакторинг. Я бы разбил на два этапа: преобразование в структуру с единственным полем и добавление новых полей с использующим их кодом.

2. Почему вытаскивание флешки не тестируется? С асинхронным кодом не знаком но поиск что-то находит. Заметьте, шор делает оговорку про использование фреймворков не предназначенных для тестирования, во-вторых, можно побольше логики выжать, например из View во ViewModel, чтобы кода для тестирования view почти не было
Флешка может быть вытащена в любой момент времени, точно так же, как и в любой момент времени может произойти асинхронное событие.

А тесты должны быть детерминированы по определению.
«метод может получить любую строку на вход, а тесты должны быть детерминированы по определению => метод не может быть протестирован вообще. „

Давайте разберем конкретный пример кода и требования которое вы хотите протестировать?

PS. Про детерминированность тестов: en.wikipedia.org/wiki/Fuzz_testing
techblog.netflix.com/2012/07/chaos-monkey-released-into-wild.html

«метод может получить любую строку на вход, а тесты должны быть детерминированы по определению => метод не может быть протестирован вообще. „

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

В то же время, как Вы будете полностью покрывать тестами код в смысле, который накладывает TDD, если, например, реальный порядок вызова функций у Вас может быть практически любой, при этом функции то друг от друга зависят, например это обработка одного TCP-соединения с клиентом?

PS. Про детерминированность тестов: en.wikipedia.org/wiki/Fuzz_testing
techblog.netflix.com/2012/07/chaos-monkey-released-into-wild.html

Да, такие методики существуют, но на мой взгляд они не укладываются в парадигму TDD.
1. В синхронном коде я не вижу проблем с тестированием обработки исключения от выткнутой флешки
2. Асинхронный код я не знаю, но давайте разберем какой-нибудь конкретный пример мне самому интересно:
— дайте пример кода
— дайте пример требования, которое нужно протестировать (я бы предпочел C# )
3. Так как по запросу «async TDD» что-то находится, хотелось бы от вас тезисно разобрать хотя бы одну из известных вам рекомендаций по тестированию асинхронного.
В синхронном коде я тоже не вижу проблем.
В асинхронном коде я не вижу проблем протестировать каждый callback в отдельности, но вот как нормально тестировать их последовательности я не знаю.

Пусть есть такой запуск асинхронных операций:
io_service.async_read(socket, read_cb);
io_service.async_write(socket, write_cb);
io_service.async_timer(timeout, io_timeout_timer_cb);
которые внутри отрабатывают какой-либо протокол взаимодействия. Функции *_cb будут запущены при появлении запрошенного события, которые могут произойти в любом порядке.

Так как в общем случае клиент мне не подконтролен, то он может, как читать из сокета, так и писать в него, так и вообще отвалиться, допустив срабатывание таймера в любом порядке. Более того, клиент вообще может сгенерировать в сокет какой-либо мусор и write_cb должен это корректно обработать.

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

Я в таких случаях в основном использую нечто подобное Fuzz_testing эмулируя проблемы иногда хардварно (выключая порты на коммутаторе) или путем kill -9 клиентских или серверных компонент в произвольные моменты времени с последующим анализом детальных логов и coredump, если что-то пошло не так и они случились.

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

Я не вижу в чем проблема протестировать write_cb на неприятие мусора — вызвать его с мусором, и протестировать что результат совпадает с ожидаемым.

2. Проблема взаимодействия асинхронного кода. Тут хотелось подробнее — в данном коде взаимодействие не показано вообще.

Давайте выберем конкретное требование и посмотрим какие сложности возникают.

>>>Я могу протестировать данный код в случае, если вторая сторона диалога исполняет свои обязанности корректно

Дык TDD это про тестирование известных требований, а не про выдумывание новых. Я бы насытил код ассертами на предусловия, постусловия и инварианты и прочей диагностикой, чтобы схватить ошибку как можно раньше.
1. Вы не знаете контракт клиента полностью — это решается его исследованием

Я его не знаю, так как в реальной эксплуатации я его не контролирую. На той стороне может оказаться telnet, в который пишут /dev/urandom.

Я не вижу в чем проблема протестировать write_cb на неприятие мусора — вызвать его с мусором, и протестировать что результат совпадает с ожидаемым.

Это да, отдельно тестирование проблем не представляет.

2. Проблема взаимодействия асинхронного кода. Тут хотелось подробнее — в данном коде взаимодействие не показано вообще.

А это не суть важно. Как-то взаимодействуют и все. Сколько вариантов порядка вызова трех функций есть?

Дык TDD это про тестирование известных требований, а не про выдумывание новых.

Э, стоп. Те TDD это только проверка корректного поведения в случае корректных входных данных?

У меня требование — работать в случае получения от клиента любого мусора. Если получен мусор нужно ругнуться ошибкой и закрыть соединение.
Опять же я не могу предугадать, что будет делать клиент, а следовательно нормально покрыть тестами эту часть.
Корректное поведение предсказуемо и нормально покрывается тестами. Отлов некорректного поведения может быть только частичный, все некорректное поведение другой стороны — счетное множество комбинаций (пусть время квантуется).

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

Ну это же не тестирование, а инструменты постанализа, когда приложение уже упало от чего-то. Без них Fuzz_testing, можно сказать, невозможен.
>>>А это не суть важно. Как-то взаимодействуют и все. Сколько вариантов порядка вызова трех функций есть?

Тестирование вообще невозможно потому, что порядок вызова функций зависит от входных данных. Так?
При чем тут асинхронность вообще?
TDD и абсолютная 100% уверенность в корректности кода это разные вещи.

>>>У меня требование — работать в случае получения от клиента любого мусора. Если получен мусор нужно ругнуться ошибкой и закрыть соединение.
>>>Опять же я не могу предугадать, что будет делать клиент, а следовательно нормально покрыть тестами эту часть.
>>>Корректное поведение предсказуемо и нормально покрывается тестами. Отлов некорректного поведения может быть только >>>частичный, все некорректное поведение другой стороны — счетное множество комбинаций (пусть время квантуется).

Некорректное поведение тоже предсказуемо и нормально покрывается тестами. Например если на вход функции подается строка и корректными являются строки длинной от 1 — до 10 символов не надо перебирать все варианты достаточно послать null, пустую строку и строку длинной 11 символов.

Причем соверщенно пофиг какие именно эти 11 символов. Надо тестировать классы эквивалентности а не все варианты входных значений.

en.wikipedia.org/wiki/Equivalence_partitioning

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

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

Причем соверщенно пофиг какие именно эти 11 символов. Надо тестировать классы эквивалентности а не все варианты входных значений.

В асинхронном коде количество классов эквивалентности растет очень быстро. Произвольный порядок вызова нескольких функций — это еще простейший случай. Остальное будет зависеть от реализации этой асинхронности.
В-общем, непонятно, при чем тут TDD — TDD не требует покрытия всех классов эквивалентности, оно требует писать код только после красного теста и писать самый простой код который проходит тесты.
Вот для асинхронного кода такие тесты написать очень сложно. А после того как тесты написаны — пройти их, и получить на выходе нерабочий код, но проходящий тесты — проще простого. Причем то, что код нерабочий — будет заметно далеко не сразу, а после того, как порядок вызовов поменялся при каких-то неизвестных условиях. Например машина клиента более производительна, и часть команд пошла в другом порядке.
Если хотите практического примера — напишите например простенький сетевой протокол, в котором клиенты могут регистрироваться, подтверждать регистрацию через ссылку на почте, логиниться, менять пароль, восстанавливать утраченый пароль. Ну и конечно помимо этого залогиненые пользователи могут аплоадить картинку/текст, удалять/заменять то, что саплоадили.
Замахаетесь через TDD покрывать такое. А это еще очень мало «возможностей» у пользователя.

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

2) В тесте подсунуть фейк объекта файловой системы выбрасывающий тот же эксепшн, что и при выдергивании флешки

3) Я не вижу никаких сложностей в разработке вебсайта в стиле TDD
НЛО прилетело и опубликовало эту надпись здесь
Дык теперь вы это знаете и перед устранением ошибки можете добавить это в тест.
НЛО прилетело и опубликовало эту надпись здесь
>>>Причем то, что код нерабочий — будет заметно далеко не сразу, а после того, как порядок вызовов поменялся при каких-то неизвестных условиях.
Еще мне кажется что вы рассматриваете TDD как святой Грааль достижения безглючного кода — то есть что он может помочь в ситуации когда вы даже не знаете условий при которых возможны ошибки. Его, на сколько я знаю, никто так не рассматривает. Просто вместо ручного тестирования во-первых, вы пишете код. Во-вторых, путем юнит тестинга добиваетесь более расширяемого дизайна (если код можно протестировать UT — это значит что он уже работает в двух окружениях — продуктивном и тестовом)
НЛО прилетело и опубликовало эту надпись здесь
запускаем море экзепляров программы и поверх запускаем какой-нить набор автоматических Acceptence тестов. Честно случайно выдёргиваем флешку (тут понадобится эмулятор железа). Тест гоняем пару суток.
Вы сейчас предлагаете интеграционные тесты. Это не TDD.
По описанию: если проблема вылезла, её нужно решать сейчас. И докупить железо — единственный надёжный вариант.
А если просить «оптимизировать», то надо выделять ресурсы разработки, которые зачастую нечем заменить (новому человеку требуется время для погружения) и обычно это дороже.
Но это по описанной ситуации.
А вообще всегда есть масса нюансов: например узким местом можеть быть БД и тогда «оптимизация» — работа админов. А иногда нужно просто переписать кусок на другом языке. Так что только собрав спецов и проанализировав ситуацию можно найти оптимальную для данного проекта стратегию.
например узким местом можеть быть БД и тогда «оптимизация» — работа админов.

Админов ли? Бывает, ORM такие запросы генерит, что ручное переписывание самых тяжких снимет проблему.
По всякому бывает.
Если БД стала узким местом, то проблема в 90% случаев в запросах и админы зачастую не в состоянии её исправить.
Могут поспособствовать, если будут высылать разрабам лог медленных запросов + лог частых запросов, которые по какой-либо причине не попадают в кеш (либо просто лог частых запросов). Ну и могут сами поковырять статистику кешируемых запросов и «подкрутить гайки».

Explain медленных запросов помогает выявить неиспользуемые/несуществующие индексы либо просто обратить внимание на потенциального/реального «убийцу» производительности и как-нибудь его переосмыслить.

Частые запросы позволяют наметить кандидатов в NoSQL-хранилища либо обратить внимание на тонкости реализации механизма кеширования в БД. Например, при миграции с MySQL на MariaDB можно «зевнуть» момент с кешированием вложенных запросов, которое при этом отключает кеширование главного запроса. Поэтому запрос, которого не было видно в логах MySQL, может «внезапно» всплыть после миграции и обратить внимание на пробел в знаниях относительно используемой БД.

Ещё лог частых запросов порой выцепляет неизменяемые запросы, случайно попавшие в цикл в программе. По разным причинам они могут не быть закешированными, а потому будут исправно гонять запросы по базе, тогда как на деле всё это — простая ошибка программиста (и code-review'ера; оба её пропустили, т.к. запара, горячка, ворох новых фич, восемь дедлайнов и пять шрёдинбагов).

Наконец, анализ кеша может привести к повышению выделенной под него памяти (и, как следствие, разгрузки всей БД, если делать это правильно) — а то и просто к его включению :)
>> И докупить железо — единственный надёжный вариант.

Да как сказать — порой просто index проставить надо, забыли…
Или, наоборот — не нужен был, а потом кто-нибудь в условия добавил поле, по которому индекса нет.

...

Как я вижу, основные проблемы две — это БД и нагрузка на диск.
Остальное, в принципе, всегда справляется без проблем.

Нагрузка в БД создаётся зачастую из-за неправильных запросов или отсутствующих / лишних индексов.

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

...

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

Другое дело, когда код написан года 2-3-6-10 назад, и там тяжело что-то уже оптимизировать — устарело всё на корню.
Влезешь в код, постараешься оптимизировать, а в итоге не то, что не оптимизируешь, так ещё и баги вылезут…

Или же, сервер на издыхании держится, потому что от времени устал уже читать-писать.
И тут, например, SSD воткнуть или памяти «пару планок» доставить, а то memcache да PHP почти всё отъедает.

...

Моё мнение — надо каждую проблему рассматривать всем трём сторонам (хотя, можно и двум — админам и программистам).
Там уже надо решить — что быстрее, дешевле и оптимальнее — купить железо или поправить запрос.
Ведь может так случиться, что косяк в скрипте — буфер не очищается, и хоть ты 120 Гб памяти поставь — всё равно она вся забьётся.
НЛО прилетело и опубликовало эту надпись здесь
В условиях рынка оптимизация никогда не будет на первом месте. ПМу нужно только фичи делать, а как их делать? А вот так: «Хренак, хренак и в продакшн»… А потом ещё удивляются, почему оно жрёт столько памяти или проца.
Иной раз посмотришь на сервисы, фичи у них явно на последнем месте.
А вот борьба с пожиранием памяти это одна из основных задач.
О каких сервисах речь?
Instagram взять, к примеру. Миллионы инвестиций, а клиент на iOS нативный никак не сделают (потому что старый работает и ладно). Социальных опций не добавляют, наверное опасаются конкуренции с самим FB. У меня много на заметке сервисов, где фичи не могут прикрутить уже долгое время (не помню названия). Но в то же время мало тех, где фичи добавляют раз в месяц под гнётом ПМ и по принципу хренак-хренак. У вас есть примеры таких?
Эк у вас N*2 на железки-то, чай не ВЦ РАО ЕЭС. Если это не тиражируемое решение, то это 0.005*N ;-) Почему так? А на амортизацию в 10 лет или сколько там положено, разделите.

А если тиражируемое — то надо смотреть тираж. Экономия в 50 центов на миллион устройств — это ого-го, это на три рефакторинга хватит и еще на фичи останется.
Выскажусь с необычной для этого вопроса точки зрения.
Я пользователь. И считаю, что программисты должны оптимизировать код! Ожирение софта и ощутимое снижение производительности с ростом функционала можно наблюдать повсеместно.
В данном случае софт крутится на серверах и пользователя в браузере не должно заботить, сколько ресурсов потребляется. Главное, чтобы все работало быстро и правильно.
Иногда с пользовательской стороны ощутимо различается, в чём же причина лага — код медленный или сервер слабый. Да, не всегда, но зачастую подмечаешь фоново, что эту сортировку списка или выбор пункта из подгружаемой таблицы можно было бы реализовать быстрее. И речь не о юзабилити, а именно об оптимальности применённого решения.
Ну и про общее впечатление от скорости интерфейса тоже не стоит забывать, см.ниже интересную заметку в тему
habrahabr.ru/post/223705/
Тоесть как — сначала задается общий вопрос, а потом он конкретизируется?

Я, как разработчик, ратую за оптимизацию/рефакторинг, не зависимо от того где приложение запускается и вот почему: докупать железо можно, но это не решает проблемы неоптимальности кода, что в свою очередь рано или поздно приводит к замедлению разработки функционала и усложнению фикса багов.
Да, приложение работает. Да, оно решает бизнес-задачи. Да, обрастает новым функционалом.
Но почему-то оно всё странее и чаще падает, жрет всё больше, новый функционал добавляется все тяжелее, а разработчики начинают подыскивать себе другую работу…
А еще есть неочевидные преимущества: быстрый и стабильный софт может, например, требовать меньше времени для работы с ним и операторы смогут обслуживать больше клиентов (-> экономия -> преимущество) или более качественно (-> большая удовлетворенность -> преимущество).
Именно поэтому в процесс разработки необходимо закладывать рефакторинг и не гнаться слепо за функционалом.
Видите ли, в условиях задачи на самом деле уже заложена некоторая подсказка, какой ответ немного правильнее.

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

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

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

Посмотрите сколько в мире людей пишет на Яве (включая меня). Почему? Потому что железо (а Ява требует уйму железа) дешевле времени программиста
Вообще-то это не совсем так… Точнее, совсем не так.

Советский мопед на четыре буквы (Ц) мы используем не потому что там что-то дешевле — дороже. А потому что без всех тех ништяков, которые дает нам Java, можно решить намного меньшей сложности задачу в те же сроки и в тот же бюджет.

Фактически, это означает вот что — или мы делаем блоатварь, которая хоть как-то решает задачу, или не решаем никак. Ибо 10х времени и 20х бюджета на ту же задачу — это ненаучная фантастика.

Вот пользователь и выбирает — шикарно детализированную графику Doom 3, или pixelation древнего wolfenstein: spear of destiny, которпый когда-то был на острие прогресса, а теперь напоминает потерю контактных линз на -8 диоптрий.
Тоже самое, что пишут на Яве можно и на С++ сделать и бегать будет на совсем другом железе. Но займет намного больше времени разработки
НЛО прилетело и опубликовало эту надпись здесь
Я считаю, что многое зависит от масштабов и пропорций сервиса. Если это относительно небольшой сервис, кормящийся за счет платных пользователей, то оптимизация кода не так важна.

А в случае если сервис бесплатный с много многомиллионной или миллиардной аудиторией (Google например), то намного выгоднее оптимизировать код, чем докупать железо.
Вот еще такой вброс в пользу покупки железа.
Программисты могут так наоптимизировать, что код станет трудно понимаемым. И новые разработчики просто будут тратить кучу времени, чтобы вникнуть в тонкости оптимизации для того, чтобы вносить минимальные изменения в существующий код.
И, по-хорошему, после такой оптимизации надо тестами покрыть, и не простыми PASS/FAIL (на логику), а с хорошей нагрузкой.
Эта задача сама по себе съест больше времени, чем оптимизация.
Я разработчик, но откровенно не понимаю смысла этого опроса.

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

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

Иногда расширяем горизонт планирования и видем долгосрочные последствия того или иного решения и делаем как в прошлом пунтке.

Как можно дать однозначный ответ в этом вопросе? Делать нужно то что возможно а не то что хочется.
Тоже не понимаю смысла опроса.
Если свободная память потихонку сокращается без очевидной «бизнес причины», то скорее всего это memory leak и надо искать причину — и тут без вариантов.
А если это нормальный рабочий процесс, к примеру количество пользователей растет, а база данных полностью «in-memory» — то гораздо дешевле переконфигурировать сервер в облаке / докупить памяти и тут тоже особо без вариантов.
Согласен, вопрос в текущей постановке не очень хорош.

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

При этом, действительно, не оговорено как растёт клиентская база. Приходится предполагать, что задача, типа SaaS или on-site инсталляции, легко разбивается на независимые профили, а железо беспрекословно (в случае SaaS) докупается пропорционально клиентуре

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

Таким образом, вопрос получается в выборе генерального курса на время жизни продукта (примерно 5-10 лет, ±ситуации):

а) оставить ли уровень программистов средним и неуклонно жрущим память, реинвестируя прибыль в расширение серверной ёмкости на один клиентский профиль.

б) оставить ли ограничение «один клиент = один сервер», и заставить программистов уговорами, штрафами, обучением и поощрением уместиться в такое ограничение в течение жизни продукта.

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

Вот в такой ситуации лично мне становится чуток понятнее, что кое-кто не мониторил некоторые показатели проекта, и задумался, когда петух уже клюнул.

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

Разумеется, «быстровики» в этот момент проигрывают.

Однако, выигрывают продажники, которые могут отработать бо́льший портфель клиентов через меньшие system requirements, и даже выигрывают «быстровики», так как могут обещать более сложные и дорогие задачи. Поэтому выигрывают директор и учредители. А «быстровики», в свою очередь, начинают трезвее оценивать сроки.

Хотя, я могу и ошибаться, а автор статьи имеет в виду совсем другую формулировку вопроса.
В такой постановке холиварный вопрос.
Обычно идёт трейдофф на скорость разработки.
Если архитектурой и рефакторингом не заниматься, то разработка новых фич становится очень дорогой.
Если заниматься слишком много — разработка становится слишком дорогой.

Была хорошая статья про отношение % времени на дизайн и объёмом приложения, найду — добавлю.
Какое-то поверхностное описание.
В компании должно быть достаточно программистов, чтобы в случае подобной ситуации можно было бы выделить хотя бы одного человека разобраться в причине.
Далее в компании должен быть кто-то (тех-лид, архитектор, хз кто, может быть несколько человек) кто бы мог оценить что в данном конкретном случае выгоднее — купить память или заоптимизировать. Оптимизация — это не обязательно рефакторинг, это может быть маленький, хорошо задокументированный костыль :)
Универсального ответа нет — иногда нужно рефакторить/оптимизировать, иногда нужно покупать железо. Бесконечно железо покупать не сможешь, рано или поздно упрёшься в какие-то лимиты
как участник движения devops, могу сказать, что не было, нет и не будет никакой «серебряной пули» в этом вопросе.
у всех задач по разработке есть свой приоритет, и его нельзя нарушать без серьезных на то причин.

разумеется, со стороны operations вопросы по оптимизации должны регулярно подниматься на основе данных мониторинга и анализа.
есть поинты, которые можно относительно просто оптимизировать, не тратя не это много человекочасов, т.е. безболезненно для velocity.
попадаются задачи, которые тяжело и/или долго оптимизировать, проще «добавить железа», если это решит проблему.
хуже, когда и проблема перфоманса серьезная, и девелоперы решить ее не могут физически — с этим часто сталкиваются в big data, например — когда нельзя просто так взять и положить сотню терабайт в одну табличку.

для большинства разрабатываемых ныне софтовых продуктов первые два типа проблем встречаются наиболее часто.
учитывая последние тенденции, когда ПО работает в облаке, имеет грамотную инфраструктуру и умеет работать в кластере, гораздо проще и дешевле, что немаловажно, просто добавлять ноды в кластер, менять типы инстансов, варьируя тем самым перфоманс.
почему? а выше уже написали — hardware is cheap, programmers are expensive. это факт.

могу только дать пару советов обоим сторонам.
админам — внедрять виртуализацию и удобные инструменты для управления, если у вас этого еще нет, и не задумываться над ответом на вопрос «добавлять памяти или нет?».
программерам — всегда держать в голове вопрос «а умеет ли мое приложение работать в кластере и скейлиться горизонтально?», и если нет — вы готовите его неправильно.

работайте в команде — ищите компромисс вместе, не перекладывайте на других ответственность, делите ее со всеми.
Согласен с вами в той части, что ответ на вопрос лежит в продукте, я бы еще добавил многое зависит от фазы его ЖЦ.
Если важно опередить конкурентов, то это действительно важно. Кого будет волновать чистый код в случае если будет три пользователя, а не сто тысяч? Оптимизацией следует заниматься при избытке ресурсов (временных), а не заранее, или даже тогда когда есть проблема (которую можно решить иначе).

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

Если новая фича критична для успеха, то тут ответ должен быть очевиден, и задача менеджера будет всем это объяснить, почему так, а не иначе. И разработчик согласится, потому что сам проект и конечный продукт важнее кода. А неоптимальности случаются, что поделать. Если проект вырастет в фэйсбук какой, то его можно и переписать хоть на своем изобретенном языке :)
Мне кажется, что разработчики, которые готовы задавать себе вопрос «а умеет ли мое приложение работать в кластере и скейлиться горизонтально?» уже давно переросли средний уровень и тупо не по карману бизнесу, описываемому в статье.
отнюдь. да, джуниорам надо об этом напоминать, интермидам тоже иногда приходится, но в целом — все готовы поддерживать этот функционал сразу.
и они его сделают (или хотя бы попытаются), если их вовремя направить в правильное русло.
зачастую, проблемы в том, что напоминать некому, а в планы по разработке и CI это вообще изначально не входило, потому что менеджер не в курсе про CI, да и в стоимость продукта это не включено :)
Без знания причины, почему кончилась память нельзя принять «правильное решение».

Ситуация 1. Программисты забыли освободить неиспользование ресурсы — это бага!!! Проблема не может быть решена покупкой памяти. Ну сегодня, мы купим еще 100500 гб памяти, а через неделю опять не хватит. Дальше может быть еще хуже.

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

Ситауция 3. Раньше обрабатывали 100500 записей в единицу времени, теперь в 2 раза больше, поэтому памяти и не хватило. Это очень странно, поэтому нужна дополнительная диагностика. Нужно проанализировать и понять на сколько сложно заиспользовать другие структуры данных и алгоритмы, позволяющие сделать все тоже самое, только использую в N раз меньше памяти. Если цена вопроса 1-2 дня, то пусть программисты поработают, а заодно и отрефакторят. Если необходимо неделя или более, то скорее всего это архитектурная бага, поэтому нужно побыстренькому купить памяти и запланировать крупный рефакторинт. Иначе все может накрытся медным тазом.

Только не забывайте, что на то, чтобы выяснить причину, порой тоже нужно бывает значительное время.
НЛО прилетело и опубликовало эту надпись здесь
Ситауция 2. Раньше обрабатывали 100500 записей в единицу времени, теперь в 1000 раз больше, поэтому памяти и не хватило. Очевидно, что нужно сходить и купить больше памяти.


Не бывает так, что ВНЕЗАПНО стало обрабатываться в 1000 раз больше — добавились клиенты, события и или что-то ещё, о чём было бы неплохо подумать заранее.
>>>Ситуация 1. Программисты забыли освободить неиспользование ресурсы — это бага!!! Проблема не может быть решена покупкой памяти. Ну сегодня, мы купим еще 100500 гб памяти, а через неделю опять не хватит. Дальше может быть еще хуже

этом случае можно периодически перезапускать процесс, чтобы нейтрализовать результат лика
> Затраты на оборудование, например, в 2 раза больше, чем затраты на зарплату (или, например, премию за внеурочную работу) разработчику, который решит проблему с текущим высоким потреблением серверных ресурсов.

За какой период? Разработчику платят постоянно, а за железо 1 раз, и списывают его за год-три.
За период, потраченный на оптимизацию. В остальное время разработчику платят за другие задачи.
Я разработчик

Считаю, что истина как всегда где то посередине.

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

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

Но и оптимизация дело важное. Есть много факторов, одни из которых:

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

Нужно уметь соблюдать баланс между фичами и оптимизацией. Подходы могут быть разные. Иногда я например просто чувствую, что нужно заняться именно этим. А случаи могут быть разными. Например у меня была ситуация, когда был известен не оптимальный участок, написанный до меня, но задач и других было предостаточно, а последствия не оптимальности были некритичными… До поры до времени. Пока из-за этой не оптимальности операция не стала выполнятся более получаса, что уже очень критично, т.к. сотрудники одного отдела для работы были вынужденны ждать это время. Пришлось срочно заняться вопросом и сократить время операции до 1-3 секунд
НЛО прилетело и опубликовало эту надпись здесь
Спасибо за ссылку!
Не такая уж простая эта операция — разворачивание битов. До первых трёх преобразований (AND, табличка, цикл) додуматься несложно, но дальше (с умножениями и остатками) надо ещё пофантазировать…
Без конкретных цифр решение принимать бессмысленно — это задача на оптимизацию ресурсов, и её решение зависит от конкретных данных. Если компания столкнулась с проблемами высоких нагрузок, нужно особенно внимательно относиться к алгоритмам, которые стоят за вычислениями.

Если баг добавляет какие-то фиксированные затраты (ну, например, из-за неудачной архитектуры пришлось сделать отдельный сервер очереди, который так бы не понадобился. То это мелочи. Чем больше клиентов, тем быстрее стоимость этого сервера растворится в общем объёме. Можно не перепиливать всю архитектуру, чтобы сэкономить на этом.

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

Куда хуже, если система тормозит из-за неэффективного алгоритма (неэффективной структуры базы данных, неэффективных запросов к ней, неудачного проектирования масштабирования, неудачного хранения данных и т.д.), сложность которых сильно выше линейной. Тогда, чем быстрее компания растёт, тем дороже ей будет стоить инфраструктура в пересчёте на каждый заработанный рубль. И такие косяки важно и нужно уметь идентифицировать на ранних сроках. Как только такая ошибка начинает сколь-либо заметно влиять на потребление ресурсов, её надо исправлять. Они не проявляются мгновенно — типа на 100% подскочило потребление. Это всё постепенный процесс — просто постоянно растёт доля выручки, которую сжирает инфраструктура.

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

Неэффективные алгоритмы — это не обязательно зона ответственности архитектора. Потребление любого, даже самого маленького компонента системы может быстро разжираться. Любой отчёт, любой запрос к базе данным, неудачный формат файла обмена, чтение/запись в файл, ведение логов, неудачное разделение ответственности между модулями, неудачный API — всё это может быть бомбами замедленного действия с неэффективными алгоритмами внутри. Такие баги нужно исправлять сразу, как только они стали оказывать заметное влияние на затраты, ибо дальше будет только хуже.
Ответ в стиле КО: Деньги надо тратить туда, где они принесут большую пользу.

Ответ в стиле «копаем глубже»: В чем вообще проблема?

1) Разработчики написали код, который требует на X МБ больше для всей системы. Это вообще не проблема, пидарасить байты выйдет дороже, чем докупить память.

2) Разработчики написали код, который требует на X МБ больше для каждого запроса\пользователя. Это проблема, если предполагается значительный (в разы) рост числа пользователей, если не предполагается то можно докупить оперативки и отложить решение вопроса об оптимизации.

3) Разработчики, написали код, который требует больше памяти на каждом экземпляре приложения, а экземпляров дофига (серверов или клиентских приложений). Тут два варианта:
    а) если потребление ресурсов не превысило возможности сервера\устройства, то можно отложить вопрос об оптимизации 
        (в будущем с высокой долей вероятности надо будет вернуться к этому вопросу)
    б) если потребление ресурсов превысило возможности сервера\устройства, то нужно оптимизировать

4) Разработчики написали код, который требует больше ресурсов от некоторого не масштабируемого компонента, например СУБД, сеть, объем хранимых данных на устройстве. Однозначно надо оптимизировать.
Что касается конкретного вопроса — не надо оптимизировать. Реальной проблемы нет, если бы была, то вопрос даже не возник бы.

При этом не надо пессимизировать код, то есть создавать код, который заведомо значительно хуже оптимального. При работе с СУБД пессимизация случается очень часто, а СУБД, к сожалению, довольно плохо масштабируется.
cgroups на сервер, программа начинает падать от нехватки оперативки (oom, local reclaim и всё такое). А админ как бы и не при делах — сервер-то работает.
Насколько я понял из условия:
Просадка производительности равномерная (т.е. не какой-то один конкретный ботлнек). Так что несмотря на то что я разработчик — считаю что нужно докупить железо, ибо это серверный код, и сделать это возможно (в отличие от клиентского кода, который таки надо оптимзировать), и сделать это проще.
Железо стоит меньше, чем время девелоперов. Вывод очевиден. Особенно в условиях конкурентной борьбы.
Поддержка этого железа, если приложение кривое и не умеет масштабироваться тоже требует времени, и не факт, что это дешевле времени девелоперов. Плюс накопление технического долга может привести к очень неприятным последствиям. Так ли этот вывод очевиден?
Покупка железа быстрее и проще. Никто не говорит, что вечно так надо делать, но в условиях бега/марафона/спринта проще взять бутылку, попить её и бросить, а не вставать и аккуратно пить из стакана.

Здесь у нас два варианта в текущий момент. На будущее конечно всё отрефакторится, но это уже будет подарок девелоперам, если продукт успеет нишу завоевать, бабло вернёт и всё такое.
Это (рефакторинг) мало кому надо. Если продукт свою нишу занял, то нужно постоянно его допиливать, чтобы эту нишу не отобрали конкуренты -> постоянное внедрение нового функционала и, как следствие, новых багов, просто не даёт времени остановиться и отрефакторить старый код. В результате имеем Эйфелеву башню, построенную из костылей. Согласитесь, поддерживать такое немасштабируемое приложение на костылях — трудозатратно. Хотя это, по-моему, проблемы в управлении данного проекта.
Угу. Особенно в компаниях с зоопарком серверов — скажем, от 1000 машин.

Посчитайте стоимость 16ГБ оперативки, умноженной на 1000 машин, умноженной на стоимость человеко-часов, необходимых для апгрейда 1 (если применимо), добавьте сюда амортизацию с моральным старением, и еще для полной картины вероятность бракованного железа (нужно будет как минимум тратить время на поездки в СЦ).

И сравните с 200-300 долларами, необходимыми для оплаты работы 1 программиста в течение пары рабочих дней.

Вывод? Все нужно просчитывать.
НЛО прилетело и опубликовало эту надпись здесь
Всё упирается в количество серверов. Ускорение программы на 10% позволит сэкономить совсем разные суммы при 10 машинах и при 100.
Зависит от ситуации. Иногда «умельцы» напишут что-нибудь эдакое (образно) O[N^4], там хоть 100 серверов добавь, много не будет…
На этапе развития продукта, когда важно набрать массу лояльных пользователей, ясно что нужно бороться за работающие фичи.

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

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

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

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

А еще забыл про один множитель — темпы роста нагрузки. Может, маркетинг так хорошо работал, что вчера все было нормально, а сегодня нагрузка стала такой, что существующее решение тупо не справляется. А перспективы и совсем неутешительны. Тогда потребуется применять оба решения сразу — а это уже вопрос архитектуры.
В любом случае такие вопросы без подробного анализа не решаются.
Я являюсь и разработчиком и менеджером проектов (вырос из разработчика, но из-за постоянной нехватки ресурсов, приходится самому кодить).
Такая проблема есть всегда.
Бизнес\заказчик всегда будет преследовать только свои цели, всякие оптимизации и рефакторинги его не интересуют, ему нужно здесь и сейчас.
Я поступаю следующим образом, когда понимаю, что проблема уже на пике:
Сообщаю заказчикам\бизнесу, что сейчас мы доделываем проект, потом мы 1 месяц решаем все ваши новые\измененные пожелания\хотелки\бантики, после чего 2 месяца сидим и рефакторим и оптимизируем, если этого не сделать, то через полгода всё это рухнет. (конечно же на меня выльют пару вёдер «субстанции детской неожиданности»).
На все их «надо», «клиенты уходят», «бизнес развалится» сообщаю, что я всё понимаю и именно по этому у вас есть время очень взвешенно подумать над тем какие задачи нам дать, чтобы этот месяц использовать с максимальной эффективностью, а не прикручивать бантики (некое подобие «уступки», на что человек как правило «ведётся»), параллельно обозначивая особую обеспокоенность за бизнес в целом.

Несколько таких итераций и бизнес\заказчик приучается к таким вот периодам технических задач по рефакторингу и оптимизации.

PS: не претендую на решение, но описал свой опыт решения таких проблем. Не факт, что он будет работать где-то еще :)
Еще можно встраивать рефакторинг и оптимизацию в каждую фичу (требования по скорости работы + регрессионные тесты для измерения скорости)
В каждом конкретном случае нужно опираться на здравый смысл, имхо. Пример из жизни: на сайте каждые 20 минут запускается обновление остатков товаров из базы данных склада. Скрипт отрабатывает за 3 минуты, попутно прилично загружая сервер. Задним умом понимаю, что что-то не так, но разработчики лениво отписываются, что с самим скриптом все ОК. Немного надавил, в результате за час работы в скрипте нашли «пожиратель времени». Теперь скрипт отрабатывает за 30 секунд, нагрузка на сервер практически не ощущается.
В опросе много сторон. :) Их можно свести в две категории — те, кто отвечает за стабильность решения и его архитектуру, и те, кто отвечает за продукт на рынке. Первые скажут про оптимизацию кода, и приведение его в модульное, расшияремое и поддерживаемое состояние. Вторые — скажут, фигня вопрос, все закрывайте заплатками, наращиванием железа. Главное — быстрее выпустить пресс-релиз о новой версии. Я это часто слышу в формулировке: «Ты же понимаешь, без нового функционала мы не можем проводить продвижение. А твой рефакторинг — он же ничего не меняет для клиента. Зачем ты это делаешь»
Проблема, описанная в статье указывает на недостатки не в разработке или материальном обеспечении, а в управлении.
Экстенсивный путь — изначально порочный принцип. Изначально должно предусматриваться тестирование и оптимизация как элемент процесса разработки.
90% ситуаций, похожих на вышеописанную, происходит из-за того, что в веб-разработке пока еще не выделилась профессия DBA.

Среднестатистический веб-разработчик обязан знать свой основной язык (допустим это PHP), пару фреймворков на основном языке, желательно — какой-то дополнительный язык, уметь установить и настроить все необходимые ему сервисы (httpd, nginx, mysql, memcached, sphinx etc), обязан хоть что-то понимать в JS или хотя бы каком-то общеупотребительном JS фреймворке и так далее, разбираться в верстке, и тому подобное, чему нет числа.

У него не остается ни времени, ни физической возможности быть хорошим разработчиком баз данных. И это не его вина, это беда тех, кто руководит им. Отсюда бездумное использование ORM там, где оно не нужно, выбор модных noSQL решений там, где они не нужны, неоптимальная структура базы, проблемы с индексами в базе, паника при виде более-менее сложных запросов, неумение перенести бизнес-логику на уровень БД, незнание современных возможностей БД, которые здорово бы облегчили и процесс разработки и потребление ресурсов.

Имхо, потребность в выделенном DBA наступает в любом проекте, чуть сложнее блога на Wordpress. И, тоже имхо, снимает большую часть «проблем», которые бы не возникли при его наличии.
Пример на моей текущей работе.
Нашли «ОЧЕНЬ ЖИРНОГО» клиента, но надо выиграть тендер у конкурентов.
Вот тут вся команда на месяц засела оптимизировать код. :)
Иначе тендер не выиграть.

А конкретно в вашем случае — докупить железо + минимальный прогон через профайлер, что бы уж совсем тупые ошибки отловить.
Увольть админа за троллинг всей команды и хабра! Ну а потом купить железа. :)
Я разработчик.
Часто бывает так: с менеджером договориваемся, что сейчас мы делаем это, это и это методом хуяк-хуяк, а потом получаем время на причесывание всего вместе.
Как только я понял, что комманду на это «время на причесывание» так скажем заведомо обманывали, я тут же проголосовал ногами (уволился).

К сожалению, фичи можно напрямую продать (и не важно на самом деле насколько хорошо или плохо они работют).
Стабильность, отсутствие багов, адекватную архитектуру и maintainability продать напрямую невозможно… к сожалению…
НЛО прилетело и опубликовало эту надпись здесь
Если отталкиваться от постановки вопроса, то моя роль скорее Boss. И с этой позиции в большинстве случаев я выберу оптимизацию кода. Но в реальной ситуации есть ещё куча факторов, которые повлияют на мой выбор.

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

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

Например, если при оптимизации проект сможет принять больше пользователей с теми же ресурсами, и эти пользователи действительно появятся в срок, соответствующий сроку выполнения оптимизации, стоимость оптимизации для отношения «дешевле» падает.
я разработчик.
и согласен с тем, что железо дешевеет, а время разработчиков — нет.
когда идет работа в стиле: поехали, шашечки потом нарисуем — проще докупать железо, пользуясь паузами в запросах клиентов для оптимизации кода и как верно писали выше: сначала задав себе же вопрос — стоит ли оптимизация потраченного на нее времени?
В статье упущена очень-очень важная деталь. А именно реальные трудозотраты на оптимизацию. По равилу парето, что бы избавиться от бОльших проблем с памятью, нужно оптимизировать меньшую часть приложения. Можно дать на оптимизацию пару дней, ну или сколько не жалко, а не +50% времени (вообще откуда такую оценку врменени выдрали, не понятно). Вполне возможно, что проблему удастся решить малой кровь. Ну а если нет, то да, вперед покупать железо.
решение пусть принимается исходя из обстановки… принимает пусть босс, или кто им уполномочен принимать решения. А в душе каждого разработчика должен быть вектор на написание оптимального кода… Ну включи в обед IDE — да поправь кусок кода, все равно в рабочее время habr читаешь!!! А памяти по-любому надо больше… за нее и проголосовал
Если при рассчетном росте нагрузки дешевая относительно зп команды докупка железок закрывает задачи по производительности на длительный период, то докупать и не париться.
Но иногда докупка железа — отсрачивание конца, и рано или поздно проект может упереться в архитектурные ограничения, например, в невозможность горизонтально масштабироваться, т.е. уже нет возможности взять и докупить железок. И если такое происходит, то без рефакторинга и смены архитектуры никуда.
Однозначно не скажешь.
Иногда лучше докупить железа особенно если софт работает только внутри фирмы. А вот если есть ещё клиенты которые после очередного релиза чудо программы должны будут обновить свой парк железа то лучше взяться за оптимизацию.
И по железу тоже затыки бывают разные, может банально оперативки не хватает, а может накодили так что уже база на SSD не справляется. К тому же если забить на оптимизацию то может наступить случай когда железо уже и не проапргрейдить так чтобы спасти ситуацию…
Админ. Проголосовал за железо (с указанными данными, подходит лучше всего).
В арсенале нужно иметь оба метода, просто не нужно слепо их применять.
Все забыли про третий метод — исследование проблемы.
Можно дать задание тимлиду/архитектору потратить день на исследование.
Почему увеличилось потребление ресурсов, насколько затратно его уменьшить.
Параллельно можно дать задание админу посчитать, сколько будет стоить новое железо.
На следующий день вы будете иметь на руках данные, которые помогут сделать выбор.
Ну и да, вы потратите какое-то количество времени/денег на оценку, про это тоже нужно помнить.
В голосовании не хватает варианта «Я девочка, я не хочу ничего решать, я хочу платье!»
Я пользователь, и хочу одновременно и быстро, и красиво, и недорого)
Я разработчик, считаю, что докупить железо не должно быть проблемой. Оптимизации хорошо, писать красивый и простой код — тоже. Но рынок не стоит на месте, конкуренты не дремлют.
Boss.
Слишком мало информации для принятия решения. Зависит от того, какой бизнес, что в нем критично, и чего нужно от системы в будущем.
Мониторьте комменты и всех, кто ответил иначе — на должность PM'а или тем более CTO не берите.
Вопрос, который Вы задали — про бабло.
Я бы просто сравнил, сколько стоит по оценке пиэма время на оптимизацию кода и сколько — добивка памяти в сервер, если и то и другое одинаково хорошо решит проблему.
Потом выбрал бы, что дешевле по времени и срокам.
Вот именно. Формула расчета конечно может быть сложнее — надо учитывать амортизацию, возможные риски по срывам сроков оптимизации или недостижению таковой вообще (в реальных условиях не всегда можно ускорить код за разумное время), возможные расходы ресурсов на простой при поломке винчестера и прочее.

Все надо просчитать, а не пороть отсебятину «нуууу наверное лучше то» или «нееее лучше это». Все-таки, как мне кажется, тут люди должны с математикой дружить — ан нет, иррациональных субъективных комментариев over 9000.
Вы со своим «всё надо просчитать» уже проскочили одну ступень: а стоит ли вообще что-либо считать? Если мы говорим об одном разнесчастном VPSе, который вы где-то арендуете, вам нужно пойти и нажать пару кнопок и приготовиться потратить ажно лишние $100 в год, то можно так и сделать и «закрыть проблему». Даже если программист мог бы это сделать не за $100, а за $50 — ну и фиг с ним, не стоит эта экономия возни. Время работы PM'а, руководителя и т.п. тоже чего-то стоит (и речь идёт не о зарплате: если руководитель решает — нужно ли upgrade'ить VPS, то он уже не может в это время делать других, более важных дел), $50 «псевдоэкономии» улетят очень быстро, не стоит.

А вот если вам нужно вложиться в переоборудование датацентра и/или вложиться в рефакторинг на пару кварталов — тут уже нужно считать и считать сурьёзно.

Потому алгоритм таков: смотрите на ценник «решения через железо», если он слишком мал, чтобы о чём-то говорить — платите и «закрываете проблему», если нужный выигрыш от «правильного» решения вообще может хотя бы теоретически оправдать потери времени и сил на точные подсчёты — вот тогда можно (и нужно) считать. И там — опять-таки не забывать про то, что «счётчик-то тикает»: если вы никак не можете решить, что лучше сделать — ну монетку киньте, что ли. Лучше всё-таки что-то выбрать и пусть даже проиграть $1000, чем потратить $10'000, чтобы выбрать на $100 более оптимальное решение.
Да, отчасти согласен. С другой стороны, подобные формулы должны быть уже готовы у каждой компании, и просчитать расходы — дело 15 минут и 200 рублей. Если этих формул нет — их все-равно нужно вводить, т.к. компания наверняка столкнется в будущем с похожей ситуацией.
Почему не рассматривается вариант, когда железо в аренде, что бывает часто.
Тогда:
* оптимизируем код (все-равно программистам уже платим зарплату) — нет дополнительных затрат денег
* арендуем более мощные сервера — ежемесячные затраты на содержание растут, и будут расти.

В первом варианте можно нанять еще 2 программиста за 2000 и наоптимизировать и написать больше кода
Во втором можно взять железо, на 2000 баксов дороже и отдавать эти деньги за аренду кому-то, не получая ничего в замен

Почему задача поставлена в лоб? Сейчас же все в облаках и в основном все платят за ресурсы ежемесячно а не разово за колокейшн.
ну и еще про админов — больше зелеза — больше админов его обслуживать, опять же без какой-то пользы (пустая трата ресурсов)
Я вообще не понимаю, как можно писать код, который ты же потом способен ускорить прямо в разы. Если знаешь, как сделать оптимально, то сразу так и сделаешь, причем без дополнительных затрат времени. Потом только мелочевку можно подчищать, но это максимум 10-20-30%.

Поэтому, если тормозит — то либо докупать железо, либо менять технологию.
Иногда нецелесообразно писать сразу по оптимальной архитектуре.
На прототипе набиваются шишки, создаются и отрабатываются алгоритмы.
Затем — третья-пятая инкарнация алгоритмов переносится в новую архитектуру.

Обе архитектуры, которые я проектировал, работали.
Линейная — была сделана и отлажена за две недели и дорабатывалась еще полтора года.
Дискретная — писалась два месяца по уже известным алгоритмам. И еще месяц была в доводке.
Чувствуете разницу?
Из за простоты реализации получить нечто работающее и быстро, либо потратить ресурсы (и не получить прибыли, поскольку ничего не продали) за нечто абстрактное, что еще не обязательно будет работать…
Это если у вас околоматематическая задача, где вообще можно говорить о каких-то «алгоритмах» и их влиянии на производительность всей системы. В 95% задач в программировании этого нет.
«Банальная» задача оптимизации таблицы BGP с целью нахождения оптимальной альтернативы, которая не совпадает с текущим маршрутом выбранным маршрутизатором согласно алгоритмов работы RFC по BGP.

Собираем метрики через альтернативные направления.
Меняем таблицу маршрутизации если текущий маршрут не оптимален.

Задача сугубо логическая.

Математики там — посчитать количество и среднее арифметическое времени задержки переноса пакетов. :-)
Ну и посчитать количественно мегабиты в секунду при рассчете перегрузки канала.
Ну и несколько патентов на это дело… ;-)
Задача оптимизации (всмысле не кода, а какого-то предметного процесса) — околоматематическая по определению. Математика это не только циферки. Вы сами прекрасно понимаете, что в задачах сделать:
— сайт
— приложение для мобилки
— игру
— интерпрайз-систему
— драйвер
Математика встречается только если в предметной области (приложение для мобилки по расчету интегралов), либо скрыта в технологии. Либо есть где-то на периферии, но несущественна для общей эффективности системы. В эти категории попадает подавляющее большинство современных задач программирования.
И пока вы пилите идеальный продукт, конкуренты выпустят просто хороший и получат рынок.
Я же пишу, по времени разницы нет. Дольше — это если собирать те самые 10-20-30%, но я это не предлагал делать ни сразу, ни потом (т. к. все равно надолго не поможет)
Вы очень ошибаетесь, разница может быть даже в разы. Проекты иногда чуть ли не с нуля переписываются, в том числе с использованием других технологий, после успешного старта первой версии, пусть и кривой, но быстро запущенной и уже приносящей деньги.
Что-то не хватает одной еще варианта голосования:
Я архитектор. Считаю, что нужно оптимизировать код. Но вижу что это не является препятствием для новых фич.

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

А критические проблемы были взяты в разработку.

Вот пара проблем:

первый вариант приложения (С++) с линейной логикой и обработкой одиночного задания в собственной нитке приводил к его зависанию из за взаимных блокировок и т.п. Нагрузка на процессор — 200-300% (относительно одного ядра) при исполнении 70-100 ниток (одновременных заданий).
Решение: приложение переписано по другой архитектуре с дискретным исполнением заданий.
три нитки для исполнения 200-500 заданий.
нагрузка на процессор — 70% в нитке обеспечивающий уровень обслуживания сети (будущая оптимизация — переписать на очереди и таймера; ожидается 4% нагрузки).

Второй вариант:
Прототип приложения написан на Perl. Ресурсов С++ не хватало для переписывания. Прототип обеспечивал функционирование production в течении полутора лет у ВСЕХ покупателей П/О.
Затем был переписан на С++. Нагрузка на процессор снизилась в 1000 раз (в частности процесс пересчета маршрутов снизил нагрузку с 40с на 10к маршрутов до менее 1с за 40к маршрутов).

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

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

С другой стороны возьмем систему, где на своих площадках уже стоит 1000 серверов и 10% мощности — это еще 100шт. Вполне очевидно, что покупка и эксплуатационные расходы сотни серверов будут в разы больше месячной зарплаты программиста. Тут уже скорее выгодно оптимизировать, чем покупать железо.
Системный архитектор.

Я бы озвучил дополнительные проблемы:
1. Не всегда «средние разработчики» могут написать хорошо масштабируемое решение. т.е. докупить серверов — может сделать хуже.
2. Не всегда «средние разработчики» могут хорошо оптимизировать код. обычно узкое место просто «переносится», например вместо RAM начинаю жрать CPU и Storage IO
3. Не все железо можно «проапгрейдить». Если в Вашей машине 96 GB RAM и больше не воткнуть — её не воткнуть. Ну а потом к пункту 1.

Я бы решал проблему с разных сторон:
1. Разделять систему на сервисы, чтобы конкретный «узкий» сервис масштабировать.
2. Конечно докупать железо — если у нас 100% ресурса испльзовано, завтра все равно потребуется 110% от текущего. Бизнес растет. Оптимизировать быстрее, чем масштабировать всеравно не возможно.
3. «Средних разработчиков» учить. Учить писать быстрый код, учить писать масштабируемый код.

P.S. Монитроить систему, и задаватся этим вопросом не на 100% RAM использовано — «решайте срочно и сейчас», а на 80% — «решите в течение недели».
Дополню: обычно «средние разработчики» пишут структурированный и слабо связанный код. Иногда модульный. А его можно разнести на сервисы. Ситуацию когда «плохие разработчики» называются средними тут рассматривать нет смысла, ибо там всегда будут пробемы с ресурсами (4 LEFT JOIN например, или MAP с foreach вместо BTREE и b-поиска и т.д.)
Я разработчик.

Продает не код и не оптимизация. Продает маркетинг и если в текущей конкурентной среде нет гонки производительности, то можно наращивать железо.
А где можно поставить "-100" к такому бестолковому опросу? Это всё равно, что опросить «1) Надевать варежки 2) Не надевать» — всё зависит от такой громады факторов, что нет смысла давать «абстрактный ответ». Но я его всё же дал, в предположении, что прогеры — квалифицированные и не говнокодят в условиях нехватки времени — ДОКУПАТЬ ЖЕЛЕЗО.
Программа — её никто не делает «специально плохой», обычно первое решение — самое простое и очевидное. Поэтому если что-то тормозит (а прогер прекрасно знает, с чем он работает), то СКОРЕЕ ВСЕГО нужно ускорять железки.
И не говорите. Судя по однобоким комментам, хабр уже действительно не торт.
Я видимо один прочитал заголовок как: Что дешевле: новое железо или труП разработчика?
А у меня только недавно стало минимум 4 гигабайта оперативки в терминальных серверах, на которых работают до 7 пользователей в файловых базах 1с (розничная сеть по всей стране). Некоторые сервера уровня пентиум-Д и коре-дуо первого поколения. И никто, пока не сломается, оборудование докупать не будет, ведь «сейчас работает», и никого не парит то, что функционал и объем данных растет.
Железо можно не докупать, а арендовать или вообще часть не особо важных данных перенести в облако, за счет чего освободится место на своих серваках.
А то такими темпами можно новые серваки покупать бесконечно.
Надо смотреть в разрезе, одно дело у тебя сто серверов и три разработчика и тебе надо удвоить сервера, понятно что тут проще нанять ещё одного разработчика на оптимизацию.
Другое дело что есть у меня один проект где разработчиков на руби штук 6 и все крутилось на одном сервере, сейчас крутится на трех, и цена аренды трех серверов за год сопоставима с зарплатой разработчика в месяц. Ну конечно было проще прикупить серверов.
Ээээ… смотря сколько серверов, и смотря сколько времени разработчиков =)
Если обычный веб-проект с 10к пользователей хочет 10-20-30 серверов — разработчики пару лет назад свернули не туда.
Я разработчик. Считаю что «все сложно».

На подобный вопрос нельзя однозначно ответить без детального анализа по всем procs/cons, всем рискам, итп, конкретного проекта.
Системный администратор.

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

А за это время я подкручу статистику чтобы узнать где узкое место и выдам разработчикам узкое место.

Я разработчик.

Код нужно оптимизировать всегда, это одна из стадий алгоритмизации. Но в описанной ситуации нужно докупить оборудование.

А вообще пост — клоака для холивара. Давно хабр превратился в форум?
Администратор. Я бы предложил прямо сейчас докупить железа, но задачку по оптимизации все же завести, не в самом высоком приоритете, возможно у команды будет период затишья, когда можно будет ею заняться. Плюс обязательно постарался бы протолкнуть задачу по повышению квалификации разработчиков.
  1. Код нужно писать сразу оптимальный (наилучшего качества), потому что…
  2. Время на «рефакторинг» ни менеджер, ни босс не выделит. Для них «нужно сделать рефакторинг» значит «нужно потратить Х часов на то, что не является новой фичей и денег не приносит».
  3. Задача админов не только купить и установить новую память, но и оптимизировать настройки серверов. Они тоже могут поучаствовать в оптимизации.
  4. Новое железо как правило обходится дешевле, чем рефакторинг и оптимизация. Не знаю почему у вас наоборот да ещё и в 2 раза.
  5. Рефакторинг действительно может не дать результата.


Предлагаю:
  1. Дать задачу самому опытному разработчику найти «бутылочные горлышки» и оценить время на их устранение и потенциальный эффект от устранения. Цель — найти крупные проблемы, которые можно легко исправить, но эффект от этого будет сразу заметен. Времени дать на эту задачу совсем немного — только оценка.
  2. Параллельно дать задачу админам — найти способы оптимизировать настройки существующих конфигураций.
  3. Если разработчик нашёл «бутылочное горлышко», которое можно исправить за 1 час, но это даст 20-30% прирост производительности, то это есть смысл сделать. Последующая оптимизация как правило не стоит того — слишком маленький эффект.
  4. Докупить новое железо, поставить и настроить.


PS. В дальнейшем, возможно, стоит проконсультироваться у специалиста по оптимизации производительности. Например, для меня было откровением, что увеличение количества памяти сервера не увеличивало количество конкурентных запросов, вот частота виртуальных ядер — да, влияла.
Действительно, в Software Development все так просто, что можно выдавать точные рекомендации по описанной в двух словах проблеме =) А код сразу нужно писать оптимальный, без багов и ровно то, что нужно клиенту.
А если без сарказма, то действительно есть две противоположных точки зрения:
1. Писать прототип тяп-ляп, всё равно требования пока не устаканились и 80% кода вылетит в помойку скоро. Через полгода переписать.
2. Писать сразу хорошо и оптимально, в ущерб времени разработки и простоте кода. Ведь, если фича приживётся, никто не даст таск её оптимизировать: сейчас работает хорошо, чего ещё желать.
Да, точно. Мы работали по второму варианту. Жесткие стандарты кодирования, обязательное ревью кода. Рефакторинг делали во время разработки новых фич — на этапе проставления эстимейтов мы смотрели код и, если нужно было рефакторить, то учитывали это в оценке времени. Всё это было согласовано с клиентом, но со временем клиент начал зажимать «большие» задачи, а брать в спринт только мелкие, таким образом опять же рефакторинг был задавлен. Вот поэтому я и писал, что вам не дадут времени на рефакторинг, потому что цель бизнеса — не красивый код (его не продашь), а новые фичи! С их точки зрения рефакторинг — бесполезная трата времени и вы вряд ли сможете их убедить в обратном. Поэтому вывод простой — сразу делать качественный код. Особенно, если вам придётся его поддерживать!

Первый вариант (быстрый прототип и затем переписать) подойдёт для случая, когда он полностью понятен клиенту/боссу и он понимает, что сейчас он тратит 20% бюджета и получает кривой-косой, но работающий прототип, а после нужно будет заплатить 80+% и всё переписать.
В моей практике был такой проект. Сделали быстро, затем раунд инвестирования с уже полностью рабочим прототипом, затем проект был отдан другой команде и она его переписывала.
Отличный показатель, как мне кажется, основной ошибки девелоперов. Мы ставим код на первое место и начинаем мыслить такими категориями, как технический долг, красота кода, рефакторинг, удобство изменения. Но это неверно, потому что единственное, что важно — это насколько проект полезен пользователям. Не надо мне говорить, что такой подход ведет к «тяп-ляп и в продакшен» (ваша точка зрения номер 1). Есть бизнесы, где быстрый фидбек очень важен для понимания нужд клиентов, и тут пригодится 100% покрытие кода тестами, чтобы деплоить 20 раз на продакшен в день. А есть где все понятно и надо сделать тулзу (пусть очень важную) за два месяца, два раза задеплоить ее, получить деньги и забыть. Я считаю, что все сложно и мыслить категориями «либо тяп-ляп, либо сразу хорошо» это неправильно.
Полностью согласен — все проекты разные и возможны разные комбинации. Если команда придётся поддерживать проект, то есть смысл об этом думать с самого начала. То же самое, если у вас продуктовая компания. Если же это разовый проект и скорость важнее, то можно и «тяп-ляп».
Всё, что я писал — моё личное субъективное и предвзятое мнение и его можно просто проигнорировать. Извините, что выражаюсь пунктами, но я так реально мыслю (known bug).

Не оптимальный код в проекте говорит о том, что вы создали «технический долг» (раз, два, три). Однажды придётся его заплатить, но вы хотите, чтобы исправление этого технического долга было оплачено (это ведь работа!), хотя раньше вы регулярно недодавали клиенту/боссу качество, хотя отчитывались о том, что работа сделана хорошо. Да, это очень неприятный момент. Написал всё, что знаю из своего опыта, чтобы помочь решить проблему.
А как точно и заранее определить, какой код оптимальный, а какой нет?
Вот есть у меня функция с O(n^5) — это плохо, а функция O(n log n) хорошо?
А если и ту и ту можно существенно оптимизировать (пусть первую до n^2, а вторую до n), подумав месяц?
А если первая выполняется 10мс один раз при старте системы, которая работает месяцами без перезапусков, а вторая выполняется при каждом обращении клиента и занимает половину времени обработки запроса?
Может быть, в таких условиях гораздо выгоднее будет контринтуитивное решение об оптимизации функции, которая и так имеет лучшую асимптотику?

Да, возможно, O(n^5) это технический долг, но придется ли его когда-нибудь отдавать? А эффективная на первый взгляд O(n log n) по факту отказывается долгом, хотя внешне не имеет к этому никаких предпосылок.

Из реальной практики, один раз при тестировании производительности некоторого приложения, я внезапно для себя протестировал производительность подсистемы записи логов этого приложения, при этом проблема оказалась даже не в скорости их записи на SSD, а в форматировании данных для записи. Без профайлера я бы не поверил, что такой простой на первый взгляд код может вызвать проблемы, но сработал эффект масштаба — функции записи в логи в максимальной детальности вызывались очень часто, таким образом совершенно неприметная на первый взгляд функция оказывалась в верхней строчке отчета профайлера.
Моё мнение — важно оценить сколько мы выиграем от любой оптимизации. При этом оптимизация одного участка кода даст большой выигрыш в производительности, а другой — совсем незначительный, но может занять существенно больше времени. Да, стоит профилировать код, стоит поискать медленные запросы к базе данных, медленные технологии. Но моё личное мнение, что раз уж код в силу разных причин не оптимальный, то дешевле будет купить дополнительное железо, а уж потом искать «бутылочные горлышки».
раз уж код в силу разных причин не оптимальный

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

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

Покупка нового сервера — это несколько месяцев работы одного программиста по затратам + сервер будет к Вам ехать до двух месяцев. Всегда ли дешевле?
Да, согласен, что изначально всё предусмотреть невозможно и код будет не оптимальным, но тут важнее выбрать правильную архитектуру и постараться предусмотреть возможные проблемы. Тут поможет плотное общение с клиентом, чтобы понять в какую сторону от заданного курса проект может отклониться.

По поводу нового сервера. Мы использовали Amazon AWS. Да, дорого, но новый instance добавить (сервер с любой на выбор OS) — пару минут работы. Убить сервер — пару кликов. Использовали spot'ы, так как они очень-очень дешевые. Включали и выключали instance когда это было нужно. Насколько я помню средний сервер обходился примерно в $150/месяц. В общем — cloud есть cloud.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории