Notifications

June 28th, 2009

A guy I work with has known my girlfriend since they were both kids, so he knew what I was up to. There was a bit of a discussion at work a few days ago, when he casually mentioned the project to another developer.

I ended up involved in the conversation, and I ended up getting some good feedback on some of the things I should be doing. We also tackled a major problem with this application: notifications.

Notifications are a fundamental part of my Review Manager. Otherwise, we would just fall back into the same problems that we currently have with the review spreadsheet (oddly, the non-shared spreadsheet that can only be used by one person at a time..), and that’s that no one ever checks the damn thing. If nobody knows you’re looking for a review, nobody will do your review. This is why so many people, myself included, tend to just spam the team with an “I need an XYZ review” emails.

I’m hoping my app will solve this problems in two ways:

  • First, everyone will have the app open because it will minimize to the tray. This makes it quick to check if you’re in the mood to pick up a random review, and it’s easy to access when you need to broadcast that you need something done
  • Everyone gets notified (once by default, and only if you’re allowed to do that type of review) that someone needs a review done, hopefully in a non-invasive way.

The main problem I had with this was determining how to display the notification without interrupting the users workflow.

After a few searches on Google and StackOverflow, I came across these two overrides:

protected override CreateParams CreateParams
{
   get
   {
      CreateParams bp = base.CreateParams;
      bp.ExStyle |= WS_EX_TOPMOST;

      return bp;
   }
}

protected override bool ShowWithoutActivation
{
   get
      {
         return true;
      }
}


The CreateParams override simply adds the option to push the form to the top of the Z-Order. This is so common that WinForms have a property already built to include this – Form.TopMost. The problem with using TopMost is that it will activate the form, stealing the focus away from the user. Since this is exactly opposite to what we want, we can’t use it. The CreateParams override will handle this functionality for us, and the ShowWithoutActivation override does exactly what it sounds like. The result is a form which is displayed above all else, but that doesn’t take the focus away from whatever the user is working on.

I decided to also allow the user to define for how long the notification is displayed. This is simply a second constructor for the form, and is in fact the only constuctor with any logic in it. The constructor without a timeout simply passes the buck onto the one that does, along with a default value of 5 seconds:

public FadeNotification (string title, string message, int timeout)
{
   InitializeComponent();
   DisplayDuration = timeout;
   tips.SetToolTip(lblMessage, message);
   this.Text = title;
   if (message.Length > MAX_MSG_LENGTH)
   {
      message = message.Substring(0, (MAX_MSG_LENGTH - 3)) + "...";
   }
   lblMessage.Text = message;
   State = DisplayState.Appearing;
}

// if no timeout is specified, use a default value
public FadeNotification(string title, string message) : this(title, message, DEFAULT_DURATION) { }

Another thing you might notice in this snippet is that I’m a bit lazy with the message. I played around with the label on the form a bit, and generally hated how it was coming out. What I decided to do instead, was to make the label the size of the form, and center it. I set the font to a nice(ish) looking size, and sent it on its way. If the message gets long enough to wrap, it looks like crap, so I just cut it off. For what I’m using it for, the maximum length I set is more than sufficient. If it’s not, the end gets chopped off and replaced with an ellipsis (sort of, since there actually is an ellipsis character which I’m not using for no particularly good reason).

This new form became revision 3 (and 4, since I left a literal in where I passed to the other constructor.. oops) in my SVN repository. There should have been more revisions relating to this, I know, but this is basically a sandbox which became too valuable. It wasn’t even originally in the same project as my main stuff. I’ll have to learn to play with my working copy more, but this source control stuff is still new to me.

The code is available in a RAR file if anyone wants to review it. I haven’t decided how I’m going to formally release this when I’m done the project, so for now lets just consider this my copyright from now. If you would like to use this in your own project (you won’t), drop me a line and force the licensing issue. It’s likely going to be LGPL’d at some point, but who knows.

My last post was also my most successful to date (where success is defined by page views and comments), but it came with a bit of criticism.

