Thursday, June 30, 2005

MonoRail, it's just good fun!

You know how some days can just drag on ya, and by the end of the day you just don't feel that you've been real productive? Yeah well, today wasn't one of those. :)

I started digging more into MonoRail & Ajax for this new website I'm working on at work, and it was really a blast.

For example, following the MindDump (at CodeProject) example's lead, I've been creating DataAccessObjects and Services. This is a Reporting site with some Administration sections. As we added more features it started to become clear that we could develop the entire application without a Database at all.

Think about that for a minute. Think you could do that in ASP Classic? How about ASP.NET, the code-behind model, using the code-behind as if it were a Controller, and embedding some O/R Mapper queries in it directly (as Thomas Tomiczek suggests)?

With MonoRail it's easy.

What makes MonoRail special though? DAO's are nothing new. Heck, you could write a VB6 COM component to use in an ASP Classic site as a DAO. So what then? The deal is that with Castle's WindsorContainer you can just whip up interfaces for your Services, and then some stub classes to implement them and serve up dummy data. So you don't need to worry about Database integration until the last possible minute. When you do have your real implementations ready, you can just make a few configuration changes and away you go!

Sounds like a lot of extra work though, all those Services, DAOs, etc... Actually, not at all. What is a DAO? It's just data access implementation details that you'd have to write anyways. The only difference is that you're wrapping it up in a class with a method signature for each task. Are a few class and method declarations really all that bad? Of course not.

So anyways, all this was a lot of fun. Even more so was getting the Table with Pagination example working though. It's just a great feeling writing something as slick as GMail. :) And MonoRail makes it easy. Then just for kicks, I surrounded the report in a div, and made it fade in from light-blue with the EffectsFatHelper. This is a new one to me, but apparently it's been around. Anyways, cyas, it's dinner time. :)

Wednesday, June 29, 2005

DataSets vs O/R Mappers (aka: Apples vs Oranges)

I was in the middle of writing a reply to a topic at the ASP.NET forums when I decided, hey, why not be greedy and post it on my blog? ;)

The topic is about "Defending the DataSet".

SeanSmith makes some good points. Some of the same points I've seen other smart developers make in defense of the DataSet. In my opinion he's missing the boat though. The post comes off as if he's presenting the DataSet as an alternative to O/R Mappers.

In reality you can't compare the two though. An O/R Mapper is incredibly complex. A DataSet, lets face it, is not. Even with all it's features it's really just a relatively simple bag o' data. They aren't interchangeable. I can easily refactor an application to switch between different O/R Mappers, say for example between LLBLGenPro and NHibernate. It's really not all that difficult of a task if I haven't let O/R Mapper specific code seep throughout my application. I can't on the other hand refactor to a DataSet. A DataSet doesn't do anywhere near the same thing. I'd also need to pickup some code-generation templates, tweak 'em, wire up my objects, and even then I'd probably still need to write a good bit of ADO.NET.

The reverse is equally true though. I can't take an application written around ADO.NET and DataSets and refactor it to an O/R Mapper easily. I'd be cutting out huge swaths of code, and unless I had very robust tests, there's a pretty strong bet that there's a good deal of logic going on in Queries or StoredProcedures that might not be immediately apparent in the context of trying to migrate to a Domain Model.

So overall I agree that it can seem like all you hear is "use an O/R Mapper", but there's a good reason for that. Using a DataSet for an Application, one that could be modelled, can easily result in a few "bad" things: Spaghetti Code, Database Driven Design, and Obscured Intent in Code. All of these are generally maintenance issues in my experience.

Is arguing this going to convince anyone who'se not willing to at least try Domain Driven Design though? Probably not. So I'll just take it as a given that you agree that there are definite benefits to the practice, and you'd like to learn how to gain them easily. The answer is, in the vast majority of projects, an O/R Mapper. Yes, there are exceptions, and yes, everyone thinks their project is it, but unless you're very experienced with such designs the truth is, it probably isn't and you should be using an O/R Mapper.

