Moment.js and Klingon Your Dates

So, I haven’t blogged in a long time. There are a lot of reasons for this, but the main one is that I’ve found a project.

I recently was invited to join the Moment.js core collaborators team. How this happened is a weird accident of networking. At CodeMash in January I was told I had to meet Matt Johnson. It turns out that Matt and I have both:

  1. Given conference talks on RavenDB
  2. Developed a time and attendance solution

This is a a very weird set of things to have in common with someone. If there is a third person in the world who has done these two things, let Matt and I know – we would like to be your friend.

Anyways, Matt is on the Moment.js team, and he decided that I should take what I know about date and time and come help out, so here I am.

Over the past month I have had a huge amount of fun working on the project. At this point I mostly write documentation and answer people’s questions on GitHub, but I have snuck a couple pull requests in :-).

On the subject of fun, it is a little known fact that as of 2.11.0 Moment.js supports Klingon as a locale, thanks to some wonderful nerds on the internet.

I felt compelled to make something out of this, so this past weekend I set out to change all the dates in your browser to Klingon via chrome extension.

As it turns out, chrome extensions are crazy easy to make. In order to support Klingon-ing of all dates, I simply queried the DOM with some regular expressions that would match a lot of common English date formats, and then fed them into a function. All of the code relevant to Moment.js is right here:

    function toKlingon (match) {
        //parse the string using the format that the Regular expression is looking for
        var a = moment(match, format);
        //change to the klingon locale and return formated as local long date
        return a.locale('tlh').format('LL');
    }

 

Rest assured that the DOM parsing involved was substantially more difficult than this.

This is a great example of just how well Moment.js does i18n. I don’t need to know anything about this language to be able to output dates formatted exactly as native speakers would.

The extension does have an issue where it will always display all date parts, even if they weren’t parsed. For example, dates from Gmail, which are written as “Mar 13” are output with a year.

I am working on a minor change to Moment that will expose what date parts were actually parsed, which would allow me to easily include only valid data in this situation.

I also need to do some more work on better/faster DOM parsing with the regular expressions, as it still doesn’t get quite every date, but generally the extension works. If you would like to try it, find it in the chrome store here.

Katas and Insecurity

I’m at CodeMash today doing precompiler sessions, and I have to say that it has so far been a great time.

Today I spent most of my session in an “Improving Software Craftsmaship” session where we pair programmed several Katas. In the course of doing this, I found myself paired with a couple of people who were a bit faster to the punch than me on what needed to be done next.

Now, I’m used to this. My coworker Erik can always do basically everything faster than me, and believe me when I say that this doesn’t upset me. Erik is a friend, and I always appreciate his help. This was DIFFERENT though.

See, here at CodeMash, I’m walking around with one of the blue lanyards – I’m a speaker. So, when someone bests me at Katas, I feel like I haven’t lived up to some unsaid expectation. This caused me a bit of a panic attack. I found myself having to walk down the hallway and remind myself of these things:

  1. I am here to learn as well as talk
  2. I can practice and get better
  3. I have my own strengths

This post is admittedly trite, but I wanted to put it out there anyways as a reminder to everyone that, well, we all feel insecure sometimes.

Dog Breeding is a Craft

I want to depart a bit from posts on the craft of coding, and instead focus on another craft that is near and dear to my heart. That is the craft of dog breeding.

It is very popular these days to say things like “don’t shop, adopt” when people talk about getting a puppy from a breeder. I understand the sentiment behind these statements – with, indeed, lots of dogs in rescues and shelters, why would one adopt from a breeder? Lots of great people in the dog world have written great things about why breeders are still relevant, and I won’t rehash arguments that others have given. However, one argument that I don’t see often is one that’s very important to me as a software craftsman.

Dog breeding is at it’s heart, a craft. In the same way that carpentry, metal work, masonry, glass blowing, brewing, and many other arts are passed down from master to apprentice, so is quality dog breeding. It takes years to become a master dog breeder. Many dog shows, many trials, many conversations, many litters that you put your heart and soul into, many litters that don’t work out exactly the way you wanted. It takes mentorship to become a master dog breeder. Nobody becomes a great dog breeder without being mentored by one or more other great breeders. One starts as an apprentice and works one’s way to mastery.

Dog breeding is one of the oldest crafts known to mankind. Keep in mind that dogs have existed nearly as long as humans, and many anthropologists believe that large parts of the success of the human race can be attributed to our breeding dogs from wolves to be our early hunting companions. This means that we have been selectively breeding dogs as long as, or longer than we’ve been engaging in other ‘ancient’ arts like brewing.

Wouldn’t it be heartbreaking if nobody ever made a finely crafted piece of furniture again because Ikea furniture is cheaper and readily available? We would lose a piece of human history if that happened.

