While preparing my talk for the German Rails-Konferenz on legacy code I thought about why we still have to deal with bad code. Why do people still write code that sucks, code that's close to being unmaintainable, code that's so insanely tangled, code that's untested?

The answer might be obvious or not. There's some simple reasons, which is to say that I couldn't come up with any reason that seems like a fair one:

  • They just don't care (gasp!)
  • They claim they don't have the time to write clean code or to clean up after themselves
  • They claim that management forces them to work on new features all the time

I'm sure you'll agree that number one is the worst. Not caring about your code is similar to doing a number two in other people's bathrooms and not flush the toilet. Yes, it's that bad. The other two are just excuses. It's not impossible to argue that tests are necessary or that refactoring is necessary. It's up to you to do your planning accordingly. Don't blame the management, work on it, improve the situation. It's in your hands.

We all wrote our fair share of bad code, I'm sure. I know I did. It's what we do with it, what we learn from it, that's important. We can look at our code a year later to see what we'd do differently today. At least I like doing that. Not so much with really old code, especially with the stuff written in those older, rather nasty languages, though even that can be quite fun. But it's refreshing to come back to what you wrote a while back to either rework it, or just to think about how you'd do it differently some months later, if at all. Maybe your code is perfect, maybe it could need some improvement.

I like that exercise because it fosters rethinking your current code. Maybe you followed a pattern that leads to unclear intentions in your code. There's always a time to rectify that, to clean up, to make the intentions of your code clearer. If you keep doing that exercise over and over again, and not only look at code that's six months old, but code you just wrote, you're halfway there. If you look at if after implementing a new feature as opposed to just looking back at old code, it's not too hard to write good code. Instead you'll notice that it gets hard to write bad code.

You might end up with a similar behaviour as mine. You'll notice a slight sting in the neck whenever you leave a code smell be, whenever you write a line of code without writing a test for it, when you leave a TODO in the code instead of putting the task in your backlog or fixing it right away. I never leave TODOs in the code, they just end up staying there for years. When you have a pair to point out problems, even better, but even practicing the look back at your code will improve its quality over time. You just need to stick to it, keep practicing over and over again until it becomes a mantra. It's sure to make you a better person too, if you need more motivation.

I'm not much of a fan of mantras, and I don't like telling people what to do, but there's things so simple, they should be common sense. Leaving code in a way that its intentions are as clear as possible should be one of them, writing tests with every line of production could should be another. It's up to you.

Tags: legacy, code

I've started a new blog (don't worry, I have not abandoned this one), specifically targeting experiences, wtf's and workarounds for the latter on Amazon's Web Services. I've been working quite a lot with them recently, and there's heaps of dark corners around, and things you need to be aware of. That's what that blog is about. Head on over to Daily AWS Wtf and give it a read. It's powered by the people of Peritor, so there'll be other people writing too.

The annual one and only German Rails Conference (some might call it Rails Konferenz) is upon us. I'll be speaking about legacy code, and I'll also be giving a tutorial on refactoring Rails applications, together with Jonathan Weiss. It's a great one day conference with a German audience. Great occasion to meet the German Rails scene. Hope to see you there!

Tags: rails, aws

Things that don't really justify their own separate posts.

  • The method instance\_methods now returns an array of symbols instead of an array of strings. So do all the other methods that return methods, e.g. singleton\_methods, public\_instance\_methods, etc.

  • There's now a method define\_singleton\_method that will remove the need of using instance\_eval when you want to define a singleton method. This is both true for classes and objects. Though if you're really picky, those actually are the same.

  • public\_send is already an oldie, but goldie, but it can't hurt to mention it. It will fail when you're trying to dynamically call a non-public method. Good old send still works as advertised.

  • Enumerable#grep can work on arrays of symbols. Add that to an array of methods, and you have a way of searching for methods that's still compatible with Ruby 1.8. As a matter of fact, and thanks for David Black for pointing that out, symbols seem to be more string-like in Ruby 1.9, so you can do :symbol.match(/ymbol/).

  • instance\_exec is a nicer way of calling a block in the context of an object when you need to access variables outside of the block. You can give the parameters you need in the block as parameters to instance\_exec which will in turn hand it to the block.

    m = User.new
    secret = "sssh!"
    m.instance_exec(secret) {|s| @secret = s}

    Now, this is a terrible example, I know, but honestly I'm not too sure how useful this is in practice. instance\_exec was also backported to Ruby 1.8.7, if you're up for that kind of thing.

  • Blocks are now handled very similar to methods, at least when they're lambdas. Don't ask me why the good old proc method is still in there. You get ArgumentErrors when your argument list doesn't match the list of parameters specified for the block. So checking the arity is probably a good idea when you're working inside a library dealing with blocks handed to you.

    Don't get me started on the new way parameters are handled in both methods and blocks. You can have optional parameters, splat parameters, and another mandatory parameter, afterwards. It's crazy, but true. Ruby will match things from the outside in. To fully understand it, I can only recommend to play around with it.

  • Fibers! Man, this stuff is neat. It's not really the place to explain everything around them, I've written a long-ish article on them for the RailsWay Magazin to fully understand what they actually do. Play with them, but not with the semi-coroutines version that's the default. require 'fiber' is where it's at. That gives you the full power of this neat little gem.

  • The Enumerable methods in Hash will now return hashes where appropriate. This is kind of a big deal, because it can break compatibility when you're solely relying on it. When you're talking to code on the outside, it's probably a good idea to still convert any results to an array using Hash#to\_a

  • Even though it's supposably still the same version, there's some differences in the code of WEBrick. It will simply fail on requests with request URIs longer than 1024 characters. That was a bit surprising to me, and since there was no reasonable way around it, I had to patch it to work with SimplerDB.

  • String now has start\_with? and end\_with?, they're also in Ruby 1.8.7.

  • In Ruby 1.9.2 there's now Method#parameters, which gives you a neat way to inspect parameters of a method (duh!):

    => [[:opt, :y], [:opt, :m], [:opt, :d], [:opt, :sg]]
    def parameterize(name, options = {}, *args, &blk)
    => [[:req, :name], [:opt, :options], [:rest, :args], [:block, :blk]]

As much fun as Ruby 1.9 is, having to deal with unmaintained code that is not compatible yet is a real pain in the ass. But still, it's totally worth checking out, and if you have a vanilla project coming up on the horizon, consider doing it with Ruby 1.9.

Tags: ruby