пятница, 23 декабря 2011 г.

Система юнит тестов - логический компилятор вашего приложения

"A unit test is almost always written using a unit-testing framework" Roy Osherove, The Art of Unit Testing.
Всем привет.

Сегодня хотел поговорить о юнит тестах. Я не буду спорить о необходимости тестов в вашем проекте. Данный момент каждый определяет для себя. Кто-то считает, что это отстой, кто-то не может без них писать код, кто-то считает что именно на его проекте и в его команде это не нужно.
Сам я на данный момент нахожусь в стадии: "юнит тесты это круто, нужно и полезно, но сам я их никогда не использовал в реальном проекте и писать не умею".

Тему эту я решил поднять поскольку был на тренинге "TDD в .NET". Тренинг прошел круто, полезно и об этом можно почитать уже в нескольких отчетах. Просто спросите гугл: TDD в .NET на XPDays и он вам все расскажет.

Но что я вынес для себя и почему выбрал именно такой заголовок статьи, а не другой?
За свои скромные несколько лет работы я вынес одну банальную вещь - программисты народ ленивый, менеджерам всегда не хватает времени, поэтому хватит экспериментов, делайте как работает и не ерзайте. Соответственно, если вы хотите ввести какую-то полезную практику у себя на проекте, то в первую очередь позабодтесь об удобных инструментах для работы. Будь-то ревью кода, continuos integration, continous delivery.

Так вот возвращаясь к теме TDD. До тренинга я думал, что писать тесты до кода это сложно, непонятно, скучно. Но как оказалось наука ушла далеко вперед. Наши тренеры (Александр Белецкий @alexbeletsky и Сергей Калинетц @skalinets) показали нам связку из плагинов для студии и фреймворков для юнит тестов, которые делают разработку тестов удобной, быстрой, а их проверку и запуск настолько нативной, насколько для меня уже стала перекомпиляция проекта. Вам не нужно даже сохранять файлы с вашими изменениями в тестах и логике, для того чтобы видеть ошибки и проваленные тесты.
Потом, вечерком переваривая всю полученную информацию я и подумал о наборе юнит тестов, как об еще одном уровне компилятора - компиляторе вашей логики, который работает в фоновом режиме и сразу же проверяет насколько были правильными ваши изменения.

Инструменты следующие, очень советую посмотреть всем кто пишет на C#:
  • xUnit (NUnit) - фреймворки для юнит тестов
  • NSubstitude - фреймворм для создания моков(заглушек, пустышек для тестов)
  • Test Driven.NET - плагин, который позволяет запускать тесты под разными тулзами, и под дебагом в том числе
  • NCrunch - плагин, который в фоне запускает тесты и выдает вам красивый результат в картинках, визуально показывает покрыт ли ваш код тестами
Конечно следующим шагом стоит поднять все темы касательно написания сложных тестов, сложностей их реального применения и самое главное поддержки актуальности ваших тестов. Я этого делать не буду поскольку не имею такого опыта и могу только повторять чужие слова. Но сейчас мой проект использует .NET технологии, я обязательно попробую TDD и мы сможем похоливорить на эти темы в следующих постах.

Также отдельно постараюсь написать о тестах и инструментах в С++. Все-таки это мой родной язык и жаль, что ситуация там немного хуже. Очень буду рад пообщаться на тему реального, практического использования TDD и юнит тестов в С++. Какие инструменты вы применяли и как настроили воркфлоу?

Всем доброй ночи. 

вторник, 6 сентября 2011 г.

Simple Render. Интерфейс IRenderer

Продолжаем рассматривать демо с организацией простенького рендера. В прошлой заметке я рассмотрел интерфейс IEntity и его реализацию. Сегодня у нас очередь интерфейса IRenderer, который в моей схеме представляет view.
Интерфейс IRenderer достаточно прост и содержит всего один важный для нас метод render, метод в котором и будет находиться код по отрисовке той или иной сущности.
class IRenderer
{
public:
virtual ~IRenderer()
{
}
virtual void render()=0;
};
Посмотрим теперь простенькую реализацию данного интерфейса, для отрисовки объектов типа GameEntity, о которых я говорил в прошлой заметке.

class SimpleRenderer2D : public IRenderer
{
private:
GameEntity& m_Entity;
protected:
const GameEntity& getGameEntity()
{
return m_Entity;
}
public:
SimpleRenderer2D(GameEntity& entity);
virtual void render();
};
И соответственно дальше реализация метода render в данном классе:

