Andriy Shyrokoryadov

.Net developer, data scientist

Code review (код ревью) и чистый код

Текст к видео "Code review (код ревью) и чистый код" на канале YouTube

Всем привет. Тему сегодняшнего видео мне подсказал зритель в комментариях к одном из видео. Code review и рефакторинг кода. Данные темы популярны на собеседованиях. Задание сводится к тому, что вашему вниманию предлагается некоторый код и вам необходимо его улучшить, проверить, сделать code review и указать недостатки. Я и сам практикую такие задания на собеседованиях, где я выступаю в качестве рекрутера.

Данные задания можно поделить на 2 класса – плохие и хорошие. К плохим заданиям с code review я отношу все задания такого типа, где проверяется знание каких-либо библиотек, сигнатур методов и синтаксиса на память. Эти задания не имеют смысла, потому что если вы ошибетесь в синтаксисе в процессе работы, то ваша среда разработки, например Visual Studio, вам обязательно об этом сообщит. То есть нет необходимости помнить точное название метода и какие аргументы он принимает – будет достаточно знать, что существует такой метод и что в результате его работы мы можем получить определенные данные. Возможно у вас своя точка зрения на этот вопрос, будут рад её узнать в комментариях и поддержать дискуссию на эту тему.

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

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

Во время подготовки данного видео я очень интенсивно использовал книгу Роберта Мартина «Чистый код». Естественно, я её уже несколько раз прочитал. Перечитываю её я для того, чтобы не забывать, как хороший и чистый код должен выглядеть. Ссылки на данную книгу будут в описании к данному видео.

Каждый из нас может определить, насколько чист и хорош наш код задав себе 4 вопроса:

  • Можно ли мой код протестировать? Написал ли я соответствующие юнит – тесты чтобы это проверить? Я еще не рассматривал юнит – тестирование на моём канале, но после выпуска такого видео в будущем вы будет в состоянии ответить на данный вопрос.
  • Будет ли мой код понятен другим программистам? Поймут ли они мой замысел и мои намерения, когда они увидят то, что я создал? Так сложил, что в компаниях с Вашим кодом будут работать также и другие программисты, чем легче им будет понять то, что вы написали, тем более качественней будет их работа.
  • Пойму ли я сам то, что я написал несколько месяцев назад? Иногда так бывает, что автор кода сам не может понять, что он сделал. Обычно это плохой знак, который свидетельствует о низком качестве кода.
  • Можно легко изменить мой код, попутно не испортив что-нибудь? На этот вопрос порой тяжело ответить, но если вы будет следовать принципам «чистого кода» и принципам SOLID, то скорей всего ответ на этот вопрос будет «Да, можно легко изменить и ничего при этом не испортить».

Далее я представлю несколько правил связанные с объектно-ориентированным программированием, паттернами проектирования и принципами SOLID:

  • Композиция всегда лучше, чем наследование. Почему? Потому что класс, который состоит из компонентов легче протестировать, создав мок-объекты определенных компонентов. О мок-объектах или объектах – имитациях мы поговорим в видео посвященному юнит-тестам. Каждый отдельный компонент сам по себе должен легко поддаваться тестированию.
  • Необходимо использовать компоненты, которые слабо связаны между собой, то есть использовать интерфейсы и абстрактные классы. Почему? Потому что если между компонентами существует слабая связь, то шансы, что ваши изменения в одном компоненте испортят что-то в другом компоненте минимальны.
  • Необходимо делать так, чтобы ваш код зависел от абстракций, а не от конкретных реализаций. Почему? Потому что абстракции легче заменить, то есть код легче изменить. И к тому же это соблюдение принципа D SOLID – инверсии зависимости.
  • Чем класс меньше, тем лучше. Почему? Принцип S SOLID. У каждого класса должна быть одна ответственность. Если класс достаточно большой, то скорей всего принцип S нарушен.
  • Чем меньше интерфейс, тем лучше. Почему? Принцип I SOLID, то есть принцип разделения интерфейсов. Если интерфейс достаточно большой, то скорей всего для него тяжело написать отдельную имплементацию. В этом случае польза от использования данного интерфейса невелика. То есть возникает вопрос почему мы должны использовать интерфейс, который тяжело реализовать?
  • Чем меньше части кода (классы, методы), тем легче их понять.

