2009-01-28

Perceived speed

I'm writing an app which basically performs the following steps in a wizard-like interface:
  1. Select an audio file of someone speaking + loads a text script in.
  2. Process the audio file and the script, can take about 5 seconds for a minute of audio.
  3. Select a character to use in the animation.
  4. Select some additional graphics and scene settings.
  5. Use the data generated in step #2.
Sitting there for 5 seconds wasn't really a problem, not to process a 1 minute audio file. A longer audio file would take a little longer, but 10-15 seconds is okay, isn't it? Well, what if I could make it take no time at all?

Obviously I can't, but I can make it look like it takes no time at all. The fact is that I don't need the processed data until Step 5. The user will probably spend at least 30 seconds twiddling settings in each Step 3 and 4. How much processing power does a bit of GUI interaction take? Hardly any at all!

So I made Step 2 run in a separate thread. As soon as the user clicks "Next" on step 1 they instantly see Step 3. They spend some time there and move onto Step 4. By this point the processing is probably already complete, if however it isn't I simply disable Step #4's "Next" button with a flashing label at the top of the form "* Processing Lip Sync". A 0.5 second timer keeps checking for the completed flag to be set, when it is the label disappears and the button enables.

Unless the user is rushing through the steps they are unlikely to get held up at all. The processing takes just as long as before (maybe a tad longer), but from the user's perspective it takes no time at all.

2009-01-27

Data Transfer Objects

My observations on data transfer objects

  1. They should not be a one to one representation of your domain classes.
    Sometimes you want a subset of the information of a single instance, sometimes your DTO will collect data from various instances (starting with an aggregate root). You might create different types of DTO from the same domain classes based on what the user needs to do. Sometimes the user only wants OrderNumber + DateRaised + TotalValue (to show as a list of orders), sometimes they want the entire order details (including lines) for editing.

  2. The domain classes should have no knowledge of your DTO classes.
    So you shouldn't have any methods such as

    pubic PersonDto CreateDto();
    public UpdateFromDto(personDto);

    DTO's are not part of the business domain, so you should never do this!

  3. The DTO you send out might not be the same type as you get back.
    For example you don't want the user to edit the order number or the date raised. If there are only a couple of properties like this you might opt to use the same DTO class but just ignore those properties when updating the domain instances, or you might decide on Request/Response DTOs

  4. The DTOs should have no knowledge of the domain classes.
    This is because the DTO classes will be shared between the client and the server, and the client will have no domain class knowledge. If you have domain classes on the client then you probably don't need DTOs.

  5. There is only one way to update domain instances from a specific DTO.
    A DTO doesn't always update domain classes, but when you receive a specific kind of DTO and need it to update domain instances it will always update in the same fasion.
So, how do you create DTOs from domain instances and how do you update domain instances from DTOs? The first thing to be aware of is that this code belongs in a layer above the domain layer, in a services layer or the app layer itself. Then we need some way of saying

  "I want to convert this Order to an OrderSummaryDto"

or

  "I want to convert this Order to an OrderDto, which includes its order lines"

and then finally

  "I have received a DTO, I need to update the relevant domain instances"

We need to do this in a reusable way, because the same DTOs may be reused in various parts of the application layer. To achieve this I used the Dependency Injection Container from Microsoft named "Unity".

Naming conventions I used are
  • xxxDtoFactory - Creates a DTO of a specific type from a specific domain instance.
  • xxxDtoTranslater - Takes a DTO of a specific type and translates its values back into the domain instances (updating existing instances, creating new instances, or whatever is required.)
The example model has a class named "Template" which has only a "string Name" property. It is an aggregate root so it owns multiple TemplateProperty instances. TemplateProperty is an abstract class with two concrete descendants; TemplateStringProperty and TemplateBooleanProperty.

When I create a DTO I want a TemplateDto and added to its Properties I want TemplateStringPropertyDto and TemplateBooleanPropertyDto. When I translate TemplateDto I want to update the existing object.

To register a factory
container.RegisterType<IDtoFactory<Template, TemplateDto>, TemplateDtoFactory>(
    new ContainerControlledLifetimeManager()
    );


The structure is IDtoFactory<TDomainClass, TDataTransferObject> to identify the domain class and desired DTO class, followed by the type that implements the interface to perform this DTO creation. This code registers a factory that takes a Template domain class and creates a TemplateDto data transfer object.

To register a translater
container.RegisterType<IDtoTranslater<TemplateDto>, TemplateDtoTranslater>(
    new ContainerControlledLifetimeManager()
    );


The structure is more simple. A DTO can only be translated in one way, so the generic IDtoTranslater interface only requires a single type, TDataTransferObject. This code registers a translater that takes a data transfer object and maps it to the domain.

Once registered the services are used like so:
//Create a template
Template template1 = new Template();

//Create a DTO from the template
TemplateDto template1Dto = container.Resolve<IDtoFactory<Template, TemplateDto>>().CreateDto(template1);

