Byndyusoft — это заказная разработка ПО с гарантией результата

Создаем IT-продукты для e-commerce, ритейла, банков и других бизнесов по всему миру. Одни из лучших в стране по реализации высоконагруженных систем и микросервисной архитектуре.

Помимо непосредственной реализации IT-решений, создаем стратегию развития IT-продуктов.

Посмотрите, что говорят о нас клиенты и как комфортно мы стартуем проекты.

Для обсуждения проекта пишите на ceo@byndyusoft.com или звоните +7 (904) 305 5263

воскресенье, 14 декабря 2008 г.

Исследования на тему Test-First Development

Сейчас очень многие говорят о разработке через тестирование. Мы уже обсуждали мантру TDD и делились своими впечатлениями и опытом на местных встречах.

четверг, 4 декабря 2008 г.

Технические долги

Определение

Этот термин впервые ввел Ward Cunningham:

  • Технические долги включают ту работу в проекте, которую мы решаем не делать в данный момент, но которая будет мешать развитию проекта в дальнейшем, если не будет выполнена.
  • Технические долги не включают отложенную функциональность, которая была бы хорошим дополнением к проекту, но в данный момент имеет низкий приоритет (например, улучшенный интерфейс пользователя)

среда, 19 ноября 2008 г.

Хороший коммит

Совсем недавно в очередной раз столкнулся с проблемой комитов и вообще отношения к хранилищу кода в команде. Этот вопрос очень часто поднимается в таких книжках, как Code Craft. Как показывает практика, ничего от этого не меняется. Либо книжки не читают, либо не знают, как применять на практике полученные знания.

Я уже начинаю думать, что основная причина - это лень. Или программирование в стиле "агонии". Так я называю печатание 10000 символов в час без передышки с полной самоотдачей и без коммитов. Хватаются то за одну задачу, то за другую. И на вопрос: "Почему уже 2 дня не коммитишь?", можно услышать: "Дак у меня еще не до конца функциональность готова. Вот еще немного подшлефую и закомичу".

Чтобы понять как делать хорошие коммиты, необходимо ответить на вопрос, что такое хороший комит?

Хороший комит:

  • Должен быть прокомментирован. Нельзя комитить изменения в общее хранилище кода без комментария
  • Содержит комментарий с информациeй о том, зачем (почему) этот комит был сделан (добавление новой функциональности, исправление бага и т.п.). Комментарий должен пояснить какие изменения были внесены в проект без необходимости просмотра кода
  • Оставляет систему в стабильном рабочем состоянии
  • Содержит единственное атомарное изменение. Не должен содержать изменения, которые не относятся к данному комиту. Возможно, эти изменения кода были сделаны в ходе рефакторинга или небольших багфиксов. Все эти изменения должны попасть в другой комит с соответствующим комментарием
  • Отформатирован в стиле, который приняла вся команда
  • Может содержать ссылку на тикет в вашей системе контроля багов. В некоторых организациях комит не принимаются без закрытия тикета
  • Закомиченный код не должен содержать закомментированного кода, который "оставили на всякий случай"

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

Ссылки:

The importance of commit messages

Are Detailed Log Messages Really Necessary?

SVN Commit Policy

SVN и отсутвие мозга у кодера

Best Practices for Version Control

Everyone Commits Every Day

пятница, 14 ноября 2008 г.

TechDays в Екатеринбурге

12ого ноября в Екатеринбурге прошла конференция TechDays.

Такие встречи всегда радуют меня и моих друзей, потому что есть возможность пообщаться с разработчиками из других городов и узнать последние новости из мира IT.

Как всегда были приятные мелочи от Microsoft - ручка, блокнот, DVD диск с записанными докладами и еще много всего. По ходу дела разыграли пару забавных сувениров.

Для всех осталось немного непонятно, почему не было докладов по самым последним тема и технологиям, таким как: ASP.NET MVC, WPF, Silverlight, ADO.NET Entity и т.д. Я, естественно, ничего не имею против Sharepoint, но по моему мнению это не "острие атаки". Зато теперь есть повод обсудить все это в нашей юзер группе.

Спасибо ребятам, которые делали доклады и всем кто присоединялся к обсуждениям в перерывах!

воскресенье, 9 ноября 2008 г.

