Mandatory overloads

Mandatory overloads

Yesterday I read a pretty sensible tweet by Jeremy D. Miller:

(args), you almost always need a Method(Type, args) too.’ width=’550′ height=’292′>

In spirit, I would like to propose another:

When you have a method like Method(IEnumerable<T> items), you should always provide a Method(params T[] items) too.

I can’t decide if this is an application service, or a domain service!

I can’t decide if this is an application service, or a domain service!

Deciding whether a service belongs in the domain or service layer can be a very tough question.

I think it’s important to remember that, just because a class:

  • Deals exclusively with objects in the domain model
  • Is called in turn by other application services
  • Has no dependencies on other non-domain services

…does not make it a domain service.

Try not thinking of it as the domain layer, but as the domain model. The domain model is a very strict abstraction of the business; domain layer is just a tier in your app where the model resides. It’s a small change of words but a big difference in perspective.

Is your service actually part of the domain model, or just manipulating it?

Back to basics: good source control check-in habits

Back to basics: good source control check-in habits

The other day at work I went over a few good source control habits (TFS-centric) for new developers, and why they’re worth doing. Here are some tips:

Check-ins are coarse-grained

When I first started using source control, a lot of my check-in logs looked like this:

  1. Added useful function foo() (that will be ultimately required for feature X)
  2. Added feature X

I was trying to be helpful by making foo() available for use as early as possible, but most of the time I checked it in too early, and needed to change/fix it later — resulting in additional check-ins. In reality though, all this did was clutter up the change history with signal-to-noise, making it harder to establish what changes were actually required to effect a change.

It also of course violates the YAGNI (you ain’t gonna need it) principle – no one ever needed foo() badly enough to make it worth checking it in early.

Check-ins should be coarsely grained — instead of staggering code changes over a period of time, save it all for one big changeset that contains everything. This actually improves YAGNI — instead of adding endless low-level functions ‘because they might be useful’, you’re forced to associate them with a higher application-level change.

Never check in unfinished work

In the main (trunk) branch, there are two cardinal rules:

  • Never check in anything that breaks the build
  • Never check in an unfinished feature

The main branch should always be in a state where it’s ready for release. Features have been entirely added or don’t exist yet; complete changes have been made, or not even started. There is no middle ground.

Having to worry about the possibly unfinished state of the ‘master copy’ is just another burden on your team. Even worse, if you check in code that doesn’t compile, you can interrupt other people’s work and waste their time commenting out bad blocks and working around it.

Sometimes, however, you’ll get a piece of work that doesn’t fit in one check-in.

  • It could take a long time to implement (needs more than one check-in).
  • Multiple developers might need to work on it.
  • The change isn’t going to be released (committed to the main branch) until a later date.

You have two options: fork a copy of the code for a new development branch, or shelve your changes so you or someone else can work on them later. The basic rule for branches is if you need more than one check-in to make a change, you need to branch and merge back in later.

Source control is not for back ups

This follows from the previous two tips. Check in your work because you’re completely done and finished — not because it’s the end of the day, or because it’s the weekend etc.

I think this habit often begins when using reserved-checkout source control systems like VSS, where having a file checked out explicitly blocks other people from editing it. Everyone who’s used VSS knows from experience that hilarious situation where you need to edit a checked-out file, but the person who has it is on holiday or otherwise unreachable.

VSS file exclusively checked out error

To avoid this, teams adapt their work habits to suit VSS, checking in frequently so as not to lock files for extended periods. This practice is continued for some reason (cargo cult programming?) when moving to less brain-damaged source control tools like TFS or subversion.

Anyway, if you want nightly backups of your local working source code, get some backup software. Don’t use source control — change tracking becomes difficult when you check in based on calendar events. It gets even more ridiculous if you have changes that don’t compile yet, and have to comment/uncomment code when checking it in.

Use a separate check-in when reformatting code

Say you go to edit a file, but the formatting is all messed up — the indenting is wrong. So you fix it up while making your changes. But then, if someone comes along later to see what your change entailed, a diff tool will highlight differences on every line, making it very hard to see what the actual code change was. Instead, use a separate check-in for mass code reformatting.

Write useful check-in comments

If you’re looking over the history of a file in source control, comments like ‘css fix’ or ‘#12345′ won’t be very useful. Instead, good check-in comments need three things:

  • What was changed
  • Why it was changed
  • Any bug/issue tracking numbers (if applicable)

Describe what you changed, and why it was necessary. You don’t have to write an essay — I find one sentence of ‘did X because Y’ is usually sufficient.

TFS change history

You should also list any bug/issue tracking numbers, or make reference to any relevant project documentation (e.g. list of requirements) to provide a higher-level context. This is a good way of establishing traceability on tightly-controlled source repositories — if you do it right, you’ll find almost every change can be traceable back to some external identifier.

I also like to paste my changeset number when I update an issue as being completed (ready for user testing or peer review) — the easier it is to find my changes, the better! (Note that some source control tools can do this automatically from your check-in comment).

