51

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
  • 739
  • 1
  • 6
  • 12
  • It may be comfortable for you to put files which you open together to a same folder, it seem to me comfortable having files doing similar things in the same folder, views with views and controllers with controllers. – Andy Feb 23 '16 at 10:01
  • 3
    You don't think it's logical to separate back-end code files from view files? If we're already taking the direction why not put the relevant CSS and JavaScript files in the same folder too? – Alternatex Feb 23 '16 at 10:09
  • 2
    If you get Resharper, then F12 on the call to `View` in the controller takes you to the view and the first option in the right click menu on the view takes you to the controller, and the whole problem with the lack of navigation goes away. – Pete Kirkham Feb 23 '16 at 10:16
  • 6
    @Alternatex I'm sorry but I don't see how a controller is "back-end". It's tightly coupled to it's view(s). The view's no good without a controller, the controller no use without the view. One day you'll want to delete them together. That for me is the best test of what belongs together in a folder?? Unless someone can show me a better way? – bbsimonbb Feb 23 '16 at 10:20
  • 1
    @PeteKirkham yep very true ! But I'm such a pervert - I want to put the .css and the .js right there in the same folder, and I don't think those are links Resharper will provide? – bbsimonbb Feb 23 '16 at 10:24
  • 2
    Views are presentation layer. Controllers are layer which contain services, which may contain objects from your domain, which contain your business logic, which therefore contain the back-end logic of your application. Views only consists of trivial conditionals and simple loops for iteration over collections, if your views contain something else, you are doing it wrong. As with the regular structure, you have separated the back-end and front-end, which to me is a better structure than the one you're suggesting. – Andy Feb 23 '16 at 10:58
  • @user1585345 The Controller is by definition back-end and in all ways different from the View. They may [both belong in the Presentation Layer](http://stackoverflow.com/questions/12429729/controller-belongs-to-the-presentation-layer) but that's where the similarities end. Ideally the View would not contain any back-end (C# or other) code, which is why I referred to it as .html instead of .cshtml. To put it simply, they are file types that serve different purposes, their responsibilities are different and so they are put in different folders. – Alternatex Feb 23 '16 at 11:11
  • 1
    @DavidPacker but why? Services, objects from my domain, business logic: these things are all reusable and sure, I would store them differently, and apart, and perhaps call that a layer. But what makes you say a controller belongs in this layer, given it's tight coupling with a small group of views? – bbsimonbb Feb 23 '16 at 13:38
  • 13
    So no shortage of folk to tell me that a controller is crockery so it goes in the crockery cupboard. Views are glasses so they go in the glass cupboard. I *know* that a controller is crockery, but I'm proposing it would be great to have a lunch cupboard and a dinner cupboard, since we're talking about stuff that only gets used at lunch *or* at dinner. – bbsimonbb Feb 23 '16 at 13:45
  • There's a nice hack here to get an asp.net MVC project structured *the right way*. http://www.gurustop.net/blog/2012/09/11/aspnetmvc4-application-structure-by-features-move-views-by-area/ and here's Uncle Bob's explanation of why you're right about this. http://youtu.be/Nsjsiz2A9mg – RubberDuck Feb 24 '16 at 00:19
  • @RubberDuck Ok that's what I was looking for thanks. It confirms the validity of what I want to do, and puts me off doing it - once I see I have to modify Razor config with string methods, without seeing what I'm modifying ! If you'd like to put that in an answer, I'll likely accept it. – bbsimonbb Feb 24 '16 at 09:12
  • @user1585345 done. – RubberDuck Feb 24 '16 at 09:49
  • @RubberDuck For controlling where razor looks for views, [this](http://theshravan.net/blog/configure-the-views-search-locations-in-asp-net-mvc/) method is a bit more comprehensive than the gurustop hack. – bbsimonbb Feb 24 '16 at 11:26
  • Not sure what 'take the bend' means. sounds like a colloquialism :) – Michael Durrant Nov 04 '16 at 11:18
  • The controller, view, script, and CSS for a single "Control" should be in the same folder, IMO. The most logical mechanism for rendering a view, or rendering a re-usable view, is to render the view and have it's script/CSS dependencies injected automatically. When rendering the view, this can be achived by "registering" the CSS/Script as part of that view, such that it's extracted out, set aside, and rendered on the page as a dependency. On the containing page that renders your view or copies of the view, it can then instantiate the dependent script class for each instance. – Triynko Nov 04 '17 at 19:42
  • If you have a controller named ReportsController, and a Views/Reports folder, you can further categorize reports with subfolders. For example, if you had a Views/Reports/Sales subfolder, You can render it from a view under Views/Reports simply as Html.Partial("Sales/SalesReport1") without having to specify app-relative paths. In other words, if it's one folder down from the expected location, you can simply prefix the view name with "Subfolder/" without adding "~/Views/{full_path}" or ".cshtml". – Triynko Nov 04 '17 at 19:48

7 Answers7

49

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,669
  • 3
  • 21
  • 35
RubberDuck
  • 8,911
  • 5
  • 35
  • 44
  • 1
    The comprehensive way of controlling where razor looks for views is [here](http://theshravan.net/blog/configure-the-views-search-locations-in-asp-net-mvc/). I might just persevere. – bbsimonbb Feb 24 '16 at 11:23
  • Very cool @user1585345! I might give that a go sometime. – RubberDuck Feb 24 '16 at 11:30
  • 4
    I watched uncle bob, at x1.25 as suggested. It leaves me thinking that if IT architects built buildings, we'd all be living on little groups of rafts tied together, floating around on some lake. Life would not necessarily be simpler. – bbsimonbb Feb 24 '16 at 11:32
  • 1
    It get's a little more complicated. To really co-locate controllers and views, you will want to resolve the view path at runtime, to include the controller namespace. [Here's how to do it](http://weblogs.asp.net/imranbaloch/view-engine-with-dynamic-view-location). – bbsimonbb Feb 25 '16 at 09:42
  • 1
    Also take a look at feature-oriented software development (http://fosd.net), for the academic counterpart to what Uncle Bob is describing. – ngm Jul 06 '16 at 10:18
  • Also, I believe the FubuMVC 'bottles' concept was this kind of feature-oriented approach in the .NET MVC world, letting you mix code, views, web endpoints etc in a reusable package. Fubu kind of died though (although with some rebooting as https://github.com/JasperFx/jasper) and it's very hard to find much documentation to do with Bottles. – ngm Jul 06 '16 at 10:34
  • " 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. " – magallanes Aug 23 '18 at 22:29
  • `It should tell me that it's a store front, or...` Any company who has its employees work on multiple different projects will rightly point out that this is counterproductive. If you do this, it will take a long time to get a new developer up and running. If you're a company who e.g. repeadly uses MVC projects and sells these to a variety of clients (= different business requirements), it makes much more sense to structure your projects in a **reusable** manner (i.e. the MVC structure). Not every developer who needs to fix a bug needs to understand the entire project. – Flater Aug 24 '18 at 08:03
  • 1
    Conway’s Law at work. I’m sure that works at your company @Flater. The standard MVC layout works at lots of companies, but I still prefer to group thing by semantics over syntax. The companies I’ve work for have been organized around products instead of roles/job functions. I believe this is the root of my preference here. – RubberDuck Aug 24 '18 at 08:09
  • 1
    @RubberDuck: Conway's Law I can agree with. Some companies may focus on storefront software and may use different technologies, whereas other companies focus on a technology and sell it to different customers. But Cargo Cult Programming I can't agree with here, because it's not _[code or program structures that serve **no real purpose**](https://en.wikipedia.org/wiki/Cargo_cult_programming)_ but rather _code or program structures that serve **a different purpose**_. – Flater Aug 24 '18 at 08:13
  • 1
    That’s a fair criticism of an old answer written by a younger & brasher version of myself @Flater – RubberDuck Aug 24 '18 at 08:17
  • @RubberDuck: The date on the question/answer had eluded me. – Flater Aug 24 '18 at 08:18
10

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.

Oliver Watkins
  • 332
  • 2
  • 5
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
  • 1
  • 5
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.

Pavel Penev
  • 582
  • 4
  • 4
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).

Frank Forte
  • 121
  • 4
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
  • 13,414
  • 2
  • 34
  • 60
Low Flying Pelican
  • 1,602
  • 9
  • 13
  • "it's the Microsoft recommended way" ... Can you clarify what you mean by that? Is there an actual, authoritative MS article about this? Or, is that just the default project setup for an MVC app? And, if you're basing this on the latter, isn't it possible that the default MVC project setup is what it is because it's how "everyone" does it?? – svidgen Dec 21 '16 at 15:30
  • 1
    Based on the article https://msdn.microsoft.com/en-us/library/dd410120%28v=vs.100%29.aspx?f=255&MSPPError=-2147217396 it says "Controllers, which is the recommended" and so on for the views, etc.. – Low Flying Pelican Dec 27 '16 at 04:52
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.

magallanes
  • 218
  • 1
  • 5
  • 6
    Whan I code I care the most about features, not types. When I see a feature not working as expected I know something's wrong in the code related to that feature while I don't necessarily know which type of code it is. – Stop harming Monica Aug 24 '18 at 07:17
  • 2
    “let’s say a team project, one is in charge of the controller, another the model, another the dao” Such a team will have a hard time shipping anything and when they do it will have cost far more in communication overhead and bugs. – RubberDuck Aug 24 '18 at 07:56
  • 1
    As established in a comment chain under the accepted answer, you've got a point but only in certain cases. When a company focuses on MVC projects that it sells to many varied clients, keeping an MVC structure makes sense for reusability. When a company focuses on a niche (e.g. webshops) and possibly uses many different technologies, it makes more sense to have a webshop-oriented structure. This is a practical application of [Conway's Law](https://en.wikipedia.org/wiki/Conway%27s_law). The code (and therefore also project structure) should follow the company's structure. – Flater Aug 24 '18 at 08:22
  • @RubberDuck: You can make an argument for added cost either way. You're right that when different people do different technical components, that you have increased business logic communication. However, if you have different people fully implement different features, then you may have increased costs in making sure everyone is on board (skilled + agreeing) with using the same technical approach. Either way, you need communication overhead to make sure people work together. – Flater Aug 24 '18 at 08:25
  • Yes and handoffs always cost more than having a single pair of devs implementing a feature end to end IME. – RubberDuck Aug 24 '18 at 08:57