I made the argument that for the moment I’m more concerned with time to release than with building a perfect design. That’s not to say that I don’t care at all about actually sitting down and designing this thing, I am; it’s just that I have a few compelling arguments for getting this thing out sooner:

  • This project was originally created to attempt to solve a problem at work, and I’d really love to see this deployed and enjoyed by the 20ish developers who could potentially benefit from it.
  • By and large, this is meant to be a portfolio project to help find me a job in .Net. I’d like to escape my current job sooner rather than later, and get on with my new life working in areas I’m actually interested in. No offense to the language, but I just don’t spend much time outside of work working on personal COBOL projects, and I don’t read mainframe blogs. Conversely, this project shows I do work on C# outside of work, and I routinely read a number of blogs, and frequent sites, which highlight newer languages and methodologies du jour.
  • If I leave room for improvement later, I’ll gain experience with refactoring (both designs and code). It’s a great learning tool to go back to your old code and see what works and what doesn’t. Seeing how far you’ve come since you wrote that stinking, rotting, maggot-infested piece of god awful code is a great way to remind yourself that you really are learning, and that you’re constantly improving.
  • With that said, I’d like to address one of the comments from my last post.

    Reader JS writes:

    Jesse,

    I’d encourage you to write at least one or two database applications before you start using an ORM. While it can be a bit more tedious writing the queries by hand and debugging them, it is a worthwhile learning experience. Once the learning is done and you’re just repeating the same busywork you’ve already done a number of times before, then the ORM makes a lot more sense.

    I think this is excellent advice. While I’m sure you’ll definitely learn a lot by implementing a ready-made ORM like NHibernate, it’ll pay more in the long run to have the understanding of how things work behind the scenes. Not all projects will use an ORM, especially when you’re working on an older code base, and being able to debug a problem in a method full of objects found in the System.Data.OleDB namespace is definitely a plus for your employer.

    This argument is tangentially related to a topic which was popular on the internet last year – whether or not a programmer should know how to program in C. The argument there is largely the same argument I’m making here: knowing the guts of your tool of choice will make you a better programmer.

    For example, I’m really amazingly bad at computer hardware. It’s embarrassing to say, but I’ve just never been comfortable pulling pieces out of my desktop and replacing them with new bits. It’s the reason why in 2003 when I bought the machine, I opted to have 1GB of RAM installed from the start. It was probably very much overkill for my needs, but I figured it would eventually be useful and I didn’t want to deal with it.

    That desktop computer I bought failed the summer after I bought it. In desperation, I got brave and opened the machine up and started pulling bits in and out. I even took apart my parents working machine and tried to swap out the power supply to see if that was the issue. When I was done, I couldn’t even get the thing back together. I left some things unplugged for fear I’d blow the whole thing up when I plugged it in, if I’d put some connector in backwards somehow. When I took it into the local shop I’d bought it from, the guys there expertly snapped all the bits together and powered up my computer. They connected their various diagnostic tools and told me my motherboard was shot. They did in minutes what I failed to do in hours on the floor with screwdrivers and hope. All this because I didn’t understand the internals of a tool I relied on everyday.

    With that in mind, I’ve decided to follow JS’ advice (which is really just following what I had decided already anyway) and forget the ORMs for now. I’m going to dig in and get dirty with my database classes. I’ll write SQL by hand, I’ll learn a bunch of new classes in a couple new namespaces, and when I crawl out the other side I’ll be a better developer for it.

    There is a comment on one of the answers to a question on StackOverflow which sums up my point nicely. The question was “What is the best language for a beginner to write a blog engine in?” and the answerer had questioned why the asker wasn’t just going with an established brand like Wordpress.

    StackOverflow user Nelson LaQuet stated:

    The OP wants to build his own; and I believe it’s not so much for the practicality but for the learning experience. Re-inventing the wheel is a good way to learn how things work – even if you end up just using a prepacked solution in a production environment.

    Excellent advice. I think I’ll take it.

If you asked my girlfriend, and others close to me, what my biggest personality flaw is, you would be told that I’m a perfectionist. The last few days have been a shining example of that.

In my last post, I documented my source tree for the Reviewer project – four directories of planned features, and one directory called ‘Database’ which is the subject of today’s post.

I’ve been thinking a lot about how to implement the database interop for this project, since it’s my first time doing something like this and I really wanted to get it right. I came up with two (fairly obvious) ideas for this:

  1. Build the database lookups directly into my core classes.
    The first idea I came up with was to have a few methods in each class which would talk directly to the database. For example, the review class would include a method like getReviewsByType(ReviewType rt) which would translate the ReviewType object into a literal stored in the ReviewTypes table in the (currently nonexistant) database, then perform a lookup on the Reviews table and translate the results into a List and return that.I didn’t like this idea because I didn’t want to mix my business logic with my database logic.
  2. Build an abstract base class to handle all the database connectivity stuff, and create subclasses for each of my business objects that would handle the nuts and bolts of translating the objects to/from the database.

    I didn’t like this idea because I’d be essentially storing details of the same business object in two separate classes. The Review class, for example, would be strongly coupled to the ReviewDB class (pending some better name for it).