What's the flip-side though? Can O/R Mappers replace DataSets? No. They can't. Think back to what a DataSet is: Just as simple container for data. So why would an O/R Mapper even need to replace them? Simply put, most don't even try. Some choose to implement their own ITypedLists or maybe even return the most basic of data structures, an array of arrays, but many will just use DataTables and/or DataSets if they even have any reporting features at all. And that's where a DataSet shines. As a data container. For reporting, for communication, for migration, whatever the case, a DataSet is wonderfully suited to these tasks.

This is why I find such posts annoying to be honest. I know Sean had the best intentions, and he seems like a sharp guy, but so many people aren't on his level yet. Is there really any more need to validate the opinion that a decent O/R Mapper and Domain Model is unnecessary in all but the simplest applications? Isn't there enough of that going around? A DataSet is a nail, a Business Object is a screw. Sure, there's some bit of overlap, but by and large they should be filling completely different roles in your average Domain Driven Design, and ne'er the twain shall meet!

So the real argument doesn't seem to be so much DataSet vs O/R Mapper to me. If you're using business objects extensively, you better have a damn good reason for not using an O/R Mapper if you're using a relational database for persistence in my opinion or you're just burning money.

If you aren't using business objects though, if you're a former or current ASP Classic developer, then there's a good chance you're dealing with Database Driven Design and you may have never even seen a good Domain Model (or probably didn't understand it if you did since it's not something most people pickup after a quick looksey the first time). If that's the case, then the real argument is about the benefits of Domain Driven Design and Object Oriented Programming I think. That's a topic for another post though. It's almost midnight. :)

Tuesday, June 28, 2005

MonoRail & WebControls

So there's a small problem with MonoRail. No WebControls. No really, it is relatively speaking not much of a problem. Since it mostly doesn't use PostBacks, there's not much point in ViewState, so a TextBox is just a input. So why not just write the markup for the input in the View?

The problem comes in when you start talking about rendering "Grids", charts, etc. More complex controls.

So what do you do? Well, one way is to basically go back to an ASP Classic style for Views. Not real pretty though. Another way is to write Helpers. You can only have so many overloads for a method though in a practical sense though or it starts to look ugly. So what then? You can pass a single path or name that tells the Helper where to go to look up the specifics on how to render a control. Then you could end up with lots of extra little "Viewlets" though.

Or we can take a cue from ASP.NET and implement our own tags. The namespace alias could refer to a helper, and the element name could refer to a specific control... or perhaps we could use "rails" as the namespace alias, and the element name would then refer to the Helper. That seems a bit cleaner. So you'd end up with something like this:

public class GridHelper: AbstractHelper, IControlHelper {
public string Render(XmlElement node) {
IList results = this.Controller.PropertyBag[node.Attributes["results"]] as IList;

// do stuff with the "rails" element passed in, and the matching
// data pulled from the Context.
}
}


Then you'd use it like this:

<rails:Grid id="blah" style="borders: none;" results="results">
<columns>
<column name="Meh" />
<column name="Moo" />
</columns>
</rails:Grid>


I think that'd be cool... I have no idea what changes this would require in MonoRail or NVelocity right now though. I'll try to find the time to do so.

Saturday, June 25, 2005

My Influences

Martin Fowler: Is an introduction really necessary? Love it or hate it, but this is the name on everyone's lips. You can't read a modern book programming book on design that doesn't mention him at least once. He certainly didn't invent the topic, but for many, he made it accessable. Here's a career tip: If Martin Fowler says something you disagree with, you're wrong. End of story. I know, I know, idolatry bad, but seriously, it's like the old phrase "nobody ever got fired for choosing IBM".

Dave Thomas: Let me start off by saying, I only buy half of what he says. :) I'm probably wrong about the half I disagree with, but just the same. Why Mr. Thomas? While Mr. Fowler dishes out the goods when it comes to principles, patterns, and career lessons, Dave Thomas keys you into what's important, and what's not. You'll find out how to get stuff done by reading his books, and how not to loose sight of the goal. He's taught me new languages, tools, and every day there's more and more I find he was right about.

Scott Bellware: I'll be satisfied if I can "just" be on his level eventually. I dunno what it is exactly, maybe it's the rants. :) This guy is just the sort you want to have on your team. He seems like a normal guy, passionate about his work, and he helps to clue the rest of us in. He needs to post more though. :)

