Over at CodeBetter, Jeremy Miller has started a new series of posts about software development, and determining what is good:
" What is best? How do we decide what is best? Is there a constant set of basic criteria that we can use to judge software techniques through time? I say yes."
In the comments, I made a comment about 'Separation of Concerns' and that I believed that much of what is called 'Best Practices' is 'just' (more on this qualifier in a second) personal preference, and I'd like to expound on that here with a couple of my patently bad analogies.
1) Database Normalization:
If you need to know what it is, you can find a good overview here. Very roughly, the idea is to eliminate the duplication of data within the tables of a database. To use a standard example, if you have a customer table where you record their address, instead of putting in the name of the state in a column in that table, you would have a State table that contained the details, and then use a StateID column in customer that held the key. Also, in any other table that needed State information, you could just use the key, instead of including the name of the state (so you can avoid different spellings, impose standardization when it comes to displaying the data, etc.)
Tied into this is the notion of a normal form. There are six (apparently, I always thought there were five), with normalization increasing as you go (so second normal form is more normalized than first normal form, etc.).
However, as anyone who has done database work knows, normalization in and of itself is not an ‘ultimate good’ that supercedes all else. Take the customer table. There are going to be columns that indicate a customer’s name. So why not a Name table, instead of recording ‘John’ for both ‘John Smith’ and ‘John Nuechterlein’? And why not a NameType table that indicates if it is a first name, middle name, surname, etc. and then have a joining table to record the name of a customer?
Besides the negative performance impact that occurs when you have to join to too many tables (‘too many’ depends on the RDBMS in question to an extent), this is much harder to maintain, and to use a highly technical term, ‘stupid.’ No one would actually ever consider doing this.
As an intellectual exercise, I once tried to figure out if you could create a database schema where every table had only two columns, a key column, and a data column. Since I quickly got bored, I’m not sure, but if you take normalization to a ridiculous logical extreme, this would be the result (I think).
Which is also why no one uses 5th normal form, and why somewhere between 2nd and 3rd normal form is the norm in most production systems (at least that I’ve worked with, I’m sure there are others with other experiences). You balance the good of normalization with other concerns. Is there an exact, perfect balance? No, it depends on the context (though I’m more willing to say there might be close to an exact, perfect balance within a context, but I digress).
2) Network Security
A common need in any important computer system is security. Business critical data, privacy information, and many other things need to be kept safe and secure (most people, on a surface level, tend to focus on external threats, but really, most data theft is internal…but I digress). There are many different ways to enforce security.
Let’s suppose the system is an ecommerce solution that contains credit card information (it shouldn’t actually, except maybe the last 4 digits, but I digress). How would you go about securing this information? There’s a lot you can do with networking equipment to enforce routing rules, there’s a lot you can do with encryption, and a host of other things.
But let’s start taking it to a ridiculous logical extreme. You want to increase security? Disconnect the database server from the network entirely, pull the cable. But someone might still log into it locally, you say? Disconnect the keyboard and monitor. Someone could still pull the hard drives and connect to a different system? Power it down and put the hard drives in a vault. Someone could crack the safe? Destroy it terminator style by throwing it into molten steel. There you go, near perfect security (science fiction scenarios excluded as an exercise for the reader).
But this is, again, to speak, technically, stupid. No one would do this, or even consider doing this. You have to balance the need for security against other needs (the system actually working, being highly available, performant, etc.).
3) Separation of Concerns
Okay, so let’s apply the same notion of a ridiculous logical extreme to SoC. What would that look like? Although no one would ever actually consider doing this, sometimes I wonder if the ‘perfect’ implementation of SoC would end up like the ‘ultimate’ database normalization, a series of classes with one method each.
Now, since no one would ever consider doing any of these things, what’s the point?
Well, to start, saying that “Separation of Concerns is good” (Jeremy has stated that SoC is “the ‘alpha and omega’ of software design”) doesn’t really tell you much by itself. Sure, it is good in the sense that normalization is good. Which, I think is really to say that having a system with NO normalization is bad. So, you normalize to the extent you need to until the system is no longer bad. Similarly, I think having a system with NO separation of concerns is bad, and so you separate your concerns to the extent that the system is no longer bad in this regard.
The question then becomes, when do you reach this point? And it is here that I think a certain amount of personal preference comes into play. What are comfortable with? How much time would be too much time to spend given the deadlines you have?
This isn’t to say that all personal preferences are equal or that they are equivalent to whim. Far from it. You would tend to lean towards the personal preferences of experienced, seasoned software developers. But even then, there is often little agreement.
Since I have a little bit of experience with it, how would an experienced, seasoned software developer develop MVP/MVC? No one needs to spend a lot of time searching blogs to discover that there is a wide and varied set of opinions on the matter. How humble is your view? Do you like events or not? Should the view invoke the presenter/controller or not?
Moreover, should you always use MVP/MVC? I think the answer is an obvious no, but others would probably say it is an obvious yes.
To go a different direction, SoC might be viewed as being anti-YAGNI when taken to far. Do I really need DI? It’s seen as a best practice, but I’m skeptical (as are others). Do I need to use mocks when testing? I don’t know. I want to know that my system in production is going to work, and if I end up with fragile mock tests, maybe I’m worse off than if I just created integration tests (slow as they are), since then I’m testing what I really want to know.
4) To wrap up
So, are there best practices in software development? Well, I think there are very clearly worst practices, things to be avoided. And I do actually think that there are techniques that can help you to avoid worst practices, but I also think they need to be considered skeptically. There is a common dictum to the effect that the worst system you will ever create is your second one, because you will over-compensate for what you see as the deficiencies of your first system, but I think that it is probably the case that you are constantly doing this.
Which is why even (I would say ‘especially’) experienced, seasoned developers have a tendency to look at their last code base and see all the ways it could be better (this is why it is apparently an empirical fact that you have to be competent at something to know when you are being incompetent…the incompetent people aren’t competent enough to know). But at some point, perfect is the enemy of good.
To pull out something from my philosophical past, Hilary Putnam used an analogy concerning knives. Roughly paraphrasing from memory, it doesn’t make any sense to ask what the “best” knife is. There is no such thing. But, there is an objective answer to the question “Is this knife good enough for this job?” and I would say you could say something similar about ‘best’ practices in software development.