До этого момента мы говорили о качественном коде обобщенно. Теперь пришло время посмотреть на конкретные элементы кода и научиться отличать хороший код от не очень хорошего. Таких элементов будет 6.

  1. Правильное использование названий
    • названия переменных и классов должным быть такими, чтобы их можно было легко прочитать. Сравните “sqrTri” и “squareOfTriangle”. Естественно, второй название прочитать легче.
    • стоит избегать использования «магических цифр», то есть названий в стиле “label1”, “label2”, “label3”…
    • не используйте тип переменной в названии переменной, например «RatioString». Здесь слово «String» избыточно. Если Вы используете для работы с кодом среду разработки, а не приложение Блокнот, то вы всегда будете в состоянии определить какой тип имеет переменная или объект, без дополнительных указаний в названии переменной.
    • названия объектов и классов должны быть существительными. Желательно на языке, который понимают все программисты, которые работают с кодом. Как правило это английский.
    • названия методов и функций должны быть глаголами
    • чем короче название, тем лучше, но всё равно надо постараться чтобы имя было описательным
  2. Замечания к функциям и методам
    • метод должен решать только одну задачу, и он должен делать это идеально;
    • название метода должно быть описательным.
    • чем меньше число аргументов метода, тем лучше; идеально число аргументов метода – 0, например DoSomething();
    • использование блоков try / catch. Обработка исключений — это отдельная операция и она должна быть отдельна от основной части кода. Если мы используем блок try / catch в теле метода, то первым словом в теле метода должно быть слово try и последними выражениями в теле метода должны быть выражения catch / finally. Не должно быть блоков try / catch где-то в середине тела метода.
  3. Комментарии

    1. Хорошие комментарии (вообще хорошим комментарием является тот комментарий, который никогда не был написан). Всё-таки иногда комментарии необходимо написать и на это у вас есть определенный список причин:
      1. юридические комментарии в начале кода приложения о правах и лицензиях – сейчас такие комментарии практически не используются – функцию такого комментария принял текстовый файл с текстом лицензии. Но если вы все-таки работаете с очень старым кодом, то такой тип комментария может быть только в одном указанном ранее месте.
      2. общие информационные комментарии в начале кода приложения. Опять-таки, как и юридические комментарии, данный тип комментария признак старого кода. В современных приложениях эта информация указывается в файлах readme.
      3. комментарии, которые объясняют выбор данного технического решения – например вы можете написать в комментарии, что для работы с базой данных вы выбрали технологию ADO.Net, потому что на тот момент в вашей команде мало кто знал фреймворк Entity Framework.
      4. комментарии, которые предупреждают о последствиях – например, вы можете указать, что если будет что-то удалено из кода, то возможно перестанет работать какая-то услуга или определенная функциональность будет работать неправильно.
      5. комментарии ToDo, то есть комментарий «сделать в будущем» - если вы видите что-то в коде, что требует улучшения, но в данный момент, у вас на это нет времени, то можете оставить этот комментарий на будущее. Существуют приложения, например ReSharper, которые могут найти все такие комментарии в коде и на их основании создать список заданий
      6. комментарии к публичным методам, которые используются в API – если Вашей библиотекой кто-то пользуются, то было бы неплохо этому кому-то объяснить как использовать вашу библиотеку.
    2. Плохие комментарии – если вы видите такой комментарий, то сразу его удаляйте без оглядки:
      1. комментарии, которые не вносят ничего нового, например комментарий «Это метод Add»
      2. повторение одних и тех же комментариев в различных частях кода
      3. комментарии, которые не имеют смысла или вообще могут натолкнуть на неправильное понимание кода
    3. не пишите комментарий, когда есть возможность написать короткий метод или добавить свойств с описательным названием
    4. вообще комментирования кода – это плохая привычка. Удаляйте комментарии, если считаете, что они не вносят ничего нового. Если кому-то будет нужен удаленный комментарий, он сможет найти его в истории изменений файла.
    5. помните, что всё комментарии, когда-то станут не актуальными, то есть кто-то изменит код, но оставит без изменений комментарий который относится к данному коду. Если вам все-таки не удалось избежать добавления комментарий, добавьте к нему дату, чтобы сразу было понятно через несколько лет на сколько данный комментарий стар.
    6. не пишите слишком длинные комментарии. Их и так никто не будет читать, а даже если и прочитают, то не факт, что читатель поймёт прочитанное.

4.Исключения

  • всегда необходимо выбрасывать исключение, а не код ошибки
  • необходимо помнить о правильной обработке исключений в методах
  • никогда не возвращайте в методах значение null, используйте паттерн «Пустой объект» или паттерн «Объект по умолчанию». Например, возврат пустой коллекции лучше, чем возврат null или возврат пустой строки всегда лучше возврата null.
  • Никогда не передавайте в качестве аргумента значение null. Если вы написали метод для которого аргументом по умолчанию является величина null, то стоит сделать рефактор этого кода и избавиться от таких аргументов.
  • не пишите ваш код в защитной манере, то есть проверяя всё и всея, если только вы не должны это делать, например при работе со старым кодом. Если вы не будете принимать и возвращать значения null, то вы избавите себя от необходимости постоянных проверок на null объектов в вашем коде

5.Юнит тесты – о них я сниму отдельное видео, ну а пока очень-очень коротко пару слов на эту тему:

  • их необходимо писать
  • они должны быть маленькими
  • необходимо использовать подход AAA: arrange, act, assert.
  • необходимо использовать подход ACID: atomicity, consistency, isolation, durability.
  • одна проверка на один тест или по крайне мере несколько проверок должны касаться одной определенной функциональности

6.Классы

  • должны быть маленькими
  • принцип S – единственная ответственность
  • зависимость от абстракций, то есть возможность использования внедрения зависимостей

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