Frans Bouma: This guy is it for DataAccess. If you have to listen to one person on the subject, this is the person IMO. Why? Because he knows his stuff. Don't think this is because I'm a fan of his product (LLBLGenPro) either. I'm not so much. What I appreciate in LLBLGenPro is it's level of polish. It is without a doubt the most stable O/R Mapper in .Net land with the best documentation. I don't personally care for it's query interface though. Hopefully v2 makes some changes. :) Anyways, Frans is just a smart, patient guy who posts some great articles. He's always entertaining, and I've never seen him wrong. Of course he freely admits that he's been wrong before, and that he learned from it, and that's why you should listen to him, because he's been there, done that, seen it from both sides, and had the sense to swallow his pride and re-evaluate his position. This is why when Frans open's his mouth, you had better listen very carefully.

Hammet: What can you say? The community needs more guys like this. While I'm here making some little post on my little blog, he's out there banging out code for free that thousands of developers are using. I can think of few people who've made contributions as great as his to the .Net community (Charlie Poole & Michael C. Two, Jamie Cansdale, Paul Wilson, Darren Neimke, Mike Doerfler to name a few on the short-list), and yet he's very accessable and friendly. Start pushing the boundries of the .Net framework when it comes to AOP, Reflection, application frameworks, Inversion Of Control, etc, and you'll quickly find that all roads seem to inexplicably lead back to hammett. Wether you're currently all that interested in these topics or not, you'd be hard-pressed to find a better resource for "thinking outside the box" when it comes to programming applied to the .Net Framework IMO.

There's lots of people that aren't on this list that deserve to be, but these are my main influences. Hopefully somebody finds these links helpful. :)

Friday, June 24, 2005

A real issue-tracker at last!

Trac is evil.

Don't get me wrong, it's cool to use an all, and hey, it's free, but it took a friend of mine the better part of two days to get it running right, and that's just for a "generic" environment for our multi-project Subversion repository.

Granted, when it comes to Apache and Python on Windows we're apparently idiots, and we didn't see the guide on getting it running on Windows (despite much googling and reading of manual pages) until late in the game, but seriously. It was without a doubt the most difficult, hackish install I've ever been through.

In the end I suppose it's worth it if it lives up to it's promises, and it really is a very sweet tool to have around if you don't have a real tracker yet, so I'd still have to endorse it I suppose. Just be prepared to go bald and have all your teeth pulled out by rusty pliers during setup of it.

UIBroker

The UIBroker is officially dead. :)

Why? Well, after working with MonoRail for awhile now there's really no point. The auto-mapping to method parameters makes it a mute (moot?) point.

Wednesday, June 22, 2005

c# tip:

Did you know you can escape reserved keywords with the @ sign so you can use them as variable names? I had no idea. Just ran across a post on the NHibernate forums describing it.

Where NHibernate uses "clazz" as a variable name now to refer to a variable holding a Type (I always use type myself, but I realize they probably want to stay more or less CLS compliant), they could be using "@class".

Just thought that was nifty.

Knee-jerking

First off, I owe Jay an apology. I posted a knee-jerk reaction here earlier to his censoring a comment of mine. It's his blog, he can do what he wants, and I need to take away the lesson from this whole little episode that you can lure more flies with honey than vinegar. :)

So Jay, if you're reading, I apologize, and if I do choose to take part in a discussion of yours again, I'll try to follow your example and be a bit more civil.

On with my (friendlier hopefully) comments on the topic:

Jay Kimble says: That there's a problem with Ajax (or the discussion about it).

What he doesn't talk much about is his implication that 5000+ lines of Javascript is inferior to a server-side (VBScript) solution.

My take is that 5000+ lines of anything for a single View is probably a problem, and if the code is hard to work with, then the real problem lies in refactoring it. That may indeed include moving more of the functionality server-side, but not necessarily. It might be easier for example to use a server-side template for return results, so that instead of a lot of .appendChild() calls in javascript, you can just set the value of an element. It's true that if you're not careful, client-side javascript can definitely be a performance problem after all.

In the end, it's still hard to comment with any authority not having actually seen the code in question though, so that's my best shot. :)

Tuesday, June 21, 2005

Subversion is king!

