Pull to refresh

Comments 364

[Почти] ни к какому коду не прилагается описание алгоритма. И к редким кодам (библиотеки, например) прилагается грамотная и полная документация (без описания алгоритма, опять же).

Поэтому нужно и использовать комментарии, и использовать выразительные названия переменных, и использовать отступы.

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

UFO just landed and posted this here

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

UFO just landed and posted this here

Я не говорю про лево-право.
Я говорю, что когда вы используете переменную, лучше будет если вы знаете ее точный тип, а не замазываете его с помощью ауто.
Вот иллюстрация:
https://stackoverflow.com/questions/71048332/does-auto-keyword-always-evaluates-floating-point-value-as-double

Я не считаю это мелочами, по мне это удобство ничтожно, по сравнению с вредом.

PS. IDE разные бывают.

В примере очень плохое использование auto. Как каждому базовому типу своё применение, так и auto нужно применять к месту и по делу. Но auto базово никак не скрывает тип, это же не any.

UFO just landed and posted this here

То что по ссылке это лишь очень сильно упрощенная версия реального кода.
Этот код был написан опытным программистом.
Он не стал разбираться в тонкостях использования auto, а просто воткнул и все.
Из-за этого случился баг - некий рисунок сдвинулся на 1 пиксель в сторону.
Пару автоматических тестов посыпались.
Разбирались два человека 4 дня.
Если бы программер не поленился правильно прописать типы - проблема бы не возникла.

UFO just landed and posted this here

Ну вот именно ошибку округления он и получил.
Еще раз: это сильно упрощенный пример "по мотивам", просто чтобы дать представление о проблеме.
Решение было именно в явном прописывании типов, поверьте на слово.

		    math.h 				cmath
  		    cos		std::cos	cos		std::cos
gcc 11.2 	f		f			d		f
msvc 22		float	float		float	float
//#include <math.h>
#include <cmath>
#include <iostream>
#include <typeinfo>

int main ( int argc, char* argv[] ) {
    auto msvcAuto1 = cos ( 9.f );
    auto msvcAuto2 = std::cos ( 9.f );
    std::cout << typeid(msvcAuto1).name () << std::endl;
    std::cout << typeid(msvcAuto2).name () << std::endl;
    return 0;
}

То есть, получается, проблема не в auto. Ведь даже если явно указать float - то всё равно могут быть проблемы, если будет вызвана перегрузка cos, возвращающая double.

Спасти может -Wconversion, но, опять же, например в msvc это не поможет.

Спасибо за интересный пример

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

UFO just landed and posted this here

А вообще, а что хорошего в перегрузках встроенных операторов и неявных преобразованиях? Разве не было бы лучше, если бы были строгие требования, и для преобразования нужно было бы указывать типы явно?

UFO just landed and posted this here

Я перегрузку операторов тоже не люблю и стараюсь избегать

Если стараетесь избегать, значит используете, а если используете, значит есть в в этом что-то хорошие в определённом контексте.

Чтобы получить ссылку, можно написать слева decltype auto. Заодно это сразу обратит внимание на то, что здесь именно ссылку надо получить, если во всех других случаях decltype не писать.

Никому не интересно, что там лично вас бесит. Если у вас есть объективные претензии - высказывайте. Если нет - обратитесь ко психотерапевту, чтобы бесы не мешали вам жить.

Не использовать автоматическое форматирование, это потерянное время на ревью.

В большинстве случаев вы получите такие-же отступы, но еще и скобками. Я, например, не вижу никакой проблемы ни в наличии скобок ни в отсутствие.

Читабельность – это в первую очередь не имена переменных, а правильное устройство кода: чтобы для понимания достаточно было смотреть на маленький кусочек, не заглядывая в остальное.

Контракты в этом плане практически идеальны, да.

UFO just landed and posted this here

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

Хотя и контракты и читаемость это не так долго, если уметь.

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

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

Но только надо ещё что бы вдруг в середине процесса заказчик не
переиначил половину тз.

Мне кажется в индустрии сложилось мнение, что это какой-то редкий случай. А по факту это просто базовое свойство разработки.

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

Интересно, было ли у автора статьи такое, что написанные коментарии переставали соответствовать коду после правок

Не знаю что у автора, он их прячет, а у меня они порой и до мерджа устаревают. Я поэтому стараюсь документировать только контракты, их всежё меняю аккуратнее.

ну для истории, нельзя же удалять

Для истроии есть гит, удалять можно всё, и даже нужно. У меня даже почти получается.

Очень полезная статья, добавил в закладки, что-бы когда буду писать code style guide на своём следующем проекте на cpp 20, использовать её как "вредные советы".

Плюсую неимоверно, не дай бог на такого коллегу нарваться...

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

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

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

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

Библиотеку для разархивирования zip можно написать один раз и за десятилетия жизни проекта, в неё не будет сделано ни единого коммита.

В бизнес логике с утра ты делаешь коммит нового кода, к вечеру там уже 6 залитых изменений от команды. Вы не понимаете что в этом случае выразительность = деньги? Сотни js фреймворков в год это явное доказательство того, что есть острая необходимость писать код более выразительно и поэтому в этом направлении сообщество активно работает, подскажете сколько в год выходит библиотек для поддержки zip?

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

Вы не понимаете что в этом случае выразительность = деньги?

К сожалению не понимаю.
Я целую статью написал про то что не понимаю, что означает слово "выразительность" применительно к коду.

Сотни js фреймворков в год это явное доказательство того, что есть острая необходимость писать код более выразительно

Я думаю, это доказательство чего-то другого.

UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here

<зануда_mode>

e = mc^2 vs j = ab * ab

пример про разработку

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

Если первый вариант не является математической формулой (mc^2 = m * c^2), а "про разработку" (т.е. mc - это переменная, а mc^2 = mc * mc ), то он не имеет упомянутой ассоциативной связи. И тогда нельзя сказать, какой из вариантов более выразительный.

Поэтому пример - ни разу не про разработку.

</зануда_mode>

UFO just landed and posted this here

первый пример будет давать доп.информацию,

Да, он будет давать информацию, что у вас "ошибка" в формуле, каждый раз при просматривании кода.

Вы троллите? Сами привели самую известную формулу в мире (e=mc^2), а теперь говорите, что не это имели ввиду.

Что ж, в таком случае j = ab * ab действительно более выразительный (хотя названия переменных всё равно плохие). Вы про это говорили? Что если использовать что-то общеизвестное в другом контексте, то можно случайно ввести в заблуждение, поэтому первый вариант невыразительный? Очень смутная иллюстрация у вас вышла.

Особенно если учесть, что "^" -- не возведение в степень. :-)
(Мы же всё ещё про С/С++?)

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

Но вот работу с диском и протоколы связи тут вы точно зря приплетаете. Если код написанный в вашем стиле пишет 100 байтов не диск один раз, то после рефракторинга в выразительный будет 5 раз писать по мегабайту? Вы точно выразительность с чем-то другим не путаете?

Готов предположить, что после разделения ответственности по разным классам, какое-нибудь сохранение глобальных настроек (или там, прогресса пользователя в игре) будет дёргаться из нескольких разных мест и чаще, чем если всё в одном God Object держать.
Не 5 мегабайт вместо 100 байт, но словить какого-то сорта ухудшение характеристик можно. Ну либо придётся дополнительно меры предпринимать, чтобы этого не допустить (а это уже усложнение кода конечно).

Готов предположить, что после разделения ответственности по разным
классам, какое-нибудь сохранение глобальных настроек (или там, прогресса
пользователя в игре) будет дёргаться из нескольких разных мест и чаще,
чем если всё в одном God Object держать.


В таком случае разделение подразумевает создание новой сущности, которая окрестрирует всю это логику, God Object превратиться в Facade и модули. То есть в рузультате мы получим простой объект с небольшим API и это будет единственное место, где система будет работать с этой функциональностью.

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

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

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

Как это повлияет на размер файла сохранения прикиньте самостоятельно.

@retry(3)
def save(filename):
    with pause(), icon("save"):
        save_character(filename)
        save_world(filename)
    print(f"Saved to '{filename}'")
    

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

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

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


Где упадёт скорость при разделении? Лишние вызовы?

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

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

Распиливание же сохранения по отдельным модулям - уронит производительность.

Сохранение это данные, модули это про код. Не очень понял, что именно вы хотите этим сказать.

Что именно уронит производительность?

Где упадёт скорость при разделении? Лишние вызовы?

Лишние вызовы. Создание новых объектов (чтобы не таскать из метода в метод по 10 параметров). Новые обращения к диску и сети (потому что теперь объекты независимо обращаются итп).

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

Эм, вот и просадка - вместо одного запроса к серверу получаем N. Это уже не "спички" (вызовы), сетевой запрос - тяжёлая штука.

Что именно уронит производительность?

Если "в лоб" разделить код по модулям (согласно тому, кто за что отвечает), можно получить отдельные хождения в IO, которые уронят производительность.

Лишние вызовы. Создание новых объектов (чтобы не таскать из метода в метод по 10 параметров)

Это копейки. На 10 вызовах в секунду вы даже померить разницу не сможете.

Новые обращения к диску и сети (потому что теперь объекты независимо обращаются итп).

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

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

Эм, вот и просадка - вместо одного запроса к серверу получаем N. Это уже не "спички" (вызовы), сетевой запрос - тяжёлая штука.


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

Если "в лоб" разделить код по модулям (согласно тому, кто за что отвечает), можно получить отдельные хождения в IO, которые уронят производительность.


С мыслью, что если делать как попало, то получится черти-что я согласен.

В моем мире среди "согласно тому, кто за что отвечает" как раз IO и будет таким компонентом разбиения. Чтение диска и работа с сетью, это низкоуровневый код и бизнес логика ничего об этом знать не должна. Это один из принципов того, как я разделяю на модули.

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

Это копейки. На 10 вызовах в секунду вы даже померить разницу не сможете.

Если их 10 в секунду - конечно нет смысла их экономить. А если миллион?

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

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

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

Тут согласен конечно. Мой пример - игровой конфиг (по сути - json-ка на десяток килобайт). Вот её тянуть одним запросом не в пример эффективнее, чем дёргать какое-то API при получении каждой настройки.

