Javascript: References to out-of-scope variables.

In JavaScript, referencing variables that are declared outside of a function’s scope can be tricky. If you have code like this:

<script>
  var btn = document.getElementById("BTN");
  var test = 1;
  btn.onclick = function() {
      alert(test);
  }
  test = 2;
</script>

The click handler above retains a reference to the test variable even though it falls out of scope as soon as the script block finishes execution. When you actually click the button, the alert will show the last value of the variable when the block finished execution (2) instead of the value at the time the function was initialized (1).

I thought about this because another developer raised a similar problem to me a few days ago. He had a loop that was initializing click handlers for an array of elements. Of course I can’t replicate his example here, but let’s say we wanted to add click handlers to an array of buttons that would show the result of multiplying an input value by different integers.

  <script>
    var btns = [];
    btns.push(document.getElementById("BTN1"));
    btns.push(document.getElementById("BTN2"));
    btns.push(document.getElementById("BTN3"));
    btns.push(document.getElementById("BTN4"));
    var input = document.getElementById("IN");
 
    for (var i=0; i<4; i++) {
      btns[i].onclick = function() {
        alert(input.value*(i+2));
      }
    }
  </script>

This is kind of an analogous example for the problem. In this case, the expected behavior is that the first button outputs the input value times 2, while the second button outputs the input value times 3, and so on. But because each of the click handlers retains a reference to the loop counter i, what they will remember on execution is the last value of i after the loop exits, that is, i==4. All the buttons will show the same output.

There are several ways to correct the behavior. One way would be to build the click handlers using a utility function, like so:

   <script>
    var btns = [];
    btns.push(document.getElementById("BTN1"));
    btns.push(document.getElementById("BTN2"));
    btns.push(document.getElementById("BTN3"));
    btns.push(document.getElementById("BTN4"));
    var input = document.getElementById("IN");
 
    function getClickHandler(counter) {
      return function() {
        alert(input.value*(counter+2));
      }
    }
 
    for (var i=0; i<4; i++) {
      btns[i].onclick = getClickHandler(i);
    }
  </script>

This way, the value for the local function variable “counter” is locked in once getClickHandler exits execution, and each returned function now has a reference to a different “counter”, and the buttons will behave as expected.

Are you willing to accept criticism?

If a friend found out your work was horrible, would you want to know? Or would your feelings be hurt?

If your coworkers think you’re doing something wrong, would you prefer that they keep quiet or that they call you out?

As a leader, do you prefer to have sycophants who sing your praises or people who are willing to tell you that you have no clothes?

Is your ego more important than doing a good job or self-improvement?

But what if the guy is just being an asshole who hates me and wants to discredit me?

Whether or not someone is an asshole is independent of whether or not his criticism is valid. You can call him out for being an asshole if you want, but you owe it to yourself to consider if any criticism given to you is valid and something you can act on regardless of whether the messenger is an asshole or not.

If you are afraid that having your mistakes called out will be damaging to you, consider how damaging it will be if you keep doing those mistakes and develop a reputation for them.

Your Product Should Be Easy to Install

This is a story of something I consider to be one of my worst mistakes in software product development.

Some years ago I was asked whether it was feasible to write software that would be integrated with Software X that allowed us to export that software’s output into a format that was compatible with Standard Y. I took a look and after a while came back with “Well sure. We could use Programming Language M that has an API that lets us integrate into Software X so we can export the output data. Then we’ll have to use Library N which lets us generate files in the format compatible with Standard Y. What project is this for by the way?”

“Oh, it’s not a bespoke project. It’s a product we’re going to develop with a partner company.”

“Oh.” That set off some alarm bells, so I pointed out that Programming Language M and Library N required the client to install two different runtimes on the client machine. I suggested we consider itself writing our own conversion library so that we wouldn’t have to require two different runtimes, but the cost estimates turned out to be prohibitive so of course we went with the more complicated stack with two runtimes.

It was a disaster. It turned out to be almost impossible to convince users to install and try out our software when the installation process included a step where the user needed to download and install a programming runtime from an external website (the licensing terms of the runtime did not allow us to package it together with our installer). In hindsight, it was probably a newbie mistake since this was the first time we were working on software product development. If this was our usual bespoke software project where users had IT staff to install software on their enterprise systems, it wouldn’t be a problem.

