Professional Code
About a year ago, I read this post in my feed reader and created a draft with a link to it and a little note to myself that said, “interesting subject.” Over the past weekend, I was going through old drafts that I’d never gotten around to finishing and looking to remedy the situation when I came across this one and decided to address it.
To be perfectly honest, I had no idea what I was going to write about a year ago. I can’t really even speculate. But I can talk a bit about what I think of now as professional code. Like Ayende and Trystan, I don’t think it’s a matter of following certain specific and abiding principles like SOLID as much as it is something else. They talk about professional code in terms of how quickly the code can be understood by maintainers since a professional should be able to understand what’s going on with the code and respond to the need to change. I like this assessment but generally categorize professionalism in code slightly differently. I think of it as the degree to which things that are rational for users to want or expect can be done easily.
To illustrate, I’ll start with a counter-example, lifted from my past and obfuscated a bit. A handful of people had written an application that centered around modifications to an XML file. The XML file and the business rules governing its contents were fairly complex, so it wasn’t a trivial application. The authors of this app had opted to prevent concurrent edits and race conditions by implementing an abstraction wherein the file was represented by a singleton class. Predictably, the design heavily depended on XmlFile.Instance.CallSomeMethod() style invocations.
One day, someone in the company expressed that it’d be a nice value-add to allow this application to show differences between incarnations of this XML file — a diff changes, if you will. When this idea was presented to the lead/architect of this code base, he scoffed and actually became sort of angry. Evidently, this was a crazy request. Why would ever want to do that? Inconceivable! And naturally, this was completely unfeasible without a rewrite of the application, and good luck getting that through.
If you’re looking for a nice ending to this story, you’re barking up the wrong tree. The person asking for this was humbled when it should have been the person with the inflexible design that was humbled. As a neutral observer, I was amazed at this exchange — but then again, I knew what the code looked like. The requester went away feeling dumb because the scoffer had a lot of organizational clout, so it was assumed that scoffing was appropriate. But I knew better.
What had really happened was that a questionable design decision (representing an XML file as a singleton instance) became calcified as a cornerstone assumption of the application. Then along came a user with a perfectly reasonable request, and the request was rebuffed because the system, as designed, simply couldn’t handle it. I think of this as equivalent to you calling up the contractor that built your house and asking him if he’d be able to paint your living room, and having him respond, “not the way I built your house.”
And that, to me, is unprofessional code. And, I don’t mean it in the sense that you often hear it when people are talking about childish or inappropriate behavior — I mean that it actually seems like amateur hour. The more frequently you tell your users that things that seem easy are actually really difficult, the less professional your code is going to seem. The reasoning is the same as with the example of a contractor that somehow built your house so that the walls couldn’t be painted. It represents a failure to understand and anticipate the way the systems you design tend to evolve and change in the wild, which is indicative of a lack of relevant professional experience. Would a seasoned, professional contractor fail to realize that most people want to paint the rooms in their houses sooner or later? Would a seasoned, professional software developer fail to realize that someone might want multiple instances of a file type?
Don’t get me wrong. I’m not saying that you’re a hack if there’s something that a user dreams up and thinks will be easy that you can’t do. There are certainly cases where something that seems easy won’t be easy, and it doesn’t mean that your design is bad or unprofessional. I’m talking about what I perceive to be a general, overarching trend. If changes to the software seem like they should be easy, then they probably should be easy. If you’ve added 20 different customer types to your system, it’d be weird if adding a 21st was extremely hard. If you currently support storing data in a database or to a file, it’d be weird if there was a particular record type that you couldn’t put in a file. If you have some concept of security and roles in your system, it’d be weird if adding a user required a re-deployment of your software.
According to the Clean Code videos by Bob Martin, a defining characteristic of good architecture is that it allows decisions to be deferred as long as possible. If the architecture is well designed, for instance, you should be able to write a lot of the code without knowing if it’s going to be a web app or desktop app or without knowing whether you’d use MySQL or PostgreSQL or MongoDB. I’d carry this a bit further and say that being able to anticipate what users might want and what they might change their minds about and then designing accordingly is the calling card of a writer of professional code.
If you’re looking to defer a decision as long as possible, is putting something in a configuration file deferring it forever? : )
I think it just becomes data at that point, rather than design decision. 🙂
Ha! “Hey business. See? Your craziness goes into here, and if my app complains? Your decision, er, the data was wrong!”
I worry (because I’ve learned to) that some of your readers will see “anticipate what users might want”, take it as advice, and go do exactly the wrong things. On the other hand, you’ve written about YAGNI and about conflicting aphorisms, so maybe your readers are all going to be just fine. 😉
That’s a good point — I certainly wouldn’t want anyone to think I’m advocating gold plating. It is a subtle difference between anticipating needs and writing software that can be modified to meet them when the time comes and between trying to write software that meets all anticipated needs right now.
It can be very hard to sell to managers for this reason. Architects will get it, but often business people don’t. It’s like you’re calling them a liar or something, by suggesting that they might change their minds later.
I’ve found that my least-effort, least-screwup way to meet future needs is to TDD just enough to meet current needs and nothing more, because more code means more resistance to change. “Red, green, refactor” + “Stop futzing and pull new work off the backlog”. I’m guessing your experience has been the same, but maybe not; I can’t tell for sure from the words in that last paragraph.
I feel much better now that I’ve read the last paragraph of Years of Lessons Learned from Home Automation. Thanks. 🙂
Agreed it’s a fine line; for example, you may never need to switch from SQL Server to RavenDB, however, there’s no reason your business class should require SQL Server. I think that’s where experience and code review really comes into play.
In my experience writing code that can be easily replaced is the ultimate feature of professional code. Any architecture that allows each and every part of it to be replaced/refactored/renewed without letting the fallout of the changes resonate throughout the whole codebase is a good architecture. It directly correlates with writing readable code, applying YAGNI and SOLID principles and thinking about the core of the problem that you are solving, not just it’s immediate manifestation.
I think this is a great summary. This concept of professional code isn’t defined by YAGNI, SOLID and other characteristics, but it necessarily encompasses them. This is a good way of putting it — thanks for the comment.