В моем мире среди "согласно тому, кто за что отвечает" как раз IO и будет таким компонентом разбиения. Чтение диска и работа с сетью, это низкоуровневый код и бизнес логика ничего об этом знать не должна. Это один из принципов того, как я разделяю на модули.

В общем-то да, тут согласен. Проблема в том, что если модули сравнительно развесистые и у каждого своё IO, иногда стоит это IO объединить под какой-то общей структурой.

Тут согласен конечно. Мой пример - игровой конфиг (по сути - json-ка на десяток килобайт). Вот её тянуть одним запросом не в пример эффективнее, чем дёргать какое-то API при получении каждой настройки.

Что мешает просто скрыть это за каким-нибудь кеширующим фасадом/адаптером c eager-load?

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

Гм, ничего конечно не мешает. И конкретно в данном случае - да, именно так и делается.

Впрочем, есть ситуации, когда "де-лапшизация" кода таки просаживает ему производительность.
Вот скажем пример https://gist.github.com/denis-ftc-denisov/7c293bd41822c557e84f9358882467e9

Как его сделать менее "лапшой", притом, чтобы не выделять дополнительно памяти (можно выделить константное число памяти, но не пропорционально размеру ввода или вывода) и не начать расходовать CPU (с CPU тут попроще). И это ещё "приличная" версия, можно эффективнее написать, но будет совсем лапша.

Ну, вообще говоря, судя по конструкциям наподобие:

 while (finishCount < cores)
 {
     Thread.Sleep(1);
 }
mutex.WaitOne();
finishCount++;
mutex.ReleaseMutex();

этот код и так должен быть, мягко говоря, далек от производительности. Впрочем, это Unity, и поэтому я вообще не в курсах - может быть в нем какие-то особенности API и подобные вещи именно так и приходится делать.

В этом месте я откровенно поленился и создаю лишний тред, да. По-хорошему, в основном потоке API сделать асинхронным и ждать в этом while корутиной, а не вот так "в лоб".

А семафоров там (в юнити) нет? (А еще лучше SemaphoreSlim).

Хотя гоню, тут, конечно, нужен event и interlocked increment.

Есть конечно. Вроде бы и тот и тот. Да, семафоры тут конечно лучше подойдут, согласен. Говорю же - есть куда оптимизировать.

Впрочем, будет ли существенно быстрее семафор тут - не думаю, как раз Mutex всего (cores - 1) раз лочится и разлочится (по сути просто инкремент защищает).

В плане общей идеи как-то так:

private int _counter;
private int _limit = 42;
private AutoResetEvent _limitReached = new AutoResetEvent(false);

public void Foo()
{
    Thread.CreateThread(Bar);
    // Ждем дочерний поток
    _limitReached.WaitOne();
}

private void Bar()
{
    while(Interlocked.Increment(ref _counter) < _limit)
    {
        // типа делаем что-то
        Thread.Sleep(100);
    }

    _limitReached.Raise();
}

Это-то понятно. Тогда уж делать массив WaitHandles по числу дополнительных тредов и в основном дёргать WaitAll на них.

А хотя сам себя запутал - лишнего треда там нет, но основной тред ждёт таким образом остальных, если он вдруг оказался быстрее всех. В целом функция нормальная, если не из main треда Unity запускать. Ну и кстати да, чтобы не делать лишний тред, там присутствует некоторая "лапшистость" (запускаются cores - 1 тредов циклом, а потом последний кусок работы запускается в текущем треде отдельно).

Да очень просто там всё упрощается.


Для начала, собрать пары из int или float в структуру, определив для неё математические операции. Среда исполнения в Unity, конечно, устаревшая хрень — но даже старая Mono поддерживает нормальную работу со структурами.


Если есть возможность использовать современный C# — можно использовать record struct, это переопределит известные ногострелы Unity в виде методов ToString, Equals и GetHashCode.


Дальше условный оператор с проверкой cores > 1. Он не нужен. Вы же текстуру ресайзите, на этом фоне немного избыточных подготовительных работ вообще никто не заметит!


Ах да, оптимизация с исполнением части работы в вызывающем потоке — важная, но сделать её можно проще. Для начала, переменную ParameterizedThreadStart ts надо вытащить из цикла. А после этого можно прямо её и использовать.


Да, убрать ещё нафиг мьютекс и сделать вместо него событие — кода будет столько же, а толку больше.


Вот мой вариант параллельной работы:


            finishedCount = 0;
            var executor = useBilinear 
                ? new ParameterizedThreadStart(BilinearScale)
                : new ParameterizedThreadStart(PointScale);

            int i;
            for (i = 0; i < cores - 1; i++)
            {
                var threadData = new ThreadData(slice * i, slice * (i + 1));
                new Thread(executor).Start(threadData);
            }

            var threadData = new ThreadData(slice * i, newHeight);
            executor(threadData);

            if (Interlocked.Increment(ref finishedCount) != cores)
                finishedCount.WaitOne();

// … и при завершении работы

            if (Interlocked.Increment(ref finishedCount) == cores)
                finishedCount.Set(); 

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

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

Упрощаю дальше.


Параметр bool useBilinear можно заменить сразу на ParameterizedThreadStart — это ещё сильнее упростит код, причём внешние потребители этого не заметят. Одновременно код станет расширяемее, и опять это бесплатно.


Поля w и w2 переименовать бы в inputWidth и outputWidth — тут вообще ничего с точки зрения производительности не изменится, а понятности резко добавится.


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


Вот эта строчка кода — while (yFloor + 1 >= h) yFloor--; — ужас полный, кто помешал использовать Min?




PS у вас ColorLerpUnclamped работает криво: цветовые каналы должны учитывать "свою" альфу, иначе на границе прозрачных областей будут проявляться контуры случайного цвета

