Moment.js Locale Inheritance

Moment.js released version 2.12.0 a couple weeks ago, and with that came a major new feature – locale inheritance.

Defining custom locale data has been possible in Moment.js for a very long time, and it is one of the coolest features of the library.

Suppose I wanted create a locale that was specifically for mobile use, which was in French, but had shorter strings for Moment’s relative time feature. Previous to 2.12, I might have tried something like this:

moment.locale('fr-mobile', 
      {   
      relativeTime : {
          future : 'dans %s',
          past : 'il y a %s',
          s : 's',
          m : 'une m',
          mm : '%d m',
          h : 'une h',
          hh : '%d h',
          d : 'un j',
          dd : '%d j',
          M : 'un mo',
          MM : '%d mo',
          y : 'un an',
          yy : '%d ans'
      }
    });

 

With 2.11.2 and previous, the result would have been great when I called .fromNow():

moment.locale('fr-mobile');
moment().subtract(2, 'minute').fromNow()
il y a 2 m

But I would have gotten a surprise when I called .calendar():

moment.locale('fr-mobile');
moment().calendar();
Today at 10:27 PM

 

English! Whoops. This is because there was no locale inheritance in Moment.js. Locales always fell back to English if data was not defined. To create this fr-mobile locale, I would have had to define every locale property available in Moment.

Enter locale inheritance.

Now I can just define a parent locale for my mobile locale:

moment.locale('fr-mobile', 
      {  parentLocale:'fr', 
        relativeTime : {
            future : 'dans %s',
            past : 'il y a %s',
            s : 's',
            m : 'une m',
            mm : '%d m',
            h : 'une h',
            hh : '%d h',
            d : 'un j',
            dd : '%d j',
            M : 'un mo',
            MM : '%d mo',
            y : 'un an',
            yy : '%d ans'
        }
    });
    moment.locale('fr-mobile');
    moment().subtract(2, 'minute').fromNow()
    //il y a 2 m
    moment().calendar()
    //Aujourd'hui à 22:33

 

Much Better!

Previously, there was also an issue with partial object definitions. Suppose I wanted to change just a couple things about relative time in the French locale. I would have tried this:

moment.locale('fr', 
      {   
      relativeTime : {
          future : 'dans %s',
          past : 'il y a %s',
          s : 's',
          m : 'une m',
          mm : '%d m',
      }
    });
    moment.locale('fr');
    moment().subtract(2, 'minute').fromNow()
    //il y a 2 m
    moment().subtract(1, 'year').fromNow()
    //Uncaught TypeError: Cannot read property 'replace' of undefined

That didn’t go well did it?

Enter updateLocale in 2.12.

moment.updateLocale('fr', 
      { 
      relativeTime : {
          future : 'dans %s',
          past : 'il y a %s',
          s : 's',
          m : 'une m',
          mm : '%d m',
      }
    });
    moment.locale('fr');
    moment().subtract(2, 'minute').fromNow();
    //il y a 2 m
    moment().subtract(1, 'year').fromNow();
    //il y a un an

 

Big thanks to Iskren for getting this in.

Save effort, save file size, be happy!

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?”.