The Case Against Use Cases

I'm currently working on a rather complex ETL system in the medical industry. There are new business rules uncovered daily as development and analysis proceeds in parallel due to overwhelming business urgencies. The use cases in the system are limited pretty much to "Process File." Everything else is buried in a system of business rules more complex than I care to think about very often and a series of events and event handlers which process the file and implement the business rules.

My own approach to this challenge could have been much more organized had I purchased Karl E. Weigers's book More About Software Requirements earlier on in this project. He says, "Use cases are less valuable for projects involving data warehouses, batch processes, hardware projects with embedded control software, and computationally intensive applications. In these softs of systems, the deep complexity doesn't lie in the user-system interactions. It might be might be worthwhile to identify use cases for such a product, but use case analysis will fall short as a technique for defining all the system's behavior."

I could not agree more. Weigers goes on to recommend the use of event-response tables to provide a way of documenting the requirements of such complex systems which have little if any interaction with users. Granted, you could write a use case using the machine or file system or OS or scheduler or some other non-human entity as the actor, but the analogies break down when trying to document the requirements of the complex rules within the case.

The event-response table is a simple approach to organizing these details that in fact works much better than an ad hoc method of writing it all down in sequential paragraphs and then asking developers, in this case that developer being me, to interpret those requirements and design and code a solution that really works.

You simply need a three column table with the following headers: Event, System State, and Response.

Breaking up functional requirements in a complex rules-driven system with minimal human interaction can be a daunting task. You can make it a bit easier by using some simple organizing structures such as the event-response table.

IBM Going After MySQL or SQL Server 2005 Express with DB2 Express-C

I subscribe to CodeProject's newsletter and "product information" emails. Today I received an interesting missive with the headline: "Introducing the new DB2 Express-C". And I noted the "no charge edition" limits you 2 (dual core) processors, 4GB ram limit but with unlimited database size and number and unlimited users.

SQL Server 2005 Express is limited to one CPU and 1GB of ram with a max database size of 4GB. Hmm... I'll bite. I want to know more.

A little exploration reveals a nice article on the wiki about leveraging your MySQL skills. And there seems to be ample information on using DB2 with .NET.

Having never used DB2, I'm completely unaware of what I'm getting myself into, but I'm seriously considering diving into this latest addition to the free, and increasingly capable, database engines.

So I'm downloading now and I'll give it a whirl and report what I find back here. No promises on when.


 Followup - Who am I kidding. The install is HUGE and I have had no time to eval this thing. Toss another distraction overboard.

ASP.NET Theme Assignment

You learn something new every day. I just don't have time to blog about it every time. This one seemed significant enough.

I'm writing a little ASP.NET app to keep up my web skills since my day job keeps me busy cranking out back-end code. For the first time, I've tried playing with themes. I wanted to assign a theme based on a user configuration, so I unwittingly assigned it in the Page_Load event.

Bo no... Nasty little error message telling me I can't do that, so a bit of digging revealed it has to be done earlier in the life of the page.

protected void Page_PreInit(object sender, EventArgs e)
{
    this.Theme = GetTheme();
}

That did the trick.

A Kit for Writing Your Own Programming Language

I'm having fun. In the last couple of months, I've carved out about 20 hours of fun playing with some code and tools I found on www.devincook.com. If you're interested in the creation of programming languages, I want to encourage you to to check out that site and the code (link below) that I've derived and organized from code found on that site.

I even tried to share my enthusiasm with the .NET Users Group I like to attend, though as most attendees will confirm, my presentation was ill prepared, disorganized and rambled. Hopefully the 20 or so new attendees at the users group meeting will realize that my presentation is not representative of the excellent presentations the group is use to and will come back.

In the code you can download below, you'll find my first attempt at a language: TROLL — Tyler's Really Obtuse Little Language. It's based on the concepts in the sample SIMPLE interpreter I downloaded from Devin Cook's site under the C# Engines (I recommend Morozov's engine).

Why would anyone want to write their own programming language, you ask. Especially when we have C#, VB.NET, Boo and yes, even Java. Yeah, yeah, there's C++ and D as well, and a hundred others.

So why one more programming language? Because now you can.

It's a great learning experience. You'll learn about BNF, LALR and other fun acronymns. What's more, you may find it an empowering experience to write your own programming language and see your own made-up code executed. You might even find a real use for creating a 4th+ generation language for a specific, vertical solution.

Well, whatever your reason, download the code, download Devin Cook's GOLD Builder and have some fun.

Download code (659KB)

Get Mono the Easy Way

Thanks to Miguel and his team for making it easier than ever for us Windows-bound .NET geeks to give Mono a try. It's a fairly big download but well worth it. You can now download a VMWare virtual machine image of Mono 1.2.2.1 on openSUSE 10.2 and the free VMWare Player. Install the player and open the unzipped VM file. Easy peasy. I had to play with network settings a bit but that was easy.

There is no easier way to check out Mono on Linux. No partitions to worry about. No setup to worry about. No drivers to mess with such as the constant failure I would get with my dual monitor card when I tried earlier to get SUSE running on a separate partition on my box which led to me giving up.

