Developers Bad habits

You don’t want to do that

Image for post
Image for post

Here is a list of things we should try to avoid, as good developers.

Cut & Paste

Yeah, your work would be hard without cut & paste, right? We do this all the time, to save time, and it actually has deeper roots: prototyping (creating from a canonical object) is a natural tendency to build concepts (B is a A but something).

There are several use cases that involves cut & paste. Typically what you are developing can be:

  • similar to existing things that would look the same, but you don’t want to re-write the common part. However, if you follow the DRY principle, you should not duplicate things and (hopefully) that’s probably not what you want: you want to edit it afterwards. But nobody’s perfect, and you may forget to do it everywhere it should be, thus leading to a bug. Maybe you should wonder if that common part could be refactored as an object or a function, and the varying parts be arguments for such a function.
  • repetitive and you don’t want to rewrite it every time. However, this must fit one of two cases: either A) it is a long repetition, and you should probably benefit of automating it (through a tool or code) ; or B) it is not long and you should not duplicate things according to the DRY principle (see above).
  • complex and you don’t want to take the time to understand it. However if it is something you need to do, you’d better understand what you are doing. Pasting code or technical commands prevents you to memorize it or even understand what you’re doing. Even if you think you do when pasting it, you won’t memorize it as well as if you typed it.

Questioning the need

When a fix or a feature is easy to implement, you a less akin to challenge the rationale for it (but you should).

But when things get harder, as a sensible being with a preservation instinct, you start to look for an escape. And the first one is to avoid the obstacle: do we really need to go there? Is it worth suffering for it? So you end up in the anti-pattern of challenging a business need because of technical difficulties.

If you’re developing the feature or fixing it, that is a question that has been settled way before. It is not the time to question it anymore. Face the problem, and make it easier to fix the next time through an agile design refactoring, so that the next discussion can focus on the business need rather than the development cost.

Hushing errors

One way to avoid problems is to hide or hush them. This is what too many developers do in too many situations:

try {
result = canFail()
}
catch (error) {
// Do nothing
}

While this kind of code seems to hide problems, it actually hides the solution: if an error occurs, you will never understand why your system is behaving so weirdly and is unable to produce results. Actually you might search for days why some code is never executed until you find that it is because some unexpected error was absorbed.

This is why the minimum action of error handling should be to display a log message.

Workaround instead of fix

A variant of this is the false fix. Suppose your program crashes because something is null. What it is the solution?

canFail(myVar)   // Crashes because myVar is null!

One of the worst short-minded behavior of some junior developers will be like this:

if (myVar != null)
result = canFail(myVar)

or

try {
result = canFail(myVar)
} catch (nullError) {
// It's ok, continue
}

Did this solve the problem? No, it worked around it. For sure the error won’t show up again, but as much sure is the fact that other problems will arise in the next steps, as we called this function for a reason.

Errors are not things developers should exterminate. They are useful, and often it is better to fail with an error than to continue with an inconsistent state that cannot succeed.

Blame the user

That’s a situation that all people working in IT know: a bug is reported and you cannot reproduce it on your local environment.

“It works on my machine”

you say.

For sure, if a bug can be reproduced, you can consider it half fixed, as the fix becomes only a matter of development time. But not reproducing a problem is probably one of the worst situation for a developer, who can only guess.

Still, the problem remains very real on the user side, and users don’t care about the fact that everything works fine for you. Keep in mind that you’re building the software for them, not for you.

To avoid those problems, you might want to deliver reproductible environments through app containerization.

“Silly users”

Even if the user actually did something wrong with your software, you have to face the fact that you allowed it. It is the responsibility of the software design to prevent such misbehaviors: if you allowed users to do silly things with your software, that should be fixed too.

Loss of rationality

Say you encounter some behavior (a bug, a message, etc) that can’t understand. You really can’t. All explanations have been exhausted, and your brain is — quite rationally actually — starting to look for other variables: Did it work yesterday, even if I didn’t touch that code? Maybe it is working only even days? Could this be a bug of the OS or hardware bug? Could a solar wind event affected my computer?

Stop it, you’re being irrational. You’re just missing something. Walk away, then go back with fresh ideas.

Belief in non-idempotence

A specific case of this when you start to retry things that fails consistently. Idempotence (same causes produce same effects, in short) is more the rule than the exception in software: if you give the same inputs, it is more than likely that you’ll get the same outputs.

Nevertheless, some developers seem to loose faith in that rule when they encounter a bug that shouldn’t be there: they will immediately repeat the faulty operation, as if repetition would imply a different behavior. If you’re not playing with time or race conditions, it won’t.

When a command fails, it doesn’t make sense to type that command again. If an error appears when you click on a button, it doesn’t make sense to click again on it. Reloading a web page usually won’t fix an error in it, and so on. The problem is there, and it’s not gonna disappear until you fix it.

Stupidity is doing same thing and expecting different results. — Albert Einstein

Belief that bugs can disappear by themselves

Another case of irrational behavior is to see a bug, then walk away as if you never saw it.

I thought it was on my machine only

would you say.

Nine time out of ten, it wouldn’t be specific to you. It is there, and it will show up again sooner or later. It won’t disappear automagically.

Once again such a behavior can be understood from a human point of vue. Bugs are bad news and, depending on your stress state, you might want to protect yourself by pretending not seeing them. Because that would mean a lot of more stress, because you don’t have time to handle it right now.

If that’s not a critical issue that you’re about to deliver on production, that’s ok. Just note it so you won’t forget to handle it when the time is right. But don’t pretend not seeing it, don’t try to forget it, because it would be worse if it’s the end user who sees it.

Consider the feature as the only goal

Let’s say you asked a junior developer to develop some feature, and the feature is delivered (possibly on time), fully functional but with unmaintainable code. You complain about it but the developer assumes to invalidate all your remarks with a single argument:

Yes, but it works.

That’s something quite irritating to hear for a senior developer who learned the cost of bad design over years, but that’s quite a natural response from a junior developer: you asked to develop a feature, and the feature is there ; so why do you complain?

As if it was not hard enough, it is likely that people expecting the feature (customers, sales people, or even your manager sometimes) would agree with the argument: all of them just want the feature to work, they don’t care how it is made (and they would be right if the development stopped there).

Then starts the tedious task of justifying good design. It is a most difficult task because you cannot transfer your experience to someone else: either A) they trust you, or B) you impose it ; or C) you try to make them understand that software development is not just about building a black box: making it work is just half of the job, and the other part is to make it maintainable for the box lifetime.

Being maintainable is achieved through design agility (the real one, not the buzz word), that is, the ability to embrace changes over time.

What can you do to prevent this?

  • Programming to mentor and show good practices ;
  • Check the developed code on a regular basis before it is finished.
  • Ask unit tests to be written, emphasising that such tests should allow to test one thing. That should drive the design toward a more granular design.

That’s it what what I can recall of. Feel free to suggest more, and I may add them to the list.

All of those bad habits share the same trait: laziness. Such a trait is often depicted as a virtue in software development, as it drives you to automate things (through tooling typically) and so improve quality (predicability, stability). Behind laziness is the will to simplify your work, and so your life.

Still, the dark side of laziness remains, to prevent you to do what you should, or to see what you should see.

Software engineer for three decades, I would like to share my memory.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store