Foundation of a .NET DateTime DSL

11.17.2011 13:57 by kbeckman | Comments

C4SC DSL Series Catalog

 

Welcome to the first of several posts in the development of a DSL for working with DateTime in .NET. I’ll keep the intro light as there are a lot of things to cover. I just wanted to mention one thing though before we get started… Some of the class names you’ll see below are extremely wordy, but by the name alone they convey the full intent of the class internals. The wordy class names are only for the static methods containing the DSL’s extension methods. We’ll never have a need to instantiate these classes so you won’t see them in any code that uses it.

 

Looking Ahead to the Desired DSL Syntax…

The following code snippets are before-and-after examples of how to calculate some sample dates using the traditional approach available in the .NET Framework followed by the desired syntax I hope to achieve using the DateTime DSL we’re beginning in this post. You’ll notice here that the DSL doesn’t exactly save you many keystrokes, but it adds a great deal to the code’s readability and immediate understandability. I can see immediate usages for this DSL in providing a more readable unit test syntax for calculating and evaluating DateTime objects. I can also think of several times I wish I had something like this for manipulating DateTime in domain objects.

//Traditional .NET Framework...
DateTime tomorrow            = DateTime.Today.AddDays(1);
DateTime yesterday           = DateTime.Today.Subtract(new TimeSpan(-1));
DateTime oneYearFromNow      = DateTime.Today.AddYears(1);
DateTime silverAnniversary   = new DateTime(2012, 10, 20).AddYears(25);

 

//DSL Syntax...
DateTime tommorow             = 1.Day().FromNow();
DateTime yesterday            = 1.Day().Ago();
DateTime oneYearFromNow       = 1.Year().FromNow();
DateTime silverAnniversary    = 25.Years().From(user.weddingDate);

 

Step 1: The DSL Semantic Model

Martin Fowler defines a semantic model as “The model that’s populated by a DSL.” For the purposes of this post, that doesn’t tell us much… Without asking you to buy the book for further reading, I’ll provide a little more detail before we get to the code. In version 3.5 of the .NET Framework, Microsoft introduced extension methods allowing developers to extend class behavior by providing an additional set of methods (via a static class) without having to extend the original class implementation. This was an extremely power feature because it allowed .NET developers to extend classes in closed libraries or purchased 3rd party libraries where no source code was available. This approach is a similar technique to using modules in Ruby mixins, but it’s more restrictive since extension methods are constrained to a single Type. Adding extension methods for base classes and interface Types allows for more flexibility, but it’s still not as forgiving as what a truly dynamic language can provide.

 

In DSLs (a term used lightly here) that only use extension methods, the semantic model is whatever Type the extension methods are targeted for. In the case of this DSL as seen in the examples above, the desired syntax uses extension methods defined for the Int32 Type and not the final result Type of DateTime. Because a conversion between the two is required, we need an intermediate semantic model that can aggregate the components of DateTime before the actual DateTime instance is created. For that purpose, I’ve created an immutable struct called DateTimeComponents that contains a read-only field for all of the components of DateTime in the .NET Framework: years, months, days, minutes, seconds and milliseconds.

/// <summary>
/// Immutable semantic model for C4SC DateTime DSL.
/// </summary>
/// <remarks>
/// http://martinfowler.com/dslCatalog/semanticModel.html
/// </remarks>
public struct DateTimeComponents
{
    public DateTimeComponents(Int32 years, Int32 months, Int32 days, 
        Int32 minutes, Int32 seconds, Int32 milliseconds)
    {
        _years        = years;
        _months       = months;
        _days         = days;
        _minutes      = minutes;
        _seconds      = seconds;
        _milliseconds = milliseconds;
    }

    private readonly Int32 _years;
    public Int32 Years { get { return _years; } }

    private readonly Int32 _months;
    public Int32 Months { get { return _months; } }

    private readonly Int32 _days;
    public Int32 Days { get { return _days; } }

    private readonly Int32 _minutes;
    public Int32 Minutes { get { return _minutes; } }

    private readonly Int32 _seconds;
    public Int32 Seconds { get { return _seconds; } }

    private readonly Int32 _milliseconds;
    public Int32 Milliseconds { get { return _milliseconds; } }
}

 

Step 2: The Int32 Extension Methods

