Sure. Here's one example, "It looks at first like there’s a clear factoring 'Baltic Avenue has a method called isUpgradableToHotel,' but when you look more closely you realize that every object representing a property is burdened with knowing almost all of the rules of the game.
The concerns are not clearly separated: there’s no one place to look and understand the behaviour of the game."
The concerns are clearly separated, but they're separated along a different axis than what you're looking for. I'll argue that for any partitioning of concerns there will be a concern that is not adequately separated.
With that said, I must admit I'm unclear why each property object has to know all of the rules of the game. They don't have to know most of the rules AFAICT. This may seem like a small point, but I do think its important. I think the only thing they have to know if their cost to buy, upgrade, and rental price (I'm not a monopoly expert, so its possible I've missed something).
To buy there's a fixed price associated with the property-- you just need to not be owned by someone else. To upgrade I assume its a fixed price. I think the only requirement is you own all the colors. In which case you defer their ability to buy to another class -- the property group class. Baltic Ave doesn't need to know what the actual rule is -- it just asks "Light Blue Property Group Object -> Can I be upgraded?"
But the property object has no idea about passing Go, what Jail is, how many dice are used, what Chance cards are, who their neighbors are, how many other like-colored properties there are, what special powers railroads have, if there's a community pot, or how many players are even playing the game. The partition of concern has been made along some axis that this programmer thought useful.
Another is the telephone test and entangling what and how. I think what and how are the same thing. The for-loop example though is solving a different problem than the select example. It's solving a more constrained problem that you can't generally solve with the select syntax. It turns out though that what you are looking for happens to be provided by both solutions. As you move up the stack your problem requirement may be less constrained, in which case you don't need the rigor, but we should note that the rigor isn't simply the how, but just a degree of rigor (unfortunately standard languages with for-loops have to solve more constrained versions of the problem). What the telephone test is really about is that for anything you actually care to discuss on the phone will not be extremely rigorous.
But I feel like those are nits which I probably uniquely have, which is why I didn't actually mention them. But I wanted to point out that I disagreed, because I think it strengthens how much I enjoyed it. And while I disagree today, the fact that I read it and thought about it may mean that I disagree less tomorrow.
I'm really surprised by this statement, and I hope you will expand on it. I think the example of relational databases and SQL (which is very close to the example in the blog post) demonstrate conclusively that there are many case where huge gains are attained (in development time, maintenance, flexibility, ...) by building systems that allow a question to be answered by specifying "what" instead of "how".
Now I suppose you could argue that writing a SQL statement doesn't really specify "what"; it still specifies a "how", it's just that the "how" includes things like "let the RDBMS decide what indexes to use to answer this query, what order to access tables, whether to get data from disk or in memory, etc". But then I would ask what you propose as an alternative to the what/how distinction ... because there very clearly is a difference between SQL and hand-crafted for loops.
To me they're just degrees of abstraction/assumptions/givens (I'm not really sure what the best/right term is).
There's an evolution from:
label:
if (i > size) goto exitLabel;
yada yada yada
To iterators. When you see an iterator you don't care if there's an exitLabel or fall-through. For the most part you don't care if the loop counter is an int or long, or if there's no loop counter at all, as its using a null terminator or something. The iterator is the "what", the old skool method is the "how".
But the walk from iterators to select is similar. A select statement (grossly simplified) is simply a for-loop over a collection where you don't care about order:
select * from collection
That's not so intersting. So lets look at a common looping construct. It might look like:
for (obj in collection) {
if (obj has some property) { add_object_to_new_collection}
}
We can abstract that and make it:
select * from collection where property_holds;
Of course, this select, again, doesn't care about the order of the iteration at all (which also likely means doing things like having side effects evaluating the property will result in non-deterministic behavior). The iterator has become the "how" and the select the "what".
But while this is one man's high level abstraction this is another man's "how". For example, if I'm looking for anomalies in the data, I may not care to specify what the anomaly is. Just something that looks "out of the ordinary". One could imagine a language saying:
find uncommon relationships in collection1 x collection2
It should have well-defined semantics, but these semantics probably don't care if you use the "select" statement or the "for-loop" or some other mechanism. Those are just implementation details. Those are both "how's" not the "what".
To me you're just walking a chain of abstractions. There's no discontinuity where things suddenly break from "how" to "what".
Remember when Fortran was created it was a revelation because you could now just tell the computer what to do, not how to do it. You no longer had to load specific bits into specific locations in specific flags or accumulators. We certainly would no longer consider Fortran specifying the "what", but people did.
Now when I see people saying here's an abstraction so you don't have to specify "how", my question is "what are the assumptions?"
I don't think this is a fundamentally different way of looking at things, but rather a way that puts the emphasis on the nuance rather than the benefit.
One more point I should make on assumptions (and this goes to the convention vs ceremony debate) is that I think that part of why Raganwald like the notion of "what" is that it captures the right assumptions or best practices. Like above when I mentioned the side effects during property evaluation -- that's a pretty yucky thing. Just makes reasoning hard. Part of what makes good library/language design is capturing assumptions that bend programmers to make usually good tradeoffs. This is the whole trend of conventions in frameworks. But again, to me this is a gradient -- not black and white.
OK, this all makes sense. But why does it matter? Am I as a programmer going to make mistakes if I try to write programs in a "what" manner instead of a "how" manner? Is there some other, better distinction that I should be making?
Are you really saying that what matters is abstraction, and that we would be better off thinking about higher vs lower levels of abstraction instead of the more subjective what vs how? I think I might agree with that, but then you do get into the problem of deciding which of two pieces of code is more abstract, and I think you are going to end up with the same problem all over again of it depending on your assumptions.
I don't think you should look at what is more vs less abstract. Rather I think you should ask, "what maps closer to the problem I'm trying to solve" and implicit in that "what are the assumptions in the abstraction?". Although I suspect this is what you do already, as most good devs do, whether they articulate it or not.