Tuesday, April 15, 2014

Рецензия книги Билла Вагнера "Effective C#"

Здравствуйте, уважаемые читатели. В этой статье представлю краткий обзор книги Билла Вагнера "Effective C#". Один из известных MVP в Украине – Сергей Тепляков  уже давал краткий обзор неточностей этой книги в своей статье  "О книге Билла Вагнера "EffectiveC#", я лишь немного их дополню своими наблюденями. 
Книги из серии Effective начал Скотт Мейерс в 1997 году свой книгой "Effective C++". Сейчас доступно третье издание этой книги "Effective C++: 55 Specific Ways to Improve Your Programs and Designs". Так вот: независимо от того, что книга Билла Вагнера из этой серии, по содержимому она не дотягивает до книги Мейерса. Не могу сказать о том, что книга не стоит прочтения. Тут проблема в другом: если Вы далеко не начинающий разработчик и прочитали как минимум с пониманием Рихтера и, например, книгу Джона Скита "C# in Depth, 3rd Edition", то пользы от этой книги будет мало. 

Приведу краткий перечень неточностей, замеченных Сергеем Тепляковым, так как они отличаются от тех, которые нашел я.
Неточность #1.Переопределение статических методов
«You never override the static Object.Reference and static Object.Equals() because they provide the correct tests, regardless of the runtime type.»
Неточность #2. Время жизни локальных переменных
All reference types, even local variables, are allocated on the heap. Every local variable of a reference type becomes garbage as soon as the function exits.
Неточность #3. Об операторе ==
«No matter what type is involved, a == a is always true.»
Неточность #4. Виртуальность интерфейсов
«Members declared in interfaces are not virtual – at least, not by default. Interface methods are not virtual. When you implement an interface, you are declaring a concrete implementation of a particular contract in that type».
Неточность #5. Порядок создания объектов
«Here is the order of operations for constructing the first instance of a type:
1.    Static variable storage is set to 0.
2.    Static variable initializers execute.
3.    Static constructors for the base class execute.
4.    The static constructor executes.
5.    …»
Неточность #6. Об итераторах коллекций
«The .NET Framework designers followed the same pattern with the other collection classes: Dictionary<T> contains a private DictionaryEnumerator<T>, Queue<T> contains a QueueEnumerator<T>, and so on. The enumerator class being private gives many advantages…»

Приведу неточности, которые заметил я. Первая проблема – в первом же совете, в котором автор рекомендует использовать проперти, вместо доступных открытых данных. Вроде и все расписано, и рассказано о валидации, и о прочих прелестях проперти. Но если копнуть глубже, то лучше в этом плане дает совет Рихтер по поводу использования properties вместо открытых данных в своей книге "CLR via C#". Тот же Рихтер говорит о том, что не нужно злоупотреблять автопроперти.  Вагнер об этом не пишет ни слова. Этот совет вряд ли вам расскажет о чем-то новом. Я не считаю данный совет неточным, я его просто считаю неполным, поскольку привел источник, в котором такой же совет занимает меньше в описании и доносит до читателей больше, чем это делает Вагнер.
Третий совет из этой серии о предпочтении использования is/as оператора, по сравнению с Cast, – неполный. О преобразовании к value type упоминается только вскользь. Возможно, это не является глобальной проблемой, но если вы посмотрите об этот пост Эрика Липперта, то заметите очень большую разницу (What's the difference between "as" and "cast" operators?). В итоге мы можем ознакомиться с интересующей нас темой либо у Липперта  в нескольких абзацах, или читать совет, часть из которого, к сожалению,  просто вода.
Небольшой отход от неточностей и критики некоторых советов: хотелось бы упомянуть об еще одной детали, которая наблюдается у Вагнера по всей книге. Если для написания какой-то заметки нужны примеры, то сначала идут некорректные примеры или примеры, которые нежелательно использовать на практике, и в конце совета – нормальный пример. В итоге имеем кучу информации, полезной из которой − около 20%. Возможно, некоторым разработчикам нравится такой подход. Меня же такое описание немного нервировало.
Также спорный совет по поводу переопределения для классов метода ToString(). К сожалению, совет имеет мало общего с практическим применением.  Как часто для своих классов вам приходится вызывать метод ToString()? А переопределять для каждого класса данный метод, который с вероятностью 80% никогда не будет использован, – нецелесобразный. Анализ этого совета я сделал, проанализировав несколько коммерческих и open sources проектов.
Очень не понравился совет по инициализации членов статических классов: "Use Proper Initialization for Static Class Members". В совете не рассказано о проблеме, которая называется double check locking in singleton pattern. Более детально об синглтоне можно посмотреть в примере  "Implementing Singleton in C#" на MSDN, а лучше посмотреть статью Скита "Implementing the Singleton Pattern in C#". Из этих статей можно почерпнуть больше, чем с совета Вагнера. Признаюсь честно: если бы я не знал, как это работает и что упустил Вагнер, я бы, наверное, не понял, что автор хотел донести этим советом.
Один из советов, который действительно понравился, – это "Ensure That 0 Is a Valid State for Value Types". В нем рассказывается, что 0 не всегда актуальное значение для value type, и приводится пример с enum.
Также в примере автора к рекомендации "Implement the Event Pattern for Notications" пример, который приведен для данного совета, некорректен. Во-первых, пример с логгером, у которого нужно добавить нотификацию, мягко говоря, странный. У него есть огромная проблема: достаточно хоть одному из подписанных событий пробросить ошибку  и прервётся вся цепочка уведомлений. Более детально, как такое побороть, можно посмотреть в статье "Обработка ошибок в C#". Слишком сложный пример для того, чтобы донести свою мысль до читателей.
Одним из неуместных примеров также оказался совет 30 "Prefer Overrides to Event Handlers". Возможно, для разработчиков, которые работают не с WPF, этот пример может показаться таким, который имеет право на существование, но в реальных примерах принято использовать паттерн MVVM и вместо событий использовать паттерн Command.

Немного сожалею о том, что не было возможности цитировать неточности данной книги в ридере. Из-за этого часть из них просто не смог вспомнить. В целом книга неплохая. Она уникальная в своем роде. Если подытожить, то по пятибалльной шкале книга заслуживает оценку 3. Думаю, что опытные разработчики смогут подчеркнуть некоторые ценные моменты из данной книги. Книга для тех, кто любит постоянно черпать новые знания. Суммарная оценка – "удовлетворительно".

No comments:

Post a Comment