Про замену useBilinear я бы поспорил - всё же вытаскивать наружу "потроха" в виде ParameterizedThreadStart наверное не очень хорошо.
Вот на какой-нить Enum его заменить наверное можно бы, да. Ну либо прямо делегат в параметр пробрасывать (но тогда надо формализовать, что там за Object у него будет в параметре, т.е. потребитель должен знать, какие методы можно передавать в аргумент, а какие нельзя - опасно, ИМХО.

w и w2 - согласен, в целом нейминг в этом куске у меня не самый лучший (ибо писалось "по-быстрому" без последующего приведения в порядок)

Про замену useBilinear я бы поспорил — всё же вытаскивать наружу "потроха" в виде ParameterizedThreadStart наверное не очень хорошо.

Так оно ж не наружу, метод ThreadedScale — приватный. Внешнее api в виде методов Point и Bilinear останется неизменным.

Да, точно, согласен.

Про аллокации самый классный вопрос, без шуток. Вообще, этот кусок кода был написан потому, что нужен был способ ресайзить прилетающие картинки, не делая крупных аллокаций на каждую новую картинку.
Почему так - я наткнулся на фрагментацию managed heap в Unity (ну по крайней мере такова гипотеза техсуппорта самой Unity, с которым я эту проблему обсуждал). Грубо говоря, если выделять большие куски памяти (под массив newColors) каждый раз при ресайзе новой текстуры, размер потребляемой Unity памяти на девайсе постоянно растёт (ибо она не может выделить новый кусок в старом хипе почему-то, хотя managed объекты там подохли уже).
Собственно потому да, аллокации мы тут экономим. Крупные конечно только.

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

Вот потому массив newColors надо переиспользовать, но это никак не мешает уложить всё остальное во временный объект.

Можно и так, правда всё равно придётся вешать лок на newColors, а по сути это значит, что можно и глобальный лок на весь ThreadedScale навесить, разницы особо не будет.

Ну да, лок тут тоже поможет. Хотя я думал взять нормальный пул, я точно видел что Span в Unity доступен, значит и ArrayPool должен быть где-то рядом.

Главное чтобы этот пул не фрагментировался потом (а то получим ровно ту же проблему, которую пытались решать).

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

while (yFloor + 1 >= h) yFloor--; - не помню, почему она такая, возможно в какой-то момент что-то из этого было float-ом и было нужно избежать ненужных приведений типов. Но замечание резонное, да.

А про ColorLerpUnclamped я бы послушал более детально, если можно.

А про ColorLerpUnclamped я бы послушал более детально, если можно.

раз: Опасайтесь прозрачных пикселей
два: Как работает альфа-композитинг


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


(c1.r * c1.a + (c2.r * c2.a - c1.r * c1.a) * value) / (c1.a + (c2.a - c1.a) * value)

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

А если миллион?

А давайте попробуем. Возьмём Питон, он не далает оптимизаций, и в черезмерном быстродействии не был замечен.

Цикл на миллион, запущен 100 раз. То есть 100 миллионов вызовов. Звучит серьёзно.

С дополнительной функцией 2.993393 секунд
Без дополнительной функции 2.991126 секунд

Итого 0.003 секунды разницы на одном из запусков.

Погрешность мужду запусками примерно 0.002. Сопоставимо с разницей.

from timeit import timeit


def foo():
    result = 0
    for x in range(1_000_000):
        result = result + x
    return result


print("Foo", timeit("foo()", number=100, globals={"foo": foo}))


def goo(a, b):
    return a + b


def boo():
    result = 0
    for x in range(1_000_000):
        result = goo(result, x)
    return result


print("Boo", timeit("boo()", number=100, globals={"boo": foo}))

Проверка на то, что там реально миллион вызовов.

from profile import run
run("boo()")
         1000005 function calls in 0.766 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.766    0.766 :0(exec)
        1    0.000    0.000    0.000    0.000 :0(setprofile)
        1    0.000    0.000    0.766    0.766 <string>:1(<module>)
        1    0.000    0.000    0.766    0.766 profile:0(boo())
        0    0.000             0.000          profile:0(profiler)
  1000000    0.375    0.000    0.375    0.000 scratch_15.py:14(goo)
        1    0.391    0.391    0.766    0.766 scratch_15.py:18(boo)

Well, для миллиона и у меня разницы не наблюдается

const int ITERATIONS = 100000000;

		static void Main(string[] args)
		{
			var start = DateTime.Now.Ticks;
			TestLoop();
			var delta = (DateTime.Now.Ticks - start) / TimeSpan.TicksPerMillisecond;
			Console.WriteLine("Loop: {0:0.000}", delta);
			start = DateTime.Now.Ticks;
			TestMethod();
			delta = (DateTime.Now.Ticks - start) / TimeSpan.TicksPerMillisecond;
			Console.WriteLine("Method: {0:0.000}", delta);
		}

		private static void TestMethod()
		{
			int result = 0;
			for (int i = 0; i < ITERATIONS; i++)
			{
				result = Method(result, i);
			}
			Console.WriteLine(result.ToString());
		}

		private static int Method(int a, int b)
		{
			return a + b;
		}

		private static void TestLoop()
		{
			int result = 0;
			for (int i = 0; i < ITERATIONS; i++)
			{
				result += i;
			}
			Console.WriteLine(result.ToString());
		}

Для ста миллионов она в общем-то есть. Однако только в Debug-версии (что понятно, потому что в Release метод инлайнится и IL-код получается идентичным).

А вот что в питоне происходит - хороший вопрос. Наверняка какие-то оптимизации.

Вызов функции-то понятно что копейки, а вот создание объекта (с выделением памяти) уже потяжелее будет. Особенно в языке GC или при использовании древнего аллокатора. Особенно в Unity где собрано комбо из древности и GC.

Как раз создание объекта в .NET очень быстрое. Какую-любо подлянку можно ожидать только от GC, потому что запускать его не замораживая все остальное приложение пока что никто не научился. В крайних версиях .NET появились "pinned object heap" и классы из System.Buffers которые в случае надобности позволяют управлять памятью более "вручную".

За любым созданием следует удаление, которое требует запуска GC с его подлянками. Это во-первых.


А во-вторых, любой stop the world GC вызывается не в произвольные моменты времени, а при неудачном создании объекта.

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

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

UFO just landed and posted this here

О как.
А я Мартина не читал вообще.
Похоже, ничего не потерял.

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

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

То есть просто разбивка одной функции на две приводит к тому что начинает тормозить?

Well, yes, и такое тоже бывает. Сталкивался и в C# и в C++. Понятно, что должно несколько факторов сложиться (компилятор не смог заинлайнить функцию, накладных расходов на параметры много итп), но бывает.
Даже при условии, что функции не виртуальные (с виртуальными ещё lookup в vtable добавляется).

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

Не знаю, на чем написана оригинальная Цивилизация 5. Но вот клон на Котлине работает ощутимо быстрее. https://github.com/yairm210/Unciv

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

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

Не надо думать о тех, кому придется читать ваш код ... профессионалы по нужде поморщатся, но прочитают и сделают то что нужно

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

Для бизнеса время - это деньги (причем немалые, учитывая современные зарплаты разработчиков)

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

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

Пишите так, чтобы ваш код больше не нужно было читать. Вообще никогда.

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

Писать надо экономно. Нужно беречь ресурсы. Нельзя говорить "клиент мол просто возьмет железо помощнее да еще 100Тб памяти".

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

Сделают, только это займет у них больше времени. А потом и у Вас займет больше времени работать с их кодом.

Бездоказательно.

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

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

Там где я работал, документировали в большинстве случаев. Наверное мне везло.

Я рекомендую Вам просто попробовать данную методологию.

спасибо.
Я веду пару пет-проектов уже несколько лет и комментирую, и документирую по мере сил и необходимости.
Пока справляюсь.

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

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

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

Чтобы в таком разобраться в любом случае нужно понять что этот кусок делает, как только разобрался - становится намного проще.
Я вот с трудом представляю как можно переписать это чтобы было значительно проще разобраться с этим кодом. Для каждой строчки коменты написать? Ну ммм, может небольшой комент перед началом функции был бы кстати.
А так в выделенном куске 2 цикла for и один while и понимать что там крутиться в любом случае потребует напряжения.
Мне вот интересно как надо переписать например один из циклов чтобы было в 2 раза понятнее например.

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

Мне вот интересно как надо переписать например один из циклов чтобы было в 2 раза понятнее например.

ИМХО, эти циклы можно сделать гораздо понятнее, если не стараться экономить на строчках:

for(int i = 0; i < n; i++) {
    va[i] = l[i];
    tcx[i] = clip((l[i].x - pc.x) / tilesz.x, 0, 1);
    tcy[i] = clip(-(l[i].y - pc.y) / tilesz.y, 0, 1);
    rcx[i] = 0;
    rcy[i] = (lh == 0)?0:((l[i].z - l[0].z) / lh);
    rn[i] = 0;
}

Оно в итоге получится длиннее, но выразительнее (в том плане что лучше видно, что хотел написать автор).

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

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

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

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


Что делает или хотя бы должен делать первый кусок я даже близко сказать не могу. Хотя потратил на его "расшифровку" намного больше времени.

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

Например, если дать кусок кода, реализующего lock-free list, человеку, который про lock-free не слышал, то судить о выразительности ему будет трудно.

Так же и здесь.

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

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

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

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

А они разве не из одной предметной области? :)

Без понятия, оба фрагмента для меня бесконечно далеки.

но я в принципе понимаю происходящее просто пробежавшись по нему глазами

и что происходит начиная со строчки 185? Что то мне подсказывает что просто пробежаться глазами тут мало

Очевидно же, что там происходит ровно то что написано в названии метода — построение сетки вершин.

UFO just landed and posted this here

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

Далее тут сразу видно, что в функции как минимум два логических блока (подготовка данных + два for, потом опять подготовка данных + while). Можно либо вынести их в отдельные функции с нормальным названием и описанием, либо хотя бы оставить коммент, что будет происходить в каждом блоке

Для начала дать переменным осмысленные имена.

Вместо tcx tcy писать texture_coord_x texture_coord_y и в таком духе?
подозреваю что сокращения в этом коде вполне типичны для графических движков.
Хотя согласен, если бы названия были бы чуть информативнее было бы лучше.

Далее тут сразу видно, что в функции как минимум два логических блока (подготовка данных + два for, потом опять подготовка данных + while). Можно либо вынести их в отдельные функции с нормальным названием и описанием, либо хотя бы оставить коммент, что будет происходить в каждом блоке

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

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

Или просто не писал

> Пишите так, чтобы ваш код больше не нужно было читать. Вообще никогда.

Я рекомендую Вам просто попробовать данную методологию. Сделайте какой-нибудь пет-проект средних размеров. Не трогайте его год, а потом добавьте в него несколько фичей.

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

Не читать никогда - это какой-то слишком идеалистический подход. Автор статьи 20 лет на десятке языков работал, но не знает о необходимости регулярно читать и перечитывать код чужой и свой? С точки зрения того, кто поддерживает десяток разных проектов на протяжении долгих лет с регулярными изменениями в команде разработчиков и в технологиях... Это самая странная мысль в статье, как мне кажется.

UFO just landed and posted this here

Зато пресловутый time to market лучше

Если честно я не вижу, как отсутствие читабельности кода улучшает time to market. Программисту со стажем не требуется часами сидеть выдумывая имена переменных. В основном все делается уже на рефлексах. Разве что сэномить пару минут на длине имен переменных?

job security тоже лучше

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

UFO just landed and posted this here

Не нужно много думать об именах, паттернах или типах ⇒ можно быстрее выкатить в прод хоть что-то. А что потом ошибки — ну так и хрен с ним.

Не все видят связь. Или не хотят видеть. Ведь если считать эффективность без этих ошибок, то можно больше премий получить.

капитально проиграл в корпоративной политике чуваку, топившему за херак-херак-и-в-продакшен

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

мы тут в нашем отделе для машинного обучения с плюсов на питон перешли, учи питон или GTFO

А что такого вы на С++ в машинном обучении делали?

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

UFO just landed and posted this here

Но в вашем проекте с отступами всё в порядке, говорящие имена переменных присутствуют, а вот комментариев мало.


С пунктом "8. Писать надо просто", кстати, согласен полностью, и, ИМХО, это то, что напрямую имеет отношение к читабельности.

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

Я не требую от других комментировать все подряд - я выступаю против идеи самодокументирующегося кода, мол "не надо вообще ничего комментировать/документировать, пусть оно само".
Считаю нелепым избегать комментирования принципиально.

Почитал комменты и ваш пост и замечаю что вы комментариями в коде пытаетесь заменить документацию, комментарии != документация

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

По мне ничего страшного, значит комментарии не так сильно нужны для документации.

Другой пример пример где javadoc комментарии излишни если они не привносят никакой информации, например:

/**
 * @return int
 */
int main()

Какой смысл тут в комментарии ?

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

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

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

Теперь представьте у вас команду из 8 разработчиков работающая над единой кодовой базой. И вот один из низ используется auto везде где только можно - ну потому что ему так понятнее (не у всех же понятность с вашей совпадает ? ). Второй везде прописывает типы. Третий использует корутины. А четвертый явно потоки пишет и через мутексы синхронизирует их. Ну и так далее - каждый привносит свой опыт и пишет как он привык.

Хороший ли это проект ? Сможет ли он быстро развиваться ?

На практике, если надо разобраться в коде, то его "правильность" мало влияет на скорость понимания, а иногда и затрудняет, особенно когда код "правильно" разложен по множеству классов и файлов


А вы когда видите в коде вызовы сторонних библиотек, вы тоже в их код заглядываете?

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

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


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


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


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

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

В сторонке можно делать все что угодно.

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

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

Обсуждаем то ваш случай, а не мой. У меня с чужими сорсами все в порядке.
Что вам мешает скопировать в стороночку и изучать молча c помощью рефакторинга?
Или клонированный код это уже не тот код?

Я писал про рефакторинг исключительно в контексте прода. В сторонке я делаю много всякого.

Т.е. проблема всего лишь в том что вам накладно иметь дело с продом и с отладочным проектом одновременно?

И из-за этого весь шум с разрывами шаблонов?

Я тут вспоминаю экосистему Embarcaderо на Delphi. Там комменты отсутствовали напрочь. Все именно так и делось, как самодокументированный код. Ну была скупая дока. И при этом мало кто жаловался. Потому что весь код отлично проходил отладку и был отличный нативный браузер кода (собственно и сейчас он живее всех живых). Это намекает на ещё один фактор, а именно среду в которой создаётся код. Т.е. если код изучаете вне его родной среды, то будет ад, а если в среде, то рай.

