Tuesday, May 22, 2007

Upgrade Issues Resolved

I think I have the upgrade issues resolved.

Hopefully now the comments will work!

Wednesday, May 16, 2007

Pardon The Dust

My blog has received a long overdue face-lift.

I was getting a little tired of the previous black background design and wanted something cleaner.  I also upgraded to dasBlog 1.9, which proved to be more than just a walk in the park.  Things are still a little broken around here, but I will get it resolved sooner or later.  I hope you don’t mind a few broken links and things while I settle this new design in.

During all of this I was really pondering switching to Subtext.  It seems like a equivalent stature blogging enging on the ASP.NET 2.0 platform, however it supports databases.  Das Blog is all about the file system, which makes it easy for people to host if they don’t have access to a database.  But since I have over 2 years of content up here, not only does it take a long time to transfer over ftp, but when I upgrade I cannot simply copy files over.  I have to be very careful and selective and I usually end up messing up something.  (This is why I always back it up before I start).

I know that database support is on the roadmap for Das Blog, but I don’t know how long it will be.  We shall see.

Until then, enjoy the new design .  Please let me know what you think in the comments!

Tags:
Monday, April 23, 2007

Paris - Day 1

My company, Sogeti, has sent me to the beautiful county of France to attend a global enterprise SOA training from some of the folks at IBM.

So far, France is absolutely gorgeous.  I braved the subway system with my friend Aaron Murrell, which was very humorous.  We got a bit turned around a few times, but we eventually found our stop.

Streets of Paris

old building

We noticed that people park crazy in Paris…

Smart car parking job

We went into Paris and tried to find a restaurant called Chartier, however we couldn’t locate the street.  A quaint restarant called Le Flash caught our eye and we walked in.  The owner greeted us with many french words (which I do not understand) and we had a fun time ordering our food and communicating with him.  The food was excellent, the beer was even better, and the owner even played Alan Jackson for us, ha!  I don’t care for country music, but it was funny and appreciated nonetheless.

Le Flash

We then took a taxi north to the city of Gouvieux where the corporate chateau resides.  It really is breath-taking.  It was built by Eiffel a long time ago, and is now home for our Capgemini University (well, the bar and dining area, that is).

Le Chateau

We start our training tomorrow and I’m sure our day will be full of introductions and hands-on training.

 

Tags: ,
Thursday, April 19, 2007

Review - Agile Principles, Patterns, and Practices in C#

Robert Martin has a great book here.  I just finished reading Agile Principle, Patterns, and Practices in C# (what a mouthful!). 
 
In this book you get a fantastic play-by-play of a typical TDD/pairing session, which I think is a great way to demonstrate the process. 
 
This was also the book that really got me to appreciate UML for what it is.  I'm typically the guy who knows the UML basic shapes, and draws a bunch of interconnected rectangles on a whiteboard to help me solve problems.  I was never a "fan" of UML because I always associated it with the monolithic CASE tools that use UML as the source for an architecture, and out spits generated code.  The book described what Martin feels are the essential (read: useful) components of UML and really abandons the rest.  He emphasizes throwing away your diagrams when you're done and encourages writing them on a napkin or a whiteboard, which is infinitely faster than, say, Visio.
 
The section on patterns is well written, and it is always nice to get refreshers on patterns that you might not know about or haven't used recently.  Again he emphasizes not to go crazy with patterns.  They are there when they help, but don't be shy about throwing them out when they complicate things.  Indeed, this book is agile.
 
The final section (or rather 1/3 of the book!) goes about a payroll system.  He does a bit of UML to get the basic idea in his head and then he goes straight to the tests.  He fleshes out the entire thing, right there in the text.  The model changes, the tests drive the design and behavior, and he frequently consults with his "Customer" (himself) over what the requirements are.  After he has a working model that is fully tested, he bolts on persistence using a custom ADO.NET pproach, which is difficult.  Seeing him do this reminds me of how I like to use NHibernate, but I found it difficult to repeat this approach using flat ADO.NET calls.
 
I'm thoroughly impressed with this book.  If any of the topics above interest you, then go pick it up!
Wednesday, April 18, 2007

TargetProcess - First Impressions are Everything

I ran across a link to TargetProcess today and I thought I’d check it out.  All I knew about it was that it is some kind of “agile tool.”

I visit the website and it looks promising.  Clean graphics, simple usable navigation:

Team Proces Home pageAll I want to do is see what it is, what it looks like, and whether I think that it’s worth investigating further.  With my typical attention span, a given product better impress me within 15-30 seconds, otherwise I’m off to do something more productive.  First impressions are everything.  The last thing you want to do is waste a potential customer’s time.

 

