Wednesday, January 29, 2014

6 вещей, которые (не)обязан делать C# разработчик

Предлагаю обсудить статью под названием "6 more things C# developers should (not) do". Этот материал, в отличие от статьи "Threadingin C#: 7 Things you should always remember about", не вызывает у разработчиков когнитивный диссонанс. Правда, меня немного смутил тот факт, что автор приводит ссылку на свою предыдущую статью "8 Most common mistakes C# developers make", которая содержит настолько поверхностно описанные, спорные моменты, что анализируемая статья сначала не вызвала особого энтузиазма (большее впечатление, чем сама статья, на меня произвела рецензия на нее: "8 наиболее распространенных ошибок C# программистов")
Очертим пункты статьи, которую нам предлагает Pawel Bejger, project manager компании Goyello.  

Try to avoid using the “ref” and “out” keywords.
В данном описании соглашусь с автором, что данный подход нарушает Single Responsibility Principle (Принцип Единой Ответственности), но у нас есть обратная сторона медали, которую автор называет "исключением из правил". Примером такого исключения служит изменение value type при передаче в метод функции и т.д. (часто такой подход наблюдается при использовании Win32 API структур данных). Использование для передачи без параметра ref приводит к копированию значения. Но в целом автор прав. Если в Вашем коде часто используется ref или out, то с большой вероятностью здесь проблема в реализации и классы пытаются выполнить код, который они не должны делать.
Do not use OrderBy before Where
В данном подходе я немного не согласен с аргументацией автора. Это здравый факт, что по производительности нецелесообразно сначала отсортировать данные, а затем для необходимых из них выполнить некое условие по выборке данных. К сожалению, мне ни разу не приходилось видеть тот факт, что вначале выполняется сортировка, а затем выборка. Предполагаю, автор статьи знаком с разработчиками, которые пишут такой код, поэтому он не счел данный факт очевидным.
Always use Properties instead of public variables
Соглашусь с автором по поводу того, что снаружи не должны быть доступны публичные переменные, но использование вместо них обычных автопроперти не решает ситуацию. Многие разработчики используют вместо публичных переменных публичные автопроперти.

class SomeClass
{
    public int _value;
    public int TestProperties { get; set; }
}

В данном подходе использование проперти вместо публичных переменных не особо спасает ситуацию. Рихтер говорит о таком явлении как о злоупотреблении автопроперти. Вариант с использованием переменных, которые доступны извне для изменений, обычно искореняется на основании принятого корпоративного стиля разработки. Если в компании такого стиля нет, то здесь бороться и утверждать, что такое хорошо, а что такое плохо, бессмысленно. Дешевле для такой компании предложить воспользоваться услугами компании JetBrains. А именно - ее продуктом, который называется ReSharper. Сложно в данном примере, приведенном автором, найти связь, которую он хотел провести между свойствами (properties) и переменными, так как это разные вещи. Даже в том контексте, который имел в виду автор, предложение звучит с ноткой бессмыслицы, потому как говорить в этом контексте только о свойствах, не упоминая при этом функций или методов, недостаточно.
Take advantage of string.IsNullOrEmpty() and string.IsNullOrWhiteSpace()
С этим пунктом также сложно поспорить. Ввиду своей очевидности этот подход можно назвать К. О.; он чем-то напоминает подход автора, замеченный в его статьях ранее. Возможно, буду не прав, но считаю, что компания может обеспечить своих разработчиков компонентом, чтобы автоматизировать этот процесс. Если компания не может выделить средств на покупку ReSharper, то в этом случае с помощью Roslyn API, доступным для скачивания и разработки и который войдет в язык C# как составная часть, Вы можете написать правило, которое позволит, не раздумывая о таких тонких нюансах, делать это автоматически.
Understand the difference between First() and Single()
Пожалуй, еще один очевидный факт. Но в последнее время часто наблюдается тенденция использования FirstOrDefault() и SingleOrDefault(), так как разработчикам лень обрамлять свои конструкции блоками try->catch.
Do not blindly use List
Автор рекомендует в некоторых случаях использовать HashSet или SortedHash как замену List для того, чтобы повысить производительность. Автор прав в данном случае по поводу альтернативы HashSet в некоторых случаях вместо List. Но тот пример, который привел автор для сравнений производительности, просто убил меня наповал.
static void Main(string[] args)
    {
        const int COUNT = 100000;
        HashSet<int> hashSetOfInts = new HashSet<int>();
        Stopwatch stopWatch = new Stopwatch();
        for (int i = 0; i < COUNT; i++)
        {
            hashSetOfInts.Add(i);
        }

        stopWatch.Start();
        for (int i = 0; i < COUNT; i++)
        {
            hashSetOfInts.Contains(i);
        }
        stopWatch.Stop();

        Console.WriteLine(stopWatch.Elapsed);

        stopWatch.Reset();
        List<int> listOfInts = new List<int>();
        for (int i = 0; i < COUNT; i++)
        {
            listOfInts.Add(i);
        }

        stopWatch.Start();
        for (int i = 0; i < COUNT; i++)
        {
            listOfInts.Contains(i);
        }
        stopWatch.Stop();

        Console.WriteLine(stopWatch.Elapsed);
        Console.ReadLine();
    }
}
Я не предполагал, что есть люди, которые сравнивают производительность коллекций, построенных на основании хешей, и коллекций по значению.  Как можно сравнивать такие вещи, ведь у данных коллекций разная эффективность.

Вместо непонятного сравнения линейной сложности коллекции List с HashSet, который имеет постоянную сложность, рекомендую ознакомиться с эффективностью использования коллекций в .NET "C#/.NETFundamentals: Choosing the Right Collection Class", с этого источника можно узнать намного больше, чем с исходной статьи.

Итоги
Анализируемая статья в автора написана на порядок лучше, чем его предыдущие статьи, но утверждения в ней выглядят из разряда К.О. Автор мог бы расширить свой список и добавить для расширения от банальности, например, пункты: "использование IEnumerable<> вместо явного использование типов List<>, Array и других коллекций"; "избегайте использования множества потоков", "не забываем using для классов, которые реализуют интерфейс IDisposable". А если разработчик пишет под .NET 2.0 или Compact Edition, то часть предложенных позиций ему просто не нужна. Интересно, почему из шести вещей, которые, по мнению автора, должен делать каждый разработчик, две из них посвящены linq. Надеюсь, статья открыла для вас очевидные вещи в языке C#, о которых Вы, могли не знать или использовать неверно J.  

  

No comments:

Post a Comment