Dabbleboard and Naked Objects for .NET

I've recently been looking for simpler and more effective tools for collaborating with geographically distributed teams. The first order of business is to find something better than a whiteboard that can be shared amongst multiple users. After some brief searching, I found Dabbleboard at www.dabbleboard.com. This gem was just recently launched and I'm impressed. The image below was created using the free version of the tool online in just a few minutes. I highly recommend that you give it a try.

proto

The next order of business is to find a better way to prototype a business application that will allow us to define data and business logic in code and sharing that in a prototype that will allow users to interact with the business model without having to build a complex UI prototype and without having to map business objects to the database. While wandering around a site called InfoQ I found through Markin Fowler's blog, I ran into Naked Objects for .NET. I was dubious at first but spend some time watching the videos and wandering around the site. I like what see.

I'm just beginning to use these two tools in a real effort to determine whether they will really make my job and life easier. I am hopeful and impressed with what I've seen so far. The drawing I've created and included in this post illustrates how the Naked Objects technology might be used in what I'm building for my employer. I'm not sure if it represents exactly what will happen in the future but the guys at Dabbleboard have certainly made it easier to envision and to share with my colleagues no matter where they are.

Business Process Management with Ultimus and .NET

After a long search for the right business process management platform that would allow us to integrate and extend with .NET, my team selected the Ultimus BPM Suite. The primary factors in the decision were the comprehensive nature of the solution which would allow us to deploy process management without requiring the use of some other tool such as InfoPath or SharePoint. Additionally, the solution would allow an incomplete process to be deployed and have assigned "process experts" make final decisions about business rules that may not have been clear or available at the time the process was designed.

I spent all of last week at their North Carolina offices in a "jumpstart" training course and met many of the key players at the company. Good people all around. Their technical expertise and willingness to listen to our team's concerns were impressive. There were a few minor UI glitches that we brought to their attention such as some scrolling issues when designing a process with limited screen real estate. The Ultimus people were genuinely interested in our input.

Having initially found and recommended the product, I was even more impressed with the product as we went through detailed training that brought out a number of features and illustrated an architecture that gave me even greater confidence in the product. This was particularly true in the area of integration points with existing systems and the ability to extend the process using custom developed controls or even process context aware ASP.NET pages hosted outside of the process server.

Our only disappointment was that some of the the training session content could have been improved as at times some of the class members were left a little lost and fell behind. This was in part because the "jumpstart" course was designed to fit a lot of material into a few days, but it was in part due to a lack of maturity in the content and presentation. We were very candid with the Ultimus training director about this and he took our input eagerly and promised improvement. Based on my conversations with key Ultimus employees, I believe that will happen.

If you are looking for a better way to deliver business process management and enterprise human-centric workflow solutions, you should consider Ultimus. There were other systems that were much more expensive that may have fit our requirements, but this was the only one we found that allowed us the freedom to extend and customize using our .NET dev skills without requiring coding skills to design and modify and manage processes.

I'll be writing more about Ultimus as our experience with the product continues.

Automated Translation Not Spammer Friendly

The following spam message (less the links) skipped through my spam filters somehow. If you are not a native speaker of English, this message may appear to be in order if your skill level with the language is limited. Otherwise, I suspect you will find this text as amusing as I did. I have not modified a single character. Enjoy...

welcome to order,
Our company is one of the largest wholesalers in Asia ,and we sell products to all over the world,we have the authorithed licence issured by Chinese government,all products in our company ranges from varieties of electronic products like mobilephone ,television, laptop,DVD,GPS,MP3/4 to photograph video game ,scanner, motorcycle prohector and so on..
We have earned our reputation in the world through our honesty business practice in the past years,and obtained many compliments from our clients globally.As we are the direct wholesalers for many reputable brands in the world,so all the products purchased in our website are promised to be at a lower price with the high quality,also all the facuty products will be returned within 7 days,exchange within 14 days,repair within 2 years without charge.
We will be right here waiting for your visitation.

I hope that as software architects and engineers we are producing code and other textual artifacts that communicate with greater clarity and understanding of the language and idiom in which we express our ideas. Do we write documentation as badly because we can only communicate clearly in code? Or vice versa? It is something to think about.

Base 30 Type in C#

I'm experimenting with using the Guid type in databases and applications but I don't like the string format of the Guid. It's not easily read or formatted on a report. I wanted to find a way to represent very large integers such as the Guid (a 128 bit integer under the covers), so I looked around and found a Base 36 type sample on Code Project article by Steve Barker that gave me a great start.

The problem with Base 36 is that several characters are similar to other characters or numbers, so took the code and modified it to use a limited set of 20 characters that are distinctive from numbers and other characters sufficiently to make it easy for humans to read them back or hand enter them in a user interface.

I downloaded the code and went to work making the modifications. Here's the core of the Base 30 struct:

//removed are chars similar to numbers or another char when printed: I, J, O, Q, V, Z
private static List<char> alphaDigits = new List<char>(new char[]{ 'A','B','C','D','E','F','G','H','K','L','M','N','P','R','S','T','U','W','X','Y' });

private static byte Base30DigitToNumber(char Base30Digit)
{
    if(char.IsDigit(Base30Digit))
    {
        //Handles 0 - 9
        return byte.Parse(Base30Digit.ToString());
    }
    else
    {
        //Converts one base-30 digit to it's base-10 value
        if (alphaDigits.IndexOf(Base30Digit) > -1)
        {
            //Handles ABCDEFGHKLMNPRSTUWXY  (these are letters that cannot be confused for numbers)
            int index = alphaDigits.IndexOf(Base30Digit) + 10;
            return (byte)(index);
        }
        else
        {
            throw new InvalidBase30DigitException(Base30Digit);
        }
    }
}

private static char NumberToBase30Digit(byte NumericValue)
{
    //Converts a number to it's base-30 value.
    //Only works for numbers <= 29.
    if(NumericValue > 29)
    {
        throw new InvalidBase30DigitValueException(NumericValue);
    }

    //Numbers:
    if(NumericValue < 10)
    {
        return NumericValue.ToString()[0];
    }
    else
    {
        //Note that A is code 65, and in this
        //scheme, A = 10, Y = 29 ABCDEFGHKLMNPRSTUWXY  use alphaDigits for List<char>
        int index = NumericValue - 10;
        return alphaDigits[index]; //(char)(NumericValue + 55);
    }
}

Now, I have added a couple of static methods to give me a shiny Base 30 guid string and convert that string back to a Guid here:

/// <summary>
/// Convert a Guid to a set of four Base30 string values connected by a dash character.
/// </summary>
/// <param name="g"></param>
/// <returns></returns>
public static string GuidToBase30Set(Guid g)
{
    byte[] b = g.ToByteArray();
    Base30 b1 = BitConverter.ToUInt32(b, 0);
    Base30 b2 = BitConverter.ToUInt32(b, 4);
    Base30 b3 = BitConverter.ToUInt32(b, 8);
    Base30 b4 = BitConverter.ToUInt32(b, 12);
    return string.Format("{0}-{1}-{2}-{3}", b1, b2, b3, b4);
}

/// <summary>
/// Convert the Base30 set string produced by GuidToBase30Set back to a Guid.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static Guid Base30SetToGuid(string s)
{
    string[] p = s.Split('-');
    if (p.Length != 4) throw new ArgumentException("Invalid Base30Set format.");
    try
    {
        Base30 b1 = p[0];
        Base30 b2 = p[1];
        Base30 b3 = p[2];
        Base30 b4 = p[3];

        uint x1 = (uint)b1.NumericValue;
        uint x2 = (uint)b2.NumericValue;
        uint x3 = (uint)b3.NumericValue;
        uint x4 = (uint)b4.NumericValue;

        byte[] a1 = BitConverter.GetBytes(x1);
        byte[] a2 = BitConverter.GetBytes(x2);
        byte[] a3 = BitConverter.GetBytes(x3);
        byte[] a4 = BitConverter.GetBytes(x4);

        byte[] gb = new byte[16];

        a1.CopyTo(gb, 0);
        a2.CopyTo(gb, 4);
        a3.CopyTo(gb, 8);
        a4.CopyTo(gb, 12);

        return new Guid(gb);
    }
    catch
    {
        throw new ArgumentOutOfRangeException("Invalid Base30Set string.");
    }
}

The code above gets you something like this:

Common Guid string: b908d243-c1ac-4ea4-a954-121e4ab5c334
Base30Set from same: 47PGC95-1S8WCHP-MPTTA1-16CUN8P

You can download the code here (Base30.zip 3.6 KB).

Apple, I'm a PC and You're a Hypocrite

One of the latest Apple ads makes fun of Microsoft for spending more on marketing than on fixing Vista. Time for all you fruit computer junkies to face some cold hard facts:

Let's take our most recent SEC filing quarter for both companies and compare spending on sales, marketing and administration versus research and development and then average that spending per employee.

Microsoft spends about $25,000 per employee on R&D and $43,000 on sales, marketing and administration.
A ratio of 1 to 1.72.

Apple spends about $16,300 per employee on R&D and $51,200 on sales, marketing and administration.
A ratio of 1 to 3.13.

So relatively speaking, Apple spends nearly twice as much on sales, marketing and administration as Microsoft does.

And that's one reason why I'm a PC. You can keep your fruit computer.

What is Enterprise Software Architecture

I just posted this on a linkedin group to which I belong, but I thought I'd also like to pose the question here.

I'd like to get a discussion started that attempts to define enterprise software architecture. My own definition seems to be evolvoing with every enterprise for whom I've worked. In the abstract, for me, enterprise software architure is the art of putting the pieces of multiple puzzles together into one great work of art.