So I click on See.  I’d rather see some screenshots than try a demo.  The first option on that small page is Try the Demo.  Umm, okay I’ll try the demo then.  The demo page says that any username and password will work.  Great, that will save me time and not get in my way.  I click on the demo.

 It asks me to submit my name, company, and email address.  I enter in random garbage.  (At this point they don’t deserve my info because I don’t know yet if I’m interested!  I can understand that they want some usage information and the ability to generate leads, but come on!  Wait until I’m excited first!).  The email address needs to be validated.  I change asdf to asdf@aol.com.

 Ah, finally the demo (1 minute 30 seconds after I initially viewed their page).  I try to login with my standard set of credentials:  asdf/asdf.

 ERROR.

  error logging in

Hrm, and exception was thrown while logging in.  Not a good sign.  At least they were nice enough to let me notify them without opening my email client.  I click on the Notify Support button.

ERROR.

Error sending email. 

At this point I am thoroughly annoyed.  I have wasted about 3 minutes (now more like 10 since I felt the need to write this blog post J ).

 I eventually went back and looked at the screenshots and ended up a little intrigued.  I saw what the app looks like, I saw how it allows me to manage an agile project and collect the information and display the metrics I am likely to care about.  Really the screenshots were their best sales tactic, not the online demo.

 Hopefully they will fix this soon so that other potential buyers won’t shy away from their product too early.  It would be a shame because it looks like a useful tool.

 The bottom line:  Your customers are impatient.  Don’t waste their time.  Don’t shoot yourself in the foot with a live demo if the live demo doesn’t work.

UPDATE:  I was able to figure out from the error that the issue is a unique value violation.  Apparently a lot of people type in a username of ‘asdf.’  Type in a unique name and it will work.

 

Wednesday, April 11, 2007

My Presentation on ORM with NHibernate

A couple of weeks ago I gave a presentation on Object Relational Mapping with NHibernate.

We talked about:

  • Basic Concepts
  • Getting Started, watching what SQL gets generated for various actions
  • Architecture, querying, etc
  • A live Blog example done with TDD

A number of people came and watched me drown in code, but I think all-in-all it was a good time and I think I conveyed a lot of information in a small time-frame.

Anyway, I recorded the presentation.  You can download it below.  You will need the TechSmith Video Codec to view it.

A few times I was asked questions by the audience and I didn’t repeat the question, so hopefully you will be able to infer a bit. 

I’d appreciate your feedback if you watch it, it’s about 1 hour and 45 minutes (ouch!).

File Attachment: ORMWithNHibernateScreenCast.wmv (64824 KB)

 

Wednesday, April 04, 2007

Billy Does It Again With NHibernate Best Practices

If you’re interested in NHibernate, or are already using it then run over to Code Project and check out Billy McCafferty’s updated article on NHibernate Best Practices with ASP.NET (1.2).

Billy hits the nail on the head with a number of issues and is able to address “real” development topics in depth.  He obviously knows his stuff.

Thursday, March 15, 2007

Writing a Simple Image Editor in CAB - Part 4

In today’s installment we’ll continue where we left off and add the functionality to apply image filters.

In order to do this, let’s take a step back and think about how we want to accomplish this.  I’m imagining two use cases:

  • Load filters from dynamic assemblies
  • Apply a filter to the image

To load the filters, I’ll have a separate assembly implement a specific interface, then they will be loaded from a directory and placed in the menu.

First, our core interface:

using System;

using System.Drawing;

 

namespace ImageFiltering

{

    public interface IImageFilter

    {

        string Name { get; }

        Bitmap Filter(Bitmap source);

    }

}

The name property determines what will be displayed on the menu.  The Filter method is, as they say on MTV Cribs, “where the magic happens.”

I’ll implement some basic image filters in a bit.  Since both of these use cases are related, I can package them up in the same module.  I create a module called ImageFiltering.

The first workitem is going to be the LoadFiltersWorkItem.  It will run at startup and read up the assemblies and obtain a list of IImageFilter implementations:

private UIExtensionSite GetMainMenu()

{

    //return the well known ui extension site for the main menu

    return RootWorkItem.UIExtensionSites["MainMenuStrip"];

}

 

protected override void OnRunStarted()

{

    base.OnRunStarted();

 

    //get the menu strip

    UIExtensionSite site = GetMainMenu();

 

    //create the new menu item

    ToolStripMenuItem filterMenu = new ToolStripMenuItem();

    filterMenu.Text = "Filters";

 

    //load the filters

    LoadFiltersFromDirectory(filterMenu);

 

    //add the filters menu to the site

    site.Add<ToolStripMenuItem>(filterMenu);

}

The LoadFiltesrFromDirectory(filterMenu) method basically uses reflection to pull out all of the assemblies in the /filters directory of our application.  The details of this aren’t important here, but if you want to see it you can download the project at the end of today’s article.

Since this needs to run when the application starts up, we code that up in the Module Init class:

public class ImageFilteringModuleInit : ModuleInit

{

    private WorkItem _rootWorkItem;

    [ServiceDependency]

    public WorkItem RootWorkItem

    {

        get { return _rootWorkItem; }

        set { _rootWorkItem = value; }

    }

 

