The first of those is not something we can categorically state given that every business is different, and the latter two are fairly subjective depending on your experience. These next few articles will aim to bring that subjective view in scope by demonstration and hopefully help those who want to learn a few more things about FubuMVC...
So welcome to the team meeting, where the plan is for Josh (our illustrious newly hired team leader) to explain to the rest of the team which includes Rob (one of the original project developers) who are all new to FubuMVC, but have a decent background working with ASP.NET MVC, albeit just following the same old patterns that lead to more and more complex software over time.
So to get going, there are a couple of things Josh likes to get out of the way early whenever tackling a new FubuMVC project. So Josh, why don’t you take it away?
Sure thing. OK folks, the first thing we need to focus on is what we already have, and see how we want to apply that in the new structure. The current ASP.NET MVC project has a wealth of conventions buried in the way the code was written that haven’t consciously had any attention. It also looks like the same basic plumbing has just been used over and over in different places, Controller after Controller and View after View. We need to make those conventions work harder than they currently do and from one place.
But hang on a sec Josh, I’m confused, we have been pushing the conventions as far as I can see. We store Controllers in a folder by that name, Views are arranged under a Views folder, heck we even put the word “Controller” at the end of
Controller names since that’s a convention built into the framework. What am I missing here?
Good questions! Maybe this is best explained if we look at our current code and solution structure folder layout. First off, let’s pull up solution explorer up for the web project to get some context:
OK, so the first thing we can see is that the framework has decided that the convention for storing
Views should be separated. Do you specifically want to put them in different folders? What if you could perhaps, I dunno, group files by feature? Would that not make it easier for you to work on related files at the same time instead of jumping around?
You mean put the related
ViewModels etc. in the same folder as one another? That sounds neat! I had always wished we could create a feature called “AdminDashboard” and put all the related Views, Controllers and ViewModels inside that folder and the framework would be OK with that.
That would also mean that we don’t need to duplicate the same non-trivial folder structure to house
Views under as projects get bigger. Ours looks OK now when we have between ten and twenty, but it really is starting to getting tough to navigate now.
What about the
Controller names, do you want to call them that?
What do you mean? They have to end with the word “Controller” to be picked up by the framework right?
Well, with ASP.NET MVC yes, but you can tell FubuMVC what convention you want to employ. I personally like something more descriptive of their nature like
Handlers? That feels like it better describes what we’re doing on the wire with HTTP. We could create
POST Handlers for the various actions that each have a single responsibility.
Err, hang on a sec - I get that we can name them what we like, but our Controllers are already employing SRP right? I mean, all the Admin stuff is in the
AdminController, and the User stuff in the
UserController. What’s wrong with that? So now we have a
UserHandler instead – how is that better?
I see what you’re saying, but that’s actually a mistake that a lot of ASP.NET MVC developers make. We’re not going to create a
UserHandler. “User” is a domain entity, and Controllers in essence, are not domain entities, and they shouldn’t be modelled as per the domain. Therein lies the path to trouble. They are just message handlers in the bigger picture right? So we should treat them as such, and not try and bend them to look like our domain. We’re going to extract the responsibilities that
UserController covers into as many
Handlers as needed to separate by concern.
Umm, I’m not sure I get it. How is moving methods all related to a User into separate classes going to help us? It’s not like there are thousands of methods, there’s less than ten in this case.
Well, developers often think that “User” is a single responsibility and conceptually it could be if it dealt with only one thing and if you’re thinking of it in terms of the domain. If you think of it in terms of message or command handling for a User, then there are many unrelated things those commands can do to a User. Therefore, if you have ten methods in the
Controller, it’s highly likely that the Controller class has ten reasons to change, and is therefore breaking SRP.
Rather than talking about this too much in theory, if you crack open the code and actually read it, you’ll be able to see that “User” is just being used as a label for a section of the site and all sorts of SRP violations are happening inside the Controller. Since you mentioned the
UserController, go ahead and open it and we’ll get a feel for what I mean:
OK, so taking a look at the collapsed code, it seems that this
UserController deals with a range of responsibilities from logging in and out, voting, basic CRUD, authentication, beta registration and point calculations. Yes they all have something to do with a user, but they are all different responsibilities. Quite often, the unit tests will give us a good idea of how this design came about. Where are the unit tests for this code?
Umm, there aren’t any. We only have some for our domain and some integration tests for our repositories to and from the database.
I see, well a lack of unit tests can also explain how this design came about. You see, if you had driven out this design using tests, you would have felt a significant amount of friction given all the dependencies you would have needed to mock out for this
Controller to even work. It would have frustrated the heck out of you, hopefully to the point where you would separate them. Without the tests to give you that friction feedback, it becomes a classic case of the Controller being modelled against the data or storage model.
Unfortunately, the current framework guides you by default in creating code that does not obey the SRP. They even go so far as to create tooling that allows you the generate these violations in the form of CRUD operations and because it’s so easy, it gets used all the time. FubuMVC does the opposite. It actually tries to help guide us in moving away from loading up our Controllers with method after method because we think they are covered under the same responsibility, when in fact we’re just fooling ourselves. It does this:
- Firstly by allowing our Controllers (or Handlers in our case) to be pure POCO objects. No base class to inherit, or interface to implement making the classes far simpler to create and unit test;
- It then offers any strategy, to scan for, detect and configure these during the bootstrap process. Some of these come out of the box, but FubuMVC will use anything that you can cook up using the power of writing your own conventions, which really isn’t tough at all once you get it;
- And lastly, it does not expect you to setup a
Routefor each of these myriad of Controllers. Instead, it will once again leave the infinite power of convention at your disposal to automatically herd these Routes into submission.
The psychological burden of creating many of these is then mitigated, as opposed to the current implementation where each Controller brings with it a considerable amount of boilerplate baggage, which unconsciously makes you want to create less of them.
Looking at the code, it’s clear that this existing
UserController above doesn’t only have one reason to change. We’re just kidding ourselves that user login, logout and getProfile for example, are responsibilities that should exist in one class. They couldn’t be more different and yet we keep lumping them together.
Ah yes, I’ve read a few things about this on some blogs. Some of the more experienced developers in that space have started advocating for techniques like Single Action Controllers in ASP.NET MVC so that they get the benefits of SRP thereby not having to instantiate the Controllers with a ton of dependencies they don’t need for every request like we’re doing in the code above.
Yeah, it’s 2011 and folks have been making the same mistakes with ASP.NET MVC for two years now and there are a few developers out there who are starting to learn that the code situation is unmaintainable as solutions get bigger. Originally, developers thought that lumping all these action methods inside the same
Controller automatically must mean that they are covered under the same responsibility. And as I’ve said before, and I can’t stress this point enough:
A Controller is just a class, and a class should only have one reason to change in order to exercise the true meaning of SRP.
OK, I have to ask, why can’t we just break up our Controllers with that Single Action Controllers pattern using ASP.NET MVC and call it a day?
The problem with that pattern is not that it doesn’t allow for SRP, it will do that just fine. The problem is that it doesn’t scale given the way you are forced to store your files in ASP.NET MVC. It will look fine with ten or maybe twenty Controllers. But given that these Controllers are slimmed down now and only have one or two methods, there are quite a few actions that can be performed on medium to large websites. Not to mention the explosion when you start thinking about JSON based AJAX requests which deliver tiny amounts of data, because there could literally be thousands of them. How does that folder structure sit in your head?
I see what you mean - we already find it pretty bad hopping between Views, Viewmodels and Controllers and we have huge Controllers. Doing it that way will lead to an explosion of Controllers far beyond what we’ve got already. But hey, aren’t we going to have an explosion of Handlers in the same way using FubuMVC?
Yes you’re right, but you’re missing a couple of crucial points here that make FubuMVC different and better at managing this particular aspect:
- Firstly, take
Routing. For every
Controlleryou setup in ASP.NET MVC, you either have to create a new route handler to deal with it, or the Regex or Pattern based route handlers you have are going to start getting pretty gnarly.
Either way, this becomes a maintenance nightmare leaving you to guess which
Routeswill hit. With FubuMVC you don’t even need to write a line of code once the basic plumbing is in.
As long as you stick to your own conventions, it takes over, matching Controllers based on your criteria, and in our case, we’re going to put that namespace, which is so often ignored, to full use.
- Secondly we can employ
Actionless Viewsfor a number of mundane tasks which we’ll get into later, meaning we don’t even need to create a Handler for them. You’re going to love this - how many times have you written that boiler plate
ActionResultin the form of
return View();just so that the View would render?
- Thirdly, we need to consider discoverability. FubuMVC bootstraps all the types in the code and knows exactly which
Actionsto call based on the
Routesbefore the website has even been hit once. Everything is already known once the container has been configured and you can inspect this via the built in rich diagnostic views.
ASP.NET MVC will cycle through every Controller it can find on every request, looking for one that matches the particular Route, only deciding at that stage if it fits which leaves you in a position of having to diagnose
Routebreaks after the fact with third party plugins rather than ahead of time.
OK, I’m starting to see a picture forming here, but I guess the next question is - where to from here? We can talk about this until the cows come home, but we’re going to have to start cutting code so that we can really see what’s going on right?
Yes, I think we’ve reached an understanding. So now that we’re in agreement on the direction, we’re going to setup the basic FubuMVC web project and spike out that
Handler convention we were talking about since it isn’t one that comes out the box, and complete a vertical slice of functionality we’d like to migrate.
When we’re done, and if enough people wanted to use it then since FubuMVC is a true OSS project that willingly accepts external submissions from anyone that wants to contribute, I guess we could submit it for consideration if we think it looks useful enough for others.
Lets get cracking! Where do we start with our conventions?
Well we’re gonna decide on those next, and instead of letting our conventions lie down quietly by the way side, we’re gonna harness those suckers and get them to work for us - make ‘em earn their keep! You think you’ve seen conventions? Well fasten your seat belts...