I’ve been thinking about my experiences writing code and managing projects over the course of the past several years. One thing that is shockingly lacking is the notion of interfaces.
About three years ago I decided I’d have to be more strict in my approach. The pattern of giving companies and legacy code a benefit of doubt and then regretting it happens too often. I was too lenient in some cases.
At a certain bio-tech employer a few years ago, I did actually try to improve and go beyond legacy code: after finishing my high priority work on the old codebase, I started a new C++ architecture, in part to correct interface / architectural inadequacies with the existing main codebase.
People were starting to buy in, but it was cut short by the entire division being shut down and everyone laid off due to the main product being late to market. And even if I claim that the Software group was not to blame, it’s a good segue into the Death March (a term from Edward Yourdon’s book of the same name).
In that example, maybe it was a Death March caused by the other groups. But Software can and often will achieve unavoidable failure and/or unsustainable overwork all on its own.
An unusable and difficult-to-maintain codebase could definitely cause schedule problems thus making a Death March that could have been avoided. As Robert Martin points out in his book Clean Code, the “total cost of owning a mess” leads to decreasing team productivity, asymptotically approaching zero over time.
It may not be noticeable if other disciplines are running even further behind schedule, but that doesn’t mean it’s a good situation.
How does this relate to interfaces? Well interfaces are everywhere if you put yourself in that mode of thinking.
Just as there are user interfaces for physical products (and user experience), there are interfaces in code, for example:
- Function signatures
- Class interfaces (essentially what a class looks like to the world)
- Class / module relationships—coupling vs. coherence
- File organization
- APIs (which often includes some of the above)
And there’s a lot of different contexts. Clients could be your fellow programmers or clients might be scientists trying to get something done with the code or it could be external users. Or the code might released in a product and the clients are also in some ways also now the end users of the product (especially the code that directly affects user interfaces).
And the ways of using the code could range from needing to modify it, to needing to extend it, to needing to just use it as is. Typically common scenarios should be the easiest to use for a coder. Nobody wants to have to read all the internal code or documentation and have to set up a whole bunch of ugly stuff or couple their code to 27 different external dependencies just to do the most common or typical things.
And yet this anti-pattern is quite common.
So please—put some thought into APIs and/or architectures or whatever clients are going to interact with.
And that thought should not be “how can I make the most generic system of all kind even if that means easy things are hard.” Don’t do that! Think about interfaces! Usability!
As an aside about languages: One of the great things about a language like C++ is you can have levels of complexity or levels of ugliness—as long as it’s wrapped / abstracted away into infrequently updated places.
In my experience, and I would love to hear counter-arguments, most programmers are not thinking about any of this. I know this because I’d ask about class interfaces when I used to interview people. And I’ve been working on software teams for a long time.
Programmers so easily stay in shallow, sometimes narrow, problem solving areas. Deadlines and prototypes allow too much coupling and overall bad design, and then are shoved into a process that allows design flaws to pass through.
And programmers accept way too willingly the authority of legacy code or the authority of older people or people who happen to have been at the company before them. But so much prototype code at startups or startup-like groups are just awful. Sometimes even supposedly well-planned frameworks turn out not to be so great because they didn’t take in to account how it would be used practically. Interfaces.
Honestly. It’s not enough to have working code or bug free code. That’s the easy part. If you’re doing a one shot demo in academia, fine. Move on. But in a corporation you need maintainable and usable code. And it very well could be the “smartest” coders in terms of being able to make one big function to do something complicated mathematically or super-fast that have no idea about architecture, clean code, interfaces, or object-oriented design.