The nature of HTTP is to provide resources where each resource is identified by a unique URL. A resource can be any kind of file: image, text file, font. Initially web sites used to deliver static HTML pages, which were pretty much limited in terms of content. CGI and server-side scripting languages like PHP, ASP(.NET), and JSP changed this by generating dynamic HTML on the server and sending it back to the client. This allowed the page content to be “configured” by the browser, f.x. using query string. This traditional web architecture is denoted on the diagram below.
It all worked fine until the Web became more complex and developers started to put more and more logic on the server. We ended up having to make requests like /index.php?module=employees&id=5 (especially with some CMS systems). This architecture tended eventually to cause many problems, from search-engine optimization to code maintenance. What we needed was another structure for our web sites and hence many frameworks were created (many of them still used today) to cope with this. One of the most popular design patterns for the Web today is MVC (Model-View-Controller) with many framework implementations, f.x. ASP.NET MVC for .NET, Rails for Ruby, Zend Framework for PHP. Its strongest advantage is the separation of concerns: decoupling the way we fetch data from the way we visualize it (see the diagram below).
What is the problem?
As before the problem arose when we started putting too much logic in controllers. Do you have controllers with more than 3-4 dependencies in the constructor? Do you have controllers with more than 5-6 action methods? If the answer to any of these two questions is yes, then you are probably overusing the controllers (exceptions do exist!). This happens partly due to the word controller itself. Just like the words manager and service, it creates the perception that the class can grow infinitely, because it does not have a well-define role. Why is this a problem? Well, we end up again in the code mess. The more dependencies we have between our components, the more difficult it becomes to change them, to test them, to analyze them. A solution to this code mess is to extract methods from our controllers into separate controllers and thus having many smaller controllers instead of fewer big ones. But this is only part of the complete solution…
The real separation of concerns
According to Wikipedia, separation of concerns is
[…] a design principle for separating a computer program into distinct sections, such that each section addresses a separate concern. A concern is a set of information that affects the code of a computer program. […]
If we take a standard ASP.NET MVC project template generated by Visual Studio, we will see the following structure:
We have basically a separate folder for every type of elements: controllers, models, views, scripts (for JavaScript files), content (for CSS files). For a moderately big project with, say, 15 controllers, each with 4 views and 4 models, it can be a struggle to navigate in this project structure. A typical task (f.x., fix a bug) includes revealing the relations between the different types of elements: views <-> controllers <-> models <-> JavaScript files <-> CSS files, which can be quite compelling. This is because we have done separation of technology, not separation of concerns. We have separated files by their extensions (and nature).
Towards component-driven development
Why not instead group all related files into one folder? When you work on log-in, gather all related elements together. When you work on user profile, gather all related elements together. This lets you navigate between functionally related files much easily. Moreover, you define a concern as a single functional unit. Even though I talk about the back-end mainly, this concept can be applied to the front-end. Santiago Esteva has written a great post about how to move from a controller-first to a directive-first approach when using AngularJS. React by Facebook is also a great example of a component-first approach.
Conclusion
The MVC way of doing things is well-spread and certainly has its advantages. One should however be careful when one’s application grows. You should ask yourself whether you are really applying separation of concerns. The component-driven approach introduces smaller-sized units that can be isolated and manipulated. This decreases the dependencies between components in our application and increases its cohesiveness.