//Update the template from the DTO
container.Resolve<IDtoTranslater<TemplateDto>>().UpdateBusinessObjects(null, null, template1Dto);


Note that the "container.Resolve" code wouldn't really be there, you would use dependency injection. I have used it in this example to avoid turning it into a dependency-injection-container blog :-)

The "null, null" here are
  • The object space that the app layer has created and is using for your domain instances to work inside. Also known as your unit of work, transaction, or other.
  • An addition context. For example when updating a Template the TemplateDtoTranslater will resolve services to translate each PropertyDto it encounters, and pass the Template as the context so that we know which aggregate root we are working with.
For now I will link to the full source code for the example. If I get time I will blog some more explaining how the code works.

2009-01-20

How often should I test?

I am lazy.  I don't mean that I don't work, I mean that I like to get my work done with as little effort as possible.  Writing tests before my code used to look like too much extra work, but I've realised just how much time they actually save me.

When you make a small change to something it's very easy to think to yourself "That's such a small change, I can't see how it can possibly fail", what I have also realised is this really means "Despite this being a small change, it will fail and I can't possibly see how".

I recently observed a change to some code that introduced a simple if statement, and all existing tests passed.  The problem is that the existing tests only checked the expected behaviour worked (which it still did), but by introducing the "if" statement (and an additional parameter on the method) the developer had changed the expected behaviour under certain circumstances.  Thinking it was so simple it couldn't possibly fail he checked in his changes.  I happened to be changing something in the same code and spotted the changes, and realised immediately that his changes would actually result in files being deleted that are still required.

So, how often should you write tests?  I think this site sums it up very well
http://howoftenshoulditest.com

2009-01-09

InstallShield

Hmmm

Considering their product is an installer I'd expect it to install okay. It's been sitting here now for about 30 minutes with the progress bar at 100% and only the Cancel bar enabled.

Domain Driven Design by Eric Evans - my book review

To me this book has been a huge disappointment. Someone told me "Pete, there's a name for what you do!" and pointed me to this book.

Now personally I prefer technical books, as I read the Ubiquitous Language part at the start I thought to myself "Not technical, but fair enough some people will get value from being taught how to ask questions" and I stuck with it.

The first thing I must say that I cannot stand and which happens a lot in this book is over emphasis. When you want to emphasise something it needs to stand out. This book not only emphasises whole paragraphs but does it far too often too. Being an Internet user for some time now when I read upper case letters the imagined vocalisation actually SHOUTS at me, when I read bold my brain vocalises it as a loud and punctuated word, so when I read a whole paragraph in bold I, READ, EACH, WORD, LIKE, THIS; it makes it difficult to read.

Another thing I don't like when reading something is reading it for the Nth time. I don't mind a bit of reiteration in the way of reading something and then at the end telling me it is another example of "X" but only if the example is so different that it probably didn't occur to me. When I am on page 400+ I really don't want to be reading more examples of what I was reading in the first chapter. It really switches my brain off when so far into the book I am reading yet another example of "The Ubiquitous Language" that was covered at the start of the book. To be honest I am finding it very difficult to motivate myself to read the remainder of the book.

So, what have I learned from the book? I would say I have learned 1 valuable thing. Many times in the past I have modeled a parent/child association such as PurchaseOrder, and then modeled a kin-like parent/child such as Invoice/InvoiceLine, where the invoice is always for a single order and each invoice line is for a specific order line. In these circumstances I would have both Invoice.Order and InvoiceLine.OrderLine, everytime I did this I would cringe, it just felt "wrong" or "messy". Enforcing the idea that I should have no direct associations to the aggregated parts of the Order means that now I merely have Invoice.Order, it's easy to see which order line the invoice line is for because they are ordered the same and both the order and invoice are immutible. Now, I don't agree with the idea of never referencing an aggregated part, but at least now I consider the option. It certainly cleaned up a 3 kin-like aggregate part of the model I am currently working on.

For someone who doesn't know how to talk the "language of the current domain" with a customer I can see that this book could be useful, and also for people who need some pointers on how to segment their apps a bit.

When I read about people mentioning the "map of the world" example being such an eye opener (or whatever other way they express their positive experience) it honestly amazes me. The idea that a "Customer" to company A is completely different from how company B sees one as a break though just makes me shake my head in disbelief. In some businesses a customer is a company, in others a person, in others it could be either, and in one domain I worked a customer could have been either

A: A company
B: A department
C: An individual
D: A non physical entity such as a business process

All of which could also be a "Supplier". This is because they saw their Customers and Suppliers as things that consume and things that produce.

On the whole I personally found the book to be "a whole lot of nothing much at all", some of the personal stories were interesting but I also mainly found it repetitive and boring; a very difficult read. Unless the last 100 pages or so have something knock-out in them I expect I will remain very disappointed with it, if I ever manage to read the end that is.

Some people seem to be quite religious about this book, referring to it as "The book" and I feel by posting this negative review I might be opening myself up to attacks from DDD-extremists :-)

The fact is that I use parts of the DDD approach (now I at least know by what name to refer to it), it's just the book...