I recently finished reading the book Brownfield Application Development in .NET by Kyle Baley and Donald Belcham. The book is available from Manning. First off, let me say that I'm a huge fan of Manning as a publisher. I've found their books to be top-quality, over all. As a Kindle owner, I also appreciate getting an ebook copy along with the dead tree copy. I find ebooks to be much more convenient to read, but hard-copies are easier to reference.
The book covers, surprisingly enough, working with brownfield applications. Which is well and good, if that term has meaning to you. It didn't for me. Without retreading a chunk of the first chapter, the authors break code bases into three broad categories: greenfield, brownfield, and legacy. Greenfield is, essentially, new development that hasn't had time to rust and is (hopefully) being approached with some discipline. Legacy applications are those that are more or less stable and functional, that do not expect to see a lot of work done to them, and are more likely to be replaced than reworked.
Brownfield code is the gray (brown?) area between the two and the authors argue, quite effectively, that it is the most likely state for an application to be in. Brownfield code has, in some way, been allowed to tarnish around the edges and can be difficult to work with. Although I hadn't realized it, most of the code I've worked on has been brownfield. Sometimes, there's talk of scrapping and starting over. Sometimes, the team dismisses increased discipline as ivory tower nonsense. And, sometimes, I've been the ignorant culprit vexing my future self.
The book is broken into two major sections, plus an introduction chapter and an appendix. The first section covers what the authors refer to as "The Ecosystem" which consists of version control, build and integration, testing, metrics, and defect management. The second section is on actually writing code for brownfield applications and discusses object-oriented principles, architecture, external dependencies, and, of course, how to deal with these when coming into an existing code base.
The ecosystem section is just shy of 140 pages long and brings some real meat to the matter. The focus on "pain points" immediately sets the tone as problem-solution, rather than academic. The authors also approach some of the topics from a different angle than some essays I've read on similar topics. For example, the chapter on automated testing is on just that -- automated testing. It's all well and good to criticize a project as conflating integration tests with unit tests, but it really doesn't make anyone's life better. The discussion on testing is more focused on the "right" level of testing for existing projects. Sometimes, an integration test is the best you can do without gutting a section of functional code. Even if you can sell other developers and/or management on doing so, it doesn't actually provide benefit to your customers to rewrite code that works. This isn't to say the authors encourage sloppy coding. Far from it. Just that they point out the wisdom of ignoring the sleeping bear until after you deal with the snarling wolf.
The other sections take a similarly real-world, workable approach to the pain points they address. As the section moves from technical solutions like version control and continuous integration (CI) to the softer, process issues of metrics and defect tracking, the authors begin to gently suggest moving toward a zero defect count. While that really sounds like an unreasonable goal for a lot of ongoing projects, it's quite apparent that the authors have first-hand experience with taming some gruesome projects. The suggestions are grounded and workable, and the difficulty of some situations is explicitly acknowledged.
I have to admit that I started getting bored by the end of the ecosystem section. No matter how valuable I think a good project manager or business analyst is to a successful ALM, at the end of the day, I'm a gear-head. Also, while I agreed with a lot of the ecosystem ideas, in theory, I didn't necessarily feel that a lot of the single-developer projects that I'm often involved in really needed that level of rigor. It's only after reading the sidebars and commentary in the coding section that I had the context for the arguments made in favor of a strong ecosystem supporting the development process. That isn't to say that I didn't support good product management -- indeed, I've probably pushed too hard, on occasion, for a strong ALM outside of just development. This book gave me deeper insight into why some corners shouldn't be cut and how damaging certain sins of omission can be.
The code section, though, kept me engaged for its entirety. Many technical books can be used as reference material from day one. The authors were clear, however, that this book is not one of these. The first chapter of the section (chapter seven, over all) addresses object oriented (OO) practices. I've read any number of definitions, discussions, and treatises on OO. None of the chapter was new to me, but it was a good review, and I'm of the opinion that it's good to review the foundations of what you do, from time to time, so I didn't mind.
The remainder of the book is really just about how to apply OOP to existing code -- and, just because all your code exists in classes does not mean that it's object oriented. That topic has the potential to be extremely condescending, but the authors miraculously managed to never once make me feel like a dolt or that they were wagging their finger at me for my prior sins. Instead, they continue the "pain points" and problem-solution presentation to give concrete examples of how to apply some pretty academic-sounding ideas. That's a point worth emphasizing, as my experience with most OO discussions is that they stay in the academic realm. This book gives some very, very good explanations of why things like the Liskov Substitution Principle exist and why a corporate programmer should even care. Even if you know, with absolute certainty, that you'll never have to work on an existing code-base, I would recommend this book just for the clarity it provides on OOP.
This book goes beyond just theory, or even real-world application. It presents some methods for fixing problems that any developer can, and probably will, encounter in the wild. First, the authors address refactoring application layers and internal dependencies. Then, they take you through those layers from the UI to the data access layer and external dependencies. Finally, they come full circle to tie it all back to the overall process. By the time the book is done, you're left with a lot of ideas, but also a reasonable plan to begin to improve an existing project structure.
Throughout the book, it's apparent that the authors have their own preferred methodology (TDD and domain-driven design), as well as some preferred tools. The "Our .NET Toolbox" is something of a neon sign pointing to that latter point. They do not beat the reader over the head with anything resembling a "One True Way" mentality. Even for the most emphatic points, the tone is quite congenial and helpful. With some of the near-theological divides that exist within the tech community, I found this to be one of the more remarkable characteristics of the book. Although the authors favor tools that might be considered Alt.NET, there is no reason the advice and techniques given couldn't be quite successful in a pure Microsoft shop with Team Foundation Server. For that matter, even though the book specifically addresses .NET, it could be applied to a Java and Oracle shop, as well.