The state of code first development in Umbraco
If you are just coming into the whole "code first" world within Umbraco, that is designing your document types (the buckets that hold your data for an individual page) in code, then you might be a little confused as to how to do it if you can do it at all.
There are a number of different ways, none offical and none perfect. First up we should briefly cover what it is that we are trying to achieve by using code to do this work rather than manually doing it by pointing and clicking around the backend. I'm repeating bits from another post but bare with me.
Essentially we want to achieve as many of these goodies as we can:
- Source control any changes - say you add a check box for a new feature, we want to know when you added it and why (thanks to a helpful commit message). If you use the UI you don't get this as its locked away in the database and we can't source control that. Ideally it should be in a file that we can see and store in source control. Also super handy for rolling back a feature or even copying a feature from one client site to another as you can see what you added/changed and hopefully why.
- Ease of deployment - we don't want to have to point and click around in the backend on every version of the site to duplicate our newly added check box, chances are we might get a bit wrong (like a typo in the name for instance) whenever we deploy anything, its prone to error and its just plain boring repeating this stuff. Ideally if its in code we should be able to drop the DLL with our code into the site and the document types should all just appear/sync up automagically.
- Strongly typed models - We would like to be able to call a spade a spade. We want a descriptive model of our data that intellisense can help us make our templates more readable and understandable. Rather than using "magic strings" for getting properties we would rather be able to do something like Hotel.StarRating and know that it will return a string or int or a whole new object but we are in control to it and the compiler will help us out to do it correctly thus avoiding errors. This is one of the main drivers for us here at Offroadcode for doing all this lovely code first stuff. We like readable templates.
- One place to define all our document types - ideally you don't want to be using the UI andcode to defined what your document types look like. You want to use one or the other, as we are talking code first we want to be doing ours in the code and ignoring the UI completely. I personally don't mind using the UI, its fast and simple but I don't to repeat any setup. I want it to be a one time thing ideally.
- Should not hinder development - we want a process that makes it quick to bash out code/sites/changes that should not get in the way of developers time. Speedy with as little boiler plate as possible.
What Umbraco gives us
In Umbraco itself there was no way to do any of the above. Then when MVC in Umbraco arrived it gave us the idea of Models. These are strongly typed and you can source control them as its actual code that you yourself have to write. So thats points 1 and 3 ticked off but you still have to manually add your document types and fields via the UI (failing point 2) and you have to make sure your models and the database are manually kept in sync (failing point 4) by manually adding the fields via the UI and then in the code (failing point 5 due to the duplication). So 2/5 for Umbraco out the box.
The Umbraco HQ team are slowly working on some proofs of concept code here and there but its just that at the minute and until Umbraco 7 (aka Belle) is out the door and settled down they won't have much time to look at it in the near future so its looking like something the community are going to have to do (top tip, thats you and me).
uSiteBuilder to the rescue?
uSiteBuilder is awesome. As a body of work I've always been impress with how it managed to "tame" the old v4 era datalayer of Umbraco with some inventive hackery and code. But times and have moved on, the new datalayer in v6 is super fast and super slick requiring a lot less of the hacks and work arounds that v4 needed. As a result the code base for uSiteBuilder is itself looking very...erm...cluttered. Its also damn complex and difficult to test. Its a bit of a house of cards, changing a bit can end up breaking something for someone else. Testing a mod to the uSiteBuilder code is insanely hard and you end up relying on "works on my machine" style testing. Hardly great for a bit of kit you are putting into the heart of your website for eternity but with lack of an alternative it is what it is.
As it stands it give us points 1,2,3 and 4 off our want list so its a serious contender. You define your document types as C# class files (point 1) and decorate them with attributes for the various bits of meta data Umbraco needs (what data type to use for a property etc.). Compile it and hit your Umbraco site and uSiteBuilder automagically loops through all your classes and injects them into Umbraco (or updated them if they already exist), points 2 and 4. You can then use these classes to give you strongly typed models for your templates which is point 3. Sounds like a winning combo!
I've talked before about why you might want to use uSiteBuilder and as a result I've uncomfortably earnt the unofficial title of "Mr uSiteBuilder" due to my keenest to spread the word in the past through presentations, blog posts and long chats over a beer at the various events. We've used it a lot and we like it but recently our fondness for it has dwindled and we have been on the look for alternatives.
The main issue with uSiteBuilder is point 5, you need quite a bit of boiler plate and on a site of any size the re-sync time (where it checks that what you've listed in your code is actually in the database and if not it adds it) just starts to get in the way of the development cycle. A change involves a recompile and then a restart of the app pool and only then can uSiteBuilder do its magic. As a result a re-sync can take minutes (our longest is 20+ with 100+ doctypes) which when adding a simple check box for a quick feature is bonkers, imagine if you get it wrong or have a typo, you have to repeat it again! You end up getting distracted while you wait and before you know it you've lost an afternoon trying to add the most simpliest of changes. So...you cheat. You add the field into your code, then you go in the backend and use the UI to manually add it there too to avoid the costly re-sync loop. Bish bosh job done. But now you have to add it to all the other sites too, manually, and you've suddenly lost the goodness of points 2 and 4 all because it can't do point 5. Ouch.
A lot has been done to speed up uSiteBuilder (stopping the sync running every time it starts up, moving to some of the v6 api calls, etc) but it has some quirks due to the difficulty in testing and it is still a slow beast when you get above a certain size. It gets slower for every additional doctype you add as it has to loop over them all several times and in nested loops. That said it is still a great tool for medium sized sites (20-30 doctypes or there abouts).
As a result if doing a medium site it scores well with 4/5 but on a big site (which is really when you really want it to shine and help you out) it becomes a pain and drops down to a score of 2/5.
Without a suitable substitute though I've been very cautious about knocking uSiteBuilder as I didn't want to sow any seeds of doubts in peoples heads, it does what it does, has some warts but the gains "should" be worth soldiering on with is. I wish it was better but the complicated nature of the code makes doing improvements a bit of a mine field. In short, any time spent patching it up I think would be better spent on finding a newer better solution.
uSync, the new kid in town
So you've heard of uSync by Kevin Jump and you hope it might be the answer to your woes? I might be, sort of.
I really like uSync as it does one job and does it very well. That job is to take anything you add via the UI and spit it out as an XML file (which can be sourced controlled, so chalk up point 1) and more importantly it can take those XML files and use them to push in the document types described in them into another site, on another machine or server. So it exports and imports document types automatically.
This as you might imagine makes deployment super easy (point 2), ftp the files up and watch it go! Your new check box is live in seconds. You use the backend UI only to added/amend fields and document types (point 4) and it does its very best to not get in your way (holy smoke Batman thats point 5 too), infact you can just ignore and let it just do its job only taking an interest when you need to commit a change into source control. Lovely.
But thats all it does. You don't get strongly types models as thats simply not what it does. So its not really code first at all, in fact its "no code" as its just a data format really. That said it still scores a very healthy 4/5 despite it not doing what you probably thought/hoped it would do.
BTW as a side note it does not do anything with the actual content for a site, everyone gets that bit confused. uSync stores the structure of your document types not the data that you store in those document types. Subtle difference but and important one. It stores and copies the blue prints not the bricks.
So whats the real state of code first in Umbraco then?
So as uSync does not do strongly typed models it might look like if you want to do code first your only choices are MVC models and manually copying anything you add via the UI into C# classes (error prone and dull) or uSiteBuilder and putting up with its re-sync time and boiler plate.
But what if there was another way? What if we could use the awesome 4/5 that uSync gives us and strap a rocket to it to give us that missing piece, strongly typed models?
At Code Garden 13 in June we had several chats about our issues with uSiteBuilder (including an excellent open space session with the core Umbraco HQ team) and pondered how we might fix them and the solution we later came up with on our return home was to use uSync to do what it does best, generate out XML for your document types then consume that XML to in turn generate out MVC Models that you could use/compile to give you strongly typed models (the missing point 5!).
Better than that is if you thought about it a bit longer and threw in some twisted logic, you might be able to write those C# models yourself first then crank the handle backward on the new as yet non-existant tool so it would consume your classes and turn them into uSync XML format files, these could then be imported by uSync and before you know it...BOOM...you've got code first and a 5/5 score!
This hybrid approach sounded messy at first, too many moving parts but the more we thought about it the more we liked it. As this additional bit of processing also only had one job to do it could be leaner and faster then uSiteBuilder (and hopefully testable too) so we thought it might work. If only it existed...if only we had the time to write it.
Turns out someone already has! Lars-Erik Aabech has been thinking along the same lines and put fingers to keyboard to start it and release an alpha github.com/lars-erik/Umbraco.CodeGen only this week.
It still needs some work and some feedback about how you might actually use it to speed up point 5 as much as possible but before you know it we might have a usable code gen solution by glueing a few different parts together to make something new. It currently only does document types and media types but thats enough to get going.
I think currently this offers the best chance at a solution until maybe further down the line something similar could be put into the Umbraco core. It may seem like a few hoops to jump through but its less than using uSiteBuilder and by keeping the different area/jobs separate it can't turn into a big ball of mud style project. I'm hoping that with some team work we can get the process pretty slick.
So do your bit, check out Lars' code, give it a whirl and offer him some feedback, better yet make some mods yourself and give him a pull request. uSiteBuilder can still be of use to offer up some great ways to achieve some of the missing pieces that it still needs to do and in the meantime could hold the fort. Sadly I feel this might be the post that kills off uSiteBuilder for some so I hope something comes of this new idea to replace it as the best solution for code first in Umbraco. So get your geek on and take a look. We hope to be working on it and with it on some recent projects but the more eyes the better.
Exciting times.
Pete