Reading the beginning of Joel’s second section of his talk at Yale clarified one reason I find myself so at odds with much of the hard-core Dependency Injection crowd (has Joel really achieved the level of fame that we can dispense with using his last name as Phil Haack suggests? Did you know who I meant right off?). Anyway, I am an in-house developer in a small company and that has a huge effect on my architectural decisions.
I described it a couple of months ago as simply "small company development", but Joel’s right that the more significant aspect of it is that it is in-house—technically, my company probably has close to the same number of employees as Joel’s Fog Creek does, but our development environments couldn’t be more different. Now, Joel describes a bleak picture of in-house development and to be honest, it’s mostly true (particularly on the consulting side). I’ve been fortunate enough that my full-time gigs have been very high quality (alleviating much of the down-side that Joel dislikes so much). His first point about not being able to explore new technologies and never being able to do things "the right way" hasn’t applied to me, for example.
Return on Investment
What he got right in a universal way, no matter the quality of your in-house programmer job, is this bit.
Once the core functionality is there, the main problem is solved, there is absolutely no return-on-investment, no business reason to make the software any better.
It is this feature of in-house development that elevates the status of YAGNI to near-absolute authority. With in-house development, you won’t win more customers with new bells and whistles, extra flexibility, or optimization of pretty much any kind.
Dancing While Juggling
It’s not just return on investment that hampers the in-house developer, though, it’s also the environment in a broader sense. While the environment is relatively stable (the next section explores how that plays out), it is also dominated by large external forces. Whatever market niche your company occupies, the chances are that there is a 500 lb. gorilla creating software for your business. Barring an actual niche vendor, business software like SAP, Dynamics, or Solomon are happy to come in and run your business. The 500 lb. gorilla’s software likely handles 80% of the software needs for your company. Unfortunately, it’s the extra 20% that provides the true market value for what your company does (good ole 80/20 rule. Where would we be without it?).
In-house developers find themselves dancing around this 500 lb. gorilla finding (or creating) integration points to make it do what the company needs. If the business software is good, you develop a love/hate relationship with it as you poke and prod looking for the openings you’ll need to do your job (if it’s bad, it’s a simple hate relationship—this can get bad enough that it becomes a good idea to look for change, either of software vendor or job).
Since management is generally clueless about computer stuff and couldn’t care less as long as they can do what they want, they’ll spend their time thinking up new things to do. Phrases like "wouldn’t it be cool if" are nearly as dangerous as "hey, ya’ll, watch this". These requests and changes come flying in with irregular frequency and require deft handling by the development manager (whatever their official title) if you want to have anything like a chance to get necessary changes implemented.
So you end up dancing around your business software vendor while management continually tosses new shiny objects your way. You need a specialized kind of Agile here if you’re going to function.
Programming for Change
Institutional ADD aside, the environment itself tends to be relatively stable and, best of all, predictable. This makes planning for the future relatively simple. Your degree of certainty about environment and usage is way higher than it would be in a computer software company. I know that there is literally zero chance that I’ll be asked to make my programs run against MySQL or Oracle, for example (about the same chance I have of needing to run on Linux or Mac).
This environment makes issues like Separation of Concerns and its twin offspring Inversion of Control and Dependency Injection much less... pressing. At the very least, it means that The Last Responsible Moment can come much later than it does in "true" software development companies.
A Shipping Example
I’ll use programming a shipping interface using vendor-provided online web services to show what I mean.
A Shipping Interface in a Software Company
Now, if I were at a software company looking to hit against a vendor-provided shipping web service, I can pretty much guarantee that whatever anybody says, the scope of this project is going to include multiple vendors and frequent changes. I would be best off planning early to keep the query mechanism for the service general and make sure that the internal and external expectations are separated. I’d probably want an IShippingService interface (at a minimum) and I’d probably better look at services from several different shipping companies to see what kind of commonalities and features I want to ensure are supported.
The extra time up front spent on architecting a generalized structure will pay off in spades both as the services themselves change and as new shipping vendors come and go with the flexing of the marketplace. The chance of change approaches certainty.
An In-house Shipping Interface
Now consider the same need in an in-house environment. The biggest obvious difference is that your requirements are likely to be as specific (and short) as "tie our shipping rates to the FedEx web service for pricing". Nine times in ten, your shipping department has a detailed contract with a specific shipper complete with daily pickup schedules and a computer in the warehouse that actually belongs to the shipper printing out labels and such like. The chances of using a different shipper, let alone multiple shippers, is remote (if you’ve never worked in wholesale, this homogeneity can be a surprise).
In this environment, spending a lot of time generalizing your solution up front is unlikely to ever pay off. Your best bet in this case is to isolate your shipping module in its own class library to encapsulate it somewhat and to allow you to reference it in multiple places if necessary. You can crib much of the data structure right from your shipping vendor without huge concerns that you are backing yourself into an untenable corner you’ll later regret.
Running Blind with Scissors
Now, could it happen that you need to make substantial changes to your in-house shipping module? Absolutely. And it may be that your shipping needs are as complex as it would be for a computer software company (particularly if you have to ship wholesale into Canada <shudder>). All that I am saying is that the Last Responsible Moment can come after the fact. The conclusion from my small company development post would probably be better if an in-house development modifier were added.
The best "lean" skill [an in-house] programmer can develop is to program with an eye on refactoring. Moving to something better when it becomes clear that it is needed isn’t a lot harder than if you had implemented it in the beginning (and has the added benefit that you know it is needed) if you have kept refactoring in mind throughout. Leave "quick and dirty" programming for the amateurs. Solid refactor-ready code is the best legacy you can create and one that doesn’t age as people get over themselves or discover some new Great New Thing™.
Being ready and willing to refactor ruthlessly is the best lean practice you can adopt as an in-house developer.
I’ll call architectural choices that have a pervasive impact on a project "environmental". Things that change how or where you instantiate objects (acting as a replacement for "new" for example), or that require that all your classes are tied to interfaces, or that force isolation of your UI layer all have a global impact. Certain patterns and techniques penetrate deeply and fundamentally and as such, they need to be used with care and, more importantly, understanding.
The thing about environmental architecture is that it requires a familiarity with the specific technique or pattern in order to understand anything that is happening in the project. As such, its cost piles up in a small in-house development shop. Before too long, the only person who can make any changes to the code is the poor sap who put it there in the first place. Environmental architecture has inertia and weight that needs to be considered specifically and individually on a project by project basis.
Note that this has more to do with the project size and reach than it does with the architecture itself. If you’re doing a lot of small, well-isolated projects (as most of my development projects are), environmental architecture doesn’t have the time or scope to amortize the skill dependency cost let alone implementation and support costs involved.
It’s this dynamic that makes YAGNI king in small-company in-house development.
Dependency Injection Cross-talk
All of this came together for me while reading Joel’s Yale talk. Much of my discussion with DI advocates has these buried assumptions that our development needs and environments are substantially similar. I’m not sure this is the case. I deal mostly with small, discreet projects that take days (in rare cases weeks) to finish. My deployment can be as simple as a one-click "publish" from the developer’s machine.
Various fanboys and architect nazis want to dismiss me or make me feel inferior because I don’t adhere closely to their Great New Thing™. Whip me, beat me, call me "Mort", but the fact of the matter is that I don’t think it is wise to cost my company the time and effort let alone commit them to spending that time and effort in perpetuity just so that I can join the in crowd. The warnings of doom and gloom simply have not panned out in the reality I occupy.