> The view layer in web app frameworks is broken. Every framework has a template language, and every template language has the same flaw: views contain both structure and logic. This flaw annoys me as a developer, and here's why.
> Let me start by making the distinction between structure and logic. Structure defines what makes up the view. Logic defines how data goes into the view. Break the view down and it consists of nothing more than some arbitrary structure populated with data. Remove the data and you're left with an empty structure.
This is a flawed definition because logic also changes structure:
<div class="results">
<% if @results.empty? %>
<h2>Sorry, your search returned no results</h2>
<% else %>
<% @results.each do |res| %>
<div class="result">
<h3><%= link_to res.title, res %></h3>
<p><%= res.snippet %></p>
</div>
<% end %>
<% end %>
</div>
What's the structure here? Are there several structures here? Where's
the data? "Structure defines what makes up the view" is also very
vague. Doesn't the data "make up the view"? It seems to me that you're
thinking about structure as something static (like a house's
foundation); and then it's very easy to distinguish between the
structure (the rooms, the walls etc) and the data (what humans bring
into the room). However, templates are more dynamic than that: No room
can fit all our data, so we build a new house every time instead.
> In most cases the data to be presented is dynamic. So, instead of hardcoding data in the view, logic is added to describe how the structure will be populated with data. In today's template languages, this view logic is mixed in with the view structure itself.
Templates are not static "things" that you can touch and re-organize.
A templates is something that *builds* a structure depending on the
data right there. Logic doesn't merely "populate structure with data";
logic forms the structure to fit the data. You can consider certain
components of the template to be static (e.g. the .result-div always
have the same structure), but the overall template must be understood
as a *process*; gluing together several parts.
It's not enough to look at parts/structures itself; if you don't see
how they are glued together, how can you understand the result? The
reason "view logic" is mixed with "view structure" is, as mentioned
before, the logic decides the structure. If you have to know both to
know everything, isn't it better to have it all in the same place?
> For example, in Rails, an ERB template contains an HTML structure along with Ruby code that is responsible for adding data to the structure. The result is a view that, prior to rendering, contains both structure and logic. Structure and logic are closely related, but they also serve two very different purposes. Putting them in the same place leads to some real problems.
> First, this causes development roles to become unclear. View structure is a design concern and view logic is a programming concern. When they're combined, the roles of designer and programmer become fuzzy. The front-end designer's responsibility is to create the view structure, since structure is very much tied to the look and feel of an app. On the other hand, view logic is the responsibility of the back-end programmer. A designer shouldn't have to understand or even think about view logic when creating the view; it's a separate concern. Yet when placed together in the view, structure and logic can't be thought of as independent things.
> This is an issue even in a team without clearly defined designer/programmer roles. And really it's for the same reason. Combining two separate concerns in the view muddies the water no matter how large or small a team is.
Just so we agree: "view logic" is very different from "domain logic"
or "controller logic"; "view logic" is the logic that builds up the
view.
How can that view logic *not* be a front-end designer's
responsibility? View logic is about *how* the view is constructed.
Designers are very concerned about the full result; they don't work on
a "this component should look like this, while this component should
look like this". Combining components to create a consistent design is
their job! They *have* to understand how the tool their working with
combines components. I'd argue that putting the view logic within the
same file as the "structure" makes it even clearer what's going to
happen. There's more cognitive load to realize that `<div
id="header"></div>` includes an external file than `<%= render :header
%>`. The designer have to understand what's happening anyway, why not
make it explicit?
> Once logic is added to structure, one can't take a step back to see the unadulterated version of the view. Structure essentially becomes lost. This means the designer really has nothing to own, creating a process that isn't very designer-friendly. Problems also come up when it comes to changing existing views.
Well, what is a good "unadulterated version of the view"? A view is a
complex thing; as you said, it consists of structure and logic. Why is
structure essentially lost? Yes, if you push too much general logic
into the view you have a problem, but then you move things into
helpers/presenters etc. The only reason you should have complex view
logic is if the view is complex; hiding the complexity in other files
doesn't solve the problem.
> Without the ability to separate logic from structure it's impossible to refactor either one in isolation. They are so intertwined that when a change must be made, there is no other option than to change both at the same time. This makes the refactoring process much more complicated and error prone than it needs to be. Separating concerns is an important part of the refactoring process and it simply isn't possible with a view layer that consists of both structure and logic.
If you want to change the result, it's pretty clear that you'll have
to change the process too. The only case where your approach work is
if you've already thought about the problems in advance in the
logic-layer. If you haven't, then there's now two different places
where you need to refactor. Because of this, your approach encourages
generalization, and I wouldn't be surprised if you're just slowly
implementing a template language (e.g. you go from <div
class="result"> to <div class="repeat-result"> to <div
data-repeat="result">).
> Solving these problems is possible, and is actually pretty simple. It requires separating concerns by removing view logic from view structure, allowing a view to remain purely structural. View logic becomes a separate layer that acts on the view structure from outside of it. This is the approach taken in designing the Pakyow web framework, and separating structure and logic has enabled us to solve all of the problems discussed here. In addition, Pakyow developers are at least 42% less likely to be annoyed. It'll change your life.
> This is simply an introduction to the concept of separating view logic and view structure. The implementation details will be the topic of a future post. If you have any comments or would like to discuss this post feel free to send me an email or find me on Twitter.
// Magnus Holm