I recommend you give it a try. Amazing what the Mono team has done. Kudos again to Miguel and his team and all those who have contributed to the Mono project. 

Semantic Web and Legacy Web

There is much ado about the coming Semantic Web and the dream of objectifying all the data in the world allowing machines to exchange mindshare, yada, yada, yada. But what happens to old web pages when they die? Do they go to HTTP heaven? And when this glorious web for machines supplants the Legacy Web (that messy old WWW), what will we all do with our fancy browsers? Where will we find the fuel to power our AJAX rocket engines? And how will humans survive the rising tide of <tag><mytag>
<yourtag>hey</yourtag>
</mytag></tag>
drive by taggings?

The truth is that while the semantic web will find some heavy hitters to knock it out of the park in a variety of industrial and scientific arenas, I'm not sure the messy old WWW is ready for retirement just yet. I doubt the content switch will occur very rapidly in most corners of the world given that most users of the web currently are human and they use the mundane web browser occasionally flicking the AJAX booster switch and dreaming of the connected client days of yore.

We humans like messes. Just look around your office if you don't believe me. Four out of five dentists recommend a messy desk for a healthy work life. And if you don't believe me, Google it.

Still, the semantic web bears some level of intrigue beyond its obvious usefulness in some areas of business and science. In fact, I'd love to have a browser that would help me make more sense of the mess on the WWW or even the mess on my desk.

My New Year's resolution is to explore that idea and determine whether or not it can be done in the messy old WWW world without holding a gun to the head of all those gumbah's with an HTML six shooter in their belt.

Simple XML to DTO and Back Again

Data transfer objects, especially in this disconnected world we live in, have become quite popular and highly useful. Here's one way I've found to create XML file based DTOs with quick and easy loading and saving from and back to the original XML format. All you need is a schema and a little gem from thinktecture.

A couple of months ago I began working on a project that would require reading and modifying a number of XML based configuration files. I had previously used thinktecture's Web Services Contract First (WSCF) plugin for Visual Studio created by Christian Weyer and Buddhike de Silva to create contract-first web services. At the time I had discovered how convenient it was to use the web service client code generation to generate simple DTO object code as well, but it had to be done in a clever way to allow me to throw away the web service code and just use the DTO object code.

A quick visit to thinktecture's web site and I found that version 0.7 had just been released on October 25, 2006. And to my delight, the major new feature in version 0.7 was the ability to generate data transfer object or data contract code from the UI plugin for Visual Studio 2005. Just install WSCF version 0.7 and then in Visual Studio 2005 create a schema file like the one below. Then right click the XSD file in the solution explorer and select "Generate Data Contract Code" from the menu. A simple dialog like this one pops up.

This will produce a partial class and give you everything you need except a Load and Save method to store the DTO in XML format. It was a simple matter to add the following partial class and the static support class called Serializer as shown below. If you need something like this, I hope this helps.

partial class:

    public partial class Parser
    {
        private static string targetNamespace = "http://mynamespace/v1/parser.xsd";
        public static Parser Load(string fileName)
        {
            if (fileName == null) return null;
            return (Parser)Serializer.Load(fileName, typeof(MyNamespace.Parser), Parser.targetNamespace);
        }
        public void Save(string fileName)
        {
            Serializer.Save(fileName, this, this.GetType(), Parser.targetNamespace);
        }
    }

Serializer class:

    public static class Serializer
    {
        private static XmlSerializerNamespaces GetNamespaces(string targetNamespace)
        {
            XmlSerializerNamespaces ns;
            ns = new XmlSerializerNamespaces();
            ns.Add("", targetNamespace);
            ns.Add("xs", "http://www.w3.org/2001/XMLSchema");
            return ns;
        }

        public static object Load(string fileName, System.Type objType, string targetNamespace)
        {
            string xml = File.ReadAllText(fileName);
            object obj = Serializer.FromXml(xml, objType, targetNamespace);
            return obj;
        }

        public static void Save(string fileName, object obj, System.Type objType, string targetNamespace)
        {
            string xml = Serializer.ToXml(obj, objType, targetNamespace);
            File.WriteAllText(fileName, xml);
        }

        public static string ToXml(object obj, System.Type objType, string targetNamespace)
        {
            XmlSerializer ser;
            ser = new XmlSerializer(objType, targetNamespace);
            MemoryStream memStream;
            memStream = new MemoryStream();
            XmlTextWriter xmlWriter;
            xmlWriter = new XmlTextWriter(memStream, Encoding.UTF8);
            xmlWriter.Formatting = Formatting.Indented;
            xmlWriter.Indentation = 1;
            xmlWriter.IndentChar = '\t';
            xmlWriter.Namespaces = true;
            ser.Serialize(xmlWriter, obj, Serializer.GetNamespaces(targetNamespace));
            xmlWriter.Close();
            memStream.Close();
            string xml;
            xml = Encoding.UTF8.GetString(memStream.GetBuffer());
            xml = xml.Substring(xml.IndexOf('<'));
            xml = xml.Substring(0, (xml.LastIndexOf('>') + 1));
            return xml;
        }

        public static object FromXml(string xml, System.Type objType, string targetNamespace)
        {
            XmlSerializer ser;
            ser = new XmlSerializer(objType, targetNamespace);
            StringReader stringReader;
            stringReader = new StringReader(xml);
            XmlTextReader xmlReader;
            xmlReader = new XmlTextReader(stringReader);
            object obj;
            obj = ser.Deserialize(xmlReader);
            xmlReader.Close();
            stringReader.Close();
            return obj;
        }
    }

