The code first in Umbraco deadend
Another epic post, sorry! As background you might like my other posts on Code First:
Using uSiteBuilder - (sadly lost in time)
So when I had to present in front of a conference room full of developers with a talk entitled "Code First Development in Umbraco: The what, how, why and even should you" it can be understandable for them to assume that I'm about to do a talk that shows them all the benefits of Code First, about why you should be using it, how we use it and of course a demo of just how easy it is to do it.
At uWestFest in Las Vegas in March I stood up knowing I'd created a slide deck that actually said nothing of the sort. Instead I had to break it to them that code first is actually quite nasty, it creates more problems than it solves, adds a dependency you don't need, masks issues, hinders performance and more.
Time for me to write up my thoughts for the rest of you lovely Umbraco developers and managers who could not make it (shame it was an excellent event) so you can make your own mind up.
Up front this is my opinion and the current stance of us here at Offroadcode, formed from doing battle with Code First in the trenches on numerous projects. You might have a strong opinion on Code First and thats fine, you might be able to counter many of my points with solutions or better ways of working and thats also fine feel free to do so in your own way of working but for us currently at Offroadcode we will not be following the Code First route.
I'm known for focusing on uSiteBuilder and once again this post is not a reflection on a fine bit of work, there is a version 2 coming out soon but I fear it might suffer from the same fundamentalissues all the frameworks do in one sense or another.
In short Code First does not "fit" well within the Umbraco model, our workflow or the type of sites built.
Code first should be fantastic
The idea of code first is intoxicating for a developer. Define your doc types (and more) in code, the medium we are happiest. Have it in source control, change it in Visual Studio, amazing and as comfy as your favourite pair of slippers!
Trouble is beyond a simple 5 page site it causes far too many side effects, making changes in the future is painful, upgrading (umbraco or your code first package of choice) is a nightmare, handing it over to someone else to maintain is a special sort of sodistic pain you should never wish on anyone unless you liked killing puppies as a child.
Lets pop the hood on some of these in more detail.
Sounds easy to make a Code First framework right?
All the code first frameworks for Umbraco are written by well meaning developers wanting to crack the tricky nut that is Code First. Its a awesome high ground to take if you can. On the face of it how hard can it be to get it to do it right? I bet any developer who's worked with Umbraco for more than a few months could problably doodle on a bit of paper the basics of the issue, heck that doodle might even cover 80% of the solution. On the face of it getting Code First to work is "quite simple", you could do it in a weekend right?. It's that last 20% thats tricky though, it's the bits you either didn't think about or pushed back until next weekend or hoped someone else would fill in the void once you released it on Github. Trouble is that 20% is really important, it will be what makes it work as a whole. I'll give you one to chew over, doctype inheritence, it's a swine trust me...go get another bit of paper, in fact get a whole pad. The sad truth is Code First needs to work 100% not just for the easy bits sadly. There is no 95% solution, it does not work, it's all or nothing.
This is why we have several different Code First offerings out there, none of them complete. The closest one to complete in my mind was uSiteBuilder (a sterling body of work) but that got behind the times when v6 came out with it's new API changes and was simply too big to tame/refactor to get it working well, which comes on to my next point.
A hard coded dependency thats out of your hands
Using code first sticks a huge fat dependency right slap bang in the middle of your site and its one that is out of your hands. For the life time of that website (on average 3 years according to the Offical Umbraco stats) that code will always be in there. So if there is an issue you have to deal with it. You could wait for the developer to fix it but he's not doing it for the money so expect a delay. You could get the source and patch it, well done you're now working on a custom build and set yourself up to accidently regressing the issue if you ever forget and drop different DLLs into the /bin/ folder. Been there, done that one, it hurts.
This dependency can stop you upgrading a site (we've got many v4 sites that we won't move up to v6 as they use uSiteBuilder for instance). Which is fine until you need (or worst a client requests) a feature in the newer version of Umbraco. You've effectively frozen that sites code base in time. Might be fine for most sites but not all.
When it goes wrong (and it will) what do you do? uSiteBuilder is a huge code base and doing alot of "taming" of the old v4 APIs. How do you make a change to that and test it? How do you know you are not breaking something else? Yes you can get the code on most frameworks but you want to be "building websites" not "building websites AND patching the tools that are meant to be making this easy". I'm not saying that you shouldn't patch up code, thats the whole open source thing, I'm just saying it's difficult to allow time to patching it up, it's not what clients pay you for and it's hard to schedule in. A good Code First framework tends to be pretty complex, it's not for the faint of heart and you certainly don't want it breaking just before go live (as happened here) normally when some real content is added in.
Messy code and a broken work flow
For code first you have to define everything you need for a doctype and data types in code. The common way to do that is via Attributes on your C# classes. This sounds logical and smart, the right place to keep it is there next to the code that uses it.
But it causes a bunch of problems.
The biggest for me is noise. Loads of attributes all over my code most of which are only of use once, when I first added the damn property! You get little intellisense here either so it's all about remembering what the heck each one needs. This death by attributes on the eyes just masks any real logic in your class and makes it more effort than it should be to see the wood for the trees. It does not make a nice place to work and you can't hide/code fold attributes.
If you need to define "allowed templates" or "allowed child doctypes" then you have to do it in a big old array or similiar. Nothing tidy about that, easy to mess up too as you have to hard code magic strings (easy typo!) into source or reference classes depending on your framework. Want to define a folder to store something in, you'll probably need a empty class for that and all the boiler plate that goes with it. 25 lines of code for a folder! You can't do some of it in the UI and some in Code First, it's all or nothing.
There can be quite a bit of boiler plate too, our last version of uSiteBuilder for instance needed lots of constructors for it all to work, not the end of the world but just a bit more noise thats all. It all starts adding up.
How does the framework know whats changed? You change the description lets say, there is no way for the framework to know without comparing every property on every doctype to every property on your classes. And it has to do this before you might use anything, so it has to do this check on start up or you have to manually trigger it (ala uSiteBuilder Admin). This involves a few bits and bobs, it needs to search all your classes for "CodeFirst Classes" however the framework defines those (probably scanning all your DLL's which is slow), loop through them all, then loop through all the data in Umbraco (which is also slow as it hits the database a lot).
Side note: Your developer mind is probably trying to solve this one with an "easy mod" you just throught up involving hashing of classes or file watchers but STOP, look at it in the bigger picture, it's one small issue in a bag full of issues.
Again this is really fast on a site with 5 pages (and that demo site they use in the video to show off the framework), you simply won't notice much of a lag. Put it on a live site with 30 doctypes and suddenly you start seeing that lag. Normally there is a way to switch off the sync on live to speed it up great stuff. But when developing a quick change can lead to a 60+ second warm up time. Imagine that for every code change you make...an insane waste of developer time and just asking you to get distracted.
The workflow here is broken.
There are other options of course, you can hard code which classes to sync in another class! Cutting out the sync time a bit (but not by much as you still have to search all the code base to find that class in the first place). How many times will you forget that one step and lose a sync cycle before you remember, how many times are you going to refresh the browser and not see the change you expected before you go "oooh yeah, I forgot the ####### sync file AGAIN!".
The workflow here is broken.
You are storing UI hints and information (description, tool tip, icons, etc.) within your code, thats not separation of frontend and backend. If you need to make a change to the description (lets say you have a typo) you need to
Pull down the source
Find the file
Find the property
Edit the property
Compile it all
Deploy the DLL
Reload the whole application
Ooops! Remember to re-enable start up sync
Wait for a minute at least...
*All this for a UI typo!*It's just not the right place for it is it? Don't worry I know you never do typos, you are too good but I do and i'ts a rubbish way to correct them.
Even when you get it all to compile you then boot up the backend (after waiting 60+ seconds) to eye ball that it's all worked, loading up the very thing (the UI) you wanted to avoid (it's ok though you are just checking not using right so it's not cheating...right? Clinton never inhaled). When you had to fix that typo how much were you wishing you could "just use the UI" to correct it. You know deep down it's not right but you tell yourself the trade off is worth it or you cheat, correct it in code then correct it in the UI to save a resync cycle...and at that point you've broken your own rules and proved my point.
The work flow here is broken.
There is no way to prevent someone editing your changes via the UI so expect to blitz someone else mods or that typo correction that the client put right for you as her boss kept nagging. Oh and by the way now the boss thinks the whole system is flakey as it keeps putting it back and no one knows why...well done.
THE WORK FLOW IS ALL BROKEN!
Is the Umbraco backend the best Umbraco package of all time?
A developers time is expensive. Code first is meant to save us some time, no more jumping between the database, visual studio, the UI, etc. to get a mod done. Right? Thats how it work inRuby on Rails! RoR does not have Umbraco as it's backend and data source.
I've yet to see these time savings with Code First in Umbraco. The UI is the fastest way to make those changes and ultimately we don't make those changes that often.
"if it didn't exist someone would create it as a package and it would be the highest voted ever!" - @drobar
Think about it, it makes sense to do what we do right there and no where else.
So what CAN we do?
MVC changed the whole landscape for Umbraco and Code First. Code First made sense of sorts (lets say it was a better fit) in v4 but with MVC it's different.
We use a shared Database for all developers, suggest you do the same. If you ever need to "push" this database anywhere either copy it or use uSync which is good for source controlling your mods but I've found our Models are all the source control documentation I need and usync files are too easy to miss in a commit.
The place for your logic about doctypes now lives in your Model. Nice and simple. I suggest you use the UI for adding the properties into the Umbraco backend/database and testing you got the names right, setting inheritence, allowed templates and all that Jazz. It's a manual step and a bit of a bore but it's important and it's a one time deal for each property so nothing to get angry at. It has to be done somewhere, might as well use the nice UI that helps you along with the process and no restarts required!
Model mappers are going to be getting more and more interest and effort, I expect quite a bit of talk about them at Code Garden 2014. These make it easier to Hydrate a C# model with all the fields stored in your Umbraco backend. If you want to spend that weekend coding on something I'd recommend one of those. Be careful though the same 80:20 rule applies sadly as does the dependency issue but try picking one thats already done and add to it if you have the itch.
Personally I'm really liking just coding these mappings manually in my Model using simple
style code in wrappers. I know how it works, there is no magic involved, I can cheat and hardcode it to a string for speedy frontend work and most importantly it helps me get a mental model of the site. Wiring the models up manually rather than letting some magic do it, helps me feel out what works and what does not. I often change my model or add/remove properties while I'm doing this. Eating my own dog food as it were.
Is there a future for Code First?
I may sound quite jaded by Code First in Umbraco and you'd be right. As it stands I won't be using it again, we've burnt a lot of hours on it and found it simply does not work the way we want it to.
There are exceptions of course, Stephan from Umbraco HQ is said to be working on some cool stuff, if anything Core is the right place for a Code First solution, once in there they would look after it and make sure it continues to work with any other changes they do. But I would not hold your breath, it's a nasty nut to crack but I'm excited to see what he's come up with.
**UPDATE:**Stephan got in touch soon after reading my post to basically say "don't hold your breath" he's not got a magic bullet. So thats killed that then.
I intend to lock Shannon from Umbraco HQ to the bar and ply him with beer until he tells me a better workflow for MVC (still not happy with it).
A framework should help you get stuff done. As it stands I think the Code First framework used on anything but a simple tiny site just help you quickly get into long term trouble. The nasty kind of trouble thats difficult to see or explain unless you've been there. Lets say I've got the 1000 yard stare and this long post is my warning to you of what it's really like out there...
If you want to chew this over with me feel free to buy me a beer between my presentations atCode Garden 2014 and we can walk through it but for now I'm tapping out of the Code First debate.