Code Renaissance is about building great teams and great software. By exploring best practices, team interactions, design, testing and related skills Code Renaissance strives to help you create the team and codebase that you've always wanted.

The Lie of Reusablity

The lie of reusability in software engineering is that modules and controls that are competently designed  are easily reused and that reuse will translate into increase productivity. Business people love this concept, which has ample examples in the physical world, because reuse should save time and time is money. So they push the expectation of reuse and increased productivity on developers who strive in vain to bring the myth to life. In practice though, reuse usually requires significant effort and the main benefit you get, at least the first couple of times something is reused, isn't increased productivity, it's increased maintainability.

Consider a simple textbox control (win-forms, asp.net, etc). It took thousands of hours of effort (adding together the planning, coding, testing and maintenance time spent on the control) to bring that level of reuse to your finger tips. It seems like a simple control, but it has lots of events and properties that make it work for everyone and behind those are a myriad of subtle and well thought out decisions that have perfected it for general reuse.

Anyone who has ever tried to do simple composite user controls for internal use can tell you that even that relatively minor level of complexity has can contain a host of hidden and unexpected problems. Ever purchase a user control from an outside vendor? Worked great didn't it... until you got past the basic cookie cutter code and tried to get it to work in you particular context with your constraints; under those conditions subtle little problems emerge and it often falls just short of what you want it to do. Now go hunt down one of those developers and ask how much blood, sweat and tears their team put into getting that control to that level of reuse.

The truth is when you build a module or control you have no way of knowing how or even if it will be reused. The best you can hope for is to follow best practices and to keep the code as clean and well commented as possible... anything else is wasted time. When you reuse it for the first time you now have a new context to code for and the code will have to be adjusted to work in that context and then refactored mercilessly to make the code clean again. In all likely hood the this work will take longer that the initial work on that item. In the next iteration if you're lucky you may get your first efficiency gain from reuse but adjustments will still need to be made.

One real danger in iteratively adjusting code for reuse is increased complexity. Each iteration will likely have new features and requirements that will have to be added to make it work in that context. The larger the code becomes the harder it will be to understand the code as a whole and the more work it will take to change it cleanly.

In some contexts ("okay now we need all but one of the fields to be read only and we also need 12 additional fields and one button added, but only here") it may be worthwhile to simply build a new control or module to handle that particular case. Yes there may be some code duplication, which you may or may not be able to refactor it our into a common module, but everything in software is a trade off. You'll have to ask yourself which hurts you more (makes things less maintainable), the code duplication or the loss of cohesion and added complexity?

Of course if you're a developer who's been around a while you've likely already been through all this, perhaps wondering what you're doing wrong that the dream of reusability isn't working for you. The truth is you're likely not doing anything wrong... reuse can be a worthwhile endeavor but in all but trivial cases it's going to be difficult.

Quotes for Software Developers #3: Efficientcy

"There is nothing so useless as doing efficiently
that which should not be done at all." [Peter Drucker]

My Take On It

Unneeded, poorly planned and underutilized features are one of the biggest wastes of time in software development. You can run the most efficient team in the world but if you're allocating time to unnecessary fluff, you're wasting time.
Is that feature needed? Really? If it is, is there a better way to do it? The longer a bad idea lives the more time it wastes. If it makes it into production not only was the development time wasted but maintenance time will continue to be allocated to a feature that never should have been.

Implement the minimum set of features first and build upon them incrementally. Kill feature ideas early and often. Good ideas will come back again and again until they're implemented.

Maintainability: Consistency Trumps Correctness

Consistency is the key to a maintainable, high quality codebase. The way an architectural problem (see def) is solved in one part of the code is the way it should be solved everywhere in the code. This is true even if that solution isn't totally correct, correct being defined here as the optimal, preferred solution at a particular moment in time. With correct defined this way, as it is in practice by developers, correctness changes on a fairly regular basis, and can vary wildly from developer to developer, leaving behind it a wake of inconsistent, bug ridden, unmaintainable code.

Consistency provides Quality