There are many puzzles to choose from and every enterprise has a unique mix. There are multiple teams with various skillsets and experience. There are multiple business processes sometimes with unique and strange business rules. Technology platforms that differ, communications protocols that won't communicate with one another, languages, frameworks, compilers, IDEs, components, and hardware that vary from team to team and department to department. Ours is the task of taking these disparate and often incongruous pieces and molding them into one coherent masterpiece of technology and human resources to get more done, get it done better, quicker, cheaper and easier. And if we do our jobs well, it may be that no one will notice that we did it at all.

What do you think?

To Outsource Or Not to Outsource, That is the Question

I just posted the following note on a LinkedIn group I follow in answer to a post about so called "software factories," which is a nice euphemism for overseas developers working for much less than they deserve struggling to meet the unreasonable demands of their bosses. This represents my opinion on the subject:

Never forget that you get what you pay for. Hiring an overseas or even local "software factory" or consultancy to build your software can be problematic at best and a complete waste of time and money at worst.

First, if you cannot communicate, forget about it. Building software is 99% communication and 1% technology. Okay, perhaps I overstate the case. A little. But you cannot overestimate the importance of clear, effective communication.

Second, unless you have the internal people required to manage such a relationship, your project will fail. This means you need project management and technical people in your own organization that you know well and trust. They need to be supremely competent. This is especially true if you plan to hire a firm outside of your own geographical area.

Third, plan for time and budget overages. It is the nature of consulting to promise a low price and quick turnaround and then when you are committed to the project and it is "nearly done," you will be informed that there is much more to do, generally due to legitimate changes in requirements because you did not fully understand what you wanted when the project first began. This is the boon and bane of software development whether internal or external.

Finally, you can have success outsourcing your software development project, but do not make the mistake of thinking that it will save you an enormous amount of time and money, especially for a single application project. It takes time to develop a working relationship with an outside consultantcy, especially one that is half way around the world. If you have multiple projects, long term goals, and a huge budget of time and money, it may in fact be cost effective to have a relationship with a so called "software factory." But if you are a small organization and have one or two projects, you will nearly always be better off hiring a professional locally, usually through one of the many technical recruiting companies, to come into your organization as a contractor to work on-site building exactly what you want as you discover over time what it is you want exactly.

ASP.NET MVC RedirectUrl on Login

In my first attempt at creating a real applicaiton using the new ASP.NET MVC project template (Codeplex Preview 5), I found that when I clicked a new tab I'd created linked to a specific controller and an action I'd decorated with the [Authorize(Roles = "user")] attribute, the "out of the box" Login action did not redirect me to the that controller/action combo once I had successfully logged in.

Here's my solution to the problem. First, I added a hidden value in the Login.aspx form. Second, I added a parameter to the Login action in the Acount controller (AccountController.cs). Let me know if you've found a better way.

Here's the code for the form:

<form method="post" action="<%= Html.AttributeEncode(Url.Action("Login")) %>">
    <div>
        <table>
            <tr>
                <td>
                    Username:
                </td>
                <td>
                    <%= Html.TextBox("username") %>
                </td>
            </tr>
            <tr>
                <td>
                    Password:
                </td>
                <td>
                    <%= Html.Password("password") %>
                </td>
            </tr>
            <tr>
                <td>
                </td>
                <td>
                    <input type="checkbox" name="rememberMe" value="true" />
                    Remember me?
                </td>
            </tr>
            <tr> <!-- Added to handle the returnUrl -->
                <td>
                    <%= Html.Hidden("returnUrl", ViewData["ReturnUrl"].ToString()) %>
                </td>
                <td>
                    <input type="submit" value="Login" />
                </td>
            </tr>
        </table>
    </div>
</form>

Here's the code for the Login action:

public ActionResult Login(string username, string password, bool? rememberMe, string returnUrl)
{
    ViewData["Title"] = "Login";
    string url = (string.IsNullOrEmpty(returnUrl) 
        ? Request.QueryString["ReturnUrl"] ?? string.Empty 
        : returnUrl)
        .Trim('/');
    ViewData["ReturnUrl"] = url;

    // Non-POST requests should just display the Login form 
    if (Request.HttpMethod != "POST")
    {
        return View();
    }

    // Basic parameter validation
    List<string> errors = new List<string>();

    if (String.IsNullOrEmpty(username))
    {
        errors.Add("You must specify a username.");
    }

    if (errors.Count == 0)
    {

        // Attempt to login
        bool loginSuccessful = Provider.ValidateUser(username, password);

        if (loginSuccessful)
        {
            FormsAuth.SetAuthCookie(username, rememberMe ?? false);
            if (url != null && url.Length > 0)
                return RedirectToAction("Index", url);
            else
                return RedirectToAction("Index", "Home");
        }
        else
        {
            errors.Add("The username or password provided is incorrect.");
        }
    }

    // If we got this far, something failed, redisplay form
    ViewData["errors"] = errors;
    ViewData["username"] = username;
    return View();
}