52

I'm getting ready to take the bend out of asp and into an mvc framework, asp.net mvc or nancy. Wherever I go, I see folders for controllers/modules and folders for views. Is this just a pavlovian reflex of tidying things away by type, or is there some deeper wisdom operating? I have a little proof-of-concept project where I store together the files I'm likely to open together, a considerable comfort. Since these files are also likely to call each other, they can do so with shorter, less brittle, relative links. This pattern is challenged by mvc, because the folder path no longer automatically corresponds to the url path, and, in asp.net mvc, the project templates and routing enforce the views\ controllers\ schism.

This microsoft page introduces the concept of areas. It can be read as an admission of how unwieldy large apps become because of this artificial separation.

People will object "separation of concerns", but separation of concerns is already achieved by having separate source files. There's no concrete gain, it seems to me, from taking these source files that are tightly coupled, and sending them to opposite ends of the folder structure?

Is anyone else fighting this? Any tips?

bbsimonbb
  • 749

7 Answers7

50

I'd like to say it's cargo cult programming, but there are technical reasons for this structure. Asp.Net MVC took a convention over configuration approach to nearly everything. By default, the Razor view engine searches the Views directory in order to resolve which view to return from the controller. There are however a few hacks to get a different project structure and Microsoft even provides an MVC feature called Areas to let us create a more sane project structure. You could also implement your own view engine in order to specify where to look for views.

Why do I say that it's cargo cult programming and that you're correct about this? Uncle Bob convinced me that the project's directory structure shouldn't tell me that it's an MVC application. It should tell me that it's a store front, or a time off request system, or whatever. The high level structure and architecture should tell us about what this thing is, not how it was implemented.

In short, I believe you're right about this, but any other directory structure would simply be fighting against the framework and trust me when I say that you don't want to try to make the Asp.Net MVC framework do something it wasn't designed to do. It's a pity that it's not more configurable really.


To quickly address architectural concerns, I do still believe that the business models (business, not view) and the DAL should live in a separate project/library that gets called from your MVC app.

It's just that the controller really is very tightly coupled with the view and likely to be modified together. We're all wise to remember the difference between coupling via dependency and logical coupling. Just because the code has had its dependencies decoupled doesn't make it less logically coupled.

johnny
  • 3,679
RubberDuck
  • 9,021
11

Whatever the reason, this is poor practise. It is very anti-OO because packages or folders (whatever you want to call them), should have weak inter-dependencies. Classes (or files) inside them should have strong inter-dependencies.

By throwing all the views in one folder and all the controllers in another folder you are creating two packages with very very tight coupling. This goes against the principle of having weak inter package dependencies.

A view and a controller are two halves of a whole and should belong to each other. You wouldn't have one cupboard draw for left side socks, and another draw for right side socks.

8

To answer your 'Why everyone...?' question: Here are some potential reasons, although I'm not entirely sure which combination of them is a real cause, since it is actually a subjective question

  • To replicate the logical architecture (model, view, controller) with a matching folder and namespace structure

  • Out of convention & convenience to follow the ASP.net MVC project template

  • To group by namespace, since Controllers/ folder will lead to a .Controllers namespace

  • Might enable some scenarios in DI/IoC where controller classes are only queried/scanned from a namespace that contains/ends-with 'Controllers' (this could be wrong)

  • To allow for T4 templates to scan and scaffold models & controllers to generate views

You can always create and follow your own convention if it makes sense to your project, no one can/will stop you. But be mindful that if you work in a large project and/or large team, then the default convention that is known to everyone might be a better choice (not necessarily the right one, though!)

If your convention is easier to follow and does not hinder productivity, then by all means do it! and maybe even write about it a blog post or two to socialise it with the developer community and get feedback

Bishoy
  • 271
2

Not necessarily everyone does this. For example python's Django framework has the concept of an app, where sub-modules of your application live in their own directories with their own models and views and templates(views are what Django calls controllers essentially). I happen to prefer that way of doing things because that means that I can easily package an "app" and reuse it across projects just by including it in the apps list in my projects settings. It's also easier to find out where different parts are. If I look at the urls.py file and see something like url(r'^users/', include('my_site.users.urls')), I know that the module my_site.users contains all the code that handles users. I know to look at the modules my_site.users.views and my_site.users.models when I want to see how users are created and authenticated. I know that all my routes are defined in my_site.users.url.

Also if it's generic enough I can probably use that module in other sites just by changing the configuration or package it as a library and publish it as OSS.

2

One reason to keep views and controllers in separate directories is when you have front end and back end developers working on a project. You can prevent front end developers from accessing back end code (e.g. to assist with PCI compliance, restricting who has access to sensitive code).

Another reason is to make it easier to have "themes" and switch out all of the templates by making a minor change to the view path.

A third reason is to have a simple directory pattern when specifying views in the MVC framework. It is easier to specify the sub-directory and file rather than a big long path to each view.

The only "tight coupling" should be:

  1. Variables sent into the view by the controller.
  2. Form fields or actions in the view, sent back to the controller.

I use a generic controller and try to keep variable names in the view generic, so that many views can use the same controller, and many controllers can use the same view. For this reason I prefer to keep the views entirely separate. The model is where you can differentiate each "thing" in your application - they can be objects with a list of properties and methods to access/modify these properties.

For tightly coupled code, an approach that could work for you is keeping all files that are part of a package or "module" together in a namespaced directory. Then you can use a script to copy or "compile" your raw templates into the main "views" directory. For example:


    lib/my-namespace/my-package/
        -> controllers/
        -> models/
        -> views/
            -> theme/
               -> template-name1
    app/compiled_views/theme/
        -> url/path/template-name1

Unfortunately, if you want to change the structure of an existing theme, there is more weaving in and out of package directories to update the views.

Consider that views are just a way to format data, whether it is json, xml, csv, or html. This especially helps if you want your application to also work as an API. Try to decouple the view from the data, by using generic variable names, so you can use the same template for many controllers or models (or use includes to minimize the amount of code you need to maintain).

1

Remember it's the Microsoft recommended way to keep the controllers and views in different folder, so many would follow recommended structure,

  1. One reason could be controllers always does not have one to one relationship with views, especially the partial views can be shared among controllers.
  2. Another reason could be when your project grows, you might want to pull controllers and unit tests out to another project(s), but it's pretty hard to do the same for views plus views/js/css belong together as they refer each other.

Having said that there are many posts about doing it your way, such as this.

svidgen
  • 15,252
1

For the record

Why do I say that it's cargo cult programming and that you're correct about this? Uncle Bob convinced me that the project's directory structure shouldn't tell me that it's an MVC application. It should tell me that it's a store front, or a time off request system, or whatever. The high level structure and architecture should tell us about what this thing is, not how it was implemented.

Question: Who has access to the code?. Programmers. Do end-users care about the code?. No. And, what a programmer does, code. Or more specifically, classes based on types (controllers, service, model and so on). So it makes sense and it's easy to debug a code, if you are able to find a code based on the type of code, instead of in the behavior of the code. Plus, let's say a team project, one is in charge of the controller, another of the model, another of the dao and another of the view. It's easy to separate the project into parts. A good code is a code that is easy to debug, not a syntax sugar code. Uncle Bob is wrong again.

Trying to mimicking the behavior of the project (a store front) is cargo cult.