Sunday, September 10, 2017

Should Bad Code Be Illegal?



A junior developer on my team asked me a rather interesting question recently.

If you were able to make laws, would you make bad code illegal?

I have a reputation where I work as being rather hard-nosed about not allowing hard to understand and maintain code into the codebase, so my answer surprised him.

No, I would not make bad code illegal, and there are very good reasons for having this opinion.

First, everyone writes bad code before they write good code. Whether it’s your first time coding in general or just your first time coding in a new language, with a new framework, etc, you are going to write bad code. I’m sorry. It’s just a fact of life.

Nobody starts out writing amazing code. Not me, not you, not Uncle Bob (in fact, Uncle Bob is open about the fact that he was a horrible developer when he started, just like the rest of us). We all get better by writing bad code, learning from our mistakes and pain, and, if we’re lucky, mentors helping us to see where things can be improved.

Second, “bad code” is rather subjective. What standard are we using for what “bad” code is?

Is it code that costs the business unreasonable amounts of money due to being full of bugs and difficult to maintain? That’s not a completely terrible definition because we can tie it to some external benchmark, but it’s still probably a bad idea since there is a risk/reward factor of why decisions were made at the time that may not be known at some later date.

Is it code that Developer X (whether me, Uncle Bob, or Joe in the cubicle across the hall) would look at and give a laundry list of things that need to change? For any given code, you can find some developer that would find flaws in it – whether it is inefficient, or it doesn’t implement their favorite pattern, or any number of other complaints.

Is it code that, six months from now, you will look back at and wonder what the heck you were thinking when you did it that way because there are so many better ways to accomplish what this code does? Here’s a hint. This should be most of your code. You didn’t know as much 6 months ago as you do now.

Third, sometimes bad code is necessary.

Yes, you heard me. There are times that it makes sense to write bad code.

If you are writing a script to perform some one-off function that you are seriously never going to use again, pretty doesn’t always matter that much. If writing code for 5 minutes and then throwing it away can save you hours of work, go for it. I’ve done it before, and I can almost guarantee that I will do it again.

Sometimes you need to fix a catastrophic flaw in a mission critical piece of software, because the company is losing millions of dollars per minute while the flaw exists. In that case, you have to do whatever you can in order to fix the issue, release the patch, and *then* go back and make it maintainable.

The same is true if we are in a startup where the money is limited, time is fairly short (as it is generally a function of money in this case), and we need to get a Minimum Viable Product out in front of users so we can start making money. This is another case were “Make it work, then make it better” can be the correct (and sometimes only) course of action.

We may not like it, but sometimes getting it to work right now is the right choice. These situations fall under the heading of consciously taking on technical debt with every intention of paying it back later and this is a very important business decision. If it’s a matter of “We can release it now and be able to make payroll” vs “It will take another month to make it perfect and we’ll be unemployed by then”, well, the choice is fairly clear then isn’t it?

Thankfully, most of the code we write doesn’t tend to fall into those categories, so we can make the effort now in order to make the code clean and maintainable, but we can’t ignore that those possibilities exist.

Making a law that is, on the whole, completely subjective and capricious is a just plain bad idea. As a general rule, when we write code that isn’t amazing, at worst we lose time in figuring out what is going on and/or fixing some bugs. Nobody generally dies from bad code (there are cases this is not true, but they are not the norm), and we can always make a conscious effort to improve it once the crisis is averted.

On the whole, yes, we need to strive to write clean, maintainable, bug free code, but we can’t be completely inflexible. If you want to make it a crime to write bad code, make the punishment be to learn how to write better code. I think that’s a fair sentence.
 

Current mood: Calm
Current music: Midnight Oil – Beds Are Burning

Monday, October 31, 2016


Happy Anniversary

Friday, October 14, 2016

Wednesday, December 09, 2015

I will miss you, fuzzy buddy




I lost my best friend today.


Since I was 17, my best friend has been the amazing cat that you see above the post. He's the best cat I've ever known. He was smart, brave, sweet, and a very good kitty. He was also very much daddy's guy. He was always there to greet me when I woke up in the morning and when I got home from work.


We've been through a lot together, we've taken care of each other, and we've always tried to be there for each other.


Unfortunately, today he passed away at the admirable age of 18. The vet was with us in hoping that he could make it much, much longer for a number of reasons, but it seems that that wasn't meant to be. Yesterday, we got word that he wasn't going to be around for much longer, so we did what we could – we bought him fried chicken (which he loved, but didn't often get because it wasn't very good for him), gave him his holiday gifts early and spent yesterday and today with him, showing him how loved he is. He ate a large amount of the chicken and enjoyed all of the cuddles.