I learned a lot of technical stuff from that project (there was a lot of math involved in the data export too), but the most important thing I learned was that the best software product in the world is going to fail if you make it difficult for your users to install it.

Wizard’s First Rule and Demagoguery

The series was a bit formulaic, and towards the end really preachy toward’s the authors personal philosophies, but Terry Goodkind’s Sword of Truth series always comes back to me because it codified one of life’s most important truths:

Wizard’s First Rule: “People are stupid. They will believe a lie because they want to believe it’s true, or because they are afraid it might be true.”

That doesn’t mean you’re stupid or I’m stupid, just that collectively, we’re kind of dumb. Put another way by another wise character in popular culture, from the film Men in Black:

Kay: A person is smart. People are dumb, panicky dangerous animals and you know it.

This is what makes it so easy for demagogues from Hitler to McCarthy to Trump to certain local politicians to stir up support: create a boogeyman that people fear, and people will willingly believe your lies as long as you tell them what they want to hear (under the guise of “telling it as it is”).

The thing is, a demagogue doesn’t even have to be consistent in what he says: he can say one thing at first (“our anti-crime drive is doing well, crime is down”) to project one image and a contradicting thing later on (“There is a state of lawlessness, we should consider harsher methods.”) depending on how his goals change and what the particular audience wants to hear. It has the added benefit of making anyone who reports on it look bad and inciting conflict (because people never agree on what the demagogue means!)

While the Wizard’s First Rule is a saddening fact of human nature, we should take heart in the fact that despite humans being stupid and often being caught in the same traps, tyrants still fall and progress is eventually made and we somehow manage to muddle through and humanity survives long enough for the next crisis. (Although Trump’s climate change denial could seriously test that last part.)

Unclear error messages

“Button for non-service floor does not light up.”

For more than a decade I regularly went to an office building where the elevators verbally spouted this nonsense message whenever you tried to go to a floor that the current elevator car did not service. For context, the elevators in the building were zoned programmatically – this means that they only service a particular subset of the floors that are provided on the elevator panel itself. They sometimes disable the zoning depending on the loading among the elevator cars so simply removing the buttons for the unsupported floors isn’t a viable solution.

Back to that message: It’s terrible. At least once a week, some clueless newcomer to the building would press the button and hear the message and totally be unable to relate it to what he just did or even understand what it was saying. (That the message audio did not have the best quality only compounded the problem.)

See, that error message doesn’t make sense because it’s telling you something you already see: when you press the button for an non-service floor, the button does not light up. It’s the equivalent of submitting a web form and receiving an error message of “Your form was not submitted.”

A good error message should do three things (none of which the elevator message do):

  • It should tell the user something went wrong.

The first one is easy and may immediately be made obvious by the nature of the error message itself. For a web platform, error messages are often displayed highlighted in a different colored font and with some sort of “X” or other icon indicating a mistake has been made. For the elevator message. For the elevator message, I’ve often observed that some people dismiss the verbal message as background noise unrelated to the button they just pressed, and some will even repeatedly press the button again, ignoring the message. An improvement would be to have some sort of high-pitched buzzing noise whenever the button for a non-service floor is pressed, before giving the verbal message. Pressing the button multiple times would reset to the buzzing noise, making it painfully obvious that “Hey, maybe I should pay attention.”

  • It should tell the user what went wrong.

For a web platform this typically means some of the fields failed some validation, in which case you should list them out. Something like “The following problems were encountered: Name is a required field. Date must not be later than today. Amount must be greater than 0.” and so on. One must also take care to use more plain language rather than technical, i.e. “The Name must be filled in.” might be better than “Name is a required field.”

For the elevator message, instead of describing what the user already sees when he presses the non-responsive button, more useful would have been a direct “This elevator does not go to that floor.”

  • It should tell the user what he can do to correct it.

For web forms with validation errors, a simple “Please correct these errors and resubmit the form.” should suffice. For the elevator message, it could simply say “Please try a different elevator.”

Good error messages make a big difference in the usability of your product, be it a web form or an elevator or something else. It makes it easier for users to find and learn their own way forwards rather than needing someone to walk them through their actions.

Bad news

Recent events both in my country and abroad, both of wide importance and personal importance, have made the past week or so difficult. Bad news and bad events have no master or timing, they do not consider giving us a break, they come and go as they please no matter how bad the situation already is.

