6 Things Junior Developers Should Learn Right Away

Check out this great, in-depth guest post from the CONSENSUS™ development team. Authors include Fumiko Richards, Stephen Felt and Rosy Grimaud

Let’s face it, being a junior developer isn’t easy.

bigstock-young-developers-twitterYou love what you do and you want to succeed at your craft. You are eager to learn the secret practices whereby one developer can be 10x as productive as another (see Steve McConnell’s blog post). And, you frequently alternate between states of apprehension ranging from finding a bug you are not equipped to handle, to euphoria, at finally discovering the solution for the bug that does appear.

But most importantly, you want to create quality code that is clear so that you can be proud of it, and your successor does not curse you for it. Especially if that successor is you returning to add a feature next month.

There is just so much to learn and so little time. The lessons that really stay with you are the ones where you stumble over in the dark and fall sprawling. As you blindly feel around to find some ray of light to lead you back on your way, you wonder how you ever got anything done. You never again stumble in that same dark spot, knowing what you know now.

In this post, we will put up a few lights in dark areas to help you avoid stumbling and get back you back up if you have fallen.

1: You should not simply compare floating-point numbers

One of our projects involved comparing data that was stored as floating-point numbers.

Here is an example from my own experience:

    If(a > b)  {  do_something();}

We saw strange results. As we began to test, many values made it through just fine and the code seemed to be working great. But as we looked at cases when the values seemed to be exactly equal (0.227 and 0.227, for example), the do_something function was still getting triggered.

Here are some things to consider before we dive into the solution:

Integers, which we think of as whole numbers (e.g. -1, 0, 333, 42) can be compared because they are stored as exact values.

Floating-point numbers are numbers with decimal points. “Wait!” you say, “Isn’t 1.1 exactly equal to 1.1?” The short answer is no, they are not. And if you think about it, this makes sense.

Take the number 1/11. Try dividing for yourself. Your result? Well, if you are using a calculator, you might one of these results:

0.090909090909091

0.00909090909091

0.0909090909

And if you grabbed a pencil and paper, you probably stopped at some point, too. Because the result is never ending (as far as we know) and your paper is only so wide.

Computers can only devote so much space to storing these numbers, too, so they “give up” after they have used up all 32 or 64 bits they have allotted to handling each number (excellent and detailed explanation)

The upshot is that floating-point numbers cannot be compared the same way integers are. If you do compare them, then you have created an exceptionally pernicious bug because languages, by and large, are perfectly happy to compare floating-point numbers.

Here are few solutions to this issue:

  1. Decide how many significant digits you need to store, and store them as an integer with an implicit exponent. For example, if you are running a store, consider storing prices as cents (199) instead of dollars and cents (1.99). If you are tracking durations, consider storing milliseconds (1110) instead of seconds (1.110). You have to decide how many digits are significant to you.
  1. If you must work with floats, decide, once again, how specific you need to be. For example, if you are tracking the duration of a phone call, it doesn’t really make sense to say, “That call was 1/10,000 of a second longer than the previous call.” When is the exact end of a call anyway? When both parties have ceased speaking? When one party presses a button to terminate the call? At any rate, your precision does not likely need to be ten-thousandths of a second.

So, to compare the two values, subtract one from the other, then decide whether the difference is big enough to count.

a = 36.12 seconds

b = 36.12 seconds

if( absolute_value(a – b) > .0001 ) {

 // they’re different enough! Do something…

}

2. Rules are made to be broken

Ok, not really, but sometimes rules need to be broken. Because every rule has a reason, if your circumstances do not match the reason, then you might need to break your rule.

For example, consider ternary operators. While they are not evil in themselves, stuffing too much logic into them, or nesting them can lead to nearly illegible code. And so, to avoid anyone getting carried away, we made a rule as a team to not use ternary operators.

So the rule is, don’t use ternary operators. But the reason is because nesting them or trying to do too much in a ternary operator leads to difficult-to-follow code.

But, what if the opposite is true? Not using ternary operators can lead to code that is much longer and hard to follow. Consider this contrived example (and imagine needing to test and initialize dozens of variables):

if(a > 0)

{

 b = a;

}

else

{

 b = 0;

}

This can be expressed using a ternary operator like so:

b = (a > 0)? a : 0

So, when circumstances don’t match the reason you made the rule in the first place, and breaking that rule leads to better code or a better practice, then break it.

3. The hardest bug to track down is no bug

