Прочитал книгу по C# или что написал Рома Сакутин

c0ccaa88e74563fe5ab540c3e30663c4

Предыстория

Я познакомился с Романом, когда он публиковал на YouTube видео, в которых критиковал качество кода, написанного другими разработчиками, и создавал образ эксперта, который знает, как писать чистый и аккуратный код. На самом деле Роман действительно обладает такими знаниями, но то, как он их применяет, вызывает вопросы. Многие люди последовали за ним, стали использовать практики, которые он пропагандировал, и в целом доверяли его мнению. Затем Роман создал свою онлайн-школу для программистов, специализирующихся на C#. Я даже приобрёл его курс. Тогда я понял, что он учит не намного лучше, чем другие школы. Сейчас его курсы доступны для бесплатного ознакомления. Изучив их, мы увидим, что в его курсе реализация FSM (конечного автомата) слишком упрощена и не готова к использованию в реальных проектах.

О чем я тут раскидал буквы

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

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

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

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

  • Clean Code by Robert C. Martin. (Uncle Bob)

  • Clean Architecture by Robert C. Martin. (Uncle Bob)

  • CLR via C# by Jeffrey Richter

Вредные советы

Я буду приводить вредные советы по мере их появления в книге и объяснять, почему они вредны.

  1. Перегрузка операторов для кастомных типов в C#

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

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

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

    Это будет выглядеть следующим образом:

    public struct Army
    {
        private readonly int _damage;
        
        public int Amount { get; }
    
        public Army(int amount, int damage)
        {
            Amount = amount;
            _damage = damage;
        }
    
        public static bool operator <(Army a, Army b)
        {
            return a.GetPower() < b.GetPower();
        }
      
        public static bool operator >(Army a, Army b)
        {
            return a.GetPower() > b.GetPower();
        }
    
        private int GetPower() => _damage * Amount;
    }

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

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

  2. Засорение аргументами
    Далее приводится пример того, как «можно» расширять код без риска его поломки при внесении изменений.

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

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

    public void Apply();
    public void Apply(int port = 80);

    Этот вариант имеет существенный недостаток: метод может начать принимать четыре, десять или двадцать аргументов, что противоречит принципам «Чистого кода» и приводит к созданию огромного и сложного метода, который берёт на себя слишком много задач.

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

    [Obsolete("It is legacy method, please use Apply(int port)")
    public void Apply();
    
    public void Apply(int port);

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

  3. Правила не передавай/возвращай null

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

    © Роман Сакутин «C# Для Начинающих на практике»

    В данном случае, мы в принципе нарушаем принципы «Чистого кода».

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

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

    © Robert C. Martin «Clean Code»

    То же самое касается и принимающей стороны. Зачем нам дополнительная проверка в алгоритме программы? И почему мы передаём null?

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

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

    Функция должна выполнять только одну операцию. Она должна выполнять ее хорошо. И ничего другого она делать не должна.

    © Robert C. Martin «Clean Code»

Венденговый автомат

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

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

Действительно полезная информация

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

К таким вещам относятся:

  • Принципы S.O. L.I.D и то, как мы их используем и почему мы их используем.

  • Fraemwork Roslyn — полезное API для написания собственных анализаторов кода.

  • Числа Фибоначчи — преведена целая глава работы с этими числами, что я считаю полезным для начинающих.

  • Работа с Reflection, но тут важно уточнить, что опять же, Роман не сообщат, что чрезмерное использование рефлексии, (может привести) приведет к снижению производительности.

Заключение

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

Исходя из заголовка книги «C# Для Начинающих На Практике», я отношусь к тексту этой книги более легко, если название было что то типо «C# Для Заканчивающих На Практике».
Но это не дает права, на те вредные советы которые были приведены в книге!

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

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

По отношению к Рихтеру, то тут все еще проще, Рихтер пишет о том, как C# работает, а Роман пишет о том, что есть if и оператор == и исходя из этих данных, выгоднее один раз купить CLR via C# и если не прочитать его, то обращаться к нему в спорных моментах, что бы понимать, как язык на котором вы общаетесь с машиной, будет работать.

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

© Habrahabr.ru