void SimpleRenderer2D::render()
{
glPushMatrix();
glTranslatef(getGameEntity().getPosition().x, getGameEntity().getPosition().y, 0.0f);
glColor3ub(255,0,0);
glBegin(GL_QUADS);
glVertex2f(0,25);
glVertex2f(0,0);
glVertex2f(25,0);
glVertex2f(25,25);
glEnd();
glPopMatrix();
}
Теперь все выглядит, как мне кажется, просто и наглядно. Класс GameEntity не имеет никакого представления о классе SimpleRenderer2D, а значит мы можем добавлять и другие view для данного типа объектов, использовать их по своему усмотрению и это никак не отражается на нашей модели.

Остается только собрать все эти классы вместе и запустить наше приложение. Этим мы и займемся в следующей заметке.
Всем доброй ночи. 

вторник, 30 августа 2011 г.

Simple render. Интерфейс IEntity

Всем привет 

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

Интерфейс IEntity представляет любую игровую сущность, это базовый класс для любого игрового объекта. Он на самом деле не большой. Как мне кажется на таком уровне нужно только две вещи:
- сохранение и возможность получения уникального идентификатора нашего объекта
- возможность обновления объекта, выполнения в нем какой-то логики

Соответственно интерфейс имеет следующую реализацию 
       class IEntity
       {
              static unsigned long m_EntityIDCounter;
              int m_EntityID;

       public:
              inline int getEntityID()const
              {
                     return m_EntityID;
              }
              
       private:
              inline void setEntityID(int id)
              {
                     m_EntityID = id;
              }

       public:
              IEntity()
              {
                     setEntityID(++m_EntityIDCounter);
              }

              virtual ~IEntity()
              {
              }

              virtual void update() = 0;
       private:
       };
Целочисленное поле m_EntityID содержит уникальный идентификатор объекта, получить который можно через метод getEntityID, а устанавливается он автоматически при создании объекта. Для того чтобы обеспечить уникальной каждого идентификатора я использую статическую переменную m_EntityIDCounter. Думаю промежутка значений, который можно хранить в long нам хватит выше крыши для идентификаторов. 

Ну а для обновления объекта создан абстрактный метод update. На данный момент он не принимает никаких параметров. 

Идем дальше. В примере я создал только один класс наследник - это класс, который представляет двухмерный объект, как статический, так и динамический. Этот объект не содержит логики, но мы потом сможем это добавить, сейчас же это не важно. 
Вот код нового класса:
       class GameEntity : public IEntity
       {
       private:

              glm::vec2 m_Position;
       public:
              inline const glm::vec2& getPosition()const
              {
                     return m_Position;
              }

              inline void setPosition(const glm::vec2& pos)
              {
                     m_Position = pos;
              }

       public:
              GameEntity();

              virtual void update();
       };

Конструктор просто инициализирует позицию нулями 
       GameEntity::GameEntity()
       {
              m_Position.x = m_Position.y = 0.0f;
       }
А метод update вообще пока не содержит логики
       void GameEntity::update()
       {
       }

Собственно все. 
Теперь у нас есть модель, которую нужно визуализировать. Осталось только дописать вид и все будет в шоколаде. 

Всем доброй ночи.

воскресенье, 21 августа 2011 г.

Simple render. Описание идеи

Всем привет. 

Представляю вашему вниманию первую часть цикла для начинающих об отрисовке в играх. 
Сегодня мы рассмотрим идею в общем и набросаем стартовое приложение. 
Для работы с рендером я буду использовать библиотеку glut. В принципе она сейчас практически не используется, но нам подойдет идеально. Использование glut позволит мне сосредоточится на структуре классов и не отвлекаться на разбор OpenGL или DirectX.

Погнали. 
Идею построена на паттерне MVC, т.е. на разделении данных и их визуального отображения. 

Давайте рассмотрим основные классы и интерфейсы, их в моей схеме 3: 
Renderer - этот класс отвечает за весь рендер в целом, он хранит в себе список всех объектов, которые нужно отобразить в игре, знает порядок их отображения. Также он отвечает за различные действия с рендер конвеером, которые необходимо выполнить в начале каждого кадра и соответственно в конце. 
IEntity - этот интерфейс является базовым для всех объектов с данными, которые находятся в нашей игре. Каждая сущность имеет свой уникальный идентификатор. Одним словом  это model.
IRenderer - данный интерфейс является базовым для всех объектов рендера в игре. Он отвечает за визуализацию модели данных, т.е за визуализацию игровых сущностей. Это view.

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

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

int _tmain(int argc, _TCHAR* argv[])
{
     /// блок инициализации окна
     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
     glutInitWindowSize(800, 600);
     glutCreateWindow("Simple");
     /// устанавливаем различные калбек функции, которые будет вызывать glut
     glutDisplayFunc(renderScene);
     glutReshapeFunc(Reshape);
     glutKeyboardFunc(Keyboard);
     setupRC();
     // запускаем основной цикл приложения
     glutMainLoop();
     return 0;
}

