вторник, сентября 30, 2008

VS2010 "Rosario" - Гонка программных вооружений.

Microsoft анонсировала следующую версию студии и .Net: Visual Studio 2010 и .Net Framework 4.0.
Здесь есть более подробная информация о нововведениях в VS 2010 (code-name "Rosario"), а о .Net 4.0 информации практически никакой нет. Если между выпусками VS 2005 и VS 2008 прошло три года, то следующая версия выйдет через два. Гонка программных вооружений продолжается и набирает обороты.
Основные нововведения должны коснуться расширения поддержки различных аспектов Application life-cycle management (ALM).
Вероятно с одной стороны у создателей VS крепнет понимание того, что software development process состоит не только из кодирования и модульных тестов. Есть еще куча всяких активностей и неплохо бы их поддержать в интегрированном инструментарии.
С другой стороны, менеджмент Microsoft не может не замечать огромного количества open source и third party инструментов разработки активно развивающихся сейчас на широком поле разработки на платформе .Net. Оставлять без внимания такой рынок было бы очень опрометчиво в рамках существующей бизнес стратегии Microsoft, которая состоит в том, что захватив плацдарм, необходимо заполнить собой все рыночные ниши на нем. Хотя на рынке средств разработки, на мой взгляд такая стратегия заведомо проигрышна. Тут деньги не на продуктах зарабатывать надо, а на максимальном расширении базы разработчиков, использующих платформу (как это к примеру делает Sun).
Посмотрим, что будет в 2010 году. Пока же я в 2008-ой студии для модульных тестов использую TestDriven.Net. Просто удобнее.

вторник, сентября 23, 2008

Комментарии и код

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


Есть распространенное мнение о том, что хорошему коду комментарии не нужны. И это действительно так. Другое дело, что хорошего кода не так уж много. Поэтому моя точка зрения: не можешь писать хороший код - пиши комментарии.
Не всегда удается написать хороший код. Иногда просто не хватает времени на проработку дизайна, кажется "потом переделаю", но "потом" обычно не наступает никогда. Иногда программисту просто не хватает опыта, чтобы разработать хороший дизайн. В этом случае очень полезно попытаться написать стандартные (для компилятора C#) комментарии к своим классам. После попытки сформулировать короткое описание класса часто наступает "просветление", после которого удается взглянуть на свой код по новому и подправить дизайн. Сам не раз ловил себя на таком.
Другая хорошая привычка, если уж ты чувствуешь в своем коде какой-то smell, но в силу каких-то причин ты не можешь им заняться прямо сейчас, напиши прямо в коде что-то вроде "//здесь воняет". Возможно потом это станет той последней каплей, которая перевесит чашу весов и ты почининишь этот код.
Одни из главных врагов читаемости кода, это невнятное именование и нарушение SRP (Single Responsibility Principle). Основные порождаемые ими проблемы, это невозможность понять по имени класса или метода что они делают, и невозможность отыскать нужный класс или метод. Есть такой парадокс: почти всегда мы считаем свой код хорошим и читаемым, а чужой плохим и невнятным. Происходит это от того, что о своем коде мы всегда знаем больше, чем о чужом. Поэтому никогда не повредит снабдить комментариями свои классы и ключевые методы.
Ну и на конец, если ты пишешь библиотеку для повторного использования, будь добр, прокоментируй публичные контракты всех своих классов. по моему это признак зрелости программиста и проявление уважения к своим коллегам.

Теперь по поводу ведения истории кода прямо в коде. Никогда не удалять старый код, а окружать его комментариями, вести многоэтажные заголовки файлов исходников с копирайтами и персональными списками изменений - все это полный маразм. Проверено, это не работает, и со временем просто превращает код в помойку. По моему это делают те, кто не умеет пользоваться системами контроля версий. Любая СКВ позволяет все это делать намного лучше и удобнее. Единственная полезная практика, сопровождать короткими коментами с номером бага или тикета свои изменения в старом коде (и то это ИМХО - мне так удобно).

Итак, что у нас в сухом остатке?
Комментарии, это самый дешевый способ улучшить поддерживаемость кода, поэтому не стоит пренебрегать ими. Однако никакие комментарии не заставят ваш код работать лучше, не улучшат никакие его характеристики (кроме читаемости) и не заменят хороший дизайн. Поэтому не стоит на них уповать и ими злоупотреблять.

четверг, сентября 18, 2008

Почтенный юбилей :-)

Двадцать шесть лет назад был придуман смайлик. Вот как это было:

