Pull to refresh

Методология и руководство по стилю кода компании Ronimo

Reading time16 min
Views5.3K
Original author: Joost van Dongen
Я большой сторонний структурного подхода к работе. Программистам игр приходится создавать сложные системы и поэтому недостаточно просто плыть по течению. Я написал два документа о том, как мы в Ronimo пишем код, которые должен изучить в первый день работы каждый программист и стажёр. Наш документ по методологии объясняет рабочий процесс, а руководство по стилю рассказывает о системе нашего кода. Для начала я хочу раскрыть методологию и рассказать о причинах, стоящих за представленными в документе правилами.


В нашей двухмерной MOBA Awesomenauts на текущий момент две тысячи классов и больше 400 тысяч строк кода. Чтобы такая объёмная кодовая база не превратилась в хаос, необходим структурный подход.

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

Давайте начнём с изучения самого документа о методологии:

Методология кода Ronimo


Стандартный способ реализации новой функции:


  1. Проанализируйте то, что нужно сделать. Обсудите подход с конечными пользователями (обычно это художники и/или дизайнеры) и с ведущим разработчиком.
  2. Разделите работу на мелкие задачи, которые можно решить максимум за день.
  3. Создайте простой план для мелких задач. Реализацию ядра функционала и самых сложных частей поставьте в начало плана.
  4. Реализуйте каждую из мелких задач.
  5. Оцените результат с конечными пользователями и ведущим разработчиком.
  6. Объясните конечным пользователям, что делает новая функция, чтобы её на самом деле использовали.

Реализация мелкой задачи:


  1. Проанализируйте то, что нужно сделать.
  2. Убедитесь, что в уже имеющемся коде нет ошибок (выполните тесты!).
  3. Изучите и поэкспериментируйте со всеми новыми технологиями, необходимыми для этой функции.
  4. Создайте дизайн кода новой функции. Не слишком акцентируйте внимание на теоретическом использовании в будущем, но имейте его в виду.
  5. Выполниет рефакторинг имеющегося кода, чтобы создать пространство для новой функции.
  6. Выполните тесты, чтобы убедиться, что старые функции по-прежнему работают.
  7. Реализуйте новую функцию.
  8. Протестируйте работу новой функции.
  9. Закончите код: добавьте комменты, подчистите код и проверьте деструкторы.
  10. Проверьте тестами, что новая функция по-прежнему работает.
  11. Протестируйте работу старых функций.
  12. Проанализируйте результат. Если возможно, покажите промежуточный результат конечному пользователю.

Другие правила:


  • Храните личный список всех небольших задач, которые нужно сделать. При возникновении проблемы, которую нельзя решить сразу же, или когда вас просят добавить функцию, которую вы обещаете добавить позже, запишите её в список. Не думайте, что сможете запомнить всё.
  • Не продолжайте работу над задачей, если возник сбой или серьёзная ошибка. Всегда сначала исправляйте сбой.
  • «Преждевременная оптимизация — корень всех зол» (Дональд Кнут). Сначала реализуйте новую функцию самым простым или чистым из возможных способом, проанализируйте, работает ли она, затем проанализируйте скорость выполнения, и только при необходимости вносите оптимизации.
  • Не очень беспокойтесь о том, чтобы в код удобно было добавлять неизвестные будущие расширения. При необходимости новой функции код можно рефакторизировать. Разумеется, если для этого не нужно много труда, то делайте всё как можно более общим.

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

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

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


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

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

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

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

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

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

Руководство по стилю кода


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


За несколько лет в кодовую базу Awesomenauts внесли свой вклад 18 программистов (включая стажёров). Благодаря строгим правилам оформления весь код читается одинаково.

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

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

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

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


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

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

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


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

Один из самых горячо обсуждаемых пунктов в стиле написания кода — нужно ли помечать переменные элементов класса. Если у класса Car есть float speed, нужно ли называть её speed, mSpeed, _speed или как-то иначе? Я решил назвать её просто speed. Здесь я снова придерживаюсь того, что код должен как можно больше походить на англоязычный текст. Чем больше префиксов и символов подчёркивания, тем дальше мы уходим от естественного языка и тем сложнее просто читать код и понимать его.

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

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

Мы обсудили причины решений, выбранных в руководстве по стилю кода, давайте же наконец посмотрим, как выглядит оно само!

Руководство по стилю кода Ronimo


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

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

