Tuesday, October 30, 2007 -
Jeff wrote a good post today on languages within languages- wrapping up the post with
Embrace the idea of languages inside languages. In The Land of Strings, we speak regular expressions. In The Land of Data, we speak SQL. Oh sure, you can pretend those languages don't exist, and hide out in the Kingdom of Nouns-- but you're only cheating yourself out of a deeper understanding of how things really work in those other places. Fluent interface object wrappers may seem like a helpful convenience, but they're actually an ugly hack, and a terrible substitute for true language integration.
There are two points at work here:
I left a comment on his blog, but thought it worth a post of my own to respond. No, I'm not cranky cause he mentioned SubSonic (and some not-so-flattering words) - that's just Jeff. What're you gonna do. He told me my blog sucked, too... but that's what you get with the guy - a cuddle or a kick, the claws or a lick - that's Jeff Atwood :). And I love him ...
Why Jeff Is High
Regex SUCKS. Someone please blow it up :). The old saying of "I solved a problem using Regex - now I have two problems" is dead on. I don't think using Regex to support any point you're trying to make is a good idea - let alone a sober one :):).
SQL is abstracted because it's a shotgun, cocked and loaded. It's locked in the gun closet so it doesn't blow the foot off your application when you screw up. .NET isn't a Query Analyzer or a spreadsheet. Their are two powerful systems at work here - they don't need to sleep together, their lovechild would eat us all and crap out Regex.
How many weird little holes would open up in your app if your Database was, essentially, IN YR APP? Consider Jeff's response to my comment:
IDataReader rdr = QueryDb("SELECT * FROM Customer WHERE Country = 'USA' ORDER BY CompanyName"); Which is more likely-- developers that understand Subsonic, or developers that understand SQL? Which is more desirable?
WIthout asking him what "QueryDB" is (nor telling him that you can actually do that very thing with SubSonic), my response to him:
Jeff - how would you write this example (from your comment), taking in an argument from a variable to avoid injection: "IDataReader rdr = QueryDb("SELECT * FROM Customer WHERE Country = '"+KILLMYAPPPLZKTHX+"' ORDER BY CompanyName");"... Which is more probable? A developer that learns SubSonic, or a developer who writes inline SQL ripe for injection? Which is more desirable?
Things like SQL Injection, Concurrency, Locking, Connection Pooling, and most importantly: Repeating Yourself. Frameworks are around so we can focus on the job at hand, not writing SQL and Regex all day. I'll take the Framework please, with a side of Going Home Early. I'll read my Regex books when I get home tonite, I promise.
All of this joking aside, I do find a lot of common ground here with Jeff - I don't like the nasty nasty API calls. It's been one of my goals to make SubSonic as readable as possible so you know whats going on, or can at least figure it out. I'm assuming you don't want to write inline SQL... right?
This is the point of this post (buried deep in the bottom of it) - I agree with Jeff about readability, and I'd like to make our next query tool a little more readable SQL-wise. I don't think the answer is hauling SQL into C# though :p.
To me, his example above, and mine:
IDataReader=new Query("Customer").WHERE("Country = 'USA'").OrderByAsc("CompanyName");
Is about as close as you can get.
And finally - a small clarification I think is in order :). It's not
proprietary SubSonic object noise
It's MPL'd Open Source code (which you're welcome to help us with Atwood!) and belongs to everyone :).
IDataReader dr = gateway.Select(Where.Field("Country").Equals("USA").Query.OrderBy("CompanyName"));
or slightly more readable
IQuery query = Where.Field("Country").Equals("USA");
IDataReader dr = gateway.Select(query.OrderBy("CompanyName"));
or with overloads..
IQuery query = Where.Field("Country") == "USA";
IDataReader dr = gateway.Select(query.OrderBy("CompanyName"));
I don't disagree with Jeff, but until MS opens up CSC, a lot of this stuff is going to have to stay with fluent interfaces (unless you wanna dig up ANTLR, etc).
As for readability, beauty is in the eye of the beholder. Honestly, I'd trade a bit of readability for intellisense as well.
(And there's nothing wrong with the SubSonic query implementation, I just thought I'd share my experiences. Although I'd be happy to donate if you do like it).
RegEx is like code herpes, there is this horrible outbreak where you spend an hour or two learning the syntax and testing your expression and then for months you never have to touch it or look at it again until suddenly it's back and worse than ever because not only do you have to relearn the syntax but also figure out what in the hell was wrong with the original expression.
My bottom line for any code I write these days is what will make it more maintainable, readable and discoverable by future me or jr. mini-me that inherits it. As you point out, embedded SQL isn't really maintainable without a lot of boring, mind-numbing effort and that's where Query steps in nicely.
So until we have compile checks of a language within a language stick with the fluent interface.
.OrderByAsc("CompanyName")
I think it should be:
.OrderByAsc(Customers.Columns.CompanyName)
Yes; it is more code to write but you will get intellisense on this, and you are sure that the fields exist according to you latest code-generation. If you change a column-name in your system, then you will get compile errors on all the queries using that field. Thats just a beauty.
Just my 0.02$ about this - even though its a bit off-topic. :-)
I agree with Jeff on the point that the small DSL languages are just as important as frameworks. I'm one of the weirdos who love regex and who've created programs that use regex extensively (shameless plug for http://www.notamace.com). I think if I had to go rewrite those applications using a framework object approach the app would be harder and more complicated to mantain (and not nearly as expressive).
I think developers need to have a basic grasp of regex and sql and some of the domain specific languages though. Just so they can have an idea of what the framework is trying to produce. This debate also reminds me of ASP.NET's horrible implementation of styles. I mean does anybody really use the "style" property of ASP.NET controls and build them programmatically (or in the designer) or do you use CSS? CSS is a DSL just like regex and sql.
I think it boils down to the right tool for the job, you can't have a framework that gives you 100%, sometimes you have to bust out the little ugly language from time to time.
BTW - I love nHibernate and ORM, not a fan of stored procs for CRUD. But even as ORM lover I have to admit there are times when you have to bust out some SQL (batch updates, batch deletes, searches that need to return a datatable not objects).
Also, here's a great tool for regex called Expresso, you can build regex by selecting options and they even show their pattern symbol. Its a great learning tool.
http://www.ultrapico.com/Expresso.htm
Anyway keep up the good posts! I love it when two great writers debate these kinds of issues intelligently on their blogs!
I agree that one should understand the underlying mechanisms. I was in a recent MSDN presentation by Microsoft where they showed off linq and some of these other tools. My friends and I commented that the reason this looked nice is because you'd done it the hard way and as a result you understood what it was doing. Without that underlying understanding, it's probably more difficult to even understand the easy way of doing it.
With that being said, the RegEx complaint he has, of that readable alternative, I don't buy. Yes, I could code up the RegEx in a single line, but six months from now when I have to reread it to fix something, that alternative syntax is a whole lot easier to look at and go "Oh, I see, we need this over here."
I can see where it'd be useful. The code I write has to be maintained.
--------------------------
Perhaps the better question is, which is more realistic?
I nearly pissed myself laughing while reading this. :)
*By the way, Rob... I downloaded SubSonic out of pure curiosity. I'll give it some eval time this weekend. We'll see if "all that". :)
I think faster than I type.
That's why I use this thing I call a "tool" to help me with it -- RegexBuddy. It's sort of like the IDE you use now, but one that understands Regex. Ditto for SQL Management Studio. It's a tool that understands SQL and databases.
If you're wondering why your IDE doesn't have this kind of understanding of the Regex language built in, hey-- me too! We have quad-core machines and 4 GB of RAM, and our IDEs have no clue what SQL syntax is, or Regex syntax is?
So instead, we have to invent these dreadful, hacky object notation wrappers just so the compiler can give us intellisense and detect errors in our syntax?
What's wrong with this picture?
> IDataReader=new Query("Customer").WHERE("Country = 'USA'").OrderByAsc("CompanyName");
This notation is like nails on a chalkboard to me. I find the original SQL far more readable-- and much more standard, e.g., SQL-92, and not some notation that Rob just invented one day (uppercase WHERE and all). I just can't deal with the embedded ObjectJunk noise -- to me, it's another explosion at the parens and periods factory.
To be fair, the LINQ syntax is quite readable as well. As Kent Sharkey pointed out in the first comment, this ultimately boils down to the very real competitive advantages of languages where you can define your own keywords and do this the right way without the ObjectJunk wrapper overhead. Not quite Lisp, but perhaps Ruby.
To be honest I wouldn't use either embedded SQL or an object wrapper. It would be better to use stored procedures. No SQL injection problems. Strong typing. Try it, you'll like it. 8)
My experience showed me several things about stored procedures. Sprocs are modular which means they're easier to maintain verses digging through GUI source code. You can also tune a stored procedure for better performance which removes the need to improve the GUI to achieve better performance for the inline-sql.
Also, from a more personal stand-point, abstracting the sql expressions away from the GUI to sprocs just feels more...clean and correct. Sure, writing sprocs involves a bit more dev time, but that time overhead just doesn't outweigh the rewards of using sprocs.
This is all my personal preference and doesn't mean it's "right". Maybe someone can show me the error of my ways.
To each their own though and if your method gets the work done and the client happy, how can anyone complain?
toyota priuso f