Real-life examples

You can see good check-in habits in action in most popular open source projects. Here are a few of examples:

  • Boost C++ Libraries revision log
  • Ruby on Rails commit history
  • Subtext revision log

Improved error reporting patch for BNC 2.9.4

Improved error reporting patch for BNC 2.9.4

BNC 2.9.4 is a simple open-source IRC proxy. Their website is down at the moment, but you can see a cached version.

I prefer it over more feature-rich proxies like psyBNC because it’s one-server-per-client model is a natural fit for mIRC‘s multi-server support. It also makes things a lot easier if you prefer to manage channels and servers at the client end (which, in my case, was running 24/7 anyway).

One thing I’m not so impressed by is the lack of proper error reporting. I have written a patch to make BNC return a descriptive error message to the client when a connection attempt fails: instead of “Failed Connection”, you now get “Failed Connection: <errno description>”. This should make debugging connection problems much easier. The patch also fixes a missing header dependency that prevents it from compiling under Mac OS X.

A new website on a new domain

A new website on a new domain

I have just finished migrating this website from Blogspot to my own domain and web server. I am now able to post code, host files and basically do whatever I like!

I am using WordPress, a powerful open-source blogging engine, and I have modified the look and feel to be as clean and simple as possible. I hope you like it.

Windows Integrated Authentication in ScrewTurn Wiki

Windows Integrated Authentication in ScrewTurn Wiki

ScrewTurn Wiki is a simple, open source wiki engine that reproduces much of the functionality found in Mediawiki. ScrewTurn Wiki is powered by ASP.NET 2 and Microsoft SQL Server, which makes it ideal for Windows-centric corporate environments. Unfortunately, ScrewTurn Wiki has no out-of-the box support for Windows Integrated Authentication (and, according to the developer, never will).

Windows Integrated Authentication allows users’ credentials to be automatically passed to IIS. This allows the application (if it supports it) to use Windows login details – i.e., the same user name across an entire domain. The user is automatically and seamlessly logged in to the application – a huge benefit over having to remember multiple user names and passwords.

I have created a simple Windows Integrated Authentication implementation for ScrewTurn Wiki, similar to that used by Community Server (another ASP.NET/SQL Server-based collaboration tool). Note that ScrewTurn Wiki’s Plugin Framework does not cater for extra functionality at this level (yet). When a new session is spawned on the web server, the application searches for an account matching the user’s login name. If none is found, a new account is created automatically. Events are logged via the standard ScrewTurn Wiki event log.

Replace Session_Start in ScrewTurn Wiki’s Global.asax with the following:

void Session_Start(object sender, EventArgs e){    // Code that runs when a new session is started    ScrewTurn.Wiki.Users.OnlineUsers++;    ScrewTurn.Wiki.SessionFacade.Breadcrumbs = new ScrewTurn.Wiki.BreadcrumbsManager();    // Get identity name from web server.    string identityName = System.Web.HttpContext.Current.User.Identity.Name;    if (identityName == null || identityName.Length < 1)        throw new System.ApplicationException("Could not get current Windows user name." +            "Ensure Integrated Windows Authentication is enabled.");    string username;    // Strip domain prefix (e.g. "\COMPANY.NETDoeJ").    int domainDelimOffset = identityName.IndexOf("\");    if (domainDelimOffset > 0)        username = identityName.Substring(domainDelimOffset + 1);    else        username = identityName;    if (username.Length < 1)        throw new System.ApplicationException("Username " + identityName +            " is empty after domain stripped.");    // Locate user.    ScrewTurn.Wiki.PluginFramework.UserInfo user =            ScrewTurn.Wiki.Users.Instance.Find(username);    if (user == null)    {        // User not found, add a new one.        if (!ScrewTurn.Wiki.Users.Instance.AddUser(username, string.Empty,                string.Empty, true, false, null))            throw new System.ApplicationException("Could not add user ""                + username + "".");            // Get freshly-added user.            user = ScrewTurn.Wiki.Users.Instance.Find(username);            if (user == null)                throw new System.ApplicationException("Could not find user ""                    + username + "".");    }    // Set up session.    ScrewTurn.Wiki.SessionFacade.LoginKey =        ScrewTurn.Wiki.Tools.ComputeSecuredUsernameHash(user.Username);    ScrewTurn.Wiki.SessionFacade.Username = user.Username;    ScrewTurn.Wiki.SessionFacade.Admin = user.Admin;    // Log event.    ScrewTurn.Wiki.Log.LogEntry("User " +        ScrewTurn.Wiki.SessionFacade.Username +        " logged in through Windows Integrated Authentication",        ScrewTurn.Wiki.EntryType.General, "SYSTEM");}

For more information about Windows Integrated Authentication and ScrewTurn Wiki (including comments on this implementation), see this thread at the ScrewTurn Wiki forum.