I fully understand why many people choose to withdraw from daily news or shut it out altogether or even just avoid social media completely. Hearing the bad news can be disheartening, and it comes at us even when there is work to be done or words to be written or deadlines to be met. We have no choice but to soldier on, to slog through the bad news and do our work anyway. It is the world we live in.

To withdraw from this world and hide away from all the darkness is understandable, if only for a short time. But all the bad things in the world won’t go away simply because we refuse to see them. At some point we have to come back to it and voice our objections and engage in discussion and reach out to other people and ask what we can do to help turn the tide. It is not a burden we simply leave other people to bear, it is on our shoulders collectively to try to make the world a better place, if only a little bit at a time, if only by saying “I don’t think these things are good, and here’s why”

The world doesn’t stop for us because it makes us sad. The work that needs to be still needs to be done. We move forward, one step at a time.

Be Willing To Throw Prototypes Away

 

There was this project we had where there was a strange bug. The developer working on it found that the problem only appears when the record ID was 12. When it was 11 or less, everything was fine. When it was 13 or more, everything was also fine. After some investigation, it was found that there was some code that executed with a condition of “if record id == 12”, which was already a WTF. It turns out that some behavior had been hardcoded for a previous demo to a client and was never reverted and made it all the way into acceptance testing builds.

Prototyping and demo builds are great tools and all, but I’ve observed a dangerous tendency for upper management to afterwards say “we already have the code right? So we just deploy it”, or something to that effect. The urge to save on development costs is understandable, but the developers who built the prototype have a responsibility to raise any risks due to poor code or hacks or workarounds or some sort of hardcoded shenanigans to make sure they are properly addressed before the code gets deployed anywhere serious. Many of these shenanigans tend to be found in prototypes or demo codes that were developed in a short timeframe to hit a particular demo date.

Above all, the team should be more than willing to decide if there is no way the demo codebase is good enough to be rolled out to an actual client and be willing to say no to such requests if needed.

(Demoing functionality you don’t really have yet is a separate matter entirely, one I don’t approve of naturally)

Whatever Doesn’t Kill You Only Makes You Stronger

There’s a very rare, privileged group of people for whom everything in life goes well and they experience great success all the time.

You and I are not part of that group (most likely). Like the vast majority of other people, sometimes our lives are good and sometimes our lives are bad.

Sometimes life can feel cruel or unfair or exhausting. In those times it’s easy to forget the times when life was good and to wallow in your misery. And I guess to some extent humans need a bit of that wallowing time, but try not to linger there too long.

You have to take the good and the bad life gives you and make what you can of it. Whatever failures or trials you suffer, learn from them and move on. Let the low points forge you into a sharper sword. Whatever doesn’t kill you only makes you stronger

Software Development Feedback Loops

The software development process is already difficult mainly because a lot of it so imprecise. Requirements are often only vague wishes that the client has, with no regard to the sheer number of instructions needed to implement those requirements. Throughout the entire process it’s important to use feedback loops to determine whether development is on the right path. And like all feedback loops, their effectiveness often hinges on how quickly we are able to turn around and give and incorporate feedback into future iterations

Feedback loops happen whenever someone gets to review something of course. Prototyping with the client is the most basic form of feedback loop. Building a quick prototype, then showing it to the client, seeing what works and what doesn’t and what the clients wants to change, then iterating into the next prototype – all of these reduce the risk that we are not building the correct thing in the first place. Similar feedback loops appear whenever someone reviews your design or your code or your documentation

For me personally, the more important feedback loop happens at the coding level. It is very rare for a dev to code to everything in a program (no matter what size) in one go. Instead, programs are almost always built incrementally, in a loop of code->build->test->back to coding again. Thus it is very important to make sure that this build is as tight and as optimized as possible

One of my major annoyances with working with Java and Eclipse over the past ten years is that even though Eclipse has that “build automatically” feature that should provide instant feedback, in practice there can be significant lag time while the application is built and for web applications, often your local server will need to be restarted to reflect the changes. Given how often devs iterate while coding, even a few seconds of lag time in each loop is already a minor annoyance. Build times of one minute or more will be deadly to productivity, often taking the dev out of the much-desired “flow zone”. Thus you have to optimize this cycle as much as possible – with Java/Eclipse/Tomcat, that meant disabling all unnecessary build validations, reducing your application size by removing redundant code and dependencies, and so on. Hardware optimizations are also an option – I was really happy when the company finally decided to spend money on SSDs for the devs (money well spent)