19-Sep-82 11:44 Scott E Fahlman :-) From: Scott E Fahlman I propose that the following character sequence for joke markers: :-) Read it sideways.

Actually, it is probably more economical to mark things that are NOT jokes, given current trends. For this, use :-(

Источник: calend.ru

Я и не думал, что смайл такой старый. Он старше Интернета (в его современном виде www/http/html). И старше большинства из тех, кто им пользуется :)

понедельник, сентября 15, 2008

Правила хорошего кода

«Компетентный программист полностью осознает строго ограниченные возможности своего черепа, поэтому подходит к задачам программирования со всей возможной скромностью»
Dijkstra.

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

Есть масса рекомендаций по созданию хорошего кода. Большинство из них касается паттернов программирования. Другие относятся к дизайну классов, третьи – к оформлению кода. Но для качественного кода важны все они. Здесь я попытюсь собрать некоторые наиболее общие, не зависящие от конкретного языка (но лежащие в пределах объектной парадигмы). Паттерны оставим за бортом. Начнем с простейших правил оформления, и будем продвигаться к правилам дизайна.

Итак, правила хорошего кода:

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

  2. Повсеместно избегайте литералов. Заменяйте их константами. Числовые литералы (известные, как магические числа) затрудняют понимание кода. Строковые литералы создают проблемы при локализации / глобализации. Любые повторяющиеся значения литералов создают проблемы при изменении кода. Избегайте констант там, где можно использовать перечислимые типы.

  3. Пишите короткие методы (функции). Есть различные мнения по поводу оптимального размера процедур и функций. Я использую следующий критерий: если весь метод нельзя увидеть целиком на экране или странице – это слишком большой метод. С увеличением размера функции комбинаторная сложность управляющих структур (условий циклов и т.д.) и переменных возрастает нелинейно, и очень быстро начинает создавать проблемы не только в обеспечении надежности кода, но и в его понимании. Зачем вам лишние проблемы? Разделяйте большие функции на более мелкие. Первые кандидаты на выделение в отдельные функции, это сложные условия в предложениях if и тела циклов. Выделяйте в функции отдельные функциональные блоки. Если функция вычисляет и сохраняет, то выделите функцию, которая вычисляет, и функцию, которая сохраняет.

  4. Избегайте любого дублирования кода (правило трех О «Once and Only Once»). Существует масса приемов рефакторинга, которые помогают выполнять это правило. Используйте константы вместо литералов, выделяйте повторяющийся код в отдельные методы.

  5. Избегайте глобальных переменных (переменных с глобальной областью видимости). Глобальные константы - это хорошо, глобальные функции - это нормально, глобальные переменные – это зло. А как же быть с настройками приложения, спросите вы? Большинство платформ предлагают для этого специальные средства. Если же таких средств нет, используйте глобальные функции вместо глобальных переменных. Вместо Boolean MyGlobalFlag используйте функцию Boolean GetMyGlobalFlag(), которая будет возвращать копию текущего значения вашего глобального флага, а само его значение спрячьте за функциями доступа.

  6. Контролируйте доступ. Модификатор public должны иметь только те члены класса, которые составляют публичный контракт этого класса и которые действительно используются другими классами. Все остальные члены должны быть скрыты для внешнего доступа (инкапсулированы). Следите за публичным контрактом своих классов и не допускайте появления в них ничего лишнего. Например:


    public class Action
    {
    public void DoAction(Context context)
    {
    string message = string.Empty;
    If(IsInternal(context))
    message += PrepareInternalMessage(context);
    else
    message += PrepareExternalMessage(context);
    SendMessage(message);
    }
    private string PrepareInternalMessage(Context context){…}
    private string PrepareExternalMessage(Context context){…}
    private bool IsInternal(Context context) {…}
    // этот метод тоже должен быть private
    public void SendMessage(string message){…}
    }


    Класс Action предназначен для выполнения некоторого действия (DoAction), это собственно и есть его контракт. Метод SendMessage() представляет собой часть реализации этого действия. При этом формат сообщения поступающего в параметр SendMessage также определяется внутренней логикой класса Action. Все эти соображения говорят в пользу того, чтобы скрыть метод SendMessage. Наличие в публичном контракте подобных методов приводит к неправильному использованию класса.

  7. Не совмещайте в одном классе разные обязанности (принцип Single Responsibility Principle). Вот, пример базового класса для реализации действий:


    public class ActionBase
    {
    public abstract void DoAction(Context context);
    // полезная фича - запись в лог
    public void WriteLog(string message){…}
    }


    Здесь программист решил, что функция записи в лог потребуется во всех реализациях классов – действий и поэтому полезно будет ее вынести в базовый класс. Но основное назначение наследников ActionBase это выполнение действий (DoAction), а запись в лог это совсем другая обязанность. Ну и что с того? Вероятно, что запись в лог потребуется не только для классов-действий, но и для многих других классов. И нам придется либо создавать экземпляр класса-действия для записи в лог (т.е. использовать класс не по назначению), либо продублировать метод WriteLog в других классах. Оба варианта неприемлемы. Поэтому метод WriteLog следует вынести в отдельный класс, который будет заниматься исключительно записью в лог.

  8. Не разговаривай с незнакомцами (правило Деметры). Внутри метода следует обращаться только:
    • К параметрам, переданным в метод (к свойствам и методам этих параметров, если это объекты)

    • К членам объекта, которому принадлежит метод (this.xxx)

    • К объектам, созданным в данном методе.


    Цель - избежать связывания с непрямыми объектами.

  9. При построении иерархий наследования старайтесь не изменять и не расширять публичный контракт базового класса в наследниках. Данное правило напрямую вытекает из известного принципа подстановки Лискоу (LSP - Liskov Substitution Principle). Вот пример иерархии, который надо избегать:


    class Shape
    {
    public int X;
    public int Y;
    }
    class Rectangle : Shape
    {
    public int Width;
    public int Height;
    }
    class Circle : Shape
    {
    public int Radius;
    }


    Придерживаясь данного правила, вы защищаете уже написанный код от изменений в классах наследниках. Крайне неприятна ситуация, когда в различные места существующего кода приходится вносить многочисленные изменения при появлении нового класса наследника. Обычно такой код насыщен операторами if и case, выполняющими обращения к специфичным членам классов наследников.
    И все же. Наследники часто расширяют контракт базовых классов, достаточно взглянуть на классы .Net Framework. Почему? Такой подход часто оправдан при проектировании библиотек и фрэймворков. В этом случае базовый класс служит не столько для определения базового интерфейса, сколько для размещения логики взаимодействия с механизмами фрэймворка. Пример такой иерархии, компоненты .Net WinForms.

  10. Разделяйте команды и запросы (принцип QCS - Query Command Separation). Каждый метод должен представлять собой либо команду либо запрос. Метод-команда выполняет какие либо действия, и, возможно, изменяет состояние объекта. Метод-запрос возвращает данные объекта, но не меняет его состояние. Следование данному принципу вы всегда можете быть уверены, что состояние объекта остается неизменным, когда вы используете его данные, и всегда изменяется явно, при вызове методов-команд (к сожалению, возможности большинства языков не позволяет явно указать компилятору, что в методе не допустимо изменение состояния объекта).
    Правильно:


    class Counter
    {
    private int _value;
    public int GetCurrentValue(){ return _value}
    public void Increment(int delta) { _value += delta;}
    public void Decrement(int delta) { _value -= delta;}
    }


    Неправильно:


    class Counter
    {
    private int _value;
    public int GetCurrentValue(){ return _value}
    public int Increment(int delta) { _value += delta; return _value;}
    public int Decrement(int delta) { _value -= delta; return _value;}
    }