The DateTimeComponents struct is our semantic model that essentially collects the components of DateTime we will eventually convert to a DateTime object. As you’ll see from the abbreviated Int32ConversionToDateTimeComponents static class below, the extension methods here are extremely trivial in their functionality. They simply call the DateTimeComponents constructor passing in the various component of DateTime into the necessary constructor parameter and return the DateTimeComponents instance as the result. You’ll also notice that the singular version of each component method simply delegates control to its plural counter part. The abbreviated example below only shows the extension methods for collecting the year component of DateTime (although all other components are implemented). To see the full class implementation, visit my C4SC GitHub repository.

/// <summary>
/// Extension methods to convert Int32 values to their DateTimeComponents equivalent.
/// </summary>
public static class Int32ConversionToDateTimeComponents
{
    /// <summary>
    /// Converts an Int32 to its equivalent DateTimeComponents representation in years. 
    /// </summary>
    /// <param name="year">Number of years.</param>
    /// <returns><see cref="DateTimeComponents"/> composed of the given year parameter.</returns>
    public static DateTimeComponents Year(this Int32 year)
    {
        return year.Years();
    }

    /// <summary>
    /// Converts an Int32 to its equivalent DateTimeComponents representation in years. 
    /// </summary>
    /// <param name="years">Number of years.</param>
    /// <returns><see cref="DateTimeComponents"/> composed of the given years parameter.</returns>
    public static DateTimeComponents Years(this Int32 years)
    {
        return new DateTimeComponents(years, 0, 0, 0, 0, 0);
    }
}

 

Step 3: The DateTimeComponents Extension Methods

Below is the complete implementation of the DateTimeComponentsConversionToDateTime static class that contains all of the extension methods to return our desired DateTime. As you can see, these methods simply use the individual components of DateTime and either add or subtract them from the given DateTime. There are some slight optimizations we can perform here, but I’m going to save those for a future post. As I’ve mentioned before, C4SC is an agile shop and we’ll worry about refactoring and optimizing when there is sufficient unit test coverage to allow for it. If this class doesn’t make much sense yet, it will in the next section when I include some unit tests that reveal the DSL’s full intent.

/// <summary>
/// Extension methods to calculate DateTime future or past result from DateTimeComponents operand.
/// </summary>
public static class DateTimeComponentsConversionToDateTime
{
    /// <summary>
    /// Calculates the result of DateTimeComponents added to DateTime.Now().
    /// </summary>
    /// <param name="components"><see cref="DateTimeComponents"/> operand.</param>
    /// <returns>Future DateTime calculated from DateTime.Now().</returns>
    public static DateTime FromNow(this DateTimeComponents components)
    {
        return components.From(DateTime.Now);
    }

    /// <summary>
    /// Calculates the result of DateTimeComponents added to a given DateTime.
    /// </summary>
    /// <param name="components"><see cref="DateTimeComponents"/> operand.</param>
    /// <param name="dateTime">DateTime operand from which to calculate a future dateTime.</param>
    /// <returns>Future DateTime calculated from the given DateTimeComponents.</returns>
    public static DateTime From(this DateTimeComponents components, DateTime dateTime)
    {
        return dateTime.AddYears(components.Years)
            .AddMonths(components.Months)
            .AddDays(components.Days)
            .AddMinutes(components.Minutes)
            .AddSeconds(components.Seconds)
            .AddMilliseconds(components.Milliseconds);
    }

    /// <summary>
    /// Calculates the result of DateTimeComponents subtracted from DateTime.Now().
    /// </summary>
    /// <param name="components"><see cref="DateTimeComponents"/> operand.</param>
    /// <returns>Past DateTime calculated from DateTime.Now().</returns>
    public static DateTime Ago(this DateTimeComponents components)
    {
        return components.Ago(DateTime.Now);
    }

    /// <summary>
    /// Calculates the result of DateTimeComponents subtracted from a given DateTime.
    /// </summary>
    /// <param name="components"><see cref="DateTimeComponents"/> operand.</param>
    /// <param name="dateTime">DateTime operand from which to calculate a past date.</param>
    /// <returns>Past DateTime calculated from the given DateTimeComponents.</returns>
    public static DateTime Ago(this DateTimeComponents components, DateTime dateTime)
    {
        return dateTime.AddYears(-components.Years)
            .AddMonths(-components.Months)
            .AddDays(-components.Days)
            .AddMinutes(-components.Minutes)
            .AddSeconds(-components.Seconds)
            .AddMilliseconds(-components.Milliseconds);
    }
}

 

