Если вы еще не слышали, на сцене программирования/разработки ПО в Твиттере происходит что-то действительно интересное. Все началось с одного из видеороликов Кейси Муратори о программировании с учетом производительности. Он метко назван: Чистый код, ужасная производительность. На самом деле это связано с собственной критикой Кейси в отношении современных программ, эффективность которых составляет менее 1/20. Что является обоснованным опасением, учитывая, что неэффективность является причиной того, что мы не можем получить хорошие вещи (а также причиной, по которой Джон Кармак покинул Meta). Затем вмешался дядя Боб (то есть Роберт С. Мартин) и провел очень обстоятельную и познавательную дискуссию с Кейси с использованием Github. Дискуссия продолжается по сей день. Это также породило тред в Hacker News.

Чистый код действительно медленный…

Я видел видео и думаю, что, хотя он и прав, на самом деле он не правильно рисовал всю картину. Что я понял из его видео, так это то, что полиморфизм и (чрезмерный) принцип единой ответственности работают медленно (и, следовательно, плохо!). Что правда, в некотором роде. Поскольку с полиморфизмом существуют затраты на поиск в vtable и косвенные действия. Не говоря уже о том, что это сделает функцию и/или данные разбросанными вокруг, а не рядом друг с другом, что приведет к промаху кэша ЦП L1/L2. То же, что и СРП. Извлечение функции в несколько частных вспомогательных функций также может привести к промахам кэша. Так же как и встроенные функции. К сожалению, полиморфизм лежит в основе принципа SOLID. Один из ключевых принципов Чистого Кода.

Производительность действительно важна…

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

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

Есть много способов сделать ваш код производительным:

  1. Во-первых, это выбор правильного алгоритма. Это, пожалуй, самый простой. Выбор правильного алгоритма может быть разницей в том, чтобы заставить код работать, как The Flash или Eeyore. Итак, освежите свой алгоритм!
  2. Затем мы можем получить помощь от самого оборудования. Например, использование кешей L1/L2 или процессора для ускорения работы кода. Кэш L1 может работать в 100 раз быстрее, чем ваша оперативная память, а L2 может работать в 25 раз быстрее. Но для этого мы должны знать, как функция и данные располагаются в памяти. Так как вам нужно, чтобы они были близко друг к другу, чтобы кеш вступил в силу. Мы можем сделать это, используя шаблоны Data Oriented Design или Entity-Component-System. Вы можете прочитать эту ссылку, если хотите узнать больше о кэшах.
  3. Мы также можем получить помощь от расширений набора инструкций ЦП, таких как MMX, SSE или AVX.

Но чистый код тоже важен…

Однако стремление только к производительности также не является правильным путем. Я видел много плохо написанных и нечитаемых кодов. И большинство из них относятся к тому времени, когда я был разработчиком игр. Как вы, возможно, знаете, разработчики игр печально известны своей погоней за производительным кодом. Потому что это означает, что вы можете настаивать на большем количестве контента, качестве, количестве трисов, текстурах и т. Д., Чтобы игра выглядела лучше, не ставя под угрозу FPS.

Но я действительно считаю, что если вы беспокоитесь только о производительности, то вы можете получить конечный продукт с ошибками, такой как Source Engine. Печально известный дефект «coconut.jpg», вероятно, является результатом нарушения принципа разделения ответственности / единой ответственности. Таким образом, если вы измените одну часть кода, это может повлиять на другую часть, которая не имеет ничего общего с частью, над которой вы работаете. То же самое произошло со мной и Blackberry Messenger. В BBM iOS есть класс, который называется BBMessage. Нам запрещено трогать класс без необходимости. И если нам нужно поработать над этим, аккуратно протяните нитку, потому что это может сломать другие вещи.

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

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

Должен сказать, когда я сменил карьеру с игрового разработчика на мобильного (в основном iOS) разработчика в KMK Labs / Vidio.com, я испытал довольно большой шок, потому что парадигма в офисе другая. Итак, мне довольно трудно не отставать. Чистота и ремонтопригодность более предпочтительны, чем производительность. Скорость процесса разработки важнее конечного продукта (но все же в приемлемом значении). Поэтому мне нужно узнать о чистом коде, SOLID, чистой архитектуре, TDD, MVVM, экстремальном программировании и т. д.

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

так что нам делать?

