|
| 1 | +<!DOCTYPE html> |
| 2 | +<html> |
| 3 | + <head> |
| 4 | + <meta charset="utf-8"> |
| 5 | + <meta http-equiv="X-UA-Compatible" content="chrome=1"> |
| 6 | + <link rel="stylesheet" href="/assets/css/styles.css"> |
| 7 | + <link rel="stylesheet" href="/assets/css/pygment_trac.css"> |
| 8 | + <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> |
| 9 | + <script src="/assets/js/respond.js"></script> |
| 10 | + <!--[if lt IE 9]> |
| 11 | + <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> |
| 12 | + <![endif]--> |
| 13 | + <!--[if lt IE 8]> |
| 14 | + <link rel="stylesheet" href="/assets/css/ie.css"> |
| 15 | + <![endif]--> |
| 16 | + <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> |
| 17 | + |
| 18 | + <LINK REL=StyleSheet HREF="/assets/css/pygments.css" TYPE="text/css" MEDIA=screen> |
| 19 | + <title>Software's Receding Hairline</title> |
| 20 | + </head> |
| 21 | + <body> |
| 22 | + |
| 23 | + <div id="header"> |
| 24 | + <nav> |
| 25 | + <li class="fork"><a |
| 26 | + href="https://leanpub.com/javascript-allonge" |
| 27 | + title="A strong cup of functions, objects, combinators, and decorators" |
| 28 | + >JavaScript Allongé</a> </li> |
| 29 | + <li class="fork"><a |
| 30 | + href="http://ristrettolo.gy" |
| 31 | + title="An intense doppio of programming" |
| 32 | + >CoffeeScript Ristretto</a> </li> |
| 33 | + <li class="fork"><a |
| 34 | + href="http://combinators.info" |
| 35 | + title="Raganwald's collected adventures in Combinatory Logic and Ruby Meta-Programming" |
| 36 | + >The “Kestrels” Book</a> </li> |
| 37 | + <li class="fork"><a |
| 38 | + href="http://allong.es" |
| 39 | + title="All of the JavaScript Allongé receipies in a free library" |
| 40 | + >allong.es</a> </li> |
| 41 | + </nav> |
| 42 | + </div><!-- end header --> |
| 43 | + |
| 44 | + <div class="wrapper"> |
| 45 | + |
| 46 | + <section> |
| 47 | + <div id="title"> |
| 48 | + <h1>Software's Receding Hairline</h1> |
| 49 | + <hr> |
| 50 | + <span class="credits left">This blog is written by <a href="http://braythwayt.com">Reg "raganwald" Braithwaite</a></span> |
| 51 | + <span class="credits right">Fixes welcome: <a href="https://github.com/raganwald/raganwald.github.com">fork and submit a pull request</a></span> |
| 52 | + </div> |
| 53 | + |
| 54 | + <p>The news is out that the Java Programming Language is going to have a clean, simple syntax for lambdas <a href="http://www.urbandictionary.com/define.php?term=real%20soon%20now">Real Soon Now</a>. It seems that after two or three or maybe even five years of wrangling, the various committees have decided on a syntax, <a href="http://mail.openjdk.java.net/pipermail/lambda-dev/2011-September/003936.html">mostly</a>.</p> |
| 55 | + |
| 56 | +<p>Obviously, I’m less than impressed. But let’s cut the designers a little slack. There are factors I don’t understand that go into a feature like this. It must be carefully considered not just for its functionality, but for the subtle ways a revised compiler would interact with billions of lines of existing code. The new feature would interact with thousands of existing features in weird ways. Each and every one of those interactions needs to be carefully considered before adding a new feature. Under the circumstances, it’s kind of amazing the feature was added at all.</p> |
| 57 | + |
| 58 | +<p>But then again, consider the following scenario: I build an application for a client. The application is a little long in the tooth, and the UX is so ancient, it is demonstrably less effective than competing applications. The client asks for a modern feature, something like changing from constantly refreshing pages to having a Single Page Application that fetches data using AJAX, or perhaps the client wants entities in the system to have “walls” with stories and posts the way Facebook pages have walls with stories.</p> |
| 59 | + |
| 60 | +<p>“Well,”, I say, rubbing my beard. “That’s going to take two or three years. There are many subtle interactions in the code, many features that interact and are coupled. While this change may look simple to you, it actually requires a massive rewrite to make sure it doesn’t break anything.”</p> |
| 61 | + |
| 62 | +<p>What is my client to think? That I have given them a marvellous, well-architected application? Or that years of <a href="http://developeraspirations.wordpress.com/2010/02/23/javas-flaws-why-primitives-are-bad/">bolting a feature on here</a> and <a href="http://cakoose.com/wiki/type_erasure_is_not_evil">hacking a workaround there</a> have created a nightmarish miss-mash where the velocity of progress is asymptotically approaching zero?</p> |
| 63 | + |
| 64 | +<h3 id="receding-hairlines">receding hairlines</h3> |
| 65 | + |
| 66 | +<p>I am balding. Fortunately for me, my hair is too nappy to form the dreaded “comb-over.” How does this happen? How do men wind up with such an obviously unattractive appearance. Don’t they know it looks ridiculous?</p> |
| 67 | + |
| 68 | +<p>The answer, of course, is that it doesn’t happen overnight. Nobody walks into the barber’s office and asks for a comb-over. Nobody carefully grows the hair on one side of their head until it can reach right across their bald pate to the other side. Instead, a comb-over is the accumulation of years of small decisions, until one day there is an unmistakable comb-over. Mercifully, nobody of character is paying attention. Nobody who matters judges a man by his hair, and nobody who judges a man by his hair matters.<sup id="fnref:pg"><a href="#fn:pg" rel="footnote">1</a></sup></p> |
| 69 | + |
| 70 | +<p>This is interesting, because <em>the mechanism of growing a comb-over applies to software development</em>. A comb-over is the accumulation of years of deciding that today is not the day to change things. A comb-over is the result of years of procrastination, years of decisions that seem right when you’re in a hurry to get ready for work but in retrospect one of those days should have included a trip to the barber and a bold decision to accept your baldness or take some other action as you saw fit.</p> |
| 71 | + |
| 72 | +<p>Software is like this. Bad software doesn’t really start with bad developers. It starts with good, decent people who make decisions that seem right on the day but in aggregate, considered over longer timeframes, are indefensible. This is a great paradox. It is difficult to pull out a calendar and tell Smithers that on February 12, 2003 he should have restyled his hair. Why the 12th? Why not the 15th? Why not June 2003? Why not some time in 2004?</p> |
| 73 | + |
| 74 | +<p>Likewise with software, it is sometimes difficult to pull out a calendar and say that on May 5th, 2010, we should have deferred adding new features and refactored this particular piece of code. On that day, adding new features might have been the optimum choice. And the next day. And the next. But over time, it’s clear that <em>some time</em> should had been devoted to something else.</p> |
| 75 | + |
| 76 | +<h3 id="the-tyranny-of-the-urgent">the tyranny of the urgent</h3> |
| 77 | + |
| 78 | +<p>This is as true of life as it is of software and hairlines. You cannot make all decisions based on short timeframes. Sometimes you have to do things that are <em>important but not urgent.</em> It is never urgent to read a new book, or learn an unpopular programming language, or refactor code that isn’t blocking you from implementing a new feature. If you are programming in Java, it is never urgent to switch to Scala. If you are implementing Java, it is certainly never urgent to release a feature that would force your legacy users to rewrite some of their code.</p> |
| 79 | + |
| 80 | +<p>But if you make all your decisions according to their urgency, one day you wake up with a receding hairline and a million lines of Java code running on a compiler that simply can’t accommodate new language features without three years of finagling. It’s entirely up to you how to proceed.</p> |
| 81 | + |
| 82 | +<p>For my part, I am going to do the following: The next time I am prioritizing features with a client and tasks with my team, I am going to explicitly ask the group to name three things to do that are <em>important but not urgent</em>. And with any luck, we’ll do some of them, and I won’t wake up one day explaining that what looks like a straightforward change will take years to implement.</p> |
| 83 | + |
| 84 | +<div class="footnotes"> |
| 85 | + <ol> |
| 86 | + <li id="fn:pg"> |
| 87 | + <p>Paul Graham used the comb-over analogy in an optimistic, positive way in “<a href="http://paulgraham.com/essay.html">The Age of the Essay</a>.” Wonderful read.<a href="#fnref:pg" rel="reference">↩</a></p> |
| 88 | + </li> |
| 89 | + </ol> |
| 90 | +</div> |
| 91 | + |
| 92 | + |
| 93 | + |
| 94 | + |
| 95 | + <hr/> |
| 96 | + |
| 97 | + <h3>my recent work</h3> |
| 98 | + |
| 99 | + <p><img src="http://i.minus.com/iL337yTdgFj7.png" alt="" /><a href="http://leanpub.com/javascript-allonge" title="JavaScript Allongé"><img src="http://i.minus.com/iW2E1A8M5UWe6.jpeg" alt="JavaScript Allongé" /></a><img src="http://i.minus.com/iL337yTdgFj7.png" alt="" /><a href="http://leanpub.com/coffeescript-ristretto" title="CoffeeScript Ristretto"><img src="http://i.minus.com/iMmGxzIZkHSLD.jpeg" alt="CoffeeScript Ristretto" /></a><img src="http://i.minus.com/iL337yTdgFj7.png" alt="" /><a href="http://leanpub.com/combinators" title="Kestrels, Quirky Birds, and Hopeless Egocentricity"><img src="http://i.minus.com/ibw1f1ARQ4bhi1.jpeg" alt="Kestrels, Quirky Birds, and Hopeless Egocentricity" /></a></p> |
| 100 | + |
| 101 | + <ul> |
| 102 | + <li><a href="http://leanpub.com/javascript-allonge" title="JavaScript Allongé">JavaScript Allongé</a>, <a href="http://leanpub.com/javascript-allonge" title="JavaScript Allongé">CoffeeScript Ristretto</a>, and my <a href="http://leanpub.com/u/raganwald">other books</a>.</li> |
| 103 | + <li><a href="http://allong.es">allong.es</a>, practical function combinators and decorators for JavaScript.</li> |
| 104 | + <li><a href="https://github.com/raganwald/method-combinators">Method Combinators</a>, a CoffeeScript/JavaScript library for writing method decorators, simply and easily.</li> |
| 105 | + <li><a href="http://github.com/raganwald/jquery-combinators">jQuery Combinators</a>, what else? A jQuery plugin for writing your own fluent, jQuery-like code. </li> |
| 106 | + </ul> |
| 107 | + |
| 108 | + </section> |
| 109 | + |
| 110 | + <hr /> |
| 111 | + |
| 112 | + <br/> |
| 113 | + |
| 114 | + <hr /> |
| 115 | + |
| 116 | +<p>Hosted on GitHub Pages — Theme by <a href="http://twitter.com/#!/michigangraham">mattgraham</a></p> |
| 117 | + |
| 118 | +<table> |
| 119 | + <tbody> |
| 120 | + <tr> |
| 121 | + <td><a href="http://braythwayt.com">Reg Braithwaite</a></td> |
| 122 | + <td><a href="https://twitter.com/share" class="twitter-share-button" data-via="raganwald">Tweet</a> |
| 123 | +<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script></td> |
| 124 | + <td><a href="https://twitter.com/RaganwaldsPen" class="twitter-follow-button" data-show-count="false">Follow @RaganwaldsPen</a> |
| 125 | +<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script></td> |
| 126 | + </tr> |
| 127 | + </tbody> |
| 128 | +</table> |
| 129 | + |
| 130 | + <!-- insert google analytics here --> |
| 131 | + |
| 132 | + </div> |
| 133 | + <!--[if !IE]><script>fixScale(document);</script><![endif]--> |
| 134 | + |
| 135 | + |
| 136 | + </body> |
| 137 | +</html> |
0 commit comments