It's hard to describe just how sweet Subversion is. At first, I thought I might miss VS.NET integration, being a former VSS/SGV user, but actually, it's so much nicer without it. I don't have to worry about readonly files, I just load up a solution, and do whatever I want to it, then commit my changes when everything works. Nothing's ever locked, I don't have to ask anyone to check something in. Downloading or Uploading is seriously at least 10 times faster than VSS. My folder structure on the drive is my folder structure in the repository, I don't have funkiness going on where the source control decides to start nesting project folders six deep for no reason (that I can tell).

It's just a thing of beauty. If you're a VSS user, you owe it to yourself to download TortoiseSVN, and force yourself to work with it for a week. If you're not convinced after a few days, then no loss, at least then you'll know why every open source project you download uses CVS or SVN. It's not (just) because it's free; it's because it really is just soooo much better.

I wish I'd had the motivation to give it a shot a long time ago. Oh well :)

Sunday, June 19, 2005

Choices choices choices...

So work is great. I got transfered into my own department (R&D) and have a lot more influence on future development so far. The "D" in R&D is apparently going to be pretty heavily emphasized since it looks like I'll be writing much of the code for the new stuff myself (along with a friend working in another department). Maybe I can convince 'em to bring in a contractor too to help out.

So basically I'm going to be in charge of rewriting our existing product. Big, scary task. So what do I do? Where do I start?

Well, first things first, Visual Source Safe sucks. I was actually pretty shocked to hear the server the shared repository is on is on the local network. It's so slow I had just previously assumed it was in our backup off-site location. :) I tried Source Gear Vault, but if anything it seems a bit slower, if a lot more stable. Still, the VSS "feel" isn't doin' it for me, and I don't like the lock model particularly. I recently had to install TortoiseSVN to get at the Castle repository, and was blown away by the speed. Since our SGV trial license is about to expire this week, we're going to make the switch to Subversion and see how that goes. I really like the idea that I won't have to check out a project or solution exclusively just to add or remove a file.

Next we need to make a big decision: Beta2 or .Net1.1? I'm thinkin' Beta2. The available memory increase to 90% from 40% alone should be pretty sweet though there's just a ton of advantages obviously. I'll definitely miss Resharper, but I've held off as long as I could. JetBrains, please hurry!

On the other hand, Beta2 doesn't buy this project a whole lot from a pragmatic stand-point. We could easily live without it, and Resharper would definitely help out a lot. I'm conflicted. :) Actually I'm 51/49% leaning towards sticking with 1.1 just to keep R#. Very on the line about it though.

Then we have to decide: CastleProject's MonoRail or WebForms? Definitely leaning towards MonoRail. Not only is it easier to test, and results in much cleaner looking code, but we can also very quickly mock up some HTML pages for review by the clients (the upper management in this case), and once we've got the look and feel nailed down, we'll be well on our way to having written the View(s) involved.

We definitely need a Wiki goin' on, and a better issue tracker than our sad in-house one, so looks like we'll be using Trac to integrate with Subversion for those duties. I like Jira's feel better, but Trac is simpler off the bat (since management will be reviewing this, that's a concern), and it's free, so if it doesn't work out, no harm, no foul.

What else? Well... we were thinking about CruiseControl.Net for scheduled builds/tests, but we're not real firm yet. CC.NET is a little ugly, but it does apparently support MSBuild. Not really sure what we'll do on that front yet.

Definitely need to switch to Cassinni. Messing with permissions with IIS5.1 can be a pain sometimes.

I need a new mouse. My Logitech MX900 never did charge well, and now one of the terminals has cracked plastic around it. Stupid hit&miss Logitech cordless mice... oh well. A simple MS Intellimouse Explorer2 like I use here at home would be better. No drivers to install, and I've only changed the batteries like once in a year. The MX900 wouldn't last more than a day, so if I forgot to charge it it was no bueno. I also need new monitors. The dual 17" LCD's I have now aren't cutting it. Spending a grand on a couple Dell FP2001's doesn't seem like such a big deal to me. I know makin' it happen is probably going to take an act of god though. I love the Samsung 213T though. That's what I use at home. It's long in the tooth I suppose, but it's got good contrast, it's bright, it's big... what more could you want? We'll see what I can pull off I guess.

Friday, June 03, 2005

Adaptive Object Modeling and Aspect Oriented Programming

