Most of you reading this blog have probably seen the ALT.NET logo and its allusion to "running with scissors". Very clever, and as a software craftsman, I full agree with its sentiment. As smart, (and as Oren would say) consenting adults, we should be given the tools and flexibility we need in order to build awesome software. We shouldn’t have our hands bound, and we shouldn’t be artificially limited by the frameworks that we work with.
So as my discussions with Oren about my last post went on in the comment thread of his latest post, I started thinking about the different places that Oren and I were coming from. I also thought quite a bit about why I feel a strong compulsion to create strategies in my software design in order to funnel developers down the correct paths. As I thought about this more and more, I started to come to the realization that I was solving business problems in my code. And not the kind of business problems that we think of when we talk about creating rules and logic to solve a businesses needs, but instead, I was correcting for institutional deficiencies that I have seen in the past by coding around them.
Most of the places I have worked at have been fairly constrained environments. I have worked with a good number of awesome developers, but almost every company I have ever worked in has either had not enough time, money, or developers. Or all three. And in environments like that, things that many people see as being fundamental to creating good software sometime just don’t happen. Not enough unit tests get written, not enough code reviews get completed, not enough testing gets done before a rollout, etc… Corners get cut, and no one likes it, but unfortunately we don’t write our own paychecks. When, for instance, a new product needs to get rolled out, you don’t just tell the company that you can’t launch the accompanying website the same day as the product because you just aren’t ready yet. I can’t imagine a company on the planet where that would be acceptable.
I’d love to be working in an industry where those kinds of things don’t happen. There is a place that I like to call "Unicorn development shops", where management gives the software developers enough time and resources in order to always get the job done 100% every time, they might exist, but I’ve never seen one. And so the question begs an answer, unfortunately one that will likely never come, but is it okay for us to solve deficiencies in our development teams with code?
I certainly don’t have an answer for this. I know that I do it, as you can see from my previous post, I might even have a compulsion to do it. But is it the right thing to do? Are we better off throwing caution to the wind and picking up the pieces later, hoping that our team can grow along with us? Even as I am writing that last sentence I get this picture of a dev lead crawling up a mountain leading a heroic team of developers behind him. There really is something grand and heroic in that approach, relying on your fellow developer to rise to the occasion, take pride in their creation, and better themselves for it.
But is that realistic? In my experience, I’m not so sure. I’d love to hear your thoughts on it though, this is one question that I don’t really have a good response to. Or maybe I’m just exposing myself as a jaded cynic. 🙂
Loved the article? Hated it? Didn’t even read it?
We’d love to hear from you.
To answer your question directly: no, I do not think we should be solving institutional problems with our code. However, that is [i]not [/i]how I would characterize what you did with that last blog post.
It is an accepted design philosophy in software design to [b]only expose as much functionality from a software module as you need to[/b]. That is, after all, why we have interfaces, access modifiers, and the like, is it not? This is in NO way meant to reflect on the capabilities (or lack thereof) of the developers who will be using our modules. That’s just good common sense!
A corollary to this is that the author of a software module is o[b]bligated to offer as much guidance as possible in using the functionality that IS exposed.[/b] That’s why we (should, at least) fully document our classes, provide additional "convenience" overloads where possible, and so on.
I have a rule for any devs that work under me, and that is this — [b]develop your libraries as though you were designing a framework. [/b]That means no quick-and-dirty, no cutting corners, clear readable style, proper interfacing, access control, full documentation of all public/protected members, and above all… always aim at the lowest common denominator. 😉
Read both of your posts and I would do it both ways, depending on the client. If it were my own project and I trusted the developers to learn and the project was small enough that I could monitor such things, I would go with Oren’s approach. In a different scenario, maybe where the team is large and I can’t trust them even to right proper performance metrics, let alone tests, certainly, I’d put up roadblocks. Another scenario: when the team maintaining the app is not the team developing it.
Some people seem as if they don’t want to learn, even if you tell them "don’t to it that way." You can rant and scream all you want that they should be fired. They’re entrenched and I’m not. Maybe in a warmer economic climate, I’d be bolder. But I doubt it.
Surely it’s all about balance? Do you have public List<T> types for example? I was always taught / mentored to restrict the contract to only what’s required.
Equally if you know your audience or your constraint is time exposing IQueryable<T> isn’t a cardinal sin.
Like everything it all (IMHO) comes down to context. What is appropriate and when is never a simple question nor answer.
I’ve always believed that he who writes the library has the responsibility to ensure developers using the library use it in the way the creator intended it to be used. I hate to say it but that does involve sometimes protecting the developers from themselves. Some would argue that if you have developers that you need to do that for you should hire better developers and that to me is just simply not a realistic perspective. Dev’s come in all shapes and sizes and you will never have a dream team nor all the time and resources in the world to do what you want.
Developers & teams change constantly, sometimes mid-project, but the language and the tools it provides are much more consistent and reliable. You should use the tools that the language gives you, and that OOP and design patterns give you to enforce "safety" in your library or framework. At least to the best extent you can, some things are unavoidable next to writing all of the code yourself.
Where I currently work we had a situation quite recently where we had a property of a popular class that was meant only for serialization and was put into the framework a long time ago. Nobody knew this as the guy who wrote the code is long gone and no documentation existed stating as such. So everyone used it as a normal property that was a collection and it was causing a HUGE performance hit in our application. We fixed it once we found out but is that each developers fault who used that property? I don’t think so. The person who wrote that code is to blame. There should have been warnings, xml comments, or better yet the property shouldn’t have existed in the first place and there should have been explicit methods for developers to call in order to do serialization.
I’m in no way advocating that you shouldn’t trust your developers or push them to rise to the occasion but putting "safety cones" in your code to protect your developers is never a bad thing no matter how good they are.
@Ed Yes, most of the time the answer is not black and white. But even more importantly, the answer is not as important sometimes as the discussion.
@Tony That is an excellent example, in my opinion, of exactly where developers should put a bit more guiding help. I think that people would use the argument that what he did was simply bad coding practice, but nonetheless I think it is a good example of the kinds of things that just "happen" in large systems and no one notices until it is a crisis.
The data access are better encapsulated, exactly like fields are hidden behind properties.
You can live with code accessing fields when no logic has to be added on it… but… you know how in pain you’ll be once things change.
Keep you data access logic limited to what’s needed, in a limited place and it will be easier to manage in the long term.
Use flexible frameworks like linq and NHibernate to implement it, and it will be easy to write.
Your post is a bit confusing. Solve institutional problems with code? How would that work? In an ideal world you would have some sort of manager that would realize that the conditions aren’t conducive to great code and will make changes. In the real world, this hardly ever happens. Either way we, as developers, can only make best with what we’ve got.
Leave a comment