Separation of Concerns

Once upon a time (in the dark ages of web application development) we built our applications as a single monolithic Perl CGI script, or perhaps a large JSP file containing the entire application. The code looked something like this:

costs.jsp

<% Cost[] costs = CostHelper.calculateCosts(loanData, currentDecision); %>
<h3>Current Costs:</h3>
<table border="0">
  <tr>
    <th>Cost</th>
    <th>Amount</th>
  </tr>
  <% for(int i=0; i<costs.length; i++) { %>
    <tr>
      <td><b><%costs[i].getName()%></b></td>
      <td>$ <%costs[i].getValue()%></td>
    </tr>
  <% } %>
</table>
<p style="text-align: center; font-style: italic">
  <a href="costHelp.html" 
      onclick="
        window.open(this.href, 'Help');
        return false;
      "
  >Explain these</a>
</p>

And it was confusing. But after a time we became enlightened and we realized that we should separate out the business logic from the rest of the presentation. We used tag libraries or velocity macros or any of a host of other technologies, and the code looked something like this:

CostController.java

Cost[] costs = CostHelper.calculateCosts(loanData, currentDecision);
modelAndView.addObject("costs", costs);

costs.vm

<h3>Current Costs:</h3>
<table border="0">
  <tr>
    <th>Cost</th>
    <th>Amount</th>
  </tr>
  #foreach( $cost in $costs )
    <tr>
      <td><b>$cost.name</b></td>
      <td>$ $cost.value</td>
    </tr>
  #end
</table>
<p style="text-align: center; font-style: italic">
  <a href="costHelp.html" 
      onclick="
        window.open(this.href, 'Help');
        return false;
      "
  >Explain these</a>
</p>

And it was confusing. But after a time we became enlightened and we realized that we should separate out the styling from the rest of the presentation. We used CSS markup in separate files, and the code looked something like this:

CostController.java

Cost[] costs = CostHelper.calculateCosts(loanData, currentDecision);
modelAndView.addObject("costs", costs);

costs.css

.costName {
  font-weight: bold;
}
.helpLink {
  text-align: center;
  font-style: italic;
}

costs.vm

<h3>Current Costs:</h3>
<table border="0">
  <tr>
    <th>Cost</th>
    <th>Amount</th>
  </tr>
  #foreach( $cost in $costs )
    <tr>
      <td class="costName">$cost.name</td>
      <td>$ $cost.value</td>
    </tr>
  #end
</table>
<p class="helpLink">
  <a href="costHelp.html" 
      onclick="
        window.open(this.href, 'Help');
        return false;
      "
  >Explain these</a>
</p>

And it was confusing. But after a time we became enlightened and we realized that we should separate out the dynamic JavaScript from the rest of the presentation. We called this unobtrusive JavaScript, and the code looked something like this:

CostController.java

Cost[] costs = CostHelper.calculateCosts(loanData, currentDecision);
modelAndView.addObject("costs", costs);

costs.css

.costName {
  font-weight: bold;
}
.helpLink {
  text-align: center;
  font-style: italic;
}

costs.js

$(function() {
  $('.popup').click(function() {
    window.open( $(this).attr('href'), 'Help');
    return false;
  });
})

costs.vm

<h3>Current Costs:</h3>
<table border="0">
  <tr>
    <th>Cost</th>
    <th>Amount</th>
  </tr>
  #foreach( $cost in $costs )
    <tr>
      <td class="costName">$cost.name</td>
      <td>$ $cost.value</td>
    </tr>
  #end
</table>
<p class="helpLink">
  <a href="costHelp.html" class="popup">Explain these</a>
</p>

And it was better. Things get a little bit confusing because each screen is rendered from several different files instead of from a single one, but separating out the concerns of business logic, styling, and dynamic behavior made each piece easier to understand and work with.

Recently, though, I became enlightened, and realized that we still have too many things going on in the same file. The HTML file still contains two independent concerns: the definition of the structure and the actual text. These facets are not really related, and they tend to be edited by different people. (HTML designers don’t necessarily produce the marketing copy and other text.) So this is a perfect candidate for another separation of concerns. That’s why my current project is organized like this instead:

CostController.java

Cost[] costs = CostHelper.calculateCosts(loanData, currentDecision);
modelAndView.addObject("costs", costs);

costs.css

.costName {
  font-weight: bold;
}
.helpLink {
  text-align: center;
  font-style: italic;
}

costs.js

$(function() {
  $('.popup').click(function() {
    window.open( $(this).attr('href'), 'Help');
    return false;
  });
})

cmstext.properties

cost-title: Current Costs:
cost-col1-label: Cost
cost-col2-label: Amount
cost-help: Explain these

costs.vm

<h3>#cms("cost-title")</h3>
<table border="0">
  <tr>
    <th>#cms("cost-col1-label")</th>
    <th>#cms("cost-col2-label")</th>
  </tr>
  #foreach( $cost in $costs )
    <tr>
      <td class="costName">$cost.name</td>
      <td>$ $cost.value</td>
    </tr>
  #end
</table>
<p class="helpLink">
  <a href="costHelp.html" class="popup">#cms("cost-help")</a>
</p>

The code that processes this allows no markup in the cmstext.properties file — any metacharacters will be properly escaped. So in principle it would be easy to give this file directly to the business to edit without IT help — or even to allow them to edit it on the live website without needing a QA cycle. The down-side is that we have yet another file to deal with: time will tell whether the benefits outweigh that cost.

Comments

One Response to “Separation of Concerns”

  1. mcherm on 2008-10-27 3:48 pm

    By the way, this approach would obviously have advantages for internationalization, but even if you never plan to support more than one language, it is still useful.

Leave a Reply