Make The Right Way Of Doing Software Development The Path Of Least Resistance

madlep

Imagine you’re standing in the middle of the countryside. You’ve got a place to be which is several kilometers away. How do you get there? You’ll probably just take the quickest, most easy route. It’s not necessarily the most direct route (that might go through a swamp or up the side of a mountain), but it’s the route with the path of least resistance.

The path of least resistance originally refers to electrons flowing though a circuit - the amount of current at any point in the circuit is inversely related to the amount of electrical resistance that the path at that point in the circuit has. It’s the same thing when you’re walking out in the country. If a given route is easy, you’re more likely to go that way to get to your destination. You’re less likely to go through obstacles (unless you’re into parkour or mountain biking…)

Think of the kodos and crocolisks

Now say that the direct route marches right through the middle of the endangered Giant Kodo habitat grounds, and then through the rare Crocolisk breeding grounds (both of which have been brought to the brink of extinction by over-zealous gold farming). The local environmental groups decide to do something about these rawblockers tramping through. The Kodo protection group constructs a big fence, while the the Crocolisk preservation association has built a paved track around the edge that actually ends up being quicker (but you can still go through if you want).

What is your new path going to look like? You’ll still take the easiest route. It’s just that it’s a different route now. The path of least resistance now involves having to detour around the Kodo’s, but you’ve chosen to take the new Crocolisk bypass track - because it’s quicker. The distinction is important. It’s all about the path of least resistance, and how it can be manipulated to achieve a result in the desired manner: either by making the undesirable paths harder; or by making the desirable path easier.

So what does this have to do with coding?

Exactly the same thing applies when developing software. There are dozens of ways to accomplish a given programming task. Developers are lazy, and will generally choose the solution that fits the constraints with the least amount of work. “Work” and “Constraints” are incredibly subjective terms, so it’s worth discussing them.

Work

“Work” is the measure of how much effort is expended. How hard is it, how long does it take. Some examples:

  • Time spent coding = effort (with some exceptions for doing heavy geeking)
  • Testing, documentation = effort
  • Doing tedious boilerplate code = extra effort
  • Using heavy syntax that requires frequent use of thick documentation = extra effort
  • 5 minute deploy and test cycle = extra effort
  • Interfacing with a buggy, badly documented external systems = extra extra effort

Constraints

“Constraints” is everything that limits the set of solutions a developer will consider. This includes obvious ones (like the actual software requirements), but also less tangible subconscious constraints. Some examples:

  • The client’s requirements = constraint
  • Personal pride in your work = constraint
  • Desire for respect from peers = constraint
  • Corporate development process = constraint
  • Project deadline = constraint

When you think about it, the constraints are really just a multiplier that affects the amount of effort. There may be a constraint that says “This project will be developed in language Foo”. Now you could go ahead and develop it in language Bar, but you have a lot of work on your hands explaining why you did that, and potentially redoing it all in the specified language - the effort to develop in language Bar has made it too costly to be considered an option. The path of least resistance is just to go with the flow and develop in the prescribed language.

Tweaking the path of least resistance to get what you want

Work and constraints apply at the micro-level of a single developer or a small team. They may end up optimizing on a local-minima, and be using an approach that has an overall negative aspect (such as copy/paste coding, or hard coding configuration data). If you’re in charge of a bunch of programmers, what’s the way to handle this? (assuming you can spot it - which is a whole other problem…)

Like with the Kodos and the Crockolisks, you can tweak the path of least resistance in a couple of ways:

Adding extra constraints

The most obvious way is to put extra constraints in that make it harder to do the wrong thing. This is the usual knee-jerk reaction to solve a perceived problem. “The developers are not using best practice! Lets add an extra layer of process and make 3 layers of management sign off another TPS form so that they are forced to do things properly!”. The path of least resistance is now to jump through the process hoop, and not do whatever was wrong before. This has a double whammy effect on the poor developers: They have to use a harder solution that doesn’t have the negative side effects (which is partly good - they aren’t trampling Kodos). But it adds even more process work on top the heavier best practice approach that was unattractive before (which is bad for obvious reasons).

Making best practice easier

The other option is to make the desired path more attractive. When you look at the root cause for developers not doing things properly, it could be that the key APIs on a project are heavy-weight and difficult to use. The solution may be to refactor these to make them easier to use. This is win-win. The developers are now more productive; are doing things properly; and don’t have to waste time with excess process (the problem has been reduced, so the process to fix it isn’t required).

This is similar to the carrot and stick approach, but is subtly different. Carrot and stick rewards/punishes various behavior to get the desired result. Thinking of a process in terms of the path of least resistance means changing the process itself so that the desired behavior is the easiest behavior.

Agile development in general, and Ruby on Rails in particular use exactly this approach to encourage developers to use best practice. When developing a Rails app, it is incredibly easy to use good practices such as proper project structure/test driven development/separation of concerns/DRY etc. Contrast this with J2EE - which has a multitude of ways for producing a mess, with a smaller more difficult set of approaches for producing a good clean structure. It’s no surprise that a lot more process is required to keep a J2EE project on track compared with a Rails project.

This is what I was hinting at a while back in JRuby can save Swing. Swing is a great API that gives you a lot of power. It’s just that the path of least resistance for building Swing apps is not pretty: autonomous views with tightly coupled, inflexible model and view code. A properly architected Swing app can be a thing of beauty and can elegantly grow and evolve as required. The solution I was talking about would provide a new Railsesque API layer in JRuby that would encourage developers to properly structure their Swing app using best practices.


Leave a Reply