One time solutions, those built from the ground up without regard to previous work, have a lot of unknowns that can't be accounted for. Though estimates will be padded to compensate, developers tend to be overly optimistic about their skills and minimize the complexity of the problems. This leads to insufficient time being allocated for a task. When nearing the end of their allotted time behind schedule, having spent time they didn't have on problems they didn't account for, developers will push themselves even harder to meet the deadline by taking short cuts and cutting code quality. These solutions will have significant problems(e.g. bugs or missed requirements) and will take yet more time to get right. To the business it may look like everything is going reasonably well, despite a few defects and delays, but in reality the foundations of the project being demolished beneath their feet.

In contrast, when a developer knows exactly how something is going to be built, especially when they've built it that way before, then their estimates tend to be accurate and realistic, allowing the business to plan accurately and pull features or make other adjustments if necessary. Solutions that are repeated can be implemented quickly with relatively few defects and solidified over time, which is to say that if a bug is found in one implementation it can be quickly checked for and fixed in all. As unfulfilling as it may be for programmers, the only way to do it right every time is to do it the same every time.

Consistent code is Maintainable

When a bug is found or a feature needs to be added the first thing that a developer will do is look at the code to understand where changes need to be made. When consistent patterns are implemented then the developers have a very good idea of how the code works, where to look, and what to do, therefore maintenance will go smoothly.

If an existing pattern isn't working then the team as a whole needs to evaluate it and define a new one... and then go back and change all of the old code. If it's not worth fixing all the old code then it's probably not that broken. Only by establishing and enforcing team standards, patterns, and practices you can create a consistent and maintainable codebase.

Fail 1: Poor Communication and Lack of Documented Standards

Writing standards is an arduous task for most developers and being restricted by them can seem stifling. It's the old "Smart for one, dumb for all" adage. Each developer thinks "I'm skilled. I'm experienced. I should be able to decide how to do things!" but when everyone does this then their disparate ideas and standards will eventually collide (as developers are forced to maintain each other's code) and the codebase will become a nightmarish hodgepodge of one offs, cludges, and hacks. If developers don't talk about the problems they're solving and work together to standardize on solutions then the codebase is doomed to devolve.

Fail 2: A Search for Interesting Problems

Smart developers love to be challenged by interesting problems. These are the kinds of problems that developers will fight over and that the more tenured developers tend to take for themselves. These problems come up frequently early in a project but become ever more valuable commodities as the project matures. During a drought of interesting problems developers will look for problems that have been solved in less than optimal ways and challenge themselves with them. This leads to a codebase peppered with complicated, novel solutions; a complex, inconsistent codebase is the bane of maintainability.

Fail 3: Excessive Speed of Development

This is the biggest killer of code quality. Early in the project, in an effort to prove they are on track and on top of things, the business pushes the developers to produce too many features too quickly. This stifles developer discussions and standards at the time when they will have the biggest impact on the success of the project and future developer productivity. In addition each developer is likely solving many of the same problems in different ways with different levels of success and a great deal of time is wasted.

Developers respond well to, and can even thrive on light to moderate amounts of consistent pressure (this varies from developer to developer). Under too much pressure though they write absolutely horrid code and will sacrifice the code quality and pretty much everything else in order to meet a deadline. Sadly, early efforts to push productivity usually end up hamstringing the project before it ever gets off of the ground.

The Solution

As counter-intuitive as it can seem from a business perspective sacrificing productivity for communication, group problem solving, and team standards actually leads to significantly greater levels of productivity over time. This can be a hard decision for leadership to commit to. Commonly they'll pay lip service to it without actually reducing the pressure on the developers so they can follow through with it. Or worse they won't hold the development team accountable and the developers will shirk the hard work of putting standards in place. The only sane way to manage a project is to put code quality, consistency and standards first.

Quick Tip: JS Event Binding and the Call Stack

Here's a little tip to make your javascript easier to debug... when subscribing to an event always wrap your event handler in an anonymous function so you can see the binding in the callstack. For instance the anonymous functions below will show up in the call stack (and thus the call stack can take you to the wiring code):

$(document).ready( function () {
   Init();
  });

Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(
  function () {
   Init();
  }
 );

But on the following calls (without the anonymous wrapper) all you'll see in the call stack is the jQuery or ASP.Net javascript that is doing the event handling:

Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(Init);

  $(document).ready(Init);

Hope this helps.