Т.е. проблема всего лишь в том что вам накладно иметь дело с продом и с отладочным проектом одновременно?

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

Просто невероятно отличный пример. Хотел его тоже озвучить, т.к. я уже более 10 лет работаю с Delphi и там действительно почти нет комментариев. Только местами и в основном для заметки ("тут не трогать, так надо" или "пришлось сделать костыль, т.к. ...").
И на самом деле я почти не трогаю справку, т.к. можно совершенно любое место открыть и получить информацию о том, что происходит в методе. А если плохо понятно, то поставить точку останова и пройтись по коду, наблюдая за значениями переменных, вызовами и т.д.

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

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

Вот у меня есть опыт работы в 2х компаниях, в обоих 200+ программистов, офисы по всему миру, миллионы пользователей и т.д. Оба проекта в которых я был находились в продакшене. Более того, это прямые конкуренты друг другу. В одной я комитил примерно раз в месяц, а ревъю и тесты могли занимать недели, а в другой я комичу в мастер раз 10 в день, по любому поводу и комиты с рефактором пушу постоянно. То что вы повторяете мантру о том, что комитить дорого, не делает её правдой. Правда в том что есть разные подходы и честно я пока для себя вообще не определился какой подход мне кажется более правильным и эффективным. Потому что оказалось оба имеют свои плюсы и минусы.

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

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

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

Говорящие имена переменных бесполезны

Не соглашусь. Да, в пункте два про "говорящие имена переменных" всё верно сказано. НО, "говорящее название переменной" позволяет легче ориентироваться по коду. Когда ты анализируешь алгоритм куда удобнее иметь переменную с именем rotor_drag, нежели rd или d. Эту переменную легче запомнить, её легче найти при чтении алгоритма и проще связать её с функционалом алгоритма.

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

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

Никто не спорит, что в математических расчетах разумно использовать названия переменных принятые в конкретной формуле.

E = mc^2

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

Кстати, в программировании mc^2, это mc*mc, что не верно)

UFO just landed and posted this here

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

Не надо думать о тех, кому придется читать ваш код

Пишите так, чтобы ваш код больше не нужно было читать

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

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

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

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

Если в ваш код не лезут, включая вас - значит он никому не нужен и никто его не использует.

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

Это никак не отменяет того факта, что его читаете вы.

Ну читаю, и что?
Я могу о себе думать или не думать - какое это имеет значение?

Значение оно имеет вот какое: в своём коде по прошествии весьма незначительного времени разбираться приходится примерно так же с нуля, как и в чужом

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

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

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

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

Остальное — документирую

А все остальные тоже документируют?

Вы пытаетесь игнорировать природные закономерности, а они мстительные, не любят, когда их игнорируют. Закономерности вот какие:

  • ненадёжность памяти обусловлена Природой, поэтому "мне помнится, что..." и "на самом деле" - разные вещи;

  • полное соответствие кода и рукописной документации недостижимо даже теоретически в то время, как код, по-видимому, соответствует сам себе;

  • комментарии - тоже документация;

  • с учётом вышесказанного, изучая код, можно быть твёрдо уверенным, что изучаешь действующую логику работы программы, а изучая доки и комменты, в этом уверенным быть нельзя:

  • нет никаких способов получить программу, "работающую правильно", поскольку для того, чтобы убедиться, что ошибки никогда не возникают, надо провести бесконечное число тестов в бесконечном количестве ситуаций;

  • раз нельзя быть уверенным в полной надёжности программы, то следует быть готовым к тому, что любая программа со временем будет нуждаться в доработках;

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

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

Ну, кстати, это не совсем правда.


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


Во-вторых, есть формальная верификация. Верифицированная программа работает верно с точностью до багов в верификаторе и в спеке.


И это даже практичный инструмент.

К сожалению, не совсем так. Даже самая простая прога исполняется в суперсложной среде

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

Поэтому на некоторых наборах входных данных на выходе будут нежданчики, называются уязвимостями и поиск их крайне сложен

Грубо говоря, f(1)=1; f(2)=2, но f(2)=2; f(1)=17

Одна и та же функция на один и тот же аргумент выдаёт разные результаты. Конкретные примеры сбоев вычислений можно увидеть, скажем, на SecurityLab

Итак, в тестах надо проверять не только все элементы доменов, но и все возможные последовательности и сочетания, то есть, ни о каком полном покрытии не может быть и речи

Всё это, заметьте, даже при допущении, что аппаратные сбои исключены, и байтики при пересылке не искажаются

UFO just landed and posted this here

Пишите так, чтобы ваш код больше не нужно было читать

Я не знаю, в каких проектах работал автор, но в моей карьере код обычно читают не из-за ошибок, а из-за новых требований к функционалу. В общем, автор прав в 5-7% утверждений и не прав во всем остальном.

Я был приятно удивлен, когда получил warning на передачу в функцию параметров с названиями включающими в себя Speed и Height, когда в обьявлении функции они стояли в обратном порядке: Height и Speed. У меня отложилось в памяти, что сработало именно по части названий переменных.

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

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

myfunc(Speed=speed, Height=height)

myfunc(Height=height, Speed=speed)

Размер кода немножко возрастает, но за это получаем аж три бонуса:

  • можно передавать переменные в любом порядке, в каком они вспомнились;

  • труднее ошибиться и передать не те параметры;

  • при чтении кода понятнее, что делает вызов, даже если переменные названы не особо интуитивно

В Питоне это даже внесли в синтсксис языка. Можно сделать такую сигнатуру функции, когда вызов будет только в таком виде.

def myfunc(*, height, speed):
    print(f"{height=} {speed=}")

myfunc(height="speed", speed="height")
myfunc("speed", "height") # TypeError: myfunc() takes 0 positional arguments but 2 were given
myfunc(height="speed") # TypeError: myfunc() missing 1 required keyword-only argument: 'speed' 

Я какое-то время бодался с багом, почему у меня не проходит верификация на сервере - пароль не верный, и хоть убейся. Оказалось, что ситуация аналогична Вашей - подключение происходило через WinApi, а там в вызове функции стояло ..., string password, string user,... А я то передавал как обычно - user, password.... И какое-то время это у меня сожрало :)

для этого и придумали алгебраические типы

А причем здесь они, если я ссылаюсь на внешнюю функцию WinAPI? Там я ничего поменять не могу, тем более ошибка была непосредственно в адаптере к этой функции - вызов res = WinApi.Function(..., user, password, ...) вместо правильного res = WinApi.Function(..., password, user, ...). Типы у имени пользователя и пароля одинаковые - LPWSTR (маршалинг через string). Ошибиться не просто, а очень просто.

Во время чтения думал, что не заметил плашку "Перевод", но её нет. Круто, автор, пишите побольше.

PS В целом оно все так и есть, можно добиться и достаточной выразительности и в то же время компактности и быстродействия кода, если не ударяться в крайности. Где нужно использовать правила, а где-то их не соблюдать. Если слепо следовать руководствам, то какая может быть "выразительность"? Выражение чего? В идеале - замысла программиста, что он не трафаретил, а понимал конкретную ситуацию в целом и в деталях.

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

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

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

По-моему автор довольно хорошо описал собственную точку зрения, как минимум она не мешает коду работать

Она мешает работать не коду автору, а тому, кто работает с ним или после него. Да и с такими принципами не удивлюсь, что и код нерабочий, зато неподдерживаемый. Упаси бог столкнуться с таким разработчиком в своей команде. Как вам такое увидеть на code review - https://habr.com/ru/articles/743114/#comment_25677686

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

Не особо следил за всеми ответами автора в комментариях, может он успел там и ревью какое-то пройти, там ответов много и не мне он отвечал. А вот статья понравилась, как уже писал, метод подачи, приведенные примеры, концепция. Да, конечно, не идеальна, как уже заметили в комментариях, но зато есть пища для размышлений.
Иногда полезно посмотреть с другой точки зрения. А потом отказаться от неё) Вот, например, возьмем некий проект, в него команда программистов пушила восемь лет каждый будний день. Кода там тьма, символов, наверное, как в небольшой библиотеке на полках. Текущий состав команды много читает и еще и добавляет в фонд. Но от общего количества это чтение ничтожно мало занимает, да и читать надо вдумчиво, это не детективы и приключения, а типа научная литература, алгоритмы.
Если бы мы составили статистику, из каких разделов чаще берутся "книги", а из каких вообще нет, смогли бы оптимизировать дальнейшее использование "библиотеки"? Ведь там где читают, это уже возвращаясь к коду, там скорее всего и изменения не за горами.
Не помню уже где конкретно, но Р. Мартин рассматривал построение архитектуры от изменений, то есть разбитие на часто изменяемые модули и редко затрагиваемые. Вот есть часто читаемые и редко читаемые части. Если это скрестить с тем, что придумывать говорящие имена программисту сложно и сколько-нибудь затратно, он может подзабить в этом смысле на малочитаемые части проекта, увеличив немного свою продуктивность. Это сказка, конечно, на код-ревью попросят уточнить (и будут читать), но в каких-то случаях может пригодиться (если все сеньоры и сеньориты и его не делают, например).
Сомневаюсь, что автор статьи везде придерживается описанных им рекомендаций, заказчики разные бывают, может даже накипело после очередного, да и сам тоже пойду соблюдать определенный code style)

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

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

Ложное противопоставление. Если человек не может писать корректный, быстрый код, который был бы читабельным, то он некомпетентен

Говорящие имена переменных бесполезны
Не надо думать о тех, кому придется читать ваш код
Пишите так, чтобы ваш код больше не нужно было читать

Вредная чепуха

Писать надо просто

Казалось бы норм, но дальше идёт снова чепуха - не пользоваться исключениями, auto, constexpr, шаблонами.

Ложное противопоставление. Если человек не может писать корректный, быстрый код, который был бы читабельным, то он некомпетентен

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

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

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

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

Автор признаётся, что не понимает что означает читабельность и выразительность, и делает замечательный вывод, что это не нужно. Ну ok, я вот, например, квантовую механику не понимаю.

Читабельность - это не технический аспект программирования