The Unit Tests

I’ve only included a couple of unit tests so you can get an idea of what we’ll actually be testing and how we’ll be testing it. I hope you’ll notice some immediate refactorings required by the tests below… We have a lot of duplicated test code across the tests and there are actually some fundamental issues with testing the results when working with the DateTime.Now value that cause the tests to fail intermittently. The intermittent failures occur mostly when testing the changes in milliseconds since those units of time are so small. For now though, they’re okay as we’ll be doing some refactoring work in the next post.

[Test]
public void it_should_add_1_year_to_now()
{
    DateTime actual      = 1.Year().FromNow();
    DateTime expected    = DateTime.Now.AddYears(1);

    Assert.That(actual.Year, Is.EqualTo(expected.Year));
    Assert.That(actual.Month, Is.EqualTo(expected.Month));
    Assert.That(actual.Day, Is.EqualTo(expected.Day));
    Assert.That(actual.Minute, Is.EqualTo(expected.Minute));
    Assert.That(actual.Second, Is.AtLeast(expected.Second));
    Assert.That(actual.Millisecond, Is.AtLeast(expected.Millisecond));
}

[Test]
public void it_should_subtract_1_year_from_now()
{
    DateTime actual     = 1.Year().Ago();
    DateTime expected   = DateTime.Now.AddYears(-1);

    Assert.That(actual.Year, Is.EqualTo(expected.Year));
    Assert.That(actual.Month, Is.EqualTo(expected.Month));
    Assert.That(actual.Day, Is.EqualTo(expected.Day));
    Assert.That(actual.Minute, Is.EqualTo(expected.Minute));
    Assert.That(actual.Second, Is.AtLeast(expected.Second));
    Assert.That(actual.Millisecond, Is.AtLeast(expected.Millisecond));
}

 

Resources

A C4SC Series: DSL Development in .NET with C#

11.16.2011 00:12 by kbeckman | Comments

For those of you that follow C4SC, you know by now that I’ve recently been working a contract absent of anything Microsoft and the .NET development platform. I’ve been working entirely in Ruby for about 7 months now and have been consistently acquiring a new set of skills to make me a more well-rounded developer. It has actually turned out to be one of the most educational opportunities I’ve had in my 10-year career in software development. This type of opportunity is extremely rare – so while I’m here (however much longer it lasts), I’m trying to absorb as much as my brain will allow. Here are some of my recent educational highlights:

  • A new perspective on the agile process including the tools that promote agile development (sorry folks, no TFS here).
  • Good working knowledge of the Ruby language as well as a better understanding of how the open source community fuels rapid software development.
  • Newfound appreciation for the MVC pattern (more specifically its implementation in Rails) and how it can make web development enjoyable again.
  • A solid foundation for jumping into JRuby on the Java platform. In the near future, I plan to explore my options with JRuby in Android application development.
  • A new appreciation for domain specific languages (DSLs) and how readable your code can be without the need for comments.

Looks like the result of one of those liberal arts college curriculums, right?

 

Over the next several posts, I will be further exploring the last bullet point from above – a new appreciation for DSLs. It wasn’t always an appreciation… During the first few months learning Ruby and all of the open source gems used in our projects, I experienced a mental overload of domain specific language. EVERYTHING seemed to have it’s own DSL… I’m learning a new language and it turns out that almost every gem has it’s own internal DSL. WTF! That went on for a couple of months or so and then things started to coalesce into understanding. As with anything in software development, I’ll probably never know or learn as much as I want to, but at least now the blank stares into code are gone.

 

So now I will be porting some of the things I’ve learned back to the .NET platform by developing a DSL for working with dates and times throughout a series of C4SC posts. I got the idea when some of my recent Rails work involved some heavy usage of the Date helper methods in the Rails ActiveSupport library. I couldn’t believe how English-like the code read and how easy it was to understand with the absence of comments. I soon felt the need for something like this in .NET…

 

