Thursday, March 28, 2013

Programming in the Real World

I've been thinking a lot recently about the difference between how I program now versus what I thought programming was in college, in part because I've had the task of trying to convey that difference to several very bright and energetic recent graduates.

Here is some food for thought:

Choosing what to work on is choosing what not to work on.

There's always more work than time.  You have to choose wisely what is worth the effort, not from some snobby sense of code righteousness, but from what is most important for your users, what develops your application towards the ideal, and what can deliver the best experience for the investment.

Every change carries risk.

Even trivial changes can break things in ways you may not discover until later.  A code refactoring that shouldn't theoretically make a difference opens the door to unpredictable outcomes.  It's better to leave something alone if you aren't willing to test it.

Simplicity is better than elegance.

I love perl, but perl has a bad reputation for being unreadable.  A perl guru can probably solve a string manipulation problem in one line, no matter how complex.  Good luck maintaining that in the future, or getting someone else to maintain it.

Making it easy to understand is important for the future you.

There's a myth out there about programmers writing obscure code as "job security".  This is baloney.  Job security comes from doing good, dependable work, and writing unmaintainable programs will only make it harder on yourself later.  Writing code that's easy to understand isn't just for other people.  When you have a project that lasts longer than a semester (mine is over 7 years old now), you will not be able to remember it all, and having confusing method or variable names will only degrade your own productivity.

The art is in how you organize.

Figuring out what the algorithm is will only solve half the problem.  The implementation of an algorithm does not necessarily suggest a class hierarchy, method organization, or a data structure; you still have to implement that algorithm in some form.  This is where the true artistry comes in, to be able to express the algorithm in a way that is correct, minimal, efficient, and easy to understand.  And the only thing you have to work with is how you organize all the pieces.

The interface matters.

What do you call this method?  Is it public or private?  If it's public, can it successfully be executed out of context, or does it have dependencies that will cause it to break?  How your class presents to the outside world, and whether it delivers what it advertises, will make or break its usefulness to other members of your team.

Plan for the future, but implement for the present.

You want your code to be extensible in ways that allow it to grow.  But you don't want to spend all of your time implementing all of that growth at the beginning.  Create an architecture that allows for growth, but only implement what you need.  By the time you are ready for that growth, it may not be exactly what you originally thought it would.

Performance matters.

Unless you work with purely conceptual machines, or you're trying to solve P=NP, it's not enough to write an algorithm that can provably solve a problem.  It has to do it within the timeframe required, which might be seconds.  If you're working on the web, making your users wait for even 2 seconds might be enough to frustrate them.  Little mistakes, extra unnecessary iterations, methods that do extraneous work, can add up when executed many thousands of times over.

Write UIs for your mother

Unless your mother happens to be a computer professional, then pick someone else.  Know your audience, and make things simple.