Программирование, на мой взгляд, это во многом социальная активность. Читаемость и выразительность это сюда. Бог с ним, можно не понимать это, но давать явно антисоциальную установку уже чересчур: "Не надо думать о тех, кому придется читать ваш код". Подход, простительный для олимпиадного программирования и утилит на выброс, но странный для промышленной разработки. Code review - в топку? будущую поддержку - туда же?

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

Возможно, вы задавали автору не те вопросы. Мне вот сложно ответить вам, вы привели цитату, а в ней нет ничего про социальный аспект программирования, вопрос про код-ревью - тоже писал, что он воспрепятствует плохо оформленному коду и тд. Спросите автора статьи напрямую. Почему он грубит людям, которых вы уважаете? Почему человек 20 лет занимался программированием, а в школе пропустил урок, где проходили слова "читабельность" и "выразительность"? Мне это неизвестно.

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

Почему же, имеет право на жизнь. Встречал в форме "пишите модульно, не больше человеконедели на модуль. понадобиться изменить через год — выкиньте модуль и напишите по новым требованиям. Это быстрее проще и дешевле, чем разобраться, отрефакторить чтобы после доработки не вырос техдолг и выполнить доработку"

Интересно, не везде взлетит, но почему бы и нет

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

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

В промышленной разработке эти два навыка как правило друг другу не мешают.

Как правило да, но в то же время есть много примеров где читаемость и скорость входят в противоречие. Точно также есть много место где не входят, и тогда удаётся написать и красиво и понятно и быстро, такие участки пролетают просто и без проблем. Но иногда это не так, два примера я писал в комменте ниже https://habr.com/ru/articles/743114/#comment_25676976 Существует сложные предметные области. И код, который их реализует будет сложным. И требовать от него ограничений на цикломатическую сложность или количество переменных или строк в методе бесполезно. Не надо прятать сложность за картонным фасадом его разрывания. И иногда попытка сделать "красивым" и "понятным" сложный код который всё равно никто, без знания предметной области, читать не будет, приводит к рождению чудовищ, к сожалению на памяти красивый пример не вертится, так что наглядно прямо сейчас показать не смогу.

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

Ну а иногда не приводит. Иногда носишь обувь - она тебе натирает. А другая не натирает. Никакую обувь теперь не носить что ли? Я думаю, на хабре не нужно пояснять разницу между частным и общим. Частные кейсы нужно разбирать в частном порядке. А общие утверждения "гони нечитаемый говнокод как будто последний день живешь" или "гони индусский код из 2005 года с абстрактными билдерами как будто железо ничего не стоит" - они одинаково бредовые и просто показывают недостаток скиллов или психологическую фиксацию на какой-то идее.

эмбедщина, мобильщина, реал-тайм и десктопные аппликации

я перестал тревожиться из-за читабельности

Заметно...

UFO just landed and posted this here

Вышел из эмбеда и комфорт от пользования auto и прочими std::vector убил любое желание возвращаться в то адище из самописных велосипедов. Эмбедерам было бы неплохо узнать про namespace + using для своих разработок и перстать нэймить переменные как будто сейчас 2004-ый. __чтоТо это немного РАК. Как и польская нотация в 2023 году. Пользуюсь Google Style Guide C++. В эмбеде кстати порой встречаются компиляторы которые умеют в C++17 минимум, что для меня стало откровением в то время.

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

Я целиком и полностью за вектор.
И против auto, потому что говно.

UFO just landed and posted this here

Нет, не случится.
Auto, в том виде, в каком оно существует и используется в С++ вызывает у меня недовольство.

UFO just landed and posted this here

Прекрасно.
А весь остальной С++ тоже его подмножество ХМ?

UFO just landed and posted this here

Никакие.
Не знаю зачем вы вообще упомянули про ХМ.
Что это добавило в дискуссию?
Если что, я имею очень поверхностное представление о ХМ, обусловленное университетским курсом миллион лет назад; так что грамотно дискутировать вряд ли смогу.

В эмбеде кстати порой встречаются компиляторы которые умеют в C++17 минимум

Я недавно обнаружил, что в Android IDE фичи последних C++ поддерживаются - и auto, и лямбды, и много чего ещё.

Лямбды были введены в C++11 (до этого грязные aka-lambda-C++03 хаки).

В C++14 добавили mutable, навешали всяких штук в список захвата для комфорта

А C++17 с авто в параметрах, боже какой сок.

const auto search_array = [&what](const auto& container){ ... };

И прям по кайфу, боже как мы жили то без этого.

Жду когда в языке разрешат так делать с простыми функциями и у нас будет typescipt... :D.

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

UFO just landed and posted this here

Автор статьи не дислексик ли случаем? Встретил несколько узнаваемых паттернов…

Говорящие имена переменных бесполезны, потому что длинные наборы слитых вместе слов ну просто никак не способствуют пониманию. Лично меня это упражнение по спортивному чтению утомляет и запутывает.

Вот, например, мы видим такое выражение:

double rotor_drag=1; Имя говорящее? Да. Но что именно оно нам говорит? Что здесь означает слово “rotor”? Что здесь означает слово “drag”? Что означает их сочетание в этом месте? Почему эти слова идут именно в таком порядке?

Говорящие имена переменных это rotor, wheel, car, power, stamina, angle вместо i1, i2, i32, i22, i98, i45.
Их цель - уменьшить когнитивную нагрузку (проще понять к чему относится переменная car чем переменная i22), количество описок и опечаток (случайно перепутать wheel с car сложнее чем i32 с i22) и упростить использование хинтов в ИДЕ (когда у Вас всплывает выбор из первого списка в подсказке, то выбрать проще чем из второго).
У говорящих переменных нет цели рассказать всю архитектуру приложения, что бы было понятно как такое имя получилось и у них нет цели помочь сформировать документацию по приложению.
В общем случае не важно что говорит drag, rotor и почему оно в таком порядке. Главное что Вы не перепутаете это с c12 и легко отличите от grinder_gears в контексте.

Говорящие имена переменных это rotor, wheel, car, power, stamina, angle вместо i1, i2, i32, i22, i98, i45

А бывает, что вместо rotor, wheel, car, power, stamina, angle идут r, w, c, p, s, a. И ищи-свищи их поиском по всем модулям..

Годный поинт кстати - если надо поразбираться в чужом коде без внятной IDE (а много ли их под C++ внятных-то) - то искать только полнотекстовым поиском. А тогда длинные названия очень и очень помогут.

VSCode очень хорошо работает за счет своего С++ экстеншена и не лагает в процессе. Но это только для jump-ов так. Можно доставить билд систему, что-бы оно там как-то доставало подсветку ошибок -- тогда превращается в лагодром уровня CLion.

Я бы не сказал, что есть хоть какая-то обоснованная причина не использовать VSCode для С++ проектов, ну только если у вас глубокий опыт для работы через менюшки Visual Studio и вас устраивает инпут лаг (возможно это моя личная проблема).

CLion - хорош, но тормознутый.

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

Попробую дать VSCode ещё один шанс, пару-тройку лет назад пробовал, но он ломался на конструкциях вида "унаследоваться от реализации шаблона".

CLion - увы, платное.

Visual Studio как по мне - отлично, пока не начинаешь под Linux писать (а вот тут оно ломалось на Linux-овых хедерах, может конечно поправили уже).

QtCreator ВНЕЗАПНО весьма неплох (даже без Qt).

Я лично не понимаю смысл слова "выразительность" для этого контекста.

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

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

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

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

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

Метрика называется cognitive complexity. Входит в SonarLint. На Ютубе есть авторское видео.

Меня, если честно, тоже заколебали архитектурные космонавты, которые наворачивают архитектуру, интерфейсы интерфейсов и MVVM толстым слоем, чтобы сверху подключить DI поизощреннее.

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

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

К сожалению то, что называют "средствами для улучшения читаемости" - это обычно какой то паттерн не к месту, добавляющий еще пару плохо структурированных слоев.

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

UFO just landed and posted this here

С чего вдруг после 20 лет программирования читабельность противопоставляется эффективности?

Неэффективное говно всегда можно сделать еще и нечитабельным, это вообще никак не связанные вещи

Количество байт в исходнике мерять? Интересный пример. И зарплату по размеру диффов вычислять

Приводить в качестве примеров исходники stl - классный трюк. Язык с 40-летней историей и коммитетом на 100 человек. Он так реализован, потому что у них еще 200 страниц документации, где написано что так необходимо реализоввывать.

Брр, какие мерзкие советы.

Справедливости ради, рекомендацию про длинные имена переменных можно переформулировать и эффективно использовать.
Во первых, действительно имя проясняется контекстом, и имеет смысл делать не Client.ClientTelephonNumber, но Client.TelephonNumber
А во вторых, если есть сложная переменная - нужно насторожиться, действительно ли тут удачная декомпозиция, может стоит причесать этот код?
Но иногда конечно стоит прямо так и писать ISelectableItemsFilterProvider, будет лучше, чем х

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

Насчет понимания что такое "выразительность кода" - вот пример (из "Programmer's Stone")

А что такое "инкапсуляция валюты" в тексте по ссылке?

Огрехи перевода. По контексту речь об определениях типов через define и typedef.

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

Код — это текстовое представление программы.

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

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

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

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

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

Получается вы одинаково хорошо можете читать обфусцированный и необфусцированный код?

Имя говорящее? Да. Но что именно оно нам говорит?

Что здесь означает слово “rotor”?

Что здесь означает слово “drag”?

Почему-то сразу вспомнился фильм "Глубже" =)

Подскажите насчёт переменных, пожалуйста.

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

А в компьютерном программировании это не так?

UFO just landed and posted this here

Верный заголовок статьи - Григорий Остер, Вредные советы

Не надо думать о тех, кому придется читать ваш код

Это же насколько нужно не любить будущего себя.

"Пусть с этим разбирается тот я, который до этого доживёт" (С)

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

UFO just landed and posted this here

Примером кода из стандартной библиотеки автор опровергает собственные слова про говорящие имена переменных и даже не замечает этого.

Ну замените __alloc_traits::construct на какое-нибудь неговорящее at::crt. Что, неужели не стало менее понятно? Не повлияла читаемость на понимание?