example schema:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="parser"
             targetNamespace="http://mynamespace/v1/parser.xsd"
             elementFormDefault="qualified"
             xmlns="http://mynamespace/v1/parser.xsd"
             xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="Parser">
        <xs:complexType>
            <xs:all>
                <xs:element ref="ColumnWidths" minOccurs="0" maxOccurs="1" />
                <xs:element name="ExpectedColumnCount" type="xs:int" />
                <xs:element name="MaxBufferSize" type="xs:int" />
                <xs:element name="MaxRows" type="xs:int" />
                <xs:element name="SkipDataRows" type="xs:int" />
                <xs:element name="FirstRowHasHeader" type="xs:boolean" />
                <xs:element name="TrimResults" type="xs:boolean" />
                <xs:element name="IncludeFileLineNumber" type="xs:boolean" />
                <xs:element name="FixedWidth" type="xs:boolean" />
                <xs:element name="RowDelimiter" type="xs:string" />
                <xs:element name="ColumnDelimiter" type="xs:string" />
                <xs:element name="TextQualifier" type="xs:int" />
                <xs:element name="EscapeCharacter" type="xs:int" />
                <xs:element name="CommentCharacter" type="xs:int" />
            </xs:all>
        </xs:complexType>
    </xs:element>
    <xs:element name="ColumnWidths">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="ColumnWidth" minOccurs="0" maxOccurs="unbounded" type="xs:int" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

 

Beware the Arbitration Agreement

I've been busy. Yeah. Sad excuse, but true.
 
On November 7, 2006, about two months after I was hired, my employer "invited" me to resign my position because I refused to sign a mandatory arbitration agreement which among other things included the following language: "I understand that by agreeing to this binding arbitration provision, both I and [company name] give up our respective rights to a trial by jury."

I told my employer that I didn't think I should have to waive my constitutional right to petition the government for redress just because so many others abuse that right. I had researched the issue on the Internet and found that these agreements are enforced by the courts and that in about 99% of all cases, the employee loses, regardless of the issues and facts.

I was annoyed. More at the law than at my employer. I know the law stands behind employers on this issue. And I even support the idea of arbitration as a first option, but I cannot abide the idea of just waiving my right to go to court just to keep a job. I don't think the law should allow an employer to require such a concession upon employees, but it does. Specifically, as long as both parties give up the same rights, the contract is enforceable.

This would be just fine except for the fact that in arbitration, the little guy is viewed by most arbiters (usually retired judges) as the money grubbing whiner and the employer as the victim of the evil, greedy employee. So you give up the same rights but you put yourself, as an employee, at a significant disadvantage if you run into some dispute with an employer.

All that said, I've never been sued by an employer and I've never sued an employer. Still, if I had to, I'd like to preserve the option of having a real court and a real jury hear my case rather than an arbiter who answers to no one regardless of his or her conduct and decisions in the face of the evidence. Take those odds? No thanks.

I was lucky. I found another job the same day I was "asked" to leave which happily pays even better. And I've been super busy with the new gig ever since. Not everyone has the same opportunity and flexibility that I enjoy, so I recognize this development as a true blessing.

Since that day, I've spent an hour or so contacting legislators about the issue. They are generally either indifferent or completely ignorant or in some cases both. Senator Hatch sent me a nice, completely off-base form letter reply referring me to legal counsel despite the fact that I had just asked for his opinion on whether employers should be allowed to continue this practice and whether he would support legislation to prohibit it. Many others just never responded. It's pretty sad when elected officials care so little about the way that employers are now forcing their employees to give up their constitutionally protected rights just because they are afraid of employees who abuse those rights.

It's typical fare for our culture. Punish those who have done nothing wrong in the false hope of protecting yourself from the real bad guys. Similar examples are not difficult to find. Such draconian practices are not needed. If you're going to get sued by employees, you're going to get sued. And if it happens a lot, you might want to consider changing your behavior and/or changing who and how you hire.

If you're reading this and you've signed employment documents without really reading them, you may have signed a similar document. I recommend reading every document your employer "invites" you to sign. Despite your excitement to have a new job and your high opinion of the people you'll be working for, you may be surprised at what they've asked you to agree to. There's only one way out of such an agreement. Don't sign it in the first place. I really liked the people at the former job, but regardless of my regard for them, I was not about to give up my rights in order to work for them.

Of course, everything I've said here is my own opinion. I'm sure my former employer sees it completely differently. I bear them no ill will and certainly have no plans to waste time and energy on the lawsuit that so many of my friends have recommended that I bring against them. I would just hope that they would see their actions for the paranoia I believe it to be and revise their agreements with their existing employees. I think it would be the right and moral thing to do. But that's up to them.

With that all said, I'll get back to coding and promise some real .NET coding posts here in the future.