When people suggest that nobody should breed dogs until there are no more dogs in the world to rescue, people are suggesting the death of an art that is as old as time. If everyone stops breeding dogs, there will be no more mentors for the next generation. We will lose an art that helped to build the human race. We will have to relearn what people have been perfecting for thousands of years.

I’m hardly advocating that everyone who breeds dogs should continue to do so. In fact, most people who are breeding dogs would do well to get out of the business. But those who are truly participating in the ancient craft with dedication should be encouraged to continue and supported in their endeavors, in order to preserve a part of our history.

Does it Scale?

Raise your virtual hand if you’ve been discussing a problem in software and asked the question “Does it Scale?”

You are probably raising your virtual hand right now, because we as software developers LOVE to ask that question. Interestingly, when we ask that question, it tends to mean a lot of things. In general, it can be translated into two main, and very distinct, questions:

  1. Can the solution be easily changed to allow for more user traffic over time?
  2. Can the solution be easily changed to allow features to be added and updated over time?

The first question generally deals with things like adding hardware to servers or adding additional servers to accommodate load. The second question deals with what architectural patterns are used, how many unit tests are written, what development methodologies are used and how the solution is supported, among many other things.

A couple of years ago, I was in a three day training with Ayende about RavenDB. At the time I had just become a tech lead and was taking point on my first project, which was using RavenDB.

During a discussion of sharding, I mentioned that we might be interested in this feature. Ayende asked me to name the number of requests per minute that we expected to have, and the number of requests that we never expected to reach, even if massively successful – a practical upper limit per say. I wasn’t able to give a good answer to this.

I think this reflects a general trend of developers when interacting with the question “Does it scale?” Truthfully, I think we don’t know what the heck we’re talking about when we ask that question!

I would like to propose some alternative questions to “Does it Scale?” that I think enhance the way we think about our technologies.

  • What are my target usage goals and will this solution either allow me to reach them with a single server, or allow me to add additional servers to my cluster to reach my target usage goals?
  • Does my programmatic solution allow me to add additional servers to my cluster without issue?
  • Is my deployment story a maintainable one over time?
  • Is my code following SOLID design principals so the code base will be able to grow over time?
  • Are my tests adequate to allow for refactoring in the future?
  • Will simply adding additional hardware adequately provide for my growth needs?
  • Does the technology I’m considering using have a good DevOps story? Is it easy to deploy, configure, and keep in good health?

All better things to think about than “Does it Scale?”.

RavenDB Mistake 3 – Giant Documents

Any initial training on RavenDB or any other document database will talk a lot about a concept in Domain Driven Design called aggregate. An aggregate is a set of domain objects that can all be contained within one other domain object, called the aggregate root. The standard modeling advice for a document database is to identify the aggregate roots in your domain model, and use those to create your documents.

Armed with this standard advice, we set out to find all the aggregates in our domain, and we made some mistakes. One of the first mistakes that we made was creating an aggregate out of what was really two entities, thereby creating a gigantic document.

To illustrate this, let’s use a standard order tracking system as an example. In an order tracking system, one probably has a set of customers, and a set of orders. Each order must be associated with a customer. Because an order cannot exist without a customer, we maybe think to model a document in a way that looks like this:

public class Customer
{
	public int Id {get;set;}
	public String Name {get;set;}
	public List<Order> Orders {get;set;}
}

public class Order
{
	public int Id {get; set;}
	public decimal Amount {get; set;}
	public List<Item> Items {get; set;}
}
public class Item
{
	public int Id {get; set;}
	public String Descritpion {get;set;}
	public decimal Price {get;set;}
}

This code does kind of makes sense. But it totally breaks down the minute we want to find an order by ID. First of all, Raven doesn’t include a way to generate an ID for a collection inside of a document, so to guarantee the uniqueness of the Id on the order, we’re forced to go to a GUID. This is just inconvenient from a usability standpoint. No customer wants to call in and have to rattle off a 32 character order id jut to get shipping status!
In addition, there is no way to get information about an order without querying an index on the customer document. Now instead of just calling _session.Load<Order>(Id) we’ve been forced to make an index on customer and query it just to grab something we already know the identity of!

In addition, our document now has the potential for boundless growth. A loyal customer’s document might end up having thousands of orders attached over the course of several years, and grow to be several megabytes. This would be neither fun to pass across the wire using HTTP, nor fun to hold in memory.

The fundamental problem here was that we put so much effort into finding aggregates, that we forgot to recognize an entity that was staring us in the face!

Remember, if an object has an identity that stays the same as the object changes, the object is an entity. Another way to put it is that an entity is identified by it’s Id, and not by it’s attributes. An entity should not exist as part of an aggregate, the root of which is another entity. The example given here is obvious (and not our real situation), but it turns out that this mistake is actually easy to make.

It is worth noting that this is a common mistake in Raven, but it’s a general mistake made with any document database.