среда, 25 мая 2011 г.

TransportMock modifications

TransportMock -- is a mock replacement of real MSMQ transport. It allows us to handle all messages which come from Plugin and post any kind of messages to Plugin syncronyously.

Yesterday TransportMock was modified to serialize all messages which passed to it. It uses the same implementation of IMessageSerializer as in real NServiceBus which allows us to detect all serialization issues at early stages.


суббота, 14 мая 2011 г.

Open-Closed Principle in practice

The code can be clean, it should be clean!

Our day-by-day development life consists of very exciting new features implementation, but from time to time we need to get back to our old code.

Recently we were introducing Revision and RevisionFile entities CRUD commands support, so it was necessary to update the following code:



public class EntityLifecycleEventToMessageMapperRepository : IEntityLifecycleEventToMessageMapperRepository
{
private readonly List<IEntityEventArgsToMessageMapper> _mappers =
new List<IEntityEventArgsToMessageMapper>();

public EntityLifecycleEventToMessageMapperRepository(IMessageGateway gateway)
{
_mappers = new List<IEntityEventArgsToMessageMapper>
{
new AttachmentEventArgsToMessageMapper(gateway),
new AttachmentFileEventArgsToMessageMapper(gateway),
new BugEventArgsToMessageMapper(gateway),
new BuildEventArgsToMessageMapper(gateway),
new CommentEventArgsToMessageMapper(gateway),
new CompanyEventArgsToMessageMapper(gateway),
new ContactEventArgsToMessageMapper(gateway),
new CustomActivityEventArgsToMessageMapper(gateway),
new CustomFieldEventArgsToMessageMapper(gateway),
new CustomReportEventArgsToMessageMapper(gateway),
new EntityStateEventArgsToMessageMapper(gateway),
new FeatureEventArgsToMessageMapper(gateway),
new ImpedimentEventArgsToMessageMapper(gateway),
new IterationEventArgsToMessageMapper(gateway),
new MessageEventArgsToMessageMapper(gateway),
new MessageUidEventArgsToMessageMapper(gateway),
new MilestoneEventArgsToMessageMapper(gateway),
new ProcessEventArgsToMessageMapper(gateway),
new ProcessPracticeEventArgsToMessageMapper(gateway),
new ProgramEventArgsToMessageMapper(gateway),
new ProjectEventArgsToMessageMapper(gateway),
new ProjectMemberEventArgsToMessageMapper(gateway),
new ReleaseEventArgsToMessageMapper(gateway),
new RequestEventArgsToMessageMapper(gateway),
new RequesterEventArgsToMessageMapper(gateway),
new RoleEventArgsToMessageMapper(gateway),
new RoleEffortEventArgsToMessageMapper(gateway),
new RoleEntityTypeEventArgsToMessageMapper(gateway),
new RuleEventArgsToMessageMapper(gateway),
new SolutionEventArgsToMessageMapper(gateway),
new TagEventArgsToMessageMapper(gateway),
new TagBundleEventArgsToMessageMapper(gateway),
new TaskEventArgsToMessageMapper(gateway),
new TeamEventArgsToMessageMapper(gateway),
new TermEventArgsToMessageMapper(gateway),
new TestCaseEventArgsToMessageMapper(gateway),
new TestPlanEventArgsToMessageMapper(gateway),
new TestPlanRunEventArgsToMessageMapper(gateway),
new TimeEventArgsToMessageMapper(gateway),
new UserEventArgsToMessageMapper(gateway),
new UserStoryEventArgsToMessageMapper(gateway)
};
}
You see? This long list should be updated everytime when a new mapper related to specified
entities introduced, which is not funny.

Besides it explicitly violates Open-Closed Principle.
After a short discussion the code above was refactored into the following form:
public class EntityLifecycleEventToMessageMapperRepository : IEntityLifecycleEventToMessageMapperRepository
{
private readonly IEntityEventArgsToMessageMapper[] _mappers;

private static readonly Type[] MessageMapperTypes;

static EntityLifecycleEventToMessageMapperRepository()
{
MessageMapperTypes = ScanForMessageMappers();
}

public EntityLifecycleEventToMessageMapperRepository()
{
_mappers = MessageMapperTypes.Select(ObjectFactory.GetInstance).Cast<IEntityEventArgsToMessageMapper>().ToArray();
}

private static Type[] ScanForMessageMappers()
{
return Assembly.GetExecutingAssembly().GetTypes()
.Where(x => typeof (IEntityEventArgsToMessageMapper).IsAssignableFrom(x))
.Where(x => !x.IsAbstract)
.ToArray();
}

So now we won't touch this class anymore: it will find all IEntityEventArgsToMessageMapper implementations. All what we need is to define a new one and it will be automatically picked up.

воскресенье, 8 мая 2011 г.

Plugins: how to establish open-source development environment

We had a meeting where we were discussing some questions of how we can establish development environment to our customers which will allow them to revise our plugins source code and write their own extension plugins.

First of all, we need to create a source code repository to keep source code.

Github was chosen to play its role.


Commit Workflow


Establishing Plugin Development Environment
  1. Create a branch on keeper
  2. Create Tp.Integration.Plugin. folder in .\Code\Plugins folder
  3. Create a repo on Github named
  4. Link (1) and (3) repos via submodules defined in folder (2)
Github plugin repo will have the following common structure:

Unit Tests
Jenkins will scan plugin folder for *.nunit files and run them via nunit.console.exe.

Make sure that a folder with *.nunit file contains all necessary files to run unit tests.


вторник, 3 мая 2011 г.