Главное быть прагматичным и гибким. Мы должны помнить как о производительности, так и о чистоте нашего кода. Я всегда думаю, что чистота, удобочитаемость, расширяемость и надежность кода важнее производительности. Поскольку большинство наших подпрограмм обычно не требуют больших ресурсов, мы можем избежать некоторого снижения производительности и добавить более структурированный код. Это за исключением случаев, когда мы принимаем во внимание нагрузку, которую наш код вызовет на устройстве нашего пользователя. Как он будет разряжать свою батарею, нагреваться через секунду и т. д. Но мы также должны понимать, какая часть нашего приложения нуждается в производительности. Обычно он находится в самом глубоком слое нашего приложения. Где его называют сотни/тысячи/сотни тысяч/миллионы раз. Затем мы отказываемся от чистого кода в пользу некоторых методологий повышения производительности. Итак, в некотором смысле, что мы должны сделать:

  1. Знать основы:намне нужно глубоко разбираться в том, что на самом деле происходит внутри компьютера. Нам просто нужно знать, что происходит под капотом, достаточно хорошо, чтобы судить о том, как обойти ваш код. Нам также необходимо знать основы языка и инструментов, которые мы используем.
  2. Знать домен: домен в области разработки программного обеспечения обычно относится к предметной области, в которой приложение предназначено для применения. Обладая глубоким пониманием предметной области, мы можем понять, что пытается решить определенный код. И как кодировать лучше. Например, в области приложения больничной очереди нам не нужны наносекунды производительности. Поэтому вместо этого лучше увеличить время разработки. Другое дело с доменом видеоигр, где нам нужно рендерить в реальном времени. Но даже при этом могут быть некоторые части кода, которые должны делать обратное. Например, рендеринг номера очереди в режиме реального времени для приложения больничной очереди, которому нужна производительность.
  3. Правильно делайте абстракции:при правильном знании предметной области вы можете разработать стратегию того, как вы будете подходить к проблеме. Затем вы должны сделать абстракции по проблеме. Абстракции можно определить как скрытие сложности и ненужной информации для данного контекста и просто предоставление информации, более соответствующей контексту. Абстракция в данном случае — это не просто абстракция, как в объектно-ориентированном программировании. Это всего лишь один из видов абстракции. Типы переменных являются абстракциями. Абстрагируются биты, которые составляют фактическое значение в памяти. Именование переменной является абстракцией. Это абстрагирование неизвестной переменной во что-то более подходящее для текущего контекста переменной. Операции и функции являются абстракциями регистровых инструкций. Именование операции или функции является абстракцией. Структуры данных — это абстракции. Слои — это абстракции. Вы поняли идею.
  4. Будьте прагматичны. В конце концов, цель программирования — предоставить пользователю решение в виде приложений. Безусловно, нам нужно предоставить то, что пользователь хочет от наших приложений или игр. Может быть, вам нужна производительная игра с более чем 100 FPS? Или, может быть, им нужно приложение, которое будет иметь множество функций и будет надежным, менее глючным и доставленным как можно скорее? Мы должны прагматично относиться к имеющимся у нас инструментам, потому что пользователям все равно, как мы делаем свою работу. Вы знаете поговорку с молотком и гвоздями? Да, это. Не делай этого.
  5. Будьте гибкими. нам нужно понять, что парадигмы, шаблоны и принципы программирования — это всего лишь инструменты и рекомендации, которые помогут сделать наш код лучше. Это не жесткие правила, которым нужно следовать всегда и за любые деньги. Не каждый корпус переключателя нужно менять, чтобы он стал открытым-закрытым. Не все объекты нужно менять с «Массив объектов» на «Объект массивов» для выполнения DOD. Их следует рассматривать в каждом конкретном случае. И чтобы понять, какой из них вам следует использовать, вам необходимо глубокое понимание основ и предметной области.
  6. Больше заботьтесь о своем коде и команде: это может говорить само за себя. Плохой код (то есть медленный и/или грязный код) — это результат работы программиста, которому все равно. Заботьтесь о своем коде, товарищах по команде, продукте и пользователях. Затем вы постараетесь кодировать как можно лучше.

Послесловия

Позвольте мне оставить вас цитатой мудрого Роберта С. Мартина, также известного как дядя Боб, из его беседы с Кейси Муратори:

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