Нет.
Я как не понимал, что там происходит, так и не понимаю.
Для понимания мне придется вникать и тратить время.
Но открою секрет - я этот код вообще не читаю, я им просто пользуюсь.
А как им корректно пользоваться, я узнал из документации!

Выразителен? Читабелен?

А как иначе написать преобразование UTF-8 в двадцать строк? Этому коду больше десятка лет, работает как часы, и комментарии в заголовках там есть, кстати.)

Мои товарищи сишники также говорили, очень знакомая философия, я от них ушел в плюсы, а потом и того хуже в котлин.

У меня есть два великолепных примера в поддержку идей автора.

Одну я писал постом, если кратко то форсирование требования расстановки скобочек линтером привело к ошибке при портировании: https://habr.com/ru/articles/440414/,

Вторую комментом, если кратко то в языке typescript есть файл на 2.7 мегабайта кода содержащий 3.5 тысячи функций и огромный общий стейт, и его нельзя распилить, потому что упадёт производительность. https://habr.com/ru/companies/gazprombank/articles/742618/comments/#comment_25669414

И расскажу немного из истории, лет эдак 10 назад у нас были жесточайшие гайдлайны, где ставить дополнительный перенос строк, как форматировать, и случилось такое, что мы с коллегой одновременно взяли в работу одну и ту же задачу, да, мы не отметили вовремя in progress, но дело не в этом. Решением задачи являлось добавление цикла в одну из функций, и проверка содержащихся в списке значений по критерию. Я написал этот код и сделал svn up (да, мы тогда на svn сидели), пытаюсь сделать svn ci, а он мне говорит что nothing to commit. Наш код совпал до символа. Это было строк 8 с парой идентично названных переменных. Тогда у нас витали идеи, что весь код должен быть однообразен, что стиль кодирования конкретного разработчика не должно быть видно по результату его работы. И мы достигли этого. И я не смог ни измерить, ни увидеть, что же улучшилось. Наш проект был весь из себя по гайдлайнам, рядом был более старый проект во многом написанный на коленке, было очень много претензий к этому коду. Потом через 5 лет, когда написанный по гайдлайнам проект проиграл конкуренцию и был закрыт, я оказался на старом проекте. Но я стал мудрее и не хейтил этот код. Его можно прочитать? Да. Он написано в разных стилях? Да. Сейчас ему 13 лет и он всё ещё гененрирует прибыль. Это игра, за эти 13 лет она пережила две смены графдвижка, при этом вся логика осталось такой какой она была, много было дописано, много переписано. А то, что код может пережить смену графдвижка говорит о том что там действительно была заложена необходимая гибкость и она была применена, на самом деле а не гипотетически. Если хотеть хейтить этот код, он даёт миллион поводов. Если хотеть этот код развивать, он даёт миллион возможностей.

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

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

Вы уж извините, но оба примера у вас… Неубедительные.


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


fn f(a: u32, b: u32, c: u32) -> u32 {
    a << b + c
}

clippy не только выдаёт предупреждение, но и показывает, как можно исправить код:


warning: operator precedence can trip the unwary
 --> src/lib.rs:2:5
  |
2 |     a << b + c
  |     ^^^^^^^^^^ help: consider parenthesizing your expression: `a << (b + c)`
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#precedence
  = note: `#[warn(clippy::precedence)]` on by default

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


Второй пример ещё более выпуклый: Typescript является, в сущности, продвинутым препроцессором для JavaScript, а JavaScript — это антиоптимизируемый язык. Тот факт, что на JavaScript в принципе можно писать хоть сколько-то производительный код — это заслуга инженерных команд, разрабатывающих V8/SpiderMonkey. Даже с ними, как вы писали,


Это давно измерено и известно, в JS обращение к замкнутой переменной быстрее чем к свойству объекта

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


И если вы считаете, что я преувеличиваю насчёт тормозов JavaScript, то вам пример из VS Code (разрабатываемый в том же Microsoft, между прочим). В CI для тестов требуется транспилировать исходники на Typescript в JavaScript. Раньше для этой цели использовался тайпчекер Typescript, и занимало это всё порядка 5 минут. Это время удалось снизить за счёт отказа от, собственно, проверки типов (в контексте запуска тестов для CI это приемлемо), но даже так транспиляция всех исходников занимала порядка 2 минут. Однако после переключения на SWC время на транспиляцию снизилось до 12 секунд. Одна и та же задача — разница в производительности на порядок.


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

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

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

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

Не помню, в каком именно видео это было - Антон Полухин приводил пример, когда можно при обходе всех элементов std::map в цикле for(auto& val : map) вместо auto написать явно тип элемента, в котором забыть написать слово const. И получить копирование каждого элемента в цикле, даже несмотря на то, что написано &

Можно.
Но в том же цикле важно, например, знать с какой именно коллекцией вы имеете дело: с map или с вектором. Разница будет в наличии/отсутствии поля .second. И вообще важно знать, какие у переменной есть поля, методы. Просто для того чтобы ими пользоваться.

UFO just landed and posted this here

Ну вот по факту не каждая.
Некоторые (не я) могут и в виме писать, или в notpad++ или kwrite или бог знает что еще.

UFO just landed and posted this here

Профессионал отличается еще и тем, что умеет играть на том инструменте, который дают.

UFO just landed and posted this here

Зачем себя загонять в рамки чего-то, если можно этого не делать?

Профессионал отличается еще и тем, что умеет играть на том инструменте, который дают.

Вот тебе лопата, а теперь сыграй на ней Моцарта.

UFO just landed and posted this here

Уже ответили про современные IDE, которые все подсказывают. Но и даже без них - кто мешает переменную назвать так, чтобы было понятно, что это map?

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

Вы и еще кое-кто упорно рассказываете мне как я должен изменить свою жизнь

Хм, а это разве не вы хотите что-то рассказать всем своей статьёй? :)

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

А если по делу - никто не спорит с тем, что иногда от auto можно поиметь геморрой. Но плюсы применения auto, на мой взгляд, перевешивают минусы, которых гораздо меньше. Главный плюс - экономия времени при написании программы. Ну правда, неужели вместо auto it = v.begin() удобнее каждый раз писать полную расшифровку вроде std::vector<...>::iterator... ?

Этак можно договориться до того, что во всем комитете по развитию C++ сидят одни... странные люди, которые не понимают, что делают и зачем.

"Сегодня он играет джаз, а завтра родину продаст"
знаете, а что если предположить, что в комитете сегодня есть довольно много ...эээ... идиотов? Ну или бывших питонистов.
Может это смелое предположение не так уж нелепо?

Ну правда, неужели вместо auto it = v.begin() удобнее каждый раз писать полную расшифровку вроде std::vector<...>::iterator... ?

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

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

Какая-то у вас дикая нелюбовь к питонистам…
Но ведь наверняка Python так популярен не только из-за низкого порога вхождения. Хотя, порог вхождения и может быть важен.

А разве венгерскую нотацию не похоронили с приходом хороших IDE?
Кажется вполне логичным, что какой нибудь ItemList будет иметь тип массив, а не список, нет? Название же должно идти по бизнес сути и не про нутрянку.

А ещё можно использовать внутри такого цикла структурное связывание, и обращаться к полям элемента не через .second, а по осмысленному названию.

Имя говорящее? Да. Но что именно оно нам говорит?

Ну так если даже из "контекста" функции и комментариев непонятно что оно нам говорит, то это имя переменной как раз таки не говорящее.


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

А кто говорит что надо запихать вот прямо всю эту информацию и именно в название переменной?


Можно написать “rd”, и толку будет не меньше.

Не уверен. Особенно если у вас будет куча переменных а ля "rd", "dr", "cf", "rd1", "x", "y", "z" и так далее.


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

Вы же в курсе что у жаваскрипта не компилятор, а интерпретатор? И именно поэтому у жаваскрипта размер исходников играет роль. В отличие от компилируемых языков.

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

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

Какое отношение это имеет к компилятору?


Кроме того а зачем вы так делаете? Мне очень сложно представить сценарий когда этого невозможно избежать и/или это действительно создаёт реальные проблемы.


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

К комментариям в коде это точно так же применимо. Теперь комментарии писать не будем?


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

Какое отношение это имеет к компилятору?

Такое же как и в жс: время компиляции и в конце концов деньги.

Кроме того а зачем вы так делаете? 

Так оно устроено там где я работаю. Примите это как данность.

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

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

UFO just landed and posted this here

Нет, я ВСЕГДА пишу для процессоров.
Вот когда программы будут выполнять люди, тогда я буду писать так, чтоб не оскорбить их тонкие вкусы.
А до тех пор я пишу для процессоров!

Такое же как и в жс: время компиляции и в конце концов деньги.

Во первых в js причина в первую очередь не во "времени компиляции", а в размерах скриптов, которые потом надо будет качать пользователям.


А во вторых во сколько у вас увеличивается время компиляции вашего проекта если названия всех переменных увеличить скажем в десять раз? И сколько денег вы на этом теряете?


Так оно устроено там где я работаю. Примите это как данность.

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


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


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

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


И код мы пишем не для людей, а для процессоров.

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


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

А кто и где этого требует? Кто утверждает что комментарии вообще не нужны? Или что документация вообще не нужна?

Во первых в js причина в первую очередь не во "времени компиляции", а в размерах скриптов, которые потом надо будет качать пользователям.

Вы крутитесь вокруг того что я написал.

И сколько денег вы на этом теряете?

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

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

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

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

Это только ваше мнение.

А кто и где этого требует?

Да есть такие пуристы

Вы крутитесь вокруг того что я написал.

Это вы пишите непонятно что.


Я могу передать ваш вопрос руководству компании. Они обязательно ответят.

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


Я еще в начале 2000х успешно запускал компиляцию на UNIX-серверах

А я ещё в 90-х писал код ручкой на бумажке, потом отдавал тётенькам и они его уже набирали на компе. Но это не значит что сейчас всё ещё надо так делать.


Это только ваше мнение.

И почему оно хуже чем ваше?


Да есть такие пуристы

Где? И почему из-за каких-то странных "пуристов" вы теперь делаете вывод что нормальное наименование переменных в принципе не нужно?

Но это не значит что сейчас всё ещё надо так делать.