Впечатления и материалы со встречи SUNETA на тему "Гибкие методологии разработки"

Вчера прошла первая встреча Южно-Уральского сообщества .NET разработчиков на тему "Гибкие методологии разработки".

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

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

Материалы моего доклада можно скачать здесь http://alex-byndyu-presentations.googlecode.com/svn/trunk/Dependency Inversion - Chelyabinsk 07.11.2008

четверг, 6 ноября 2008 г.

Паттерн MVP для ASP.NET WebForms

Сейчас разрабатываю проект на ASP.NET. Для отделения представления данных в слое отображения от логики их формирования и обработки применяю паттерн Model-View-Presenter.

Суть паттерна в том, чтобы ASP.NET форма (View) реализовывала интерфейс, с которым сможет работать представление данных (Presenter), которое в свою очередь оперирует объектами предметной области (Model).

воскресенье, 2 ноября 2008 г.

Red-Green-Refactoring. Зачем красная полоска?

Для «прожженых» TDD программистов это уже уже не вопрос. Воспринимайте эту статью, как заметку. Я сам иногда ленюсь смотреть на красную полосу, но заставить себя обязательно надо. Теперь будет ещё один повод - раз написал про это, значит и сам должен подавать пример!

среда, 29 октября 2008 г.

TDD и LLBLGen Pro

LLBLGen Pro - это O/R mapper, который генерирует .NET код, основываясь на схеме в базе данных.

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

воскресенье, 26 октября 2008 г.

Тесты вперед?

Многие меня спрашивают: "Не жалко тебе тратить время на написание тестов?". Могу ответить коротко: "Нет".

суббота, 25 октября 2008 г.

Exception logic?

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

> calculator.exe 1 + 2

После чего должен показаться результат.

Мы сели вместе за компьютер и начали конечно же с тестов. Постепенно вырисовывалась логика приложения. Мы решили, что у нас будет объект AgrumentParser, который принимает массив аргументов командной строки в конструкторе и проверяете их. Потом у этого класса можно узнать значение первого операнда, операцию, которую он уже преобразовал в enum, и второй операнд.

   1:  public enum OperationType
   2:  {
   3:      None = 0,
   4:      Add,
   5:      Min,
   6:      Plus,
   7:      Div
   8:  }
   9:   
  10:  public class ArgumentParser
  11:  {
  12:      private double firstOperand;
  13:      private double secondOperand;
  14:      private OperationType operationType;
  15:   
  16:      public ArgumentParser(string[] args)
  17:      {
  18:      // заполняем переменные firstOperand, secondOperand и operationType из args
  19:      }
  20:   
  21:      public double FirstOperand
  22:      {
  23:          get { return firstOperand; }
  24:      }
  25:   
  26:      public OperationType OperationType
  27:      {
  28:          get { return operationType; }
  29:      }
  30:   
  31:      public double SecondOperand
  32:      {
  33:          get { return secondOperand; }
  34:      }
  35:  }

К тому же мы завели очень интересный спор. Суть его вот в чем - если пользователь ввел аргументы в неверном формате (например, 1 плюс 2), как вести себя классу, который "оборачивает" эти аргументы? Если аргументы неверные, то как можно обратиться к полю FirstOperand? Должны мы выбрасывать исключение или же добавить поле IsArgumentValid в класс ArgumentParser?

Здесь нам виделось 2 основных подхода:

  1. Т.к. состояние объекта после передачи ему неверных аргументов будет не определено, то сам объект должен выбрасывать исключение. Соответственно его клиент, должен ловить это исключение и обрабатывать ошибку.
  2. После того, как создан класс ArgumentParser из параметров командной строки, мы должны узнать у него на сколько эти параметры верны, т.е. вызвать у него свойство IsArgumentValid.

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

В данном примере это абсолютно оправдано:

   1:  using (var adapter = new DataAccessAdapter(false))
   2:  {
   3:      try
   4:      {
   5:          adapter.SaveEntity(entity, false, false);
   6:      }
   7:      catch
   8:      {
   9:          adapter.Rollback();
  10:          throw;
  11:      }
  12:      adapter.Commit();
  13:  }

А что если ваш модуль при обращении к нему может выбрасывать свои определнные исключения? Как работать с такой "исключительной" логикой?