In the end I decided that I liked option two best. I could probably decouple the two in such a way that the Review class would be reusable, even if I didn’t want to bring the ReviewDB class with it.

With that decision made, I turned to StackOverflow yet again (those guys will be sick of me and my noobish questions soon enough, I’m sure) to ask if this sort of implementation was standard or fundamentally flawed. I didn’t get any negative feedback on the design question I intended to ask, but I did get one answer which asked me why I wasn’t using Object/Relational Mapping (O/RM).

I’m forced to plead ignorance here. The two examples I was given were LinqToSQL and nHibernate.

For LinqToSQL my reasoning was that I’m using the Jet database engine for the short term on this project. The reason for this have a lot to do with the deployment options at my work since they’re the only customer for the product at this point. LinqToSQL is simply not designed to work with Jet. It can be tricked into working, I’m told, but you really don’t get the complete experience.

As for nHibernate, well, I really didn’t know what that was until today. I had heard the name before, especially relating to Java, but had never looked into what it was.

I weighed the pros and cons of this approach, and have decided to completely ignore both of these options at least until the project makes it to the 1.0 release. My goal for right now is to ship the product soon, so that my colleagues at work can benefit from it, and also to teach myself C# and development in general. Whether I’m learning how to use OleDB connections, or nHibernate, I’m still learning something useful. For now, I’ve decided that taking an extra week to figure out nHibernate really isn’t worth it. For v1.1 (or 2.0), I’ll take another look and start refactoring my design and my code, and that’ll also be good practice. I’m also planning on adding support for multiple database engines (SQL Server being the main target here), without losing the existing support for Jet/Access. It should be exciting, if most likely horribly frustrating at first.

I know this seems like a bad case of “if all you have is a hammer, everything looks like a nail,” but I’m thinking instead that if my hammer does a good enough job now, why not use it?

This past weekend, I made a mistake.

For the past couple of weeks, I’ve been experimenting with a few things in C#. I made a quick mockup of some Registry-accessing code, which turned out to be completely misguided as far as why I was writing it, but it was great for diving into unfamiliar parts of C# and the .Net framework. The code takes a file extension and retrieves the default application for the ‘Open’ command, then spits it out to the screen. It was nice to get back into ‘real’ development after spending so much time in the terrifying depths of a legacy COBOL code base, and it also segued nicely into learning a bit about the OpenFileDialog class.

One of my adventures in C# accidentally turned into the user interface of my ‘Review Manager’ project. I’ll talk about the drunken stumble to this design in a later post, but suffice it to say I really liked the way it was shaping up.

Somewhere along this journey, likely as a direct result of some StackOverflow-related procrastination, I decided that to do this project right, what I really needed was some source control.

Although Git is getting a lot of press these days, it seems good ol’ Subversion is still the recommended choice for noobs like me. I downloaded the latest version of TortoiseSVN (1.6.2) and was on my way:

  1. Create a new ‘Development Projects’ directory for my serious work destined for an online portfolio… Check!
  2. Move my ReviewManager folder out of my Visual Studio ‘Projects’ directory (which will now be used for one-off projects and some prototyping) into the new ‘Development Projects’ directory…Check!
  3. Create a new root level directory to hold my SVN repositories…Check!
  4. Create a new repository for the Review Manager project…Check!
  5. Check in my existing work to the new repository…Che..Wait, where’s my.. Oh God..

As I said, I made a mistake. I’m still not 100% sure what happened, but it seems my work never actually made the move out of the Visual Studio ‘Projects’ folder. In a fit of irony, I managed to completely obliterate all my work while attempting to safely secure it in my version control system.

Thankfully, all that was really in the project was mostly just some basic GUI stuff that was partially contained in one of my prototyping projects, so it wasn’t a huge loss. What it was, however, was a giant wakeup call. Even on small projects, it pays to have a nice, secure, version controlled backup of your work.

This wasn’t a total loss. I decided to restart on the right foot and have organized my project directory a bit. This structure might not be optimal, and it sure as hell isn’t complete, but it’s a nice step in the right direction:

Review Manager
├───doc
└───src
    ├───Database
    ├───DirectoryManagement
    ├───Estimation
    ├───PeerReview
    └───TimeTracking

The Database directory is going to be used for db connectivity classes and the like, but the other four are the main goals of this project. I’ll talk about each of these in a later entry.

As always, all feedback (positive and negative) is encouraged in the comments. I’d love to hear what you all think of my progress!