    private LoadFiltersWorkItem _loadFiltersWorkItem;

 

    public override void Load()

    {

        base.Load();

 

        //load up our work items

        _loadFiltersWorkItem = this.RootWorkItem.WorkItems.AddNew<LoadFiltersWorkItem>("LoadFiltersWorkItem");

        _loadFiltersWorkItem.Run();

    } 

}

This is pretty basic Module Init stuff.  Create the work item and run it.  Assuming we’ve already created some filters and placed the dll inside of the filters directory, we should be able to run the application and see the filters loaded in the menu.

Our filters have been loaded

Notice how I initially set the menu items to be disabled.  This is because no image has been loaded yet!  We already have an event being raise when the image is loaded, so I handle that in the LoadFiltersWorkItem and enable the menu items:

[EventSubscription("topic://ImageEditor/ImageDisplayModule/ImageLoaded", ThreadOption.UserInterface)]

public void OnImageSelected(object sender, DataEventArgs<Bitmap> e)

{

    _image = e.Data;

    foreach (ToolStripMenuItem filterItem in _filterItems)

    {

        filterItem.Enabled = true;               

    }

}

Attached to the Tag property of each of these menu items is the concrete filter that we dynamically loaded.  The next step is to raise an event when the filter is clicked, so that the other work item (that we’re about to create) can apply the filter.

As I create each of the menu items, I wire up the click event to call this handler:

void filterItem_Click(object sender, EventArgs e)

{

    ToolStripMenuItem menuItem = sender as ToolStripMenuItem;

    IImageFilter filter = menuItem.Tag as IImageFilter;

 

    if (FilterSelected != null)

    {

        DataEventArgs<IImageFilter> args = new DataEventArgs<IImageFilter>(filter);

        FilterSelected(this, args);

    }

}

The event is raised with the concrete filter passed along as data event args.

The next work item doesn’t get created at start up.  It begins when the user clicks the menu item.  So when/where do we kick off the work item?  We handle the FilterSelected event (that is being published as a CAB event) in our module, and create the workitem there:

 [EventSubscription(ModuleConstants.Events.FilterSelected, ThreadOption.UserInterface)]

 public void OnFilterSelected(object sender, DataEventArgs<IImageFilter> e)

 {

    //get the current image

    Bitmap image = _loadFiltersWorkItem.Image;

 

    //create a new workitem to apply the filter           

    WorkItem wi = new FilterImageWorkItem(e.Data, image);

    this.RootWorkItem.WorkItems.Add(wi);

 

    wi.Run();

 }

We have to get a handle on the current image as well as the filter, and this proved to be a bit difficult.  I’d like to have some sort of global state (and maybe I’m missing something) but the State property is WorkItem specific.  I was already handling the ImageLoaded event in the LoadFiltersWorkItem, so I snag the image from that event and hang on to it.  The module reads this and passes it to the FilterImageWorkItem.  Until I can figure out a cleaner way to do this, it will have to stay for now.

Here’s the FilterImageWorkItem:

public class FilterImageWorkItem : WorkItem

{

    private IImageFilter _filter;

    private Bitmap _image;

 

    [EventPublication(ModuleConstants.Events.ImageLoaded, PublicationScope.Global)]

    public event EventHandler<DataEventArgs<Bitmap>> ImageLoaded;

 

    public FilterImageWorkItem(IImageFilter filter, Bitmap image)

    {

        _filter = filter;

        _image = image;

    }   

 

    protected override void OnRunStarted()

    {

        base.OnRunStarted();

 

        Bitmap newImage = _filter.Filter(_image);

        if (ImageLoaded != null)

        {

            ImageLoaded(this, new DataEventArgs<Bitmap>(newImage));

        }

    }

}

Pretty plain and simple.  It calls the filter on the image when it runs.  We need to notify the canvas to redraw the new image, so we raise the already implemented event ImageLoaded.  Once this fires, the DisplayImageWorkItem picks it up and displays the filtered image.

Let’s check out the app in action.

The original image
The original image

The Black & White filter applied
The Black & White filter applied

The inversion filter applied
The inversion filter applied

The image filters I originally wrote were painfully slow, so I borrowed some excellent filters from the code project article here by Christian Graus.  I’m glad I could leverage somebody else’s hard work, because it’s been a few years since I did complex image processing .

I hope you enjoyed this short series of articles on building an application using CAB.  I only touched on some of the topics.  For example, ObjectBuilder was barely used in this application.  I also didn’t use WorkItem State or the StatePersistenceService.  This would be a quick and easy way to save the users work, or you could provide a standard FileSaveDialog box.

You can download the source here:
File Attachment: CAB-ImageEditor.zip (86 KB)
(you’ll need to have CAB already installed and you need to point the reference to the CAB dlls)

I’d appreciate any comments or criticisms you may have for me.

Remortgages - Renegade motorhomes - Loan - Phoenix Pools