Прочитал книгу по C# или что написал Рома Сакутин
Предыстория
Я познакомился с Романом, когда он публиковал на YouTube видео, в которых критиковал качество кода, написанного другими разработчиками, и создавал образ эксперта, который знает, как писать чистый и аккуратный код. На самом деле Роман действительно обладает такими знаниями, но то, как он их применяет, вызывает вопросы. Многие люди последовали за ним, стали использовать практики, которые он пропагандировал, и в целом доверяли его мнению. Затем Роман создал свою онлайн-школу для программистов, специализирующихся на C#. Я даже приобрёл его курс. Тогда я понял, что он учит не намного лучше, чем другие школы. Сейчас его курсы доступны для бесплатного ознакомления. Изучив их, мы увидим, что в его курсе реализация FSM (конечного автомата) слишком упрощена и не готова к использованию в реальных проектах.
О чем я тут раскидал буквы
Прежде всего, я хотел бы обозначить рамки, за которые я не буду выходить в этой статье. А именно, о чём пойдёт речь.
Я не стремлюсь кого-либо обидеть или очернить. Я лишь хочу указать на недостатки, которые можно и нужно исправить.
Моё мнение не претендует на абсолютную истину, я высказываю его, основываясь на своём жизненном и профессиональном опыте в сфере коммерческой разработки.
В основном мы будем говорить не о том, как написана книга, а о том, какие вредные советы она может давать. А в конце обсудим, насколько полезна эта книга в мире, где есть такие издания, как:
Clean Code by Robert C. Martin. (Uncle Bob)
Clean Architecture by Robert C. Martin. (Uncle Bob)
CLR via C# by Jeffrey Richter
Вредные советы
Я буду приводить вредные советы по мере их появления в книге и объяснять, почему они вредны.
Перегрузка операторов для кастомных типов в 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 публичным произвести нужные сравнения в нужных местах.
Засорение аргументами
Далее приводится пример того, как «можно» расширять код без риска его поломки при внесении изменений.В таком случае мы можем просто добавить параметр в метод как необязательный и сделать ему значение по умолчанию, которое и было раньше.
В этом случае нам говорят, что нужно сделать следующий ход конем:
Ниже будет два примера, первый до обновления, второй после обновления кодовой базы: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);
Вот так просто, мы разработали новый метод, который соответствует текущим требованиям и не нарушает принципы «Чистого кода». Кроме того, мы уведомили других разработчиков о том, что старый метод устарел и рекомендуется использовать новый.
Правила не передавай/возвращай 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# и если не прочитать его, то обращаться к нему в спорных моментах, что бы понимать, как язык на котором вы общаетесь с машиной, будет работать.
На этом у меня все, дайте свой фидбэк, так как это первая статься для меня за долгие годы и я уверен, что многое мог упустить или не заметить.