When a bug is reported, a programer might set about searching to find the malfunctioning part of an application. We may try to replicate it in a test environment, or start poring over error logs. After all, once you find an issue, it is often easy to fix.  Tracking down the bug is the most time consuming part, right?

But what if there is no bug? How long can you search for something that isn’t there? The answer is: forever.

Some bugs are actually just a misunderstanding. Perhaps the reporter’s expectations are contrary to the proper behavior of the application. Imagine for a moment a library. If a book is due Friday, but not returned until 7 in the morning on Monday, is it past due? At my library, thankfully, it is not. But if a new librarian from another library is accustomed to a different policy, he or she would consider this past due. And for the new librarian, as well as the reporter of a bug, not meeting those expectations can seem like a bug in the system.

Sometimes, however, we do have a real bug, but it is not in our system or code.

Recently, our office’s Internet connection stopped working. Going back to what had changed, we realized we had reconfigured the wireless router the night before. We pounced on it, and took several steps to restore it back to health (yes, we turned it off and back on, too). But, we still had no Internet access.

We started to walk up the chain until we were outside of our building. It turned out that our Internet provider had suffered a backhoe and fiber optics-related incident. We could have kept fiddling with our wireless router for days and it would have made no difference, the problem was outside of our sphere entirely.

4. The next-hardest bug to track down is 2 bugs

There was what seemed to be one bug on one environment that could not be replicated on any other environment. The cron function kept repeating itself and firing off so many processes.

Because it seemed to be happening on only one environment, we thought the cause must be an environmental issue. But our search turned out no good cause for this issue. Next we looked at the functions trying to find any places we may have been looping. Perhaps a flaw in the logic was causing an infinite loop. And, again we had no good lead to the issue.  

As we debugged further, we realized that this was in fact a product of 2 issues. The first issue was comparing floating-points. When we did not need to take any action, because the values were supposed to be the same, the computer thought that one was bigger than the other. The second issue was that the command cron was using (wget) was set to keep rerunning the function if it timed out. So comparing floating-points caused each function to run a lot longer, and then wget kept calling itself over and over, since the server got impatient and responded with timeout error.

Because of the combination of these issues, a simple code issue (Comparing floating-points) behaved like it was caused by environmental issue. It took us down the wrong path in our search for a possible solution.

5. Never assume

To quote Sir Arthur Conan Doyle:

How often have I said to you that when you have eliminated the impossible, whatever remains,however improbable, must be the truth?”

While debugging, assuming certain parts are working fine just because it looks good, and it was working the other day, could cause you to miss the real cause of the issue. Likewise, assuming certain functions of a new feature should work in a certain way without confirmation from the product manager could result in redoing the entire project.

As mentioned previously, when we had assumed that the cause of an issue was an environmental setting, it costed us a few hours. And ever since, we make sure that we are checking every part of the function, from the beginning to the end, and step by step. This process has allowed us to identify issues a lot quicker.

Never assume. It only makes animals out of all of us.

6. Pair programing is great

In the beginning, programming alone is great. You gets tickets assigned, and you fix the issues or get to create the new features. You get to work at your own pace, and feel productive. Then, our CTO mentioned that he wanted us to pair program often with each other. This made some of us feel very uncomfortable. Some had never pair programmed before, and everyone else’s extensive experience was intimidating to the junior developers.

Just as people have different styles of talking or writing, they also have different coding styles. It can range from something very small like how to indent lines (tabs vs spaces), to something bigger like how to organize a function, file, or project. Even thought processes are unique to the developer.

At first, it was awkward to get used to the other styles. But, once we’d made it past the awkward stage, we realized how much we were learning by pair programming. People can solve issues in different ways, so, as junior developers, we were exposed to more possible solutions and ways to arrive at those solutions. Coding all on our own would never have provided us that exposure, and the knowledge of so many hotkeys would have been beyond us.

Also, because there is more than one person coding, we can come up with different scenarios that could introduce a bug, and solve for those scenarios thus making more stable code.You might think it would take longer to pair program than working alone, since your thought process also has to be accounted for. But if you think of the time spent on fixing every issue QA finds after working alone on an issue, pair programming shortens that time significantly. It produces cleaner code and front loads the time spent going back and forth with QA.

These are just a few of the little things that you will get to experience in your programming career. And, as you learn more and experience more, you will grow as a developer. Use these tips and learned lessons of a junior developer to help keep you out of the dark. Eventually, you’ll set up enough light posts and guides as you code, making you efficient and maybe even a true senior developer.

sitemap