When to find a library vs when to write code.

2015-02-24

As a C/C++ programmer I rarely looked for libraries unless it was larger project. For example, I needed to read a BMP file or a TGA file it's like literally less than 100 lines of code. Look up the format, write a little code, done. On the other hand if I needed to load a JPG file or PNG file those formats are far more complicated and so I'd end up finding a library.

But, now that I'm in JavaScript land there's a bajillion tiny library for all kinds of things and it ends up making me always wonder if I should write some code myself or check for a library. This ends up often feeling like a waste of time.

For example, I have a very small function that replaces things in a string by keyword. Example

replaceParams("Hello %(name)s", {name: "World"});

// produces:
// Hello World

Later it expanded to about 20 lines so you could do this

replaceParams(
    "Hello %(name)s from %(user.country)s",
    {
      name: "Joe",
      user: {
        country:"USA",
      },
    });

// produces:
// Hello Joe from USA

So then recently I wanted to be able to insert other files by path. Like this

replaceParams("->%(insertfile: foo/bar/moo.txt)s<-");

If moo.txt contains this-and-that the result would be

-->this-and-that<--

Now it would only take me a few minutes to add that feature, but ...., there's tons of templating systems in JavaScript. I'm effectively making a templating system. Maybe I should go use one of those instead of re−inventing the wheel.

So, first problem, which one? I've heard of mustache, and handlebars, and jade, and ejs, and others. Why one over the other? I probably spend 20 minutes looking, trying to find comparisons or something that tells me one is better than another. I see ejs = Embedded JavaScript which looks like PHP. I see handlebars is based on mustache but is a lot faster. I settle on handlebars. I change my code to use it in maybe 20 minutes and it's producing the same output so things look good. Great!

I then try to add my insertfile command. Uh−oh 😎 It turns out AFAICT, there's no way to pass info from the template, well, except the keyword. So now it's been an hour. Tell me why I did this again?

And that's really where this post came from, how do you know when you should be looking for a library vs coding your own? Sure this example would probably only have taken me 5−10 minutes if I had just not even looked for a library. But at the same time the library I used had a few features, one it was expandable, yes I can add that to mine too. Another it had options for escaped vs non−escaped substitutions. Sure I could add that too. I don't have an answer.

What I do know is it feels like a distraction, a waste of time. I ranted previously that many popular libraries I downloaded turned out to be broken so there was time searching for libraries, setting them up, and testing them. Conversely I've had people tell me I should use more libraries. For example recently on HappyFunTimes someone told be I should be using the body-parser library to auto−parse JSON rather than do it myself. My code was about 5, maybe 10 lines. body−parser is 2000 lines. Ok it handles a bunch of cases. But, they are almost all cases HappyFunTimes will never hit. I install it anyway, try it out, it turns out it doesn't handle errors the same way as my own code. I see if I can find out how to catch those errors, searching the internet it can't be done. There are references to others who've run into this issue, none of them have been resolved.

I want to use libraries because I'd like to assume they'll handle edge cases I'm unaware of. But, it seems often they're more trouble than they're worth.


update: 2015−4−21

I was wrong, handlebars does support this feature. Not as flexible IMO as what I wrote? but good enough that I switched just for the purpose of using something more people are familiar with. I finished up mine (which is still only about 100 lines), wrote a bunch of tests, and was about to publish it but then I thought I should go dig a little deeper into handlebars before I put something stupid out.

Somethings mine did that they don't AFAICT so far.

They allow parameters but only flat like html attributes.

   {{someHelper arg1="foo" arg2="bar"}}

Where as I just used hanson style JSON

   {{someHelper: arg1: "foo" arg2: "bar", complex: { x: 123, y: 345, foo:[ "a", "b", "c"]}}}

You can think of mine as just "take everything inside the braces, wrap it in a {} and call JSON.parse on it" or in my case hanson.parse because I didn't want to have to quote the property names. That's slightly more flexible though I have no idea if or when it would come up. In my impl it came up immediately.

   {{include: "somefile.foo"}}

just works.

   innerPart = 'include: "somefile.foo"'; 
   var data = Object.keys(JSON.parse("{" + innerPart + "}");
   var handlerName = Object.keys(data)[0];
   handlers[handlerName](data[handlerName]));

So when I implement my example helper

   {{example: { filename: "someexample.html", width: 400, height: 400}}}

It just works, no special treatment. In handlebars' defenses it's based on mustache which was Ruby based which probably means JSON wasn't the thing get.

Another thing I support which I've found really useful is being able to pass in multiple contexts when doing substitutions. So for example if you have a template like this

   {{foo}} {{bar}}

I can apply it like this

   var localContext = { 
     foo: "abc",
     bar: "def",
   };
   var globalContext = {
     foo: "ghi",
   }
   template([localContext, globalContext]);

Which ever substitution is found first is used. AFAICT in handlebars I have to merge all the objects before I pass them into it. there's no passing multiple contexts. Probably not a big deal. It does go up to parent contexts but AFAICT that's not quite the same thing, or maybe I just need to figure out how to coerce my data into a parent/child form.

One more which I'm not totally sure of in handlebars (better check) is I allowed recursion. Example:

   {{include: "{{myfile}}"}}

In other words I want "myfile" to come from the context and then pass that into include. Of course in handlebars you can just do this

   {{include myfile}}

which will pull "myfile" from the current context and pass it to include but it's not quite the same thing. The do allow some recursion but you have to use parens for some reason which makes it sound hacked in.

On the plus side handlebars has escape/unescape options and a bunch of stuff for switching contexts and loops etc which I'm sure will come in handy eventually.

Comments
Tonde Iko, a 6 Screen 5 player game
The VR Workspace