C++


  • Весь код и комментарии пишутся на британском английском. (Не на американском английском.) Правильно: colour, centre, initialiser. Неправильно: color, center, initializer.
  • За каждой запятой следует пробел, например: doStuff(5, 7, 8)
  • Операторы отделяются пробелами, например: 5 + 7 вместо 5+7
  • Табы имеют длину в четыре пробела. Табы хранятся как табы, а не как пробелы.
  • Функции и статичные переменные указываются в одинаковом порядке в файлах .h и .cpp.
  • Используйте #pragma once вместо #include guard (мы перешли к этому недавно, поэтому в нашем коде вы увидите много старых #include guard).
  • Старайтесь писать короткие функции, желательно не длиннее 50 строк.
  • Избегайте создания слишком больших классов. Если вы ожидаете, что класс сильно разрастётся и его можно логично разделить, то разделите его. Стремитесь к тому, чтобы стандартный размер класса не превышал 750 строк. Однако не стоит разделять класс, если код станет менее читаемым. Вот примеры нечитаемых разделений: слишком тесно связанные классы, классы friend и сложные иерархии классов.
  • Не пишите длинные строки, которые не поместятся на стандартном экране 1920*1080 (не забывайте, что на этом экране есть и окно Solution Explorer).
  • При разбиении длинной строки на несколько строк убедитесь, что отступы соответствуют скобкам. Например, вот так:

    myReallyLongFunctionName(Vector2(bananaXPos + xOffset,
                                     bananaYPos * multiplier),
                             explodingKiwi);
  • По возможности пользуйтесь предварительным объявлением: в файлах заголовков должно быть как можно меньше include. Например, используйте class Bert; и переместите #include "Bert.h" в файл .cpp.
  • Include и предварительные объявления должны иметь следующий порядок:
    • Начните со всех предварительных объявлений из вашего собственного кода (в алфавитном порядке)
    • Затем все include из вашего собственного кода (в алфавитном порядке)
    • Пустая строка
    • Затем для каждой библиотеки:
      • Предварительные объявления из этой библиотеки (в алфавитном порядке)
      • Все include из этой библиотеки (в алфавитном порядке)
  • include файла .h, принадлежащий к файлу .cpp, всегда находится вверху.
  • Не определяйте переменные static в функции. Используйте переменные элементов класса (возможно, статичные).
  • Всё должно быть корректно с точки зрения const.
  • Названия переменных и функций должны быть описательными. Можно без проблем использовать длинные названия, нельзя использовать невнятные названия. Используйте аббревиатуры, только если они очень понятны и стандартны.
  • Первая буква названий классов, типов struct и enum — заглавная. Переменные и функции начинаются с прописной. Каждое следующее слово в названии начинается с заглавной буквы. Не используйте в названиях переменных символы подчёркивания ( _ ). Вот пример:

    class MyClass
    {
        void someFunction();
        int someVariable;
    };
  • Переменные элементов никак не помечаются, ни буквой m перед названием, ни _ после. Функции должны быть достаточно короткими, чтобы можно было отслеживать то, что объявлено в функции, а что — в классе. Не помечайте переменные элементов this->.
  • Реализации функций никогда не должны находиться в файлах .h.
  • Шаблонные функции, которые невозможно реализовать в файле .cpp, реализуются в дополнительном файле заголовка, который подключается из основного файла заголовка. Такой класс может иметь три файла: MyClass.h, MyClassImplementation.h и MyClass.cpp. Например:

    class MyClass
    {
        template <typename T>
        void doStuff(T thingy);
    };
    
    #include "MyClassImplementation.h"
  • Начинайте названия типов шаблонов с буквы T. Если нужно больше информации, то после неё можно добавить слова, например TString.
  • Нельзя объявлять несколько классов в одном файле заголовка. Исключение: файл является частью другого класса (например, объявлен внутри другого класса).
  • Между функциями должны быть две пустые строки (в файле .cpp).
  • Используйте пустые строки для структурирования и группировки кода ради читаемости.
  • Сопровождайте код подробными комментариями.
  • Над каждым классом приводите короткое описание работы класса. В особенности стоит описывать взаимосвязи (например «Этот класс помогает классу X, выполняя за него Y»).
  • Фигурные скобки { и } всегда занимают отдельную строку, то есть их нельзя помещать в одну строку с if или for. Также их никогда нельзя пропускать их. Единственное исключение: несколько похожих однострочных конструкций if, идущих одна под другой. В этом случае допускается поставить их в одной строке. Как в этом примере:

    if      ( banana &&  kiwi && length > 5) return cow;
    else if ( banana && !kiwi && length > 9) return pig;
    else if (!banana && !kiwi && length < 7) return duck;
    else                                     return dragon;
  • При написании функции do-while while должно стоять в одной строке с закрывающей скобкой:

    do
    {
        blabla;
    } while (bleble);
  • Отступы в конструкциях switch следует расставлять следующим образом:

    switch (giraffeCount)
    {
        case 1: text = "one giraffe";  break;
        case 2: text = "two giraffes"; break;
        case 3:
            // Если строк кода несколько
            doStuffOnSeveralLines;
            text = "three giraffes";
            break;
        case 4:
        {
            // Для читаемости можно добавить фигурные скобки
            int x = getComplexThing();
            text = "quadruple giraffe";
            break;
        }
    }
  • Параметры функций должны иметь одинаковые названия в файлах .h и .cpp.
  • Если параметр функции и переменная элемента класса имеют одинаковое название, то нужно или придумать другое название, или добавить _ в конце параметра функции. Например вот так:

    void setHealth(float health_)
    {
        health = health_;
    }
  • Количество инструкций препроцессора (всё, начинающееся с #) должно быть минимальным, разумеется, за исключением #include и #pragma once.
  • Не пишите макросы.
  • Переменные внутри функций объявляются там, где они необходимы, не все их нужно объявлять в начале функции.
  • В теле конструкторов лучше использовать списки инициализации (initialiser list), а не задавать переменные. Каждая инициализация в списке инициализации должна занимать отдельную строку. Убедитесь, что переменные в списке инициализации находятся в том же порядке, что и в определении класса в файле .h.
  • Не используйте исключения (если вы не применяете библиотеку, которая их требует).
  • Не используйте динамическую идентификацию типа данных (RTTI) (то есть не используйте dynamic_cast). RTTI немного снижает скорость, но более важно то, что RTTI почти всегда является свидетельством плохого объектно-ориентированного дизайна.
  • Применяйте reinterpret_cast и const_cast только при абсолютной необходимости.
  • Не делайте коммиты кода, который не компилируется без ошибок или предупреждений (и не отключайте сообщения о предупреждениях/ошибках).
  • Не делайте коммиты кода, ломающего существующий функционал.
  • Никаких глобальных переменных. Пользуйтесь вместо них переменными элементов типа static.
  • Вместо std::abs используйте нашу собственную функцию MathTools::abs. Причина: реализация std::abs на разных платформах отличается, что приводит к труднообнаруживаемым ошибкам.
  • Всегда используйте пространства имён явным образом. Не вставляйте в код ничего типа using namespace std.
  • Даже не думайте использовать конструкции с go-to. У нас есть распознаватель мыслей и в таких случаях он бьёт программиста током.
  • Не используйте в качестве разделителей запятые. Пример: if (i += 7, i < 10)
  • Не используйте объединения union.
  • Не применяйте указатели на функции, кроме случаев, когда этого требуют другие библиотеки (например, sort из STL).
  • Используйте тернарные операторы только в простейших случаях. Никогда не используйте вложенные тернарные операторы. Пример разрешённого простого использования:

    print(i > 5 ? "big" : "small");
  • Используемые художником или дизайнером счётчики должны начинаться с 0, как в обычных массивах в коде. Некоторые старые инструменты могут по-прежнему начинать с 1, но все новые разработанные для художников инструменты начинают с 0.
  • При проверке существования указателя выполняйте эту операцию явным образом. Поэтому используйте if (myPointer != nullptr), а не if (myPointer).
  • По возможности используйте RAII (Resource Acquisition Is Initialization). То есть вместо создания отдельной функции initialise() полностью инициализируйте класс в его конструкторе, чтобы он никогда не был в незавершённом состоянии.
  • Пишите конструктор и деструктор одновременно: пишите каждый соответствующий delete для каждого new, чтобы не забыть о них позже.
  • Если вы пишете временный отладочный код, то добавьте к нему комментарий с QQQ. Никогда не делайте коммит с QQQ: удаляйте весь отладочный код перед коммитом.
  • Если хотите оставить пометку о том, что нужно сделать позже, используйте QQToDo. Если это нужно будет сделать вам, до добавьте к комментарию свою букву, например, QQToDoJ. Делайте коммиты с QQToDo только если непрактично завершать работу сейчас.
  • Определения классов начинаются со всех функций, затем идут все переменные. Порядок должен быть следующим: public/protected/private. Это может иногда означать, что вам потребуется использовать одни и те же ключевые слова public/protected/private в одном файле заголовка несколько раз (сначала для функций, потом для переменных).
  • Класс начинается с его конструкторов, за которым идёт деструктор. Если они private или protected, то всё равно должны находиться наверху.
  • Если что-то имеет два варианта, но не точно true/false, то лучше использовать класс enum, а не boolean. Например, для указания направления не используйте bool isRight. Вместо этого применяйте enum Direction со значениями Left и Right.
  • Вместо std::string и std::stringstream используйте наши собственные классы RString, RStringstream, WString и WStringstream (они привязаны к нашей собственной системе управления памятью).
  • Переменная float time всегда означает время после последнего кадра в секундах. Если time значит что-то другое, то выразите это явным образом, например, дав название timeExisting.
  • Убедитесь, что весь код независим от частоты кадров, поэтому активно используйте для этого переменную float time.
  • Делайте структуры явными и понятными. Например, избегайте подобного:

    if (yellow)
    {
        return banana;
    }
    return kiwi;

    Здесь подразумевается, что в зависимости от yellow возвращается banana или kiwi. Более читаемым код будет, если выразить это явно:

    if (yellow)
    {
        return banana;
    }
    else
    {
        return kiwi;
    }
  • Используйте nullptr, а не NULL.
  • Мы используем auto только для таких случаев, как сложные типы итераторов. Для всего остального мы указываем тип явным образом.
  • Используйте там, где это применимо, range-based for, например:

    for (const Banana& ultimateFruit : myList)

    (Учтите, что когда вы не работаете с указателями, важно типизировать эту ссылку, потому что иначе в этом случае Banana будет скопирована.)
  • По мере применимости используйте override и final.
  • Если функция виртуальная, то к ней всегда нужно добавлять ключевое слово virtual, не только в родительском классе, но и в каждой из версий функций в классах-потомках.
  • Используйте enum со строгой типизацией, то же самое со словом class. Регистр в названиях такой же, как в классах. Например:

    enum class Fruit
    {
        Banana,
        Kiwi,
        ApplePie
    };
  • Используйте rvalue-ссылки (&&), если только это совершенно необходимо.
  • По возможности используйте unique_ptr. Если объект не имеет владельца, то он хранится как обычный указатель.
  • Избегайте создания экземпляров сложных типов в списке инициализации. В списке инициализации используется простое копирование и назначение, а более сложный код, например вызов new, должен находиться в теле конструктора. Вот пример того, как это работает:

    FruitManager::FruitManager(Kiwi* notMyFruit):
        notMyFruit(notMyFruit)
    {
        bestFruitOwnedHere.reset(new Banana());
    }
  • Используйте shared_ptr только в случаях, когда общее владение действительно необходимо. В общем случае старайтесь избегать общего владения и используйте
    unique_ptr
    .
  • Лямбда-функции, которые слишком длинны для записи в одну строку, должны иметь следующие отступы:

    auto it = std::find_if(myVec.begin(),
                           myVec.end(),
                           [id = 42] (const Element& e)
                           { 
                               return e.id() == id;
                           });
  • Не пользуйтесь MyConstructor = delete (похоже, что это не поддерживается в некоторых используемых нами компиляторах).
  • Не используйте возможности C++11 для инициализации списков (похоже, что это не поддерживается в некоторых используемых нами компиляторах). Поэтому мы не используем такого:

    std::vector<int> thingy = {1, 2, 3};
  • Не используйте возможности, добавленные в C++14.

C#

  • Переменные должны находиться в начале файла, а не внизу. Мы строго разделяем функции и переменные (как и в C++), поэтому сначала указываются все переменные, затем все функции.
  • Названия async-функций всегда должны заканчиваться на Async, например, eatBananaAsync.

На этом всё, это наше руководство по стилю кода! Думаю, вы можете не согласиться с некоторыми из правил, но любой компании всё равно полезно создать собственное руководство по стилю. Наше руководство может стать неплохой основой для создания своего руководства. Мне любопытно: какое руководство по стилю кода используется в вашей компании и нравится ли оно вам? И есть ли оно вообще?
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+4
Comments5

Articles

Change theme settings