Факт остается фактом: сегодня все еще существует распределенная компиляция, отлаженные производственные процессы, и они будут существовать еще очень долго; и все более-менее крупные организации будут работать именно так, нравится вам это или нет.

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

Угу. И это всё великолепно работает с нормальными именами переменных и комментариями. По крайней мере у нас это работает. Так что само по себе это не аргумент.


и они будут существовать еще очень долго

Ну так и код без комментариев существует и будет существовать ещё долго.


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

На мой взгляд все более-менее крупные организации как раз таки имеют нормальные styleguides. Нравится вам это или нет.

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

Там нигде ничего не написано про читабельность и выразительность.

Ну давайте возьмём тот же гугл


+

The most important consistency rules are those that govern naming. The style of a name immediately informs us what sort of thing the named entity is: a type, a variable, a function, a constant, a macro, etc., without requiring us to search for the declaration of that entity. The pattern-matching engine in our brains relies a great deal on these naming rules.


Use names that describe the purpose or intent of the object. Do not worry about saving horizontal space as it is far more important to make your code immediately understandable by a new reader. Minimize the use of abbreviations that would likely be unknown to someone outside your project (especially acronyms and initialisms). Do not abbreviate by deleting letters within a word. As a rule of thumb, an abbreviation is probably OK if it's listed in Wikipedia. Generally speaking, descriptiveness should be proportional to the name's scope of visibility. For example, n may be a fine name within a 5-line function, but within the scope of a class, it's likely too vague.


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


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

Так а кто не рекомендует это делать? Или тем более запрещает? Кто эти "пуристы"? Можете дать линк на их стайлгайды?

И возможно это вам стоит у себя это прописать :)

Нет, не стоит.
И так хорошо.

Ну это хорошо что вам хорошо. Но вы же вроде бы хотите всех убедить что так надо делать? Или о чём была статья?

О том что читабельность с выразительностью (значительно) менее важны чем корректная работа и производительность программы.

А кто и где утверждал обратное? Вы решили с ветряными мельницами побороться?


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

Так а кто не рекомендует это делать? Или тем более запрещает?

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

То есть у вас в результате код коммитится без комментариев? Даже в тех местах где они действительно нужны?

Ха-ха-ха.
Вот видите.
"Когда научитесь плавать-нальем воду"

Во первых давайте подождём ответа. А во вторых ваша позиция от этого правильной не становится :)

Скорее: научитесь работать микроскопом - тогда выдадим молоток)

Но с поинтом оратора, что комментарии в коде это немного не ок - согласен.

Вообще у нас тут стандартизация подхода и дизайна и после того как долго поработал на проекте долгое время "сразу видишь" когда реализация отличается и ищешь причину. Тогда комментарий вида:

// Да, это сделано потому-что мы олени и не смогли в разделение сущностей

Очень упрощает быт

UFO just landed and posted this here

Так пока такое место встретится, пройдёт уже пол-года-год.

Так оно устроено там где я работаю. Примите это как данность.

Вы даете рекомендации для кого угодно, или для тех, кто загнан в какие-то специфические условия, вроде как у Вас на работе? Есть же способы не тянуть код по сети при каждой компиляции. Я понимаю, что у Вас так это устроено - а почему оно именно так? Кто-то один раз так настроил N лет назад, и перенастроить некому? Или руководитель проекта не знает, как можно сделать по-другому?

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

И процессы не меняются просто так, раз в неделю.
Это просто данность.

UFO just landed and posted this here

Кооперативная разработка ведётся через систему контроля версий вроде SVN или GitHub, например. Но зачем при каждой компиляции все исходники по сети гонять? Или у Вас какие-то библиотеки лежат на сетевом диске на сервере и компилируются прямо оттуда?

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

Они при этом исходники не на своем диске хранят, а где-то в стороне на другом сервере? Зачем?

UFO just landed and posted this here
компилятору абсолютно безразлично — красив ваш код, читабелен ли, выразителен ли.
Процессору это тоже безразлично.

Именно так. Рассмотрим два случая:
1) Код некрасив и нечитабелен. В данном случае процессору всё равно, а люди страдают.
2) Код красив и читабелен. В данном случае процессору всё равно, а людям хорошо.


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

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

Экономим на длине идентификаторов, чтобы cэкономить при передаче исходников по сети? Надеюсь, что это была шутка.

Речь про компилируемые языки C/C++

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

Вы сами то читали что там написано?


Minification is the process of minimizing code and markup in your web pages and script files. It’s one of the main methods used to reduce load times and bandwidth usage on websites.

Какое это имеет отношение к "тянете сорсы с другого компьютера при каждой компиляции"?

У JS есть минификаторы. И размер минифицированного кода практически не зависит ни от длины имён переменных в исходнике, ни от количества и размера комментариев.

UFO just landed and posted this here

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

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

И да, строгая типизация - это весьма важно.

UFO just landed and posted this here

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

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

Как и предполагалось, автора заминусили толпы "программистов", по 10 часов в день перерисовывающих перделки в броузере

UFO just landed and posted this here

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

Да ничего там не бьют. Я в таких всю жизнь работаю.

Кхе

image

