2012-07-21

Simplicity, Flexibility, and Agility


Agile programming is supposed to be about flexibility in the face of changing requirements. It's supposed to be about rapid development and iteration. But all too often it ends up being like classical methodologies in many ways. Many agile methodologies drown developers in process, taking time away from development. Test-driven development is a brilliant concept, but it puts more time between planning and iteration, making it more difficult to deal with changing requirements, not easier, and increasing the burden of change and the cost of refactoring.

Every developer wants carefully, precisely defined requirements. Developers often try to handle changing requirements by developing for flexibility, but flexibility often comes at the cost of added complexity. Trying to write-in endless flexibility to allow for changing requirements is very much akin to premature optimization. You end up doing a whole lot of work to make some code "better" - more flexible in this case, versus more performant in the case of optimization - when you don't yet know which code really needs it and which code doesn't.
"There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies." --C. A. R. Hoare 
Often the best way to maintain flexibility is through simplicity. A program that meets its requirements with the simplest possible implementation is one that will be naturally flexible, maintainable, stable, and manageable.Of course, intelligent development plays a major role; making appropriate use of design patterns can do a lot to improve both flexibility and simplicity. Key design tenets like DRY, YAGNI, separation of concerns, and avoiding premature optimization (including overarchitecting for flexibility) help keep complexity down and productivity up.

What if requirements change? What if the simplest possible solutions isn't as extensible? Good news: having invested in the simplest possible solution, you've lost little in development. You haven't built anything that wasn't strictly necessary. The new solution will still aim for simplicity, still reap the same rewards. By keeping things simple, you've kept down the cost of change.

Software development is a learning process by nature; you're building something that's never been done before, or at least building something in a way that's never been done before. Innovation is at its heart, and learning is the personal experience of innovation. That being the case, every iteration has value in what's learned, even if the code is later removed or replaced. The experience of writing it adds value to the team, and the team defines the value of the end product.

Many readers may think of targeting simplicity as a given, but it truly isn't; while simplicity is often a goal, all too frequently it takes a back seat to other concerns, or is abandoned altogether because simplicity becomes far more difficult to achieve with many of the popular frameworks and libraries available today. Frameworks have to aim for maximum flexibility in order to be successful; in order to be general-purpose, they can't make many assumptions, and they have to account for a whole host of different usage scenarios and edge cases. This increases the complexity of the framework, and accordingly, the complexity of any implementation using the framework. The fewer assumptions the framework can make, the more effort a developer has to put in just telling the framework what she's trying to accomplish.

I can't count how many implementations I've seen that are drastically more complex than necessary, simply because they have been forced to apply the conventions required by their chosen framework; and even following those conventions, they're still left managing arcane configuration files, and tracking down bugs becomes an epic undertaking requiring delving deep into the inner workings of the framework and libraries. All too often, the quick-start "hello world" app is far more complex with a framework than without it, and adding functionality only makes the situation more bleak.

So, what does all this add up to? Here's the bullet-point version:
  • If you're aiming for agility - the ability to adapt quickly to changing requirements - don't invest too much time on nailing down requirements. Get as much detail as you can, and start iterating. If you're planning for requirements to change, go all the way - assume that your initial requirements are wrong, and think of each iteration as an opportunity to refine the requirements. All code is wrong until proven right by user acceptance.
  • Use interface mockups (for software with a UI) or API documentation (for libraries and services) as a tool to give stakeholders a chance to revise requirements while looking at a proposed solution and thinking about using it in real-world scenarios.
  • Don't choose flexibility or modularity over simplicity. Choose a framework that won't get in your way; if there isn't one, then don't use a framework at all. Don't write what you don't need. Don't turn a piece of code into a general-purpose API just because you might need to use it again. If you need it in multiple places now, separate it out; otherwise, you can refactor it when it's appropriate.
  • Think about separation of concerns early in the game, but don't sacrifice simplicity for the sake of compartmentalization. Simple code is easier to refactor later if refactoring turns out to be necessary. Overarchitecting is the same sin as premature optimization, it's just wearing a nicer suit.
  • The simplest solution isn't always the easiest. The simplest solution often requires a lot of thought and little code. Don't be a code mason, laying layer after layer of brick after brick; be a code poet, making every line count. If a change could be implemented by increasing the complexity of existing code, or by refactoring the existing code to maintain simplicity, always take the latter route; you'll end up spending the same amount of time either way, but will reap far more benefits by maintaining simplicity as a priority.
  • Simplicity carries a great many implicit benefits. Simpler code is very often faster (and easier to optimize), more stable (and easier to debug), cleaner (and easier to refactor), and clearer to read and comprehend. This reduces development, operational, and support costs across the board.
  • Simplicity doesn't just mean "less code", it means better code. SLOC counts don't correlate directly to complexity.
  • Don't reinvent the wheel - unless you need to. All wheels aren't created equal; there's a reason cars don't use the same wheels as bicycles.
What are your experiences? What ways have you found to keep hold of simplicity in the face of other pressures? Feedback is welcome in the comments!

2011-03-31

Dynamic Playlists

There is a feature I miss from Audion, which they removed before they retired the app entirely, that I have yet to see recreated in any other music player. It was simple. It was brilliant. I want it back.

Basically, Audion used to allow you to group tracks in your playlists into folders, and - this is the important part - check or uncheck folders to include or exclude them from the playlist, temporarily.

Big deal, right? iTunes lets you check or uncheck songs, and you can multi-select and do a bunch at once. Except that it unchecks them everywhere, not just in that playlist, and you still have to do your multi-select by hand every time.

