Friday, November 09, 2007

On Fluent Interfaces and Friction

So I decided to start that NHibernate Mapping DSL project and open-source it.  Right now it doesn't do anything, but you're free to take a look at http://www.assembla.com/space/nhibernate-mapping

I wrote all of this code test-first, and it allowed me to tackle the interface and flow the way I thought might be useful.  I ended up with something that was mildly usable like this:

IMapping mapping = Mapping.For<Product>()
.Identity("Id")
.Property("Name")
.Property("Price")
.Map();

So this allows me to quickly accept the defaults of the mappings, so NHibernate will assume that I have ...
  • the column names are the same as the property names
  • the type of the column matches the type of the property and it can be picked up via reflection
  • the identity generator of the primary key is Identity
  • the identity/properties have setters
  • the "Name" and "Price" columns are nullable
This isn't always true of course, so we need to be able to specify where we deviate from the defaults.  So how can we accomplish this using a fluent interface?  We could resort to adding more overloads to the Identity() method, so you might have....

IMapping mapping = Mapping.For<Product>()
.Identity("Id", "product_id", Access.NoSetterCamelcaseUnderscore, Generator.Native)
.Property("Name", "product_name", false)
.Property("Price", false)
.Map();
But we don't know how many settings the user might want to specify.  If we have 4 simple, independent settings, then we'd have to support 4! method overload options!  Yuck!

public IPropertySpecificationPredicate Property(string name);
public IPropertySpecificationPredicate Property(string name, string columnName);
public IPropertySpecificationPredicate Property(string name, string columnName, DbType type);
public IPropertySpecificationPredicate Property(string name, string columnName, DbType type, int length);
public IPropertySpecificationPredicate Property(string name, string columnName, bool nullable);
...
This is just the beginning.  What if you wanted to only specify the property name and the nullability?  We quickly end up in an anti-pattern I like to call overload explosion

We can do a bit better, right?  I started to gather my thoughts and came up with this syntax:

IMapping mapping = Mapping.For<Product>()
.Identity("Id")
.Column("product_id")
.Generator(Generator.Native)
.Map();
So now the Identity() method takes a single parameter, the name of the property.  Anything else is optional.  The return type is now something like an IIdentityBuilder interface, which accepts methods on altering the identity object that its building.  Here you can see that we only specified the settings that we wanted, nothing else.  We still had to have a way to "pop" the current object (and thus the entire mapping) so that we can indicate to the builder that we are done building the property and you can return the IMapping object next.  This feels awkward for now, but for now it's ok.

Let's extend this pattern.  Once I'm working with the IMappingBuilder interface, I can now see methods called Generator(), Access(), Column(), etc.  There's nothing there to prevent me from calling .Column("...").Column("...").Column("...").Column("...") which I guess isn't such a big deal.  All it's doing is setting the column property of this object we're building.

Now I'm noticing that there has to be a spot where the user gets finished with the mapping identity and now has some choices.  The obvious next operation would be to create a property, but how do I pop the current context and start working on a new one?

Maybe something like this?

IMapping mapping = Mapping.For<Product>()
      .Identity("Id")
      .Column("product_id")
      .Generator(Generator.Native)
      .AndProperty("Name")
      .Nullable(false)
      .Map();

I'm already started to notice that my identity and property elements are getting lost in the noise.  If I keep up this pattern not only do I have TONS of ISomethingPredicateBuilder objects, I also remember that it's not only properties that I can add at any time.  I could add a Bag, a Set, a List, or any number of other mapping elements.

Another route I might take is using anonymous to provide me with the flexibility of code within the interface.  Take a look:

IMapping mapping = Mapping.For<Product>()
      .Identity("Id", delegate(Identity i) {
                         i.column = "product_id";
                         i.generator = Generator.Native;
                      })      
      .AndProperty("Name", delegate(Property p) {
                         p.column = "product_name";
                         p.nullable = false;
                      })
      .Map();
Here I have a lot more flexibility over the different ways that I define various mapping elements.  The only part of this that is really cumbersome is the delegate syntax itself.

This is probably where Boo or Ruby would come in and save the day because of it's super-dynamicness-flexibility-extraordinaire, but I'd like to see how far I can push C# for now.  At least until C# 3.0 comes out, where I'll get object initializers, lamba expressions, and a few other neat tricks that really make this stuff more fun to sculpt.