Отстал от жизни, Хабр случайно не платит теперь за активность в посте? Выглядит как байт на комменты(=

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

Да и в целом, часто бывает, что тип переменной вот так просто и не выразить, как в случае с лямбдой. Есть std::function, но он про стирание типов, что не бесплатная операция.

Меня std::function вполне устраивает.
Если честно, то учитывая как в С++ реализованы лямбды (а также корутины) лучше ими пользоваться поменьше.
В Obj-C все намного проще и удобнее.

А что не так с лямбдами в C++? Под словом "реализовано" Вы имеете ввиду синтаксис языка или то, в какой код лямбды компилятор разворачивает? О чем речь?

Синтаксис.
Я сравниваю с Obj-C и там оно более удобно сделано.

Что именно неудобно в лямбдах C++?

Мне необходимо передавать ламбду как параметр функции.
Это можно сделать либо через std::function, либо возиться с шаблонами.
Шаблоны мне не подходят.
Остается std::function.
А потом еще указывать все переменные скопа.
Как-то слишком много бюрократии.

UFO just landed and posted this here

То Вам auto не нравится, то вдруг хочется, чтобы поменьше бюрократии и поменьше писать. Чем шаблоны не угодили? Вот они уж точно помогают не расписывать много чего вручную.

У шаблонов есть свои недостатки:
Время компиляции.
Их надо задавать в хедере.
совершенно нечитабельные сообщения об ошибках.
И еще кое-что.

У меня получается задавать шаблоны не только в хедере. Что я делаю не так?

Не знаю.
Попробуйте создать темплэйт класса, а имплементацию методов вынести в .cpp файл.
А потом попробуйте вызвать один из методов.

Псст, хотите немного уличной магии!

// main.cpp
template <typename T> void foo();

int main() {
    foo<int>();
}

// foo.cpp
template <typename T> void foo();

template<>
void foo<int>() {}
g++ main.cpp foo.cpp && ./a.out

Для сравнения:

// main.d
void main() {
  import foo;
  foo( 777 );
  foo( "xxx" );
}

// foo.d
void foo( Arg )( Arg arg ) {
  import std.stdio: writeln;
  writeln( arg );
}

В C++20 с модулями примерно также должно быть. Только когда ещё их поддержка дозреет до нужного уровня...

Ну да, std:: function всего лишь требует динамической памяти - это прямо такая мелочь, особенно, когда пишешь код не для userspace. Это такая мелочь в плане эффективности кода, что можно вообще не беспокоится.

Тем более, что код ядра что Linux, что Windows, люди уже успешно пишут на Rust, где нет никаких неожиданностей в плане отключения стандартной библиотеки, в отличие от.

Мне в одном месте пришлось вместо std::function использовать "старые добрые" указатели на функцию. После того, как профилировщик показал, насколько просаживается производительность при вызове через std::function. Да, такое бывает критично далеко не всегда, но тем не менее.

UFO just landed and posted this here
UFO just landed and posted this here

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

UFO just landed and posted this here

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

Но да, наброс знатный.

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

Вы очевидным образом даже не поняли что вы критикуете.

Да куда уж мне.

Расскажу вам по секрету: это экспериментальный пет-проект, который я пишу в своем темпе, по своему личному техзаданию.

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

И что мы там увидим? Да сразу увидим то, что автор посылает в пешее эротическое собственные же рекомендации.

Рекомендация писать комментарии была? Была:

Надо комментировать. Не надо стесняться комментариев. Компилятор их игнорирует, а лично вам они очень помогут.

Видно ли ее применение в вашем коде? Нет!

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

Мимо кассы.

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

Видно ли ее применение в вашем коде? Нет!

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

Тому кто не хочет видеть-не видно.

Ну покажите мне, что я здесь не вижу: тыц
Функция, в которой два фрагмента закомментированны. Почему, зачем, какой смысл их оставлять в коде, если они вымараны комментариями?

Когда человек пишет код нормально, то в таких местах он оставляет пояснение о том, почему так было сделано (еще лучше с маркерами TODO/FIXME) и почему куски не были выброшены полностью. Может нужно провести какие-то тесты, может это промежуточный workaround на какое-то время (на какое?), может просто не хватило времени доделать что-то и пришлось коммитить как есть и нужно вернуться позже.

Нормальные разработчики делают именно так.

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

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

Я произвожу нормальный работающий код

Работающий не значит нормальный.

я все делаю правильно, не нравится-не ешьте.

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

Так вот для тех, кто поведется на озвученные 20 лет опыта и пр. бла-бла-бла, предупреждение: товарищи, автор сам плюет на собственные же рекомендации. Так оно вам нужно?

Мои рекомендации верны.
Мой код правильный и нормальный.
Точка.

Прежде о себе: более 20 лет программирую на С/С++/Objective-C, в разной степени знаком с десятком других языков.

А если я пятьдесят лет программирую и знаю сто языков, но в корне не согласен с автором, факты из моей биографии хоть как-то повлияют на его точку зрения?
@tri_tuza_v_karmane Мы не оценивали ваш код, не знаем в каких командах и на каких проектах вы работали, не видели вас на конференциях, не знаем как вас и ваш труд оценивают ваши коллеги. Я поверю на слово - всё что вы пишите про свой опыт в цифрах, всё правда. Но, кажется, это как раз тот случай, когда "мудрость приходит с опытом, но иногда опыт приходит один". Вот такая печальная история, двадцать лет опыта не научили вас азам профессии, гордиться тут не чем.

мудрость приходит с опытом, но иногда опыт приходит один

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

в корне не согласен с автором

Есть две крайности - не заморачиваться читабельностью и чрезмерно заморачиваться читабельностью. Обе крайности плохи. Борясь с любой из вредных крайностей важно не удариться в противоположную. Рулит разумный баланс между крайностями.

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

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

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

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

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

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

Чужой код обязан бесить. Его писал другой человек, с другой логикой и 100% совместимости с вашей логикой никогда не будет. А т.к. ваше мышление постоянно немного меняется, то через некоторое время это немного превращается в много и ваш код становится для вас чужим.

Считаю что нужно стремится к уменьшению когнитивной нагрузки и избеганию ошибок. Названия должны быть легко отличимы друг от друга. Не должно быть похожих названий. Представьте что срочно БЫСТРО надо писать, а у вас похмелье и температура 38. Вы будете тупить и заранее нужно писать такой код чтобы в таком состоянии было проще. Ну естественно нужно разделять слова в названиях разным регистром. При этом в регистрозависимых языках строго следить за регистром. Выпорол бы всех кто придумал различать большие и маленькие буквы.

Также гугол стайл гайд (он кстати дефолтный в Я.Такси и соседних сервисах):

class DataTypesWrittenThisWay {

int class_members_written_this_way_;

};

models::CoolSeviceResponse GetServiceResponse();

auto response = GetServiceResponse();

const auto kConstsWrittenReallyDifferent = "Some magic"

При этом в регистрозависимых языках строго следить за регистром.

И проблема испарилась.

Надо просто стайлгайд нормальный брать, а не как дедушка в 97 писал.

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

Как же SOLID ещё никто не помянул то... А оно ведь работает. Просто не на уровне именования переменных и функций, а на уровне микроархитектуры приложения. Ну возможности распиливания монолита на микросервисы потом, да.
PS:

Говорящие имена переменных бесполезны

А что касается выразительности... Зависит от языка конечно, но вот в Java к примеру, не завезли перегрузку операторов и кое-какое наследование, через что адски неудобно делать типы. Т.е. классов с интерфейсами хоть залейся, а вот определить два несовместимых Double, один для градусов цельсия, второй для кельвинов - примерно никак. Ну или городить вычисления словами, а инициализацию через фабрику. А не, это из 2016. Теперь через билдер. Но если он будет порождаться фабрикой, так будет энтерпрайзней, всё равно в половине кода сделано так, а в половине, которая писалась при другом архитекторе, этак. И единственный способ поймать косяк на review - это таки да, говорящие имена. У нас на проекте, если имя локальной переменной не говорит, зачем она тут - MR тут же заворачивается на доработку. Плюс JavaDoc по стандартам, и дополнительно следим, чтобы там было написано ЗАЧЕМ этот параметр, а не что он есть. Иначе получается Сепулька сепулька; //ссылка на сепульку.

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

Есть области, где это не работает. Ну нет описания алгоритма, вот вообще. Есть БТ + Функциональные требования. Есть толковый разработчик, который с утра наливает кофе, открывает тикет, читает, матерится на аналитиков, которые это писали, открывает исходник и начинает соображать, в какое вообще место в коде (который писали три команды за последние семь лет) это можно присрать. И как. По дороге выясняется, что на двадцатой странице БТ написано про семь параллельных линий, на тридцать второй про то, как они должны пересекаться. Ещё через пол-года другой разработчик что-то там унаследует, чтобы одна из линий была в форме котёнка. А ещё через год - выяснится, что всё должно быть совсем не так, потому что Госдума. И очередной новый разработчик, после двух недель на "изучение существующего решения", таки осознает, что алгоритма - нет. То, что написано в ТЗ №1 - вообще не соответствует кодовой базе, потому что были доработки XX и XY, а постановка задачи на фикс с котёнком потонула в переписке двух эффективных менеджеров и РП. Ни один из которых в данный момент в конторе уже не работает. И единственный источник истины - код, потому как стоит в проде и функциональный заказчик почти не ругается. И вот тут говорящие имена переменных, выразительная структура классов и паттерны проектирования где надо, описания зачем так и ссылки на тикеты (хотя в Java сейчас хорошо - есть плагин для IDEA, который умеет показать это для каждой строки прямо в коде) - становятся ключевым фактором сроков выкатки фич. А это уже про чистые деньги.

Всегда работал в больших проектах больших компаний, на всех этапах, от демо до полевых испытаний

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

О, наконец-то бывалый пришел, все распедалил как есть.
Лови экстрасенса!

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

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

Ладно уже с опытом, 3й раз жевать смысла не вижу. А вам китайские иероглифы в именах переменных не приходилось видеть? А американский коллега в 10 вечера не спрашивал вас, как ему перевести слова «счетчик» или «запрос»?

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

void DoSomeLogic(IMessageBroker broker)
{
    broker.Publish(message)
}

сразу понятен, с первого взгляда, в отличии от

void X(Y a)
{
  a.B(c)
}

Во втором варианте мне надо будет потратить некоторое время чтобы понять что же тут происходит - подозреваю я не одинок.

А если кодовая база в десятки(если не сотни) млн LOC, писалось это все десятилетиями, разными вендорами со всего мира, и вот вам повезло получить такое наследство и как то с ним работать… то проблема с неймингом начинает играть совсем другими красками.

There are only two hard things in Computer Science: cache invalidation and naming things.

-- Phil Karlton

Чувак знал что говорил много лет назад.

Автор. Целую в десна. Сам больше 20 лет в разработке и пришел буквально к тем же самым выводам!

Просто хотел сказать спасибо за статью.

Говрокодеров большинство.. как и плохих специалистов в любой другой области. Значит ли это, что они правы?

Работал на таком проекте, где забили на читаемость, и рефакторинг был запрещён. Код там был беспросветный погибельный. Циклы на 500 строк, глобальные переменные и многое другое... Попадался даже оператор goto. И auto было запрещено, и не только. Программисты работали полгода и уходили. И руководитель - очень нервный тип - сетовал, почему так, что такое?!
Автор думает, что можно сразу написать хорошо работающий код, тогда как процесс чаще напоминает эволюцию. Не говоря уже о том, что программист может ошибиться.
Я такой вывод сделал, что если не стараешься писать понятный код, значит, не уважаешь коллег и не любишь свою профессию.

Мне по поводу запрета использования auto интересен момент. Допустим, есть что-то вроде auto it = v.begin(), где v - какой-то контейнер, и по принципиальным соображениям вместо auto расписан вручную тип итератора. Потом вдруг оказалось, что тип контейнера пришлось изменить, или добавить какие-то поля в его элементы. После чего сидим и в 500 местах в переписываем, что такое it? Глобальная автоматическая замена далеко не всегда безопасна - можно взять и что-то лишнее заменить.

Если рефакторинг запрещён, то существующий код объявляется священной коровой. Соответственно, все его недостатки, несовершенства и костыли также объявляются идеалом. В такой ситуации менять тип контейнера руководство не позволит.

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

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

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

Нет, не 4. Это auto состоит из 4 букв. Сэкономить можно гораздо больше.

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

А иожно ещё лучше: давайте вместо переменных и функций использовать их адреса в памяти. Что-то такое было, когда я начинал программировать. И форматирование со всеми отступами не было нужно. Просто пишешь и всё. Oh shi...

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

До сих пор встречается и даже является частью стайдгайда в отдельных немецких фирмах. И у французов кстати тоже встречал.

UFO just landed and posted this here

Французский я как раз знаю на таком уровне, что мне это даже понятно :-) Но здесь есть и исходник на английском, без него у меня случился бы когнитивный диссонанс в первый момент. Оператор NOP отдельно доставляет. А вот слова вместо фигурных скобок - это странновато.

Ну у вас хоть на немецком. У меня когда-то вообще на финском код был :)

Такое ощущение, что автору статьи НИКОГДА не приходилось залезать в свой код, написанный год назад. Мне - приходится регулярно, и читаемость в этом случае важна. У меня на работе есть код, которому больше 10 лет, и он развивается "импульсами".

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

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


А чего тут грустного?

По мне самоя большая грусть, что произоводительность обожествляют и под это творят всякую дичь. Особенно там где она не нужна, или там где она нужна, но её измеряют на глазок и оптимизируют где попало.

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

До таких приёмов как ручной инлайн и короткие имена, мне не приходилось опускаться.

Мой основной стек: Python, Java, Go, SQL

Короткие имена - тоже не встречал.
А вот например "вместо списка передавать в метод массив и 2 индекса в нём" и "использовать один раз выделенные массивы вместо создания List-ов" - такое очень даже было.
Unity/C# если что.

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

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

А когда пишется что-то фик пойми что, но очень (sic!) умно — это точно написал джун.

Как там у классиков было - "Программист на паскале может писать на паскале на любом языке" :) Не надо так. Не надо быть джуном со стажем :)

А в чем именно особенность Паскаля в ланном случае?

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

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

Тема большая и сложная - давайте разбираться :)

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

Программисты сопровождают написанный код. Каждый программист хочет легко понять код, даже если он его не писал, поэтому тимлид объявляет ряд правил для проекта - code style guide.

Люди понимают друг друга, когда говорят на одном языке. Программисты понимают друг друга, когда пишут на одном языке и в одном стиле. Музыканты собирают оркестр и играют симфонию, программисты собирают команду и работают над кодом.

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

Не можете договориться - наймите тимлида, а по стенам офиса расклейте басню Крылова "Лебедь, щука и рак".

Хотя, судя по написанному, тут уже ничем не поможешь.

Прекрасно понимаю автора статьи - рекомендаций, наставлений много, а в чем польза? 20 лет проб и ошибок, столько стилей опробовано, а толку? Книга А, книга Б, статьи, конференции, видеокурсы... Надоело.

Никогда не поздно учиться. Автор задает вопросы, делает выводы, ищет решение проблемы, делится опытом. Отчаиваться не стоит :)

Articles