The beauty of this was it gave playlists a sort of dynamic quality: I could have a playlist with folders for happy tracks, funny tracks, angry tracks, sad tracks, tracks with a good beat, tracks with a fast beat, etc. and so on. Then, depending on my mood, I could check, say, happy songs and songs with a good beat, when I'm in a good mood. Or angry songs and songs with a fast beat, when I'm looking to play some first-person shooters. And if my mood changes an hour later, I can uncheck parts and check other parts and it will just keep shuffling through whatever is active when it comes time to pick the next track. It was brilliant.

And I miss it, and I want it back. iTunes doesn't do it, WinAmp doesn't do it, Songbird doesn't do it, VLC doesn't do it... nobody does. And it doesn't seem like it should be necessary to write an entire music player just to get this one feature; maybe one day I'll get up the nerve to modify Songbird or VLC to do it. Or maybe, sometime between now and then, some kind-hearted developer will hear my pleas and implement it in their player. Who knows.

If anybody out there knows of a player that does have this functionality, please, let me know in the comments... I'd be forever grateful!

2010-07-06

On New Tricks, Old Hacks, and Web Browsers

I must say, I'm a little curious why I haven't seen mention of this before; a quick Google search didn't turn anything up either. For the last, oh, ten years or so, web designers have been wrestling with all the different browsers, and different versions of each browser, to get their web pages to behave the same - or at the very least, behave relatively well - on all the browsers their users are likely to employ.

The whole time, the W3C has been releasing new standards and new versions of old standards to give web designers new tricks... and every time, the browsers all catch up to the new standards at different speeds, and implement different parts of the standards, or implement them slightly differently.

My question, then, is this: why is there no W3C specification for browser detection? Why can't I use CSS selectors to target certain styles at certain browsers, without resorting to lousy hacks? Even CSS3's new media queries allow me to check the screen size before applying styles, but not whether or not the browser supports, say, CSS3 Of course, it'll take forever for designers to be able to count on all the browsers supporting a new feature like that, but I haven't even seen a proposal.

Today, putting together a design involves pulling up your design in all the browsers, figuring out what works and what doesn't, and then applying hacks specific to each browser. Life would be so much easier in the web design world if instead you could say something like, "if the browser doesn't support CSS3 background properties, apply this style instead."

Suddenly, I don't need to use the hack that hides CSS from IE, and the other hack that hides CSS from everything but IE, and test it, and then find another set of hacks for the Android browser, and another for FireFox, and so on. I can apply styles logically by selecting for specific features, rather than selecting for specific browsers, then having to keep up with the features of each browser - because the features are all I really care about as a designer.

I would much rather "hack" for specific features than specific browsers because it's more intuitive, and it's less work to support multiple browsers and different versions of each browser. The browser makers know what features they support. If I can select for the features I want to use, I don't have to worry about keeping up-to-date with what features are supported by what versions of what browsers.

I'm bringing it up on the W3C mailing list, but I thought I would bring it up here... I'd love to hear your thoughts in the comments!

2010-02-01

Home-Made Guitar Work Mat

I made a guitar work mat for about $6 and ten minutes' work. It works perfectly, so I thought I'd share it here.


From Mat

While I was at the grocery store one day, I saw a small selection of shelf/drawer liners. They had a rubber webbing liner, and a self-adhesive cork liner. I bought one of each, I think the cork was $4 and the rubber was $2.




The rubber roll was 12" x 5', and the cork roll was 12" by 4'. 12" is too narrow, so I used two rows of each. I laid the rubber down in two 2' rows, then adhered the cork to it in two perpendicular rows, so that each side would hold the other side together. So far it's been fine, but if the layers start to separate I plan to seal around the edges with tape, probably electrical tape.


This picture shows how the seams on each layer run perpendicular. Half of the mat is rolled up so you can see the cork side against the rubber side.


Advantages:
  • Rubber bottom provides traction on all surfaces -- I have a glass work table and it's rock solid.
  • Cork top provides good traction for your guitar body, but will not mar or scuff the finish in any way.
  • Both the cork and the rubber provide some level of impact protection; a regular cloth doesn't protect your guitar from the hard surface underneath, while the rubber and cork will.
  • Rolls up for easy storage.
  • Costs less than a store-bought guitar work mat, which will probably not have the nice non-skid surface. Cheap & easy to replace if it gets lost or damaged.
If you try this out yourself, please let me know in the comments how it worked out for you!

2009-12-12

Neverwinter Nights 2 Crash on Windows 7

I've had Neverwinter Nights 2 pretty much since it was released, but I never bought the expansion packs. I installed it on my new machine, and it's worked perfectly. Then I saw that the expansion packs were 50% off right now, so I went and grabbed them, digital download.

I installed the first expansion first, Mask of the Betrayer. I launched NWN2. It crashed before it ever started. I tried to update, in case there were updates specific to MotB, but it said I had to launch the game before I could update; but launching the game hangs instantly.

So I uninstalled, thinking the issue was that NWN2 was fully updated before I installed MotB, which is built against v1.10. I reinstalled NWN2, didn't update it, just launched it, closed it, and installed MotB. And it crashed as soon as it opened.

So I installed Storm of Zehir. And it installed successfully. And NWN2 launched without crashing. SoZ is built against v1.20, so it was a short trip to the current latest v1.23, which also launches without crashing. All is well now.

Just thought I'd post this for anyone having Neverwinter Nights 2 crash on Windows 7 after installing Mask of the Betrayer. Try installing Storm of Zehir (if you've got it) and see if that helps. I don't know if you have to install against a base (non-updated) copy of NWN2, as I haven't tried it with updating NWN2 fully then installing the expansions. However, given that there are no catch-up patches and you have to install all the intermediate patches to get the boxed v1.00 up to the current v1.23, installing MotB and SoZ may be the fastest way to get a fresh install fully-updated anyway.

Hope that helps somebody out there!