What about you?  What types of syntax do you find most readable, usable?
Tuesday, November 06, 2007

Prototype & Scriptaculous - Protips #1

I often talk to people who haven't worked with one of the cool javascript frameworks out there.  I am partial to prototype and scripaculous, but I also really like MochiKit.

If you aren't taking advantage of one of these, then perhaps this post is for you... I give you the ultra quickstart to diving into prototype and scriptaculous!

Things you shouldn't ever program javascript without

The best thing ever invented since rubber tires: a replacement for document.getElementById('control_id');

You know you're not supposed to use document.all or document.ctrl_id, right?  Well at least now you do. document.getElementById() is the cross-browser safe way of getting an element off of the page. The prototype equivalent is $('control_id'). This will automatically extend the element returned with some helpful utility methods (like extension methods in C# 3.0). -- more on this later.

Along the same lines is a useful method for selecting elements using CSS selectors. If you're a CSS junkie (like me!) you'll appreciate this.    

$$("div span.info");
This will return all of the DOM elements that would be matched by that CSS Selector. (for those who don't know, this would get all span tags with a class of "info" that are directly nested underneath a div.

Want to show or hide an element? Use Element.hide(ctrl), Element.show(ctrl), or Element.toggle(ctrl). You can attach these methods onto the element itself by saying Element.extend(ctrl). If you retrieved it via the $() method, then your object already has these methods.

Let's say you want to grab all of the span tags from a parent div tag.  Typically you'd do this:

var spans = parentDiv.getElementsByTagName("span");

but what is spans?  If you thought it was an array, you'd be wrong.  It's a NodeList, which is not nearly as powerful as a javascript array.  (With javascript arrays you can push(), pop(), shift(), and other cool things that you can't do with a NodeList.  Anyway, back to the spans collection, we can elevate this to an array by using the $A( spans ) method.  Now we can use all of the nice array goodness for that list.

Effects for that extra polish

How about fading an element?

new Effect.fade(elem);
This also takes options so you can control how fast it fades, for example. Check the excellent docs for all the gory details.

Want to make a slide out box?

new Effect.toggle(elem, "slide");
This will toggle the element using slide up and slide down. ("fade" and "appear" also work here for toggling).

How about some ajax?

Forget UpdatePanels. Most of the time we just need to fire off a request and get a list of values back from the server. Prototype has you covered there:

new Ajax.Request( "/path_to_server/ajax/AjaxHandler.ashx?op=getUsername&value=bob",
{
method: "get",
onSuccesss: function(result) {
if(result.responseText) alert('available!); else alert('taken');
},
onFailure: function(e) { alert('something went wrong ' + e); }
}

I don't know about you, but that's pretty painless to me.

Want something a bit richer?  How about an autocomplete textbox? I wrote this one to auto-complete cities as you type.

var url = '~/AjaxHandler.ashx?op=get_cities';

ac = new Ajax.Autocompleter(city_textbox_id, results_id, url,
{
paramName: 'filter',
frequency: 0.2,
minChars: 1,
indicator: indicator_id,
callback : function(element, filter) {
var state = $(state_dropdown_id);
var state_code = state.options[state.selectedIndex].value;

return filter + '&state=' + state_code;
}
});

That's it. I'm not kidding. I handed it a textbox, a div to display the results, and a url to get the data. It takes care of all of the ajax requests, the frequency limiter to prevent us from firing a request with every single keystroke, and returning the results into a list. It even has full keyboard support. The url looks like ~/AjaxHandler.ashx?op=get_citiees&state=TX&filter=Hou and it will return the matches that it finds (based on an HttpHandler I wrote).

What are your favorite prototype / scriptaculous protiops?

Friday, November 02, 2007

Why No Ribbon in Visual Studio 2008?

Yesterday I was getting frustrated with the completely user-unfriendly massive toolbar that Visual Studio boasts, and noted that Visual Studio 2008 *should* have gotten the ribbon toolbar that shipped with Office 2007.  My cube-mate Peter said,
"They'd probably get sued by the Office Team."

Well said, my friend.  They probably would.  For "Toolbar Infringement." 

Wednesday, October 31, 2007

Fluent Interfaces Allow a Higher Level of Abstraction

Jeff Atwood takes a stand against using embedded languages to express intent. I concur with Ayende's response for most of his points, however I wanted to chime in on the discussion.

Later on, Jeff argues that a better way (or as he puts it, the "ultimate solution") is to include the underlying features of other languages to leverage them natively. He specifically mentions LINQ. Take a look at this sample LINQ syntax:

var priorityCustomers = from customer in Customers
where customer.Status = 'Gold'
select customer;

This syntax is great, and I welcome it for VS 2008. But this is almost the same thing as the Criteria API in NHibernate, or the Querying API in SubSonic. The only difference is that we're not using parentheses and dots all over the place, but the end result is the same.

Having this code directly in our language also makes it more difficult to construct dynamic queries. By dynamic I don't mean make the 'Gold' text a parameter, I'm talking about building the where clause dynamically based on run-time decisions. Using a query builder API such as SubSonic's allows you to do this.

Another point that Atwood makes is that creating fluent interfaces over things like regexes and SQL allows you to NOT learn the underlying concepts, which is unacceptable for professional developers. I agree with him, but LINQ is also one of those! The syntax we wrote above will get translated into a real T-SQL query for us. We should still be cognizant of the SQL that is generated and make adjustments where necessary, but does that mean we always have to program at the lowest common denominator? As professional developers we have to be aware of many technical concepts that are being abstracted from us. A lot of us program in .NET, and most of us probably have a background in C++. I'm glad I learned C++ so that I understand what's going on "behind the curtain," but I'm programming at a higher level of abstraction now. Remember having to always null-terminate your strings (I mean char arrays)?. I'm glad I don't have to do that anymore. Working at a higher level of abstraction allows me to be more productive.

The languages that we see in the coming years will almost certainly bost higher layers of abstraction and specialty, so that we can more easily build data-driven business applications, or 3D-modeled geology simulations, or whatever your domain is. AT&T has just created a programming language called Hancock, specifically geared for mass surveylance. ERLang is designed specifically for mission-critical, always-on systems.  There are many that exist today and even more that we haven't seen yet.  Don't fear the abstractions!

Friday, October 26, 2007

Ouch! From the ALTNET Mailing List

Someone suggested to use DotNetNuke for the community site for ALT.NET and I heard this reply:

I'd rather chew glass.

Ouch!

DotNetNuke does have a lot of flexibility and generally buys you a lot, but I don’t find it a joy to work with at all.  Especially the OOB experience is just nasty.

 

Tags:

The MSFT Open Source Conspiracy Continues

The latest news just broke in the previously noted Microsoft Conspiracy to Consume good open source project leaders.  I'm sure you've heard it 10 times before me, but what the hell, what's 1 more?

Rob Conery, creator of SubSonic is joining Microsoft full time to work on SubSonic!  I think this is great news.  First, it reaffirms my belief that Microsoft has their eye dead on the community.  Things are changing, and for the better, mark my words (muahahah).

I can't wait to see how this will affect the project, because I know that Rob has passion, and now that he doesn't have to worry about other projects, clients, or deadlines... he can focus and make SubSonic even better!

Who will be next?  Speculate in the comments...



Thinking of an NHibernate Mapping DSL

Something about Ayende inspires me to build something.  I got to thinking today about how I could create a DSL for NHibernate mapping files.  What's wrong with XML, you say?  Well...

  • It's verbose - XML is known for it's ability to easily validate based on a schema, not for readability.  In other words, XML was designed for computers, not humans.  Since I am a human (are you?) I would prefer something a bit more friendly.
  • Schema Validation takes time - Usually you don't notice, but some recent metrics show that it can account for more than 1/2 of the startup time for NHibernate when there are many mapping files.  If you have an appliaction with 1000 entities, arguably you have bigger problems than XML's readability and schema validation performance, but it IS noticable so hey....
  • Generates runtimes errors for semantic structure - Sure, the syntax is validated, but there are so many things that can go wrong with runtime compilation (that's a weird term) of mappings.
So I got to thinking how we could do better.  Here's what I came up with (with some additions from Ayende) -- it's in Boo:

import flux88.NHibernate.Mapping

mapping Test.Project, Test.Project.Entities

entity Customer,
table: Customers
default_access: "nosetter.camelcase-underscore"entity Customer,
     
        identity "Id",
generator: "native"
       
        property Name,         
column:   "CustomerName",
type:     "String(12)",          
nullable: false

property DateJoined,

property Address,
type: "String(200)"

set _orders,
access: "field",
manyToMany Order,
table: Orders,
pk_column: "customer_id",
fk_column: "order_id",
inverse: true

entity Order,
table: Orders

Note that there isn't a ton of extra fluff, it's meant to be light-weight and easy to write.  Additionally you could set defaults at the top (like default_access) so that you can avoid typing it all over your mappings.

Ayende added the notion of doing this:

for type in assembly.GetTypes():
continue if type.Namespace != "My.Model"
entity type.Name, type.Namespace:
idenity "id"

for prop in type.GetProperties():
property prop.Name

You get the idea.

There could be a number of benefits of doing it like this.  First, you can compile it, so you can get syntax errors notified.  If you use the BooExplorer I'm pretty sure you'd get intellisense for this.  I could also see plugging this into a model validator that would reflect over the model and make sure that all of the properties and access strategies will work with the mapping as defined.

Anyway, I have some reading up on DSL's to do... Ayende, that means I need you to write that book on DSLs with Boo :)  Can I have it next week?

Thoughts?  Suggestions?

Wednesday, October 17, 2007

Bandaids, Coke, QTips, Kleenex, and Ajax

 I’m sure you’ve noticed these…

  • Bandaid - Adhesive Bandage
  • Coke - Soda (at least here in the crazy south)
  • QTip - Cotton Swab
  • Kleenex - Tissue

The world doesn’t need another one:

  • Ajax - Microsoft ASP.NET AJAX

For the 100th time… AJAX does not mean Microsoft ASP.NET AJAX!

Need I say more?

Tags:
Monday, October 15, 2007

MVC versus MonoRail and the Corporate Giant

A lot of buzz is going around about the MVC framework coming out of Microsoft.  I posted about how cool it was and got a couple of comments that basically said: 

They just copied MonoRail.

Well, yes.  In a sense they did.  And Rails.  And Django.  And another one that The Gu mentioned that I hadn’t heard of.  Is that a bad thing?  If you’re using MonoRail today, then you should continue to use it.  Unless you like some of the different syntax or ability to mock the core ASP.NET Runtime objects.

The reason I think that ASP.NET MVC is so exciting and important is because I often come to clients that refuse to (or make it very difficult) to use non-MSFT produced thingies.  Can I use Resharper?  No, we gave you Visual Studio.  Can I use NHibernate?  No we use Enterprise Library.  Can I use NAnt, StructureMap, MonoRail, SubSonic?  Often times the answer is no.  Recently I’ve had experience where our team dumped eWorldUI in favor of ASP.NET Ajax Control Toolkit.  The reason?  Easier to get approved since it has Microsoft’s name attached to it.  It doesn’t matter that eWorldUI is free and easy to implement.  It matters because somebody sees eworldui.dll in a bin folder somewhere and everyone wants to know where it came from.

When you work in an organization with 10,000 employees that has widely adopted Microsoft as a technology platform, trying to get something approved like MonoRail is like trying to convince a Catholic priest that he’s really a MormonOk so that doesn’t really make much sense, but what I’m getting across is that it’s hard.

Some of my readers have already gone down this route, and succeeded.  And I commend you.  But I have yet to get corporate adoption of something like that.  Maybe it’s my inability to convince people of the benefits, or sway their concerns about supportability and such.  Or maybe I just work with very beligerant clients. 

Some of my colleagues probably read this blog, so just so you know I’m not talking about you… I’m talking about the other guy. .

Back to my original argument.  Since this is a new framework coming out of Microsoft, I will not have to fight to get it adopted.  I can go in and say “this is how it’s done for real applications” and have Microsoft guidance to back me up.  Hell, some clients might even ask me for it!  That’ll be interesting.  I can’t imagine what it would be like for a client to come up to me and say “hey I was thinking, maybe we should use NHibernate for this…”

Thinking about that makes me kind of sad that it hasn’t happened before.  Am I just unlucky?  Am I just not skilled at convincing?  Or is this commonplace in the industry?

System.Web.MVC will reach an audience that MonoRail doesn’t:  The corporate giant who already swallowed the pill and will do anything that Microsoft pushes, good or bad.  And a lot of consultants work firmly in this space.

Credit - Renegade motorhomes - Personal Loan - Debt Help