Так:

   1:  Customer customer = CustomerFactory.Create();
   2:  if (customer.IsLoaded)
   3:  {
   4:      // обычная логика
   5:  }
   6:  else
   7:  {
   8:      // альтернативная логика
   9:  }

или так:

   1:  try
   2:  {
   3:      Customer customer = CustomerFactory.Create();
   4:      // обычная логика
   5:  }
   6:  catch(NotLoadedException)
   7:  {
   8:      // альтернативная логика
   9:  }

Возвращаясь к примеру с консольным калькулятором.

Первый вариант:

   1:  var parser = new ArgumentParser(args);
   2:  if (parser.IsArgumentValid)
   3:  {
   4:      // работаем с аргументами и производим операцию выбранную пользователем
   5:  }
   6:  else
   7:  {
   8:      // показываем пользователю формат работы с нашим приложением
   9:  }

Второй вариант:

   1:  try
   2:  {
   3:      var parser = new ArgumentParser(args);
   4:      // работаем с аргументами и производим операцию выбранную пользователем
   5:  }
   6:  catch(ArgumentException)
   7:  {
   8:      // показываем пользователю формат работы с нашим приложением
   9:  }

Лично я склоняюсь к первому варианту. Какие будут мысли?



Примечание

Crypto привел отличный аргумент против логики построенной на исключениях.

пятница, 24 октября 2008 г.

Использование паттернов Strategy и Registry

Слишком много получилось писать в комментарии, решил вынести в отдельный пост.

В приведеном случае, когда логика постоянно меняется (пример кода в моем комментарии на пост Евгения), действительно лучше всего подойдет паттерн Visitor.

Но для такого простого варианта, когда классу ClassA соответствует определеная функция, лучше все-таки использовать Стратегию.

Хочу предложить модификацию реализации стратегии Евгения.

Лучше вынести информацию о сопоставлении типа класса к IHandler в отдельную сущность. Т.е. создать статический Регистр с тем же словарем.

   1:  public class BaseClass
   2:  {
   3:  }
   4:   
   5:  public class ClassA : BaseClass
   6:  {
   7:  }
   8:   
   9:  public interface IHandler<T> where T : BaseClass
  10:  {
  11:      void DoFor(T obj);
  12:  }
  13:   
  14:  public class MyClass
  15:  {
  16:      public void DoSomethingWith<T>(T obj) where T : BaseClass
  17:      {
  18:          // какая-то логика
  19:   
  20:          HanlderRegistry.Get<T>().DoFor(obj);
  21:      }
  22:  }
  23:   
  24:  public static class HanlderRegistry
  25:  {
  26:      private static readonly Dictionary<Type, Type> _handlers = InitHanlders();
  27:   
  28:      private static Dictionary<Type, Type> InitHanlders()
  29:      {
  30:          return new Dictionary<Type, Type>
  31:          {
  32:              {typeof (ClassA), typeof(HanlderForClassA)}
  33:          };
  34:      }
  35:   
  36:      public static IHandler<T> Get<T>() where T : BaseClass
  37:      {
  38:          Type hanlderType = _handlers[typeof (T)];
  39:          return Activator.CreateInstance(hanlderType) as IHandler<T>;
  40:      }
  41:  }
  42:   
  43:  internal class HanlderForClassA : IHandler<ClassA>
  44:  {
  45:      #region Implementation of IHandler
  46:   
  47:      public void DoFor(ClassA obj)
  48:      {
  49:          // логика работы с классом ClassA
  50:      }
  51:   
  52:      #endregion
  53:  }

Здесь, HanlderRegistry - это единственное место, в котором происходит сопоставление обработчиков и подклассов BaseClass.

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

Если приводить пример более приближенный к реальности, то таким образом можно связать объект и его маппер в базу данных.

Byndyusoft — это заказная разработка ПО с гарантией результата

Создаем IT-продукты для e-commerce, ритейла, банков и других бизнесов по всему миру. Одни из лучших в стране по реализации высоконагруженных систем и микросервисной архитектуре.

Помимо непосредственной реализации IT-решений, создаем стратегию развития IT-продуктов.

Посмотрите, что говорят о нас клиенты и как комфортно мы стартуем проекты.

Для обсуждения проекта пишите на ceo@byndyusoft.com или звоните +7 (904) 305 5263