Most developers that are interested in bettering themselves really do want to hear both sides of the story. They want to understand the strengths of other platforms, not so they can move, but so that they can understand how to make their own framework/platform better. When you read this post, I hope you will read it with that in mind. I hope you will see this not as me criticizing your platform, or someone else’s work, but instead as me saying “here is what I think is cool about this other platform, how can your platform get in on that?”
A Tale Of Two Frameworks
There was a time when Ruby on Rails was the hottest thing on the block, and many ASP.NET developers pined for the day when we could leave behind controls and viewstate and move into the glorious world of web development. Cause what we were doing wasn’t web development, don’t kid yourself. Then ASP.NET MVC came out, and a lot of people (myself included) jumped on that bandwagon and have never looked back.
I have been very happy with ASP.NET MVC for a long time. It gives me a simple to use framework that gets out of my way and lets me write real web applications. And I love it! But there is just one problem, websites are quite often complex beasts and ASP.NET MVC only solves a small part of the puzzle. Every project I start I have to pull in a membership system, migrations, an ORM, an IOC container, logging, testing framework, etc… I have to find and plugin all of these tools every time I want to do build another site. (Nuget has helped with the finding and integrating part immensely!)
I guess this is to be expected though, ASP.NET MVC wasn’t really meant to be an opinionated framework. They wanted to produce a framework which would have broad appeal across the hundreds of thousands of .NET developers out there. Not an easy task! They also wanted a smaller framework that they could release in short cycles. Based on their goals, I’d say that they have done a great job.
But because of this they couldn’t just pick different frameworks and include them as defaults. First of all, there were few choices that would not have been controversial. Secondly, if they had made controversial decisions, the framework would have been rejected by early adopters and not seen the adoption that it has now.
Creating a generic framework is fine, as long as you understand what you are giving up to get there. The power of frameworks like Ruby on Rails, Django, or CakePHP is that they span the whole stack. While this might lock you down to doing things in a certain way, in the end the benefit derived from the tight integration is very often worth it.
Walking Through The Problem
In order to demonstrate this, let’s take the example of authentication in a web application. In ASP.NET MVC we have the normal ASP.NET authentication mechanism which we can leverage in order to have users and roles, but as most of us know, a lot of people end up rolling their own or looking for an outside solution. Why? Because the user is part of our domain, and the ASP.NET authentication system forces us to use their tables, stored procs, db deployment tools, etc… It is clunky and not extensible at all. So let’s say we want to build an alternative, what would we have to do?
The first we need is a model that represents a user, we can either include this in the framework, or maybe just let the user define the class that they need, and then implement an interface for us to interact with. Okay, so how do we get the tables in the database? Well, we could create some scripts and put them in the project, then the developer can run those to create the user tables. That doesn’t seem very awesome, what if they aren’t running SQL Server? Yes, some of us do use .NET without SQL Server. What if they need to automate creating the database for testing? Also, how much does it suck to have to manually run the scripts on every machine you need to deploy to?
Well, we could write code to connect to the database and run the DDL to create a table. That would be more automatic. But again, what database are they running, which connection do we use, how do we let the user modify their user object to fit their needs if we need to create the table? Arrrrgh! Okay, let’s just punt on that and say that we will just create scripts for a few databases, and let the user modify and then run them manually, or integrate the scripts into their build process. That sucks.
Now how do we get the user model in and out of the database? We don’t really know how the developer is going to be doing data access, so we can’t pull the user from the database within the framework, we will have to force the user to implement a class that we can call and get users, in the same way that the provider model is currently implemented in .NET. This isn’t terrible, just inconvenient.
So now we are at the point where we have a database table, and we can pull users from the database. The only problem is that the developer has had to implement an interface on his user object, manually edit and run scripts, implement a persistence mechanism (most likely an ORM), and implement a provider to allow us to perform CRUD operations on users. And we are just getting started! What about creating a controller, views, adding routes, validation, sending e-mails, etc…? There are a lot of pieces that go into a successful authentication mechanism, this isn’t easy stuff.
In the ASP.NET MVC world, all of these problems may seem overwhelming. Sure, we could implement a full solution, but we’d have to make a lot of assumptions and force the user into tools that they might not be using. Or we include our own tools, and bypass their stack in the same way that the ASP.NET providers work. This disconnect is what frameworks like Sharp Architecture try to solve, but third party libraries could never depend on frameworks like this until their adoption reached a critical mass. Otherwise they would be spending a lot of effort, for every little return.
How Would You Do This In Rails?
In Rails there are a few different frameworks available to do authentication. The one that I have used is Devise. In order to use Devise, the first thing we would do is to add the gem to our Gemfile (a gem is like a NuGet package, if you don’t know what a NuGet package is, go here) with a line like this:
gem 'devise', '~> 1.3.4'
Then we just run “bundle install” and the gem is installed into our project. Now we have to configure devise. We can run this command (you can type out ‘generate’ instead of ‘g’ if you want):
And it will show you all of the generators available to you. You will see a section for Devise. Devise is able to hook into these generators and do some really powerful stuff. We can see from this list that there is a generator for devise called “devise:install”. We can run that:
rails g devise:install
Now Devise has installed its configuration file into your app, and you are almost ready to go. You’ll notice there is another generator just called “devise”, if we run that it tells us to give it a model name so it can generate a User model for you. Because everything in Rails has a place, you simply run this command:
rails g devise User
And it drops User model into your /app/models folder, generates a migration for you, and puts routes into your routes.rb file. Now all I have to do is run my migrations (I can edit the migration or create another migration to edit my user table, allowing me to completely customize my user):
And now my database tables are created and everything is ready to go. I can put this on my controller:
And now that controller will redirect me to a login/signup page, allow me to create an account, send confirmation e-mails (if I want), etc… I also have a number of helper methods that I can run like “user_signed_in?” or “current_user” in order to interact with users on a more fine grained level.
What Happened There?
Well, you saw the power and productivity of a full stack framework. Devise knows what tools you are using (or how to integrate with them), and where everything goes. Because of this we don’t need to tell it how to create a model, create database tables, save/retrieve users from the database, how to connect to the database, how to send e-mail, etc… These are all configuration and sensible defaults that have already been setup in your application.
And for anything that isn’t automated, there are Rails generators that we can hook into to create config files, add routes, views, and any other assets. We are able to do this because most everything has a place in a Rails app. Rails is a very opinionated framework, and it shows. If you follow the “Rails Way” then things will be smooth and super productive.
How Do We Make ASP.NET MVC Better?
That is a very difficult question. You see, the Rails community long ago agreed to go along with the “Rails Way” in exchange for increased productivity and integration. I’m not sure that the .NET developer community would respond favorably to the kinds of changes which would be required to bring ASP.NET MVC up to the level of integration that Rails enjoys.
This doesn’t mean that they can’t come close though. One thing they could do is start to favor certain tools more in the framework. Start to setup conventions and tools that developers are expected to use, and let them know that if they stray, they are on their own. However, the problems here are obvious. The tools that are going to be made the defaults will be Microsoft’s own tools, like Entity Framework or MEF. This could create some serious friction with the developer community if they start to integrate too tightly with these tools.
An MVC Uber-Framework?
Another interesting path would be to see some full stack frameworks spring up on top of ASP.NET MVC. Maybe Microsoft could implement another framework on top of ASP.NET MVC which would be fully integrated, but could be tossed out if you just wanted just the underlying web framework. As long as this framework was simple and powerful enough, you would probably see a large number of developers jump on board, which would give OSS creators a reason to integrate with it. On the MS platform, a tool like this usually has to come from within Microsoft itself, otherwise it has an extremely hard time gaining any momentum.
I can see a lot of eyes rolling and hands shooting up after that last paragraph, but hear me out. If Microsoft continues down the path they are now, and they start integrating things like Entity Framework and MEF as defaults, but not truly integrated, then all we are going to get is a bunch of code generation when we start a project. This isn’t going to help OSS developers extend the framework. But, if they could instead tease out the web layer from the rest, and build a more integrated application stack on top of it, that would go a lot further. I’d love to hear people’s feedback on this.
Will It Change?
I don’t know! ASP.NET MVC is a fine framework. I just don’t feel like it is as productive as it could be. Good, solid, testable web development just doesn’t have to be as hard as it currently is with ASP.NET MVC. ASP.NET MVC has given us a good start on the web layer, but hooking up our applications to this front end is often repetitive, clumsy, and cumbersome. All I want is for my whole stack to play nicely together, is that really too much to ask?