So I was reading Chris Lasater's articles on AOM at CodeProject, and it got me thinking...

At work, there's an application that's in routine flux. The past week alone I've had 3 change requests for it. It takes in Sales Leads, assigns them statuses, and then assigns the leads to users based on the state of the SalesLead object. I wrote a rudimentary RulesEngine to make my life easier with these changes, and now much of the process flow is driven by rules defined in the app.config. 95% of these changes are limited to these two operations: Assignment of Status, and Assignment to User.

In this scenario then I don't see much value in AOM. On the other hand, the RulesEngine could be more powerful. Not because it's really needed to be so far, but because it'd be cool. :)

So far the rule Consequences are simple ValueType assignments to the examined object, so no biggie. On the other hand, wouldn't it be cool if I could transfer more of the behaviour to meta-data? For example, if the phoneNumber already exists in the database, it's considered a duplicate, the status is set accordingly, and the duplicateHandler is assigned the lead. This is in code right now, and it's one of the sore spots design-wise that just gets under my skin.

What if I could move that to the business rules meta-data?

Well... I'd need support for more than just simple target value matching then. I'd need to be able to tell it to try to match that field against all SalesLeads in the database.

So I'm no whiz when it comes to AOP, but I do have a level of familiarity with Aspect#, so I'm pretty comfortable thinking I could use it to inject some pointcuts and mixins to extend the behaviour of my object. If I fleshed out the rules engine so that it could have more fully realized Condition and Consequence scenarios that'd be cool too.

Basically instead of the Controller I have now to process these objects, I could merely Parse->ApplyBusinessRules->Persist. The Controller then would be much simpler.

Just tryin' to think this through, but yeah... this seems do-able...

NHibernate ICriteria.SetFetchMode() issue.

I think I might have solved it? It's sloppy, and frankly, might be causing other bugs, but it seems to work for me, so until it's officially resolved, I think I'll stick to it if I don't run across anything broken by it.

The solution was on line 313 in NHibernate.Loader.Loader.cs:

int count;
for ( count = 0; count < maxRows && rs.Read(); count++ )
{
object result = GetRowFromResultSet( rs, session, queryParameters, hydratedObjects, optionalObject, optionalId, keys, returnProxies );
results.Add( result );
}


As you can see, each row in the resultSet results in an object reference in the results IList. This is obviously no-bueno.

So I modified it to this:

int count;
for ( count = 0; count < maxRows && rs.Read(); count++ )
{
object result = GetRowFromResultSet( rs, session, queryParameters, hydratedObjects, optionalObject, optionalId, keys, returnProxies );
if(!results.Contains(result)) {
results.Add( result );
}
}


And now you see the hackiness. Basically this will prevent you from getting a list with duplicate objects in it.

Now I can't think of why you'd want that off the top of my head, but it does seem a huge change to be making, so I dunno. I'm anxious to see what the real solution is the NHibernate guys come up with...

My Job (2)

Things are much better this week. It looks like all the hard work on the ASP.Net project paid off, and things are looking up!

Woo hoo!

I've got a lot on my plate to digest this weekend. Hopefully I'll get to atleast one. :)

I want to look into that new OfficeXml stuff to see if it'll be useable anytime soon. I wanted to take a deeper look at Drools2.0. I need to work more on my own RulesEngine. I need to add some more features to my UIBroker. I need to add support for Flags() enums in the XmlActivator, and I really need to get around to adding support for custom Constructors. I need to see if I can swap out NHibernate 0.8's criteriaImpl for 0.7's so I get my pre-fetch support back. I need to get started on a new version of an Excel/SqlServer Automation Reporting/Mailing Service I wrote. If I can get it done on the weekend I'll open-source it. (Probably not, but who knows?)

I need to brush up on my Asp.Net skills more regarding dynamic controls, server controls, etc. I need to polish up my Ajax adventures and control-ify 'em.

If I could I'd spend a couple weeks on all that. :)

Oh yeah, and I need to polish off "The Pickaxe" Ruby book... I think I might do that Excel automation thing in Ruby for practice.

I'm currently reading:

"Anti-Patterns" by Brown, Malveau, McCormick, & Mowbray.

This page is powered by Blogger. Isn't yours?