This problem also happens in the bigger loop of devs coding -> build deployment -> verification by the testing team -> send bugs/comments back to devs for fixing. Often the main bottleneck is the build deployment, so you want this process as fast as possible as well. I’ve been on projects where we had the misfortune to have the build process go as long as 2 hours at a time. After some optimization, we were able to trim it to around 30-40 minutes, but this is still pretty bad. During hard deadlines when you have to deliver something the next day, this loop can cycle many, many times, and long build times will be the difference between whether your team merely does a bit of overtime or have to stay until morning. Unfortunately it can be a difficult problem to address, and the fact that the problems only become urgent during the times of greatest schedule pressure does not help. I believe that once you have a large enough system and dev team, having people dedicated to maintaining and optimizing the build system quickly becomes a necessary evil

Feedback Loops

A feedback loop happens in a system when you are able to use an output of that system to influence the inputs, which in turn influences the outputs and repeats the cycle

In engineering, feedback loops are useful to generate steady-state outputs. We had an entire subject dedicated to feedback loop controllers back in college. I enjoyed the topic so much I took the subject twice! An example of the use of feedback loops would be a thermostat that has a sensor to detect the current temperature. Once it senses the current temperature, it compares that with the target temperature and uses the difference in values to adjust the thermostat input. In this way, the temperature eventually reaches the target value

Humans are also machines subject to feedback loops. We enjoy receiving positive feedback. The more feedback we receive about how well we are performing, the happier we are and the more we are able to perform well. This is part of why we enjoy getting paid a salary regularly – some part of our brain treats money as a way to “keep score” and as feedback that hey, you’re not doing so bad, here’s some cash to keep you going!

Feedback can be negative too, but the effect can vary based on the person’s attitude. If you accept feedback and criticism of your work and use it to learn and move forward, then you can use even negative feedback as positive reinforcement. If you refuse to acknowledge legitimate negative feedback and instead take it personally or criticize the one giving feedback, then you are failing to learn from the feedback and it either becomes useless or in the worst case can even reinforce negative behavior

Quicker feedback loops allow humans to iterate faster and determine which behavior is best to achieve his goals. My favorite example of feedback loops is in games. Computer and video games are very good at providing near-instant feedback. Run into an enemy? Okay that means you take damage, so that’s not good. Finish a task? Ah, you gained some experience points, so it looks like that’s good. And games will even tell you immediately how far you are from achieving your goal! How many experience points until I unlock a new ability? How much more damage can I take before I die?

People enjoy this sort of instant feedback loops, so more and more systems are using some form of “gamification” to improve adoption and usage. Websites like stackoverflow grant you points for answering questions. Fitness trackers give you immediate feedback on how many calories you’ve lost. And so it goes

The downside of this instant feedback culture is that it becomes more difficult for us to appreciate things that have long feedback loops. And they are already difficult in the first place, since the feedback takes a long time to get back to you!

My favorite example of this is dieting. Dieting is hard mainly because you suffer regularly (due to having to eat food you don’t like) but the effect isn’t measurable immediately. It takes a while to notice any changes, so it takes more discipline to maintain the diet in the absence of that feedback.

This is why people have systems like calorie counting – it provides an intermediate feedback to substitute for the feedback you don’t have yet on how much weight you’ve lost or gained. But it’s still an abstract concept and doesn’t translate too easily into weight gained or lost. And also it can be difficult to track precisely since not everything you eat will have a calorie count available. I reckon that once we have an app where you just take pictures of the food you just ate it tells you how many pounds you gained or lost, a lot of people will be better at keeping to their diets

I like to look at the activities I pursue regularly and see if there is anything I can measure to help provide feedback loops for self-improvement. This is why I enjoy daily habits that track streaks – it’s simple, instant feedback that tells me I accomplished something.

Of course, humans are not machines that need to have perfect systems and be slaves to their feedback loops. So it’s also okay to break your daily habits every so often or to cheat on your diet once a week or such, it is one of the privileges of being human. And breaking your patterns also provides some feedback which you can use later