Самый интересный для нас метод renderScene. Именно в него мы будем встраивать код по отрисовке. 
Сейчас он имеет следующий вид:

 void renderScene(void)
{
     //очищаем экран
     glClear(GL_COLOR_BUFFER_BIT);
     // устанавливаем матрицу для нашего объекта
     glPushMatrix();

     glTranslatef(-200.0f+pos, 0.0f, 0.0f);
     // отрисовываем квадрат красного цвета на экране.
     glColor3ub(255,0,0);
     glBegin(GL_QUADS);
         glVertex2f(200,400);
         glVertex2f(200,200);
         glVertex2f(400,200);
         glVertex2f(400,400);
     glEnd();

     glPopMatrix();
     // вызываем свап буфера для того, чтобы наша картинка появилась на кране монитора
     glutSwapBuffers();
     glutPostRedisplay();
}

На сегодня это все. В следующий раз я подробно пройдусь по интерфейсам, покажу реализацию класса Renderer. 
Весь код стартового приложения можно посмотреть здесь. Для использования glut нужно подключить статическую либу к проекту, а потом рядом с исполняемым файлом положить dll библиотеку. Все есть вот тут

Всем доброй ночи.

среда, 17 августа 2011 г.

Simple render. Вступление


Всем привет.

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

Описание разбил на несколько частей:
1. Общее описание и создание окна с помощью glut
2. Интерфейс IEntity
3. Интерфейс IRenderer
4. Renderer и запуск финального приложения.

Вот ссылка на исходники примера для тех, кому код понятнее, чем мои сбивчивые описания.
Для написания примера я использовал Microsoft Visual Studio C++ Express 2010.

Всем доброй ночи.

среда, 29 июня 2011 г.

Книги для легкого чтения

Под влиянием книги "Бесцельная жизнь" от издательства Манн, Иванов и Фербер набросал для себя список книг от успешных людей. Вот он:
1. Генри Форд "Моя жизнь, мои достижения"
2. Дональд Трамп "Никогда не сдавайся"
3. Ли Яккока "Карьера менеджера"
4. Наполеон Хилл "Думай и богатей"
5. Ричард Бренсон "Теряя невинность"

О всех книгах много слышал, надеюсь для себя почерпнуть много интересного. Но основная цель - выделить хорошие привычки этих людей и попробовать привить их себе. К тому же такие книги являются для меня отличными мотиваторами.

А что мотивирует вас?

Всем доброй ночи.

пятница, 1 апреля 2011 г.

cURLpp: реализация комбинации С++ и WEB

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

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

Вначале решил использовать C# и .Net Framework, но потом выяснились дополнительные требования:

  1. приложение должно быть кросплатформенным: Mac, PC UNIX
  2. приложение неплохо бы реализовать в виде плагина к SVN, который как известно реализован на плюсах. 

После недолгих рысканий набрел на библиотеку cURLpp, которая является оберткой над libcURL. Вот определение библиотеки на сайте:

a free and easy-to-use client-side URL transfer library, supporting FTPFTPSHTTPHTTPSGOPHERTELNETDICTFILE and LDAP. libcurl supports HTTPS certificates, HTTP POSTHTTP PUTFTP uploading, kerberos, HTTP form based upload, proxies, cookies, user+password authentication, file transfer resume, http proxy tunneling and more!

libcurl is highly portable, it builds and works identically on numerous platforms, including Solaris, NetBSD, FreeBSD, OpenBSD, Darwin, HPUXIRIXAIX, Tru64, Linux, Windows, Amiga, OS/2, BeOs, Mac OS X, Ultrix, QNX, OpenVMS, RISC OS, Novell NetWare, DOS and more…

libcurl is free, thread-safe, IPv6 compatible, feature rich, well supported and fast.

 

К сожалению еще не пробовал данную библиотеку на ощупь. Как только попробую, отпишусь. Пока все выглядит отлично, я смогу сделать все что мне нужно. 

 

А вам приходилось решать аналогичные задачи? Какие решения предпочли вы?

 

Всем доброй ночи.

 

четверг, 20 января 2011 г.

Command Window and Macros in Visual Studio. Part 2

Всем привет.

В прошлой статье я рассматривал работу с командной строкой в Microsoft Visual Studio. Сегодня мы продолжаем ковырять студию и рассмотрим работу с макросами в студии. Одним из самых мощных инструментов для автоматизации работы.

Поскольку рассматривать что либо на абстрактных примерах себе дороже, то для начала небольшая пред-история. 