We were both there for him when he passed away, petting and cuddling him while telling him what a good kitty he has always been and how much we love him. He's now having a well deserved rest and isn't suffering anymore. We laid him to rest next to Karyl's cat, Simba, who passed away a couple of years ago and whom he adored basically since he met her.


I will miss him greatly. Karyl and I both will, to be honest. The house will feel very empty without him in it.

To share our love for him with the world, at least a little bit, here are a few links involving him:

 

I will miss you very much, fuzzy buddy. You will always have a big place in my heart


Current mood: Sad
Current music: Craig Ferguson's series finale – Bang Your Drum

Saturday, October 31, 2015



Happy Anniversary

Wednesday, October 14, 2015

Sunday, August 30, 2015

TDD - It'll only hurt for a little while ;)



TDD is a very useful tool. Done well, it offers assurance that your code does what it is supposed to do, provides a set of baked in regression tests, allows you to refactor code without worrying that you will break something in the process and acts as a sort of living design document.

It is not, however, a silver bullet. If done poorly, it can cause code to become rigid. This generally happens when people test the implementation details rather than the behavior. In a language like Python, where there are no truly private methods, it can be even easier to test implementation rather than behavior if you aren't cautious. I'll also say that it can be really difficult to effectively test Android code because TDD isn't a first class citizen in that ecosystem.

In my opinion, the possible downsides of TDD are generally far outweighed by the bonuses – especially since the downsides are usually able to be mitigated by exercising some self-discipline.

That's not to say that every piece of code you ever write has to be done with TDD. There are some small, usually one-liner style programs, that I write which I don't test drive. If I'm going to be using something once and tossing it, provided that there isn't really a danger of permanent damage if the code doesn't do what I want the first time, I may decide that it isn't worth the effort to set up a testing harness.

Now that we've got my opinions on the topic out of the way, I have to say that I don't get the hate that some developers have for TDD. I can understand a non-technical manager not understanding how writing tests (more code) isn't a drawback, but people who write software for a living are another story.

If I had to guess, I'd say it was probably some combination of fear of the unknown, a previous bad experience (whether because of lackluster tools, lack of guidance, or inexperience), or posturing on the part of the developer (after all, we are often not known for a lack of ego).

There are occasionally reasons to not test something (few and far between), but as a general rule, having the tests will only help you now as well as helping future you when you have to dig back into the code in 6 months. Not wanting all of the tools that could help you is just crazy.

This whole post was inspired by a tweet that a friend of mine re-tweeted (and its associated tweets), so let's take a little time to critique the conversation.


Yes. Because it works. I've already covered that above, so I'm not going to repeat myself.


If you are working in a shop that doesn't do test driving (I'd be tempted to ask why not, but just for the sake of argument), then yes, a person who doesn't do TDD will be fine. If you are in a shop that does TDD and the person is willing and able to learn TDD, then consider helping them get up to speed. If they refuse, then they're probably not a good fit for your team/company. Sorry, but that's the way it is.

If your team all does TDD, but one person refuses to do so, you lose a lot of the benefits. The baked in set of regression tests is no longer complete. The living documentation is no longer complete. Refactoring becomes trickier. Bugs can become harder to track down. These are problems.


Then you're probably doing TDD wrong. In all likelihood, you are testing implementation instead of behavior. This is actually a pretty common mistake for people who aren't used to TDD and it takes some experience to get over. Heck, even people who have been doing it for a while can slip up sometimes. None of us are perfect. That doesn't change the fact that you're probably using the tool wrong.


You don't TDD with Integration Tests, or at least not only with integration tests. You use Unit Tests to test functions (given input, check output for example). Integration Tests are used to test a series of Units (kind of like checking to see that a bunch of legos you put together actually build a wall).


Then you're looking at it wrong. Each unit test should be a condition that your function should fulfil. You only test the criteria that your code is supposed to fulfill. That's not to say that you can't spike out something you're not sure of (especially if you're working with a new language), but before that code actually makes it into your codebase, it needs to be under test, and that test needs to fail first.


I can sort of get behind this for one very simple reason – some things are just ridiculously difficult (if not damned near impossible) to test. These cases don't come up often, but they do occasionally come up. Other than that, test your code. For everyone's sake.


I disagree. If the entire team (or company) does TDD, then yes, it is a valid requirement for the job. If you refuse to use TDD, then you don't have a place on the team for reasons that I've already outlined. In fact, I'm glad more places are making it a requirement (provided that their people write good tests).

The sad thing is that I hear these sorts of arguments a lot. Thankfully, however, I seem to be hearing them less lately. I honestly welcome constructive criticism of practices because it helps people grow. You need to be prepared to have others respond to that criticism though.

Just complaining about a methodology you don't like without valid reasons doesn't help anyone (and that's exactly what that last tweet was).

Current mood: Calm
Current music: INXS – The Stairs