Театр абсурда: iPhone 3G в России

Все бросились продавать и покупать iPhone 3G. И никого не смущает тот факт, что сетей 3G у нас практически нигде нет, а без 3G толку от нового девайса - чуть.
Впрочем, все это уже становится традиционной национальной забавой. Мы закупаем из года в год миллионы новых автомобилей, но нам недосуг построить нормальные дороги для этих автомобилей. Именно недосуг, потому что только на одних автомобильных импортных пошлинах можно было бы пол России в асфальт закатать.
Такие инфраструктурные перекосы всегда были уделом отсталых, колониальных по своей сути экономик, и они очень четко характеризуют сегодняшнее положение России, сколько бы не надувало щеки наше уважаемое правительство.

пятница, сентября 12, 2008

Programmer's Day!

В этом году 256 (0x100) день выпадает на 12 сентября.
А посему, поздравляю всех коллег с профессиональным праздником, Днем программиста.
Желаю вам чистого и красивого кода, легкой и приятной отладки, и зеленой полосы в юнит-тестах. Горячего, ароматного кофе по утрам и холодного свежего пива по вечерам. Больших и светлых новых проектов и поменьше макарон легаси кода в поддержке. Маленького бэклога и большого бонуса. В общем, всего хорошего, чем богата наша с вами профессия!
С праздником, друзья!