Простое и сложное (но эффективное по производительности) решение - какое выбрать и когда?


28

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

Есть два решения -

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

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

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


10
см .: Как избежать «Плохой интуиции разработчика»? «К сожалению, разработчики обычно имеют ужасную интуицию о том, где на самом деле будут проблемы с производительностью в приложении…»
gnat

1
Будет ли «не самый оптимальный» еще «достаточно хорошим»? Тогда оставайся с этим.

8
Ага. " Le mieux est l'ennemi du bien. " Вольтер. («Идеально - враг хорошего».) Достаточно хорошего - достаточно хорошо, пока тестирование производительности не скажет иначе.
Дэвид Хаммен,

Я считаю, что (в общем) простое подразумевает эффективность. Поэтому часто нет необходимости идти на компромисс.
Дэн

2
«Кажется, что совершенство достигается не тогда, когда больше нечего добавить, а когда нечего больше убирать». - Антуан де Сент-Экзюпери
keuleJ

Ответы:


58

К какому решению я должен стремиться, когда у меня нет жесткой производительности SLA, и даже простое решение может соответствовать производительности SLA?

Простой. Он соответствует спецификациям, его легче понять, легче поддерживать и, вероятно, он намного менее глючит.

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

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

Повышение производительности почти неизбежно связано с множеством проблем с запахом кода. Вы упомянули несколько вопросов: сложный подход, сложный для реализации, более высокая связь. Это действительно стоит потянуть?


Ваш ответ очень полезен
MoveFast

1
Как можно проще, но не проще; Как можно быстрее, но не быстрее; и т.д.
user606723

2
«Если сомневаешься, используй грубую силу»;)
tdammers

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

12

Краткий ответ: предпочитайте простые решения сложным и помните принципы KISS и YAGNI

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

Кроме того, пытаться быть умным и размещать дополнительную оптимизацию, в то же время создавая приложение, не является хорошей практикой и может слишком усложнить ваше решение. Как известно, "premature optimization is the root of all evil"- из книги Кнута


1
@ManojGumber, нет проблем, и это действительно суть, что нас, программистов, должно заботить в первую очередь.
Е.Л. Юсубов

8

Возьмите урок от Кнута: «Мы должны забыть о малой эффективности, скажем, в 97% случаев: преждевременная оптимизация - корень всего зла».

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

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


4
Обратите внимание, что это не означает, что вы не должны писать хорошую реализацию в первую очередь.

@ ThorbjørnRavnAndersen: конечно, это то, о чем говорят первые два пункта.
Симон

1
@ Симон цитата часто используется в качестве предлога, чтобы выбрать небрежно,

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

@ ThorbjørnRavnAndersen некомпетентные люди будут использовать что-либо для оправдания. Не влияет на ценность оригинальной мысли.
Симон

7

Простота является предпосылкой надежности . Если у вас есть простое решение, которое работает, обязательно сделайте это! Оптимизировать рабочую программу намного проще, чем заставить оптимизированную программу работать. Также не забывайте о законе Мура : если ваше простое решение соответствует сегодняшним целям производительности, оно, вероятно, сокрушит их 1 раз в год или два.


1 Там нет никаких гарантий, потому что, как отметил Джимми Хоффа в своем комментарии ниже, закон Мура имеет свои пределы.


Вы забыли о другом законе Мура, который гласит: «Ой, о моем первом законе ...» Извините, босс, закона Мура больше нет (игра слов) Я не согласен с остальной частью вашей точки зрения, я хотел бы по крайней мере предостеречь, что последняя часть там.
Джимми Хоффа

2
Извините, но во всем моем опыте в этой отрасли. «рабочие наборы» увеличивают FAR быстрее, чем скорость нашего оборудования, которое постоянно обновляется. На самом деле, я бы просто удалил точку зрения Мура.
user606723

@ user606723 Рост точки «рабочего задания» ортогонален «оптимизированному или простому» вопросу: рабочая нагрузка будет догонять их независимо от того, какое решение они реализуют. Смысл введения закона Мура в микс состоял в том, чтобы указать, что даже если простое решение находится под некоторым давлением производительности на момент написания, давление будет уменьшаться по мере появления более быстрого оборудования.
dasblinkenlight

@dasblinkenlight, рост рабочего набора не более ортогональн к вопросу, чем закон Мура. Смысл проблемы с рабочим набором состоит в том, что, если на момент выпуска простого решения под некоторым давлением производительности не будет, производительность будет недостаточной в самом ближайшем будущем, так как увеличивающийся рабочий набор разрушает любое улучшение производительности, достигаемое улучшенным оборудованием. Хотя я все за простое, надежное и удобное в обслуживании программное обеспечение, выпуск программного обеспечения, которое уже находится под давлением производительности при выпуске, и ожидание, что закон Мура выровняет его, - ужасная философия.
user606723

3

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

Оптимальное слово неоднозначное!

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

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


2

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

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


2

Какой стоит дешевле?

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

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

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


2

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

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

Затем рассмотрим другой пример. Консольный игровой движок, который должен обеспечить работу будущих игр компании в течение следующих 5+ лет. Поскольку игры являются программами с чрезвычайно ограниченными ресурсами, во многих случаях эффективность превосходит удобство обслуживания. Написание ваших собственных, очень специфических структур данных и алгоритмов для какой-либо задачи может быть очень важным, даже если это идет вразрез с какими-либо «передовыми методами» разработки программного обеспечения. Хорошим примером этого может служить Data Oriented Design, в котором вы храните свои данные в похожих массивах данных, а не в реальных объектах. Это должно увеличить ссылку на локальность и, как таковой, увеличить эффективность кэша ЦП. Не практично, но очень важно в данной области.


1

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

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

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

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

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


0

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

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

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

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.