Following is a tentative set of topics that I plan on covering throughout the series. I will update this list if any of the topics change, are reordered or if more are added. I will also include the links to the actual posts as I complete them. Throughout this process, I intend for the codebase to be very fluid and to change significantly. You can follow along on my public C4SC GitHub repository for the latest updates in their entirety.

This is going to be fun and educational – I hope you enjoy!

VirtualBox: Getting Around an Absence of Domain

11.06.2011 00:56 by kbeckman | Comments

UPDATE: The contents of this post are a hack for static IP addresses… I’ve posted a better way here.

 

A while back, I wrote about the benefits of using cross-platform tools (when available) for software development. The Bottom Line: it allows developers to more easily make the transition to other platforms and new languages. The practice enables developers to use tools they are already familiar with without having to assume the overhead of learning a completely new set of tools along with the new platform or language. So in the spirit of drinking my own Kool-Aid, I’ve recently made the transition from VMWare Fusion to VirtualBox to power my back end SQL Server VM required for our Rails project. Following are the setup details in case anyone else out there is looking to do the same…

 

A Little Development Environment Background…

My current client is a typical large enterprise with almost all-things Microsoft. Recently, things have changed a bit with our R&D team because we’ve introduced Ruby / Rails development on Mac Book Pro laptops running OSX Snow Leopard. As is the case with many slow-to-adopt IT departments, our Mac Book development machines are either not required or are not allowed to participate in the corporate domain. It seems to me to be either a fear of the unknown or an unwillingness to support something outside of the status quo – I think that answer will change depending on who ask. Reasons aside, local development must mimic the production environment as close as possible to catch any configuration surprises early in the development process.

 

Step 1: Server Internet Connectivity

Internet connectivity is the easy part… Unless you use some weird, custom setup during your VM build-out, VirtualBox will add a default NAT network adapter to ensure the VM has an active Internet connection. No need for further configuration here.

 

NAT adapter

Virtual Machine Settings: NAT Network Adapter

 

Step 2: Pseudo-Static IP Setup to Replace NetBIOS

As I mentioned earlier in this post, our development machines are not part of the corporate domain. The same is true with our development VMs even though they are Windows servers. Joining a server or development machine to the corporate domain is the only way I know of to be able to assign it a static IP address. It’s also the only way I know of to use NetBIOS to connect to the machine using it’s assigned machine name rather than using a static IP address.

 

Absence of a corporate domain is obviously a problem here… To work around it, we need some VirtualBox customization. I found a solution in adding a second VM network adapter: a Host-Only Network Adapter. It is possible to setup your own local domain using the Windows Server 2008 R2 DNS Server Role. But for a single-server environment, I didn’t want the hassle of setting up and maintaining my own local domain. So I set up the Host-Only adapter to use DHCP. You’ll see from the screenshots below that my DHCP settings provide for a relatively wide range of IP address settings, but the nice thing about VirtualBox’s DHCP server is that it will always assign the first sequentially available IP address to every VM you bring online. In other words, my single VM instance always gets the IP address listed in my DHCP server’s “Lower Address Bound” setting. Bingo! I always get the following IP address for my SQL Server VM: 192.198.56.2.

 

To change VirtualBox’s DHCP server settings, go to “Preferences” in the application settings. From the “Network” tab, use the edit button (screwdriver icon) to modify the network settings for the host-only network.

 

preferences

VirtualBox Host-Only Network Listing

 

The DHCP Server will probably not be enabled by default, so be sure to configure it accordingly.

 

network adapter settings          dhcp server settings

VirtualBox Host-Only Network Adapter and DHCP Server Settings

 

Now you’re done with the VirtualBox server settings. The last part of the configuration is to add a second host-only network adapter to the SQL Server VM. After adding the second network adapter, be sure to assign it to the same virtual network that was configured for DHCP access. If you’ve only configured a single VirtualBox host-only network, you don’t need to worry about assignment as it will default correctly.

 

Host-Only adapter

Virtual Machine Settings: Host-Only Network Adapter

 

Problem Solved!

And that’s it. You’re now ready for server and database connectivity via IP address resolution. Below is a screenshot of the VM’s IP configuration. Notice the dual network adapters.

 

ipconfig

Virtual Machine IP Configuration

 

References