Symphonious

Living in a state of accord.

The One True Language

Lawrence Kesteloot has an excellent post Java for Everything.

About a year ago, though, I started to form a strange idea: That Java is the right language for all jobs. (I pause here while you vomit in your mouth.) This rests on the argument that what you perceive to be true does not match reality, and that’s never a popular approach, but let me explain anyway.

There are two key realisations that are vital to understanding why this argument has merit and the first one is right there in the introduction: what you perceive to be true does not match reality. As Lawrence notes:

The problem is that programmers perceive mindless work as painful and time-consuming, but the reality is never so bad. Here’s a quote from a forum about language design:

It really sucks when you have to add type declarations for blindingly obvious things, e.g. Foo x = new Foo(). – @pazsxn

No, actually, typing Foo one extra time does not “really suck”. It’s three letters. The burden is massively overstated because the work is mindless, but it’s really pretty trivial.

Every developer knows the mantra that code is only written once but it’s read many times, yet we focus on the number of keystrokes required to do something or the number of lines required. Besides which, the time required to type statements is almost never the limiting factor for how fast code can be written – it’s almost always dwarfed by the amount of time required to think about what the code should be doing and how it fits into the architecture.

The second key realisation is how powerful consistency is:

This focus on a single language has had an interesting effect: It has encouraged me to improve my personal library of utility functions (teamten.jar above), since my efforts are no longer split across several languages. […] I can now confidently invest in Java as an important part of my professional and personal technical future.

Being consistent in your choice of language allows you to learn it in much greater detail, become more familiar with a wider range of its available libraries and idioms and get a big return on investment when developing tools or libraries to pave over any rough spots.

None of this implies however that different languages aren’t better suited to different tasks. It just means that the benefits from switching languages is generally overstated and the costs generally understated. Thus, it should be far less common for switching languages to be worth it.

There are times when switching languages makes a lot of sense. For example, if your one true language in Java and you need to write code that runs in a web browser, Java is such a poor fit that it is worth switching languages.

Similarly, it doesn’t have to be Java that’s your one true language – C# would probably make more sense if you primarily worked with Windows environments and C would be better if you were a kernel programmer.

Ultimately it’s not so much about what choices you make, rather that it’s about correctly weighting the factors that go into those choices. We need to be aware of the innate bias we have towards overvaluing the elimination of immediate pain and undervaluing longer term benefits.

Safely Encoding Any String Into JavaScript Code Using JavaScript

When generating a JavaScript file dynamically it’s not uncommon to have to embed an arbitrary string into the resulting code so it can be operated on. For example:

function createCode(inputValue) {
return "function getValue() { return '" + inputValue + "'; }"
}

This simplistic version works great for simple strings:

createCode("Hello world!");
// Gives: function getValue() { return 'Hello world!'; }

But breaks as soon as inputValue contains a special character, e.g.

createCode("Hello 'quotes'!");
// Gives: function getValue() { return 'Hello 'quotes' !'; }

You can escape single quotes but it still breaks if the input contains a \ character. The easiest way to fully escape the string is to use JSON.stringify:

function createCode(inputValue) {
return "function getValue() { return " +
JSON.stringify(String(inputValue)) +
"; }"
}

Note that JSON.stringify even adds the quotes for us. This works because a JSON string is a JavaScript string, so if you pass a string to JSON.stringify it will return a perfectly valid JavaScript string complete with quotes that is guaranteed to evaluate back to the original string.

The one catch is that JSON.stringify will happily JavaScript objects and numbers, not just strings, so we need to force the value to be a string first – hence, String(inputValue).

 

Software is sometimes done

In Software is sometimes done Rian van der Merwe makes the argument that we need more software that is “done”:

I do wonder what would happen if we felt the weight of responsibility a little more when we’re designing software. What if we go into a project as if the design we come up with might not only be done at some point, but might be around for 100 years or more? Would we make it fit into the web environment better, give it a timeless aesthetic, and spend more time considering the consequences of our design decisions?

It’s an interesting question – if we had to get things right the first time, would we do a better job? If our design decisions were set in stone for all time would things be better?

The problem is, we’ve already asked this question and decided that in fact designing things up front and setting it in stone doesn’t work as well as releasing early and often with short feedback cycles so that we can adjust as we go. It’s waterfall vs agile and it turns out agile wins.

That said, there’s a difference between being rushing a sloppy job out the door and doing things well with an iterative cycle to adjust to learning.  An short feedback loop is there to let you learn and improve, not to let you release any old thing and get away with it. We need more software developed by doing the best job possible with the information available, combined with a short feedback cycle to gather more information and continually raise the stakes for what’s possible.

It can be romantic to look back and think that we used to do a better job because things were more permanent, that software used to be done, but it’s just not true:

When Windows 95 came out, it was done. Yes, there were some patches to it, but they were few and far between, and in general quite difficult to come by. But of course, then the Internet and App Stores happened in full force, and suddenly we decided that “Software is never done”. In some sense this is certainly true. There are always bugs to fix, things to improve, more features to add, unused features to remove — and of course, the SaaS model makes it all so easy. But I wonder if we’ve taken this a bit too far.

Windows 95 may have a been done, but Windows was not. Otherwise we’d still be running Windows 95. We’re kidding ourselves if we think that anyone at Microsoft ever thought that Windows 95 would be the last thing they ever released, that the OS would never change in the future.

Even if we consider Windows 95 as a standalone thing that is “done”, would you run it today? Of course not, by modern standards it’s horrible. The same is true of every other piece of unmaintained software I can think of, it may have been good enough or even the best for a long time after it became unmaintained but eventually it falls behind. Eventually it stops being “done” in the sense that it doesn’t need any further work and becomes “done” in the sense that no one uses it anymore.

 

CI Isn’t a To-do List

When you have automated testing setup with a big display board to provide clear feedback, it’s tempting to try and use it for things it wasn’t intended for. One example of that is as a kind of reminder system – you identify a problem somewhere that can’t be addressed immediately but needs to be handled at some point in the future. It’s tempting to add a test that begins failing after a certain date (or the inverse, whitelisting errors until a certain date). Now the build is green and there’s no risk of you forgetting to address the problem because it will fail again in the future. Perfect right?

The problem is that it sacrifices the ability to easily isolate the cause of a failure. You can no longer revert changes to get back to a working baseline because the current time is a factor in whether your tests pass or not. You can no longer run historical builds through CI which you may need to do as part of supporting clients on older versions.

It also inevitably leads to false failures as the time points are almost always arbitrary and estimated time lines for completing tasks often slip. So the board goes red and the response is to just suppress it again.

Continuous integration isn’t there to remind you to do something – it’s there to tell you if your build is ok to ship to production or not. It doesn’t make sense to say that a build is ok to ship to production now but not ok to ship in a week’s time. If production is going to blow up in the future because of a bug in the code you want to the board to be red now, not when production actually blows up. And if the client is prepared to accept the risk and leave the problem unfixed then it’s not yet a requirement and doesn’t need tests asserting it – just put a card in the backlog for the client to prioritise and play when required.

If you need to remember to do something, either put a task in the backlog or on the current story board to do it or put a reminder in your calendar. Keep CI focussed on telling you about the state of your code right now – if it’s broken it should be red, if it’s not broken it should be green. Not broken until next week should never be an option.