Styleguide Driven Development

Styleguide Driven Development (SDD) is a practice that encourages the separation of UX, Design & Frontend from Backend concerns. This is achieved by developing the UI separately in a styleguide.

By separating the UI and backend tasks so they don’t rely on each other, it allows teams to iterate fast on prototypes and designs without having to make changes to the backend. With careful planning they should plug-and-play together nicely.

SDD isn’t just limited for big teams working on large applications, but the core concepts of developing UI elements separately in a styleguide (living or static) can still benefit a sole developer working on a single page app.

SDD in the real world

We have recently embraced SDD in the Envato Market ‘Purchase’ team and have spent the last 6 months building a new shopping cart using this approach with great success.

SDD evolved slowly out of our team’s growth and the need to visualise complex features and their scenarios at a glance. By introducing such a wide-reaching and sophisticated feature into an already complex application it spurred a change in our development and agile practices.

As a frontend developer working on a cross-functional team with 4 backend developers, a UX designer and a product manager, it is easy to become a bottleneck. The UI has many moving parts and strong dependencies on each team member.

Living Styleguides

Styleguide Driven Development

Styleguides and pattern libraries do a great job of visualising an application’s framework and static UI library, however when developing data rich applications the ‘views’ (aka partials) are mostly dynamic and require data to bring them alive. In order to render these dynamic views in the styleguide we need to use sample data to trigger the scenarios we want to test.

By using real views, we can be confident that the styleguide truly reflects our application. This confidence allowed us to change our approach and develop our views directly in the styleguide as the first step in assembling a new page or adding a feature.

Using sample data means that we can iterate quickly on prototypes and designs before requiring the backend to be complete or even exist. Developing the views early helps to expose any gaps in the designs or wireframes. It also helps us figure out what sort of logic we need from the backend. Having it all separated like this offers us the freedom to complete the backend and frontend work asynchronously.

Living styleguides are the key to SDD and they also provide a fantastic base for regression testing so that we can avoid breaking our UI when working on new features.

Scenario Visualisation

User interfaces are often developed for best case scenarios, however they can unknowingly break in a handful of cases when a possible scenario hasn’t been considered or is ‘out of sight, out of mind’. Simple things like the length of the data or how it responds to mobile breakpoints can turn an otherwise well designed UI into an amateurish mess.

Having a styleguide that documents all the possible scenarios for a view is a tremendously powerful asset. It directly benefits each team member’s role as well as other members of the business. Historically, testing a view across all of its various states was very manual process and occasionally required database manipulation.

By documenting all scenarios in a central location the styleguide essentially becomes a frontend spec and helps identify edge-cases, gaps in the UX and breakages.

Below is an early prototype of the user-nav view and its possible scenarios.

User navigation scenarios

Bringing the views alive

Developing views that can handle sample data required us to change our development practices. Historically our views pulled data directly from our database backed models, which meant that they were not very reusable outside of their primary context.

In order to decouple the views from the models, we create a layer of objects responsible for asking our data models for information and converting it into whatever form will make our views happy. In Ruby on Rails there are several ways to do this; the way that we currently use is for each view to have a presenter object sitting behind it.

Essentially this makes our views ‘dumb’ as they only care about the values that they require. Removing the bulk of their logic and their direct relationship with our data models makes them reusable in other contexts, similar to the way that javascript templates work.

The following is a simplified example of the ‘user-nav’ view and presenters.

User navigation example

Styleguide Presenter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class UserNavPresenter
  def signed_in_cart_with_a_few_items
    OpenStruct.new(
      :user_signed_in? => true,
      :shopping_cart_enabled? => true,
      :username => "michael-jordan",
      :balance => "$314.15",
      :shopping_cart_count => 2,
      :shopping_cart_empty? => false,
      :sign_in_url => "#",
      :sign_out_url => "#",
      :sign_up_url => "#"
    )
  end

  def signed_out_cart_with_a_few_items
    # etc
  end
end
Application Presenter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class UserNavPresenter
  def user_signed_in?
    @signed_in_user.present?
  end

  def shopping_cart_enabled?
    feature_on?(:shopping_cart)
  end

  def username
    @user.username
  end

  def balance
    @user.balance.format
  end

  def shopping_cart_count
    @cart.entries_count
  end

  def shopping_cart_empty?
    @cart.entries_count == 0
  end

  def sign_in_url
    routes.sign_in_path
  end

  def sign_out_url
    routes.sign_out_path
  end

  def sign_up_url
    routes.sign_up_path
  end
end
Our View (user_nav.html.erb)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div>
  <div>
    <% if presenter.user_signed_in? %>
      <span><%= presenter.username %></span>
      <span><%= presenter.balance %></span>
    <% else %>
      <a href="<%= presenter.sign_up_url %>">Create an Envato Account</a>
    <% end %>
  </div>
  <% if presenter.shopping_cart_enabled? %>
    <div>
      <div class="cart-summary<%= "--empty" if presenter.shopping_cart_empty? %>">
        <span><%= presenter.shopping_cart_count %></span>
      </div>
    </div>
  <% end %>
  <div>
    <% if presenter.user_signed_in? %>
      <a href="<%= presenter.sign_out_url %>">Sign Out</a>
    <% else %>
      <a href="<%= presenter.sign_in_url %>">Sign In</a>
    <% end %>
  </div>
</div>

This approach does mean we do need to manage two presenters for each view which we add to the styleguide, however we are currently investigating different methods to decouple our views from the models and are trialling Cells to reduce the need for duplication.

Change in agile practices

As we experimented with SDD our agile practices evolved to compliment our new approach.

Historically we included both frontend and backend tasks in one self contained and estimated user-story, but this often meant that we were creating blockers and bottlenecks for ourselves on day one as often a frontend task couldn’t start until the backend was completed or vice versa.

Using SDD we can now split our larger user-stories into smaller more focussed stories with smaller estimates and less dependencies. The benefit of this is that they can be tackled in any order even over the course of several sprints as the resources become available.

With good communication the UI and backend will seamlessly come together.

An added benefit of this approach we have found is that our Git branches and Pull Requests are much smaller as they don’t combine as much frontend and backend code and as a result makes them easier to get reviewed.

Conclusion

By developing directly in the styleguide we immediately have to start thinking about the user experience and how we want our view to interface with the backend.

While this approach requires changing some development and agile practices, the process directly benefits and compliments the UX, design, frontend and backend stages of development.

The added benefit of this approach is that we are documenting our application and all its views, thus bringing light to otherwise hidden or broken scenarios. Any edge cases or gaps in the UI are identified early and the frontend and backend devs can be confident they are developing towards a consistent interface.