У нас на проекте для сборки игры используется Nant. Тем кто не знаком с этой системой советую ознакомиться. А пока небольшая вводная. Nant  это система, которая позволяет выполнять из командной строки различные команды. Реализован он на С# и доступен вместе с исходниками. Но основным достоинством Nant является широкий набор команд, а также возможность писать свои собственные команды на любом скриптовом или компилируемом языке, главное чтобы этот скрипт или скомпилированное приложение можно было выполнить из командной строки. 

У нас на проекте с помощью Nant собирается все, начиная от артовых ресурсов и заканчивая исходным кодом. Соответственно есть команды BuildGameCode, BuildGameAnimation, BuildLevel  и т.д.

Для конфигурации команд используется конфигурационный xml файл. 

Единственное неудобство, что пишу код я в студии, а вот для запуска команд приходиться использовать что под руки попадется. Одно время запускал просто из виндовой командной строки, потом использовал Luancher, потом использовал Notepad++. Правда в последнем случае кодировать тоже приходилось в блокноте, что не всегда удобно. 

Вот после всех скитаний попробовал использовать макросы в Visual Studio и получилось достаточно неплохо.

Использование макросов имеет несколько неоспоримых плюсов:

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

Но как всегда есть и несколько минусов:

  • писать макросы можно только на Visual Basic .Net
  • макросы это единичные команды - они хороши когда нужно выполнить быстрое, конечное действие, но когда вам нужно, что постоянно выполнялся некий процесс в фоне, то лучше использовать плагины

И еще один момент, который я пока не могу занести в минусы - это создание диалоговых окон. Предположим вы хотите, чтобы при вызове вашей команды открылось диалоговое окно (которое вы предварительно задизайнили) потом вы ввели некие значения в поля окна и нажав клавишу "Enter" получили результат. Так вот я не знаю, можно ли создавать свои окна, не успел проверить. 

Вернемся к моему примеру. Итак я создал макрос, который позволяет запустить любую команду или набор команд из командной строки в студии. Лог при этом выводится в это же командное окно, что позволяет мне его потом легко проанализировать и сохранить в файл. Также я написал команду, которая позволяет поменять любое поле xml файла конфигурации, например имя уровня с которого нужно стартовать. 

Следующая возможность, которую я хотел получить от макросов, это возможность снипетты, которых нет в студии ни для С++, ни для Lua. 

С макросами этот момент также оказался достаточно простым. Я создал текстовый файл, некий шаблон, в котором есть специальные символы $1, $2 и т.д. При вызове команды, текст из файла вставляется в код и символы заменяются параметрами, которые были переданы в команду. Вот и у нас есть снипеты. 

Всем доброй ночи. 

360: смотри да оценивай

Вот зацепился за методы оценки персонала. Один из них понравился и здесь результат небольшого исследования

Методика 360 ориентирована на то, чтобы получить максимально объективную оценку сотрудника. Основное достоинство «круговой оценки» в том, что она позволяет получить полную картину личностных и профессиональных качеств, знаний и умений сотрудника.

 Ключевые моменты методики:

 Сотрудника оценивают:

  • Подчиненные
  • Коллеги (те кто находиться на одном уровне иерархии с сотрудником)
  • Руководство
  • Клиенты (не обязательно)

Оценивание анонимное, при этом указывается только к какой группе оценивания принадлежит тот, кто дает оценку (коллега, подчиненный и т.д.)

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

Оценка проводится раз в полгода/год

Как работает:

  1. Для каждой должности определяется свой набор наиболее важных компетенций, качеств (5-15)
  2. Для каждого качества определяется свой набор идентификаторов, поведенческих примеров (чаще всего 5, иногда 10)
  3. Оценщики, которых обычно 5-15 человек, выставляют по каждой компетенции оценку и потом подбивается статистика.
  4. На завершающем этапе результат доноситься до сотрудника и составляется план развития 

Например:

Компетенция – инициативность

Критерии

  1. никогда не проявляет инициативу, явно уклоняется от принятия решения по вопросу своей компетентности;
  2. инициативу для достижения поставленных целей проявляет крайне редко или проявляет неадекватно решаемой задаче;
  3. проявляет разумную инициативу для достижения поставленных целей;
  4. стремится постоянно проявлять разумную инициативу, не ждет указаний, инициирует действия;
  5. высокая степень проявления инициативы, в любой ситуации ищет и находит творческие подходы для достижения поставленных целей

Я считаю, что применение данной методики было бы целесообразно как минимум для лидов и ключевых сотрудников любой компании. Т.е. на том уровне, когда просто знания языков программирования или технологий становится мало.

 Ресурсы, где можно ознакомиться с методикой 360 более подробно:

Для меня остались еще открытыми 2 вопроса:

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

А что вы по этому поводу думаете? Буду рад услышать кто как оценивает коллег, подчиненных.

Всем доброй ночи